1 /* $Id$ */
2 /****************************************************************************
3 *
4 * Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
5 * Copyright (C) 2007-2013 Sourcefire, Inc.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License Version 2 as
9 * published by the Free Software Foundation. You may not use, modify or
10 * distribute this program under any other version of the GNU General
11 * Public License.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 *
22 ****************************************************************************/
23
24 #include <string.h>
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28
29 #include "decode.h"
30 #include "reg_test.h"
31
32 #define FAILURE -1
33 #define SUCCESS 0
34 #define IP6_HEADER_LEN 40
35
36 /* Version is the first four bits of the uint32_t passed in */
37 #define IP6_VER(x) \
38 (ntohl(x) >> 28)
39
40 /* The 'Packet' structure is almost always allocated on the stack.
41 * Likewise, return buffers will almost always be aswell.
42 * So, for performance reasons, argument validation can be disabled
43 * and removed from the code at compile time to prevent unecessary extra
44 * conditionals from being checked at run-time. */
45 #define ERR_CHK_LVL 0
46 #if ERR_CHK_LVL == 2
47 #define VALIDATE(x,y) if(!x || !y) return FAILURE;
48 #elif ERR_CHK_LVL == 1
49 #define VALIDATE(x,y) if(!y) return FAILURE;
50 #else
51 #define VALIDATE(x,y)
52 #endif
53
ip6_ret_src(const Packet * p)54 sfaddr_t *ip6_ret_src(const Packet *p)
55 {
56 VALIDATE(p, 1);
57
58 return &p->ip6h->ip_addrs->ip_src;
59 }
60
orig_ip6_ret_src(const Packet * p)61 sfaddr_t *orig_ip6_ret_src(const Packet *p)
62 {
63 VALIDATE(p, 1);
64
65 return &p->orig_ip6h->ip_addrs->ip_src;
66 }
67
ip6_ret_dst(const Packet * p)68 sfaddr_t *ip6_ret_dst(const Packet *p)
69 {
70 VALIDATE(p, 1);
71
72 return &p->ip6h->ip_addrs->ip_dst;
73 }
74
75
orig_ip6_ret_dst(const Packet * p)76 sfaddr_t *orig_ip6_ret_dst(const Packet *p)
77 {
78 VALIDATE(p, 1);
79
80 return &p->orig_ip6h->ip_addrs->ip_dst;
81 }
82
ip6_ret_toc(const Packet * p)83 uint16_t ip6_ret_toc(const Packet *p)
84 {
85 uint16_t toc;
86 VALIDATE(p,1);
87
88 toc = (uint16_t)((ntohl(p->ip6h->vcl) & 0x0FF00000) >> 20);
89
90 return toc;
91 }
92
orig_ip6_ret_toc(const Packet * p)93 uint16_t orig_ip6_ret_toc(const Packet *p)
94 {
95 uint16_t toc;
96 VALIDATE(p,1);
97
98 toc = (uint16_t)((ntohl(p->orig_ip6h->vcl) & 0x0FF00000) >> 20);
99 return toc;
100 }
101
ip6_ret_hops(const Packet * p)102 uint8_t ip6_ret_hops(const Packet *p)
103 {
104 // VALIDATE(p,1);
105
106 return p->ip6h->hop_lmt;
107 }
108
orig_ip6_ret_hops(const Packet * p)109 uint8_t orig_ip6_ret_hops(const Packet *p)
110 {
111 // VALIDATE(p,1);
112
113 return p->orig_ip6h->hop_lmt;
114 }
115
ip6_ret_len(const Packet * p)116 uint16_t ip6_ret_len(const Packet *p)
117 {
118 VALIDATE(p,1);
119
120 /* The length field does not include the header in IPv6, but does in IPv4.
121 * To make this analogous to IPv4, for Snort's purposes, we need to tack
122 * on the difference. */
123 return p->ip6h->len;
124 }
125
orig_ip6_ret_len(const Packet * p)126 uint16_t orig_ip6_ret_len(const Packet *p)
127 {
128 VALIDATE(p,1);
129
130 return p->orig_ip6h->len;
131 }
132
ip6_ret_id(const Packet * p)133 uint32_t ip6_ret_id(const Packet *p)
134 {
135 IP6Frag *frag_hdr;
136 if (p->ip6_extension_count == 0)
137 return 0;
138
139 frag_hdr = (IP6Frag*)p->ip6_extensions[p->ip6_frag_index].data;
140
141 return frag_hdr->ip6f_ident;
142 }
143
orig_ip6_ret_id(const Packet * p)144 uint32_t orig_ip6_ret_id(const Packet *p)
145 {
146 // XXX-IPv6 "NOT YET IMPLEMENTED - IP6 identification"
147 return 0;
148 }
149
ip6_ret_next(const Packet * p)150 uint8_t ip6_ret_next(const Packet *p)
151 {
152 VALIDATE(p,1);
153 return p->ip6h->next;
154 }
155
orig_ip6_ret_next(const Packet * p)156 uint8_t orig_ip6_ret_next(const Packet *p)
157 {
158 VALIDATE(p,1);
159 return p->orig_ip6h->next;
160 }
161
ip6_ret_off(const Packet * p)162 uint16_t ip6_ret_off(const Packet *p)
163 {
164 IP6Frag *frag_hdr;
165 if (p->ip6_extension_count == 0)
166 return 0;
167
168 frag_hdr = (IP6Frag *)p->ip6_extensions[p->ip6_frag_index].data;
169
170 return frag_hdr->ip6f_offlg;
171 }
172
orig_ip6_ret_off(const Packet * p)173 uint16_t orig_ip6_ret_off(const Packet *p)
174 {
175 // XXX-IPv6 "NOT YET IMPLEMENTED - IP6 frag offset"
176 return 0;
177 }
178
ip6_ret_ver(const Packet * p)179 uint8_t ip6_ret_ver(const Packet *p)
180 {
181 return (uint8_t)IP6_VER(p->ip6h->vcl);
182 }
183
orig_ip6_ret_ver(const Packet * p)184 uint8_t orig_ip6_ret_ver(const Packet *p)
185 {
186 return (uint8_t)IP6_VER(p->orig_ip6h->vcl);
187 }
188
ip4_ret_dst(const Packet * p)189 sfaddr_t *ip4_ret_dst(const Packet *p)
190 {
191 VALIDATE(p,1);
192 return &p->ip4h->ip_addrs->ip_dst;
193 }
194
orig_ip4_ret_dst(const Packet * p)195 sfaddr_t *orig_ip4_ret_dst(const Packet *p)
196 {
197 VALIDATE(p,1);
198 return &p->orig_ip4h->ip_addrs->ip_dst;
199 }
200
ip4_ret_src(const Packet * p)201 sfaddr_t *ip4_ret_src(const Packet *p)
202 {
203 VALIDATE(p,1);
204 return &p->ip4h->ip_addrs->ip_src;
205 }
206
orig_ip4_ret_src(const Packet * p)207 sfaddr_t *orig_ip4_ret_src(const Packet *p)
208 {
209 VALIDATE(p,1);
210 return &p->orig_ip4h->ip_addrs->ip_src;
211 }
212
ip4_ret_tos(const Packet * p)213 uint16_t ip4_ret_tos(const Packet *p)
214 {
215 VALIDATE(p,1);
216
217 return p->ip4h->ip_tos;
218 }
219
orig_ip4_ret_tos(const Packet * p)220 uint16_t orig_ip4_ret_tos(const Packet *p)
221 {
222 VALIDATE(p,1);
223
224 return p->orig_ip4h->ip_tos;
225 }
226
ip4_ret_ttl(const Packet * p)227 uint8_t ip4_ret_ttl(const Packet *p)
228 {
229 VALIDATE(p,1);
230
231 return p->ip4h->ip_ttl;
232 }
233
orig_ip4_ret_ttl(const Packet * p)234 uint8_t orig_ip4_ret_ttl(const Packet *p)
235 {
236 VALIDATE(p,1);
237
238 return p->orig_ip4h->ip_ttl;
239 }
240
ip4_ret_len(const Packet * p)241 uint16_t ip4_ret_len(const Packet *p)
242 {
243 VALIDATE(p,1);
244
245 return p->ip4h->ip_len;
246 }
247
orig_ip4_ret_len(const Packet * p)248 uint16_t orig_ip4_ret_len(const Packet *p)
249 {
250 VALIDATE(p,1);
251
252 return p->orig_ip4h->ip_len;
253 }
254
ip4_ret_id(const Packet * p)255 uint32_t ip4_ret_id(const Packet *p)
256 {
257 VALIDATE(p,1);
258
259 return (uint32_t)p->ip4h->ip_id;
260 }
261
orig_ip4_ret_id(const Packet * p)262 uint32_t orig_ip4_ret_id(const Packet *p)
263 {
264 VALIDATE(p,1);
265
266 return (uint32_t)p->orig_ip4h->ip_id;
267 }
268
ip4_ret_proto(const Packet * p)269 uint8_t ip4_ret_proto(const Packet *p)
270 {
271 // VALIDATION()
272
273 return p->ip4h->ip_proto;
274 }
275
orig_ip4_ret_proto(const Packet * p)276 uint8_t orig_ip4_ret_proto(const Packet *p)
277 {
278 // VALIDATION()
279
280 return p->orig_ip4h->ip_proto;
281 }
282
ip4_ret_off(const Packet * p)283 uint16_t ip4_ret_off(const Packet *p)
284 {
285 return p->ip4h->ip_off;
286 }
287
orig_ip4_ret_off(const Packet * p)288 uint16_t orig_ip4_ret_off(const Packet *p)
289 {
290 return p->orig_ip4h->ip_off;
291 }
292
ip4_ret_ver(const Packet * p)293 uint8_t ip4_ret_ver(const Packet *p)
294 {
295 return IP_VER(p->iph);
296 }
297
orig_ip4_ret_ver(const Packet * p)298 uint8_t orig_ip4_ret_ver(const Packet *p)
299 {
300 return IP_VER(p->orig_iph);
301 }
302
ip4_ret_hlen(const Packet * p)303 uint8_t ip4_ret_hlen(const Packet *p)
304 {
305 return IP_HLEN(p->iph);
306 }
307
orig_ip4_ret_hlen(const Packet * p)308 uint8_t orig_ip4_ret_hlen(const Packet *p)
309 {
310 return IP_HLEN(p->orig_iph);
311 }
312
ip6_ret_hlen(const Packet * p)313 uint8_t ip6_ret_hlen(const Packet *p)
314 {
315 /* Snort is expecting this number to be in terms of 32 bit words */
316 return IP6_HDR_LEN / 4 ;
317 }
318
orig_ip6_ret_hlen(const Packet * p)319 uint8_t orig_ip6_ret_hlen(const Packet *p)
320 {
321 return IP6_HDR_LEN / 4;
322 }
323
324 IPH_API ip4 =
325 {
326 ip4_ret_src,
327 ip4_ret_dst,
328 ip4_ret_tos,
329 ip4_ret_ttl,
330 ip4_ret_len,
331 ip4_ret_id,
332 ip4_ret_proto,
333 ip4_ret_off,
334 ip4_ret_ver,
335 ip4_ret_hlen,
336
337 orig_ip4_ret_src,
338 orig_ip4_ret_dst,
339 orig_ip4_ret_tos,
340 orig_ip4_ret_ttl,
341 orig_ip4_ret_len,
342 orig_ip4_ret_id,
343 orig_ip4_ret_proto,
344 orig_ip4_ret_off,
345 orig_ip4_ret_ver,
346 orig_ip4_ret_hlen,
347
348 IPH_API_V4
349 };
350
351 IPH_API ip6 =
352 {
353 ip6_ret_src,
354 ip6_ret_dst,
355 ip6_ret_toc,
356 ip6_ret_hops,
357 ip6_ret_len,
358 ip6_ret_id,
359 ip6_ret_next,
360 ip6_ret_off,
361 ip6_ret_ver,
362 ip6_ret_hlen,
363
364 orig_ip6_ret_src,
365 orig_ip6_ret_dst,
366 orig_ip6_ret_toc,
367 orig_ip6_ret_hops,
368 orig_ip6_ret_len,
369 orig_ip6_ret_id,
370 orig_ip6_ret_next,
371 orig_ip6_ret_off,
372 orig_ip6_ret_ver,
373 orig_ip6_ret_hlen,
374
375 IPH_API_V6
376 };
377
_set_callbacks(struct _Packet * p,int family,char orig)378 static inline void _set_callbacks(struct _Packet *p, int family, char orig)
379 {
380 if ( !orig )
381 {
382 if(family == AF_INET)
383 p->iph_api = &ip4;
384 else
385 p->iph_api = &ip6;
386
387 p->family = family;
388 }
389 else
390 {
391 if(family == AF_INET)
392 p->orig_iph_api = &ip4;
393 else
394 p->orig_iph_api = &ip6;
395
396 p->orig_family = family;
397 }
398 }
399
set_callbacks(struct _Packet * p,int family,char orig)400 void set_callbacks(struct _Packet *p, int family, char orig)
401 {
402 _set_callbacks(p, family, orig);
403 }
404
sfiph_build(Packet * p,const void * hdr,int family)405 void sfiph_build(Packet *p, const void *hdr, int family)
406 {
407 IP6RawHdr *hdr6;
408 IPHdr *hdr4;
409
410 if(!p || !hdr)
411 return;
412
413 /* If family is already set, we've been here before.
414 * That means this is a nested IP. */
415 if (p->family != NO_IP)
416 {
417 memcpy(&p->outer_ips, &p->inner_ips, sizeof(p->outer_ips));
418 if (p->iph_api->ver == IPH_API_V4)
419 {
420 memcpy(&p->outer_ip4h, &p->inner_ip4h, sizeof(p->outer_ip4h) - sizeof(p->outer_ip4h.ip_addrs));
421 p->outer_ip4h.ip_addrs = &p->outer_ips;
422 }
423 else if (p->iph_api->ver == IPH_API_V6)
424 {
425 memcpy(&p->outer_ip6h, &p->inner_ip6h, sizeof(p->outer_ip6h) - sizeof(p->outer_ip6h.ip_addrs));
426 p->outer_ip6h.ip_addrs = &p->outer_ips;
427 }
428
429 p->outer_iph_api = p->iph_api;
430 p->outer_family = p->family;
431 }
432
433 _set_callbacks(p, family, CALLBACK_IP);
434
435 if(family == AF_INET)
436 {
437 hdr4 = (IPHdr*)hdr;
438
439 /* The struct Snort uses is identical to the actual IP4 struct,
440 * with the exception of the IP addresses. Copy over everything but
441 * the IPs */
442 memcpy(&p->inner_ip4h, hdr4, sizeof(IPHdr) - 8);
443 #ifdef HAVE_DAQ_REAL_ADDRESSES
444 if (p->outer_family != NO_IP || !(p->pkth->flags & DAQ_PKT_FLAG_REAL_ADDRESSES))
445 {
446 #endif
447 sfip_set_raw(&p->inner_ips.ip_src, &hdr4->ip_src, AF_INET);
448 sfip_set_raw(&p->inner_ips.ip_dst, &hdr4->ip_dst, AF_INET);
449 #ifdef HAVE_DAQ_REAL_ADDRESSES
450 }
451 else
452 {
453 sfip_set_raw(&p->inner_ips.ip_src, p->pkth->real_sIP.s6_addr, (p->pkth->flags & DAQ_PKT_FLAG_REAL_SIP_V6) ? AF_INET6 : AF_INET);
454 sfip_set_raw(&p->inner_ips.ip_dst, p->pkth->real_dIP.s6_addr, (p->pkth->flags & DAQ_PKT_FLAG_REAL_DIP_V6) ? AF_INET6 : AF_INET);
455 }
456 #endif
457 p->inner_ip4h.ip_addrs = &p->inner_ips;
458 p->actual_ip_len = ntohs(p->inner_ip4h.ip_len);
459 p->ip4h = &p->inner_ip4h;
460 }
461 else
462 {
463 hdr6 = (IP6RawHdr*)hdr;
464
465 /* The struct Snort uses is identical to the actual IP6 struct,
466 * with the exception of the IP addresses. Copy over everything but
467 * the IPs*/
468 memcpy(&p->inner_ip6h, hdr6, sizeof(IP6RawHdr) - 32);
469 #ifdef HAVE_DAQ_REAL_ADDRESSES
470 if (p->outer_family != NO_IP || !(p->pkth->flags & DAQ_PKT_FLAG_REAL_ADDRESSES))
471 {
472 #endif
473 sfip_set_raw(&p->inner_ips.ip_src, &hdr6->ip6_src, family);
474 sfip_set_raw(&p->inner_ips.ip_dst, &hdr6->ip6_dst, family);
475 #ifdef HAVE_DAQ_REAL_ADDRESSES
476 }
477 else
478 {
479 sfip_set_raw(&p->inner_ips.ip_src, p->pkth->real_sIP.s6_addr, (p->pkth->flags & DAQ_PKT_FLAG_REAL_SIP_V6) ? AF_INET6 : AF_INET);
480 sfip_set_raw(&p->inner_ips.ip_dst, p->pkth->real_dIP.s6_addr, (p->pkth->flags & DAQ_PKT_FLAG_REAL_DIP_V6) ? AF_INET6 : AF_INET);
481 }
482 #endif
483 p->inner_ip6h.ip_addrs = &p->inner_ips;
484 p->actual_ip_len = ntohs(p->inner_ip6h.len) + IP6_HDR_LEN;
485 p->ip6h = &p->inner_ip6h;
486 }
487 #ifdef REG_TEST
488 if (rt_ip_increment)
489 {
490 uint32_t* addr;
491 addr = sfaddr_get_ip4_ptr(&p->inner_ips.ip_src);
492 *addr = htonl(ntohl(*addr) + rt_ip_increment);
493 addr = sfaddr_get_ip4_ptr(&p->inner_ips.ip_dst);
494 *addr = htonl(ntohl(*addr) + rt_ip_increment);
495 }
496 #endif
497 }
498
sfiph_orig_build(Packet * p,const void * hdr,int family)499 void sfiph_orig_build(Packet *p, const void *hdr, int family)
500 {
501 IP6RawHdr *hdr6;
502 IPHdr *hdr4;
503
504 if(!p || !hdr)
505 return;
506
507 /* If iph_api is already set, we've been here before.
508 * That means this is a nested IP. */
509 if (p->orig_iph_api)
510 {
511 memcpy(&p->outer_orig_ips, &p->inner_orig_ips, sizeof(p->outer_orig_ips));
512 if (p->orig_iph_api->ver == IPH_API_V4)
513 {
514 memcpy(&p->outer_orig_ip4h, &p->inner_orig_ip4h,
515 sizeof(p->outer_orig_ip4h) - sizeof(p->outer_orig_ip4h.ip_addrs));
516 p->outer_orig_ip4h.ip_addrs = &p->outer_orig_ips;
517 p->outer_orig_iph_api = p->orig_iph_api;
518 }
519 else if (p->orig_iph_api->ver == IPH_API_V6)
520 {
521 memcpy(&p->outer_orig_ip6h, &p->inner_orig_ip6h,
522 sizeof(p->outer_orig_ip6h) - sizeof(p->outer_orig_ip6h.ip_addrs));
523 p->outer_orig_ip6h.ip_addrs = &p->outer_orig_ips;
524 p->outer_orig_iph_api = p->orig_iph_api;
525 }
526 }
527
528 _set_callbacks(p, family, CALLBACK_ICMP_ORIG);
529
530 if(family == AF_INET)
531 {
532 hdr4 = (IPHdr*)hdr;
533
534 /* The struct Snort uses is identical to the actual IP6 struct,
535 * with the exception of the IP addresses. Copy over everything but
536 * the IPs */
537 memcpy(&p->inner_orig_ip4h, hdr4, sizeof(IPHdr) - 8);
538 sfip_set_raw(&p->inner_orig_ips.ip_src, &hdr4->ip_src, family);
539 sfip_set_raw(&p->inner_orig_ips.ip_dst, &hdr4->ip_dst, family);
540 p->inner_orig_ip4h.ip_addrs = &p->inner_orig_ips;
541 p->actual_ip_len = ntohs(p->inner_orig_ip4h.ip_len);
542 p->orig_ip4h = &p->inner_orig_ip4h;
543 }
544 else
545 {
546 hdr6 = (IP6RawHdr*)hdr;
547
548 /* The struct Snort uses is identical to the actual IP6 struct,
549 * with the exception of the IP addresses. Copy over everything but
550 * the IPs*/
551 memcpy(&p->inner_orig_ip6h, hdr6, sizeof(IP6RawHdr) - 32);
552 sfip_set_raw(&p->inner_orig_ips.ip_src, &hdr6->ip6_src, family);
553 sfip_set_raw(&p->inner_orig_ips.ip_dst, &hdr6->ip6_dst, family);
554 p->inner_orig_ip6h.ip_addrs = &p->inner_orig_ips;
555 p->actual_ip_len = ntohs(p->inner_orig_ip6h.len) + IP6_HDR_LEN;
556 p->orig_ip6h = &p->inner_orig_ip6h;
557 }
558 }
559
560 #ifdef TESTER
main()561 int main()
562 {
563 Packet p;
564 IP4Hdr i4;
565 IP6Hdr i6;
566
567 /* This test assumes we get an IPv4 packet and verifies
568 * that the correct callbacks are setup, and they return
569 * the correct values. */
570
571 _set_callbacks(&p, AF_INET, CALLBACK_IP);
572
573 /* Same test as above, but with IPv6 */
574 _set_callbacks(&p, AF_INET6, CALLBACK_IP);
575
576 return 0;
577 }
578 #endif
579