diff options
-rw-r--r-- | packet/validate.go | 28 | ||||
-rw-r--r-- | packet/validate_test.go | 217 |
2 files changed, 229 insertions, 16 deletions
diff --git a/packet/validate.go b/packet/validate.go index 5711a91b..0b1effaf 100644 --- a/packet/validate.go +++ b/packet/validate.go @@ -2,6 +2,7 @@ package bgp import ( "github.com/osrg/gobgp/config" + "net" "strconv" ) @@ -10,7 +11,6 @@ func ValidateUpdateMsg(m *BGPUpdate) (bool, error) { eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR) eSubCodeAttrList := uint8(BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST) eSubCodeFlagsError := uint8(BGP_ERROR_SUB_ATTRIBUTE_FLAGS_ERROR) - eSubCodeInvalidNetField := uint8(BGP_ERROR_SUB_INVALID_NETWORK_FIELD) eSubCodeMissing := uint8(BGP_ERROR_SUB_MISSING_WELL_KNOWN_ATTRIBUTE) seen := make(map[BGPAttrType]PathAttributeInterface) @@ -56,14 +56,6 @@ func ValidateUpdateMsg(m *BGPUpdate) (bool, error) { return false, NewMessageError(eCode, eSubCodeMissing, data, eMsg) } - // check NLRI - for _, n := range m.NLRI { - if n.Prefix.To4() == nil { - eMsg := "invalid nlri" - return false, NewMessageError(eCode, eSubCodeInvalidNetField, nil, eMsg) - } - } - return true, nil } @@ -80,12 +72,24 @@ func ValidateAttribute(a PathAttributeInterface) (bool, error) { if v != config.BGP_ORIGIN_ATTR_TYPE_IGP && v != config.BGP_ORIGIN_ATTR_TYPE_EGP && v != config.BGP_ORIGIN_ATTR_TYPE_INCOMPLETE { + data, _ := a.Serialize() eMsg := "invalid origin attribute. value : " + strconv.Itoa(int(v)) - return false, NewMessageError(eCode, eSubCodeBadOrigin, nil, eMsg) + return false, NewMessageError(eCode, eSubCodeBadOrigin, data, eMsg) } case *PathAttributeNextHop: - //check IP address syntax - if p.Value.To4() == nil { + + isZero := func(ip net.IP) bool { + res := ip[0] & 0xff + return res == 0x00 + } + + isClassDorE := func(ip net.IP) bool { + res := ip[0] & 0xe0 + return res == 0xe0 + } + + //check IP address represents host address + if p.Value.IsLoopback() || isZero(p.Value) || isClassDorE(p.Value) { eMsg := "invalid nexthop address" data, _ := a.Serialize() return false, NewMessageError(eCode, eSubCodeBadNextHop, data, eMsg) diff --git a/packet/validate_test.go b/packet/validate_test.go index 3bdb0949..801c3868 100644 --- a/packet/validate_test.go +++ b/packet/validate_test.go @@ -1,11 +1,13 @@ package bgp import ( + "encoding/binary" "github.com/stretchr/testify/assert" + "net" "testing" ) -func update1() *BGPMessage { +func bgpupdate() *BGPMessage { aspath := []AsPathParamInterface{ NewAsPathParam(2, []uint16{65001}), } @@ -21,9 +23,216 @@ func update1() *BGPMessage { } func Test_Validate_OK(t *testing.T) { - message := update1().Body.(*BGPUpdate) + assert := assert.New(t) + message := bgpupdate().Body.(*BGPUpdate) res, err := ValidateUpdateMsg(message) - assert.Equal(t, true, res) - assert.NoError(t, err) + assert.Equal(true, res) + assert.NoError(err) } + +func Test_Validate_wellknown_but_nontransitive(t *testing.T) { + assert := assert.New(t) + message := bgpupdate().Body.(*BGPUpdate) + + originBytes := []byte{0, 1, 1, 1} // 0 means Flags + origin := &PathAttributeOrigin{} + origin.DecodeFromBytes(originBytes) + message.PathAttributes[0] = origin + + res, err := ValidateUpdateMsg(message) + assert.Equal(false, res) + assert.Error(err) + e := err.(*MessageError) + assert.Equal(BGP_ERROR_UPDATE_MESSAGE_ERROR, e.TypeCode) + assert.Equal(BGP_ERROR_SUB_ATTRIBUTE_FLAGS_ERROR, e.SubTypeCode) + assert.Equal(originBytes, e.Data) +} + +func Test_Validate_wellknown_but_partial(t *testing.T) { + assert := assert.New(t) + message := bgpupdate().Body.(*BGPUpdate) + + originBytes := []byte{BGP_ATTR_FLAG_PARTIAL, 1, 1, 1} + origin := &PathAttributeOrigin{} + origin.DecodeFromBytes(originBytes) + message.PathAttributes[0] = origin + + res, err := ValidateUpdateMsg(message) + assert.Equal(false, res) + assert.Error(err) + e := err.(*MessageError) + assert.Equal(BGP_ERROR_UPDATE_MESSAGE_ERROR, e.TypeCode) + assert.Equal(BGP_ERROR_SUB_ATTRIBUTE_FLAGS_ERROR, e.SubTypeCode) + assert.Equal(originBytes, e.Data) +} + +func Test_Validate_optional_nontransitive_but_partial(t *testing.T) { + assert := assert.New(t) + message := bgpupdate().Body.(*BGPUpdate) + f := BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_PARTIAL + originBytes := []byte{byte(f), 1, 1, 1} + origin := &PathAttributeOrigin{} + origin.DecodeFromBytes(originBytes) + message.PathAttributes[0] = origin + + res, err := ValidateUpdateMsg(message) + assert.Equal(false, res) + assert.Error(err) + e := err.(*MessageError) + assert.Equal(BGP_ERROR_UPDATE_MESSAGE_ERROR, e.TypeCode) + assert.Equal(BGP_ERROR_SUB_ATTRIBUTE_FLAGS_ERROR, e.SubTypeCode) + assert.Equal(originBytes, e.Data) +} + +func Test_Validate_flag_mismatch(t *testing.T) { + assert := assert.New(t) + message := bgpupdate().Body.(*BGPUpdate) + f := BGP_ATTR_FLAG_OPTIONAL + // origin needs to be well-known + originBytes := []byte{byte(f), 1, 1, 1} + origin := &PathAttributeOrigin{} + origin.DecodeFromBytes(originBytes) + message.PathAttributes[0] = origin + + res, err := ValidateUpdateMsg(message) + assert.Equal(false, res) + assert.Error(err) + e := err.(*MessageError) + assert.Equal(BGP_ERROR_UPDATE_MESSAGE_ERROR, e.TypeCode) + assert.Equal(BGP_ERROR_SUB_ATTRIBUTE_FLAGS_ERROR, e.SubTypeCode) + assert.Equal(originBytes, e.Data) +} + +func Test_Validate_duplicate_attribute(t *testing.T) { + assert := assert.New(t) + message := bgpupdate().Body.(*BGPUpdate) + // duplicate origin path attribute + originBytes := []byte{pathAttrFlags[BGP_ATTR_TYPE_ORIGIN], 1, 1, 1} + origin := &PathAttributeOrigin{} + origin.DecodeFromBytes(originBytes) + message.PathAttributes = append(message.PathAttributes, origin) + + res, err := ValidateUpdateMsg(message) + assert.Equal(false, res) + assert.Error(err) + e := err.(*MessageError) + assert.Equal(BGP_ERROR_UPDATE_MESSAGE_ERROR, e.TypeCode) + assert.Equal(BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, e.SubTypeCode) + assert.Nil(e.Data) +} + +func Test_Validate_mandatory_missing(t *testing.T) { + assert := assert.New(t) + message := bgpupdate().Body.(*BGPUpdate) + message.PathAttributes = message.PathAttributes[1:] + res, err := ValidateUpdateMsg(message) + assert.Equal(false, res) + assert.Error(err) + e := err.(*MessageError) + assert.Equal(BGP_ERROR_UPDATE_MESSAGE_ERROR, e.TypeCode) + assert.Equal(BGP_ERROR_SUB_MISSING_WELL_KNOWN_ATTRIBUTE, e.SubTypeCode) + missing, _ := binary.Uvarint(e.Data) + assert.Equal(1, missing) +} + +func Test_Validate_invalid_origin(t *testing.T) { + assert := assert.New(t) + message := bgpupdate().Body.(*BGPUpdate) + // origin needs to be well-known + originBytes := []byte{pathAttrFlags[BGP_ATTR_TYPE_ORIGIN], 1, 1, 5} + origin := &PathAttributeOrigin{} + origin.DecodeFromBytes(originBytes) + message.PathAttributes[0] = origin + + res, err := ValidateUpdateMsg(message) + assert.Equal(false, res) + assert.Error(err) + e := err.(*MessageError) + assert.Equal(BGP_ERROR_UPDATE_MESSAGE_ERROR, e.TypeCode) + assert.Equal(BGP_ERROR_SUB_INVALID_ORIGIN_ATTRIBUTE, e.SubTypeCode) + assert.Equal(originBytes, e.Data) +} + +func Test_Validate_invalid_nexthop_zero(t *testing.T) { + assert := assert.New(t) + message := bgpupdate().Body.(*BGPUpdate) + + // invalid nexthop + addr := net.ParseIP("0.0.0.1").To4() + nexthopBytes := []byte{pathAttrFlags[BGP_ATTR_TYPE_NEXT_HOP], 3, 4} + nexthopBytes = append(nexthopBytes, addr...) + nexthop := &PathAttributeNextHop{} + nexthop.DecodeFromBytes(nexthopBytes) + message.PathAttributes[2] = nexthop + + res, err := ValidateUpdateMsg(message) + assert.Equal(false, res) + assert.Error(err) + e := err.(*MessageError) + assert.Equal(BGP_ERROR_UPDATE_MESSAGE_ERROR, e.TypeCode) + assert.Equal(BGP_ERROR_SUB_INVALID_NEXT_HOP_ATTRIBUTE, e.SubTypeCode) + assert.Equal(nexthopBytes, e.Data) +} + +func Test_Validate_invalid_nexthop_lo(t *testing.T) { + assert := assert.New(t) + message := bgpupdate().Body.(*BGPUpdate) + + // invalid nexthop + addr := net.ParseIP("127.0.0.1").To4() + nexthopBytes := []byte{pathAttrFlags[BGP_ATTR_TYPE_NEXT_HOP], 3, 4} + nexthopBytes = append(nexthopBytes, addr...) + nexthop := &PathAttributeNextHop{} + nexthop.DecodeFromBytes(nexthopBytes) + message.PathAttributes[2] = nexthop + + res, err := ValidateUpdateMsg(message) + assert.Equal(false, res) + assert.Error(err) + e := err.(*MessageError) + assert.Equal(BGP_ERROR_UPDATE_MESSAGE_ERROR, e.TypeCode) + assert.Equal(BGP_ERROR_SUB_INVALID_NEXT_HOP_ATTRIBUTE, e.SubTypeCode) + assert.Equal(nexthopBytes, e.Data) +} + +func Test_Validate_invalid_nexthop_de(t *testing.T) { + assert := assert.New(t) + message := bgpupdate().Body.(*BGPUpdate) + + // invalid nexthop + addr := net.ParseIP("224.0.0.1").To4() + nexthopBytes := []byte{pathAttrFlags[BGP_ATTR_TYPE_NEXT_HOP], 3, 4} + nexthopBytes = append(nexthopBytes, addr...) + nexthop := &PathAttributeNextHop{} + nexthop.DecodeFromBytes(nexthopBytes) + message.PathAttributes[2] = nexthop + + res, err := ValidateUpdateMsg(message) + assert.Equal(false, res) + assert.Error(err) + e := err.(*MessageError) + assert.Equal(BGP_ERROR_UPDATE_MESSAGE_ERROR, e.TypeCode) + assert.Equal(BGP_ERROR_SUB_INVALID_NEXT_HOP_ATTRIBUTE, e.SubTypeCode) + assert.Equal(nexthopBytes, e.Data) + +} + +func Test_Validate_unrecognized_well_known(t *testing.T) { + + assert := assert.New(t) + message := bgpupdate().Body.(*BGPUpdate) + f := BGP_ATTR_FLAG_TRANSITIVE + unknownBytes := []byte{byte(f), 30, 1, 1} + unknown := &PathAttributeUnknown{} + unknown.DecodeFromBytes(unknownBytes) + message.PathAttributes = append(message.PathAttributes, unknown) + + res, err := ValidateUpdateMsg(message) + assert.Equal(false, res) + assert.Error(err) + e := err.(*MessageError) + assert.Equal(BGP_ERROR_UPDATE_MESSAGE_ERROR, e.TypeCode) + assert.Equal(BGP_ERROR_SUB_UNRECOGNIZED_WELL_KNOWN_ATTRIBUTE, e.SubTypeCode) + assert.Equal(unknownBytes, e.Data) +} |