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_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)
36 // int print_frame_details()
38 // ***************************************************************************
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.)
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
,
67 fprintf(stderr
, " mz/update_Eth_SA: Can't build Ethernet header: %s\n",
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
)
81 struct mz_timestamp ts
;
84 tx
.rtp_stmp
+=160; // TODO: different values for different codecs
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
,
114 fprintf(stderr
," mz/send_frame: RTP header update failed!\n");
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
)
140 tx
.ip_src_h
= (u_int32_t
) ( ((float) rand()/RAND_MAX
)*0xE0000000); //this is 224.0.0.0
143 else if (tx
.ip_src_isrange
)
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
;
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
;
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
,
176 tx
.ip_src
, // possibly now random
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,
185 fprintf(stderr
," mz/update_IP_SA: IP address manipulation failed!\n");
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
)
212 if (tx
.ip_dst_isrange
)
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
;
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
;
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
,
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,
257 fprintf(stderr
," mz/update_IP_DA: IP address manipulation failed!\n");
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
)
281 // DP = (u_int32_t) 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
297 t
= libnet_build_udp(tx
.sp
,
301 (tx
.udp_payload_s
) ? tx
.udp_payload
: NULL
,
308 fprintf(stderr
," mz/send_frame: UDP header manipulation failed!\n");
314 t
= libnet_build_tcp (tx
.sp
,
323 (tx
.tcp_payload_s
) ? tx
.tcp_payload
: NULL
,
330 fprintf(stderr
, " mz/update_DPORT: Can't build TCP header: %s\n", libnet_geterror(l
));
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
)
354 // SP = (u_int32_t) 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
369 t
= libnet_build_udp(tx
.sp
,
373 (tx
.udp_payload_s
) ? tx
.udp_payload
: NULL
,
380 fprintf(stderr
," mz/send_frame: UDP header manipulation failed!\n");
386 t
= libnet_build_tcp (tx
.sp
,
395 (tx
.tcp_payload_s
) ? tx
.tcp_payload
: NULL
,
402 fprintf(stderr
, " mz/update_DPORT: Can't build TCP header: %s\n", libnet_geterror(l
));
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
)
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
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
,
447 tx
.udp_payload_s
? tx
.udp_payload
: NULL
,
454 int update_TSUM(libnet_t
*l
, libnet_ptag_t t
)
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
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
,
503 tx
.tcp_payload_s
? tx
.tcp_payload
: NULL
,
511 int update_ISUM(libnet_t
*l
, libnet_ptag_t t
)
516 if (tx
.icmp_chksum
!= 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
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
,
543 tx
.icmp_payload_s
? tx
.icmp_payload
: NULL
,
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
)
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
;
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
;
585 t
= libnet_build_tcp (tx
.sp
,
594 (tx
.tcp_payload_s
) ? tx
.tcp_payload
: NULL
,
601 fprintf(stderr
, " mz/update_TCP_SQNR: Can't build TCP header: %s\n", libnet_geterror(l
));
609 ////////////////////////////////////////////////////////////////////////
613 int print_frame_details()
615 unsigned char *dum1
, *dum2
;
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
);
629 fprintf(stderr
, " 802.1Q VLAN-TAG = %s\n", tx
.dot1Q_txt
);
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]");
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
);
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"
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...
678 fprintf(stderr
, " %s\n", tx
.icmp_verbose_txt
);
683 fprintf(stderr
, " %s\n", tx
.icmp_verbose_txt
);
686 // libnet_diag_dump_pblock(l);
687 fprintf(stderr
,"\n");
691 fprintf(stderr
, "*** NOTE: Simulation only! Nothing has been sent! ***\n");