trafgen: parser: Add 'drnd()' function for proto fields
[netsniff-ng.git] / staging / send_eth.c
blobae811e8546f4565bf0b9206da63877139c892896
1 /*
2 * Mausezahn - A fast versatile traffic generator
3 * Copyright (C) 2008 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 // This sections contains (as alternative to 'send_frame' in send.c)
24 // a layer-2 based flexible sending function.
25 //
26 // Layer-2 modifications such as 802.1Q and MPLS is considered here!
27 //
28 // ***************************************************************************
32 #include "mz.h"
34 libnet_ptag_t create_eth_frame (libnet_t *l, libnet_ptag_t t3, libnet_ptag_t t4)
36 libnet_t *L=NULL;
37 char errbuf[LIBNET_ERRBUF_SIZE];
38 libnet_ptag_t t=0, tmpls;
39 char argval[128];
40 u_int8_t et[2];
41 int et_len;
43 int i=0, j, mlen, mkomma, len, count, offset=0, found_colon=0;
44 char *left, *right;
45 char *f, mtag[64];
46 char verbose_mpls_string[128];
48 u_int8_t *packet;
49 u_int32_t packet_s;
51 char *saveptr, *ptrsubstring, substring[16], tmp[4*MAX_8021Q_TAGS];
52 u_int8_t CoS; // 0..7
53 u_int16_t vlan; // 12 bit value (0..4095)
54 u_int8_t dot1Q[4*MAX_8021Q_TAGS], *ptr;
55 u_int16_t dot1Q_eth_type=0x8100;
56 int bytecnt=0;
58 int isdot1Q, tcp_seq_delta, dp_isrange, sp_isrange, ip_dst_isrange, ip_src_isrange, eth_src_rand, rtp_mode=0;
59 unsigned int delay;
66 ////////////////////////////////////////////////////
67 // Prepare MPLS header if required
68 if (tx.mpls)
70 // first check how many labels have been specified:
71 mlen = strlen (tx.mpls_txt);
72 mkomma=0;
74 for (i=0; i<mlen; i++)
76 if (tx.mpls_txt[i]==',') mkomma++;
79 f = strtok_r (tx.mpls_txt, ",", &saveptr);
81 tx.mpls_bos=1;
85 strncpy(mtag, f, 64);
87 if (mkomma==0)
89 tx.mpls_bos=0;
91 else
93 printf("BOS=1\n");
94 tx.mpls_bos=1;
99 if ( get_mpls_params(mtag) ) // error?
101 fprintf(stderr," mz/get_mpls_params: MPLS Parameters problem.\n");
102 exit (0);
105 tmpls = libnet_build_mpls(tx.mpls_label,
106 tx.mpls_exp,
107 tx.mpls_bos,
108 tx.mpls_ttl,
109 NULL,
114 if (tmpls == -1)
116 fprintf(stderr, " mz/create_ip_packet: Can't build MPLS header: %s\n", libnet_geterror(l));
117 exit (0);
120 if (verbose)
122 sprintf(verbose_mpls_string,"[%u:%u:%u:%u]",
123 tx.mpls_label,
124 tx.mpls_exp,
125 tx.mpls_bos,
126 tx.mpls_ttl);
127 strcat(tx.mpls_verbose_string, verbose_mpls_string);
128 strcat(tx.mpls_verbose_string, " ");
131 tx.mpls_bos=0;
132 mkomma--;
134 while ( (f=strtok_r(NULL, ",", &saveptr)) != NULL);
144 ////////////////////////////////////////////////////////////////////////////////////////////
145 // Evaluate Ethernet CLI options (-a and -b)
146 if (check_eth_mac_txt(ETH_DST)) // if true then problem (invalid user input?)
148 str2hex("ff:ff:ff:ff:ff:ff",tx.eth_dst, 6); // the default
151 // if not specified then own MAC will be used automatically
152 (void) check_eth_mac_txt(ETH_SRC);
155 // Get CLI arguments:
156 // If NOT set, default: 0x800 or ETHERTYPE_MPLS if MPLS is used (see init.c)
157 if (getarg(tx.arg_string,"ether_type", argval)==1)
159 et_len = str2hex (argval, et, 2);
161 if (et_len==1)
162 tx.eth_type = et[0];
163 else // 2 bytes specified
164 tx.eth_type = 256 * et[0] + et[1];
166 //tx.eth_type = (u_int16_t) str2int(argval);
176 /////////////////////////////////////////////////////////////////////////////////
177 // Ethernet with 802.1Q
179 // If multiple 802.1Q tags are specified then we need to build the whole
180 // frame manually because libnet only supports adding a single VLAN header.
181 // The easiest solution is to create the hex-string of the 802.1Q-chain as
182 // u_int8_t QinQ[] then add the IP packet as payload...
184 if (tx.dot1Q) // actually contains the number of VLAN tags
187 // we want our own context!
188 L = libnet_init(LIBNET_LINK_ADV, tx.device, errbuf);
189 if (L == NULL)
191 fprintf(stderr, "%s", errbuf);
192 exit(EXIT_FAILURE);
195 strncpy(tmp,tx.dot1Q_txt,(4*MAX_8021Q_TAGS));
196 ptrsubstring = strtok_r(tmp, ",.", &saveptr);
197 bytecnt=0;
200 // make a local copy
201 strncpy(substring, ptrsubstring, 16);
202 CoS=0; vlan=0;
203 // Get CoS and VLAN ID from partial string
204 len = strlen(substring);
205 found_colon=0;
206 for (i=0; i<len; i++)
208 if (substring[i]==':') found_colon=1;
210 if (found_colon) // Both CoS and VLAN specified
212 left = strtok (substring, ":");
213 right = strtok (NULL, ":");
214 CoS = (u_int8_t) str2int (left);
215 vlan = (u_int16_t) str2int (right);
217 else // Only VLAN specified
219 vlan = (u_int16_t) str2int (substring);
222 if (CoS > 7)
224 fprintf(stderr, " mz/create_eth_frame: CoS too high, adjusted to 7\n");
225 CoS = 7;
228 if (vlan > 4095)
230 fprintf(stderr, " mz/create_eth_frame: VLAN number too high, adjusted to 4095\n");
231 vlan = 4095;
234 // create 4 byte 802.1Q header:
236 dot1Q[bytecnt+0]=0x81;
237 dot1Q[bytecnt+1]=0x00;
238 ptr = (u_int8_t*) &vlan;
239 dot1Q[bytecnt+3]=*ptr;
240 ptr++;
241 *ptr = *ptr ^ (CoS<<5); // add CoS
242 dot1Q[bytecnt+2]=*ptr;
243 //check:
244 //printf("%02x %02x %02x %02x\n",dot1Q[bytecnt+0],dot1Q[bytecnt+1],dot1Q[bytecnt+2],dot1Q[bytecnt+3]);
245 bytecnt+=4; // next tag (note that bytecnt will finally hold the number of used bytes!)
247 } while ( (ptrsubstring = strtok_r(NULL, ",.", &saveptr)) !=NULL); //get all VLAN tags
249 // now create the whole packet:
251 dot1Q_eth_type = 0x8100; //these are also the first two bytes of dot1Q[]
252 bytecnt = bytecnt-2;
254 for (i=0;i<bytecnt;i++)
256 tx.eth_payload[i]=dot1Q[i+2];
259 // now add official EtherType for the payload (this has been determined some lines above)
260 ptr = (u_int8_t*) & tx.eth_type;
261 tx.eth_payload[i+1]= *ptr;
262 ptr++;
263 tx.eth_payload[i]= *ptr;
264 offset = i+2;
266 // -
267 // --
268 // ---
269 // ---- now all 802.1Q headers are genereated ----
270 // ---- and are placed already in tx.eth_payload ----
271 // ---- (and 'i' points to the next free byte) ----
272 // ---
273 // --
274 // -
276 // Finally get all bytes of upper layers (IP packet and payload)
277 if (libnet_adv_cull_packet(l, &packet, &packet_s) == -1)
279 fprintf(stderr, "%s", libnet_geterror(l));
282 // Copy the upper layer data to the eth_payload
283 for (j=0; j<packet_s; j++)
285 tx.eth_payload[j+offset]=packet[j];
288 // 'libnet_adv_cull_packet' performs an implicit malloc() and a corresponding call
289 // to libnet_adv_free_packet() should be made to free the memory packet occupies:
290 libnet_adv_free_packet(l, packet);
292 tx.eth_payload_s = j+offset;
293 tx.eth_type = dot1Q_eth_type;
295 t = libnet_build_ethernet (tx.eth_dst,
296 tx.eth_src,
297 tx.eth_type,
298 tx.eth_payload,
299 tx.eth_payload_s,
303 if (t == -1)
305 fprintf(stderr, " mz/create_eth_frame: Can't build Ethernet header: %s\n",
306 libnet_geterror(l));
307 exit(EXIT_FAILURE);
310 // NOW the whole frame is ready to send!
314 else // normal Ethernet header without any 802.1Q-tag or MPLS-label
318 t = libnet_build_ethernet (tx.eth_dst,
319 tx.eth_src,
320 tx.eth_type,
321 NULL, // the payload
326 if (t == -1)
328 fprintf(stderr, " mz/create_eth_frame: Can't build Ethernet header: %s\n",
329 libnet_geterror(l));
330 exit(EXIT_FAILURE);
334 /////////////////////////////////////////////////////////////////////////////
336 // Now send everything - maybe lots of times with modifications.
340 // local vars are faster :-)
341 count = tx.count;
342 delay = tx.delay;
343 eth_src_rand = tx.eth_src_rand;
344 tcp_seq_delta = tx.tcp_seq_delta;
345 dp_isrange = tx.dp_isrange;
346 sp_isrange = tx.sp_isrange;
347 ip_dst_isrange = tx.ip_dst_isrange;
348 ip_src_isrange = tx.ip_src_isrange | tx.ip_src_rand; // either case should call update_SA()
349 isdot1Q = tx.dot1Q;
350 if (mode == RTP) rtp_mode = 1;
352 if (count==0) goto AGAIN;
354 for (i=0; i<count; i++)
357 AGAIN:
359 if (isdot1Q)
361 // Get all bytes of upper layers (IP packet and payload)
362 if (libnet_adv_cull_packet(l, &packet, &packet_s) == -1)
364 fprintf(stderr, "%s", libnet_geterror(l));
367 // Copy the upper layer data to the eth_payload
368 for (j=0; j<packet_s; j++)
370 tx.eth_payload[j+offset]=packet[j];
373 // 'libnet_adv_cull_packet' performs an implicit malloc() and a corresponding call
374 // to libnet_adv_free_packet() should be made to free the memory packet occupies:
375 libnet_adv_free_packet(l, packet);
377 if (eth_src_rand) update_Eth_SA(L, t);
379 t = libnet_build_ethernet (tx.eth_dst,
380 tx.eth_src,
381 tx.eth_type,
382 tx.eth_payload,
383 tx.eth_payload_s,
386 if (t == -1)
388 fprintf(stderr, " mz/create_eth_frame: Can't build Ethernet header: %s\n",
389 libnet_geterror(l));
390 exit(EXIT_FAILURE);
392 if (verbose) (void) print_frame_details();
393 libnet_write(L);
395 else // No QinQ and/or MPLS modifications => use normal 'l' context:
397 if (eth_src_rand) update_Eth_SA(l, t);
398 if (verbose) (void) print_frame_details();
399 libnet_write(l);
403 // if (verbose) (void) print_frame_details();
404 if (delay) SLEEP (delay);
407 if (tcp_seq_delta)
409 if (update_TCP_SQNR(l, t4)==0) // end of range not yet reached
411 goto AGAIN;
415 if (dp_isrange)
417 if (update_DPORT(l, t4)==0) // end of range not yet reached
419 goto AGAIN;
423 if (sp_isrange)
425 if (update_SPORT(l, t4)==0) // end of range not yet reached
427 goto AGAIN;
431 if (ip_dst_isrange)
433 if (update_IP_DA(l, t3)==0) // end of range not yet reached
435 goto AGAIN;
439 if (ip_src_isrange)
441 if (update_IP_SA(l, t3)==0) // end of range not yet reached
443 goto AGAIN;
448 if (rtp_mode) // update SQNR and Timestamps in RTP header and payload
450 update_RTP(l, t4);
454 if (!count) goto AGAIN;
458 libnet_destroy(l);
459 if (isdot1Q)
460 libnet_destroy(L);
463 return t;
468 void print_dot1Q_help(void)
471 fprintf(stderr,"\n"
472 MAUSEZAHN_VERSION
473 "\n"
474 "| 802.1Q header Syntax: -Q tag[,tag[,tag[,...]]]\n"
475 "| where each tag may consist of a CoS value using the syntax:\n"
476 "|\n"
477 "| <CoS>:<tag value>\n"
478 "|\n"
479 "| Examples:\n"
480 "|\n"
481 "| # mz -Q 100\n"
482 "| # mz -Q 5:100\n"
483 "| # mz -Q 5:100,200\n"
484 "| # mz -Q 5:100,7:200\n"
485 "| # mz -Q 100,200,300,5:400\n"
486 "\n\n");
488 exit(0);