github.com/osrg/gobgp/v3@v3.30.0/pkg/server/rpki.go (about) 1 // Copyright (C) 2015-2021 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 "context" 20 "encoding/binary" 21 "fmt" 22 "io" 23 "net" 24 "strconv" 25 "time" 26 27 "github.com/osrg/gobgp/v3/internal/pkg/table" 28 "github.com/osrg/gobgp/v3/pkg/config/oc" 29 "github.com/osrg/gobgp/v3/pkg/log" 30 "github.com/osrg/gobgp/v3/pkg/packet/bgp" 31 "github.com/osrg/gobgp/v3/pkg/packet/rtr" 32 ) 33 34 const ( 35 connectRetryInterval = 30 36 ) 37 38 func before(a, b uint32) bool { 39 return int32(a-b) < 0 40 } 41 42 type roaEventType uint8 43 44 const ( 45 roaConnected roaEventType = iota 46 roaDisconnected 47 roaRTR 48 roaLifetimeout 49 ) 50 51 type roaEvent struct { 52 EventType roaEventType 53 Src string 54 Data []byte 55 conn *net.TCPConn 56 } 57 58 type roaManager struct { 59 eventCh chan *roaEvent 60 clientMap map[string]*roaClient 61 table *table.ROATable 62 logger log.Logger 63 } 64 65 func newROAManager(table *table.ROATable, logger log.Logger) *roaManager { 66 m := &roaManager{ 67 eventCh: make(chan *roaEvent), 68 clientMap: make(map[string]*roaClient), 69 table: table, 70 logger: logger, 71 } 72 return m 73 } 74 75 func (m *roaManager) enabled() bool { 76 return len(m.clientMap) != 0 77 } 78 79 func (m *roaManager) AddServer(host string, lifetime int64) error { 80 address, port, err := net.SplitHostPort(host) 81 if err != nil { 82 return err 83 } 84 if lifetime == 0 { 85 lifetime = 3600 86 } 87 if _, ok := m.clientMap[host]; ok { 88 return fmt.Errorf("ROA server exists %s", host) 89 } 90 m.clientMap[host] = newRoaClient(address, port, m.eventCh, lifetime) 91 return nil 92 } 93 94 func (m *roaManager) DeleteServer(host string) error { 95 client, ok := m.clientMap[host] 96 if !ok { 97 return fmt.Errorf("ROA server doesn't exists %s", host) 98 } 99 client.stop() 100 m.table.DeleteAll(host) 101 delete(m.clientMap, host) 102 return nil 103 } 104 105 func (m *roaManager) Enable(address string) error { 106 for network, client := range m.clientMap { 107 add, _, _ := net.SplitHostPort(network) 108 if add == address { 109 client.enable(client.serialNumber) 110 return nil 111 } 112 } 113 return fmt.Errorf("ROA server not found %s", address) 114 } 115 116 func (m *roaManager) Disable(address string) error { 117 for network, client := range m.clientMap { 118 add, _, _ := net.SplitHostPort(network) 119 if add == address { 120 client.reset() 121 m.table.DeleteAll(add) 122 return nil 123 } 124 } 125 return fmt.Errorf("ROA server not found %s", address) 126 } 127 128 func (m *roaManager) Reset(address string) error { 129 return m.Disable(address) 130 } 131 132 func (m *roaManager) SoftReset(address string) error { 133 for network, client := range m.clientMap { 134 add, _, _ := net.SplitHostPort(network) 135 if add == address { 136 client.softReset() 137 m.table.DeleteAll(network) 138 return nil 139 } 140 } 141 return fmt.Errorf("ROA server not found %s", address) 142 } 143 144 func (m *roaManager) ReceiveROA() chan *roaEvent { 145 return m.eventCh 146 } 147 148 func (c *roaClient) lifetimeout() { 149 c.eventCh <- &roaEvent{ 150 EventType: roaLifetimeout, 151 Src: c.host, 152 } 153 } 154 155 func (m *roaManager) HandleROAEvent(ev *roaEvent) { 156 client, y := m.clientMap[ev.Src] 157 if !y { 158 if ev.EventType == roaConnected { 159 ev.conn.Close() 160 } 161 m.logger.Error("Can't find ROA server configuration", 162 log.Fields{ 163 "Topic": "rpki", 164 "Key": ev.Src}) 165 return 166 } 167 switch ev.EventType { 168 case roaDisconnected: 169 m.logger.Info("ROA server is disconnected", 170 log.Fields{ 171 "Topic": "rpki", 172 "Key": ev.Src}) 173 client.state.Downtime = time.Now().Unix() 174 // clear state 175 client.endOfData = false 176 client.pendingROAs = make([]*table.ROA, 0) 177 client.state.RpkiMessages = oc.RpkiMessages{} 178 client.conn = nil 179 go client.tryConnect() 180 client.timer = time.AfterFunc(time.Duration(client.lifetime)*time.Second, client.lifetimeout) 181 client.oldSessionID = client.sessionID 182 case roaConnected: 183 m.logger.Info("ROA server is connected", 184 log.Fields{ 185 "Topic": "rpki", 186 "Key": ev.Src}) 187 client.conn = ev.conn 188 client.state.Uptime = time.Now().Unix() 189 go client.established() 190 case roaRTR: 191 m.handleRTRMsg(client, &client.state, ev.Data) 192 case roaLifetimeout: 193 // a) already reconnected but hasn't received 194 // EndOfData -> needs to delete stale ROAs 195 // b) not reconnected -> needs to delete stale ROAs 196 // 197 // c) already reconnected and received EndOfData so 198 // all stale ROAs were deleted -> timer was cancelled 199 // so should not be here. 200 if client.oldSessionID != client.sessionID { 201 m.logger.Info("Reconnected, ignore timeout", 202 log.Fields{ 203 "Topic": "rpki", 204 "Key": client.host}) 205 } else { 206 m.logger.Info("Deleting all ROAs due to timeout", 207 log.Fields{ 208 "Topic": "rpki", 209 "Key": client.host}) 210 m.table.DeleteAll(client.host) 211 } 212 } 213 } 214 215 func (m *roaManager) handleRTRMsg(client *roaClient, state *oc.RpkiServerState, buf []byte) { 216 received := &state.RpkiMessages.RpkiReceived 217 218 m1, err := rtr.ParseRTR(buf) 219 if err == nil { 220 switch msg := m1.(type) { 221 case *rtr.RTRSerialNotify: 222 if before(client.serialNumber, msg.RTRCommon.SerialNumber) { 223 client.enable(client.serialNumber) 224 } else if client.serialNumber == msg.RTRCommon.SerialNumber { 225 // nothing 226 } else { 227 // should not happen. try to get the whole ROAs. 228 client.softReset() 229 } 230 received.SerialNotify++ 231 case *rtr.RTRSerialQuery: 232 case *rtr.RTRResetQuery: 233 case *rtr.RTRCacheResponse: 234 received.CacheResponse++ 235 client.endOfData = false 236 case *rtr.RTRIPPrefix: 237 family := bgp.AFI_IP 238 if msg.Type == rtr.RTR_IPV4_PREFIX { 239 received.Ipv4Prefix++ 240 } else { 241 family = bgp.AFI_IP6 242 received.Ipv6Prefix++ 243 } 244 roa := table.NewROA(family, msg.Prefix, msg.PrefixLen, msg.MaxLen, msg.AS, client.host) 245 if (msg.Flags & 1) == 1 { 246 if client.endOfData { 247 m.table.Add(roa) 248 } else { 249 client.pendingROAs = append(client.pendingROAs, roa) 250 } 251 } else { 252 m.table.Delete(roa) 253 } 254 case *rtr.RTREndOfData: 255 received.EndOfData++ 256 if client.sessionID != msg.RTRCommon.SessionID { 257 // remove all ROAs related with the 258 // previous session 259 m.table.DeleteAll(client.host) 260 } 261 client.sessionID = msg.RTRCommon.SessionID 262 client.serialNumber = msg.RTRCommon.SerialNumber 263 client.endOfData = true 264 if client.timer != nil { 265 client.timer.Stop() 266 client.timer = nil 267 } 268 for _, roa := range client.pendingROAs { 269 m.table.Add(roa) 270 } 271 client.pendingROAs = make([]*table.ROA, 0) 272 case *rtr.RTRCacheReset: 273 client.softReset() 274 received.CacheReset++ 275 case *rtr.RTRErrorReport: 276 received.Error++ 277 } 278 } else { 279 m.logger.Info("Failed to parse an RTR message", 280 log.Fields{ 281 "Topic": "rpki", 282 "Host": client.host, 283 "Error": err}) 284 } 285 } 286 287 func (m *roaManager) GetServers() []*oc.RpkiServer { 288 recordsV4, prefixesV4 := m.table.Info(bgp.RF_IPv4_UC) 289 recordsV6, prefixesV6 := m.table.Info(bgp.RF_IPv6_UC) 290 291 l := make([]*oc.RpkiServer, 0, len(m.clientMap)) 292 for _, client := range m.clientMap { 293 state := &client.state 294 295 if client.conn == nil { 296 state.Up = false 297 } else { 298 state.Up = true 299 } 300 f := func(m map[string]uint32, key string) uint32 { 301 if r, ok := m[key]; ok { 302 return r 303 } 304 return 0 305 } 306 state.RecordsV4 = f(recordsV4, client.host) 307 state.RecordsV6 = f(recordsV6, client.host) 308 state.PrefixesV4 = f(prefixesV4, client.host) 309 state.PrefixesV6 = f(prefixesV6, client.host) 310 state.SerialNumber = client.serialNumber 311 312 addr, port, _ := net.SplitHostPort(client.host) 313 l = append(l, &oc.RpkiServer{ 314 Config: oc.RpkiServerConfig{ 315 Address: addr, 316 // Note: RpkiServerConfig.Port is uint32 type, but the TCP/UDP 317 // port is 16-bit length. 318 Port: func() uint32 { p, _ := strconv.ParseUint(port, 10, 16); return uint32(p) }(), 319 }, 320 State: client.state, 321 }) 322 } 323 return l 324 } 325 326 type roaClient struct { 327 host string 328 conn *net.TCPConn 329 state oc.RpkiServerState 330 eventCh chan *roaEvent 331 sessionID uint16 332 oldSessionID uint16 333 serialNumber uint32 334 timer *time.Timer 335 lifetime int64 336 endOfData bool 337 pendingROAs []*table.ROA 338 cancelfnc context.CancelFunc 339 ctx context.Context 340 } 341 342 func newRoaClient(address, port string, ch chan *roaEvent, lifetime int64) *roaClient { 343 ctx, cancel := context.WithCancel(context.Background()) 344 c := &roaClient{ 345 host: net.JoinHostPort(address, port), 346 eventCh: ch, 347 lifetime: lifetime, 348 pendingROAs: make([]*table.ROA, 0), 349 ctx: ctx, 350 cancelfnc: cancel, 351 } 352 go c.tryConnect() 353 return c 354 } 355 356 func (c *roaClient) enable(serial uint32) error { 357 if c.conn != nil { 358 r := rtr.NewRTRSerialQuery(c.sessionID, serial) 359 data, _ := r.Serialize() 360 _, err := c.conn.Write(data) 361 if err != nil { 362 return err 363 } 364 c.state.RpkiMessages.RpkiSent.SerialQuery++ 365 } 366 return nil 367 } 368 369 func (c *roaClient) softReset() error { 370 if c.conn != nil { 371 r := rtr.NewRTRResetQuery() 372 data, _ := r.Serialize() 373 _, err := c.conn.Write(data) 374 if err != nil { 375 return err 376 } 377 c.state.RpkiMessages.RpkiSent.ResetQuery++ 378 c.endOfData = false 379 c.pendingROAs = make([]*table.ROA, 0) 380 } 381 return nil 382 } 383 384 func (c *roaClient) reset() { 385 if c.conn != nil { 386 c.conn.Close() 387 } 388 } 389 390 func (c *roaClient) stop() { 391 c.cancelfnc() 392 c.reset() 393 } 394 395 func (c *roaClient) tryConnect() { 396 for { 397 select { 398 case <-c.ctx.Done(): 399 return 400 default: 401 } 402 if conn, err := net.Dial("tcp", c.host); err != nil { 403 // better to use context with timeout 404 time.Sleep(connectRetryInterval * time.Second) 405 } else { 406 c.eventCh <- &roaEvent{ 407 EventType: roaConnected, 408 Src: c.host, 409 conn: conn.(*net.TCPConn), 410 } 411 return 412 } 413 } 414 } 415 416 func (c *roaClient) established() (err error) { 417 defer func() { 418 c.conn.Close() 419 c.eventCh <- &roaEvent{ 420 EventType: roaDisconnected, 421 Src: c.host, 422 } 423 }() 424 425 if err := c.softReset(); err != nil { 426 return err 427 } 428 429 for { 430 header := make([]byte, rtr.RTR_MIN_LEN) 431 if _, err = io.ReadFull(c.conn, header); err != nil { 432 return err 433 } 434 totalLen := binary.BigEndian.Uint32(header[4:8]) 435 if totalLen < rtr.RTR_MIN_LEN { 436 return fmt.Errorf("too short header length %v", totalLen) 437 } 438 439 body := make([]byte, totalLen-rtr.RTR_MIN_LEN) 440 if _, err = io.ReadFull(c.conn, body); err != nil { 441 return 442 } 443 444 c.eventCh <- &roaEvent{ 445 EventType: roaRTR, 446 Src: c.host, 447 Data: append(header, body...), 448 } 449 } 450 }