summaryrefslogtreecommitdiffhomepage
path: root/packet/bgp
diff options
context:
space:
mode:
authorSatoshi Fujimoto <satoshi.fujimoto7@gmail.com>2017-07-31 16:35:40 +0900
committerFUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>2017-09-29 15:05:43 +0900
commite2e8a840e67868cc3070530fe5e1a0dc3edf73f1 (patch)
tree2a7f3ed7b2fe8e384aafabd051f09b8dc875b04b /packet/bgp
parent4158d82bf6129e49b7fbc40809a54ca44820f581 (diff)
packet/bgp: Return ErrorHandling in decoding/validating BGPUpdate
For Revised Error Handling(RFC7606), this patch modifies the BGPUpdate message decoder/validator to return ErrorHandling according to what was detected as an error. In addition, this patch adds some validation defined in RFC7606. Signed-off-by: Satoshi Fujimoto <satoshi.fujimoto7@gmail.com>
Diffstat (limited to 'packet/bgp')
-rw-r--r--packet/bgp/bgp.go43
-rw-r--r--packet/bgp/validate.go56
2 files changed, 77 insertions, 22 deletions
diff --git a/packet/bgp/bgp.go b/packet/bgp/bgp.go
index c8050ab5..7e60b96e 100644
--- a/packet/bgp/bgp.go
+++ b/packet/bgp/bgp.go
@@ -7817,6 +7817,7 @@ type BGPUpdate struct {
}
func (msg *BGPUpdate) DecodeFromBytes(data []byte, options ...*MarshallingOption) error {
+ var strongestError error
// cache error codes
eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR)
@@ -7870,20 +7871,46 @@ func (msg *BGPUpdate) DecodeFromBytes(data []byte, options ...*MarshallingOption
msg.PathAttributes = []PathAttributeInterface{}
for pathlen := msg.TotalPathAttributeLen; pathlen > 0; {
+ var e error
+ if pathlen < 3 {
+ e = NewMessageErrorWithErrorHandling(
+ eCode, BGP_ERROR_SUB_ATTRIBUTE_LENGTH_ERROR, data, ERROR_HANDLING_TREAT_AS_WITHDRAW, nil, "insufficient data to decode")
+ if e.(*MessageError).Stronger(strongestError) {
+ strongestError = e
+ }
+ data = data[pathlen:]
+ break
+ }
p, err := GetPathAttribute(data)
if err != nil {
return err
}
+
err = p.DecodeFromBytes(data, options...)
if err != nil {
- return err
+ e = err.(*MessageError)
+ if e.(*MessageError).SubTypeCode == BGP_ERROR_SUB_ATTRIBUTE_FLAGS_ERROR {
+ e.(*MessageError).ErrorHandling = ERROR_HANDLING_TREAT_AS_WITHDRAW
+ } else {
+ e.(*MessageError).ErrorHandling = getErrorHandlingFromPathAttribute(p.GetType())
+ e.(*MessageError).ErrorAttribute = &p
+ }
+ if e.(*MessageError).Stronger(strongestError) {
+ strongestError = e
+ }
}
pathlen -= uint16(p.Len(options...))
if len(data) < p.Len(options...) {
- return NewMessageError(eCode, BGP_ERROR_SUB_ATTRIBUTE_LENGTH_ERROR, data, "attribute length is short")
+ e = NewMessageErrorWithErrorHandling(
+ eCode, BGP_ERROR_SUB_ATTRIBUTE_LENGTH_ERROR, data, ERROR_HANDLING_TREAT_AS_WITHDRAW, nil, "attribute length is short")
+ if e.(*MessageError).Stronger(strongestError) {
+ strongestError = e
+ }
}
data = data[p.Len(options...):]
- msg.PathAttributes = append(msg.PathAttributes, p)
+ if e == nil || e.(*MessageError).ErrorHandling != ERROR_HANDLING_ATTRIBUTE_DISCARD {
+ msg.PathAttributes = append(msg.PathAttributes, p)
+ }
}
msg.NLRI = make([]*IPAddrPrefix, 0)
@@ -7897,11 +7924,14 @@ func (msg *BGPUpdate) DecodeFromBytes(data []byte, options ...*MarshallingOption
if len(data) < n.Len(options...)+addpathLen {
return NewMessageError(eCode, BGP_ERROR_SUB_INVALID_NETWORK_FIELD, nil, "NLRI length is short")
}
+ if n.Len(options...) > 32 {
+ return NewMessageError(eCode, BGP_ERROR_SUB_INVALID_NETWORK_FIELD, nil, "NLRI length is too long")
+ }
data = data[n.Len(options...)+addpathLen:]
msg.NLRI = append(msg.NLRI, n)
}
- return nil
+ return strongestError
}
func (msg *BGPUpdate) Serialize(options ...*MarshallingOption) ([]byte, error) {
@@ -8125,10 +8155,7 @@ func parseBody(h *BGPHeader, data []byte, options ...*MarshallingOption) (*BGPMe
return nil, NewMessageError(BGP_ERROR_MESSAGE_HEADER_ERROR, BGP_ERROR_SUB_BAD_MESSAGE_TYPE, nil, "unknown message type")
}
err := msg.Body.DecodeFromBytes(data, options...)
- if err != nil {
- return nil, err
- }
- return msg, nil
+ return msg, err
}
func ParseBGPMessage(data []byte, options ...*MarshallingOption) (*BGPMessage, error) {
diff --git a/packet/bgp/validate.go b/packet/bgp/validate.go
index be44e605..eefb7afe 100644
--- a/packet/bgp/validate.go
+++ b/packet/bgp/validate.go
@@ -9,6 +9,8 @@ import (
// Validator for BGPUpdate
func ValidateUpdateMsg(m *BGPUpdate, rfs map[RouteFamily]BGPAddPathMode, doConfedCheck bool) (bool, error) {
+ var strongestError error
+
eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR)
eSubCodeAttrList := uint8(BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST)
eSubCodeMissing := uint8(BGP_ERROR_SUB_MISSING_WELL_KNOWN_ATTRIBUTE)
@@ -20,22 +22,34 @@ func ValidateUpdateMsg(m *BGPUpdate, rfs map[RouteFamily]BGPAddPathMode, doConfe
}
seen := make(map[BGPAttrType]PathAttributeInterface)
+ newAttrs := make([]PathAttributeInterface, 0, len(seen))
// check path attribute
for _, a := range m.PathAttributes {
// check duplication
if _, ok := seen[a.GetType()]; !ok {
seen[a.GetType()] = a
- } else {
+ newAttrs = append(newAttrs, a)
+ //check specific path attribute
+ ok, err := ValidateAttribute(a, rfs, doConfedCheck)
+ if !ok {
+ if err.(*MessageError).ErrorHandling == ERROR_HANDLING_SESSION_RESET {
+ return false, err
+ } else if err.(*MessageError).Stronger(strongestError) {
+ strongestError = err
+ }
+ }
+ } else if a.GetType() == BGP_ATTR_TYPE_MP_REACH_NLRI || a.GetType() == BGP_ATTR_TYPE_MP_UNREACH_NLRI {
eMsg := "the path attribute apears twice. Type : " + strconv.Itoa(int(a.GetType()))
return false, NewMessageError(eCode, eSubCodeAttrList, nil, eMsg)
- }
-
- //check specific path attribute
- ok, e := ValidateAttribute(a, rfs, doConfedCheck)
- if !ok {
- return false, e
+ } else {
+ eMsg := "the path attribute apears twice. Type : " + strconv.Itoa(int(a.GetType()))
+ e := NewMessageErrorWithErrorHandling(eCode, eSubCodeAttrList, nil, ERROR_HANDLING_ATTRIBUTE_DISCARD, nil, eMsg)
+ if e.(*MessageError).Stronger(strongestError) {
+ strongestError = e
+ }
}
}
+ m.PathAttributes = newAttrs
if _, ok := seen[BGP_ATTR_TYPE_MP_REACH_NLRI]; ok || len(m.NLRI) > 0 {
// check the existence of well-known mandatory attributes
@@ -55,13 +69,18 @@ func ValidateUpdateMsg(m *BGPUpdate, rfs map[RouteFamily]BGPAddPathMode, doConfe
if ok, t := exist(mandatory); !ok {
eMsg := "well-known mandatory attributes are not present. type : " + strconv.Itoa(int(t))
data := []byte{byte(t)}
- return false, NewMessageError(eCode, eSubCodeMissing, data, eMsg)
+ e := NewMessageErrorWithErrorHandling(eCode, eSubCodeMissing, data, ERROR_HANDLING_TREAT_AS_WITHDRAW, nil, eMsg)
+ if e.(*MessageError).Stronger(strongestError) {
+ strongestError = e
+ }
}
}
- return true, nil
+
+ return strongestError == nil, strongestError
}
func ValidateAttribute(a PathAttributeInterface, rfs map[RouteFamily]BGPAddPathMode, doConfedCheck bool) (bool, error) {
+ var strongestError error
eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR)
eSubCodeBadOrigin := uint8(BGP_ERROR_SUB_INVALID_ORIGIN_ATTRIBUTE)
@@ -126,7 +145,10 @@ func ValidateAttribute(a PathAttributeInterface, rfs map[RouteFamily]BGPAddPathM
v != BGP_ORIGIN_ATTR_TYPE_INCOMPLETE {
data, _ := a.Serialize()
eMsg := "invalid origin attribute. value : " + strconv.Itoa(int(v))
- return false, NewMessageError(eCode, eSubCodeBadOrigin, data, eMsg)
+ e := NewMessageErrorWithErrorHandling(eCode, eSubCodeBadOrigin, data, getErrorHandlingFromPathAttribute(p.GetType()), nil, eMsg)
+ if e.(*MessageError).Stronger(strongestError) {
+ strongestError = e
+ }
}
case *PathAttributeNextHop:
@@ -144,7 +166,10 @@ func ValidateAttribute(a PathAttributeInterface, rfs map[RouteFamily]BGPAddPathM
if p.Value.IsLoopback() || isZero(p.Value) || isClassDorE(p.Value) {
eMsg := "invalid nexthop address"
data, _ := a.Serialize()
- return false, NewMessageError(eCode, eSubCodeBadNextHop, data, eMsg)
+ e := NewMessageErrorWithErrorHandling(eCode, eSubCodeBadNextHop, data, getErrorHandlingFromPathAttribute(p.GetType()), nil, eMsg)
+ if e.(*MessageError).Stronger(strongestError) {
+ strongestError = e
+ }
}
case *PathAttributeAsPath:
if doConfedCheck {
@@ -158,7 +183,11 @@ func ValidateAttribute(a PathAttributeInterface, rfs map[RouteFamily]BGPAddPathM
}
if segType == BGP_ASPATH_ATTR_TYPE_CONFED_SET || segType == BGP_ASPATH_ATTR_TYPE_CONFED_SEQ {
- return false, NewMessageError(eCode, eSubCodeMalformedAspath, nil, fmt.Sprintf("segment type confederation(%d) found", segType))
+ err := NewMessageErrorWithErrorHandling(
+ eCode, eSubCodeMalformedAspath, nil, getErrorHandlingFromPathAttribute(p.GetType()), nil, fmt.Sprintf("segment type confederation(%d) found", segType))
+ if err.(*MessageError).Stronger(strongestError) {
+ strongestError = err
+ }
}
}
}
@@ -186,8 +215,7 @@ func ValidateAttribute(a PathAttributeInterface, rfs map[RouteFamily]BGPAddPathM
}
}
- return true, nil
-
+ return strongestError == nil, strongestError
}
// validator for PathAttribute