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
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)
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)
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)
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!
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);
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 = ...
87 // RETURN VALUE: + Pointer to new mops
88 // - NULL upon failure
89 struct mops
* mops_alloc_packet(struct mops
*cur
)
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
;
117 sprintf(pname
, "PKT%04d", 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;
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
)
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
) {
171 if (cur
->amp_pdu
!= NULL
) {
177 cur
->next
->prev
= cur
->prev
;
178 cur
->prev
->next
= cur
->next
;
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
)
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
) {
213 if (cur
->amp_pdu
!= NULL
) {
219 sprintf(pname
, "PKT%04d", 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
);
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
;
242 int anzmops
=0, active
=0, config
=0, raw
=0, ival
=0;
245 if (cur
->state
== MOPS_STATE_ACTIVE
) {
247 } else if (cur
->state
== MOPS_STATE_CONFIG
) {
249 } else if (cur
->interval_used
==2) {
252 if (cur
->use_ETHER
== 0) raw
++;
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;
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
;
279 if ( (strncasecmp(key
,
281 MAX_MOPS_PACKET_NAME_LEN
) == 0)) {
282 return cur
; // FOUND!
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
;
299 if ( cur
->id
== key
) {
300 return cur
; // FOUND!
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
;
323 // Delete all but head element:
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
) {
335 if (cur
->amp_pdu
!= NULL
) {
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
);
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
399 mp
->description
[0]='\0';
400 mp
->auto_delivery_off
= 0;
402 strncpy (mp
->device
, tx
.device
, 16);
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;
420 mp
->chunk_s
= MAX_MOPS_MSG_CHUNK_SIZE
;
422 // TODO: check if amp and amp_header is free()'d in any case!!!
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;
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
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
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;
465 // L4 defaults (port numbers)
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"
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;
491 mp
->tcp_ack_delta
= 0; // no range
492 mp
->tcp_ack_start
= 0;
493 mp
->tcp_ack_stop
= 0xffffffff;
495 mp
->tcp_sum_false
= 0;
496 mp
->tcp_offset_false
= 0;
498 mp
->tcp_sum
= 0xffff; // this default means "transmitter didn't compute checksum"
499 mp
->tcp_option_used
= 0;
507 mp
->tcp_ctrl_SYN
=1; // assume that we begin with a TCP SYN
521 int mops_print_frame (struct mops
*mp
, char *str
)
524 char octet
[8], lnr
[8], hex
[MAX_MOPS_FRAME_SIZE
*3];
528 if (! (fs
= mp
->frame_s
) ) return -1; // frame length zero (no frame?)
532 sprintf(lnr
,"%4i ",i
+1);
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);
549 sprintf(octet
, "%02x:", mp
->frame
[i
]);
554 hex
[strlen(hex
)-1]=' ';
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;
577 if (cur
->id
< min
) min
= cur
->id
; // determine current min id
578 if (cur
->id
> max
) max
= cur
->id
; // determine current max id
588 // just for paranoia: check again if unique!
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
610 // MOPS_SNAP 2 // either LLC, LLC+SNAP
617 int mops_clear_layers (struct mops
*mp
, int l
)
622 if (mp
->use_ETHER
) ret
+=1;
627 if (mp
->use_SNAP
) ret
+=2;
631 if (l
& MOPS_dot1Q
) {
632 if (mp
->use_dot1Q
) ret
+=4;
637 if (mp
->use_MPLS
) ret
+=8;
642 if (mp
->use_IP
) ret
+=16;
647 if (mp
->use_UDP
) ret
+=32;
652 if (mp
->use_TCP
) ret
+=64;
660 // Get global device index for a given device name.
663 // Either the desired device index or -1 if not found.
666 // i = mops_get_device_index("eth0")
668 int mops_get_device_index(char *devname
)
672 for (i
=0; i
<device_list_entries
; i
++) {
673 if (strncmp(device_list
[i
].dev
, devname
, 16)==0) {
683 // Assign device-specific values (source IP and MAC addresses),
684 // drawn from global device table, to the specified MOPS entry
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);
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
)
713 if (mp
==NULL
) return 1;
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
,"-");
723 if (mp
->auto_delivery_off
)
727 } else strcat(ds
,"-");
732 (mp
->use_TCP
) strcat(ds
,"T");
735 switch (mp
->p_desc_type
) {
737 strncpy(pr
, "ARP", 8);
740 strncpy(pr
, "BPDU", 8);
743 strncpy(pr
, "CDP", 8);
746 strncpy(pr
, "DNS", 8);
749 strncpy(pr
, "ICMP", 8);
752 strncpy(pr
, "IGMP", 8);
755 strncpy(pr
, "LLDP", 8);
758 strncpy(pr
, "RTP", 8);
761 strncpy(pr
, "SYSLOG", 8);
767 strncpy(layers
, ds
, 16);
768 strncpy(proto
, pr
, 16);