mirror of
https://github.com/bgp/stayrtr.git
synced 2024-05-06 15:54:54 +00:00
Add basic BGPsec support to RTRMon
It is not pretty, I didnt really want to overhaul the whole tool since I also use this tool to test my own releases of stayrtr. So instead bgpsec router keys are injected as "special" VRPs. Since RTRMon is not complying to a standard, I feel we can be more flexible here. Tag: https://github.com/bgp/stayrtr/issues/57
This commit is contained in:
@ -4,6 +4,7 @@ import (
|
||||
"bytes"
|
||||
"crypto/tls"
|
||||
_ "embed"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"flag"
|
||||
@ -345,7 +346,7 @@ func (c *Client) Start(id int, ch chan int) {
|
||||
continue
|
||||
}
|
||||
|
||||
updatedVrpMap, inGracePeriod = BuildNewVrpMap(log.WithField("client", c.id), c.vrps, decoded.Data, tCurrentUpdate)
|
||||
updatedVrpMap, inGracePeriod = BuildNewVrpMap(log.WithField("client", c.id), c.vrps, decoded, tCurrentUpdate)
|
||||
}
|
||||
|
||||
VRPInGracePeriod.With(prometheus.Labels{"url": c.Path}).Set(float64(inGracePeriod))
|
||||
@ -368,7 +369,8 @@ func (c *Client) Start(id int, ch chan int) {
|
||||
// * contains all the VRPs in newVRPs
|
||||
// * keeps the firstSeen value for VRPs already in the old map
|
||||
// * keeps elements around for GracePeriod after they are not in the input.
|
||||
func BuildNewVrpMap(log *log.Entry, currentVrps VRPMap, newVrps []prefixfile.VRPJson, now time.Time) (VRPMap, int) {
|
||||
func BuildNewVrpMap(log *log.Entry, currentVrps VRPMap, pfxFile *prefixfile.VRPList, now time.Time) (VRPMap, int) {
|
||||
var newVrps = pfxFile.Data
|
||||
tCurrentUpdate := now.Unix()
|
||||
res := make(VRPMap)
|
||||
|
||||
@ -404,6 +406,27 @@ func BuildNewVrpMap(log *log.Entry, currentVrps VRPMap, newVrps []prefixfile.VRP
|
||||
}
|
||||
}
|
||||
|
||||
for _, bgpsecKey := range pfxFile.BgpSecKeys {
|
||||
key := fmt.Sprintf("%s-%d-%s", bgpsecKey.Ski, bgpsecKey.Asn, bgpsecKey.Pubkey)
|
||||
|
||||
firstSeen := tCurrentUpdate
|
||||
currentEntry, ok := currentVrps[key]
|
||||
if ok && currentEntry.Visible {
|
||||
// VRP is still visible, so keep the existing `FirstSeen`.
|
||||
firstSeen = currentEntry.FirstSeen
|
||||
}
|
||||
|
||||
copyOf := bgpsecKey
|
||||
|
||||
res[key] = &VRPJsonSimple{
|
||||
ASN: bgpsecKey.Asn,
|
||||
FirstSeen: firstSeen,
|
||||
LastSeen: tCurrentUpdate,
|
||||
Visible: true,
|
||||
BGPSecData: ©Of,
|
||||
}
|
||||
}
|
||||
|
||||
// Copy objects that are within the grace period to the new map
|
||||
gracePeriodEnds := tCurrentUpdate - int64(GracePeriod.Seconds())
|
||||
inGracePeriod := 0
|
||||
@ -482,6 +505,28 @@ func (c *Client) HandlePDU(cs *rtr.ClientSession, pdu rtr.PDU) {
|
||||
delete(c.vrpsRtr, key)
|
||||
}
|
||||
|
||||
c.compRtrLock.Unlock()
|
||||
case *rtr.PDURouterKey:
|
||||
vrp := VRPJsonSimple{
|
||||
ASN: pdu.ASN,
|
||||
FirstSeen: time.Now().Unix(),
|
||||
Visible: true,
|
||||
BGPSecData: &prefixfile.BgpSecKeyJson{
|
||||
Asn: pdu.ASN,
|
||||
Pubkey: pdu.SubjectPublicKeyInfo,
|
||||
Ski: hex.EncodeToString(pdu.SubjectKeyIdentifier),
|
||||
},
|
||||
}
|
||||
|
||||
key := fmt.Sprintf("%s-%d-%s", vrp.BGPSecData.Ski, pdu.ASN, pdu.SubjectPublicKeyInfo)
|
||||
c.compRtrLock.Lock()
|
||||
|
||||
if pdu.Flags == rtr.FLAG_ADDED {
|
||||
c.vrpsRtr[key] = &vrp
|
||||
} else {
|
||||
delete(c.vrpsRtr, key)
|
||||
}
|
||||
|
||||
c.compRtrLock.Unlock()
|
||||
case *rtr.PDUEndOfData:
|
||||
log.Infof("%d: Received: %v", c.id, pdu)
|
||||
@ -678,12 +723,13 @@ type diffMetadata struct {
|
||||
}
|
||||
|
||||
type VRPJsonSimple struct {
|
||||
ASN uint32 `json:"asn"`
|
||||
Length uint8 `json:"max-length"`
|
||||
Prefix string `json:"prefix"`
|
||||
FirstSeen int64 `json:"first-seen"`
|
||||
LastSeen int64 `json:"last-seen"`
|
||||
Visible bool `json:"visible"`
|
||||
ASN uint32 `json:"asn"`
|
||||
Length uint8 `json:"max-length"`
|
||||
Prefix string `json:"prefix"`
|
||||
FirstSeen int64 `json:"first-seen"`
|
||||
LastSeen int64 `json:"last-seen"`
|
||||
Visible bool `json:"visible"`
|
||||
BGPSecData *prefixfile.BgpSecKeyJson `json:"bgpsec,omitempty"`
|
||||
}
|
||||
type VRPMap map[string]*VRPJsonSimple
|
||||
|
||||
|
@ -10,7 +10,13 @@ import (
|
||||
)
|
||||
|
||||
func TestBuildNewVrpMap_expiry(t *testing.T) {
|
||||
stuff := testData()
|
||||
stuff := testDataFile()
|
||||
emptyFile := &prefixfile.VRPList{
|
||||
Metadata: prefixfile.MetaData{},
|
||||
Data: []prefixfile.VRPJson{},
|
||||
BgpSecKeys: []prefixfile.BgpSecKeyJson{},
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
log := log.WithField("client", "TestBuildNewVrpMap_expiry")
|
||||
|
||||
@ -19,7 +25,7 @@ func TestBuildNewVrpMap_expiry(t *testing.T) {
|
||||
t.Errorf("Initial build does not have objects in grace period")
|
||||
}
|
||||
|
||||
_, inGracePeriodPreserved := BuildNewVrpMap(log, res, []prefixfile.VRPJson{}, now.Add(time.Minute*10))
|
||||
_, inGracePeriodPreserved := BuildNewVrpMap(log, res, emptyFile, now.Add(time.Minute*10))
|
||||
if inGracePeriodPreserved != len(res) {
|
||||
t.Errorf("All objects are in grace period")
|
||||
}
|
||||
@ -27,16 +33,16 @@ func TestBuildNewVrpMap_expiry(t *testing.T) {
|
||||
// Objects are kept in grace period
|
||||
// 1s before grace period ends
|
||||
t1 := now.Add(*GracePeriod).Add(-time.Second * 1)
|
||||
res, inGracePeriod = BuildNewVrpMap(log, res, []prefixfile.VRPJson{}, t1)
|
||||
res, inGracePeriod = BuildNewVrpMap(log, res, emptyFile, t1)
|
||||
|
||||
assertLastSeenMatchesTimeCount(t, res, t1, 0)
|
||||
assertLastSeenMatchesTimeCount(t, res, now, len(stuff))
|
||||
if inGracePeriod != len(stuff) {
|
||||
t.Errorf("All objects should be in grace period. Expected: %d, actual: %d", len(stuff), inGracePeriod)
|
||||
assertLastSeenMatchesTimeCount(t, res, now, len(stuff.Data))
|
||||
if inGracePeriod != len(stuff.Data) {
|
||||
t.Errorf("All objects should be in grace period. Expected: %d, actual: %d", len(stuff.Data), inGracePeriod)
|
||||
}
|
||||
|
||||
// 1s after grace period ends, they are removed
|
||||
res, inGracePeriod = BuildNewVrpMap(log, res, []prefixfile.VRPJson{}, now.Add(*GracePeriod).Add(time.Second*1))
|
||||
res, inGracePeriod = BuildNewVrpMap(log, res, emptyFile, now.Add(*GracePeriod).Add(time.Second*1))
|
||||
if len(res) != 0 {
|
||||
t.Errorf("Expected no objects to be left after grace period, actual: %d", len(res))
|
||||
}
|
||||
@ -48,23 +54,23 @@ func TestBuildNewVrpMap_expiry(t *testing.T) {
|
||||
func TestBuildNewVrpMap_firsSeen_lastSeen(t *testing.T) {
|
||||
t0 := time.Now()
|
||||
log := log.WithField("client", "TestBuildNewVrpMap_firstSeen_lastSeen")
|
||||
stuff := testData()
|
||||
stuff := testDataFile()
|
||||
|
||||
var res, _ = BuildNewVrpMap(log, make(VRPMap), stuff, t0)
|
||||
|
||||
// All have firstSeen + lastSeen equal to t0
|
||||
assertFirstSeenMatchesTimeCount(t, res, t0, len(stuff))
|
||||
assertLastSeenMatchesTimeCount(t, res, t0, len(stuff))
|
||||
assertVisibleMatchesTimeCount(t, res, len(stuff))
|
||||
assertFirstSeenMatchesTimeCount(t, res, t0, len(stuff.Data))
|
||||
assertLastSeenMatchesTimeCount(t, res, t0, len(stuff.Data))
|
||||
assertVisibleMatchesTimeCount(t, res, len(stuff.Data))
|
||||
|
||||
// Supply same data again later
|
||||
t1 := t0.Add(time.Minute * 10)
|
||||
res, _ = BuildNewVrpMap(log, res, stuff, t1)
|
||||
|
||||
// FirstSeen is constant, LastSeen gets updated, none removed
|
||||
assertFirstSeenMatchesTimeCount(t, res, t0, len(stuff))
|
||||
assertLastSeenMatchesTimeCount(t, res, t1, len(stuff))
|
||||
assertVisibleMatchesTimeCount(t, res, len(stuff))
|
||||
assertFirstSeenMatchesTimeCount(t, res, t0, len(stuff.Data))
|
||||
assertLastSeenMatchesTimeCount(t, res, t1, len(stuff.Data))
|
||||
assertVisibleMatchesTimeCount(t, res, len(stuff.Data))
|
||||
|
||||
// Supply one new VRP, expect one at new time, others at old time
|
||||
otherStuff := []prefixfile.VRPJson{
|
||||
@ -75,12 +81,17 @@ func TestBuildNewVrpMap_firsSeen_lastSeen(t *testing.T) {
|
||||
TA: "testrir",
|
||||
},
|
||||
}
|
||||
otherStuffFile := prefixfile.VRPList{
|
||||
Metadata: prefixfile.MetaData{},
|
||||
Data: otherStuff,
|
||||
BgpSecKeys: []prefixfile.BgpSecKeyJson{},
|
||||
}
|
||||
t2 := t1.Add(time.Minute * 10)
|
||||
res, _ = BuildNewVrpMap(log, res, otherStuff, t2)
|
||||
res, _ = BuildNewVrpMap(log, res, &otherStuffFile, t2)
|
||||
|
||||
// LastSeen gets updated just for the new item
|
||||
assertFirstSeenMatchesTimeCount(t, res, t0, len(stuff))
|
||||
assertLastSeenMatchesTimeCount(t, res, t1, len(stuff))
|
||||
assertFirstSeenMatchesTimeCount(t, res, t0, len(stuff.Data))
|
||||
assertLastSeenMatchesTimeCount(t, res, t1, len(stuff.Data))
|
||||
|
||||
assertFirstSeenMatchesTimeCount(t, res, t2, len(otherStuff))
|
||||
assertLastSeenMatchesTimeCount(t, res, t2, len(otherStuff))
|
||||
@ -152,3 +163,12 @@ func testData() []prefixfile.VRPJson {
|
||||
|
||||
return stuff
|
||||
}
|
||||
|
||||
func testDataFile() *prefixfile.VRPList {
|
||||
stuff := prefixfile.VRPList{
|
||||
Metadata: prefixfile.MetaData{},
|
||||
Data: testData(),
|
||||
BgpSecKeys: []prefixfile.BgpSecKeyJson{},
|
||||
}
|
||||
return &stuff
|
||||
}
|
||||
|
Reference in New Issue
Block a user