netsniff-ng: trafgen: use bug_on around gettimeofday
[netsniff-ng.git] / src / mops.c
blobf56deffb9d6add25a1a56b81d52199544c84445e
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"
52 // Creates first element, aka "head" element
53 // This element can also be used! See mops_alloc_packet!
54 //
55 struct mops * mops_init()
57 // these defaults can be changed by the user:
58 min_frame_s = MIN_MOPS_FRAME_SIZE; // important global; depends on used packet tx subsystem such as libnet
59 max_frame_s = MAX_MOPS_FRAME_SIZE-MOPS_SIZE_MARGIN;
61 // Create initial mops element:
62 struct mops *new_mops = (struct mops*) malloc(sizeof(struct mops));
63 new_mops->next = new_mops;
64 new_mops->prev = new_mops;
65 new_mops->state = MOPS_STATE_NULL;
66 new_mops->id = 0; // importante!
67 mops_set_defaults (new_mops);
68 strncpy(new_mops->packet_name, "-------", 8);
70 return new_mops;
77 // Returns pointer to new mops element:
78 // 1) either insert a new mops element in list
79 // 2) or returns same pointer again if current mops element is empty
80 // Note that new element N is always PREPENDED to cur:
81 // ... = N-2 = N-1 = N = cur = 1 = 2 = ...
82 //
83 //
84 // RETURN VALUE: + Pointer to new mops
85 // - NULL upon failure
86 struct mops * mops_alloc_packet(struct mops *cur)
88 int j;
89 struct mops *new_mops;
90 int new_pkt_id, pkt_id_name;
91 char pname[MAX_MOPS_PACKET_NAME_LEN];
93 if (cur->state == MOPS_STATE_NULL) { // allows to use first packet in list
94 new_mops = cur; // current mops was unused => no need to insert a new mops!
96 else { // create new mops element
97 new_mops = (struct mops *) malloc(sizeof(struct mops));
98 if (new_mops==NULL) {
99 fprintf(stderr, "MZ alert: cannot create new mops entry - memory full?\n");
100 return NULL; // memory full?
104 new_mops->state = MOPS_STATE_INIT;
106 // Assign unique packet id
107 new_pkt_id = mops_get_new_pkt_id (cur);
108 if (new_pkt_id==-1) return NULL;
109 new_mops->id = new_pkt_id;
111 // Assign unique packet name
112 pkt_id_name = new_pkt_id;
113 do {
114 sprintf(pname, "PKT%04d", pkt_id_name);
115 pkt_id_name++;
116 } while (mops_search_name (mp_head, pname)); // check if this name is really unique
118 strncpy(new_mops->packet_name, pname, MAX_MOPS_PACKET_NAME_LEN);
120 // append to doubly linked list
121 new_mops->prev = cur->prev;
122 new_mops->next = cur;
123 cur->prev = new_mops;
124 new_mops->prev->next = new_mops;
126 mops_set_defaults (new_mops); // set header parametes (addresses etc)
128 // Reset protocol descriptor
129 new_mops->p_desc = NULL;
130 new_mops->p_desc_type = MOPS_NO_PDESC;
132 // clear counter values
133 new_mops->used_counters=0;
134 for (j=0; j<MAX_MOPS_COUNTERS_PER_PACKET; j++) {
135 new_mops->counter[j].use = 0;
136 new_mops->counter[j].offset = 0;
137 new_mops->counter[j].random = 0;
140 return new_mops;
145 // Delete particular packet (remove it from list).
147 // If mp_head is deleted, makes previous element mp_head.
148 // Note that the global mp_head must exist but within MOPS this
149 // is always the case.
151 // Returns pointer to previous element in the list
152 // or NULL if packet is active
153 struct mops * mops_delete_packet(struct mops *cur)
155 struct mops *last;
157 if (mops_is_active(cur)) {
158 mops_destroy_thread(cur);
161 mops_ext_del_pdesc (cur); // delete p_desc (if available)
163 // remove automops data if available
164 if (cur->amp != NULL) {
165 free(cur->amp);
166 cur->amp=NULL;
168 if (cur->amp_pdu != NULL) {
169 free (cur->amp_pdu);
170 cur->amp_pdu=NULL;
173 last = cur->prev;
174 cur->next->prev = cur->prev;
175 cur->prev->next = cur->next;
176 if (cur==mp_head) {
177 mp_head = last;
179 if (cur!=NULL) {
180 free (cur);
181 cur=NULL;
183 return last;
188 // Erase all data of a mops entry and even chooses a new standard name
189 // DOES NOT delete the entry from the list
191 int mops_reset_packet(struct mops *cur)
193 int i=0;
194 char pname[16];
196 // stop thread if necessary
197 if (mops_is_active(cur)) {
198 mops_destroy_thread(cur);
201 // remove pdesc if available
202 mops_ext_del_pdesc (cur);
203 cur->state = MOPS_STATE_NULL;
205 // remove automops data if available
206 if (cur->amp != NULL) {
207 free(cur->amp);
208 cur->amp=NULL;
210 if (cur->amp_pdu != NULL) {
211 free (cur->amp_pdu);
212 cur->amp_pdu=NULL;
214 // find another name
215 do {
216 sprintf(pname, "PKT%04d", i);
217 i++;
218 } while (mops_search_name (mp_head, pname)); // check if this name is really unique
219 strncpy(cur->packet_name, pname, MAX_MOPS_PACKET_NAME_LEN);
221 // Place everything else in this function:
222 mops_set_defaults (cur);
224 return 0;
230 // Runs through all packets and dumps some statistics into 'str'
231 // Returns 1 if only the uninitialized head is available
233 int mops_dump_all(struct mops* list, char *str)
235 struct mops *head = list;
236 struct mops *cur = list;
238 char output[100];
239 int anzmops=0, active=0, config=0, raw=0, ival=0;
241 do {
242 if (cur->state == MOPS_STATE_ACTIVE) {
243 active++;
244 } else if (cur->state == MOPS_STATE_CONFIG) {
245 config++;
246 } else if (cur->interval_used==2) {
247 ival++;
249 if (cur->use_ETHER == 0) raw++;
251 anzmops++;
252 cur = cur->next;
253 } while (head != cur);
255 snprintf(output, 99, "%i Mopse(s) (interval: %i, active: %i, config: %i, raw: %i)",
256 anzmops, ival, active, config, raw);
258 strncpy(str, output, 99);
260 if ((!active) && (!config)) return 1;
262 return 0;
269 // Search for key = name and return pointer to that mops
270 // Return NULL if not found
271 struct mops * mops_search_name (struct mops* list, char *key)
273 struct mops *head = list;
274 struct mops *cur = list;
275 do {
276 if ( (strncasecmp(key,
277 cur->packet_name,
278 MAX_MOPS_PACKET_NAME_LEN) == 0)) {
279 return cur; // FOUND!
281 cur = cur->next;
283 while (head != cur);
284 return NULL; // NOT FOUND!
289 // Search for key = id and return pointer to that mops
290 // Return NULL if not found
291 struct mops * mops_search_id (struct mops* list, u_int32_t key)
293 struct mops *head = list;
294 struct mops *cur = list;
295 do {
296 if ( cur->id == key ) {
297 return cur; // FOUND!
299 cur = cur->next;
301 while (head != cur);
302 return NULL; // NOT FOUND!
308 // Deletes all elements except the specified element which us usually
309 // the head element. Also ACTIVE elements will be removed and the
310 // corresponding threads will be stopped.
312 // Thus the list can grow again later via mops_alloc_packet
314 void mops_delete_all(struct mops* list)
316 struct mops *head = list;
317 struct mops *cur = list->next;
318 struct mops *tmp;
320 // Delete all but head element:
321 while (head != cur)
323 tmp = cur->next;
324 mops_ext_del_pdesc (cur); // delete p_desc (if available)
325 mops_destroy_thread(cur);
327 // remove automops data if available
328 if (cur->amp != NULL) {
329 free(cur->amp);
330 cur->amp=NULL;
332 if (cur->amp_pdu != NULL) {
333 free (cur->amp_pdu);
334 cur->amp_pdu=NULL;
336 cur->amp_pdu_s=0;
338 if (cur!=NULL) {
339 free(cur);
340 cur=NULL;
342 cur = tmp;
345 head->next = head;
346 head->prev = head;
348 head->state = MOPS_STATE_NULL;
353 // Same as mops_delete_all but also destroys the head element:
354 void mops_cleanup(struct mops* list)
356 mops_delete_all(list);
357 mops_ext_del_pdesc (list); // delete p_desc (if available)
358 mops_destroy_thread(list);
359 if (list!=NULL) {
360 free(list);
361 list=NULL;
368 // Set default MOPS and protocol header parameters
369 // Currently most parameters are taken from the legacy tx-structure
371 // NOTE: Does NOT and should NOT change the packet_name !!!
372 // Because user might be confused if it is changed to something
373 // unexpected such as 'PKT0341'.
375 // TODO: find out MAC of default GW
376 int mops_set_defaults (struct mops *mp)
378 // Initialize frame arrays with zero bytes
379 memset(mp->frame, 0x00, MAX_MOPS_FRAME_SIZE);
380 memset(mp->msg, 0x00, MAX_MOPS_MSG_SIZE);
382 // Basics -- MOPS Management Parameters
383 pthread_mutex_init (& mp->mops_mutex, NULL);
384 // mp->mops_thread = 0; // TODO
385 // mp->interval_thread = 0; // TODO
386 mp->verbose = 1; // normal verbosity
387 mp->use_ETHER = 0;
388 mp->use_SNAP = 0;
389 mp->use_dot1Q = 0;
390 mp->use_MPLS = 0;
391 mp->use_IP = 0;
392 mp->use_UDP = 0;
393 mp->use_TCP = 0;
394 mp->frame_s = 0;
395 mp->msg_s = 0;
396 mp->description[0]='\0';
397 mp->auto_delivery_off = 0;
398 mp->mz_system = 0;
399 strncpy (mp->device, tx.device, 16);
400 mp->count = 0;
401 mp->cntx = 0;
403 mp->ndelay.tv_sec = 0;
404 mp->ndelay.tv_nsec = 100000000L; // 100 ms default delay
406 mp->interval_used = 0;
407 mp->interval.tv_sec = 0;
408 mp->interval.tv_nsec = 0;
410 mp->delay_sigma.tv_sec = 0;
411 mp->delay_sigma.tv_nsec = 0;
413 mp->MSG_use_RAW_FILE=0;
414 mp->MSG_use_HEX_FILE=0;
415 mp->MSG_use_ASC_FILE=0;
416 mp->fp=NULL;
417 mp->chunk_s = MAX_MOPS_MSG_CHUNK_SIZE;
419 // TODO: check if amp and amp_header is free()'d in any case!!!
420 mp->amp = NULL;
421 mp->amp_pdu = NULL;
422 mp->amp_pdu_s = 0;
424 // Ethernet defaults:
425 memcpy((void *) &mp->eth_dst, (void *) &tx.eth_dst, 6);
426 memcpy((void *) &mp->eth_src, (void *) &tx.eth_src, 6);
427 mp->eth_type = 0x800;
428 mp->eth_src_israndom = 0;
430 mp->dot1Q_isrange = 0;
431 mp->mpls_isrange = 0;
433 // IP defaults:
434 // abuse our hton: here we actually convert from net to host order:
435 mops_hton4 ((u_int32_t*) &tx.ip_dst, (u_int8_t*) &mp->ip_dst);
436 mops_hton4 ((u_int32_t*) &tx.ip_src, (u_int8_t*) &mp->ip_src);
437 // Note that the IP address of the "default interface" is assigned to that mops.
438 // If the mops is bind to another interface then use the associated interface.
439 // Implement this in cli_packet and function cmd_packet_bind
441 mp->ip_version = 4;
442 mp->ip_IHL = 0;
443 mp->ip_len = 20;
444 mp->ip_tos = 0;
445 mp->ip_flags_RS=0; // 0|1 ... Reserved flag "must be zero"
446 mp->ip_flags_DF=0; // 0|1 ... Don't Fragment
447 mp->ip_flags_MF=0; // 0|1 ... More Fragments
448 mp->ip_frag_offset=0;
449 mp->ip_fragsize=0; // fragmentation OFF
450 mp->ip_frag_overlap=0; // no overlapping fragments
451 mp->ip_ttl = 255;
452 mp->ip_proto = 17; // UDP
453 mp->ip_src_israndom = 0;
454 mp->ip_src_isrange = 0;
455 mp->ip_dst_isrange = 0;
456 mp->ip_option_used = 0;
457 mp->ip_IHL_false = 0;
458 mp->ip_len_false = 0;
459 mp->ip_sum_false = 0;
460 mp->ip_option_used = 0;
461 mp->ip_option_s = 0;
462 // L4 defaults (port numbers)
463 mp->sp=0;
464 mp->sp_start=0;
465 mp->sp_stop=0;
466 mp->sp_isrand=0;
467 mp->sp_isrange=0;
469 mp->dp=0;
470 mp->dp_start=0;
471 mp->dp_stop=0;
472 mp->dp_isrand=0;
473 mp->dp_isrange=0;
475 // UDP defaults
477 mp->udp_len_false = 0;
478 mp->udp_sum_false = 0;
479 mp->udp_sum = 0xffff; // this default means "transmitter didn't compute checksum"
481 // TCP defaults
483 mp->tcp_seq = 0xcafebabe;
484 mp->tcp_seq_delta = 0; // no range
485 mp->tcp_seq_start = 0;
486 mp->tcp_seq_stop = 0xffffffff;
487 mp->tcp_ack = 0;
488 mp->tcp_ack_delta = 0; // no range
489 mp->tcp_ack_start = 0;
490 mp->tcp_ack_stop = 0xffffffff;
491 mp->tcp_win = 100;
492 mp->tcp_sum_false = 0;
493 mp->tcp_offset_false = 0;
494 mp->tcp_offset = 0;
495 mp->tcp_sum = 0xffff; // this default means "transmitter didn't compute checksum"
496 mp->tcp_option_used = 0;
497 mp->tcp_option_s =0;
498 mp->tcp_ctrl_CWR =0;
499 mp->tcp_ctrl_ECE =0;
500 mp->tcp_ctrl_URG =0;
501 mp->tcp_ctrl_ACK =0;
502 mp->tcp_ctrl_PSH =0;
503 mp->tcp_ctrl_RST =0;
504 mp->tcp_ctrl_SYN =1; // assume that we begin with a TCP SYN
505 mp->tcp_ctrl_FIN =0;
506 mp->tcp_urg =0;
507 mp->tcp_ack =0;
508 mp->tcp_res =0;
509 return 0;
518 int mops_print_frame (struct mops *mp, char *str)
520 int i=0, fs;
521 char octet[8], lnr[8], hex[MAX_MOPS_FRAME_SIZE*3];
523 hex[0]=0x00;
525 if (! (fs = mp->frame_s) ) return -1; // frame length zero (no frame?)
527 if (fs>1)
529 sprintf(lnr,"%4i ",i+1);
530 strcat(hex, lnr);
532 for (i=0; i<fs; i++)
534 if ((i>0) && (!(i%8)))
536 strcat(hex, " "); // insert space after each 8 bytes
537 hex[strlen(hex)-2]=' ';
540 if ((i>0) && (!(i%MAX_CLI_LINE_BYTES)))
542 sprintf(lnr,"\n%4i ",i+1);
543 strcat(hex, lnr);
546 sprintf(octet, "%02x:", mp->frame[i]);
547 strcat(hex, octet);
551 hex[strlen(hex)-1]=' ';
552 strcpy(str, hex);
554 return 0;
564 // Find and returns a new unique packet id
565 // If none can be found, returns -1.
567 int mops_get_new_pkt_id (struct mops *list)
569 struct mops *head = list;
570 struct mops *cur = list;
571 int i, min=0xffffffff, max=0;
573 do {
574 if (cur->id < min) min = cur->id; // determine current min id
575 if (cur->id > max) max = cur->id; // determine current max id
576 cur = cur->next;
578 while (head != cur);
580 if (min>0)
581 i= min-1;
582 else
583 i = max+1;
585 // just for paranoia: check again if unique!
586 do {
587 if (cur->id == i) {
588 return -1; //
590 cur = cur->next;
592 while (head != cur);
594 return i;
598 // Simply sets specified 'layer switches' in mops struct
599 // (use_ETHER, use_IP, ...) to zero.
601 // RETURN VALUE: tells which layers had been configured before clearing.
603 // The presence of the layers is indicated via binary coding:
605 // MOPS_ALL 127 // clear all
606 // MOPS_ETH 1
607 // MOPS_SNAP 2 // either LLC, LLC+SNAP
608 // MOPS_dot1Q 4
609 // MOPS_MPLS 8
610 // MOPS_IP 16
611 // MOPS_UDP 32
612 // MOPS_TCP 64
614 int mops_clear_layers (struct mops *mp, int l)
616 int ret=0;
618 if (l & MOPS_ETH) {
619 if (mp->use_ETHER) ret+=1;
620 mp->use_ETHER = 0;
623 if (l & MOPS_SNAP) {
624 if (mp->use_SNAP) ret+=2;
625 mp->use_SNAP = 0;
628 if (l & MOPS_dot1Q) {
629 if (mp->use_dot1Q) ret+=4;
630 mp->use_dot1Q = 0;
633 if (l & MOPS_MPLS) {
634 if (mp->use_MPLS) ret+=8;
635 mp->use_MPLS = 0;
638 if (l & MOPS_IP) {
639 if (mp->use_IP) ret+=16;
640 mp->use_IP = 0;
643 if (l & MOPS_UDP) {
644 if (mp->use_UDP) ret+=32;
645 mp->use_UDP = 0;
648 if (l & MOPS_TCP) {
649 if (mp->use_TCP) ret+=64;
650 mp->use_TCP = 0;
653 return ret;
657 // Get global device index for a given device name.
659 // RETURN VALUE:
660 // Either the desired device index or -1 if not found.
662 // EXAMPLE:
663 // i = mops_get_device_index("eth0")
665 int mops_get_device_index(char *devname)
667 int i;
669 for (i=0; i<device_list_entries; i++) {
670 if (strncmp(device_list[i].dev, devname, 16)==0) {
671 return i;
675 return -1;
680 // Assign device-specific values (source IP and MAC addresses),
681 // drawn from global device table, to the specified MOPS entry
682 // with index i.
684 int mops_use_device(struct mops * mp, int i)
686 // Assign source MAC address
687 // Assign source IP address
688 // TODO? Assign default gateway
690 memcpy((void *) &mp->eth_src, (void *) &device_list[i].mac_mops[0], 6);
691 memcpy((void *) &mp->ip_src, (void *) &device_list[i].ip_mops[0], 4);
693 return 0;
697 // Creates two strings as used by the 'show packet' command,
698 // 1) one identifying all used layers of a packet,
699 // 2) the other which higher layer protocol is used
701 // caller must define:
702 // char layers[16], proto[16];
704 // RETURNS 0 upon success, 1 upon failure.
706 int mops_get_proto_info(struct mops *mp, char *layers, char *proto)
708 char ds[16], pr[16];
710 if (mp==NULL) return 1;
712 ds[0]='\0';
713 pr[0]='\0';
715 if (mp->use_ETHER) strcat(ds,"E"); else strcat(ds,"-");
716 if (mp->use_SNAP) strcat(ds,"S"); else strcat(ds,"-");
717 if (mp->use_dot1Q) strcat(ds,"Q"); else strcat(ds,"-");
718 if (mp->use_MPLS) strcat(ds,"M"); else strcat(ds,"-");
719 if (mp->use_IP) {
720 if (mp->auto_delivery_off)
721 strcat(ds,"i");
722 else
723 strcat(ds,"I");
724 } else strcat(ds,"-");
726 if (mp->use_UDP)
727 strcat(ds,"U");
728 else if
729 (mp->use_TCP) strcat(ds,"T");
730 else strcat(ds,"-");
732 switch (mp->p_desc_type) {
733 case MOPS_ARP:
734 strncpy(pr, "ARP", 8);
735 break;
736 case MOPS_BPDU:
737 strncpy(pr, "BPDU", 8);
738 break;
739 case MOPS_CDP:
740 strncpy(pr, "CDP", 8);
741 break;
742 case MOPS_DNS:
743 strncpy(pr, "DNS", 8);
744 break;
745 case MOPS_ICMP:
746 strncpy(pr, "ICMP", 8);
747 break;
748 case MOPS_IGMP:
749 strncpy(pr, "IGMP", 8);
750 break;
751 case MOPS_LLDP:
752 strncpy(pr, "LLDP", 8);
753 break;
754 case MOPS_RTP:
755 strncpy(pr, "RTP", 8);
756 break;
757 case MOPS_SYSLOG:
758 strncpy(pr, "SYSLOG", 8);
759 break;
760 default:
761 break;
764 strncpy(layers, ds, 16);
765 strncpy(proto, pr, 16);
766 return 0;