OSDN Git Service

Hulk did something
[bytom/vapor.git] / vendor / golang.org / x / net / icmp / interface.go
diff --git a/vendor/golang.org/x/net/icmp/interface.go b/vendor/golang.org/x/net/icmp/interface.go
new file mode 100644 (file)
index 0000000..78b5b98
--- /dev/null
@@ -0,0 +1,236 @@
+// 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
+
+       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
+}