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  }