github.com/Andyfoo/golang/x/net@v0.0.0-20190901054642-57c1bf301704/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  	"encoding/binary"
     9  	"net"
    10  	"strings"
    11  
    12  	"github.com/Andyfoo/golang/x/net/internal/iana"
    13  )
    14  
    15  const (
    16  	classInterfaceInfo = 2
    17  )
    18  
    19  const (
    20  	attrMTU = 1 << iota
    21  	attrName
    22  	attrIPAddr
    23  	attrIfIndex
    24  )
    25  
    26  // An InterfaceInfo represents interface and next-hop identification.
    27  type InterfaceInfo struct {
    28  	Class     int // extension object class number
    29  	Type      int // extension object sub-type
    30  	Interface *net.Interface
    31  	Addr      *net.IPAddr
    32  }
    33  
    34  func (ifi *InterfaceInfo) nameLen() int {
    35  	if len(ifi.Interface.Name) > 63 {
    36  		return 64
    37  	}
    38  	l := 1 + len(ifi.Interface.Name)
    39  	return (l + 3) &^ 3
    40  }
    41  
    42  func (ifi *InterfaceInfo) attrsAndLen(proto int) (attrs, l int) {
    43  	l = 4
    44  	if ifi.Interface != nil && ifi.Interface.Index > 0 {
    45  		attrs |= attrIfIndex
    46  		l += 4
    47  		if len(ifi.Interface.Name) > 0 {
    48  			attrs |= attrName
    49  			l += ifi.nameLen()
    50  		}
    51  		if ifi.Interface.MTU > 0 {
    52  			attrs |= attrMTU
    53  			l += 4
    54  		}
    55  	}
    56  	if ifi.Addr != nil {
    57  		switch proto {
    58  		case iana.ProtocolICMP:
    59  			if ifi.Addr.IP.To4() != nil {
    60  				attrs |= attrIPAddr
    61  				l += 4 + net.IPv4len
    62  			}
    63  		case iana.ProtocolIPv6ICMP:
    64  			if ifi.Addr.IP.To16() != nil && ifi.Addr.IP.To4() == nil {
    65  				attrs |= attrIPAddr
    66  				l += 4 + net.IPv6len
    67  			}
    68  		}
    69  	}
    70  	return
    71  }
    72  
    73  // Len implements the Len method of Extension interface.
    74  func (ifi *InterfaceInfo) Len(proto int) int {
    75  	_, l := ifi.attrsAndLen(proto)
    76  	return l
    77  }
    78  
    79  // Marshal implements the Marshal method of Extension interface.
    80  func (ifi *InterfaceInfo) Marshal(proto int) ([]byte, error) {
    81  	attrs, l := ifi.attrsAndLen(proto)
    82  	b := make([]byte, l)
    83  	if err := ifi.marshal(proto, b, attrs, l); err != nil {
    84  		return nil, err
    85  	}
    86  	return b, nil
    87  }
    88  
    89  func (ifi *InterfaceInfo) marshal(proto int, b []byte, attrs, l int) error {
    90  	binary.BigEndian.PutUint16(b[:2], uint16(l))
    91  	b[2], b[3] = classInterfaceInfo, byte(ifi.Type)
    92  	for b = b[4:]; len(b) > 0 && attrs != 0; {
    93  		switch {
    94  		case attrs&attrIfIndex != 0:
    95  			b = ifi.marshalIfIndex(proto, b)
    96  			attrs &^= attrIfIndex
    97  		case attrs&attrIPAddr != 0:
    98  			b = ifi.marshalIPAddr(proto, b)
    99  			attrs &^= attrIPAddr
   100  		case attrs&attrName != 0:
   101  			b = ifi.marshalName(proto, b)
   102  			attrs &^= attrName
   103  		case attrs&attrMTU != 0:
   104  			b = ifi.marshalMTU(proto, b)
   105  			attrs &^= attrMTU
   106  		}
   107  	}
   108  	return nil
   109  }
   110  
   111  func (ifi *InterfaceInfo) marshalIfIndex(proto int, b []byte) []byte {
   112  	binary.BigEndian.PutUint32(b[:4], uint32(ifi.Interface.Index))
   113  	return b[4:]
   114  }
   115  
   116  func (ifi *InterfaceInfo) parseIfIndex(b []byte) ([]byte, error) {
   117  	if len(b) < 4 {
   118  		return nil, errMessageTooShort
   119  	}
   120  	ifi.Interface.Index = int(binary.BigEndian.Uint32(b[:4]))
   121  	return b[4:], nil
   122  }
   123  
   124  func (ifi *InterfaceInfo) marshalIPAddr(proto int, b []byte) []byte {
   125  	switch proto {
   126  	case iana.ProtocolICMP:
   127  		binary.BigEndian.PutUint16(b[:2], uint16(iana.AddrFamilyIPv4))
   128  		copy(b[4:4+net.IPv4len], ifi.Addr.IP.To4())
   129  		b = b[4+net.IPv4len:]
   130  	case iana.ProtocolIPv6ICMP:
   131  		binary.BigEndian.PutUint16(b[:2], uint16(iana.AddrFamilyIPv6))
   132  		copy(b[4:4+net.IPv6len], ifi.Addr.IP.To16())
   133  		b = b[4+net.IPv6len:]
   134  	}
   135  	return b
   136  }
   137  
   138  func (ifi *InterfaceInfo) parseIPAddr(b []byte) ([]byte, error) {
   139  	if len(b) < 4 {
   140  		return nil, errMessageTooShort
   141  	}
   142  	afi := int(binary.BigEndian.Uint16(b[:2]))
   143  	b = b[4:]
   144  	switch afi {
   145  	case iana.AddrFamilyIPv4:
   146  		if len(b) < net.IPv4len {
   147  			return nil, errMessageTooShort
   148  		}
   149  		ifi.Addr.IP = make(net.IP, net.IPv4len)
   150  		copy(ifi.Addr.IP, b[:net.IPv4len])
   151  		b = b[net.IPv4len:]
   152  	case iana.AddrFamilyIPv6:
   153  		if len(b) < net.IPv6len {
   154  			return nil, errMessageTooShort
   155  		}
   156  		ifi.Addr.IP = make(net.IP, net.IPv6len)
   157  		copy(ifi.Addr.IP, b[:net.IPv6len])
   158  		b = b[net.IPv6len:]
   159  	}
   160  	return b, nil
   161  }
   162  
   163  func (ifi *InterfaceInfo) marshalName(proto int, b []byte) []byte {
   164  	l := byte(ifi.nameLen())
   165  	b[0] = l
   166  	copy(b[1:], []byte(ifi.Interface.Name))
   167  	return b[l:]
   168  }
   169  
   170  func (ifi *InterfaceInfo) parseName(b []byte) ([]byte, error) {
   171  	if 4 > len(b) || len(b) < int(b[0]) {
   172  		return nil, errMessageTooShort
   173  	}
   174  	l := int(b[0])
   175  	if l%4 != 0 || 4 > l || l > 64 {
   176  		return nil, errInvalidExtension
   177  	}
   178  	var name [63]byte
   179  	copy(name[:], b[1:l])
   180  	ifi.Interface.Name = strings.Trim(string(name[:]), "\000")
   181  	return b[l:], nil
   182  }
   183  
   184  func (ifi *InterfaceInfo) marshalMTU(proto int, b []byte) []byte {
   185  	binary.BigEndian.PutUint32(b[:4], uint32(ifi.Interface.MTU))
   186  	return b[4:]
   187  }
   188  
   189  func (ifi *InterfaceInfo) parseMTU(b []byte) ([]byte, error) {
   190  	if len(b) < 4 {
   191  		return nil, errMessageTooShort
   192  	}
   193  	ifi.Interface.MTU = int(binary.BigEndian.Uint32(b[:4]))
   194  	return b[4:], nil
   195  }
   196  
   197  func parseInterfaceInfo(b []byte) (Extension, error) {
   198  	ifi := &InterfaceInfo{
   199  		Class: int(b[2]),
   200  		Type:  int(b[3]),
   201  	}
   202  	if ifi.Type&(attrIfIndex|attrName|attrMTU) != 0 {
   203  		ifi.Interface = &net.Interface{}
   204  	}
   205  	if ifi.Type&attrIPAddr != 0 {
   206  		ifi.Addr = &net.IPAddr{}
   207  	}
   208  	attrs := ifi.Type & (attrIfIndex | attrIPAddr | attrName | attrMTU)
   209  	for b = b[4:]; len(b) > 0 && attrs != 0; {
   210  		var err error
   211  		switch {
   212  		case attrs&attrIfIndex != 0:
   213  			b, err = ifi.parseIfIndex(b)
   214  			attrs &^= attrIfIndex
   215  		case attrs&attrIPAddr != 0:
   216  			b, err = ifi.parseIPAddr(b)
   217  			attrs &^= attrIPAddr
   218  		case attrs&attrName != 0:
   219  			b, err = ifi.parseName(b)
   220  			attrs &^= attrName
   221  		case attrs&attrMTU != 0:
   222  			b, err = ifi.parseMTU(b)
   223  			attrs &^= attrMTU
   224  		}
   225  		if err != nil {
   226  			return nil, err
   227  		}
   228  	}
   229  	if ifi.Interface != nil && ifi.Interface.Name != "" && ifi.Addr != nil && ifi.Addr.IP.To16() != nil && ifi.Addr.IP.To4() == nil {
   230  		ifi.Addr.Zone = ifi.Interface.Name
   231  	}
   232  	return ifi, nil
   233  }
   234  
   235  const (
   236  	classInterfaceIdent    = 3
   237  	typeInterfaceByName    = 1
   238  	typeInterfaceByIndex   = 2
   239  	typeInterfaceByAddress = 3
   240  )
   241  
   242  // An InterfaceIdent represents interface identification.
   243  type InterfaceIdent struct {
   244  	Class int    // extension object class number
   245  	Type  int    // extension object sub-type
   246  	Name  string // interface name
   247  	Index int    // interface index
   248  	AFI   int    // address family identifier; see address family numbers in IANA registry
   249  	Addr  []byte // address
   250  }
   251  
   252  // Len implements the Len method of Extension interface.
   253  func (ifi *InterfaceIdent) Len(_ int) int {
   254  	switch ifi.Type {
   255  	case typeInterfaceByName:
   256  		l := len(ifi.Name)
   257  		if l > 255 {
   258  			l = 255
   259  		}
   260  		return 4 + (l+3)&^3
   261  	case typeInterfaceByIndex:
   262  		return 4 + 4
   263  	case typeInterfaceByAddress:
   264  		return 4 + 4 + (len(ifi.Addr)+3)&^3
   265  	default:
   266  		return 4
   267  	}
   268  }
   269  
   270  // Marshal implements the Marshal method of Extension interface.
   271  func (ifi *InterfaceIdent) Marshal(proto int) ([]byte, error) {
   272  	b := make([]byte, ifi.Len(proto))
   273  	if err := ifi.marshal(proto, b); err != nil {
   274  		return nil, err
   275  	}
   276  	return b, nil
   277  }
   278  
   279  func (ifi *InterfaceIdent) marshal(proto int, b []byte) error {
   280  	l := ifi.Len(proto)
   281  	binary.BigEndian.PutUint16(b[:2], uint16(l))
   282  	b[2], b[3] = classInterfaceIdent, byte(ifi.Type)
   283  	switch ifi.Type {
   284  	case typeInterfaceByName:
   285  		copy(b[4:], ifi.Name)
   286  	case typeInterfaceByIndex:
   287  		binary.BigEndian.PutUint32(b[4:4+4], uint32(ifi.Index))
   288  	case typeInterfaceByAddress:
   289  		binary.BigEndian.PutUint16(b[4:4+2], uint16(ifi.AFI))
   290  		b[4+2] = byte(len(ifi.Addr))
   291  		copy(b[4+4:], ifi.Addr)
   292  	}
   293  	return nil
   294  }
   295  
   296  func parseInterfaceIdent(b []byte) (Extension, error) {
   297  	ifi := &InterfaceIdent{
   298  		Class: int(b[2]),
   299  		Type:  int(b[3]),
   300  	}
   301  	switch ifi.Type {
   302  	case typeInterfaceByName:
   303  		ifi.Name = strings.Trim(string(b[4:]), string(0))
   304  	case typeInterfaceByIndex:
   305  		if len(b[4:]) < 4 {
   306  			return nil, errInvalidExtension
   307  		}
   308  		ifi.Index = int(binary.BigEndian.Uint32(b[4 : 4+4]))
   309  	case typeInterfaceByAddress:
   310  		if len(b[4:]) < 4 {
   311  			return nil, errInvalidExtension
   312  		}
   313  		ifi.AFI = int(binary.BigEndian.Uint16(b[4 : 4+2]))
   314  		l := int(b[4+2])
   315  		if len(b[4+4:]) < l {
   316  			return nil, errInvalidExtension
   317  		}
   318  		ifi.Addr = make([]byte, l)
   319  		copy(ifi.Addr, b[4+4:])
   320  	}
   321  	return ifi, nil
   322  }