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)
52 // Creates first element, aka "head" element
53 // This element can also be used! See mops_alloc_packet!
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);
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 = ...
84 // RETURN VALUE: + Pointer to new mops
85 // - NULL upon failure
86 struct mops
* mops_alloc_packet(struct mops
*cur
)
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
));
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
;
114 sprintf(pname
, "PKT%04d", 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;
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
)
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
) {
168 if (cur
->amp_pdu
!= NULL
) {
174 cur
->next
->prev
= cur
->prev
;
175 cur
->prev
->next
= cur
->next
;
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
)
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
) {
210 if (cur
->amp_pdu
!= NULL
) {
216 sprintf(pname
, "PKT%04d", 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
);
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
;
239 int anzmops
=0, active
=0, config
=0, raw
=0, ival
=0;
242 if (cur
->state
== MOPS_STATE_ACTIVE
) {
244 } else if (cur
->state
== MOPS_STATE_CONFIG
) {
246 } else if (cur
->interval_used
==2) {
249 if (cur
->use_ETHER
== 0) raw
++;
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;
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
;
276 if ( (strncasecmp(key
,
278 MAX_MOPS_PACKET_NAME_LEN
) == 0)) {
279 return cur
; // FOUND!
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
;
296 if ( cur
->id
== key
) {
297 return cur
; // FOUND!
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
;
320 // Delete all but head element:
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
) {
332 if (cur
->amp_pdu
!= NULL
) {
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
);
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
396 mp
->description
[0]='\0';
397 mp
->auto_delivery_off
= 0;
399 strncpy (mp
->device
, tx
.device
, 16);
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;
417 mp
->chunk_s
= MAX_MOPS_MSG_CHUNK_SIZE
;
419 // TODO: check if amp and amp_header is free()'d in any case!!!
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;
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
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
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;
462 // L4 defaults (port numbers)
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"
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;
488 mp
->tcp_ack_delta
= 0; // no range
489 mp
->tcp_ack_start
= 0;
490 mp
->tcp_ack_stop
= 0xffffffff;
492 mp
->tcp_sum_false
= 0;
493 mp
->tcp_offset_false
= 0;
495 mp
->tcp_sum
= 0xffff; // this default means "transmitter didn't compute checksum"
496 mp
->tcp_option_used
= 0;
504 mp
->tcp_ctrl_SYN
=1; // assume that we begin with a TCP SYN
518 int mops_print_frame (struct mops
*mp
, char *str
)
521 char octet
[8], lnr
[8], hex
[MAX_MOPS_FRAME_SIZE
*3];
525 if (! (fs
= mp
->frame_s
) ) return -1; // frame length zero (no frame?)
529 sprintf(lnr
,"%4i ",i
+1);
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);
546 sprintf(octet
, "%02x:", mp
->frame
[i
]);
551 hex
[strlen(hex
)-1]=' ';
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;
574 if (cur
->id
< min
) min
= cur
->id
; // determine current min id
575 if (cur
->id
> max
) max
= cur
->id
; // determine current max id
585 // just for paranoia: check again if unique!
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
607 // MOPS_SNAP 2 // either LLC, LLC+SNAP
614 int mops_clear_layers (struct mops
*mp
, int l
)
619 if (mp
->use_ETHER
) ret
+=1;
624 if (mp
->use_SNAP
) ret
+=2;
628 if (l
& MOPS_dot1Q
) {
629 if (mp
->use_dot1Q
) ret
+=4;
634 if (mp
->use_MPLS
) ret
+=8;
639 if (mp
->use_IP
) ret
+=16;
644 if (mp
->use_UDP
) ret
+=32;
649 if (mp
->use_TCP
) ret
+=64;
657 // Get global device index for a given device name.
660 // Either the desired device index or -1 if not found.
663 // i = mops_get_device_index("eth0")
665 int mops_get_device_index(char *devname
)
669 for (i
=0; i
<device_list_entries
; i
++) {
670 if (strncmp(device_list
[i
].dev
, devname
, 16)==0) {
680 // Assign device-specific values (source IP and MAC addresses),
681 // drawn from global device table, to the specified MOPS entry
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);
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
)
710 if (mp
==NULL
) return 1;
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
,"-");
720 if (mp
->auto_delivery_off
)
724 } else strcat(ds
,"-");
729 (mp
->use_TCP
) strcat(ds
,"T");
732 switch (mp
->p_desc_type
) {
734 strncpy(pr
, "ARP", 8);
737 strncpy(pr
, "BPDU", 8);
740 strncpy(pr
, "CDP", 8);
743 strncpy(pr
, "DNS", 8);
746 strncpy(pr
, "ICMP", 8);
749 strncpy(pr
, "IGMP", 8);
752 strncpy(pr
, "LLDP", 8);
755 strncpy(pr
, "RTP", 8);
758 strncpy(pr
, "SYSLOG", 8);
764 strncpy(layers
, ds
, 16);
765 strncpy(proto
, pr
, 16);