diff options
author | FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> | 2016-02-21 06:44:02 -0800 |
---|---|---|
committer | FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> | 2016-02-21 06:44:02 -0800 |
commit | bbed1307daa2cda8434ac5f91ae68f41fb59461e (patch) | |
tree | 39696c072fa0f33da23568311e7de762cb1794bb /server | |
parent | 7899f30f3a8875256b49c579953ca5cee3fe7eaf (diff) |
rpki: fix the numbers of records and prefixes about removal
Let's calculate the numbers of records and prefixes when they are
necessary. This fixes a bug that the numbers of records and prefixes
in deleteAllROA().
Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
Diffstat (limited to 'server')
-rw-r--r-- | server/rpki.go | 242 | ||||
-rw-r--r-- | server/rpki_test.go | 99 |
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) |