-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathIP.h
505 lines (421 loc) · 15.2 KB
/
IP.h
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
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
// See the file "COPYING" in the main distribution directory for copyright.
#pragma once
#include "zeek/zeek-config.h"
// clang-format off
#include <sys/types.h> // for u_char
#include <netinet/in.h>
#include <netinet/ip.h>
// clang-format on
#ifdef HAVE_NETINET_IP6_H
#include <netinet/ip6.h>
#else
#include "net_util.h" // for struct ip6_hdr
#endif
#include <vector>
#include "zeek/IntrusivePtr.h"
namespace zeek {
class IPAddr;
class RecordVal;
class VectorVal;
using RecordValPtr = IntrusivePtr<RecordVal>;
using VectorValPtr = IntrusivePtr<VectorVal>;
namespace detail {
class FragReassembler;
}
#ifndef IPPROTO_MOBILITY
#define IPPROTO_MOBILITY 135
#endif
struct ip6_mobility {
uint8_t ip6mob_payload;
uint8_t ip6mob_len;
uint8_t ip6mob_type;
uint8_t ip6mob_rsv;
uint16_t ip6mob_chksum;
};
/**
* Base class for IPv6 header/extensions.
*/
class IPv6_Hdr {
public:
/**
* Construct an IPv6 header or extension header from assigned type number.
*/
IPv6_Hdr(uint8_t t, const u_char* d) : type(t), data(d) {}
/**
* Replace the value of the next protocol field.
*/
void ChangeNext(uint8_t next_type) {
switch ( type ) {
case IPPROTO_IPV6: ((ip6_hdr*)data)->ip6_nxt = next_type; break;
case IPPROTO_HOPOPTS:
case IPPROTO_DSTOPTS:
case IPPROTO_ROUTING:
case IPPROTO_FRAGMENT:
case IPPROTO_AH:
case IPPROTO_MOBILITY: ((ip6_ext*)data)->ip6e_nxt = next_type; break;
case IPPROTO_ESP:
default: break;
}
}
~IPv6_Hdr() {}
/**
* Returns the assigned IPv6 extension header type number of the header
* that immediately follows this one.
*/
uint8_t NextHdr() const {
switch ( type ) {
case IPPROTO_IPV6: return ((ip6_hdr*)data)->ip6_nxt;
case IPPROTO_HOPOPTS:
case IPPROTO_DSTOPTS:
case IPPROTO_ROUTING:
case IPPROTO_FRAGMENT:
case IPPROTO_AH:
case IPPROTO_MOBILITY: return ((ip6_ext*)data)->ip6e_nxt;
case IPPROTO_ESP:
default: return IPPROTO_NONE;
}
}
/**
* Returns the length of the header in bytes.
*/
uint16_t Length() const {
switch ( type ) {
case IPPROTO_IPV6: return 40;
case IPPROTO_HOPOPTS:
case IPPROTO_DSTOPTS:
case IPPROTO_ROUTING:
case IPPROTO_MOBILITY: return 8 + 8 * ((ip6_ext*)data)->ip6e_len;
case IPPROTO_FRAGMENT: return 8;
case IPPROTO_AH: return 8 + 4 * ((ip6_ext*)data)->ip6e_len;
case IPPROTO_ESP: return 8; // encrypted payload begins after 8 bytes
default: return 0;
}
}
/**
* Returns the RFC 1700 et seq. IANA assigned number for the header.
*/
uint8_t Type() const { return type; }
/**
* Returns pointer to the start of where header structure resides in memory.
*/
const u_char* Data() const { return data; }
/**
* Returns the script-layer record representation of the header.
*/
RecordValPtr ToVal(VectorValPtr chain) const;
RecordValPtr ToVal() const;
protected:
uint8_t type;
const u_char* data;
private:
bool IsOptionTruncated(uint16_t off) const;
};
class IPv6_Hdr_Chain {
public:
/**
* Initializes the header chain from an IPv6 header structure.
*/
IPv6_Hdr_Chain(const struct ip6_hdr* ip6, uint64_t len) { Init(ip6, len, false); }
~IPv6_Hdr_Chain();
/**
* @return a copy of the header chain, but with pointers to individual
* IPv6 headers now pointing within \a new_hdr.
*/
IPv6_Hdr_Chain* Copy(const struct ip6_hdr* new_hdr) const;
/**
* Returns the number of headers in the chain.
*/
size_t Size() const { return chain.size(); }
/**
* Returns the sum of the length of all headers in the chain in bytes.
*/
uint16_t TotalLength() const { return length; }
/**
* Accesses the header at the given location in the chain.
*/
const IPv6_Hdr* operator[](const size_t i) const { return chain[i]; }
/**
* Returns whether the header chain indicates a fragmented packet.
*/
bool IsFragment() const;
/**
* Returns pointer to fragment header structure if the chain contains one.
*/
const struct ip6_frag* GetFragHdr() const {
return IsFragment() ? (const struct ip6_frag*)chain[chain.size() - 1]->Data() : nullptr;
}
/**
* If the header chain is a fragment, returns the offset in number of bytes
* relative to the start of the Fragmentable Part of the original packet.
*/
uint16_t FragOffset() const { return IsFragment() ? (ntohs(GetFragHdr()->ip6f_offlg) & 0xfff8) : 0; }
/**
* If the header chain is a fragment, returns the identification field.
*/
uint32_t ID() const { return IsFragment() ? ntohl(GetFragHdr()->ip6f_ident) : 0; }
/**
* If the header chain is a fragment, returns the M (more fragments) flag.
*/
int MF() const { return IsFragment() ? (ntohs(GetFragHdr()->ip6f_offlg) & 0x0001) != 0 : 0; }
/**
* If the chain contains a Destination Options header with a Home Address
* option as defined by Mobile IPv6 (RFC 6275), then return it, else
* return the source address in the main IPv6 header.
*/
IPAddr SrcAddr() const;
/**
* If the chain contains a Routing header with non-zero segments left,
* then return the last address of the first such header, else return
* the destination address of the main IPv6 header.
*/
IPAddr DstAddr() const;
/**
* Returns a vector of ip6_ext_hdr RecordVals that includes script-layer
* representation of all extension headers in the chain.
*/
VectorValPtr ToVal() const;
protected:
// for access to protected ctor that changes next header values that
// point to a fragment
friend class detail::FragReassembler;
IPv6_Hdr_Chain() = default;
/**
* Initializes the header chain from an IPv6 header structure, and replaces
* the first next protocol pointer field that points to a fragment header.
*/
IPv6_Hdr_Chain(const struct ip6_hdr* ip6, uint16_t next, uint64_t len) { Init(ip6, len, true, next); }
/**
* Initializes the header chain from an IPv6 header structure of a given
* length, possibly setting the first next protocol pointer field that
* points to a fragment header.
*/
void Init(const struct ip6_hdr* ip6, uint64_t total_len, bool set_next, uint16_t next = 0);
/**
* Process a routing header and allocate/remember the final destination
* address if it has segments left and is a valid routing header.
*/
void ProcessRoutingHeader(const struct ip6_rthdr* r, uint16_t len);
/**
* Inspect a Destination Option header's options for things we need to
* remember, such as the Home Address option from Mobile IPv6.
*/
void ProcessDstOpts(const struct ip6_dest* d, uint16_t len);
std::vector<IPv6_Hdr*> chain;
/**
* The summation of all header lengths in the chain in bytes.
*/
uint16_t length = 0;
/**
* Home Address of the packet's source as defined by Mobile IPv6 (RFC 6275).
*/
IPAddr* homeAddr = nullptr;
/**
* The final destination address in chain's first Routing header that has
* non-zero segments left.
*/
IPAddr* finalDst = nullptr;
};
/**
* A class that wraps either an IPv4 or IPv6 packet and abstracts methods
* for inquiring about common features between the two.
*/
class IP_Hdr {
public:
/**
* Construct the header wrapper from an IPv4 packet. Caller must have
* already checked that the header is not truncated.
* @param arg_ip4 pointer to memory containing an IPv4 packet.
* @param arg_del whether to take ownership of \a arg_ip4 pointer's memory.
* @param reassembled whether this header is for a reassembled packet.
*/
IP_Hdr(const struct ip* arg_ip4, bool arg_del, bool reassembled = false)
: ip4(arg_ip4), del(arg_del), reassembled(reassembled) {}
/**
* Construct the header wrapper from an IPv6 packet. Caller must have
* already checked that the static IPv6 header is not truncated. If
* the packet contains extension headers and they are truncated, that can
* be checked afterwards by comparing \a len with \a TotalLen. E.g.
* The IP packet analyzer does this to skip truncated packets.
* @param arg_ip6 pointer to memory containing an IPv6 packet.
* @param arg_del whether to take ownership of \a arg_ip6 pointer's memory.
* @param len the packet's length in bytes.
* @param c an already-constructed header chain to take ownership of.
* @param reassembled whether this header is for a reassembled packet.
*/
IP_Hdr(const struct ip6_hdr* arg_ip6, bool arg_del, uint64_t len, const IPv6_Hdr_Chain* c = nullptr,
bool reassembled = false)
: ip6(arg_ip6), ip6_hdrs(c ? c : new IPv6_Hdr_Chain(ip6, len)), del(arg_del), reassembled(reassembled) {}
/**
* Copy a header. The internal buffer which contains the header data
* must not be truncated. Also note that if that buffer points to a full
* packet payload, only the IP header portion is copied.
*/
IP_Hdr* Copy() const;
/**
* Destructor.
*/
~IP_Hdr() {
delete ip6_hdrs;
if ( del ) {
delete[] (struct ip*)ip4;
delete[] (struct ip6_hdr*)ip6;
}
}
/**
* If an IPv4 packet is wrapped, return a pointer to it, else null.
*/
const struct ip* IP4_Hdr() const { return ip4; }
/**
* If an IPv6 packet is wrapped, return a pointer to it, else null.
*/
const struct ip6_hdr* IP6_Hdr() const { return ip6; }
/**
* Returns the source address held in the IP header.
*/
IPAddr IPHeaderSrcAddr() const;
/**
* Returns the destination address held in the IP header.
*/
IPAddr IPHeaderDstAddr() const;
/**
* For IPv4 or IPv6 headers that don't contain a Home Address option
* (Mobile IPv6, RFC 6275), return source address held in the IP header.
* For IPv6 headers that contain a Home Address option, return that address.
*/
IPAddr SrcAddr() const;
/**
* For IPv4 or IPv6 headers that don't contain a Routing header with
* non-zero segments left, return destination address held in the IP header.
* For IPv6 headers with a Routing header that has non-zero segments left,
* return the last address in the first such Routing header.
*/
IPAddr DstAddr() const;
/**
* Returns a pointer to the payload of the IP packet, usually an
* upper-layer protocol.
*/
const u_char* Payload() const {
if ( ip4 )
return ((const u_char*)ip4) + ip4->ip_hl * 4;
return ((const u_char*)ip6) + ip6_hdrs->TotalLength();
}
/**
* Returns a pointer to the mobility header of the IP packet, if present,
* else a null pointer.
*/
const ip6_mobility* MobilityHeader() const {
if ( ip4 )
return nullptr;
else if ( (*ip6_hdrs)[ip6_hdrs->Size() - 1]->Type() != IPPROTO_MOBILITY )
return nullptr;
else
return (const ip6_mobility*)(*ip6_hdrs)[ip6_hdrs->Size() - 1]->Data();
}
/**
* Returns the length of the IP packet's payload (length of packet minus
* header length or, for IPv6, also minus length of all extension headers).
*
* Also returns 0 if the IPv4 length field is set to zero - which is, e.g.,
* the case when TCP segment offloading is enabled.
*/
uint16_t PayloadLen() const {
if ( ip4 ) {
// prevent overflow in case of segment offloading/zeroed header length.
auto total_len = ntohs(ip4->ip_len);
return total_len ? total_len - ip4->ip_hl * 4 : 0;
}
return ntohs(ip6->ip6_plen) + 40 - ip6_hdrs->TotalLength();
}
/**
* Returns the length of the IP packet (length of headers and payload).
*/
uint32_t TotalLen() const {
if ( ip4 )
return ntohs(ip4->ip_len);
return ntohs(ip6->ip6_plen) + 40;
}
/**
* Returns length of IP packet header (includes extension headers for IPv6).
*/
uint16_t HdrLen() const { return ip4 ? ip4->ip_hl * 4 : ip6_hdrs->TotalLength(); }
/**
* For IPv6 header chains, returns the type of the last header in the chain.
*/
uint8_t LastHeader() const {
if ( ip4 )
return IPPROTO_RAW;
size_t i = ip6_hdrs->Size();
if ( i > 0 )
return (*ip6_hdrs)[i - 1]->Type();
return IPPROTO_NONE;
}
/**
* Returns the protocol type of the IP packet's payload, usually an
* upper-layer protocol. For IPv6, this returns the last (extension)
* header's Next Header value.
*/
unsigned char NextProto() const {
if ( ip4 )
return ip4->ip_p;
size_t i = ip6_hdrs->Size();
if ( i > 0 )
return (*ip6_hdrs)[i - 1]->NextHdr();
return IPPROTO_NONE;
}
/**
* Returns the IPv4 Time to Live or IPv6 Hop Limit field.
*/
unsigned char TTL() const { return ip4 ? ip4->ip_ttl : ip6->ip6_hlim; }
/**
* Returns whether the IP header indicates this packet is a fragment.
*/
bool IsFragment() const { return ip4 ? (ntohs(ip4->ip_off) & 0x3fff) != 0 : ip6_hdrs->IsFragment(); }
/**
* Returns the fragment packet's offset in relation to the original
* packet in bytes.
*/
uint16_t FragOffset() const { return ip4 ? (ntohs(ip4->ip_off) & 0x1fff) * 8 : ip6_hdrs->FragOffset(); }
/**
* Returns the fragment packet's identification field.
*/
uint32_t ID() const { return ip4 ? ntohs(ip4->ip_id) : ip6_hdrs->ID(); }
/**
* Returns whether a fragment packet's "More Fragments" field is set.
*/
int MF() const { return ip4 ? (ntohs(ip4->ip_off) & 0x2000) != 0 : ip6_hdrs->MF(); }
/**
* Returns whether a fragment packet's "Don't Fragment" field is set.
* Note that IPv6 has no such field.
*/
int DF() const { return ip4 ? ((ntohs(ip4->ip_off) & 0x4000) != 0) : 0; }
/**
* Returns value of an IPv6 header's flow label field or 0 if it's IPv4.
*/
uint32_t FlowLabel() const { return ip4 ? 0 : (ntohl(ip6->ip6_flow) & 0x000fffff); }
/**
* Returns number of IP headers in packet (includes IPv6 extension headers).
*/
size_t NumHeaders() const { return ip4 ? 1 : ip6_hdrs->Size(); }
/**
* Returns an ip_hdr or ip6_hdr_chain RecordVal.
*/
RecordValPtr ToIPHdrVal() const;
/**
* Returns a pkt_hdr RecordVal, which includes not only the IP header, but
* also upper-layer (tcp/udp/icmp) headers.
*/
RecordValPtr ToPktHdrVal() const;
/**
* Same as above, but simply add our values into the record at the
* specified starting index.
*/
RecordValPtr ToPktHdrVal(RecordValPtr pkt_hdr, int sindex) const;
bool Reassembled() const { return reassembled; }
private:
const struct ip* ip4 = nullptr;
const struct ip6_hdr* ip6 = nullptr;
const IPv6_Hdr_Chain* ip6_hdrs = nullptr;
bool del = false;
bool reassembled = false;
};
} // namespace zeek