github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/net/icmp/interface.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  	"net"
     9  	"strings"
    10  
    11  	"golang.org/x/net/internal/iana"
    12  )
    13  
    14  const (
    15  	classInterfaceInfo = 2
    16  
    17  	afiIPv4 = 1
    18  	afiIPv6 = 2
    19  )
    20  
    21  const (
    22  	attrMTU = 1 << iota
    23  	attrName
    24  	attrIPAddr
    25  	attrIfIndex
    26  )
    27  
    28  // An InterfaceInfo represents interface and next-hop identification.
    29  type InterfaceInfo struct {
    30  	Class     int // extension object class number
    31  	Type      int // extension object sub-type
    32  	Interface *net.Interface
    33  	Addr      *net.IPAddr
    34  }
    35  
    36  func (ifi *InterfaceInfo) nameLen() int {
    37  	if len(ifi.Interface.Name) > 63 {
    38  		return 64
    39  	}
    40  	l := 1 + len(ifi.Interface.Name)
    41  	return (l + 3) &^ 3
    42  }
    43  
    44  func (ifi *InterfaceInfo) attrsAndLen(proto int) (attrs, l int) {
    45  	l = 4
    46  	if ifi.Interface != nil && ifi.Interface.Index > 0 {
    47  		attrs |= attrIfIndex
    48  		l += 4
    49  		if len(ifi.Interface.Name) > 0 {
    50  			attrs |= attrName
    51  			l += ifi.nameLen()
    52  		}
    53  		if ifi.Interface.MTU > 0 {
    54  			attrs |= attrMTU
    55  			l += 4
    56  		}
    57  	}
    58  	if ifi.Addr != nil {
    59  		switch proto {
    60  		case iana.ProtocolICMP:
    61  			if ifi.Addr.IP.To4() != nil {
    62  				attrs |= attrIPAddr
    63  				l += 4 + net.IPv4len
    64  			}
    65  		case iana.ProtocolIPv6ICMP:
    66  			if ifi.Addr.IP.To16() != nil && ifi.Addr.IP.To4() == nil {
    67  				attrs |= attrIPAddr
    68  				l += 4 + net.IPv6len
    69  			}
    70  		}
    71  	}
    72  	return
    73  }
    74  
    75  // Len implements the Len method of Extension interface.
    76  func (ifi *InterfaceInfo) Len(proto int) int {
    77  	_, l := ifi.attrsAndLen(proto)
    78  	return l
    79  }
    80  
    81  // Marshal implements the Marshal method of Extension interface.
    82  func (ifi *InterfaceInfo) Marshal(proto int) ([]byte, error) {
    83  	attrs, l := ifi.attrsAndLen(proto)
    84  	b := make([]byte, l)
    85  	if err := ifi.marshal(proto, b, attrs, l); err != nil {
    86  		return nil, err
    87  	}
    88  	return b, nil
    89  }
    90  
    91  func (ifi *InterfaceInfo) marshal(proto int, b []byte, attrs, l int) error {
    92  	b[0], b[1] = byte(l>>8), byte(l)
    93  	b[2], b[3] = classInterfaceInfo, byte(ifi.Type)
    94  	for b = b[4:]; len(b) > 0 && attrs != 0; {
    95  		switch {
    96  		case attrs&attrIfIndex != 0:
    97  			b = ifi.marshalIfIndex(proto, b)
    98  			attrs &^= attrIfIndex
    99  		case attrs&attrIPAddr != 0:
   100  			b = ifi.marshalIPAddr(proto, b)
   101  			attrs &^= attrIPAddr
   102  		case attrs&attrName != 0:
   103  			b = ifi.marshalName(proto, b)
   104  			attrs &^= attrName
   105  		case attrs&attrMTU != 0:
   106  			b = ifi.marshalMTU(proto, b)
   107  			attrs &^= attrMTU
   108  		}
   109  	}
   110  	return nil
   111  }
   112  
   113  func (ifi *InterfaceInfo) marshalIfIndex(proto int, b []byte) []byte {
   114  	b[0], b[1], b[2], b[3] = byte(ifi.Interface.Index>>24), byte(ifi.Interface.Index>>16), byte(ifi.Interface.Index>>8), byte(ifi.Interface.Index)
   115  	return b[4:]
   116  }
   117  
   118  func (ifi *InterfaceInfo) parseIfIndex(b []byte) ([]byte, error) {
   119  	if len(b) < 4 {
   120  		return nil, errMessageTooShort
   121  	}
   122  	ifi.Interface.Index = int(b[0])<<24 | int(b[1])<<16 | int(b[2])<<8 | int(b[3])
   123  	return b[4:], nil
   124  }
   125  
   126  func (ifi *InterfaceInfo) marshalIPAddr(proto int, b []byte) []byte {
   127  	switch proto {
   128  	case iana.ProtocolICMP:
   129  		b[0], b[1] = byte(afiIPv4>>8), byte(afiIPv4)
   130  		copy(b[4:4+net.IPv4len], ifi.Addr.IP.To4())
   131  		b = b[4+net.IPv4len:]
   132  	case iana.ProtocolIPv6ICMP:
   133  		b[0], b[1] = byte(afiIPv6>>8), byte(afiIPv6)
   134  		copy(b[4:4+net.IPv6len], ifi.Addr.IP.To16())
   135  		b = b[4+net.IPv6len:]
   136  	}
   137  	return b
   138  }
   139  
   140  func (ifi *InterfaceInfo) parseIPAddr(b []byte) ([]byte, error) {
   141  	if len(b) < 4 {
   142  		return nil, errMessageTooShort
   143  	}
   144  	afi := int(b[0])<<8 | int(b[1])
   145  	b = b[4:]
   146  	switch afi {
   147  	case afiIPv4:
   148  		if len(b) < net.IPv4len {
   149  			return nil, errMessageTooShort
   150  		}
   151  		ifi.Addr.IP = make(net.IP, net.IPv4len)
   152  		copy(ifi.Addr.IP, b[:net.IPv4len])
   153  		b = b[net.IPv4len:]
   154  	case afiIPv6:
   155  		if len(b) < net.IPv6len {
   156  			return nil, errMessageTooShort
   157  		}
   158  		ifi.Addr.IP = make(net.IP, net.IPv6len)
   159  		copy(ifi.Addr.IP, b[:net.IPv6len])
   160  		b = b[net.IPv6len:]
   161  	}
   162  	return b, nil
   163  }
   164  
   165  func (ifi *InterfaceInfo) marshalName(proto int, b []byte) []byte {
   166  	l := byte(ifi.nameLen())
   167  	b[0] = l
   168  	copy(b[1:], []byte(ifi.Interface.Name))
   169  	return b[l:]
   170  }
   171  
   172  func (ifi *InterfaceInfo) parseName(b []byte) ([]byte, error) {
   173  	if 4 > len(b) || len(b) < int(b[0]) {
   174  		return nil, errMessageTooShort
   175  	}
   176  	l := int(b[0])
   177  	if l%4 != 0 || 4 > l || l > 64 {
   178  		return nil, errInvalidExtension
   179  	}
   180  	var name [63]byte
   181  	copy(name[:], b[1:l])
   182  	ifi.Interface.Name = strings.Trim(string(name[:]), "\000")
   183  	return b[l:], nil
   184  }
   185  
   186  func (ifi *InterfaceInfo) marshalMTU(proto int, b []byte) []byte {
   187  	b[0], b[1], b[2], b[3] = byte(ifi.Interface.MTU>>24), byte(ifi.Interface.MTU>>16), byte(ifi.Interface.MTU>>8), byte(ifi.Interface.MTU)
   188  	return b[4:]
   189  }
   190  
   191  func (ifi *InterfaceInfo) parseMTU(b []byte) ([]byte, error) {
   192  	if len(b) < 4 {
   193  		return nil, errMessageTooShort
   194  	}
   195  	ifi.Interface.MTU = int(b[0])<<24 | int(b[1])<<16 | int(b[2])<<8 | int(b[3])
   196  	return b[4:], nil
   197  }
   198  
   199  func parseInterfaceInfo(b []byte) (Extension, error) {
   200  	ifi := &InterfaceInfo{
   201  		Class: int(b[2]),
   202  		Type:  int(b[3]),
   203  	}
   204  	if ifi.Type&(attrIfIndex|attrName|attrMTU) != 0 {
   205  		ifi.Interface = &net.Interface{}
   206  	}
   207  	if ifi.Type&attrIPAddr != 0 {
   208  		ifi.Addr = &net.IPAddr{}
   209  	}
   210  	attrs := ifi.Type & (attrIfIndex | attrIPAddr | attrName | attrMTU)
   211  	for b = b[4:]; len(b) > 0 && attrs != 0; {
   212  		var err error
   213  		switch {
   214  		case attrs&attrIfIndex != 0:
   215  			b, err = ifi.parseIfIndex(b)
   216  			attrs &^= attrIfIndex
   217  		case attrs&attrIPAddr != 0:
   218  			b, err = ifi.parseIPAddr(b)
   219  			attrs &^= attrIPAddr
   220  		case attrs&attrName != 0:
   221  			b, err = ifi.parseName(b)
   222  			attrs &^= attrName
   223  		case attrs&attrMTU != 0:
   224  			b, err = ifi.parseMTU(b)
   225  			attrs &^= attrMTU
   226  		}
   227  		if err != nil {
   228  			return nil, err
   229  		}
   230  	}
   231  	if ifi.Interface != nil && ifi.Interface.Name != "" && ifi.Addr != nil && ifi.Addr.IP.To16() != nil && ifi.Addr.IP.To4() == nil {
   232  		ifi.Addr.Zone = ifi.Interface.Name
   233  	}
   234  	return ifi, nil
   235  }