1
2
3
4
5 package icmp
6
7 import (
8 "encoding/binary"
9
10 "golang.org/x/net/internal/iana"
11 "golang.org/x/net/ipv4"
12 "golang.org/x/net/ipv6"
13 )
14
15
16 type Echo struct {
17 ID int
18 Seq int
19 Data []byte
20 }
21
22
23 func (p *Echo) Len(proto int) int {
24 if p == nil {
25 return 0
26 }
27 return 4 + len(p.Data)
28 }
29
30
31 func (p *Echo) Marshal(proto int) ([]byte, error) {
32 b := make([]byte, 4+len(p.Data))
33 binary.BigEndian.PutUint16(b[:2], uint16(p.ID))
34 binary.BigEndian.PutUint16(b[2:4], uint16(p.Seq))
35 copy(b[4:], p.Data)
36 return b, nil
37 }
38
39
40 func parseEcho(proto int, _ Type, b []byte) (MessageBody, error) {
41 bodyLen := len(b)
42 if bodyLen < 4 {
43 return nil, errMessageTooShort
44 }
45 p := &Echo{ID: int(binary.BigEndian.Uint16(b[:2])), Seq: int(binary.BigEndian.Uint16(b[2:4]))}
46 if bodyLen > 4 {
47 p.Data = make([]byte, bodyLen-4)
48 copy(p.Data, b[4:])
49 }
50 return p, nil
51 }
52
53
54
55 type ExtendedEchoRequest struct {
56 ID int
57 Seq int
58 Local bool
59 Extensions []Extension
60 }
61
62
63 func (p *ExtendedEchoRequest) Len(proto int) int {
64 if p == nil {
65 return 0
66 }
67 l, _ := multipartMessageBodyDataLen(proto, false, nil, p.Extensions)
68 return l
69 }
70
71
72 func (p *ExtendedEchoRequest) Marshal(proto int) ([]byte, error) {
73 var typ Type
74 switch proto {
75 case iana.ProtocolICMP:
76 typ = ipv4.ICMPTypeExtendedEchoRequest
77 case iana.ProtocolIPv6ICMP:
78 typ = ipv6.ICMPTypeExtendedEchoRequest
79 default:
80 return nil, errInvalidProtocol
81 }
82 if !validExtensions(typ, p.Extensions) {
83 return nil, errInvalidExtension
84 }
85 b, err := marshalMultipartMessageBody(proto, false, nil, p.Extensions)
86 if err != nil {
87 return nil, err
88 }
89 binary.BigEndian.PutUint16(b[:2], uint16(p.ID))
90 b[2] = byte(p.Seq)
91 if p.Local {
92 b[3] |= 0x01
93 }
94 return b, nil
95 }
96
97
98
99 func parseExtendedEchoRequest(proto int, typ Type, b []byte) (MessageBody, error) {
100 if len(b) < 4 {
101 return nil, errMessageTooShort
102 }
103 p := &ExtendedEchoRequest{ID: int(binary.BigEndian.Uint16(b[:2])), Seq: int(b[2])}
104 if b[3]&0x01 != 0 {
105 p.Local = true
106 }
107 var err error
108 _, p.Extensions, err = parseMultipartMessageBody(proto, typ, b)
109 if err != nil {
110 return nil, err
111 }
112 return p, nil
113 }
114
115
116
117 type ExtendedEchoReply struct {
118 ID int
119 Seq int
120 State int
121 Active bool
122 IPv4 bool
123 IPv6 bool
124 }
125
126
127 func (p *ExtendedEchoReply) Len(proto int) int {
128 if p == nil {
129 return 0
130 }
131 return 4
132 }
133
134
135 func (p *ExtendedEchoReply) Marshal(proto int) ([]byte, error) {
136 b := make([]byte, 4)
137 binary.BigEndian.PutUint16(b[:2], uint16(p.ID))
138 b[2] = byte(p.Seq)
139 b[3] = byte(p.State<<5) & 0xe0
140 if p.Active {
141 b[3] |= 0x04
142 }
143 if p.IPv4 {
144 b[3] |= 0x02
145 }
146 if p.IPv6 {
147 b[3] |= 0x01
148 }
149 return b, nil
150 }
151
152
153
154 func parseExtendedEchoReply(proto int, _ Type, b []byte) (MessageBody, error) {
155 if len(b) < 4 {
156 return nil, errMessageTooShort
157 }
158 p := &ExtendedEchoReply{
159 ID: int(binary.BigEndian.Uint16(b[:2])),
160 Seq: int(b[2]),
161 State: int(b[3]) >> 5,
162 }
163 if b[3]&0x04 != 0 {
164 p.Active = true
165 }
166 if b[3]&0x02 != 0 {
167 p.IPv4 = true
168 }
169 if b[3]&0x01 != 0 {
170 p.IPv6 = true
171 }
172 return p, nil
173 }
174
View as plain text