golang.org/x/net@v0.25.1-0.20240516223405-c87a5b62e243/icmp/extension.go (about)

     1  // Copyright 2015 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package icmp
     6  
     7  import (
     8  	"encoding/binary"
     9  
    10  	"golang.org/x/net/ipv4"
    11  	"golang.org/x/net/ipv6"
    12  )
    13  
    14  // An Extension represents an ICMP extension.
    15  type Extension interface {
    16  	// Len returns the length of ICMP extension.
    17  	// The provided proto must be either the ICMPv4 or ICMPv6
    18  	// protocol number.
    19  	Len(proto int) int
    20  
    21  	// Marshal returns the binary encoding of ICMP extension.
    22  	// The provided proto must be either the ICMPv4 or ICMPv6
    23  	// protocol number.
    24  	Marshal(proto int) ([]byte, error)
    25  }
    26  
    27  const extensionVersion = 2
    28  
    29  func validExtensionHeader(b []byte) bool {
    30  	v := int(b[0]&0xf0) >> 4
    31  	s := binary.BigEndian.Uint16(b[2:4])
    32  	if s != 0 {
    33  		s = checksum(b)
    34  	}
    35  	if v != extensionVersion || s != 0 {
    36  		return false
    37  	}
    38  	return true
    39  }
    40  
    41  // parseExtensions parses b as a list of ICMP extensions.
    42  // The length attribute l must be the length attribute field in
    43  // received icmp messages.
    44  //
    45  // It will return a list of ICMP extensions and an adjusted length
    46  // attribute that represents the length of the padded original
    47  // datagram field. Otherwise, it returns an error.
    48  func parseExtensions(typ Type, b []byte, l int) ([]Extension, int, error) {
    49  	// Still a lot of non-RFC 4884 compliant implementations are
    50  	// out there. Set the length attribute l to 128 when it looks
    51  	// inappropriate for backwards compatibility.
    52  	//
    53  	// A minimal extension at least requires 8 octets; 4 octets
    54  	// for an extension header, and 4 octets for a single object
    55  	// header.
    56  	//
    57  	// See RFC 4884 for further information.
    58  	switch typ {
    59  	case ipv4.ICMPTypeExtendedEchoRequest, ipv6.ICMPTypeExtendedEchoRequest:
    60  		if len(b) < 8 || !validExtensionHeader(b) {
    61  			return nil, -1, errNoExtension
    62  		}
    63  		l = 0
    64  	default:
    65  		if 128 > l || l+8 > len(b) {
    66  			l = 128
    67  		}
    68  		if l+8 > len(b) {
    69  			return nil, -1, errNoExtension
    70  		}
    71  		if !validExtensionHeader(b[l:]) {
    72  			if l == 128 {
    73  				return nil, -1, errNoExtension
    74  			}
    75  			l = 128
    76  			if !validExtensionHeader(b[l:]) {
    77  				return nil, -1, errNoExtension
    78  			}
    79  		}
    80  	}
    81  	var exts []Extension
    82  	for b = b[l+4:]; len(b) >= 4; {
    83  		ol := int(binary.BigEndian.Uint16(b[:2]))
    84  		if 4 > ol || ol > len(b) {
    85  			break
    86  		}
    87  		switch b[2] {
    88  		case classMPLSLabelStack:
    89  			ext, err := parseMPLSLabelStack(b[:ol])
    90  			if err != nil {
    91  				return nil, -1, err
    92  			}
    93  			exts = append(exts, ext)
    94  		case classInterfaceInfo:
    95  			ext, err := parseInterfaceInfo(b[:ol])
    96  			if err != nil {
    97  				return nil, -1, err
    98  			}
    99  			exts = append(exts, ext)
   100  		case classInterfaceIdent:
   101  			ext, err := parseInterfaceIdent(b[:ol])
   102  			if err != nil {
   103  				return nil, -1, err
   104  			}
   105  			exts = append(exts, ext)
   106  		default:
   107  			ext := &RawExtension{Data: make([]byte, ol)}
   108  			copy(ext.Data, b[:ol])
   109  			exts = append(exts, ext)
   110  		}
   111  		b = b[ol:]
   112  	}
   113  	return exts, l, nil
   114  }
   115  
   116  func validExtensions(typ Type, exts []Extension) bool {
   117  	switch typ {
   118  	case ipv4.ICMPTypeDestinationUnreachable, ipv4.ICMPTypeTimeExceeded, ipv4.ICMPTypeParameterProblem,
   119  		ipv6.ICMPTypeDestinationUnreachable, ipv6.ICMPTypeTimeExceeded:
   120  		for i := range exts {
   121  			switch exts[i].(type) {
   122  			case *MPLSLabelStack, *InterfaceInfo, *RawExtension:
   123  			default:
   124  				return false
   125  			}
   126  		}
   127  		return true
   128  	case ipv4.ICMPTypeExtendedEchoRequest, ipv6.ICMPTypeExtendedEchoRequest:
   129  		var n int
   130  		for i := range exts {
   131  			switch exts[i].(type) {
   132  			case *InterfaceIdent:
   133  				n++
   134  			case *RawExtension:
   135  			default:
   136  				return false
   137  			}
   138  		}
   139  		// Not a single InterfaceIdent object or a combo of
   140  		// RawExtension and InterfaceIdent objects is not
   141  		// allowed.
   142  		if n == 1 && len(exts) > 1 {
   143  			return false
   144  		}
   145  		return true
   146  	default:
   147  		return false
   148  	}
   149  }
   150  
   151  // A RawExtension represents a raw extension.
   152  //
   153  // A raw extension is excluded from message processing and can be used
   154  // to construct applications such as protocol conformance testing.
   155  type RawExtension struct {
   156  	Data []byte // data
   157  }
   158  
   159  // Len implements the Len method of Extension interface.
   160  func (p *RawExtension) Len(proto int) int {
   161  	if p == nil {
   162  		return 0
   163  	}
   164  	return len(p.Data)
   165  }
   166  
   167  // Marshal implements the Marshal method of Extension interface.
   168  func (p *RawExtension) Marshal(proto int) ([]byte, error) {
   169  	return p.Data, nil
   170  }