From 433f77dc27792acc95ecc4ad3d5726aafc1b27ae Mon Sep 17 00:00:00 2001 From: Daniel Czerwonk <daniel@dan-nrw.de> Date: Sat, 23 Jun 2018 19:16:56 +0200 Subject: [PATCH] added parsing for 4 byte ASN capability --- protocols/bgp/packet/bgp.go | 4 +- protocols/bgp/packet/decoder.go | 2 +- protocols/bgp/packet/decoder_test.go | 6 +- protocols/bgp/packet/encoder.go | 2 +- protocols/bgp/packet/parameters.go | 8 ++ protocols/bgp/server/fsm2.go | 2 +- protocols/bgp/server/fsm_open_sent.go | 24 +++++- protocols/bgp/server/fsm_open_sent_test.go | 87 ++++++++++++++++++++++ 8 files changed, 126 insertions(+), 9 deletions(-) create mode 100644 protocols/bgp/server/fsm_open_sent_test.go diff --git a/protocols/bgp/packet/bgp.go b/protocols/bgp/packet/bgp.go index 622b46f3..8082f5dd 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 31583bf1..e473f3ed 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 a9ae237b..916660a3 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 ea87d1ff..de2966bf 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 8edf42fc..0ed9af66 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 6e1682c7..9b8163ab 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 63680636..aba1193d 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 00000000..d4f2634e --- /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") + }) + } +} -- GitLab