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