trafgen: add smoke test for drnd packets
[netsniff-ng.git] / src / modifications.c
blob3dc2abfbb537c6ce511407ed6d450b1951e0d1a5
1 /*
2 * Mausezahn - A fast versatile traffic generator
3 * Copyright (C) 2008-2010 Herbert Haas
4 *
5 * This program is free software; you can redistribute it and/or modify it under
6 * the terms of the GNU General Public License version 2 as published by the
7 * Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
12 * details.
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
22 // ***************************************************************************
23 //
24 // This sections contains functions to manipulate headers of
25 // Eth, MPLS, 802.1Q, IP, UDP, and TCP:
26 //
27 // int update_Eth_SA (libnet_t *l, libnet_ptag_t t)
28 // int update_IP_SA (libnet_t *l, libnet_ptag_t t)
29 // int update_IP_DA (libnet_t *l, libnet_ptag_t t)
30 // int update_DPORT (libnet_t *l, libnet_ptag_t t)
31 // int update_SPORT (libnet_t *l, libnet_ptag_t t)
32 // int update_TCP_SQNR (libnet_t *l, libnet_ptag_t t)
33 //
34 // and finally:
35 //
36 // int print_frame_details()
38 // ***************************************************************************
40 #include "mz.h"
41 #include "mops.h"
43 ///////////////////////////////////////////////////////////////////////////
44 // Applies another random Ethernet source address to a given Ethernet-PTAG.
45 // (The calling function should check 'tx.eth_src_rand' whether the SA
46 // should be randomized.)
47 //
48 int update_Eth_SA(libnet_t *l, libnet_ptag_t t)
50 tx.eth_src[0] = (u_int8_t) ( ((float) rand()/RAND_MAX)*256) & 0xFE; // keeps bcast-bit zero
51 tx.eth_src[1] = (u_int8_t) ( ((float) rand()/RAND_MAX)*256);
52 tx.eth_src[2] = (u_int8_t) ( ((float) rand()/RAND_MAX)*256);
53 tx.eth_src[3] = (u_int8_t) ( ((float) rand()/RAND_MAX)*256);
54 tx.eth_src[4] = (u_int8_t) ( ((float) rand()/RAND_MAX)*256);
55 tx.eth_src[5] = (u_int8_t) ( ((float) rand()/RAND_MAX)*256);
57 t = libnet_build_ethernet (tx.eth_dst,
58 tx.eth_src,
59 tx.eth_type,
60 NULL, // the payload
61 0,
62 l,
63 t);
65 if (t == -1)
67 fprintf(stderr, " mz/update_Eth_SA: Can't build Ethernet header: %s\n",
68 libnet_geterror(l));
69 exit(EXIT_FAILURE);
72 return 0;
76 // Update official timestamp, own timestamp and sequence number in the RTP header.
77 // The actual RTP message is stored in tx.udp_payload.
78 int update_RTP(libnet_t *l, libnet_ptag_t t)
80 u_int8_t *ptr;
81 struct mz_timestamp ts;
83 tx.rtp_sqnr++;
84 tx.rtp_stmp+=160; // TODO: different values for different codecs
86 // update SQNR
87 ptr = (u_int8_t*) &tx.rtp_sqnr;
88 tx.udp_payload[2] = *(ptr+1);
89 tx.udp_payload[3] = *ptr;
91 // update official timestamp
92 ptr = (u_int8_t*) &tx.rtp_stmp;
93 tx.udp_payload[4] = *(ptr+3);
94 tx.udp_payload[5] = *(ptr+2);
95 tx.udp_payload[6] = *(ptr+1);
96 tx.udp_payload[7] = *ptr;
99 // update own timestamp
100 getcurtime(&ts); // Now add TX timestamp:
101 mops_hton4 ((u_int32_t*) &ts.sec, &tx.udp_payload[16]);
102 mops_hton4 ((u_int32_t*) &ts.nsec, &tx.udp_payload[20]);
104 t = libnet_build_udp(tx.sp,
105 tx.dp,
106 tx.udp_len,
107 tx.udp_sum,
108 tx.udp_payload,
109 tx.udp_payload_s,
113 if (t == -1) {
114 fprintf(stderr," mz/send_frame: RTP header update failed!\n");
115 exit (1);
117 return 0;
121 ///////////////////////////////////////////////////////////////////////////
122 // Applies another SOURCE IP address,
123 // - either a random one (tx.ip_src_rand==1)
124 // - or from a specified range (tx.ip_src_isrange==1)
125 // to a given IP-PTAG.
127 // Note: tx.ip_src MUST be already initialized with tx.ip_src_start.
128 // This is done by 'get_ip_range_src()' in tools.c.
131 // RETURNS '1' if tx.ip_src restarts
133 int update_IP_SA (libnet_t *l, libnet_ptag_t t)
135 u_int8_t *x, *y;
136 int i=0;
138 if (tx.ip_src_rand)
140 tx.ip_src_h = (u_int32_t) ( ((float) rand()/RAND_MAX)*0xE0000000); //this is 224.0.0.0
141 i=1;
143 else if (tx.ip_src_isrange)
145 tx.ip_src_h++;
146 if (tx.ip_src_h > tx.ip_src_stop) // reached the end of the range => restart!
148 tx.ip_src_h = tx.ip_src_start;
149 i=1;
153 // Now convert "tx.ip_src_h" into "tx.ip_src" which is in 'Network Byte Order':
154 x = (unsigned char*) &tx.ip_src_h;
155 y = (unsigned char*) &tx.ip_src;
157 *y = *(x+3);
158 y++;
159 *y = *(x+2);
160 y++;
161 *y = *(x+1);
162 y++;
163 *y = *x;
165 // TODO: Omit certain IP addresses:
166 // E.g. if (rand_ip == tx.ip_src) goto rand_again; // never use true interface IP
167 // TODO: Check other address exceptions ...
169 t = libnet_build_ipv4 (tx.ip_len,
170 tx.ip_tos,
171 tx.ip_id,
172 tx.ip_frag,
173 tx.ip_ttl,
174 tx.ip_proto,
175 tx.ip_sum,
176 tx.ip_src, // possibly now random
177 tx.ip_dst,
178 (mode==IP) ? (tx.ip_payload_s) ? tx.ip_payload : NULL : NULL, // if e.g. mode=UDP ignore payload argument
179 (mode==IP) ? tx.ip_payload_s : 0,
183 if (t == -1)
185 fprintf(stderr," mz/update_IP_SA: IP address manipulation failed!\n");
186 exit (1);
189 return i;
195 /////////////////////////////////////////////////////////////////////////////////////////
196 // Applies another DESTINATION IP address from a specified range (tx.ip_dst_isrange==1)
197 // to a given IP-PTAG.
199 // Note: tx.ip_dst MUST be already initialized with tx.ip_dst_start.
200 // tx.ip_dst_h 'mirrors' tx.ip_dst
201 // (i. e. tx.ip_dst_h is NOT in network byte order => easy to count)
202 // This is done by 'get_ip_range_dst()' in tools.c.
204 // RETURN VALUE: '1' if tx.ip_dst restarts
206 int update_IP_DA(libnet_t *l, libnet_ptag_t t)
208 u_int8_t *x, *y;
209 int i=0;
212 if (tx.ip_dst_isrange)
214 tx.ip_dst_h++;
215 if (tx.ip_dst_h > tx.ip_dst_stop) // we reached the end of the range => restart!
217 tx.ip_dst_h = tx.ip_dst_start;
218 i=1;
223 // Now convert "tx.ip_dst_h" into "tx.ip_dst" which is in 'Network Byte Order':
225 x = (unsigned char*) &tx.ip_dst_h;
226 y = (unsigned char*) &tx.ip_dst;
228 *y = *(x+3);
229 y++;
230 *y = *(x+2);
231 y++;
232 *y = *(x+1);
233 y++;
234 *y = *x;
237 // TODO: Omit certain IP addresses:
238 // E.g. if (rand_ip == tx.ip_src) goto rand_again; // never use true interface IP
239 // TODO: Check other address exceptions ...
241 t = libnet_build_ipv4 (tx.ip_len,
242 tx.ip_tos,
243 tx.ip_id,
244 tx.ip_frag,
245 tx.ip_ttl,
246 tx.ip_proto,
247 tx.ip_sum,
248 tx.ip_src,
249 tx.ip_dst,
250 (mode==IP) ? (tx.ip_payload_s) ? tx.ip_payload : NULL : NULL, // if e.g. mode=UDP ignore payload argument
251 (mode==IP) ? tx.ip_payload_s : 0,
255 if (t == -1)
257 fprintf(stderr," mz/update_IP_DA: IP address manipulation failed!\n");
258 exit (1);
261 return i;
267 ///////////////////////////////////////////////////////////////////////////////////////
269 // Applies another DESTINATION PORT from a specified range to a given UDP- or TCP-PTAG.
271 // Note: tx.dp MUST be already initialized with tx.dp_start
272 // This is done by 'get_port_range()' in tools.c.
274 // RETURN VALUE: '1' if tx.dp restarts
276 int update_DPORT(libnet_t *l, libnet_ptag_t t)
278 // u_int32_t DP;
279 int i=0;
281 // DP = (u_int32_t) tx.dp;
282 // DP++;
283 tx.dp++;
286 // Exceeded range => restart:
287 if ((tx.dp > tx.dp_stop) || // we exceeded the end of the range
288 (tx.dp == 65535) ) // or exceeded the 16-bit range
290 tx.dp = tx.dp_start;
291 i=1;
295 if (mode==UDP)
297 t = libnet_build_udp(tx.sp,
298 tx.dp,
299 tx.udp_len,
300 tx.udp_sum,
301 (tx.udp_payload_s) ? tx.udp_payload : NULL,
302 tx.udp_payload_s,
306 if (t == -1)
308 fprintf(stderr," mz/send_frame: UDP header manipulation failed!\n");
309 exit (1);
312 else // TCP
314 t = libnet_build_tcp (tx.sp,
315 tx.dp,
316 tx.tcp_seq,
317 tx.tcp_ack,
318 tx.tcp_control,
319 tx.tcp_win,
320 tx.tcp_sum,
321 tx.tcp_urg,
322 tx.tcp_len,
323 (tx.tcp_payload_s) ? tx.tcp_payload : NULL,
324 tx.tcp_payload_s,
328 if (t == -1)
330 fprintf(stderr, " mz/update_DPORT: Can't build TCP header: %s\n", libnet_geterror(l));
331 exit (0);
335 return i;
339 ///////////////////////////////////////////////////////////////////////////////////
341 // Applies another SOURCE PORT from a specified range to a given UDP- or TCP-PTAG.
343 // Note: tx.sp MUST be already initialized with tx.sp_start
344 // This is done by 'get_port_range()' in tools.c.
346 // RETURN VALUE: '1' if tx.sp restarts
348 int update_SPORT(libnet_t *l, libnet_ptag_t t)
351 // u_int32_t SP;
352 int i=0;
354 // SP = (u_int32_t) tx.sp;
355 // SP++;
356 tx.sp++;
359 // Exceeded range => restart:
360 if ((tx.sp > tx.sp_stop) || // we exceeded the end of the range
361 (tx.sp == 65535) ) // or exceeded the 16-bit range
363 tx.sp = tx.sp_start;
364 i=1;
367 if (mode==UDP)
369 t = libnet_build_udp(tx.sp,
370 tx.dp,
371 tx.udp_len,
372 tx.udp_sum,
373 (tx.udp_payload_s) ? tx.udp_payload : NULL,
374 tx.udp_payload_s,
378 if (t == -1)
380 fprintf(stderr," mz/send_frame: UDP header manipulation failed!\n");
381 exit (1);
384 else // TCP
386 t = libnet_build_tcp (tx.sp,
387 tx.dp,
388 tx.tcp_seq,
389 tx.tcp_ack,
390 tx.tcp_control,
391 tx.tcp_win,
392 tx.tcp_sum,
393 tx.tcp_urg,
394 tx.tcp_len,
395 (tx.tcp_payload_s) ? tx.tcp_payload : NULL,
396 tx.tcp_payload_s,
400 if (t == -1)
402 fprintf(stderr, " mz/update_DPORT: Can't build TCP header: %s\n", libnet_geterror(l));
403 exit (0);
407 return i;
410 #define LIBNET_CKSUM_CARRY(x) \
411 (x = (x >> 16) + (x & 0xffff), (~(x + (x >> 16)) & 0xffff))
413 int update_USUM(libnet_t *l, libnet_ptag_t t)
415 int sum = 0;
416 unsigned int tmp;
418 if (tx.udp_sum != 0)
419 return 0;
421 sum += libnet_in_cksum((u_int16_t *) &tx.ip6_src, 16);
422 if (tx.ip_option_s && tx.ip6_segs)
423 sum += libnet_in_cksum((u_int16_t *) &tx.ip_option[tx.ip_option_s - 16], 16); // Use last IP address
424 else
425 sum += libnet_in_cksum((u_int16_t *) &tx.ip6_dst, 16);
427 tmp = htonl(tx.udp_len);
428 sum += libnet_in_cksum((u_int16_t *) &tmp, 4);
429 tmp = htonl(IPPROTO_UDP);
430 sum += libnet_in_cksum((u_int16_t *) &tmp, 4);
432 tmp = ((htons(tx.sp) << 16) + htons(tx.dp));
433 sum += libnet_in_cksum((u_int16_t *) &tmp, 4);
435 tmp = htons(tx.udp_len) << 16;
436 sum += libnet_in_cksum((u_int16_t *) &tmp, 4);
438 if (tx.udp_payload_s)
439 sum += libnet_in_cksum((u_int16_t *) tx.udp_payload, tx.udp_payload_s);
441 tx.udp_sum = ntohs(LIBNET_CKSUM_CARRY(sum));
443 t = libnet_build_udp(tx.sp,
444 tx.dp,
445 tx.udp_len,
446 tx.udp_sum,
447 tx.udp_payload_s ? tx.udp_payload : NULL,
448 tx.udp_payload_s,
451 return t;
454 int update_TSUM(libnet_t *l, libnet_ptag_t t)
456 int sum = 0;
457 unsigned int tmp;
459 if (tx.tcp_sum != 0)
460 return 0;
462 sum += libnet_in_cksum((u_int16_t *) &tx.ip6_src, 16);
463 if (tx.ip_option_s && tx.ip6_segs)
464 sum += libnet_in_cksum((u_int16_t *) &tx.ip_option[tx.ip_option_s - 16], 16); // Use last IP address
465 else
466 sum += libnet_in_cksum((u_int16_t *) &tx.ip6_dst, 16);
468 tmp = htonl(tx.tcp_len);
469 sum += libnet_in_cksum((u_int16_t *) &tmp, 4);
470 tmp = htonl(IPPROTO_TCP);
471 sum += libnet_in_cksum((u_int16_t *) &tmp, 4);
473 tmp = ((htons(tx.sp) << 16) + htons(tx.dp));
474 sum += libnet_in_cksum((u_int16_t *) &tmp, 4);
476 tmp = htonl(tx.tcp_seq);
477 sum += libnet_in_cksum((u_int16_t *) &tmp, 4);
478 tmp = htonl(tx.tcp_ack);
479 sum += libnet_in_cksum((u_int16_t *) &tmp, 4);
481 tmp = ((ntohs(((tx.tcp_offset) << 12) + tx.tcp_control) << 16) + htons(tx.tcp_win));
482 sum += libnet_in_cksum((u_int16_t *) &tmp, 4);
484 tmp = htonl(tx.tcp_urg);
485 sum += libnet_in_cksum((u_int16_t *) &tmp, 4);
487 sum += tx.tcp_sum_part;
489 if (tx.tcp_payload_s)
490 sum += libnet_in_cksum((u_int16_t *) tx.tcp_payload, tx.tcp_payload_s);
492 tx.tcp_sum = ntohs(LIBNET_CKSUM_CARRY(sum));
494 t = libnet_build_tcp (tx.sp,
495 tx.dp,
496 tx.tcp_seq,
497 tx.tcp_ack,
498 tx.tcp_control,
499 tx.tcp_win,
500 tx.tcp_sum,
501 tx.tcp_urg,
502 tx.tcp_len,
503 tx.tcp_payload_s ? tx.tcp_payload : NULL,
504 tx.tcp_payload_s,
508 return t;
511 int update_ISUM(libnet_t *l, libnet_ptag_t t)
513 int sum = 0;
514 unsigned int tmp;
516 if (tx.icmp_chksum != 0)
517 return 0;
519 sum += libnet_in_cksum((u_int16_t *) &tx.ip6_src, 16);
520 if (tx.ip_option_s && tx.ip6_segs)
521 sum += libnet_in_cksum((u_int16_t *) &tx.ip_option[tx.ip_option_s - 16], 16); // Use last IP address
522 else
523 sum += libnet_in_cksum((u_int16_t *) &tx.ip6_dst, 16);
525 tmp = htonl(LIBNET_ICMPV6_H + tx.icmp_payload_s);
526 sum += libnet_in_cksum((u_int16_t *) &tmp, 4);
527 tmp = htonl(IPPROTO_ICMP6);
528 sum += libnet_in_cksum((u_int16_t *) &tmp, 4);
530 tmp = htonl(((tx.icmp_type << 8) + tx.icmp_code));
531 sum += libnet_in_cksum((u_int16_t *) &tmp, 4);
533 if (tx.icmp_payload_s)
534 sum += libnet_in_cksum((u_int16_t *) tx.icmp_payload, tx.icmp_payload_s);
536 tx.icmp_chksum = ntohs(LIBNET_CKSUM_CARRY(sum));
538 t = libnet_build_icmpv4_echo (tx.icmp_type,
539 tx.icmp_code,
540 tx.icmp_chksum,
541 tx.icmp_ident,
542 tx.icmp_sqnr,
543 tx.icmp_payload_s ? tx.icmp_payload : NULL,
544 tx.icmp_payload_s,
548 return t;
551 ///////////////////////////////////////////////////////////////////////
553 // Applies another TCP SQNR from a specified range to a given TCP-PTAG
555 // RETURN VALUE: '1' if tx.txp_seq restarts
557 int update_TCP_SQNR(libnet_t *l, libnet_ptag_t t)
560 u_int32_t diff;
561 int i=0;
563 tx.tcp_seq += tx.tcp_seq_delta;
564 diff = tx.tcp_seq_stop - tx.tcp_seq_start;
566 if (diff < tx.tcp_seq_stop) // start < stop
568 if (tx.tcp_seq > tx.tcp_seq_stop)
570 tx.tcp_seq = tx.tcp_seq_start;
571 i=1;
574 else // stop < start
576 if ( (tx.tcp_seq<tx.tcp_seq_start) &&
577 (tx.tcp_seq>tx.tcp_seq_stop) )
579 tx.tcp_seq = tx.tcp_seq_start;
580 i=1;
585 t = libnet_build_tcp (tx.sp,
586 tx.dp,
587 tx.tcp_seq,
588 tx.tcp_ack,
589 tx.tcp_control,
590 tx.tcp_win,
591 tx.tcp_sum,
592 tx.tcp_urg,
593 tx.tcp_len,
594 (tx.tcp_payload_s) ? tx.tcp_payload : NULL,
595 tx.tcp_payload_s,
599 if (t == -1)
601 fprintf(stderr, " mz/update_TCP_SQNR: Can't build TCP header: %s\n", libnet_geterror(l));
602 exit (0);
605 return i;
609 ////////////////////////////////////////////////////////////////////////
613 int print_frame_details()
615 unsigned char *dum1, *dum2;
616 char pld[65535];
617 char sa[32], da[32];
619 if (!tx.packet_mode)
621 bs2str(tx.eth_dst, da, 6);
622 bs2str(tx.eth_src, sa, 6);
623 fprintf(stderr, " Eth: DA = %s, SA = %s\n",da,sa);
627 if (tx.dot1Q)
629 fprintf(stderr, " 802.1Q VLAN-TAG = %s\n", tx.dot1Q_txt);
632 if (tx.mpls)
634 fprintf(stderr," MPLS labels (label:exp:bos:ttl): %s\n",tx.mpls_verbose_string);
639 dum1 = (unsigned char*) &tx.ip_src_h;
640 dum2 = (unsigned char*) &tx.ip_dst_h;
641 (mode==IP) ? (void) bs2str(tx.ip_payload, pld, tx.ip_payload_s) : strcpy(pld, "[see next layer]");
643 if (ipv6_mode) {
644 char src6[64]; char dst6[64];
645 libnet_addr2name6_r(tx.ip6_src, LIBNET_DONT_RESOLVE, src6, 64);
646 libnet_addr2name6_r(tx.ip6_dst, LIBNET_DONT_RESOLVE, dst6, 64);
648 fprintf(stderr," IP: ver=6, dscp=%u, flow=%u, len=%u, next=%u, hop=%u "
649 "SA=%s, DA=%s\n payload=%s\n", tx.ip_tos, tx.ip_flow,
650 tx.ip_len, tx.ip_proto, tx.ip_ttl, src6, dst6, pld);
652 else {
653 fprintf(stderr," IP: ver=4, len=%u, tos=%u, id=%u, frag=%u, ttl=%u, proto=%u, sum=%u, "
654 "SA=%u.%u.%u.%u, DA=%u.%u.%u.%u,\n"
655 " payload=%s\n", tx.ip_len, tx.ip_tos,
656 tx.ip_id, tx.ip_frag, tx.ip_ttl, tx.ip_proto, tx.ip_sum,
657 *(dum1+3),*(dum1+2),*(dum1+1),*(dum1), *(dum2+3),*(dum2+2),*(dum2+1),*(dum2+0), pld);
660 if ((mode==UDP)||(mode==DNS)||(mode==RTP))
662 bs2str(tx.udp_payload, pld, tx.udp_payload_s);
663 fprintf(stderr, " UDP: sp=%u, dp=%u, len=%u, sum=%u, \n"
664 " payload=%s\n", tx.sp, tx.dp, tx.udp_len, tx.udp_sum, pld);
666 if (mode==TCP) // TODO: Improve message details (flags, ...)
668 bs2str(tx.tcp_payload, pld, tx.tcp_payload_s);
669 fprintf(stderr, " TCP: sp=%u, dp=%u, S=%u, A=%u, flags=%x, win=%u, len=%u, sum=%u, \n"
670 " payload=%s\n",
671 tx.sp, tx.dp, tx.tcp_seq, tx.tcp_ack, tx.tcp_control, tx.tcp_win, tx.tcp_len, tx.tcp_sum, pld);
674 // send_icmp must prepare the verbose string because there are many
675 // different types of ICMP packets...
676 if (mode==ICMP)
678 fprintf(stderr, " %s\n", tx.icmp_verbose_txt);
681 if (mode==ICMP6)
683 fprintf(stderr, " %s\n", tx.icmp_verbose_txt);
686 // libnet_diag_dump_pblock(l);
687 fprintf(stderr,"\n");
689 if (simulate)
691 fprintf(stderr, "*** NOTE: Simulation only! Nothing has been sent! ***\n");
692 exit(0);
696 return 0;