| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236 | // Copyright 2015 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.package icmpimport (	"encoding/binary"	"net"	"strings"	"golang.org/x/net/internal/iana")const (	classInterfaceInfo = 2	afiIPv4 = 1	afiIPv6 = 2)const (	attrMTU = 1 << iota	attrName	attrIPAddr	attrIfIndex)// An InterfaceInfo represents interface and next-hop identification.type InterfaceInfo struct {	Class     int // extension object class number	Type      int // extension object sub-type	Interface *net.Interface	Addr      *net.IPAddr}func (ifi *InterfaceInfo) nameLen() int {	if len(ifi.Interface.Name) > 63 {		return 64	}	l := 1 + len(ifi.Interface.Name)	return (l + 3) &^ 3}func (ifi *InterfaceInfo) attrsAndLen(proto int) (attrs, l int) {	l = 4	if ifi.Interface != nil && ifi.Interface.Index > 0 {		attrs |= attrIfIndex		l += 4		if len(ifi.Interface.Name) > 0 {			attrs |= attrName			l += ifi.nameLen()		}		if ifi.Interface.MTU > 0 {			attrs |= attrMTU			l += 4		}	}	if ifi.Addr != nil {		switch proto {		case iana.ProtocolICMP:			if ifi.Addr.IP.To4() != nil {				attrs |= attrIPAddr				l += 4 + net.IPv4len			}		case iana.ProtocolIPv6ICMP:			if ifi.Addr.IP.To16() != nil && ifi.Addr.IP.To4() == nil {				attrs |= attrIPAddr				l += 4 + net.IPv6len			}		}	}	return}// Len implements the Len method of Extension interface.func (ifi *InterfaceInfo) Len(proto int) int {	_, l := ifi.attrsAndLen(proto)	return l}// Marshal implements the Marshal method of Extension interface.func (ifi *InterfaceInfo) Marshal(proto int) ([]byte, error) {	attrs, l := ifi.attrsAndLen(proto)	b := make([]byte, l)	if err := ifi.marshal(proto, b, attrs, l); err != nil {		return nil, err	}	return b, nil}func (ifi *InterfaceInfo) marshal(proto int, b []byte, attrs, l int) error {	binary.BigEndian.PutUint16(b[:2], uint16(l))	b[2], b[3] = classInterfaceInfo, byte(ifi.Type)	for b = b[4:]; len(b) > 0 && attrs != 0; {		switch {		case attrs&attrIfIndex != 0:			b = ifi.marshalIfIndex(proto, b)			attrs &^= attrIfIndex		case attrs&attrIPAddr != 0:			b = ifi.marshalIPAddr(proto, b)			attrs &^= attrIPAddr		case attrs&attrName != 0:			b = ifi.marshalName(proto, b)			attrs &^= attrName		case attrs&attrMTU != 0:			b = ifi.marshalMTU(proto, b)			attrs &^= attrMTU		}	}	return nil}func (ifi *InterfaceInfo) marshalIfIndex(proto int, b []byte) []byte {	binary.BigEndian.PutUint32(b[:4], uint32(ifi.Interface.Index))	return b[4:]}func (ifi *InterfaceInfo) parseIfIndex(b []byte) ([]byte, error) {	if len(b) < 4 {		return nil, errMessageTooShort	}	ifi.Interface.Index = int(binary.BigEndian.Uint32(b[:4]))	return b[4:], nil}func (ifi *InterfaceInfo) marshalIPAddr(proto int, b []byte) []byte {	switch proto {	case iana.ProtocolICMP:		binary.BigEndian.PutUint16(b[:2], uint16(afiIPv4))		copy(b[4:4+net.IPv4len], ifi.Addr.IP.To4())		b = b[4+net.IPv4len:]	case iana.ProtocolIPv6ICMP:		binary.BigEndian.PutUint16(b[:2], uint16(afiIPv6))		copy(b[4:4+net.IPv6len], ifi.Addr.IP.To16())		b = b[4+net.IPv6len:]	}	return b}func (ifi *InterfaceInfo) parseIPAddr(b []byte) ([]byte, error) {	if len(b) < 4 {		return nil, errMessageTooShort	}	afi := int(binary.BigEndian.Uint16(b[:2]))	b = b[4:]	switch afi {	case afiIPv4:		if len(b) < net.IPv4len {			return nil, errMessageTooShort		}		ifi.Addr.IP = make(net.IP, net.IPv4len)		copy(ifi.Addr.IP, b[:net.IPv4len])		b = b[net.IPv4len:]	case afiIPv6:		if len(b) < net.IPv6len {			return nil, errMessageTooShort		}		ifi.Addr.IP = make(net.IP, net.IPv6len)		copy(ifi.Addr.IP, b[:net.IPv6len])		b = b[net.IPv6len:]	}	return b, nil}func (ifi *InterfaceInfo) marshalName(proto int, b []byte) []byte {	l := byte(ifi.nameLen())	b[0] = l	copy(b[1:], []byte(ifi.Interface.Name))	return b[l:]}func (ifi *InterfaceInfo) parseName(b []byte) ([]byte, error) {	if 4 > len(b) || len(b) < int(b[0]) {		return nil, errMessageTooShort	}	l := int(b[0])	if l%4 != 0 || 4 > l || l > 64 {		return nil, errInvalidExtension	}	var name [63]byte	copy(name[:], b[1:l])	ifi.Interface.Name = strings.Trim(string(name[:]), "\000")	return b[l:], nil}func (ifi *InterfaceInfo) marshalMTU(proto int, b []byte) []byte {	binary.BigEndian.PutUint32(b[:4], uint32(ifi.Interface.MTU))	return b[4:]}func (ifi *InterfaceInfo) parseMTU(b []byte) ([]byte, error) {	if len(b) < 4 {		return nil, errMessageTooShort	}	ifi.Interface.MTU = int(binary.BigEndian.Uint32(b[:4]))	return b[4:], nil}func parseInterfaceInfo(b []byte) (Extension, error) {	ifi := &InterfaceInfo{		Class: int(b[2]),		Type:  int(b[3]),	}	if ifi.Type&(attrIfIndex|attrName|attrMTU) != 0 {		ifi.Interface = &net.Interface{}	}	if ifi.Type&attrIPAddr != 0 {		ifi.Addr = &net.IPAddr{}	}	attrs := ifi.Type & (attrIfIndex | attrIPAddr | attrName | attrMTU)	for b = b[4:]; len(b) > 0 && attrs != 0; {		var err error		switch {		case attrs&attrIfIndex != 0:			b, err = ifi.parseIfIndex(b)			attrs &^= attrIfIndex		case attrs&attrIPAddr != 0:			b, err = ifi.parseIPAddr(b)			attrs &^= attrIPAddr		case attrs&attrName != 0:			b, err = ifi.parseName(b)			attrs &^= attrName		case attrs&attrMTU != 0:			b, err = ifi.parseMTU(b)			attrs &^= attrMTU		}		if err != nil {			return nil, err		}	}	if ifi.Interface != nil && ifi.Interface.Name != "" && ifi.Addr != nil && ifi.Addr.IP.To16() != nil && ifi.Addr.IP.To4() == nil {		ifi.Addr.Zone = ifi.Interface.Name	}	return ifi, nil}
 |