github.com/osrg/gobgp@v2.0.0+incompatible/pkg/packet/bgp/validate.go (about) 1 package bgp 2 3 import ( 4 "encoding/binary" 5 "fmt" 6 "math" 7 "net" 8 "strconv" 9 ) 10 11 // Validator for BGPUpdate 12 func ValidateUpdateMsg(m *BGPUpdate, rfs map[RouteFamily]BGPAddPathMode, isEBGP bool, isConfed bool) (bool, error) { 13 var strongestError error 14 15 eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR) 16 eSubCodeAttrList := uint8(BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST) 17 eSubCodeMissing := uint8(BGP_ERROR_SUB_MISSING_WELL_KNOWN_ATTRIBUTE) 18 19 if len(m.NLRI) > 0 || len(m.WithdrawnRoutes) > 0 { 20 if _, ok := rfs[RF_IPv4_UC]; !ok { 21 return false, NewMessageError(0, 0, nil, fmt.Sprintf("Address-family rf %d not available for session", RF_IPv4_UC)) 22 } 23 } 24 25 seen := make(map[BGPAttrType]PathAttributeInterface) 26 newAttrs := make([]PathAttributeInterface, 0, len(seen)) 27 // check path attribute 28 for _, a := range m.PathAttributes { 29 // check duplication 30 if _, ok := seen[a.GetType()]; !ok { 31 seen[a.GetType()] = a 32 newAttrs = append(newAttrs, a) 33 //check specific path attribute 34 ok, err := ValidateAttribute(a, rfs, isEBGP, isConfed) 35 if !ok { 36 if err.(*MessageError).ErrorHandling == ERROR_HANDLING_SESSION_RESET { 37 return false, err 38 } else if err.(*MessageError).Stronger(strongestError) { 39 strongestError = err 40 } 41 } 42 } else if a.GetType() == BGP_ATTR_TYPE_MP_REACH_NLRI || a.GetType() == BGP_ATTR_TYPE_MP_UNREACH_NLRI { 43 eMsg := "the path attribute apears twice. Type : " + strconv.Itoa(int(a.GetType())) 44 return false, NewMessageError(eCode, eSubCodeAttrList, nil, eMsg) 45 } else { 46 eMsg := "the path attribute apears twice. Type : " + strconv.Itoa(int(a.GetType())) 47 e := NewMessageErrorWithErrorHandling(eCode, eSubCodeAttrList, nil, ERROR_HANDLING_ATTRIBUTE_DISCARD, nil, eMsg) 48 if e.(*MessageError).Stronger(strongestError) { 49 strongestError = e 50 } 51 } 52 } 53 m.PathAttributes = newAttrs 54 55 if _, ok := seen[BGP_ATTR_TYPE_MP_REACH_NLRI]; ok || len(m.NLRI) > 0 { 56 // check the existence of well-known mandatory attributes 57 exist := func(attrs []BGPAttrType) (bool, BGPAttrType) { 58 for _, attr := range attrs { 59 _, ok := seen[attr] 60 if !ok { 61 return false, attr 62 } 63 } 64 return true, 0 65 } 66 mandatory := []BGPAttrType{BGP_ATTR_TYPE_ORIGIN, BGP_ATTR_TYPE_AS_PATH} 67 if len(m.NLRI) > 0 { 68 mandatory = append(mandatory, BGP_ATTR_TYPE_NEXT_HOP) 69 } 70 if ok, t := exist(mandatory); !ok { 71 eMsg := "well-known mandatory attributes are not present. type : " + strconv.Itoa(int(t)) 72 data := []byte{byte(t)} 73 e := NewMessageErrorWithErrorHandling(eCode, eSubCodeMissing, data, ERROR_HANDLING_TREAT_AS_WITHDRAW, nil, eMsg) 74 if e.(*MessageError).Stronger(strongestError) { 75 strongestError = e 76 } 77 } 78 } 79 80 return strongestError == nil, strongestError 81 } 82 83 func ValidateAttribute(a PathAttributeInterface, rfs map[RouteFamily]BGPAddPathMode, isEBGP bool, isConfed bool) (bool, error) { 84 var strongestError error 85 86 eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR) 87 eSubCodeBadOrigin := uint8(BGP_ERROR_SUB_INVALID_ORIGIN_ATTRIBUTE) 88 eSubCodeBadNextHop := uint8(BGP_ERROR_SUB_INVALID_NEXT_HOP_ATTRIBUTE) 89 eSubCodeUnknown := uint8(BGP_ERROR_SUB_UNRECOGNIZED_WELL_KNOWN_ATTRIBUTE) 90 eSubCodeMalformedAspath := uint8(BGP_ERROR_SUB_MALFORMED_AS_PATH) 91 92 checkPrefix := func(l []AddrPrefixInterface) error { 93 for _, prefix := range l { 94 rf := AfiSafiToRouteFamily(prefix.AFI(), prefix.SAFI()) 95 if _, ok := rfs[rf]; !ok { 96 return NewMessageError(0, 0, nil, fmt.Sprintf("Address-family %s not available for this session", rf)) 97 } 98 switch rf { 99 case RF_FS_IPv4_UC, RF_FS_IPv6_UC, RF_FS_IPv4_VPN, RF_FS_IPv6_VPN, RF_FS_L2_VPN: 100 t := BGPFlowSpecType(0) 101 value := make([]FlowSpecComponentInterface, 0) 102 switch rf { 103 case RF_FS_IPv4_UC: 104 value = prefix.(*FlowSpecIPv4Unicast).Value 105 case RF_FS_IPv6_UC: 106 value = prefix.(*FlowSpecIPv6Unicast).Value 107 case RF_FS_IPv4_VPN: 108 value = prefix.(*FlowSpecIPv4VPN).Value 109 case RF_FS_IPv6_VPN: 110 value = prefix.(*FlowSpecIPv6VPN).Value 111 case RF_FS_L2_VPN: 112 value = prefix.(*FlowSpecL2VPN).Value 113 } 114 for _, v := range value { 115 if v.Type() <= t { 116 return NewMessageError(0, 0, nil, fmt.Sprintf("%s nlri violate strict type ordering", rf)) 117 } 118 t = v.Type() 119 } 120 } 121 } 122 return nil 123 } 124 125 switch p := a.(type) { 126 case *PathAttributeMpUnreachNLRI: 127 rf := AfiSafiToRouteFamily(p.AFI, p.SAFI) 128 if _, ok := rfs[rf]; !ok { 129 return false, NewMessageError(0, 0, nil, fmt.Sprintf("Address-family rf %d not available for session", rf)) 130 } 131 if err := checkPrefix(p.Value); err != nil { 132 return false, err 133 } 134 case *PathAttributeMpReachNLRI: 135 rf := AfiSafiToRouteFamily(p.AFI, p.SAFI) 136 if _, ok := rfs[rf]; !ok { 137 return false, NewMessageError(0, 0, nil, fmt.Sprintf("Address-family rf %d not available for session", rf)) 138 } 139 if err := checkPrefix(p.Value); err != nil { 140 return false, err 141 } 142 case *PathAttributeOrigin: 143 v := uint8(p.Value) 144 if v != BGP_ORIGIN_ATTR_TYPE_IGP && 145 v != BGP_ORIGIN_ATTR_TYPE_EGP && 146 v != BGP_ORIGIN_ATTR_TYPE_INCOMPLETE { 147 data, _ := a.Serialize() 148 eMsg := "invalid origin attribute. value : " + strconv.Itoa(int(v)) 149 e := NewMessageErrorWithErrorHandling(eCode, eSubCodeBadOrigin, data, getErrorHandlingFromPathAttribute(p.GetType()), nil, eMsg) 150 if e.(*MessageError).Stronger(strongestError) { 151 strongestError = e 152 } 153 } 154 case *PathAttributeNextHop: 155 156 isZero := func(ip net.IP) bool { 157 res := ip[0] & 0xff 158 return res == 0x00 159 } 160 161 isClassDorE := func(ip net.IP) bool { 162 if ip.To4() == nil { 163 // needs to verify ipv6 too? 164 return false 165 } 166 res := ip[0] & 0xe0 167 return res == 0xe0 168 } 169 170 //check IP address represents host address 171 if p.Value.IsLoopback() || isZero(p.Value) || isClassDorE(p.Value) { 172 eMsg := "invalid nexthop address" 173 data, _ := a.Serialize() 174 e := NewMessageErrorWithErrorHandling(eCode, eSubCodeBadNextHop, data, getErrorHandlingFromPathAttribute(p.GetType()), nil, eMsg) 175 if e.(*MessageError).Stronger(strongestError) { 176 strongestError = e 177 } 178 } 179 case *PathAttributeAsPath: 180 if isEBGP { 181 if isConfed { 182 if segType := p.Value[0].GetType(); segType != BGP_ASPATH_ATTR_TYPE_CONFED_SEQ { 183 return false, NewMessageError(eCode, eSubCodeMalformedAspath, nil, fmt.Sprintf("segment type is not confederation seq (%d)", segType)) 184 } 185 } else { 186 for _, param := range p.Value { 187 segType := param.GetType() 188 switch segType { 189 case BGP_ASPATH_ATTR_TYPE_CONFED_SET, BGP_ASPATH_ATTR_TYPE_CONFED_SEQ: 190 err := NewMessageErrorWithErrorHandling( 191 eCode, eSubCodeMalformedAspath, nil, getErrorHandlingFromPathAttribute(p.GetType()), nil, fmt.Sprintf("segment type confederation(%d) found", segType)) 192 if err.(*MessageError).Stronger(strongestError) { 193 strongestError = err 194 } 195 } 196 } 197 } 198 } 199 case *PathAttributeLargeCommunities: 200 uniq := make([]*LargeCommunity, 0, len(p.Values)) 201 for _, x := range p.Values { 202 found := false 203 for _, y := range uniq { 204 if x.String() == y.String() { 205 found = true 206 break 207 } 208 } 209 if !found { 210 uniq = append(uniq, x) 211 } 212 } 213 p.Values = uniq 214 215 case *PathAttributeUnknown: 216 if p.GetFlags()&BGP_ATTR_FLAG_OPTIONAL == 0 { 217 eMsg := fmt.Sprintf("unrecognized well-known attribute %s", p.GetType()) 218 data, _ := a.Serialize() 219 return false, NewMessageError(eCode, eSubCodeUnknown, data, eMsg) 220 } 221 } 222 223 return strongestError == nil, strongestError 224 } 225 226 // validator for PathAttribute 227 func validatePathAttributeFlags(t BGPAttrType, flags BGPAttrFlag) string { 228 229 /* 230 * RFC 4271 P.17 For well-known attributes, the Transitive bit MUST be set to 1. 231 */ 232 if flags&BGP_ATTR_FLAG_OPTIONAL == 0 && flags&BGP_ATTR_FLAG_TRANSITIVE == 0 { 233 eMsg := fmt.Sprintf("well-known attribute %s must have transitive flag 1", t) 234 return eMsg 235 } 236 /* 237 * RFC 4271 P.17 For well-known attributes and for optional non-transitive attributes, 238 * the Partial bit MUST be set to 0. 239 */ 240 if flags&BGP_ATTR_FLAG_OPTIONAL == 0 && flags&BGP_ATTR_FLAG_PARTIAL != 0 { 241 eMsg := fmt.Sprintf("well-known attribute %s must have partial bit 0", t) 242 return eMsg 243 } 244 if flags&BGP_ATTR_FLAG_OPTIONAL != 0 && flags&BGP_ATTR_FLAG_TRANSITIVE == 0 && flags&BGP_ATTR_FLAG_PARTIAL != 0 { 245 eMsg := fmt.Sprintf("optional non-transitive attribute %s must have partial bit 0", t) 246 return eMsg 247 } 248 249 // check flags are correct 250 if f, ok := PathAttrFlags[t]; ok { 251 if f != flags & ^BGP_ATTR_FLAG_EXTENDED_LENGTH & ^BGP_ATTR_FLAG_PARTIAL { 252 eMsg := fmt.Sprintf("flags are invalid. attribute type: %s, expect: %s, actual: %s", t, f, flags) 253 return eMsg 254 } 255 } 256 return "" 257 } 258 259 func validateAsPathValueBytes(data []byte) (bool, error) { 260 eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR) 261 eSubCode := uint8(BGP_ERROR_SUB_MALFORMED_AS_PATH) 262 if len(data)%2 != 0 { 263 return false, NewMessageError(eCode, eSubCode, nil, "AS PATH length is not odd") 264 } 265 266 tryParse := func(data []byte, use4byte bool) (bool, error) { 267 for len(data) > 0 { 268 if len(data) < 2 { 269 return false, NewMessageError(eCode, eSubCode, nil, "AS PATH header is short") 270 } 271 segType := data[0] 272 if segType == 0 || segType > 4 { 273 return false, NewMessageError(eCode, eSubCode, nil, "unknown AS_PATH seg type") 274 } 275 asNum := data[1] 276 data = data[2:] 277 if asNum == 0 || int(asNum) > math.MaxUint8 { 278 return false, NewMessageError(eCode, eSubCode, nil, "AS PATH the number of AS is incorrect") 279 } 280 segLength := int(asNum) 281 if use4byte { 282 segLength *= 4 283 } else { 284 segLength *= 2 285 } 286 if int(segLength) > len(data) { 287 return false, NewMessageError(eCode, eSubCode, nil, "seg length is short") 288 } 289 data = data[segLength:] 290 } 291 return true, nil 292 } 293 _, err := tryParse(data, true) 294 if err == nil { 295 return true, nil 296 } 297 298 _, err = tryParse(data, false) 299 if err == nil { 300 return false, nil 301 } 302 return false, NewMessageError(eCode, eSubCode, nil, "can't parse AS_PATH") 303 } 304 305 func ValidateBGPMessage(m *BGPMessage) error { 306 if m.Header.Len > BGP_MAX_MESSAGE_LENGTH { 307 buf := make([]byte, 2) 308 binary.BigEndian.PutUint16(buf, m.Header.Len) 309 return NewMessageError(BGP_ERROR_MESSAGE_HEADER_ERROR, BGP_ERROR_SUB_BAD_MESSAGE_LENGTH, buf, "too long length") 310 } 311 312 return nil 313 } 314 315 func ValidateOpenMsg(m *BGPOpen, expectedAS uint32) (uint32, error) { 316 if m.Version != 4 { 317 return 0, NewMessageError(BGP_ERROR_OPEN_MESSAGE_ERROR, BGP_ERROR_SUB_UNSUPPORTED_VERSION_NUMBER, nil, fmt.Sprintf("unsupported version %d", m.Version)) 318 } 319 320 as := uint32(m.MyAS) 321 for _, p := range m.OptParams { 322 paramCap, y := p.(*OptionParameterCapability) 323 if !y { 324 continue 325 } 326 for _, c := range paramCap.Capability { 327 if c.Code() == BGP_CAP_FOUR_OCTET_AS_NUMBER { 328 cap := c.(*CapFourOctetASNumber) 329 as = cap.CapValue 330 } 331 } 332 } 333 if expectedAS != 0 && as != expectedAS { 334 return 0, NewMessageError(BGP_ERROR_OPEN_MESSAGE_ERROR, BGP_ERROR_SUB_BAD_PEER_AS, nil, fmt.Sprintf("as number mismatch expected %d, received %d", expectedAS, as)) 335 } 336 337 if m.HoldTime < 3 && m.HoldTime != 0 { 338 return 0, NewMessageError(BGP_ERROR_OPEN_MESSAGE_ERROR, BGP_ERROR_SUB_UNACCEPTABLE_HOLD_TIME, nil, fmt.Sprintf("unacceptable hold time %d", m.HoldTime)) 339 } 340 return as, nil 341 }