diff --git a/protocols/bgp/packet/bgp.go b/protocols/bgp/packet/bgp.go index 41a2113f8e6cb85cb0250d0333908071dc03fd79..c3a80b93aa666e18525e702d12530d66381c36c9 100644 --- a/protocols/bgp/packet/bgp.go +++ b/protocols/bgp/packet/bgp.go @@ -51,13 +51,14 @@ const ( MalformedASPath = 11 // Attribute Type Codes - OriginAttr = 1 - ASPathAttr = 2 - NextHopAttr = 3 - MEDAttr = 4 - LocalPrefAttr = 5 - AtomicAggrAttr = 6 - AggregatorAttr = 7 + OriginAttr = 1 + ASPathAttr = 2 + NextHopAttr = 3 + MEDAttr = 4 + LocalPrefAttr = 5 + AtomicAggrAttr = 6 + AggregatorAttr = 7 + CommunitiesAttr = 8 // ORIGIN values IGP = 0 diff --git a/protocols/bgp/packet/decoder_test.go b/protocols/bgp/packet/decoder_test.go index a69b4acbcc8e985fad6a9a58637214d4c3496c49..c2222e6da95735a9faeedbb5db8cc12fbe34fb74 100644 --- a/protocols/bgp/packet/decoder_test.go +++ b/protocols/bgp/packet/decoder_test.go @@ -651,7 +651,6 @@ func TestDecodeUpdateMsg(t *testing.T) { 3, // Attribute Type code (Next Hop) 4, // Length 10, 11, 12, 13, // Next Hop - }, wantFail: false, expected: &BGPUpdate{ @@ -745,7 +744,6 @@ func TestDecodeUpdateMsg(t *testing.T) { 4, // Attribute Type code (Next Hop) 4, // Length 0, 0, 1, 0, // MED 256 - }, wantFail: false, expected: &BGPUpdate{ @@ -852,7 +850,6 @@ func TestDecodeUpdateMsg(t *testing.T) { 5, // Attribute Type code (Local Pref) 4, // Length 0, 0, 1, 0, // Local Pref 256 - }, wantFail: false, expected: &BGPUpdate{ @@ -1262,6 +1259,94 @@ func TestDecodeUpdateMsg(t *testing.T) { }, }, }, + { + // 2 withdraws with two path attributes (Communities + Origin), valid update + testNum: 17, + input: []byte{0, 5, 8, 10, 16, 192, 168, + 0, 16, // Total Path Attribute Length + + 0, // Attribute flags + 8, // Attribute Type code (Community) + 8, // Length + 0, 0, 1, 0, // Arbitrary Community + 0, 0, 1, 1, // Arbitrary Community + + 255, // Attribute flags + 1, // Attribute Type code (ORIGIN) + 0, 1, // Length + 2, // INCOMPLETE + + }, + wantFail: false, + expected: &BGPUpdate{ + WithdrawnRoutesLen: 5, + WithdrawnRoutes: &NLRI{ + IP: strAddr("10.0.0.0"), + Pfxlen: 8, + Next: &NLRI{ + IP: strAddr("192.168.0.0"), + Pfxlen: 16, + }, + }, + TotalPathAttrLen: 16, + PathAttributes: &PathAttribute{ + Optional: false, + Transitive: false, + Partial: false, + ExtendedLength: false, + Length: 8, + TypeCode: 8, + Value: []uint32{256, 257}, + Next: &PathAttribute{ + Optional: true, + Transitive: true, + Partial: true, + ExtendedLength: true, + Length: 1, + TypeCode: 1, + Value: uint8(2), + }, + }, + }, + }, + { + // 2 withdraws with two path attributes (ORIGIN + Community), invalid update (too short community) + testNum: 18, + input: []byte{0, 5, 8, 10, 16, 192, 168, + 0, 11, // Total Path Attribute Length + + 255, // Attribute flags + 1, // Attribute Type code (ORIGIN) + 0, 1, // Length + 2, // INCOMPLETE + + 0, // Attribute flags + 8, // Attribute Type code (Community) + 3, // Length + 0, 0, 1, // Arbitrary Community + }, + wantFail: true, + expected: nil, + }, + { + // 2 withdraws with two path attributes (ORIGIN + Community), invalid update (too long community) + testNum: 19, + input: []byte{0, 5, 8, 10, 16, 192, 168, + 0, 13, // Total Path Attribute Length + + 255, // Attribute flags + 1, // Attribute Type code (ORIGIN) + 0, 1, // Length + 2, // INCOMPLETE + + 0, // Attribute flags + 8, // Attribute Type code (Community) + 5, // Length + 0, 0, 1, 0, 1, // Arbitrary Community + }, + wantFail: true, + expected: nil, + }, } for _, test := range tests { diff --git a/protocols/bgp/packet/path_attributes.go b/protocols/bgp/packet/path_attributes.go index 4db07c1d9f89b69ff292c7167228b3bfd47df3cf..846767989f400f1ede2fcf1e2c9202f33ad10974 100644 --- a/protocols/bgp/packet/path_attributes.go +++ b/protocols/bgp/packet/path_attributes.go @@ -84,6 +84,10 @@ func decodePathAttr(buf *bytes.Buffer) (pa *PathAttribute, consumed uint16, err } case AtomicAggrAttr: // Nothing to do for 0 octet long attribute + case CommunitiesAttr: + if err := pa.decodeCommunities(buf); err != nil { + return nil, consumed, fmt.Errorf("Failed to decode Community: %v", err) + } default: if err := pa.decodeUnknown(buf); err != nil { return nil, consumed, fmt.Errorf("Failed to decode unknown attribute: %v", err) @@ -227,6 +231,27 @@ func (pa *PathAttribute) decodeAggregator(buf *bytes.Buffer) error { return dumpNBytes(buf, pa.Length-p) } +func (pa *PathAttribute) decodeCommunities(buf *bytes.Buffer) error { + if pa.Length%4 != 0 { + return fmt.Errorf("Unable to read community path attribute length %d is not divisible by 4", pa.Length) + } + comNumber := pa.Length / 4 + var com = make([]uint32, comNumber) + for i := uint16(0); i < comNumber; i++ { + c := [4]byte{} + n, err := buf.Read(c[:]) + if err != nil { + return err + } + if n != 4 { + return fmt.Errorf("Unable to read next hop: buf.Read read %d bytes", n) + } + com[i] = fourBytesToUint32(c) + } + pa.Value = com + return nil +} + func (pa *PathAttribute) setLength(buf *bytes.Buffer) (int, error) { bytesRead := 0 if pa.ExtendedLength { diff --git a/protocols/bgp/server/fsm.go b/protocols/bgp/server/fsm.go index fc342e821871667f3d4fe7aab18e5d50e225674a..e20efb18015ea38b07587d043f76cdbfa531bba8 100644 --- a/protocols/bgp/server/fsm.go +++ b/protocols/bgp/server/fsm.go @@ -790,7 +790,7 @@ func (fsm *FSM) established() int { case recvMsg := <-fsm.msgRecvCh: msg, err := packet.Decode(bytes.NewBuffer(recvMsg.msg)) if err != nil { - fmt.Printf("Failed to decode BGP message: %v\n", recvMsg.msg) + fmt.Printf("Failed to decode BGP message: %v msg: %v\n", err, recvMsg.msg) switch bgperr := err.(type) { case packet.BGPError: sendNotification(fsm.con, bgperr.ErrorCode, bgperr.ErrorSubCode)