diff --git a/protocols/bgp/packet/bgp.go b/protocols/bgp/packet/bgp.go index 622b46f37b115dd27779a285284d177d75695230..8082f5dd8c02ae2c74a23013bcdb4c63d524d52b 100644 --- a/protocols/bgp/packet/bgp.go +++ b/protocols/bgp/packet/bgp.go @@ -92,9 +92,11 @@ const ( UnicastSAFI = 1 CapabilitiesParamType = 2 AddPathCapabilityCode = 69 + ASN4CapabilityCode = 65 AddPathReceive = 1 AddPathSend = 2 AddPathSendReceive = 3 + ASTransASN = 23456 ) type BGPError struct { @@ -119,7 +121,7 @@ type BGPHeader struct { type BGPOpen struct { Version uint8 - AS uint16 + ASN uint16 HoldTime uint16 BGPIdentifier uint32 OptParmLen uint8 diff --git a/protocols/bgp/packet/decoder.go b/protocols/bgp/packet/decoder.go index 31583bf1b68257625dfaa3d8b8e40893982d6713..e473f3edf38c208f5726ecc3b776dbf883f61197 100644 --- a/protocols/bgp/packet/decoder.go +++ b/protocols/bgp/packet/decoder.go @@ -141,7 +141,7 @@ func _decodeOpenMsg(buf *bytes.Buffer) (interface{}, error) { fields := []interface{}{ &msg.Version, - &msg.AS, + &msg.ASN, &msg.HoldTime, &msg.BGPIdentifier, &msg.OptParmLen, diff --git a/protocols/bgp/packet/decoder_test.go b/protocols/bgp/packet/decoder_test.go index a9ae237b9cb94a3e0ec6af0b988bc09f41d3f806..916660a3dd06e08b23d29ea4a8c48fb63ed68b47 100644 --- a/protocols/bgp/packet/decoder_test.go +++ b/protocols/bgp/packet/decoder_test.go @@ -156,7 +156,7 @@ func TestDecode(t *testing.T) { }, Body: &BGPOpen{ Version: 4, - AS: 200, + ASN: 200, HoldTime: 15, BGPIdentifier: uint32(169090600), OptParmLen: 0, @@ -184,7 +184,7 @@ func TestDecode(t *testing.T) { }, Body: &BGPOpen{ Version: 4, - AS: 200, + ASN: 200, HoldTime: 15, BGPIdentifier: uint32(100), }, @@ -1512,7 +1512,7 @@ func TestDecodeOpenMsg(t *testing.T) { wantFail: false, expected: &BGPOpen{ Version: 4, - AS: 257, + ASN: 257, HoldTime: 15, BGPIdentifier: 169090600, OptParmLen: 0, diff --git a/protocols/bgp/packet/encoder.go b/protocols/bgp/packet/encoder.go index ea87d1ff64cfc946688e738ae9f7ffa372cf10c7..de2966bfeb404c70828a72874b7f1f6788fc974c 100644 --- a/protocols/bgp/packet/encoder.go +++ b/protocols/bgp/packet/encoder.go @@ -35,7 +35,7 @@ func SerializeOpenMsg(msg *BGPOpen) []byte { serializeHeader(buf, openLen, OpenMsg) buf.WriteByte(msg.Version) - buf.Write(convert.Uint16Byte(msg.AS)) + buf.Write(convert.Uint16Byte(msg.ASN)) buf.Write(convert.Uint16Byte(msg.HoldTime)) buf.Write(convert.Uint32Byte(msg.BGPIdentifier)) diff --git a/protocols/bgp/packet/parameters.go b/protocols/bgp/packet/parameters.go index 8edf42fc58e05bb3b73cacd4272012844bedcd45..0ed9af66fe01f96600c02eeb2c00b69b11edc76c 100644 --- a/protocols/bgp/packet/parameters.go +++ b/protocols/bgp/packet/parameters.go @@ -52,3 +52,11 @@ func (a AddPathCapability) serialize(buf *bytes.Buffer) { buf.WriteByte(a.SAFI) buf.WriteByte(a.SendReceive) } + +type ASN4Capability struct { + ASN4 uint32 +} + +func (a ASN4Capability) serialize(buf *bytes.Buffer) { + buf.Write(convert.Uint32Byte(a.ASN4)) +} diff --git a/protocols/bgp/server/fsm2.go b/protocols/bgp/server/fsm2.go index 6e1682c71b7aaf47ff2858a30b199fc07cb43297..9b8163ab22dd53966f4efb25c38e1bfd7b826451 100644 --- a/protocols/bgp/server/fsm2.go +++ b/protocols/bgp/server/fsm2.go @@ -221,7 +221,7 @@ func (fsm *FSM) resetConnectRetryCounter() { func (fsm *FSM) sendOpen() error { msg := packet.SerializeOpenMsg(&packet.BGPOpen{ Version: BGPVersion, - AS: uint16(fsm.peer.localASN), + ASN: uint16(fsm.peer.localASN), HoldTime: uint16(fsm.peer.holdTime / time.Second), BGPIdentifier: fsm.peer.server.routerID, OptParams: fsm.peer.optOpenParams, diff --git a/protocols/bgp/server/fsm_open_sent.go b/protocols/bgp/server/fsm_open_sent.go index 63680636d8e0c65afe1dad9ec9d1280c34e9c37d..aba1193dd9b75010e50a3d4e2de932e9bc87647e 100644 --- a/protocols/bgp/server/fsm_open_sent.go +++ b/protocols/bgp/server/fsm_open_sent.go @@ -10,7 +10,8 @@ import ( ) type openSentState struct { - fsm *FSM + fsm *FSM + peerASNRcvd uint32 } func newOpenSentState(fsm *FSM) *openSentState { @@ -104,6 +105,8 @@ func (s *openSentState) unexpectedMessage() (state, string) { func (s *openSentState) openMsgReceived(msg *packet.BGPMessage) (state, string) { openMsg := msg.Body.(*packet.BGPOpen) + s.peerASNRcvd = uint32(openMsg.ASN) + s.fsm.neighborID = openMsg.BGPIdentifier stopTimer(s.fsm.connectRetryTimer) if s.fsm.peer.collisionHandling(s.fsm) { @@ -114,6 +117,10 @@ func (s *openSentState) openMsgReceived(msg *packet.BGPMessage) (state, string) return s.tcpFailure() } + return s.handleOpenMessage(openMsg) +} + +func (s *openSentState) handleOpenMessage(openMsg *packet.BGPOpen) (state, string) { s.fsm.holdTime = time.Duration(math.Min(float64(s.fsm.peer.holdTime), float64(time.Duration(openMsg.HoldTime)*time.Second))) if s.fsm.holdTime != 0 { if !s.fsm.holdTimer.Reset(s.fsm.holdTime) { @@ -123,7 +130,13 @@ func (s *openSentState) openMsgReceived(msg *packet.BGPMessage) (state, string) s.fsm.keepaliveTimer = time.NewTimer(s.fsm.keepaliveTime) } + s.peerASNRcvd = uint32(openMsg.ASN) s.processOpenOptions(openMsg.OptParams) + + if s.peerASNRcvd != s.fsm.peer.peerASN { + return newCeaseState(), fmt.Sprintf("Expected session from %d, got open message with ASN %d", s.fsm.peer.peerASN, s.peerASNRcvd) + } + return newOpenConfirmState(s.fsm), "Received OPEN message" } @@ -153,7 +166,8 @@ func (s *openSentState) processCapability(cap packet.Capability) { switch cap.Code { case packet.AddPathCapabilityCode: s.processAddPathCapability(cap.Value.(packet.AddPathCapability)) - + case packet.ASN4CapabilityCode: + s.processASN4Capability(cap.Value.(packet.ASN4Capability)) } } @@ -184,6 +198,12 @@ func (s *openSentState) processAddPathCapability(addPathCap packet.AddPathCapabi } } +func (s *openSentState) processASN4Capability(cap packet.ASN4Capability) { + if s.peerASNRcvd == packet.ASTransASN { + s.peerASNRcvd = cap.ASN4 + } +} + func (s *openSentState) notification(msg *packet.BGPMessage) (state, string) { stopTimer(s.fsm.connectRetryTimer) s.fsm.con.Close() diff --git a/protocols/bgp/server/fsm_open_sent_test.go b/protocols/bgp/server/fsm_open_sent_test.go new file mode 100644 index 0000000000000000000000000000000000000000..d4f2634eac2adba7a70c9a636a8969388d0a7fc3 --- /dev/null +++ b/protocols/bgp/server/fsm_open_sent_test.go @@ -0,0 +1,87 @@ +package server + +import ( + "testing" + + "github.com/bio-routing/bio-rd/protocols/bgp/packet" + "github.com/stretchr/testify/assert" +) + +func TestOpenMsgReceived(t *testing.T) { + tests := []struct { + asn uint32 + name string + msg packet.BGPOpen + wantsCease bool + }{ + { + name: "valid open message (16bit ASN)", + asn: 12345, + msg: packet.BGPOpen{ + HoldTime: 90, + BGPIdentifier: 1, + Version: 4, + ASN: 12345, + }, + }, + { + name: "valid open message (32bit ASN)", + asn: 202739, + msg: packet.BGPOpen{ + HoldTime: 90, + BGPIdentifier: 1, + Version: 4, + ASN: 23456, + OptParmLen: 1, + OptParams: []packet.OptParam{ + { + Type: packet.CapabilitiesParamType, + Length: 6, + Value: packet.Capabilities{ + packet.Capability{ + Code: packet.ASN4CapabilityCode, + Length: 4, + Value: packet.ASN4Capability{ + ASN4: 202739, + }, + }, + }, + }, + }, + }, + }, + { + name: "open message does not match configured remote ASN", + asn: 12345, + msg: packet.BGPOpen{ + HoldTime: 90, + BGPIdentifier: 1, + Version: 4, + ASN: 54321, + }, + wantsCease: true, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + fsm := newFSM2(&Peer{ + peerASN: test.asn, + }) + + s := &openSentState{ + fsm: fsm, + } + + state, _ := s.handleOpenMessage(&test.msg) + + if test.wantsCease { + assert.IsType(t, &ceaseState{}, state, "state") + return + } + + assert.IsType(t, &openConfirmState{}, state, "state") + assert.Equal(t, test.asn, s.peerASNRcvd, "asn") + }) + } +}