mirror of
https://github.com/bgp/stayrtr.git
synced 2024-05-06 15:54:54 +00:00
Implment ASPA as defined in draft-ietf-sidrops-8210bis-10
Tag: https://github.com/bgp/stayrtr/issues/79
This commit is contained in:
@@ -39,3 +39,5 @@ test/scenario_test/nosetest*.xml
|
||||
# IDE workspace
|
||||
.idea
|
||||
.vscode
|
||||
|
||||
output.json
|
||||
+36
-1
@@ -38,6 +38,8 @@ var (
|
||||
Serial = flag.Int("serial.value", 0, "Serial number")
|
||||
Session = flag.Int("session.id", 0, "Session ID")
|
||||
|
||||
FlagVersion = flag.Int("rtr.version", 1, "What RTR version you want to use, Version 2 is draft-ietf-sidrops-8210bis-10")
|
||||
|
||||
ConnType = flag.String("type", "plain", "Type of connection: plain, tls or ssh")
|
||||
ValidateCert = flag.Bool("tls.validate", true, "Validate TLS")
|
||||
|
||||
@@ -109,6 +111,29 @@ func (c *Client) HandlePDU(cs *rtr.ClientSession, pdu rtr.PDU) {
|
||||
}
|
||||
c.Data.BgpSecKeys = append(c.Data.BgpSecKeys, rj)
|
||||
|
||||
if *LogDataPDU {
|
||||
log.Debugf("Received: %v", pdu)
|
||||
}
|
||||
|
||||
case *rtr.PDUASPA:
|
||||
if c.Data.ASPA == nil {
|
||||
c.Data.ASPA = &prefixfile.ProviderAuthorizationsJson{
|
||||
IPv4: make([]prefixfile.ASPAJson, 0),
|
||||
IPv6: make([]prefixfile.ASPAJson, 0),
|
||||
}
|
||||
}
|
||||
aj := prefixfile.ASPAJson{
|
||||
CustomerAsid: pdu.CustomerASNumber,
|
||||
Providers: pdu.ProviderASNumbers,
|
||||
}
|
||||
|
||||
switch pdu.AFIFlags {
|
||||
case rtr.AFI_IPv4:
|
||||
c.Data.ASPA.IPv4 = append(c.Data.ASPA.IPv4, aj)
|
||||
case rtr.AFI_IPv6:
|
||||
c.Data.ASPA.IPv6 = append(c.Data.ASPA.IPv6, aj)
|
||||
}
|
||||
|
||||
if *LogDataPDU {
|
||||
log.Debugf("Received: %v", pdu)
|
||||
}
|
||||
@@ -146,11 +171,21 @@ func main() {
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
targetVersion := rtr.PROTOCOL_VERSION_0
|
||||
if *FlagVersion > 2 {
|
||||
log.Fatalf("Invalid RTR Version provided, the highest version this release supports is 2")
|
||||
}
|
||||
if *FlagVersion == 1 {
|
||||
targetVersion = rtr.PROTOCOL_VERSION_1
|
||||
} else if *FlagVersion == 2 {
|
||||
targetVersion = rtr.PROTOCOL_VERSION_2
|
||||
}
|
||||
|
||||
lvl, _ := log.ParseLevel(*LogLevel)
|
||||
log.SetLevel(lvl)
|
||||
|
||||
cc := rtr.ClientConfiguration{
|
||||
ProtocolVersion: rtr.PROTOCOL_VERSION_1,
|
||||
ProtocolVersion: uint8(targetVersion),
|
||||
Log: log.StandardLogger(),
|
||||
}
|
||||
|
||||
|
||||
+49
-10
@@ -14,6 +14,7 @@ import (
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
@@ -52,7 +53,7 @@ var (
|
||||
|
||||
ExportPath = flag.String("export.path", "/rpki.json", "Export path")
|
||||
|
||||
RTRVersion = flag.Int("protocol", 1, "RTR protocol version")
|
||||
RTRVersion = flag.Int("protocol", 1, "RTR protocol version. Version 2 is draft-ietf-sidrops-8210bis-10")
|
||||
RefreshRTR = flag.Int("rtr.refresh", 3600, "Refresh interval")
|
||||
RetryRTR = flag.Int("rtr.retry", 600, "Retry interval")
|
||||
ExpireRTR = flag.Int("rtr.expire", 7200, "Expire interval")
|
||||
@@ -146,6 +147,7 @@ var (
|
||||
protoverToLib = map[int]uint8{
|
||||
0: rtr.PROTOCOL_VERSION_0,
|
||||
1: rtr.PROTOCOL_VERSION_1,
|
||||
2: rtr.PROTOCOL_VERSION_2,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -195,8 +197,11 @@ func isValidPrefixLength(prefix *net.IPNet, maxLength uint8) bool {
|
||||
// 1 - The prefix is a valid prefix
|
||||
// 2 - The ASN is a valid ASN
|
||||
// 3 - The MaxLength is valid
|
||||
// Will return a deduped slice, as well as total VRPs, IPv4 VRPs, and IPv6 VRPs
|
||||
func processData(vrplistjson []prefixfile.VRPJson, bsklistjson []prefixfile.BgpSecKeyJson) ([]rtr.VRP, []rtr.BgpsecKey, int, int, int) {
|
||||
// Will return a deduped slice, as well as total VRPs, IPv4 VRPs, IPv6 VRPs, BGPsec Keys and ASPA records
|
||||
func processData(vrplistjson []prefixfile.VRPJson,
|
||||
bsklistjson []prefixfile.BgpSecKeyJson,
|
||||
aspajson *prefixfile.ProviderAuthorizationsJson) /*Export*/ ([]rtr.VRP, []rtr.BgpsecKey, []rtr.ASPARecord, int, int, int) {
|
||||
//
|
||||
filterDuplicates := make(map[string]bool)
|
||||
|
||||
// It may be tempting to change this to a simple time.Since() but that will
|
||||
@@ -207,6 +212,7 @@ func processData(vrplistjson []prefixfile.VRPJson, bsklistjson []prefixfile.BgpS
|
||||
|
||||
var vrplist []rtr.VRP
|
||||
var bsklist = make([]rtr.BgpsecKey, 0)
|
||||
var aspalist = make([]rtr.ASPARecord, 0)
|
||||
var countv4 int
|
||||
var countv6 int
|
||||
|
||||
@@ -276,7 +282,35 @@ func processData(vrplistjson []prefixfile.VRPJson, bsklistjson []prefixfile.BgpS
|
||||
})
|
||||
}
|
||||
|
||||
return vrplist, bsklist, countv4 + countv6, countv4, countv6
|
||||
if aspajson != nil {
|
||||
aspalist = handleASPAList(aspajson.IPv4, NowUnix, aspalist, rtr.AFI_IPv4)
|
||||
aspalist = handleASPAList(aspajson.IPv6, NowUnix, aspalist, rtr.AFI_IPv6)
|
||||
}
|
||||
|
||||
return vrplist, bsklist, aspalist, countv4 + countv6, countv4, countv6
|
||||
}
|
||||
|
||||
func handleASPAList(list []prefixfile.ASPAJson, NowUnix int64, aspalist []rtr.ASPARecord, AFI uint8) []rtr.ASPARecord {
|
||||
for _, v := range list {
|
||||
if v.Expires != nil {
|
||||
if int(NowUnix) > int(*v.Expires) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that these are sorted, otherwise they
|
||||
// don't has right.
|
||||
sort.Slice(v.Providers, func(i, j int) bool {
|
||||
return v.Providers[i] < v.Providers[j]
|
||||
})
|
||||
|
||||
aspalist = append(aspalist, rtr.ASPARecord{
|
||||
AFI: AFI,
|
||||
CustomerASN: v.CustomerAsid,
|
||||
Providers: v.Providers,
|
||||
})
|
||||
}
|
||||
return aspalist
|
||||
}
|
||||
|
||||
type IdenticalFile struct {
|
||||
@@ -317,10 +351,10 @@ func (s *state) updateFromNewState() error {
|
||||
vrpsjson = append(kept, asserted...)
|
||||
}
|
||||
|
||||
vrps, bsks, count, countv4, countv6 := processData(vrpsjson, s.lastdata.BgpSecKeys)
|
||||
vrps, bsks, aspas, count, countv4, countv6 := processData(vrpsjson, s.lastdata.BgpSecKeys, s.lastdata.ASPA)
|
||||
|
||||
log.Infof("New update (%v uniques, %v total prefixes).", len(vrps), count)
|
||||
return s.applyUpdateFromNewState(vrps, bsks, sessid, vrpsjson, s.lastdata.BgpSecKeys, countv4, countv6)
|
||||
return s.applyUpdateFromNewState(vrps, bsks, aspas, sessid, vrpsjson, s.lastdata.BgpSecKeys, s.lastdata.ASPA, countv4, countv6)
|
||||
}
|
||||
|
||||
// Update the state based on the currently loaded files
|
||||
@@ -351,16 +385,17 @@ func (s *state) reloadFromCurrentState() error {
|
||||
vrpsjson = append(kept, asserted...)
|
||||
}
|
||||
|
||||
vrps, bsks, count, countv4, countv6 := processData(vrpsjson, s.lastdata.BgpSecKeys)
|
||||
vrps, bsks, aspas, count, countv4, countv6 := processData(vrpsjson, s.lastdata.BgpSecKeys, s.lastdata.ASPA)
|
||||
if s.server.CountVRPs() != count {
|
||||
log.Infof("New update to old state (%v uniques, %v total prefixes). (old %v - new %v)", len(vrps), count, s.server.CountVRPs(), count)
|
||||
return s.applyUpdateFromNewState(vrps, bsks, sessid, vrpsjson, s.lastdata.BgpSecKeys, countv4, countv6)
|
||||
return s.applyUpdateFromNewState(vrps, bsks, aspas, sessid, vrpsjson, s.lastdata.BgpSecKeys, s.lastdata.ASPA, countv4, countv6)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *state) applyUpdateFromNewState(vrps []rtr.VRP, bsks []rtr.BgpsecKey, sessid uint16,
|
||||
vrpsjson []prefixfile.VRPJson, bsksjson []prefixfile.BgpSecKeyJson,
|
||||
func (s *state) applyUpdateFromNewState(vrps []rtr.VRP, bsks []rtr.BgpsecKey, aspas []rtr.ASPARecord,
|
||||
sessid uint16,
|
||||
vrpsjson []prefixfile.VRPJson, bsksjson []prefixfile.BgpSecKeyJson, aspajson *prefixfile.ProviderAuthorizationsJson,
|
||||
countv4 int, countv6 int) error {
|
||||
|
||||
SDs := make([]rtr.SendableData, 0)
|
||||
@@ -370,6 +405,9 @@ func (s *state) applyUpdateFromNewState(vrps []rtr.VRP, bsks []rtr.BgpsecKey, se
|
||||
for _, v := range bsks {
|
||||
SDs = append(SDs, v.Copy())
|
||||
}
|
||||
for _, v := range aspas {
|
||||
SDs = append(SDs, v.Copy())
|
||||
}
|
||||
s.server.AddData(SDs)
|
||||
|
||||
serial, _ := s.server.GetCurrentSerial(sessid)
|
||||
@@ -387,6 +425,7 @@ func (s *state) applyUpdateFromNewState(vrps []rtr.VRP, bsks []rtr.BgpsecKey, se
|
||||
},
|
||||
Data: vrpsjson,
|
||||
BgpSecKeys: bsksjson,
|
||||
ASPA: aspajson,
|
||||
}
|
||||
|
||||
s.lockJson.Unlock()
|
||||
|
||||
@@ -100,7 +100,7 @@ func TestProcessData(t *testing.T) {
|
||||
Expires: &ExpiredTime,
|
||||
},
|
||||
)
|
||||
got, _, count, v4count, v6count := processData(stuff, nil)
|
||||
got, _, _, count, v4count, v6count := processData(stuff, nil, nil)
|
||||
want := []rtr.VRP{
|
||||
{
|
||||
Prefix: mustParseIPNet("192.168.0.0/24"),
|
||||
|
||||
@@ -119,7 +119,21 @@ func (c *ClientSession) StartRW(rd io.Reader, wr io.Writer) error {
|
||||
if c.version == PROTOCOL_VERSION_1 && dec.GetVersion() == PROTOCOL_VERSION_0 {
|
||||
if c.log != nil {
|
||||
c.log.Infof("Downgrading to version 0")
|
||||
}
|
||||
c.version = PROTOCOL_VERSION_0
|
||||
}
|
||||
if c.version == PROTOCOL_VERSION_2 {
|
||||
downgraded := false
|
||||
switch dec.GetVersion() {
|
||||
case PROTOCOL_VERSION_0:
|
||||
c.version = PROTOCOL_VERSION_0
|
||||
downgraded = true
|
||||
case PROTOCOL_VERSION_1:
|
||||
c.version = PROTOCOL_VERSION_1
|
||||
downgraded = true
|
||||
}
|
||||
if c.log != nil && downgraded {
|
||||
c.log.Infof("Downgrading to version %d", c.version)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+62
-1
@@ -772,7 +772,7 @@ func (c *Client) SetDisableVersionCheck(disableCheck bool) {
|
||||
}
|
||||
|
||||
func (c *Client) checkVersion(newversion uint8) {
|
||||
if (!c.versionset || newversion == c.version) && (newversion == PROTOCOL_VERSION_1 || newversion == PROTOCOL_VERSION_0) {
|
||||
if (!c.versionset || newversion == c.version) && (newversion == PROTOCOL_VERSION_2 || newversion == PROTOCOL_VERSION_1 || newversion == PROTOCOL_VERSION_0) {
|
||||
c.SetVersion(newversion)
|
||||
} else {
|
||||
if c.log != nil {
|
||||
@@ -972,6 +972,53 @@ func (bsk *BgpsecKey) GetFlag() uint8 {
|
||||
return bsk.Flags
|
||||
}
|
||||
|
||||
type ASPARecord struct {
|
||||
Flags uint8
|
||||
AFI uint8
|
||||
CustomerASN uint32
|
||||
Providers []uint32
|
||||
}
|
||||
|
||||
func (ASPAr *ASPARecord) Type() string {
|
||||
return "ASPA"
|
||||
}
|
||||
|
||||
func (ASPAr *ASPARecord) String() string {
|
||||
return fmt.Sprintf("ASPA AS%v -> AFI %d, Providers: %v", ASPAr.CustomerASN, ASPAr.AFI, ASPAr.Providers)
|
||||
}
|
||||
|
||||
func (ASPAr *ASPARecord) HashKey() string {
|
||||
return fmt.Sprintf("%v-%x-%v", ASPAr.CustomerASN, ASPAr.AFI, ASPAr.Providers)
|
||||
}
|
||||
|
||||
func (r1 *ASPARecord) Equals(r2 SendableData) bool {
|
||||
if r1.Type() != r2.Type() {
|
||||
return false
|
||||
}
|
||||
|
||||
r2True := r2.(*ASPARecord)
|
||||
return r1.CustomerASN == r2True.CustomerASN && fmt.Sprint(r1.Providers) == fmt.Sprint(r2True.Providers) /*This could be made faster*/
|
||||
}
|
||||
|
||||
func (ASPAr *ASPARecord) Copy() SendableData {
|
||||
cop := ASPARecord{
|
||||
CustomerASN: ASPAr.CustomerASN,
|
||||
AFI: ASPAr.AFI,
|
||||
Flags: ASPAr.Flags,
|
||||
Providers: make([]uint32, 0),
|
||||
}
|
||||
cop.Providers = append(cop.Providers, ASPAr.Providers...)
|
||||
return &cop
|
||||
}
|
||||
|
||||
func (ASPAr *ASPARecord) SetFlag(f uint8) {
|
||||
ASPAr.Flags = f
|
||||
}
|
||||
|
||||
func (ASPAr *ASPARecord) GetFlag() uint8 {
|
||||
return ASPAr.Flags
|
||||
}
|
||||
|
||||
func (c *Client) SendSDs(sessionId uint16, serialNumber uint32, data []SendableData) {
|
||||
pduBegin := &PDUCacheResponse{
|
||||
SessionId: sessionId,
|
||||
@@ -1062,6 +1109,20 @@ func (c *Client) SendData(sd SendableData) {
|
||||
SubjectPublicKeyInfo: t.Pubkey,
|
||||
}
|
||||
c.SendPDU(pdu)
|
||||
case *ASPARecord:
|
||||
if c.version < 2 || c.dontSendBGPsecKeys {
|
||||
return
|
||||
}
|
||||
|
||||
pdu := &PDUASPA{
|
||||
Version: c.version,
|
||||
Flags: t.Flags,
|
||||
AFIFlags: t.AFI,
|
||||
ProviderASCount: uint16(len(t.Providers)),
|
||||
CustomerASNumber: t.CustomerASN,
|
||||
ProviderASNumbers: t.Providers,
|
||||
}
|
||||
c.SendPDU(pdu)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
-1
@@ -49,6 +49,9 @@ const (
|
||||
PDU_ERROR_WITHDRAWUNKNOWN = 6
|
||||
PDU_ERROR_DUPANNOUNCE = 7
|
||||
|
||||
AFI_IPv4 = uint8(0)
|
||||
AFI_IPv6 = uint8(1)
|
||||
|
||||
TYPE_UNKNOWN = iota
|
||||
TYPE_PLAIN
|
||||
TYPE_TLS
|
||||
@@ -376,7 +379,7 @@ func (pdu *PDUEndOfData) Write(wr io.Writer) {
|
||||
if pdu.Version == PROTOCOL_VERSION_0 {
|
||||
binary.Write(wr, binary.BigEndian, uint32(12))
|
||||
binary.Write(wr, binary.BigEndian, pdu.SerialNumber)
|
||||
} else if pdu.Version == PROTOCOL_VERSION_1 {
|
||||
} else if pdu.Version == PROTOCOL_VERSION_1 || pdu.Version == PROTOCOL_VERSION_2 {
|
||||
binary.Write(wr, binary.BigEndian, uint32(24))
|
||||
binary.Write(wr, binary.BigEndian, pdu.SerialNumber)
|
||||
binary.Write(wr, binary.BigEndian, pdu.RefreshInterval)
|
||||
|
||||
@@ -30,9 +30,10 @@ func (md MetaData) GetBuildTime() time.Time {
|
||||
}
|
||||
|
||||
type VRPList struct {
|
||||
Metadata MetaData `json:"metadata,omitempty"`
|
||||
Data []VRPJson `json:"roas"` // for historical reasons this is called 'roas', but should've been called vrps
|
||||
BgpSecKeys []BgpSecKeyJson `json:"bgpsec_keys,omitempty"`
|
||||
Metadata MetaData `json:"metadata,omitempty"`
|
||||
Data []VRPJson `json:"roas"` // for historical reasons this is called 'roas', but should've been called vrps
|
||||
BgpSecKeys []BgpSecKeyJson `json:"bgpsec_keys,omitempty"`
|
||||
ASPA *ProviderAuthorizationsJson `json:"provider_authorizations,omitempty"`
|
||||
}
|
||||
|
||||
type BgpSecKeyJson struct {
|
||||
@@ -48,6 +49,18 @@ type BgpSecKeyJson struct {
|
||||
Ski string `json:"ski"`
|
||||
}
|
||||
|
||||
// ASPA
|
||||
type ProviderAuthorizationsJson struct {
|
||||
IPv4 []ASPAJson `json:"ipv4"`
|
||||
IPv6 []ASPAJson `json:"ipv6"`
|
||||
}
|
||||
|
||||
type ASPAJson struct {
|
||||
CustomerAsid uint32 `json:"customer_asid"`
|
||||
Expires *uint32 `json:"expires,omitempty"`
|
||||
Providers []uint32 `json:"providers"`
|
||||
}
|
||||
|
||||
func (vrp *VRPJson) GetASN2() (uint32, error) {
|
||||
switch asnc := vrp.ASN.(type) {
|
||||
case string:
|
||||
|
||||
Reference in New Issue
Block a user