2 * Mausezahn - A fast versatile traffic generator
3 * Copyright (C) 2008-2010 Herbert Haas
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.
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
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 // ***************************************************************************
24 // This sections contains functions to manipulate headers of
25 // Eth, MPLS, 802.1Q, IP, UDP, and TCP:
27 // int rand_addr (u_int8_t *addr)
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_IP6_SA (libnet_t *l, libnet_ptag_t t)
31 // int update_IP6_DA (libnet_t *l, libnet_ptag_t t)
32 // int update_DPORT (libnet_t *l, libnet_ptag_t t)
33 // int update_SPORT (libnet_t *l, libnet_ptag_t t)
34 // int update_TCP_SQNR (libnet_t *l, libnet_ptag_t t)
38 // int print_frame_details()
40 // ***************************************************************************
45 // Applies another random address to a given buffer.
46 // (The calling function should check 'tx.eth_(dst|src)_rand' whether the address
47 // should be randomized.)
48 void rand_addr(u_int8_t
*addr
)
50 nrand48((unsigned short *)addr
);
51 nrand48((unsigned short *)(addr
+ 3));
53 // Get rid of multicast addresses
56 // Set the locally administered bit
61 // Update official timestamp, own timestamp and sequence number in the RTP header.
62 // The actual RTP message is stored in tx.udp_payload.
63 int update_RTP(libnet_t
*l
, libnet_ptag_t t
)
66 struct mz_timestamp ts
;
69 tx
.rtp_stmp
+=160; // TODO: different values for different codecs
72 ptr
= (u_int8_t
*) &tx
.rtp_sqnr
;
73 tx
.udp_payload
[2] = *(ptr
+1);
74 tx
.udp_payload
[3] = *ptr
;
76 // update official timestamp
77 ptr
= (u_int8_t
*) &tx
.rtp_stmp
;
78 tx
.udp_payload
[4] = *(ptr
+3);
79 tx
.udp_payload
[5] = *(ptr
+2);
80 tx
.udp_payload
[6] = *(ptr
+1);
81 tx
.udp_payload
[7] = *ptr
;
84 // update own timestamp
85 getcurtime(&ts
); // Now add TX timestamp:
86 mops_hton4 ((u_int32_t
*) &ts
.sec
, &tx
.udp_payload
[16]);
87 mops_hton4 ((u_int32_t
*) &ts
.nsec
, &tx
.udp_payload
[20]);
89 t
= libnet_build_udp(tx
.sp
,
99 fprintf(stderr
," mz/send_frame: RTP header update failed!\n");
106 ///////////////////////////////////////////////////////////////////////////
107 // Applies another SOURCE IP address,
108 // - either a random one (tx.ip_src_rand==1)
109 // - or from a specified range (tx.ip_src_isrange==1)
110 // to a given IP-PTAG.
112 // Note: tx.ip_src MUST be already initialized with tx.ip_src_start.
113 // This is done by 'get_ip_range_src()' in tools.c.
116 // RETURNS '1' if tx.ip_src restarts
118 int update_IP_SA (libnet_t
*l
, libnet_ptag_t t
)
124 return update_IP6_SA(l
, t
);
129 tx
.ip_src_h
= (u_int32_t
) ( ((float) rand()/RAND_MAX
)*0xE0000000); //this is 224.0.0.0
132 else if (tx
.ip_src_isrange
)
135 if (tx
.ip_src_h
> tx
.ip_src_stop
) // reached the end of the range => restart!
137 tx
.ip_src_h
= tx
.ip_src_start
;
142 // Now convert "tx.ip_src_h" into "tx.ip_src" which is in 'Network Byte Order':
143 x
= (unsigned char*) &tx
.ip_src_h
;
144 y
= (unsigned char*) &tx
.ip_src
;
154 // TODO: Omit certain IP addresses:
155 // E.g. if (rand_ip == tx.ip_src) goto rand_again; // never use true interface IP
156 // TODO: Check other address exceptions ...
158 t
= libnet_build_ipv4 (tx
.ip_len
,
165 tx
.ip_src
, // possibly now random
167 (mode
==IP
) ? (tx
.ip_payload_s
) ? tx
.ip_payload
: NULL
: NULL
, // if e.g. mode=UDP ignore payload argument
168 (mode
==IP
) ? tx
.ip_payload_s
: 0,
174 fprintf(stderr
," mz/update_IP_SA: IP address manipulation failed!\n");
183 update_IP6_SA(libnet_t
*l
, libnet_ptag_t t
)
186 if (tx
.ip_src_rand
) {
187 fprintf(stderr
, "Random source addresses are not supported in IPv6 mode.\n");
189 } else if (tx
.ip_src_isrange
) {
190 if (incr_in6_addr(tx
.ip6_src
, &tx
.ip6_src
)
191 || (in6_addr_cmp(tx
.ip6_src
, tx
.ip6_src_stop
) > 0))
193 tx
.ip6_src
= tx
.ip6_src_start
;
198 t
= libnet_build_ipv6(tx
.ip_tos
,
205 (mode
==IP
) ? (tx
.ip_payload_s
) ? tx
.ip_payload
: NULL
: NULL
,
206 (mode
==IP
) ? tx
.ip_payload_s
: 0,
211 fprintf(stderr
," mz/update_IP6_SA: IP address manipulation failed!\n");
219 /////////////////////////////////////////////////////////////////////////////////////////
220 // Applies another DESTINATION IP address from a specified range (tx.ip_dst_isrange==1)
221 // to a given IP-PTAG.
223 // Note: tx.ip_dst MUST be already initialized with tx.ip_dst_start.
224 // tx.ip_dst_h 'mirrors' tx.ip_dst
225 // (i. e. tx.ip_dst_h is NOT in network byte order => easy to count)
226 // This is done by 'get_ip_range_dst()' in tools.c.
228 // RETURN VALUE: '1' if tx.ip_dst restarts
230 int update_IP_DA(libnet_t
*l
, libnet_ptag_t t
)
236 return update_IP6_DA(l
, t
);
239 if (tx
.ip_dst_isrange
)
242 if (tx
.ip_dst_h
> tx
.ip_dst_stop
) // we reached the end of the range => restart!
244 tx
.ip_dst_h
= tx
.ip_dst_start
;
250 // Now convert "tx.ip_dst_h" into "tx.ip_dst" which is in 'Network Byte Order':
252 x
= (unsigned char*) &tx
.ip_dst_h
;
253 y
= (unsigned char*) &tx
.ip_dst
;
264 // TODO: Omit certain IP addresses:
265 // E.g. if (rand_ip == tx.ip_src) goto rand_again; // never use true interface IP
266 // TODO: Check other address exceptions ...
268 t
= libnet_build_ipv4 (tx
.ip_len
,
277 (mode
==IP
) ? (tx
.ip_payload_s
) ? tx
.ip_payload
: NULL
: NULL
, // if e.g. mode=UDP ignore payload argument
278 (mode
==IP
) ? tx
.ip_payload_s
: 0,
284 fprintf(stderr
," mz/update_IP_DA: IP address manipulation failed!\n");
293 update_IP6_DA(libnet_t
*l
, libnet_ptag_t t
)
296 if (tx
.ip_dst_isrange
) {
297 if (incr_in6_addr(tx
.ip6_dst
, &tx
.ip6_dst
)
298 || (in6_addr_cmp(tx
.ip6_dst
, tx
.ip6_dst_stop
) > 0))
300 tx
.ip6_dst
= tx
.ip6_dst_start
;
305 t
= libnet_build_ipv6(tx
.ip_tos
,
312 (mode
==IP
) ? (tx
.ip_payload_s
) ? tx
.ip_payload
: NULL
: NULL
,
313 (mode
==IP
) ? tx
.ip_payload_s
: 0,
318 fprintf(stderr
," mz/update_IP6_DA: IP address manipulation failed!\n");
327 ///////////////////////////////////////////////////////////////////////////////////////
329 // Applies another DESTINATION PORT from a specified range to a given UDP- or TCP-PTAG.
331 // Note: tx.dp MUST be already initialized with tx.dp_start
332 // This is done by 'get_port_range()' in tools.c.
334 // RETURN VALUE: '1' if tx.dp restarts
336 int update_DPORT(libnet_t
*l
, libnet_ptag_t t
)
341 // DP = (u_int32_t) tx.dp;
346 // Exceeded range => restart:
347 if ((tx
.dp
> tx
.dp_stop
) || // we exceeded the end of the range
348 (tx
.dp
== 65535) ) // or exceeded the 16-bit range
357 t
= libnet_build_udp(tx
.sp
,
361 (tx
.udp_payload_s
) ? tx
.udp_payload
: NULL
,
368 fprintf(stderr
," mz/send_frame: UDP header manipulation failed!\n");
374 t
= libnet_build_tcp (tx
.sp
,
383 (tx
.tcp_payload_s
) ? tx
.tcp_payload
: NULL
,
390 fprintf(stderr
, " mz/update_DPORT: Can't build TCP header: %s\n", libnet_geterror(l
));
399 ///////////////////////////////////////////////////////////////////////////////////
401 // Applies another SOURCE PORT from a specified range to a given UDP- or TCP-PTAG.
403 // Note: tx.sp MUST be already initialized with tx.sp_start
404 // This is done by 'get_port_range()' in tools.c.
406 // RETURN VALUE: '1' if tx.sp restarts
408 int update_SPORT(libnet_t
*l
, libnet_ptag_t t
)
414 // SP = (u_int32_t) tx.sp;
419 // Exceeded range => restart:
420 if ((tx
.sp
> tx
.sp_stop
) || // we exceeded the end of the range
421 (tx
.sp
== 65535) ) // or exceeded the 16-bit range
429 t
= libnet_build_udp(tx
.sp
,
433 (tx
.udp_payload_s
) ? tx
.udp_payload
: NULL
,
440 fprintf(stderr
," mz/send_frame: UDP header manipulation failed!\n");
446 t
= libnet_build_tcp (tx
.sp
,
455 (tx
.tcp_payload_s
) ? tx
.tcp_payload
: NULL
,
462 fprintf(stderr
, " mz/update_SPORT: Can't build TCP header: %s\n", libnet_geterror(l
));
470 #define LIBNET_CKSUM_CARRY(x) \
471 (x = (x >> 16) + (x & 0xffff), (~(x + (x >> 16)) & 0xffff))
473 int update_USUM(libnet_t
*l
, libnet_ptag_t t
)
481 sum
+= libnet_in_cksum((u_int16_t
*) &tx
.ip6_src
, 16);
482 if (tx
.ip_option_s
&& tx
.ip6_segs
)
483 sum
+= libnet_in_cksum((u_int16_t
*) &tx
.ip_option
[tx
.ip_option_s
- 16], 16); // Use last IP address
485 sum
+= libnet_in_cksum((u_int16_t
*) &tx
.ip6_dst
, 16);
487 tmp
= htonl(tx
.udp_len
);
488 sum
+= libnet_in_cksum((u_int16_t
*) &tmp
, 4);
489 tmp
= htonl(IPPROTO_UDP
);
490 sum
+= libnet_in_cksum((u_int16_t
*) &tmp
, 4);
492 tmp
= ((htons(tx
.sp
) << 16) + htons(tx
.dp
));
493 sum
+= libnet_in_cksum((u_int16_t
*) &tmp
, 4);
495 tmp
= htons(tx
.udp_len
) << 16;
496 sum
+= libnet_in_cksum((u_int16_t
*) &tmp
, 4);
498 if (tx
.udp_payload_s
)
499 sum
+= libnet_in_cksum((u_int16_t
*) tx
.udp_payload
, tx
.udp_payload_s
);
501 tx
.udp_sum
= ntohs(LIBNET_CKSUM_CARRY(sum
));
503 t
= libnet_build_udp(tx
.sp
,
507 tx
.udp_payload_s
? tx
.udp_payload
: NULL
,
515 int update_TSUM(libnet_t
*l
, libnet_ptag_t t
)
523 sum
+= libnet_in_cksum((u_int16_t
*) &tx
.ip6_src
, 16);
524 if (tx
.ip_option_s
&& tx
.ip6_segs
)
525 sum
+= libnet_in_cksum((u_int16_t
*) &tx
.ip_option
[tx
.ip_option_s
- 16], 16); // Use last IP address
527 sum
+= libnet_in_cksum((u_int16_t
*) &tx
.ip6_dst
, 16);
529 tmp
= htonl(tx
.tcp_len
);
530 sum
+= libnet_in_cksum((u_int16_t
*) &tmp
, 4);
531 tmp
= htonl(IPPROTO_TCP
);
532 sum
+= libnet_in_cksum((u_int16_t
*) &tmp
, 4);
534 tmp
= ((htons(tx
.sp
) << 16) + htons(tx
.dp
));
535 sum
+= libnet_in_cksum((u_int16_t
*) &tmp
, 4);
537 tmp
= htonl(tx
.tcp_seq
);
538 sum
+= libnet_in_cksum((u_int16_t
*) &tmp
, 4);
539 tmp
= htonl(tx
.tcp_ack
);
540 sum
+= libnet_in_cksum((u_int16_t
*) &tmp
, 4);
542 tmp
= ((ntohs(((tx
.tcp_offset
) << 12) + tx
.tcp_control
) << 16) + htons(tx
.tcp_win
));
543 sum
+= libnet_in_cksum((u_int16_t
*) &tmp
, 4);
545 tmp
= htonl(tx
.tcp_urg
);
546 sum
+= libnet_in_cksum((u_int16_t
*) &tmp
, 4);
548 sum
+= tx
.tcp_sum_part
;
550 if (tx
.tcp_payload_s
)
551 sum
+= libnet_in_cksum((u_int16_t
*) tx
.tcp_payload
, tx
.tcp_payload_s
);
553 tx
.tcp_sum
= ntohs(LIBNET_CKSUM_CARRY(sum
));
555 t
= libnet_build_tcp (tx
.sp
,
564 tx
.tcp_payload_s
? tx
.tcp_payload
: NULL
,
573 int update_ISUM(libnet_t
*l
, libnet_ptag_t t
)
578 if (tx
.icmp_chksum
!= 0)
581 sum
+= libnet_in_cksum((u_int16_t
*) &tx
.ip6_src
, 16);
582 if (tx
.ip_option_s
&& tx
.ip6_segs
)
583 sum
+= libnet_in_cksum((u_int16_t
*) &tx
.ip_option
[tx
.ip_option_s
- 16], 16); // Use last IP address
585 sum
+= libnet_in_cksum((u_int16_t
*) &tx
.ip6_dst
, 16);
587 tmp
= htonl(LIBNET_ICMPV6_H
+ tx
.icmp_payload_s
);
588 sum
+= libnet_in_cksum((u_int16_t
*) &tmp
, 4);
589 tmp
= htonl(IPPROTO_ICMP6
);
590 sum
+= libnet_in_cksum((u_int16_t
*) &tmp
, 4);
592 tmp
= htonl(((tx
.icmp_type
<< 8) + tx
.icmp_code
));
593 sum
+= libnet_in_cksum((u_int16_t
*) &tmp
, 4);
595 if (tx
.icmp_payload_s
)
596 sum
+= libnet_in_cksum((u_int16_t
*) tx
.icmp_payload
, tx
.icmp_payload_s
);
598 tx
.icmp_chksum
= ntohs(LIBNET_CKSUM_CARRY(sum
));
600 t
= libnet_build_icmpv4_echo (tx
.icmp_type
,
605 tx
.icmp_payload_s
? tx
.icmp_payload
: NULL
,
614 ///////////////////////////////////////////////////////////////////////
616 // Applies another TCP SQNR from a specified range to a given TCP-PTAG
618 // RETURN VALUE: '1' if tx.txp_seq restarts
620 int update_TCP_SQNR(libnet_t
*l
, libnet_ptag_t t
)
626 tx
.tcp_seq
+= tx
.tcp_seq_delta
;
627 diff
= tx
.tcp_seq_stop
- tx
.tcp_seq_start
;
629 if (diff
< tx
.tcp_seq_stop
) // start < stop
631 if (tx
.tcp_seq
> tx
.tcp_seq_stop
)
633 tx
.tcp_seq
= tx
.tcp_seq_start
;
639 if ( (tx
.tcp_seq
<tx
.tcp_seq_start
) &&
640 (tx
.tcp_seq
>tx
.tcp_seq_stop
) )
642 tx
.tcp_seq
= tx
.tcp_seq_start
;
648 t
= libnet_build_tcp (tx
.sp
,
657 (tx
.tcp_payload_s
) ? tx
.tcp_payload
: NULL
,
664 fprintf(stderr
, " mz/update_TCP_SQNR: Can't build TCP header: %s\n", libnet_geterror(l
));
672 ////////////////////////////////////////////////////////////////////////
676 int print_frame_details(void)
678 unsigned char *dum1
, *dum2
;
684 bs2str(tx
.eth_dst
, da
, 6);
685 bs2str(tx
.eth_src
, sa
, 6);
686 fprintf(stderr
, " Eth: DA = %s, SA = %s\n",da
,sa
);
692 fprintf(stderr
, " 802.1Q VLAN-TAG = %s\n", tx
.dot1Q_txt
);
697 fprintf(stderr
," MPLS labels (label:exp:bos:ttl): %s\n",tx
.mpls_verbose_string
);
702 dum1
= (unsigned char*) &tx
.ip_src_h
;
703 dum2
= (unsigned char*) &tx
.ip_dst_h
;
705 (void) bs2str(tx
.ip_payload
, pld
, tx
.ip_payload_s
);
707 strcpy(pld
, "[see next layer]");
711 char src6
[64]; char dst6
[64];
712 libnet_addr2name6_r(tx
.ip6_src
, LIBNET_DONT_RESOLVE
, src6
, 64);
713 libnet_addr2name6_r(tx
.ip6_dst
, LIBNET_DONT_RESOLVE
, dst6
, 64);
715 fprintf(stderr
," IP: ver=6, dscp=%u, flow=%u, len=%u, next=%u, hop=%u "
716 "SA=%s, DA=%s\n payload=%s\n", tx
.ip_tos
, tx
.ip_flow
,
717 tx
.ip_len
, tx
.ip_proto
, tx
.ip_ttl
, src6
, dst6
, pld
);
720 fprintf(stderr
," IP: ver=4, len=%u, tos=%u, id=%u, frag=%u, ttl=%u, proto=%u, sum=%u, "
721 "SA=%u.%u.%u.%u, DA=%u.%u.%u.%u,\n"
722 " payload=%s\n", tx
.ip_len
, tx
.ip_tos
,
723 tx
.ip_id
, tx
.ip_frag
, tx
.ip_ttl
, tx
.ip_proto
, tx
.ip_sum
,
724 *(dum1
+3),*(dum1
+2),*(dum1
+1),*(dum1
), *(dum2
+3),*(dum2
+2),*(dum2
+1),*(dum2
+0), pld
);
727 if ((mode
==UDP
)||(mode
==DNS
)||(mode
==RTP
))
729 bs2str(tx
.udp_payload
, pld
, tx
.udp_payload_s
);
730 fprintf(stderr
, " UDP: sp=%u, dp=%u, len=%u, sum=%u, \n"
731 " payload=%s\n", tx
.sp
, tx
.dp
, tx
.udp_len
, tx
.udp_sum
, pld
);
733 if (mode
==TCP
) // TODO: Improve message details (flags, ...)
735 bs2str(tx
.tcp_payload
, pld
, tx
.tcp_payload_s
);
736 fprintf(stderr
, " TCP: sp=%u, dp=%u, S=%u, A=%u, flags=%x, win=%u, len=%u, sum=%u, \n"
738 tx
.sp
, tx
.dp
, tx
.tcp_seq
, tx
.tcp_ack
, tx
.tcp_control
, tx
.tcp_win
, tx
.tcp_len
, tx
.tcp_sum
, pld
);
741 // send_icmp must prepare the verbose string because there are many
742 // different types of ICMP packets...
745 fprintf(stderr
, " %s\n", tx
.icmp_verbose_txt
);
750 fprintf(stderr
, " %s\n", tx
.icmp_verbose_txt
);
753 // libnet_diag_dump_pblock(l);
754 fprintf(stderr
,"\n");
758 fprintf(stderr
, "*** NOTE: Simulation only! Nothing has been sent! ***\n");