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  }