123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322 |
- // 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 icmp
- import (
- "encoding/binary"
- "net"
- "strings"
- "golang.org/x/net/internal/iana"
- )
- const (
- classInterfaceInfo = 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(iana.AddrFamilyIPv4))
- copy(b[4:4+net.IPv4len], ifi.Addr.IP.To4())
- b = b[4+net.IPv4len:]
- case iana.ProtocolIPv6ICMP:
- binary.BigEndian.PutUint16(b[:2], uint16(iana.AddrFamilyIPv6))
- 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 iana.AddrFamilyIPv4:
- 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 iana.AddrFamilyIPv6:
- 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
- }
- const (
- classInterfaceIdent = 3
- typeInterfaceByName = 1
- typeInterfaceByIndex = 2
- typeInterfaceByAddress = 3
- )
- // An InterfaceIdent represents interface identification.
- type InterfaceIdent struct {
- Class int // extension object class number
- Type int // extension object sub-type
- Name string // interface name
- Index int // interface index
- AFI int // address family identifier; see address family numbers in IANA registry
- Addr []byte // address
- }
- // Len implements the Len method of Extension interface.
- func (ifi *InterfaceIdent) Len(_ int) int {
- switch ifi.Type {
- case typeInterfaceByName:
- l := len(ifi.Name)
- if l > 255 {
- l = 255
- }
- return 4 + (l+3)&^3
- case typeInterfaceByIndex:
- return 4 + 4
- case typeInterfaceByAddress:
- return 4 + 4 + (len(ifi.Addr)+3)&^3
- default:
- return 4
- }
- }
- // Marshal implements the Marshal method of Extension interface.
- func (ifi *InterfaceIdent) Marshal(proto int) ([]byte, error) {
- b := make([]byte, ifi.Len(proto))
- if err := ifi.marshal(proto, b); err != nil {
- return nil, err
- }
- return b, nil
- }
- func (ifi *InterfaceIdent) marshal(proto int, b []byte) error {
- l := ifi.Len(proto)
- binary.BigEndian.PutUint16(b[:2], uint16(l))
- b[2], b[3] = classInterfaceIdent, byte(ifi.Type)
- switch ifi.Type {
- case typeInterfaceByName:
- copy(b[4:], ifi.Name)
- case typeInterfaceByIndex:
- binary.BigEndian.PutUint32(b[4:4+4], uint32(ifi.Index))
- case typeInterfaceByAddress:
- binary.BigEndian.PutUint16(b[4:4+2], uint16(ifi.AFI))
- b[4+2] = byte(len(ifi.Addr))
- copy(b[4+4:], ifi.Addr)
- }
- return nil
- }
- func parseInterfaceIdent(b []byte) (Extension, error) {
- ifi := &InterfaceIdent{
- Class: int(b[2]),
- Type: int(b[3]),
- }
- switch ifi.Type {
- case typeInterfaceByName:
- ifi.Name = strings.Trim(string(b[4:]), "\x00")
- case typeInterfaceByIndex:
- if len(b[4:]) < 4 {
- return nil, errInvalidExtension
- }
- ifi.Index = int(binary.BigEndian.Uint32(b[4 : 4+4]))
- case typeInterfaceByAddress:
- if len(b[4:]) < 4 {
- return nil, errInvalidExtension
- }
- ifi.AFI = int(binary.BigEndian.Uint16(b[4 : 4+2]))
- l := int(b[4+2])
- if len(b[4+4:]) < l {
- return nil, errInvalidExtension
- }
- ifi.Addr = make([]byte, l)
- copy(ifi.Addr, b[4+4:])
- }
- return ifi, nil
- }
|