github.com/osrg/gobgp@v2.0.0+incompatible/pkg/server/rpki.go (about) 1 // Copyright (C) 2015,2016 Nippon Telegraph and Telephone Corporation. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 12 // implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 16 package server 17 18 import ( 19 "encoding/binary" 20 "fmt" 21 "io" 22 "net" 23 "sort" 24 "strconv" 25 "time" 26 27 "github.com/osrg/gobgp/internal/pkg/config" 28 "github.com/osrg/gobgp/internal/pkg/table" 29 "github.com/osrg/gobgp/pkg/packet/bgp" 30 "github.com/osrg/gobgp/pkg/packet/rtr" 31 32 "github.com/armon/go-radix" 33 log "github.com/sirupsen/logrus" 34 "golang.org/x/net/context" 35 ) 36 37 const ( 38 connectRetryInterval = 30 39 ) 40 41 func before(a, b uint32) bool { 42 return int32(a-b) < 0 43 } 44 45 type roaBucket struct { 46 Prefix *table.IPPrefix 47 entries []*table.ROA 48 } 49 50 func (r *roaBucket) GetEntries() []*table.ROA { 51 return r.entries 52 } 53 54 type roas []*table.ROA 55 56 func (r roas) Len() int { 57 return len(r) 58 } 59 60 func (r roas) Swap(i, j int) { 61 r[i], r[j] = r[j], r[i] 62 } 63 64 func (r roas) Less(i, j int) bool { 65 r1 := r[i] 66 r2 := r[j] 67 68 if r1.MaxLen < r2.MaxLen { 69 return true 70 } else if r1.MaxLen > r2.MaxLen { 71 return false 72 } 73 74 if r1.AS < r2.AS { 75 return true 76 } 77 return false 78 } 79 80 type roaEventType uint8 81 82 const ( 83 roaConnected roaEventType = iota 84 roaDisconnected 85 roaRTR 86 roaLifetimeout 87 ) 88 89 type roaEvent struct { 90 EventType roaEventType 91 Src string 92 Data []byte 93 conn *net.TCPConn 94 } 95 96 type roaManager struct { 97 AS uint32 98 Roas map[bgp.RouteFamily]*radix.Tree 99 eventCh chan *roaEvent 100 clientMap map[string]*roaClient 101 } 102 103 func newROAManager(as uint32) (*roaManager, error) { 104 m := &roaManager{ 105 AS: as, 106 Roas: make(map[bgp.RouteFamily]*radix.Tree), 107 } 108 m.Roas[bgp.RF_IPv4_UC] = radix.New() 109 m.Roas[bgp.RF_IPv6_UC] = radix.New() 110 m.eventCh = make(chan *roaEvent) 111 m.clientMap = make(map[string]*roaClient) 112 return m, nil 113 } 114 115 func (m *roaManager) enabled() bool { 116 return len(m.clientMap) != 0 117 } 118 119 func (m *roaManager) SetAS(as uint32) error { 120 if m.AS != 0 { 121 return fmt.Errorf("AS was already configured") 122 } 123 m.AS = as 124 return nil 125 } 126 127 func (m *roaManager) AddServer(host string, lifetime int64) error { 128 address, port, err := net.SplitHostPort(host) 129 if err != nil { 130 return err 131 } 132 if lifetime == 0 { 133 lifetime = 3600 134 } 135 if _, ok := m.clientMap[host]; ok { 136 return fmt.Errorf("ROA server exists %s", host) 137 } 138 m.clientMap[host] = newRoaClient(address, port, m.eventCh, lifetime) 139 return nil 140 } 141 142 func (m *roaManager) DeleteServer(host string) error { 143 client, ok := m.clientMap[host] 144 if !ok { 145 return fmt.Errorf("ROA server doesn't exists %s", host) 146 } 147 client.stop() 148 m.deleteAllROA(host) 149 delete(m.clientMap, host) 150 return nil 151 } 152 153 func (m *roaManager) deleteAllROA(network string) { 154 for _, tree := range m.Roas { 155 deleteKeys := make([]string, 0, tree.Len()) 156 tree.Walk(func(s string, v interface{}) bool { 157 b, _ := v.(*roaBucket) 158 newEntries := make([]*table.ROA, 0, len(b.entries)) 159 for _, r := range b.entries { 160 if r.Src != network { 161 newEntries = append(newEntries, r) 162 } 163 } 164 if len(newEntries) > 0 { 165 b.entries = newEntries 166 } else { 167 deleteKeys = append(deleteKeys, s) 168 } 169 return false 170 }) 171 for _, key := range deleteKeys { 172 tree.Delete(key) 173 } 174 } 175 } 176 177 func (m *roaManager) Enable(address string) error { 178 for network, client := range m.clientMap { 179 add, _, _ := net.SplitHostPort(network) 180 if add == address { 181 client.enable(client.serialNumber) 182 return nil 183 } 184 } 185 return fmt.Errorf("ROA server not found %s", address) 186 } 187 188 func (m *roaManager) Disable(address string) error { 189 for network, client := range m.clientMap { 190 add, _, _ := net.SplitHostPort(network) 191 if add == address { 192 client.reset() 193 m.deleteAllROA(add) 194 return nil 195 } 196 } 197 return fmt.Errorf("ROA server not found %s", address) 198 } 199 200 func (m *roaManager) Reset(address string) error { 201 return m.Disable(address) 202 } 203 204 func (m *roaManager) SoftReset(address string) error { 205 for network, client := range m.clientMap { 206 add, _, _ := net.SplitHostPort(network) 207 if add == address { 208 client.softReset() 209 m.deleteAllROA(network) 210 return nil 211 } 212 } 213 return fmt.Errorf("ROA server not found %s", address) 214 } 215 216 func (m *roaManager) ReceiveROA() chan *roaEvent { 217 return m.eventCh 218 } 219 220 func (c *roaClient) lifetimeout() { 221 c.eventCh <- &roaEvent{ 222 EventType: roaLifetimeout, 223 Src: c.host, 224 } 225 } 226 227 func (m *roaManager) HandleROAEvent(ev *roaEvent) { 228 client, y := m.clientMap[ev.Src] 229 if !y { 230 if ev.EventType == roaConnected { 231 ev.conn.Close() 232 } 233 log.WithFields(log.Fields{"Topic": "rpki"}).Errorf("Can't find %s ROA server configuration", ev.Src) 234 return 235 } 236 switch ev.EventType { 237 case roaDisconnected: 238 log.WithFields(log.Fields{"Topic": "rpki"}).Infof("ROA server %s is disconnected", ev.Src) 239 client.state.Downtime = time.Now().Unix() 240 // clear state 241 client.endOfData = false 242 client.pendingROAs = make([]*table.ROA, 0) 243 client.state.RpkiMessages = config.RpkiMessages{} 244 client.conn = nil 245 go client.tryConnect() 246 client.timer = time.AfterFunc(time.Duration(client.lifetime)*time.Second, client.lifetimeout) 247 client.oldSessionID = client.sessionID 248 case roaConnected: 249 log.WithFields(log.Fields{"Topic": "rpki"}).Infof("ROA server %s is connected", ev.Src) 250 client.conn = ev.conn 251 client.state.Uptime = time.Now().Unix() 252 go client.established() 253 case roaRTR: 254 m.handleRTRMsg(client, &client.state, ev.Data) 255 case roaLifetimeout: 256 // a) already reconnected but hasn't received 257 // EndOfData -> needs to delete stale ROAs 258 // b) not reconnected -> needs to delete stale ROAs 259 // 260 // c) already reconnected and received EndOfData so 261 // all stale ROAs were deleted -> timer was cancelled 262 // so should not be here. 263 if client.oldSessionID != client.sessionID { 264 log.WithFields(log.Fields{"Topic": "rpki"}).Infof("Reconnected to %s. Ignore timeout", client.host) 265 } else { 266 log.WithFields(log.Fields{"Topic": "rpki"}).Infof("Deleting all ROAs due to timeout with:%s", client.host) 267 m.deleteAllROA(client.host) 268 } 269 } 270 } 271 272 func (m *roaManager) roa2tree(roa *table.ROA) (*radix.Tree, string) { 273 tree := m.Roas[bgp.RF_IPv4_UC] 274 if roa.Family == bgp.AFI_IP6 { 275 tree = m.Roas[bgp.RF_IPv6_UC] 276 } 277 return tree, table.IpToRadixkey(roa.Prefix.Prefix, roa.Prefix.Length) 278 } 279 280 func (m *roaManager) deleteROA(roa *table.ROA) { 281 tree, key := m.roa2tree(roa) 282 b, _ := tree.Get(key) 283 if b != nil { 284 bucket := b.(*roaBucket) 285 newEntries := make([]*table.ROA, 0, len(bucket.entries)) 286 for _, r := range bucket.entries { 287 if !r.Equal(roa) { 288 newEntries = append(newEntries, r) 289 } 290 } 291 if len(newEntries) != len(bucket.entries) { 292 bucket.entries = newEntries 293 if len(newEntries) == 0 { 294 tree.Delete(key) 295 } 296 return 297 } 298 } 299 log.WithFields(log.Fields{ 300 "Topic": "rpki", 301 "Prefix": roa.Prefix.Prefix.String(), 302 "Prefix Length": roa.Prefix.Length, 303 "AS": roa.AS, 304 "Max Length": roa.MaxLen, 305 }).Info("Can't withdraw a ROA") 306 } 307 308 func (m *roaManager) DeleteROA(roa *table.ROA) { 309 m.deleteROA(roa) 310 } 311 312 func (m *roaManager) addROA(roa *table.ROA) { 313 tree, key := m.roa2tree(roa) 314 b, _ := tree.Get(key) 315 var bucket *roaBucket 316 if b == nil { 317 bucket = &roaBucket{ 318 Prefix: roa.Prefix, 319 entries: make([]*table.ROA, 0), 320 } 321 tree.Insert(key, bucket) 322 } else { 323 bucket = b.(*roaBucket) 324 for _, r := range bucket.entries { 325 if r.Equal(roa) { 326 // we already have the same one 327 return 328 } 329 } 330 } 331 bucket.entries = append(bucket.entries, roa) 332 } 333 334 func (m *roaManager) AddROA(roa *table.ROA) { 335 m.addROA(roa) 336 } 337 338 func (m *roaManager) handleRTRMsg(client *roaClient, state *config.RpkiServerState, buf []byte) { 339 received := &state.RpkiMessages.RpkiReceived 340 341 m1, err := rtr.ParseRTR(buf) 342 if err == nil { 343 switch msg := m1.(type) { 344 case *rtr.RTRSerialNotify: 345 if before(client.serialNumber, msg.RTRCommon.SerialNumber) { 346 client.enable(client.serialNumber) 347 } else if client.serialNumber == msg.RTRCommon.SerialNumber { 348 // nothing 349 } else { 350 // should not happen. try to get the whole ROAs. 351 client.softReset() 352 } 353 received.SerialNotify++ 354 case *rtr.RTRSerialQuery: 355 case *rtr.RTRResetQuery: 356 case *rtr.RTRCacheResponse: 357 received.CacheResponse++ 358 client.endOfData = false 359 case *rtr.RTRIPPrefix: 360 family := bgp.AFI_IP 361 if msg.Type == rtr.RTR_IPV4_PREFIX { 362 received.Ipv4Prefix++ 363 } else { 364 family = bgp.AFI_IP6 365 received.Ipv6Prefix++ 366 } 367 roa := table.NewROA(family, msg.Prefix, msg.PrefixLen, msg.MaxLen, msg.AS, client.host) 368 if (msg.Flags & 1) == 1 { 369 if client.endOfData { 370 m.addROA(roa) 371 } else { 372 client.pendingROAs = append(client.pendingROAs, roa) 373 } 374 } else { 375 m.deleteROA(roa) 376 } 377 case *rtr.RTREndOfData: 378 received.EndOfData++ 379 if client.sessionID != msg.RTRCommon.SessionID { 380 // remove all ROAs related with the 381 // previous session 382 m.deleteAllROA(client.host) 383 } 384 client.sessionID = msg.RTRCommon.SessionID 385 client.serialNumber = msg.RTRCommon.SerialNumber 386 client.endOfData = true 387 if client.timer != nil { 388 client.timer.Stop() 389 client.timer = nil 390 } 391 for _, roa := range client.pendingROAs { 392 m.addROA(roa) 393 } 394 client.pendingROAs = make([]*table.ROA, 0) 395 case *rtr.RTRCacheReset: 396 client.softReset() 397 received.CacheReset++ 398 case *rtr.RTRErrorReport: 399 received.Error++ 400 } 401 } else { 402 log.WithFields(log.Fields{ 403 "Topic": "rpki", 404 "Host": client.host, 405 "Error": err, 406 }).Info("Failed to parse an RTR message") 407 } 408 } 409 410 func (m *roaManager) GetServers() []*config.RpkiServer { 411 f := func(tree *radix.Tree) (map[string]uint32, map[string]uint32) { 412 records := make(map[string]uint32) 413 prefixes := make(map[string]uint32) 414 415 tree.Walk(func(s string, v interface{}) bool { 416 b, _ := v.(*roaBucket) 417 tmpRecords := make(map[string]uint32) 418 for _, roa := range b.entries { 419 tmpRecords[roa.Src]++ 420 } 421 422 for src, r := range tmpRecords { 423 if r > 0 { 424 records[src] += r 425 prefixes[src]++ 426 } 427 } 428 return false 429 }) 430 return records, prefixes 431 } 432 433 recordsV4, prefixesV4 := f(m.Roas[bgp.RF_IPv4_UC]) 434 recordsV6, prefixesV6 := f(m.Roas[bgp.RF_IPv6_UC]) 435 436 l := make([]*config.RpkiServer, 0, len(m.clientMap)) 437 for _, client := range m.clientMap { 438 state := &client.state 439 440 if client.conn == nil { 441 state.Up = false 442 } else { 443 state.Up = true 444 } 445 f := func(m map[string]uint32, key string) uint32 { 446 if r, ok := m[key]; ok { 447 return r 448 } 449 return 0 450 } 451 state.RecordsV4 = f(recordsV4, client.host) 452 state.RecordsV6 = f(recordsV6, client.host) 453 state.PrefixesV4 = f(prefixesV4, client.host) 454 state.PrefixesV6 = f(prefixesV6, client.host) 455 state.SerialNumber = client.serialNumber 456 457 addr, port, _ := net.SplitHostPort(client.host) 458 l = append(l, &config.RpkiServer{ 459 Config: config.RpkiServerConfig{ 460 Address: addr, 461 // Note: RpkiServerConfig.Port is uint32 type, but the TCP/UDP 462 // port is 16-bit length. 463 Port: func() uint32 { p, _ := strconv.ParseUint(port, 10, 16); return uint32(p) }(), 464 }, 465 State: client.state, 466 }) 467 } 468 return l 469 } 470 471 func (m *roaManager) GetRoa(family bgp.RouteFamily) ([]*table.ROA, error) { 472 if len(m.clientMap) == 0 { 473 return []*table.ROA{}, fmt.Errorf("RPKI server isn't configured.") 474 } 475 var rfList []bgp.RouteFamily 476 switch family { 477 case bgp.RF_IPv4_UC: 478 rfList = []bgp.RouteFamily{bgp.RF_IPv4_UC} 479 case bgp.RF_IPv6_UC: 480 rfList = []bgp.RouteFamily{bgp.RF_IPv6_UC} 481 default: 482 rfList = []bgp.RouteFamily{bgp.RF_IPv4_UC, bgp.RF_IPv6_UC} 483 } 484 l := make([]*table.ROA, 0) 485 for _, rf := range rfList { 486 if tree, ok := m.Roas[rf]; ok { 487 tree.Walk(func(s string, v interface{}) bool { 488 b, _ := v.(*roaBucket) 489 var roaList roas 490 for _, r := range b.entries { 491 roaList = append(roaList, r) 492 } 493 sort.Sort(roaList) 494 for _, roa := range roaList { 495 l = append(l, roa) 496 } 497 return false 498 }) 499 } 500 } 501 return l, nil 502 } 503 504 func validatePath(ownAs uint32, tree *radix.Tree, cidr string, asPath *bgp.PathAttributeAsPath) *table.Validation { 505 var as uint32 506 507 validation := &table.Validation{ 508 Status: config.RPKI_VALIDATION_RESULT_TYPE_NOT_FOUND, 509 Reason: table.RPKI_VALIDATION_REASON_TYPE_NONE, 510 Matched: make([]*table.ROA, 0), 511 UnmatchedLength: make([]*table.ROA, 0), 512 UnmatchedAs: make([]*table.ROA, 0), 513 } 514 515 if asPath == nil || len(asPath.Value) == 0 { 516 as = ownAs 517 } else { 518 param := asPath.Value[len(asPath.Value)-1] 519 switch param.GetType() { 520 case bgp.BGP_ASPATH_ATTR_TYPE_SEQ: 521 asList := param.GetAS() 522 if len(asList) == 0 { 523 as = ownAs 524 } else { 525 as = asList[len(asList)-1] 526 } 527 case bgp.BGP_ASPATH_ATTR_TYPE_CONFED_SET, bgp.BGP_ASPATH_ATTR_TYPE_CONFED_SEQ: 528 as = ownAs 529 default: 530 return validation 531 } 532 } 533 _, n, _ := net.ParseCIDR(cidr) 534 ones, _ := n.Mask.Size() 535 prefixLen := uint8(ones) 536 key := table.IpToRadixkey(n.IP, prefixLen) 537 _, b, _ := tree.LongestPrefix(key) 538 if b == nil { 539 return validation 540 } 541 542 var bucket *roaBucket 543 fn := radix.WalkFn(func(k string, v interface{}) bool { 544 bucket, _ = v.(*roaBucket) 545 for _, r := range bucket.entries { 546 if prefixLen <= r.MaxLen { 547 if r.AS != 0 && r.AS == as { 548 validation.Matched = append(validation.Matched, r) 549 } else { 550 validation.UnmatchedAs = append(validation.UnmatchedAs, r) 551 } 552 } else { 553 validation.UnmatchedLength = append(validation.UnmatchedLength, r) 554 } 555 } 556 return false 557 }) 558 tree.WalkPath(key, fn) 559 560 if len(validation.Matched) != 0 { 561 validation.Status = config.RPKI_VALIDATION_RESULT_TYPE_VALID 562 validation.Reason = table.RPKI_VALIDATION_REASON_TYPE_NONE 563 } else if len(validation.UnmatchedAs) != 0 { 564 validation.Status = config.RPKI_VALIDATION_RESULT_TYPE_INVALID 565 validation.Reason = table.RPKI_VALIDATION_REASON_TYPE_AS 566 } else if len(validation.UnmatchedLength) != 0 { 567 validation.Status = config.RPKI_VALIDATION_RESULT_TYPE_INVALID 568 validation.Reason = table.RPKI_VALIDATION_REASON_TYPE_LENGTH 569 } else { 570 validation.Status = config.RPKI_VALIDATION_RESULT_TYPE_NOT_FOUND 571 validation.Reason = table.RPKI_VALIDATION_REASON_TYPE_NONE 572 } 573 574 return validation 575 } 576 577 func (m *roaManager) validate(path *table.Path) *table.Validation { 578 if len(m.clientMap) == 0 || path.IsWithdraw || path.IsEOR() { 579 // RPKI isn't enabled or invalid path 580 return nil 581 } 582 if tree, ok := m.Roas[path.GetRouteFamily()]; ok { 583 return validatePath(m.AS, tree, path.GetNlri().String(), path.GetAsPath()) 584 } 585 return nil 586 } 587 588 type roaClient struct { 589 host string 590 conn *net.TCPConn 591 state config.RpkiServerState 592 eventCh chan *roaEvent 593 sessionID uint16 594 oldSessionID uint16 595 serialNumber uint32 596 timer *time.Timer 597 lifetime int64 598 endOfData bool 599 pendingROAs []*table.ROA 600 cancelfnc context.CancelFunc 601 ctx context.Context 602 } 603 604 func newRoaClient(address, port string, ch chan *roaEvent, lifetime int64) *roaClient { 605 ctx, cancel := context.WithCancel(context.Background()) 606 c := &roaClient{ 607 host: net.JoinHostPort(address, port), 608 eventCh: ch, 609 lifetime: lifetime, 610 pendingROAs: make([]*table.ROA, 0), 611 ctx: ctx, 612 cancelfnc: cancel, 613 } 614 go c.tryConnect() 615 return c 616 } 617 618 func (c *roaClient) enable(serial uint32) error { 619 if c.conn != nil { 620 r := rtr.NewRTRSerialQuery(c.sessionID, serial) 621 data, _ := r.Serialize() 622 _, err := c.conn.Write(data) 623 if err != nil { 624 return err 625 } 626 c.state.RpkiMessages.RpkiSent.SerialQuery++ 627 } 628 return nil 629 } 630 631 func (c *roaClient) softReset() error { 632 if c.conn != nil { 633 r := rtr.NewRTRResetQuery() 634 data, _ := r.Serialize() 635 _, err := c.conn.Write(data) 636 if err != nil { 637 return err 638 } 639 c.state.RpkiMessages.RpkiSent.ResetQuery++ 640 c.endOfData = false 641 c.pendingROAs = make([]*table.ROA, 0) 642 } 643 return nil 644 } 645 646 func (c *roaClient) reset() { 647 if c.conn != nil { 648 c.conn.Close() 649 } 650 } 651 652 func (c *roaClient) stop() { 653 c.cancelfnc() 654 c.reset() 655 } 656 657 func (c *roaClient) tryConnect() { 658 for { 659 select { 660 case <-c.ctx.Done(): 661 return 662 default: 663 } 664 if conn, err := net.Dial("tcp", c.host); err != nil { 665 // better to use context with timeout 666 time.Sleep(connectRetryInterval * time.Second) 667 } else { 668 c.eventCh <- &roaEvent{ 669 EventType: roaConnected, 670 Src: c.host, 671 conn: conn.(*net.TCPConn), 672 } 673 return 674 } 675 } 676 } 677 678 func (c *roaClient) established() (err error) { 679 defer func() { 680 c.conn.Close() 681 c.eventCh <- &roaEvent{ 682 EventType: roaDisconnected, 683 Src: c.host, 684 } 685 }() 686 687 if err := c.softReset(); err != nil { 688 return err 689 } 690 691 for { 692 header := make([]byte, rtr.RTR_MIN_LEN) 693 if _, err = io.ReadFull(c.conn, header); err != nil { 694 return err 695 } 696 totalLen := binary.BigEndian.Uint32(header[4:8]) 697 if totalLen < rtr.RTR_MIN_LEN { 698 return fmt.Errorf("too short header length %v", totalLen) 699 } 700 701 body := make([]byte, totalLen-rtr.RTR_MIN_LEN) 702 if _, err = io.ReadFull(c.conn, body); err != nil { 703 return 704 } 705 706 c.eventCh <- &roaEvent{ 707 EventType: roaRTR, 708 Src: c.host, 709 Data: append(header, body...), 710 } 711 } 712 }