File: extension.go

package info (click to toggle)
golang-golang-x-net 1:0.0+git20191112.2180aed+dfsg-2
  • links: PTS, VCS
  • area: main
  • in suites: bullseye, sid
  • size: 6,584 kB
  • sloc: makefile: 34; asm: 18
file content (170 lines) | stat: -rw-r--r-- 4,277 bytes parent folder | download | duplicates (7)
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
}