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  }