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 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_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 ///////////////////////////////////////////////////////////////////////////
46 // Applies another random Ethernet source address to a given Ethernet-PTAG.
47 // (The calling function should check 'tx.eth_src_rand' whether the SA
48 // should be randomized.)
50 int update_Eth_SA(libnet_t
*l
, libnet_ptag_t t
)
52 tx
.eth_src
[0] = (u_int8_t
) ( ((float) rand()/RAND_MAX
)*256) & 0xFE; // keeps bcast-bit zero
53 tx
.eth_src
[1] = (u_int8_t
) ( ((float) rand()/RAND_MAX
)*256);
54 tx
.eth_src
[2] = (u_int8_t
) ( ((float) rand()/RAND_MAX
)*256);
55 tx
.eth_src
[3] = (u_int8_t
) ( ((float) rand()/RAND_MAX
)*256);
56 tx
.eth_src
[4] = (u_int8_t
) ( ((float) rand()/RAND_MAX
)*256);
57 tx
.eth_src
[5] = (u_int8_t
) ( ((float) rand()/RAND_MAX
)*256);
59 t
= libnet_build_ethernet (tx
.eth_dst
,
69 fprintf(stderr
, " mz/update_Eth_SA: Can't build Ethernet header: %s\n",
78 // Update official timestamp, own timestamp and sequence number in the RTP header.
79 // The actual RTP message is stored in tx.udp_payload.
80 int update_RTP(libnet_t
*l
, libnet_ptag_t t
)
83 struct mz_timestamp ts
;
86 tx
.rtp_stmp
+=160; // TODO: different values for different codecs
89 ptr
= (u_int8_t
*) &tx
.rtp_sqnr
;
90 tx
.udp_payload
[2] = *(ptr
+1);
91 tx
.udp_payload
[3] = *ptr
;
93 // update official timestamp
94 ptr
= (u_int8_t
*) &tx
.rtp_stmp
;
95 tx
.udp_payload
[4] = *(ptr
+3);
96 tx
.udp_payload
[5] = *(ptr
+2);
97 tx
.udp_payload
[6] = *(ptr
+1);
98 tx
.udp_payload
[7] = *ptr
;
101 // update own timestamp
102 getcurtime(&ts
); // Now add TX timestamp:
103 mops_hton4 ((u_int32_t
*) &ts
.sec
, &tx
.udp_payload
[16]);
104 mops_hton4 ((u_int32_t
*) &ts
.nsec
, &tx
.udp_payload
[20]);
106 t
= libnet_build_udp(tx
.sp
,
116 fprintf(stderr
," mz/send_frame: RTP header update failed!\n");
123 ///////////////////////////////////////////////////////////////////////////
124 // Applies another SOURCE IP address,
125 // - either a random one (tx.ip_src_rand==1)
126 // - or from a specified range (tx.ip_src_isrange==1)
127 // to a given IP-PTAG.
129 // Note: tx.ip_src MUST be already initialized with tx.ip_src_start.
130 // This is done by 'get_ip_range_src()' in tools.c.
133 // RETURNS '1' if tx.ip_src restarts
135 int update_IP_SA (libnet_t
*l
, libnet_ptag_t t
)
141 return update_IP6_SA(l
, t
);
146 tx
.ip_src_h
= (u_int32_t
) ( ((float) rand()/RAND_MAX
)*0xE0000000); //this is 224.0.0.0
149 else if (tx
.ip_src_isrange
)
152 if (tx
.ip_src_h
> tx
.ip_src_stop
) // reached the end of the range => restart!
154 tx
.ip_src_h
= tx
.ip_src_start
;
159 // Now convert "tx.ip_src_h" into "tx.ip_src" which is in 'Network Byte Order':
160 x
= (unsigned char*) &tx
.ip_src_h
;
161 y
= (unsigned char*) &tx
.ip_src
;
171 // TODO: Omit certain IP addresses:
172 // E.g. if (rand_ip == tx.ip_src) goto rand_again; // never use true interface IP
173 // TODO: Check other address exceptions ...
175 t
= libnet_build_ipv4 (tx
.ip_len
,
182 tx
.ip_src
, // possibly now random
184 (mode
==IP
) ? (tx
.ip_payload_s
) ? tx
.ip_payload
: NULL
: NULL
, // if e.g. mode=UDP ignore payload argument
185 (mode
==IP
) ? tx
.ip_payload_s
: 0,
191 fprintf(stderr
," mz/update_IP_SA: IP address manipulation failed!\n");
200 update_IP6_SA(libnet_t
*l
, libnet_ptag_t t
)
203 if (tx
.ip_src_rand
) {
204 fprintf(stderr
, "Random source addresses are not supported in IPv6 mode.\n");
206 } else if (tx
.ip_src_isrange
) {
207 if (incr_in6_addr(tx
.ip6_src
, &tx
.ip6_src
)
208 || (in6_addr_cmp(tx
.ip6_src
, tx
.ip6_src_stop
) > 0))
210 tx
.ip6_src
= tx
.ip6_src_start
;
215 t
= libnet_build_ipv6(tx
.ip_tos
,
222 (mode
==IP
) ? (tx
.ip_payload_s
) ? tx
.ip_payload
: NULL
: NULL
,
223 (mode
==IP
) ? tx
.ip_payload_s
: 0,
228 fprintf(stderr
," mz/update_IP6_SA: IP address manipulation failed!\n");
236 /////////////////////////////////////////////////////////////////////////////////////////
237 // Applies another DESTINATION IP address from a specified range (tx.ip_dst_isrange==1)
238 // to a given IP-PTAG.
240 // Note: tx.ip_dst MUST be already initialized with tx.ip_dst_start.
241 // tx.ip_dst_h 'mirrors' tx.ip_dst
242 // (i. e. tx.ip_dst_h is NOT in network byte order => easy to count)
243 // This is done by 'get_ip_range_dst()' in tools.c.
245 // RETURN VALUE: '1' if tx.ip_dst restarts
247 int update_IP_DA(libnet_t
*l
, libnet_ptag_t t
)
253 return update_IP6_DA(l
, t
);
256 if (tx
.ip_dst_isrange
)
259 if (tx
.ip_dst_h
> tx
.ip_dst_stop
) // we reached the end of the range => restart!
261 tx
.ip_dst_h
= tx
.ip_dst_start
;
267 // Now convert "tx.ip_dst_h" into "tx.ip_dst" which is in 'Network Byte Order':
269 x
= (unsigned char*) &tx
.ip_dst_h
;
270 y
= (unsigned char*) &tx
.ip_dst
;
281 // TODO: Omit certain IP addresses:
282 // E.g. if (rand_ip == tx.ip_src) goto rand_again; // never use true interface IP
283 // TODO: Check other address exceptions ...
285 t
= libnet_build_ipv4 (tx
.ip_len
,
294 (mode
==IP
) ? (tx
.ip_payload_s
) ? tx
.ip_payload
: NULL
: NULL
, // if e.g. mode=UDP ignore payload argument
295 (mode
==IP
) ? tx
.ip_payload_s
: 0,
301 fprintf(stderr
," mz/update_IP_DA: IP address manipulation failed!\n");
310 update_IP6_DA(libnet_t
*l
, libnet_ptag_t t
)
313 if (tx
.ip_dst_isrange
) {
314 if (incr_in6_addr(tx
.ip6_dst
, &tx
.ip6_dst
)
315 || (in6_addr_cmp(tx
.ip6_dst
, tx
.ip6_dst_stop
) > 0))
317 tx
.ip6_dst
= tx
.ip6_dst_start
;
322 t
= libnet_build_ipv6(tx
.ip_tos
,
329 (mode
==IP
) ? (tx
.ip_payload_s
) ? tx
.ip_payload
: NULL
: NULL
,
330 (mode
==IP
) ? tx
.ip_payload_s
: 0,
335 fprintf(stderr
," mz/update_IP6_DA: IP address manipulation failed!\n");
344 ///////////////////////////////////////////////////////////////////////////////////////
346 // Applies another DESTINATION PORT from a specified range to a given UDP- or TCP-PTAG.
348 // Note: tx.dp MUST be already initialized with tx.dp_start
349 // This is done by 'get_port_range()' in tools.c.
351 // RETURN VALUE: '1' if tx.dp restarts
353 int update_DPORT(libnet_t
*l
, libnet_ptag_t t
)
358 // DP = (u_int32_t) tx.dp;
363 // Exceeded range => restart:
364 if ((tx
.dp
> tx
.dp_stop
) || // we exceeded the end of the range
365 (tx
.dp
== 65535) ) // or exceeded the 16-bit range
374 t
= libnet_build_udp(tx
.sp
,
378 (tx
.udp_payload_s
) ? tx
.udp_payload
: NULL
,
385 fprintf(stderr
," mz/send_frame: UDP header manipulation failed!\n");
391 t
= libnet_build_tcp (tx
.sp
,
400 (tx
.tcp_payload_s
) ? tx
.tcp_payload
: NULL
,
407 fprintf(stderr
, " mz/update_DPORT: Can't build TCP header: %s\n", libnet_geterror(l
));
416 ///////////////////////////////////////////////////////////////////////////////////
418 // Applies another SOURCE PORT from a specified range to a given UDP- or TCP-PTAG.
420 // Note: tx.sp MUST be already initialized with tx.sp_start
421 // This is done by 'get_port_range()' in tools.c.
423 // RETURN VALUE: '1' if tx.sp restarts
425 int update_SPORT(libnet_t
*l
, libnet_ptag_t t
)
431 // SP = (u_int32_t) tx.sp;
436 // Exceeded range => restart:
437 if ((tx
.sp
> tx
.sp_stop
) || // we exceeded the end of the range
438 (tx
.sp
== 65535) ) // or exceeded the 16-bit range
446 t
= libnet_build_udp(tx
.sp
,
450 (tx
.udp_payload_s
) ? tx
.udp_payload
: NULL
,
457 fprintf(stderr
," mz/send_frame: UDP header manipulation failed!\n");
463 t
= libnet_build_tcp (tx
.sp
,
472 (tx
.tcp_payload_s
) ? tx
.tcp_payload
: NULL
,
479 fprintf(stderr
, " mz/update_SPORT: Can't build TCP header: %s\n", libnet_geterror(l
));
487 #define LIBNET_CKSUM_CARRY(x) \
488 (x = (x >> 16) + (x & 0xffff), (~(x + (x >> 16)) & 0xffff))
490 int update_USUM(libnet_t
*l
, libnet_ptag_t t
)
498 sum
+= libnet_in_cksum((u_int16_t
*) &tx
.ip6_src
, 16);
499 if (tx
.ip_option_s
&& tx
.ip6_segs
)
500 sum
+= libnet_in_cksum((u_int16_t
*) &tx
.ip_option
[tx
.ip_option_s
- 16], 16); // Use last IP address
502 sum
+= libnet_in_cksum((u_int16_t
*) &tx
.ip6_dst
, 16);
504 tmp
= htonl(tx
.udp_len
);
505 sum
+= libnet_in_cksum((u_int16_t
*) &tmp
, 4);
506 tmp
= htonl(IPPROTO_UDP
);
507 sum
+= libnet_in_cksum((u_int16_t
*) &tmp
, 4);
509 tmp
= ((htons(tx
.sp
) << 16) + htons(tx
.dp
));
510 sum
+= libnet_in_cksum((u_int16_t
*) &tmp
, 4);
512 tmp
= htons(tx
.udp_len
) << 16;
513 sum
+= libnet_in_cksum((u_int16_t
*) &tmp
, 4);
515 if (tx
.udp_payload_s
)
516 sum
+= libnet_in_cksum((u_int16_t
*) tx
.udp_payload
, tx
.udp_payload_s
);
518 tx
.udp_sum
= ntohs(LIBNET_CKSUM_CARRY(sum
));
520 t
= libnet_build_udp(tx
.sp
,
524 tx
.udp_payload_s
? tx
.udp_payload
: NULL
,
532 int update_TSUM(libnet_t
*l
, libnet_ptag_t t
)
540 sum
+= libnet_in_cksum((u_int16_t
*) &tx
.ip6_src
, 16);
541 if (tx
.ip_option_s
&& tx
.ip6_segs
)
542 sum
+= libnet_in_cksum((u_int16_t
*) &tx
.ip_option
[tx
.ip_option_s
- 16], 16); // Use last IP address
544 sum
+= libnet_in_cksum((u_int16_t
*) &tx
.ip6_dst
, 16);
546 tmp
= htonl(tx
.tcp_len
);
547 sum
+= libnet_in_cksum((u_int16_t
*) &tmp
, 4);
548 tmp
= htonl(IPPROTO_TCP
);
549 sum
+= libnet_in_cksum((u_int16_t
*) &tmp
, 4);
551 tmp
= ((htons(tx
.sp
) << 16) + htons(tx
.dp
));
552 sum
+= libnet_in_cksum((u_int16_t
*) &tmp
, 4);
554 tmp
= htonl(tx
.tcp_seq
);
555 sum
+= libnet_in_cksum((u_int16_t
*) &tmp
, 4);
556 tmp
= htonl(tx
.tcp_ack
);
557 sum
+= libnet_in_cksum((u_int16_t
*) &tmp
, 4);
559 tmp
= ((ntohs(((tx
.tcp_offset
) << 12) + tx
.tcp_control
) << 16) + htons(tx
.tcp_win
));
560 sum
+= libnet_in_cksum((u_int16_t
*) &tmp
, 4);
562 tmp
= htonl(tx
.tcp_urg
);
563 sum
+= libnet_in_cksum((u_int16_t
*) &tmp
, 4);
565 sum
+= tx
.tcp_sum_part
;
567 if (tx
.tcp_payload_s
)
568 sum
+= libnet_in_cksum((u_int16_t
*) tx
.tcp_payload
, tx
.tcp_payload_s
);
570 tx
.tcp_sum
= ntohs(LIBNET_CKSUM_CARRY(sum
));
572 t
= libnet_build_tcp (tx
.sp
,
581 tx
.tcp_payload_s
? tx
.tcp_payload
: NULL
,
590 int update_ISUM(libnet_t
*l
, libnet_ptag_t t
)
595 if (tx
.icmp_chksum
!= 0)
598 sum
+= libnet_in_cksum((u_int16_t
*) &tx
.ip6_src
, 16);
599 if (tx
.ip_option_s
&& tx
.ip6_segs
)
600 sum
+= libnet_in_cksum((u_int16_t
*) &tx
.ip_option
[tx
.ip_option_s
- 16], 16); // Use last IP address
602 sum
+= libnet_in_cksum((u_int16_t
*) &tx
.ip6_dst
, 16);
604 tmp
= htonl(LIBNET_ICMPV6_H
+ tx
.icmp_payload_s
);
605 sum
+= libnet_in_cksum((u_int16_t
*) &tmp
, 4);
606 tmp
= htonl(IPPROTO_ICMP6
);
607 sum
+= libnet_in_cksum((u_int16_t
*) &tmp
, 4);
609 tmp
= htonl(((tx
.icmp_type
<< 8) + tx
.icmp_code
));
610 sum
+= libnet_in_cksum((u_int16_t
*) &tmp
, 4);
612 if (tx
.icmp_payload_s
)
613 sum
+= libnet_in_cksum((u_int16_t
*) tx
.icmp_payload
, tx
.icmp_payload_s
);
615 tx
.icmp_chksum
= ntohs(LIBNET_CKSUM_CARRY(sum
));
617 t
= libnet_build_icmpv4_echo (tx
.icmp_type
,
622 tx
.icmp_payload_s
? tx
.icmp_payload
: NULL
,
631 ///////////////////////////////////////////////////////////////////////
633 // Applies another TCP SQNR from a specified range to a given TCP-PTAG
635 // RETURN VALUE: '1' if tx.txp_seq restarts
637 int update_TCP_SQNR(libnet_t
*l
, libnet_ptag_t t
)
643 tx
.tcp_seq
+= tx
.tcp_seq_delta
;
644 diff
= tx
.tcp_seq_stop
- tx
.tcp_seq_start
;
646 if (diff
< tx
.tcp_seq_stop
) // start < stop
648 if (tx
.tcp_seq
> tx
.tcp_seq_stop
)
650 tx
.tcp_seq
= tx
.tcp_seq_start
;
656 if ( (tx
.tcp_seq
<tx
.tcp_seq_start
) &&
657 (tx
.tcp_seq
>tx
.tcp_seq_stop
) )
659 tx
.tcp_seq
= tx
.tcp_seq_start
;
665 t
= libnet_build_tcp (tx
.sp
,
674 (tx
.tcp_payload_s
) ? tx
.tcp_payload
: NULL
,
681 fprintf(stderr
, " mz/update_TCP_SQNR: Can't build TCP header: %s\n", libnet_geterror(l
));
689 ////////////////////////////////////////////////////////////////////////
693 int print_frame_details(void)
695 unsigned char *dum1
, *dum2
;
701 bs2str(tx
.eth_dst
, da
, 6);
702 bs2str(tx
.eth_src
, sa
, 6);
703 fprintf(stderr
, " Eth: DA = %s, SA = %s\n",da
,sa
);
709 fprintf(stderr
, " 802.1Q VLAN-TAG = %s\n", tx
.dot1Q_txt
);
714 fprintf(stderr
," MPLS labels (label:exp:bos:ttl): %s\n",tx
.mpls_verbose_string
);
719 dum1
= (unsigned char*) &tx
.ip_src_h
;
720 dum2
= (unsigned char*) &tx
.ip_dst_h
;
722 (void) bs2str(tx
.ip_payload
, pld
, tx
.ip_payload_s
);
724 strcpy(pld
, "[see next layer]");
728 char src6
[64]; char dst6
[64];
729 libnet_addr2name6_r(tx
.ip6_src
, LIBNET_DONT_RESOLVE
, src6
, 64);
730 libnet_addr2name6_r(tx
.ip6_dst
, LIBNET_DONT_RESOLVE
, dst6
, 64);
732 fprintf(stderr
," IP: ver=6, dscp=%u, flow=%u, len=%u, next=%u, hop=%u "
733 "SA=%s, DA=%s\n payload=%s\n", tx
.ip_tos
, tx
.ip_flow
,
734 tx
.ip_len
, tx
.ip_proto
, tx
.ip_ttl
, src6
, dst6
, pld
);
737 fprintf(stderr
," IP: ver=4, len=%u, tos=%u, id=%u, frag=%u, ttl=%u, proto=%u, sum=%u, "
738 "SA=%u.%u.%u.%u, DA=%u.%u.%u.%u,\n"
739 " payload=%s\n", tx
.ip_len
, tx
.ip_tos
,
740 tx
.ip_id
, tx
.ip_frag
, tx
.ip_ttl
, tx
.ip_proto
, tx
.ip_sum
,
741 *(dum1
+3),*(dum1
+2),*(dum1
+1),*(dum1
), *(dum2
+3),*(dum2
+2),*(dum2
+1),*(dum2
+0), pld
);
744 if ((mode
==UDP
)||(mode
==DNS
)||(mode
==RTP
))
746 bs2str(tx
.udp_payload
, pld
, tx
.udp_payload_s
);
747 fprintf(stderr
, " UDP: sp=%u, dp=%u, len=%u, sum=%u, \n"
748 " payload=%s\n", tx
.sp
, tx
.dp
, tx
.udp_len
, tx
.udp_sum
, pld
);
750 if (mode
==TCP
) // TODO: Improve message details (flags, ...)
752 bs2str(tx
.tcp_payload
, pld
, tx
.tcp_payload_s
);
753 fprintf(stderr
, " TCP: sp=%u, dp=%u, S=%u, A=%u, flags=%x, win=%u, len=%u, sum=%u, \n"
755 tx
.sp
, tx
.dp
, tx
.tcp_seq
, tx
.tcp_ack
, tx
.tcp_control
, tx
.tcp_win
, tx
.tcp_len
, tx
.tcp_sum
, pld
);
758 // send_icmp must prepare the verbose string because there are many
759 // different types of ICMP packets...
762 fprintf(stderr
, " %s\n", tx
.icmp_verbose_txt
);
767 fprintf(stderr
, " %s\n", tx
.icmp_verbose_txt
);
770 // libnet_diag_dump_pblock(l);
771 fprintf(stderr
,"\n");
775 fprintf(stderr
, "*** NOTE: Simulation only! Nothing has been sent! ***\n");