summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--server/rpki.go242
-rw-r--r--server/rpki_test.go99
2 files changed, 162 insertions, 179 deletions
diff --git a/server/rpki.go b/server/rpki.go
index aadb2fdd..4f073d5e 100644
--- a/server/rpki.go
+++ b/server/rpki.go
@@ -33,26 +33,53 @@ import (
"gopkg.in/tomb.v2"
)
+type ipPrefix struct {
+ Prefix net.IP
+ Length uint8
+}
+
type roaBucket struct {
- Prefix net.IP
- PrefixLen uint8
- entries []*roa
+ Prefix *ipPrefix
+ entries []*ROA
}
-type roa struct {
- bucket *roaBucket
- Src string
+type ROA struct {
+ Family int
+ Prefix *ipPrefix
MaxLen uint8
AS uint32
+ Src string
+}
+
+func NewROA(family int, prefixByte []byte, prefixLen uint8, maxLen uint8, as uint32, src string) *ROA {
+ p := make([]byte, len(prefixByte))
+ copy(p, prefixByte)
+ return &ROA{
+ Family: family,
+ Prefix: &ipPrefix{
+ Prefix: p,
+ Length: prefixLen,
+ },
+ MaxLen: maxLen,
+ AS: as,
+ Src: src,
+ }
+}
+
+func (r *ROA) Equal(roa *ROA) bool {
+ if r.MaxLen == roa.MaxLen && r.Src == roa.Src && r.AS == roa.AS {
+ return true
+ }
+ return false
}
-func (r *roa) toApiStruct() *api.ROA {
+func (r *ROA) toApiStruct() *api.ROA {
host, port, _ := net.SplitHostPort(r.Src)
return &api.ROA{
As: r.AS,
Maxlen: uint32(r.MaxLen),
- Prefixlen: uint32(r.bucket.PrefixLen),
- Prefix: r.bucket.Prefix.String(),
+ Prefixlen: uint32(r.Prefix.Length),
+ Prefix: r.Prefix.Prefix.String(),
Conf: &api.RPKIConf{
Address: host,
RemotePort: port,
@@ -125,13 +152,7 @@ func newROAManager(as uint32, servers []config.RpkiServer) (*roaManager, error)
if c.RecordLifetime == 0 {
c.RecordLifetime = 3600
}
- client := &roaClient{
- host: net.JoinHostPort(c.Address, strconv.Itoa(int(c.Port))),
- eventCh: m.eventCh,
- records: make(map[int]uint32),
- prefixes: make(map[int]uint32),
- lifetime: c.RecordLifetime,
- }
+ client := NewRoaClient(c.Address, strconv.Itoa(int(c.Port)), m.eventCh, c.RecordLifetime)
m.clientMap[client.host] = client
client.t.Go(client.tryConnect)
}
@@ -144,7 +165,7 @@ func (m *roaManager) deleteAllROA(network string) {
deleteKeys := make([]string, 0, tree.Len())
tree.Walk(func(s string, v interface{}) bool {
b, _ := v.(*roaBucket)
- newEntries := make([]*roa, 0, len(b.entries))
+ newEntries := make([]*ROA, 0, len(b.entries))
for _, r := range b.entries {
if r.Src != network {
newEntries = append(newEntries, r)
@@ -234,105 +255,56 @@ func (m *roaManager) handleROAEvent(ev *roaClientEvent) {
}
}
-func deleteROA(client *roaClient, family int, tree *radix.Tree, as uint32, prefix []byte, prefixLen, maxLen uint8) {
- host := client.host
- key := table.IpToRadixkey(prefix, prefixLen)
+func (m *roaManager) roa2tree(roa *ROA) (*radix.Tree, string) {
+ tree := m.roas[bgp.RF_IPv4_UC]
+ if roa.Family == bgp.AFI_IP6 {
+ tree = m.roas[bgp.RF_IPv6_UC]
+ }
+ return tree, table.IpToRadixkey(roa.Prefix.Prefix, roa.Prefix.Length)
+}
+
+func (m *roaManager) deleteROA(roa *ROA) {
+ tree, key := m.roa2tree(roa)
b, _ := tree.Get(key)
- isDeleted := func() bool {
- if b != nil {
- bucket := b.(*roaBucket)
- newEntries := make([]*roa, 0, len(bucket.entries))
- for _, r := range bucket.entries {
- if r.MaxLen != maxLen || r.Src != host || r.AS != as {
- newEntries = append(newEntries, r)
- }
- }
- if len(newEntries) != len(bucket.entries) {
- bucket.entries = newEntries
- if len(newEntries) == 0 {
- tree.Delete(key)
- }
- return true
+ if b != nil {
+ bucket := b.(*roaBucket)
+ newEntries := make([]*ROA, 0, len(bucket.entries))
+ for _, r := range bucket.entries {
+ if !r.Equal(roa) {
+ newEntries = append(newEntries, r)
}
}
- return false
- }()
- if isDeleted {
- client.records[family]--
- isNoPrefix := func() bool {
- if b, _ := tree.Get(key); b != nil {
- bucket := b.(*roaBucket)
- for _, r := range bucket.entries {
- if r.Src == host {
- return false
- }
- }
- return true
- } else {
- return true
+ if len(newEntries) != len(bucket.entries) {
+ bucket.entries = newEntries
+ if len(newEntries) == 0 {
+ tree.Delete(key)
}
- }()
- if isNoPrefix {
- client.prefixes[family]--
+ return
}
- } else {
- log.Info("can't withdraw a roa", net.IP(prefix).String(), as, prefixLen, maxLen)
}
+ log.Info("can't withdraw a roa", roa.Prefix.Prefix.String(), roa.Prefix.Length, roa.AS, roa.MaxLen)
}
-func addROA(client *roaClient, family int, tree *radix.Tree, as uint32, prefix []byte, prefixLen, maxLen uint8) {
- host := client.host
- key := table.IpToRadixkey(prefix, prefixLen)
+func (m *roaManager) addROA(roa *ROA) {
+ tree, key := m.roa2tree(roa)
b, _ := tree.Get(key)
+ var bucket *roaBucket
if b == nil {
- p := make([]byte, len(prefix))
- copy(p, prefix)
-
- r := &roa{
- AS: as,
- MaxLen: maxLen,
- Src: host,
- }
-
- b := &roaBucket{
- PrefixLen: prefixLen,
- Prefix: p,
- entries: []*roa{r},
+ bucket = &roaBucket{
+ Prefix: roa.Prefix,
+ entries: make([]*ROA, 0),
}
- r.bucket = b
-
- tree.Insert(key, b)
- client.prefixes[family]++
- client.records[family]++
+ tree.Insert(key, bucket)
} else {
- bucket := b.(*roaBucket)
- isNewPrefix := func() bool {
- for _, r := range bucket.entries {
- if r.Src == host {
- return false
- }
- }
- return true
- }()
- if isNewPrefix {
- client.prefixes[family]++
- }
-
+ bucket = b.(*roaBucket)
for _, r := range bucket.entries {
- if r.MaxLen == maxLen && r.Src == host && r.AS == as {
- // we already have
+ if r.Equal(roa) {
+ // we already have the same one
return
}
}
- r := &roa{
- bucket: bucket,
- MaxLen: maxLen,
- AS: as,
- Src: host,
- }
- bucket.entries = append(bucket.entries, r)
- client.records[family]++
}
+ bucket.entries = append(bucket.entries, roa)
}
func (c *roaManager) handleRTRMsg(client *roaClient, state *config.RpkiServerState, buf []byte) {
@@ -354,20 +326,18 @@ func (c *roaManager) handleRTRMsg(client *roaClient, state *config.RpkiServerSta
case *bgp.RTRCacheResponse:
received.CacheResponse++
case *bgp.RTRIPPrefix:
- var tree *radix.Tree
family := bgp.AFI_IP
if msg.Type == bgp.RTR_IPV4_PREFIX {
received.Ipv4Prefix++
- tree = c.roas[bgp.RF_IPv4_UC]
} else {
family = bgp.AFI_IP6
received.Ipv6Prefix++
- tree = c.roas[bgp.RF_IPv6_UC]
}
+ roa := NewROA(family, msg.Prefix, msg.PrefixLen, msg.MaxLen, msg.AS, client.host)
if (msg.Flags & 1) == 1 {
- addROA(client, family, tree, msg.AS, msg.Prefix, msg.PrefixLen, msg.MaxLen)
+ c.addROA(roa)
} else {
- deleteROA(client, family, tree, msg.AS, msg.Prefix, msg.PrefixLen, msg.MaxLen)
+ c.deleteROA(roa)
}
case *bgp.RTREndOfData:
received.EndOfData++
@@ -388,6 +358,32 @@ func (c *roaManager) handleGRPC(grpcReq *GrpcRequest) {
switch grpcReq.RequestType {
case REQ_RPKI:
results := make([]*GrpcResponse, 0)
+
+ f := func(tree *radix.Tree) (map[string]uint32, map[string]uint32) {
+ records := make(map[string]uint32)
+ prefixes := make(map[string]uint32)
+
+ tree.Walk(func(s string, v interface{}) bool {
+ b, _ := v.(*roaBucket)
+ tmpRecords := make(map[string]uint32)
+ for _, roa := range b.entries {
+ tmpRecords[roa.Src]++
+ }
+
+ for src, r := range tmpRecords {
+ if r > 0 {
+ records[src] += r
+ prefixes[src]++
+ }
+ }
+ return false
+ })
+ return records, prefixes
+ }
+
+ recordsV4, prefixesV4 := f(c.roas[bgp.RF_IPv4_UC])
+ recordsV6, prefixesV6 := f(c.roas[bgp.RF_IPv6_UC])
+
for _, client := range c.clientMap {
state := client.state
addr, port, _ := net.SplitHostPort(client.host)
@@ -397,6 +393,14 @@ func (c *roaManager) handleGRPC(grpcReq *GrpcRequest) {
if client.conn == nil {
up = false
}
+
+ f := func(m map[string]uint32, key string) uint32 {
+ if r, ok := m[key]; ok {
+ return r
+ }
+ return 0
+ }
+
rpki := &api.RPKI{
Conf: &api.RPKIConf{
Address: addr,
@@ -406,10 +410,10 @@ func (c *roaManager) handleGRPC(grpcReq *GrpcRequest) {
Uptime: state.Uptime,
Downtime: state.Downtime,
Up: up,
- RecordIpv4: client.records[bgp.AFI_IP],
- RecordIpv6: client.records[bgp.AFI_IP6],
- PrefixIpv4: client.prefixes[bgp.AFI_IP],
- PrefixIpv6: client.prefixes[bgp.AFI_IP6],
+ RecordIpv4: f(recordsV4, client.host),
+ RecordIpv6: f(recordsV6, client.host),
+ PrefixIpv4: f(prefixesV4, client.host),
+ PrefixIpv6: f(prefixesV6, client.host),
Serial: client.serialNumber,
ReceivedIpv4: received.Ipv4Prefix,
ReceivedIpv6: received.Ipv6Prefix,
@@ -468,32 +472,32 @@ func (c *roaManager) handleGRPC(grpcReq *GrpcRequest) {
}
}
-func validatePath(ownAs uint32, tree *radix.Tree, cidr string, asPath *bgp.PathAttributeAsPath) (config.RpkiValidationResultType, []*roa) {
+func validatePath(ownAs uint32, tree *radix.Tree, cidr string, asPath *bgp.PathAttributeAsPath) (config.RpkiValidationResultType, []*ROA) {
var as uint32
if asPath == nil || len(asPath.Value) == 0 {
- return config.RPKI_VALIDATION_RESULT_TYPE_NOT_FOUND, []*roa{}
+ return config.RPKI_VALIDATION_RESULT_TYPE_NOT_FOUND, []*ROA{}
}
asParam := asPath.Value[len(asPath.Value)-1].(*bgp.As4PathParam)
switch asParam.Type {
case bgp.BGP_ASPATH_ATTR_TYPE_SEQ:
if len(asParam.AS) == 0 {
- return config.RPKI_VALIDATION_RESULT_TYPE_NOT_FOUND, []*roa{}
+ return config.RPKI_VALIDATION_RESULT_TYPE_NOT_FOUND, []*ROA{}
}
as = asParam.AS[len(asParam.AS)-1]
case bgp.BGP_ASPATH_ATTR_TYPE_CONFED_SET, bgp.BGP_ASPATH_ATTR_TYPE_CONFED_SEQ:
as = ownAs
default:
- return config.RPKI_VALIDATION_RESULT_TYPE_NOT_FOUND, []*roa{}
+ return config.RPKI_VALIDATION_RESULT_TYPE_NOT_FOUND, []*ROA{}
}
_, n, _ := net.ParseCIDR(cidr)
ones, _ := n.Mask.Size()
prefixLen := uint8(ones)
_, b, _ := tree.LongestPrefix(table.IpToRadixkey(n.IP, prefixLen))
if b == nil {
- return config.RPKI_VALIDATION_RESULT_TYPE_NOT_FOUND, []*roa{}
+ return config.RPKI_VALIDATION_RESULT_TYPE_NOT_FOUND, []*ROA{}
}
- roaList := make([]*roa, 0)
+ roaList := make([]*ROA, 0)
result := config.RPKI_VALIDATION_RESULT_TYPE_INVALID
bucket, _ := b.(*roaBucket)
@@ -556,12 +560,18 @@ type roaClient struct {
eventCh chan *roaClientEvent
sessionID uint16
serialNumber uint32
- prefixes map[int]uint32
- records map[int]uint32
timer *time.Timer
lifetime int64
}
+func NewRoaClient(address, port string, ch chan *roaClientEvent, lifetime int64) *roaClient {
+ return &roaClient{
+ host: net.JoinHostPort(address, port),
+ eventCh: ch,
+ lifetime: lifetime,
+ }
+}
+
func (c *roaClient) enable(serial uint32) error {
if c.conn != nil {
r := bgp.NewRTRSerialQuery(c.sessionID, serial)
diff --git a/server/rpki_test.go b/server/rpki_test.go
index 3d7be7b3..aa0a85be 100644
--- a/server/rpki_test.go
+++ b/server/rpki_test.go
@@ -60,16 +60,13 @@ func validateOne(tree *radix.Tree, cidr, aspathStr string) config.RpkiValidation
func TestValidate0(t *testing.T) {
assert := assert.New(t)
- client := &roaClient{
- records: make(map[int]uint32),
- prefixes: make(map[int]uint32),
- }
- tree := radix.New()
- addROA(client, bgp.AFI_IP, tree, 100, net.ParseIP("192.168.0.0").To4(), 24, 32)
- addROA(client, bgp.AFI_IP, tree, 200, net.ParseIP("192.168.0.0").To4(), 24, 24)
+ manager, _ := newROAManager(0, []config.RpkiServer{})
+ manager.addROA(NewROA(bgp.AFI_IP, net.ParseIP("192.168.0.0").To4(), 24, 32, 100, ""))
+ manager.addROA(NewROA(bgp.AFI_IP, net.ParseIP("192.168.0.0").To4(), 24, 24, 200, ""))
var r config.RpkiValidationResultType
+ tree := manager.roas[bgp.RF_IPv4_UC]
r = validateOne(tree, "192.168.0.0/24", "100")
assert.Equal(r, config.RPKI_VALIDATION_RESULT_TYPE_VALID)
@@ -92,15 +89,12 @@ func TestValidate0(t *testing.T) {
func TestValidate1(t *testing.T) {
assert := assert.New(t)
- client := &roaClient{
- records: make(map[int]uint32),
- prefixes: make(map[int]uint32),
- }
- tree := radix.New()
- addROA(client, bgp.AFI_IP, tree, 65000, net.ParseIP("10.0.0.0").To4(), 16, 16)
+ manager, _ := newROAManager(0, []config.RpkiServer{})
+ manager.addROA(NewROA(bgp.AFI_IP, net.ParseIP("10.0.0.0").To4(), 16, 16, 65000, ""))
var r config.RpkiValidationResultType
+ tree := manager.roas[bgp.RF_IPv4_UC]
r = validateOne(tree, "10.0.0.0/16", "65000")
assert.Equal(r, config.RPKI_VALIDATION_RESULT_TYPE_VALID)
@@ -111,10 +105,11 @@ func TestValidate1(t *testing.T) {
func TestValidate2(t *testing.T) {
assert := assert.New(t)
- tree := radix.New()
+ manager, _ := newROAManager(0, []config.RpkiServer{})
var r config.RpkiValidationResultType
+ tree := manager.roas[bgp.RF_IPv4_UC]
r = validateOne(tree, "10.0.0.0/16", "65000")
assert.Equal(r, config.RPKI_VALIDATION_RESULT_TYPE_NOT_FOUND)
@@ -125,41 +120,35 @@ func TestValidate2(t *testing.T) {
func TestValidate3(t *testing.T) {
assert := assert.New(t)
- client := &roaClient{
- records: make(map[int]uint32),
- prefixes: make(map[int]uint32),
- }
- tree1 := radix.New()
- addROA(client, bgp.AFI_IP, tree1, 65000, net.ParseIP("10.0.0.0").To4(), 16, 16)
+ manager, _ := newROAManager(0, []config.RpkiServer{})
+ manager.addROA(NewROA(bgp.AFI_IP, net.ParseIP("10.0.0.0").To4(), 16, 16, 65000, ""))
var r config.RpkiValidationResultType
- r = validateOne(tree1, "10.0.0.0/8", "65000")
+ tree := manager.roas[bgp.RF_IPv4_UC]
+ r = validateOne(tree, "10.0.0.0/8", "65000")
assert.Equal(r, config.RPKI_VALIDATION_RESULT_TYPE_NOT_FOUND)
- r = validateOne(tree1, "10.0.0.0/17", "65000")
+ r = validateOne(tree, "10.0.0.0/17", "65000")
assert.Equal(r, config.RPKI_VALIDATION_RESULT_TYPE_INVALID)
- tree2 := radix.New()
- addROA(client, bgp.AFI_IP, tree2, 65000, net.ParseIP("10.0.0.0").To4(), 16, 24)
+ manager, _ = newROAManager(0, []config.RpkiServer{})
+ manager.addROA(NewROA(bgp.AFI_IP, net.ParseIP("10.0.0.0").To4(), 16, 24, 65000, ""))
- r = validateOne(tree2, "10.0.0.0/17", "65000")
+ tree = manager.roas[bgp.RF_IPv4_UC]
+ r = validateOne(tree, "10.0.0.0/17", "65000")
assert.Equal(r, config.RPKI_VALIDATION_RESULT_TYPE_VALID)
}
func TestValidate4(t *testing.T) {
assert := assert.New(t)
- client := &roaClient{
- records: make(map[int]uint32),
- prefixes: make(map[int]uint32),
- }
- tree := radix.New()
- addROA(client, bgp.AFI_IP, tree, 65000, net.ParseIP("10.0.0.0").To4(), 16, 16)
- addROA(client, bgp.AFI_IP, tree, 65001, net.ParseIP("10.0.0.0").To4(), 16, 16)
+ manager, _ := newROAManager(0, []config.RpkiServer{})
+ manager.addROA(NewROA(bgp.AFI_IP, net.ParseIP("10.0.0.0").To4(), 16, 16, 65000, ""))
+ manager.addROA(NewROA(bgp.AFI_IP, net.ParseIP("10.0.0.0").To4(), 16, 16, 65001, ""))
var r config.RpkiValidationResultType
-
+ tree := manager.roas[bgp.RF_IPv4_UC]
r = validateOne(tree, "10.0.0.0/16", "65000")
assert.Equal(r, config.RPKI_VALIDATION_RESULT_TYPE_VALID)
@@ -170,16 +159,12 @@ func TestValidate4(t *testing.T) {
func TestValidate5(t *testing.T) {
assert := assert.New(t)
- client := &roaClient{
- records: make(map[int]uint32),
- prefixes: make(map[int]uint32),
- }
- tree := radix.New()
- addROA(client, bgp.AFI_IP, tree, 65000, net.ParseIP("10.0.0.0").To4(), 17, 17)
- addROA(client, bgp.AFI_IP, tree, 65000, net.ParseIP("10.0.128.0").To4(), 17, 17)
+ manager, _ := newROAManager(0, []config.RpkiServer{})
+ manager.addROA(NewROA(bgp.AFI_IP, net.ParseIP("10.0.0.0").To4(), 17, 17, 65000, ""))
+ manager.addROA(NewROA(bgp.AFI_IP, net.ParseIP("10.0.128.0").To4(), 17, 17, 65000, ""))
var r config.RpkiValidationResultType
-
+ tree := manager.roas[bgp.RF_IPv4_UC]
r = validateOne(tree, "10.0.0.0/16", "65000")
assert.Equal(r, config.RPKI_VALIDATION_RESULT_TYPE_NOT_FOUND)
}
@@ -187,15 +172,11 @@ func TestValidate5(t *testing.T) {
func TestValidate6(t *testing.T) {
assert := assert.New(t)
- client := &roaClient{
- records: make(map[int]uint32),
- prefixes: make(map[int]uint32),
- }
- tree := radix.New()
- addROA(client, bgp.AFI_IP, tree, 0, net.ParseIP("10.0.0.0").To4(), 8, 32)
+ manager, _ := newROAManager(0, []config.RpkiServer{})
+ manager.addROA(NewROA(bgp.AFI_IP, net.ParseIP("10.0.0.0").To4(), 8, 32, 0, ""))
var r config.RpkiValidationResultType
-
+ tree := manager.roas[bgp.RF_IPv4_UC]
r = validateOne(tree, "10.0.0.0/7", "65000")
assert.Equal(r, config.RPKI_VALIDATION_RESULT_TYPE_NOT_FOUND)
@@ -209,15 +190,11 @@ func TestValidate6(t *testing.T) {
func TestValidate7(t *testing.T) {
assert := assert.New(t)
- client := &roaClient{
- records: make(map[int]uint32),
- prefixes: make(map[int]uint32),
- }
- tree := radix.New()
- addROA(client, bgp.AFI_IP, tree, 65000, net.ParseIP("10.0.0.0").To4(), 16, 24)
+ manager, _ := newROAManager(0, []config.RpkiServer{})
+ manager.addROA(NewROA(bgp.AFI_IP, net.ParseIP("10.0.0.0").To4(), 16, 24, 65000, ""))
var r config.RpkiValidationResultType
-
+ tree := manager.roas[bgp.RF_IPv4_UC]
r = validateOne(tree, "10.0.0.0/24", "{65000}")
assert.Equal(r, config.RPKI_VALIDATION_RESULT_TYPE_NOT_FOUND)
@@ -231,16 +208,12 @@ func TestValidate7(t *testing.T) {
func TestValidate8(t *testing.T) {
assert := assert.New(t)
- client := &roaClient{
- records: make(map[int]uint32),
- prefixes: make(map[int]uint32),
- }
- tree := radix.New()
- addROA(client, bgp.AFI_IP, tree, 0, net.ParseIP("10.0.0.0").To4(), 16, 24)
- addROA(client, bgp.AFI_IP, tree, 65000, net.ParseIP("10.0.0.0").To4(), 16, 24)
+ manager, _ := newROAManager(0, []config.RpkiServer{})
+ manager.addROA(NewROA(bgp.AFI_IP, net.ParseIP("10.0.0.0").To4(), 16, 24, 0, ""))
+ manager.addROA(NewROA(bgp.AFI_IP, net.ParseIP("10.0.0.0").To4(), 16, 24, 65000, ""))
var r config.RpkiValidationResultType
-
+ tree := manager.roas[bgp.RF_IPv4_UC]
r = validateOne(tree, "10.0.0.0/24", "65000")
assert.Equal(r, config.RPKI_VALIDATION_RESULT_TYPE_VALID)