mausezahn: use getopt_long instead of getopt
[netsniff-ng.git] / staging / mops.c
blobfc00e29a46bcc2754a102dea2478761bd5c6085c
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 // -- TOC: --
23 //
24 // struct mops * mops_init ()
25 // struct mops * mops_alloc_packet (struct mops *cur)
26 // struct mops * mops_delete_packet (struct mops *cur)
27 // int mops_reset_packet (struct mops *cur)
28 //
29 // int mops_dump_all (struct mops* list)
30 // struct mops * mops_search_name (struct mops* list, char* key)
31 // struct mops * mops_search_id (struct mops* list, int key)
32 // void mops_delete_all (struct mops* list)
33 // void mops_cleanup (struct mops* list)
34 //
35 // int mops_set_defaults (struct mops *mp)
36 // int mops_print_frame (struct mops *mp, char *str)
38 // int mops_get_new_pkt_id (struct mops *mp)
39 // int mops_clear_layers (struct mops *mp)
41 // int mops_get_device_index (char *devname)
42 // int mops_use_device (struct mops * mp, int i)
44 // int mops_get_proto_info (struct mops * mp, char *layers, char *proto)
46 #include "mz.h"
47 #include "mops.h"
49 unsigned int min_frame_s;
50 unsigned int max_frame_s;
52 struct automops * amp_head;
53 struct mops *mp_head; // This global will point to the head of the mops list
55 // Creates first element, aka "head" element
56 // This element can also be used! See mops_alloc_packet!
57 //
58 struct mops * mops_init(void)
60 // these defaults can be changed by the user:
61 min_frame_s = MIN_MOPS_FRAME_SIZE; // important global; depends on used packet tx subsystem such as libnet
62 max_frame_s = MAX_MOPS_FRAME_SIZE-MOPS_SIZE_MARGIN;
64 // Create initial mops element:
65 struct mops *new_mops = (struct mops*) malloc(sizeof(struct mops));
66 new_mops->next = new_mops;
67 new_mops->prev = new_mops;
68 new_mops->state = MOPS_STATE_NULL;
69 new_mops->id = 0; // importante!
70 mops_set_defaults (new_mops);
71 strncpy(new_mops->packet_name, "-------", 8);
73 return new_mops;
80 // Returns pointer to new mops element:
81 // 1) either insert a new mops element in list
82 // 2) or returns same pointer again if current mops element is empty
83 // Note that new element N is always PREPENDED to cur:
84 // ... = N-2 = N-1 = N = cur = 1 = 2 = ...
85 //
86 //
87 // RETURN VALUE: + Pointer to new mops
88 // - NULL upon failure
89 struct mops * mops_alloc_packet(struct mops *cur)
91 int j;
92 struct mops *new_mops;
93 int new_pkt_id, pkt_id_name;
94 char pname[MAX_MOPS_PACKET_NAME_LEN];
96 if (cur->state == MOPS_STATE_NULL) { // allows to use first packet in list
97 new_mops = cur; // current mops was unused => no need to insert a new mops!
99 else { // create new mops element
100 new_mops = (struct mops *) malloc(sizeof(struct mops));
101 if (new_mops==NULL) {
102 fprintf(stderr, "MZ alert: cannot create new mops entry - memory full?\n");
103 return NULL; // memory full?
107 new_mops->state = MOPS_STATE_INIT;
109 // Assign unique packet id
110 new_pkt_id = mops_get_new_pkt_id (cur);
111 if (new_pkt_id==-1) return NULL;
112 new_mops->id = new_pkt_id;
114 // Assign unique packet name
115 pkt_id_name = new_pkt_id;
116 do {
117 sprintf(pname, "PKT%04d", pkt_id_name);
118 pkt_id_name++;
119 } while (mops_search_name (mp_head, pname)); // check if this name is really unique
121 strncpy(new_mops->packet_name, pname, MAX_MOPS_PACKET_NAME_LEN);
123 // append to doubly linked list
124 new_mops->prev = cur->prev;
125 new_mops->next = cur;
126 cur->prev = new_mops;
127 new_mops->prev->next = new_mops;
129 mops_set_defaults (new_mops); // set header parametes (addresses etc)
131 // Reset protocol descriptor
132 new_mops->p_desc = NULL;
133 new_mops->p_desc_type = MOPS_NO_PDESC;
135 // clear counter values
136 new_mops->used_counters=0;
137 for (j=0; j<MAX_MOPS_COUNTERS_PER_PACKET; j++) {
138 new_mops->counter[j].use = 0;
139 new_mops->counter[j].offset = 0;
140 new_mops->counter[j].random = 0;
143 return new_mops;
148 // Delete particular packet (remove it from list).
150 // If mp_head is deleted, makes previous element mp_head.
151 // Note that the global mp_head must exist but within MOPS this
152 // is always the case.
154 // Returns pointer to previous element in the list
155 // or NULL if packet is active
156 struct mops * mops_delete_packet(struct mops *cur)
158 struct mops *last;
160 if (mops_is_active(cur)) {
161 mops_destroy_thread(cur);
164 mops_ext_del_pdesc (cur); // delete p_desc (if available)
166 // remove automops data if available
167 if (cur->amp != NULL) {
168 free(cur->amp);
169 cur->amp=NULL;
171 if (cur->amp_pdu != NULL) {
172 free (cur->amp_pdu);
173 cur->amp_pdu=NULL;
176 last = cur->prev;
177 cur->next->prev = cur->prev;
178 cur->prev->next = cur->next;
179 if (cur==mp_head) {
180 mp_head = last;
182 if (cur!=NULL) {
183 free (cur);
184 cur=NULL;
186 return last;
191 // Erase all data of a mops entry and even chooses a new standard name
192 // DOES NOT delete the entry from the list
194 int mops_reset_packet(struct mops *cur)
196 int i=0;
197 char pname[16];
199 // stop thread if necessary
200 if (mops_is_active(cur)) {
201 mops_destroy_thread(cur);
204 // remove pdesc if available
205 mops_ext_del_pdesc (cur);
206 cur->state = MOPS_STATE_NULL;
208 // remove automops data if available
209 if (cur->amp != NULL) {
210 free(cur->amp);
211 cur->amp=NULL;
213 if (cur->amp_pdu != NULL) {
214 free (cur->amp_pdu);
215 cur->amp_pdu=NULL;
217 // find another name
218 do {
219 sprintf(pname, "PKT%04d", i);
220 i++;
221 } while (mops_search_name (mp_head, pname)); // check if this name is really unique
222 strncpy(cur->packet_name, pname, MAX_MOPS_PACKET_NAME_LEN);
224 // Place everything else in this function:
225 mops_set_defaults (cur);
227 return 0;
233 // Runs through all packets and dumps some statistics into 'str'
234 // Returns 1 if only the uninitialized head is available
236 int mops_dump_all(struct mops* list, char *str)
238 struct mops *head = list;
239 struct mops *cur = list;
241 char output[100];
242 int anzmops=0, active=0, config=0, raw=0, ival=0;
244 do {
245 if (cur->state == MOPS_STATE_ACTIVE) {
246 active++;
247 } else if (cur->state == MOPS_STATE_CONFIG) {
248 config++;
249 } else if (cur->interval_used==2) {
250 ival++;
252 if (cur->use_ETHER == 0) raw++;
254 anzmops++;
255 cur = cur->next;
256 } while (head != cur);
258 snprintf(output, 99, "%i Mopse(s) (interval: %i, active: %i, config: %i, raw: %i)",
259 anzmops, ival, active, config, raw);
261 strncpy(str, output, 99);
263 if ((!active) && (!config)) return 1;
265 return 0;
272 // Search for key = name and return pointer to that mops
273 // Return NULL if not found
274 struct mops * mops_search_name (struct mops* list, char *key)
276 struct mops *head = list;
277 struct mops *cur = list;
278 do {
279 if ( (strncasecmp(key,
280 cur->packet_name,
281 MAX_MOPS_PACKET_NAME_LEN) == 0)) {
282 return cur; // FOUND!
284 cur = cur->next;
286 while (head != cur);
287 return NULL; // NOT FOUND!
292 // Search for key = id and return pointer to that mops
293 // Return NULL if not found
294 struct mops * mops_search_id (struct mops* list, u_int32_t key)
296 struct mops *head = list;
297 struct mops *cur = list;
298 do {
299 if ( cur->id == key ) {
300 return cur; // FOUND!
302 cur = cur->next;
304 while (head != cur);
305 return NULL; // NOT FOUND!
311 // Deletes all elements except the specified element which us usually
312 // the head element. Also ACTIVE elements will be removed and the
313 // corresponding threads will be stopped.
315 // Thus the list can grow again later via mops_alloc_packet
317 void mops_delete_all(struct mops* list)
319 struct mops *head = list;
320 struct mops *cur = list->next;
321 struct mops *tmp;
323 // Delete all but head element:
324 while (head != cur)
326 tmp = cur->next;
327 mops_ext_del_pdesc (cur); // delete p_desc (if available)
328 mops_destroy_thread(cur);
330 // remove automops data if available
331 if (cur->amp != NULL) {
332 free(cur->amp);
333 cur->amp=NULL;
335 if (cur->amp_pdu != NULL) {
336 free (cur->amp_pdu);
337 cur->amp_pdu=NULL;
339 cur->amp_pdu_s=0;
341 if (cur!=NULL) {
342 free(cur);
343 cur=NULL;
345 cur = tmp;
348 head->next = head;
349 head->prev = head;
351 head->state = MOPS_STATE_NULL;
356 // Same as mops_delete_all but also destroys the head element:
357 void mops_cleanup(struct mops* list)
359 mops_delete_all(list);
360 mops_ext_del_pdesc (list); // delete p_desc (if available)
361 mops_destroy_thread(list);
362 if (list!=NULL) {
363 free(list);
364 list=NULL;
371 // Set default MOPS and protocol header parameters
372 // Currently most parameters are taken from the legacy tx-structure
374 // NOTE: Does NOT and should NOT change the packet_name !!!
375 // Because user might be confused if it is changed to something
376 // unexpected such as 'PKT0341'.
378 // TODO: find out MAC of default GW
379 int mops_set_defaults (struct mops *mp)
381 // Initialize frame arrays with zero bytes
382 memset(mp->frame, 0x00, MAX_MOPS_FRAME_SIZE);
383 memset(mp->msg, 0x00, MAX_MOPS_MSG_SIZE);
385 // Basics -- MOPS Management Parameters
386 pthread_mutex_init (& mp->mops_mutex, NULL);
387 // mp->mops_thread = 0; // TODO
388 // mp->interval_thread = 0; // TODO
389 mp->verbose = 1; // normal verbosity
390 mp->use_ETHER = 0;
391 mp->use_SNAP = 0;
392 mp->use_dot1Q = 0;
393 mp->use_MPLS = 0;
394 mp->use_IP = 0;
395 mp->use_UDP = 0;
396 mp->use_TCP = 0;
397 mp->frame_s = 0;
398 mp->msg_s = 0;
399 mp->description[0]='\0';
400 mp->auto_delivery_off = 0;
401 mp->mz_system = 0;
402 strncpy (mp->device, tx.device, 16);
403 mp->count = 0;
404 mp->cntx = 0;
406 mp->ndelay.tv_sec = 0;
407 mp->ndelay.tv_nsec = 100000000L; // 100 ms default delay
409 mp->interval_used = 0;
410 mp->interval.tv_sec = 0;
411 mp->interval.tv_nsec = 0;
413 mp->delay_sigma.tv_sec = 0;
414 mp->delay_sigma.tv_nsec = 0;
416 mp->MSG_use_RAW_FILE=0;
417 mp->MSG_use_HEX_FILE=0;
418 mp->MSG_use_ASC_FILE=0;
419 mp->fp=NULL;
420 mp->chunk_s = MAX_MOPS_MSG_CHUNK_SIZE;
422 // TODO: check if amp and amp_header is free()'d in any case!!!
423 mp->amp = NULL;
424 mp->amp_pdu = NULL;
425 mp->amp_pdu_s = 0;
427 // Ethernet defaults:
428 memcpy((void *) &mp->eth_dst, (void *) &tx.eth_dst, 6);
429 memcpy((void *) &mp->eth_src, (void *) &tx.eth_src, 6);
430 mp->eth_type = 0x800;
431 mp->eth_src_israndom = 0;
433 mp->dot1Q_isrange = 0;
434 mp->mpls_isrange = 0;
436 // IP defaults:
437 // abuse our hton: here we actually convert from net to host order:
438 mops_hton4 ((u_int32_t*) &tx.ip_dst, (u_int8_t*) &mp->ip_dst);
439 mops_hton4 ((u_int32_t*) &tx.ip_src, (u_int8_t*) &mp->ip_src);
440 // Note that the IP address of the "default interface" is assigned to that mops.
441 // If the mops is bind to another interface then use the associated interface.
442 // Implement this in cli_packet and function cmd_packet_bind
444 mp->ip_version = 4;
445 mp->ip_IHL = 0;
446 mp->ip_len = 20;
447 mp->ip_tos = 0;
448 mp->ip_flags_RS=0; // 0|1 ... Reserved flag "must be zero"
449 mp->ip_flags_DF=0; // 0|1 ... Don't Fragment
450 mp->ip_flags_MF=0; // 0|1 ... More Fragments
451 mp->ip_frag_offset=0;
452 mp->ip_fragsize=0; // fragmentation OFF
453 mp->ip_frag_overlap=0; // no overlapping fragments
454 mp->ip_ttl = 255;
455 mp->ip_proto = 17; // UDP
456 mp->ip_src_israndom = 0;
457 mp->ip_src_isrange = 0;
458 mp->ip_dst_isrange = 0;
459 mp->ip_option_used = 0;
460 mp->ip_IHL_false = 0;
461 mp->ip_len_false = 0;
462 mp->ip_sum_false = 0;
463 mp->ip_option_used = 0;
464 mp->ip_option_s = 0;
465 // L4 defaults (port numbers)
466 mp->sp=0;
467 mp->sp_start=0;
468 mp->sp_stop=0;
469 mp->sp_isrand=0;
470 mp->sp_isrange=0;
472 mp->dp=0;
473 mp->dp_start=0;
474 mp->dp_stop=0;
475 mp->dp_isrand=0;
476 mp->dp_isrange=0;
478 // UDP defaults
480 mp->udp_len_false = 0;
481 mp->udp_sum_false = 0;
482 mp->udp_sum = 0xffff; // this default means "transmitter didn't compute checksum"
484 // TCP defaults
486 mp->tcp_seq = 0xcafebabe;
487 mp->tcp_seq_delta = 0; // no range
488 mp->tcp_seq_start = 0;
489 mp->tcp_seq_stop = 0xffffffff;
490 mp->tcp_ack = 0;
491 mp->tcp_ack_delta = 0; // no range
492 mp->tcp_ack_start = 0;
493 mp->tcp_ack_stop = 0xffffffff;
494 mp->tcp_win = 100;
495 mp->tcp_sum_false = 0;
496 mp->tcp_offset_false = 0;
497 mp->tcp_offset = 0;
498 mp->tcp_sum = 0xffff; // this default means "transmitter didn't compute checksum"
499 mp->tcp_option_used = 0;
500 mp->tcp_option_s =0;
501 mp->tcp_ctrl_CWR =0;
502 mp->tcp_ctrl_ECE =0;
503 mp->tcp_ctrl_URG =0;
504 mp->tcp_ctrl_ACK =0;
505 mp->tcp_ctrl_PSH =0;
506 mp->tcp_ctrl_RST =0;
507 mp->tcp_ctrl_SYN =1; // assume that we begin with a TCP SYN
508 mp->tcp_ctrl_FIN =0;
509 mp->tcp_urg =0;
510 mp->tcp_ack =0;
511 mp->tcp_res =0;
512 return 0;
521 int mops_print_frame (struct mops *mp, char *str)
523 int i=0, fs;
524 char octet[8], lnr[8], hex[MAX_MOPS_FRAME_SIZE*3];
526 hex[0]=0x00;
528 if (! (fs = mp->frame_s) ) return -1; // frame length zero (no frame?)
530 if (fs>1)
532 sprintf(lnr,"%4i ",i+1);
533 strcat(hex, lnr);
535 for (i=0; i<fs; i++)
537 if ((i>0) && (!(i%8)))
539 strcat(hex, " "); // insert space after each 8 bytes
540 hex[strlen(hex)-2]=' ';
543 if ((i>0) && (!(i%MAX_CLI_LINE_BYTES)))
545 sprintf(lnr,"\n%4i ",i+1);
546 strcat(hex, lnr);
549 sprintf(octet, "%02x:", mp->frame[i]);
550 strcat(hex, octet);
554 hex[strlen(hex)-1]=' ';
555 strcpy(str, hex);
557 return 0;
567 // Find and returns a new unique packet id
568 // If none can be found, returns -1.
570 int mops_get_new_pkt_id (struct mops *list)
572 struct mops *head = list;
573 struct mops *cur = list;
574 int i, min=0xffffffff, max=0;
576 do {
577 if (cur->id < min) min = cur->id; // determine current min id
578 if (cur->id > max) max = cur->id; // determine current max id
579 cur = cur->next;
581 while (head != cur);
583 if (min>0)
584 i= min-1;
585 else
586 i = max+1;
588 // just for paranoia: check again if unique!
589 do {
590 if (cur->id == i) {
591 return -1; //
593 cur = cur->next;
595 while (head != cur);
597 return i;
601 // Simply sets specified 'layer switches' in mops struct
602 // (use_ETHER, use_IP, ...) to zero.
604 // RETURN VALUE: tells which layers had been configured before clearing.
606 // The presence of the layers is indicated via binary coding:
608 // MOPS_ALL 127 // clear all
609 // MOPS_ETH 1
610 // MOPS_SNAP 2 // either LLC, LLC+SNAP
611 // MOPS_dot1Q 4
612 // MOPS_MPLS 8
613 // MOPS_IP 16
614 // MOPS_UDP 32
615 // MOPS_TCP 64
617 int mops_clear_layers (struct mops *mp, int l)
619 int ret=0;
621 if (l & MOPS_ETH) {
622 if (mp->use_ETHER) ret+=1;
623 mp->use_ETHER = 0;
626 if (l & MOPS_SNAP) {
627 if (mp->use_SNAP) ret+=2;
628 mp->use_SNAP = 0;
631 if (l & MOPS_dot1Q) {
632 if (mp->use_dot1Q) ret+=4;
633 mp->use_dot1Q = 0;
636 if (l & MOPS_MPLS) {
637 if (mp->use_MPLS) ret+=8;
638 mp->use_MPLS = 0;
641 if (l & MOPS_IP) {
642 if (mp->use_IP) ret+=16;
643 mp->use_IP = 0;
646 if (l & MOPS_UDP) {
647 if (mp->use_UDP) ret+=32;
648 mp->use_UDP = 0;
651 if (l & MOPS_TCP) {
652 if (mp->use_TCP) ret+=64;
653 mp->use_TCP = 0;
656 return ret;
660 // Get global device index for a given device name.
662 // RETURN VALUE:
663 // Either the desired device index or -1 if not found.
665 // EXAMPLE:
666 // i = mops_get_device_index("eth0")
668 int mops_get_device_index(char *devname)
670 int i;
672 for (i=0; i<device_list_entries; i++) {
673 if (strncmp(device_list[i].dev, devname, 16)==0) {
674 return i;
678 return -1;
683 // Assign device-specific values (source IP and MAC addresses),
684 // drawn from global device table, to the specified MOPS entry
685 // with index i.
687 int mops_use_device(struct mops * mp, int i)
689 // Assign source MAC address
690 // Assign source IP address
691 // TODO? Assign default gateway
693 memcpy((void *) &mp->eth_src, (void *) &device_list[i].mac_mops[0], 6);
694 memcpy((void *) &mp->ip_src, (void *) &device_list[i].ip_mops[0], 4);
696 return 0;
700 // Creates two strings as used by the 'show packet' command,
701 // 1) one identifying all used layers of a packet,
702 // 2) the other which higher layer protocol is used
704 // caller must define:
705 // char layers[16], proto[16];
707 // RETURNS 0 upon success, 1 upon failure.
709 int mops_get_proto_info(struct mops *mp, char *layers, char *proto)
711 char ds[16], pr[16];
713 if (mp==NULL) return 1;
715 ds[0]='\0';
716 pr[0]='\0';
718 if (mp->use_ETHER) strcat(ds,"E"); else strcat(ds,"-");
719 if (mp->use_SNAP) strcat(ds,"S"); else strcat(ds,"-");
720 if (mp->use_dot1Q) strcat(ds,"Q"); else strcat(ds,"-");
721 if (mp->use_MPLS) strcat(ds,"M"); else strcat(ds,"-");
722 if (mp->use_IP) {
723 if (mp->auto_delivery_off)
724 strcat(ds,"i");
725 else
726 strcat(ds,"I");
727 } else strcat(ds,"-");
729 if (mp->use_UDP)
730 strcat(ds,"U");
731 else if
732 (mp->use_TCP) strcat(ds,"T");
733 else strcat(ds,"-");
735 switch (mp->p_desc_type) {
736 case MOPS_ARP:
737 strncpy(pr, "ARP", 8);
738 break;
739 case MOPS_BPDU:
740 strncpy(pr, "BPDU", 8);
741 break;
742 case MOPS_CDP:
743 strncpy(pr, "CDP", 8);
744 break;
745 case MOPS_DNS:
746 strncpy(pr, "DNS", 8);
747 break;
748 case MOPS_ICMP:
749 strncpy(pr, "ICMP", 8);
750 break;
751 case MOPS_IGMP:
752 strncpy(pr, "IGMP", 8);
753 break;
754 case MOPS_LLDP:
755 strncpy(pr, "LLDP", 8);
756 break;
757 case MOPS_RTP:
758 strncpy(pr, "RTP", 8);
759 break;
760 case MOPS_SYSLOG:
761 strncpy(pr, "SYSLOG", 8);
762 break;
763 default:
764 break;
767 strncpy(layers, ds, 16);
768 strncpy(proto, pr, 16);
769 return 0;