1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
|
// 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"
"golang.org/x/net/ipv4"
"golang.org/x/net/ipv6"
)
// An Extension represents an ICMP extension.
type Extension interface {
// Len returns the length of ICMP extension.
// The provided proto must be either the ICMPv4 or ICMPv6
// protocol number.
Len(proto int) int
// Marshal returns the binary encoding of ICMP extension.
// The provided proto must be either the ICMPv4 or ICMPv6
// protocol number.
Marshal(proto int) ([]byte, error)
}
const extensionVersion = 2
func validExtensionHeader(b []byte) bool {
v := int(b[0]&0xf0) >> 4
s := binary.BigEndian.Uint16(b[2:4])
if s != 0 {
s = checksum(b)
}
if v != extensionVersion || s != 0 {
return false
}
return true
}
// parseExtensions parses b as a list of ICMP extensions.
// The length attribute l must be the length attribute field in
// received icmp messages.
//
// It will return a list of ICMP extensions and an adjusted length
// attribute that represents the length of the padded original
// datagram field. Otherwise, it returns an error.
func parseExtensions(typ Type, b []byte, l int) ([]Extension, int, error) {
// Still a lot of non-RFC 4884 compliant implementations are
// out there. Set the length attribute l to 128 when it looks
// inappropriate for backwards compatibility.
//
// A minimal extension at least requires 8 octets; 4 octets
// for an extension header, and 4 octets for a single object
// header.
//
// See RFC 4884 for further information.
switch typ {
case ipv4.ICMPTypeExtendedEchoRequest, ipv6.ICMPTypeExtendedEchoRequest:
if len(b) < 8 || !validExtensionHeader(b) {
return nil, -1, errNoExtension
}
l = 0
default:
if 128 > l || l+8 > len(b) {
l = 128
}
if l+8 > len(b) {
return nil, -1, errNoExtension
}
if !validExtensionHeader(b[l:]) {
if l == 128 {
return nil, -1, errNoExtension
}
l = 128
if !validExtensionHeader(b[l:]) {
return nil, -1, errNoExtension
}
}
}
var exts []Extension
for b = b[l+4:]; len(b) >= 4; {
ol := int(binary.BigEndian.Uint16(b[:2]))
if 4 > ol || ol > len(b) {
break
}
switch b[2] {
case classMPLSLabelStack:
ext, err := parseMPLSLabelStack(b[:ol])
if err != nil {
return nil, -1, err
}
exts = append(exts, ext)
case classInterfaceInfo:
ext, err := parseInterfaceInfo(b[:ol])
if err != nil {
return nil, -1, err
}
exts = append(exts, ext)
case classInterfaceIdent:
ext, err := parseInterfaceIdent(b[:ol])
if err != nil {
return nil, -1, err
}
exts = append(exts, ext)
default:
ext := &RawExtension{Data: make([]byte, ol)}
copy(ext.Data, b[:ol])
exts = append(exts, ext)
}
b = b[ol:]
}
return exts, l, nil
}
func validExtensions(typ Type, exts []Extension) bool {
switch typ {
case ipv4.ICMPTypeDestinationUnreachable, ipv4.ICMPTypeTimeExceeded, ipv4.ICMPTypeParameterProblem,
ipv6.ICMPTypeDestinationUnreachable, ipv6.ICMPTypeTimeExceeded:
for i := range exts {
switch exts[i].(type) {
case *MPLSLabelStack, *InterfaceInfo, *RawExtension:
default:
return false
}
}
return true
case ipv4.ICMPTypeExtendedEchoRequest, ipv6.ICMPTypeExtendedEchoRequest:
var n int
for i := range exts {
switch exts[i].(type) {
case *InterfaceIdent:
n++
case *RawExtension:
default:
return false
}
}
// Not a single InterfaceIdent object or a combo of
// RawExtension and InterfaceIdent objects is not
// allowed.
if n == 1 && len(exts) > 1 {
return false
}
return true
default:
return false
}
}
// A RawExtension represents a raw extension.
//
// A raw extension is excluded from message processing and can be used
// to construct applications such as protocol conformance testing.
type RawExtension struct {
Data []byte // data
}
// Len implements the Len method of Extension interface.
func (p *RawExtension) Len(proto int) int {
if p == nil {
return 0
}
return len(p.Data)
}
// Marshal implements the Marshal method of Extension interface.
func (p *RawExtension) Marshal(proto int) ([]byte, error) {
return p.Data, nil
}
|