summaryrefslogtreecommitdiff
path: root/staging
diff options
context:
space:
mode:
authorDaniel Borkmann <dborkman@redhat.com>2013-05-13 13:53:27 +0200
committerDaniel Borkmann <dborkman@redhat.com>2013-05-13 15:10:16 +0200
commitd0009856814c13d13770db5aadd7b2fabf947776 (patch)
tree6d18a94439f27f3c2685f05c57435116673f40cc /staging
parent2b100f7515dbd01032967c2d1b81d2f8d63bf9b5 (diff)
staging: add mausezahn staging directory
After some back and forth, we decided that it is easier to maintain mausezahn in a staging directory until it is fully reworked and cleaned up to be ready to be fully integrated. This way, it is better than having it in a separate branch, and we can also accept patches from outside more easily. Also, while at it, fix up some function mismatches with libcli. Signed-off-by: Daniel Borkmann <dborkman@redhat.com> Signed-off-by: Tobias Klauser <tklauser@distanz.ch>
Diffstat (limited to 'staging')
-rw-r--r--staging/automops.c1013
-rw-r--r--staging/cdp.c769
-rw-r--r--staging/cli.c570
-rw-r--r--staging/cli.h268
-rw-r--r--staging/cli_arp.c232
-rw-r--r--staging/cli_bpdu.c750
-rw-r--r--staging/cli_cmds.c1428
-rw-r--r--staging/cli_dns.c53
-rw-r--r--staging/cli_eth.c269
-rw-r--r--staging/cli_igmp.c322
-rw-r--r--staging/cli_interface.c142
-rw-r--r--staging/cli_ip.c888
-rw-r--r--staging/cli_launch.c141
-rw-r--r--staging/cli_legacy.c141
-rw-r--r--staging/cli_lldp.c437
-rw-r--r--staging/cli_packet.c1121
-rw-r--r--staging/cli_rtp.c343
-rw-r--r--staging/cli_sequence.c263
-rw-r--r--staging/cli_set.c350
-rw-r--r--staging/cli_tcp.c679
-rw-r--r--staging/cli_tools.c40
-rw-r--r--staging/cli_udp.c204
-rw-r--r--staging/directmops.c30
-rw-r--r--staging/dns.c817
-rw-r--r--staging/hextools.c322
-rw-r--r--staging/layer1.c383
-rw-r--r--staging/layer2.c902
-rw-r--r--staging/layer3.c734
-rw-r--r--staging/layer4.c884
-rw-r--r--staging/llist.c176
-rw-r--r--staging/llist.h75
-rw-r--r--staging/lookupdev.c357
-rw-r--r--staging/mausezahn.c1013
-rw-r--r--staging/modifications.c698
-rw-r--r--staging/mops.c769
-rw-r--r--staging/mops.h1023
-rw-r--r--staging/mops_checksums.c128
-rw-r--r--staging/mops_dot1Q.c131
-rw-r--r--staging/mops_ext.c466
-rw-r--r--staging/mops_ext_arp.c239
-rw-r--r--staging/mops_ext_bpdu.c242
-rw-r--r--staging/mops_ext_igmp.c270
-rw-r--r--staging/mops_ext_lldp.c430
-rw-r--r--staging/mops_ext_rtp.c243
-rw-r--r--staging/mops_ip.c447
-rw-r--r--staging/mops_mpls.c149
-rw-r--r--staging/mops_sequence.c303
-rw-r--r--staging/mops_tcp.c154
-rw-r--r--staging/mops_threads.c639
-rw-r--r--staging/mops_tools.c259
-rw-r--r--staging/mops_update.c422
-rw-r--r--staging/mopsrx_arp.c301
-rw-r--r--staging/mz.h931
-rw-r--r--staging/parse_xml.c568
-rw-r--r--staging/rcv_rtp.c769
-rw-r--r--staging/rtp.c217
-rw-r--r--staging/send.c264
-rw-r--r--staging/send_eth.c491
-rw-r--r--staging/syslog.c248
-rw-r--r--staging/time.c211
-rw-r--r--staging/tools.c1344
-rw-r--r--staging/tx_switch.c178
62 files changed, 28650 insertions, 0 deletions
diff --git a/staging/automops.c b/staging/automops.c
new file mode 100644
index 0000000..b465346
--- /dev/null
+++ b/staging/automops.c
@@ -0,0 +1,1013 @@
+/*
+ * Mausezahn - A fast versatile traffic generator
+ * Copyright (C) 2008-2010 Herbert Haas
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
+ *
+*/
+
+#include "mz.h"
+#include "mops.h"
+
+
+// Creates first element, aka "head" element
+// This element can also be used! See automops_alloc_protocol!
+//
+struct automops * automops_init()
+{
+ // Create initial automops element:
+ struct automops *new_automops = (struct automops*) malloc(sizeof(struct automops));
+ new_automops->next = new_automops;
+ new_automops->prev = new_automops;
+ automops_set_defaults (new_automops);
+ new_automops->used = -1; // freshly created, no valid data in it
+ return new_automops;
+}
+
+
+
+// (Re-)sets anything within the specified automops element
+void automops_set_defaults(struct automops * cur)
+{
+ int i;
+
+ mz_strncpy(cur->name, "user_proto", 16);
+ mz_strncpy(cur->desc, "undefined", 16);
+ cur->layers_on = 0;
+ cur->layers_off = 0;
+
+ cur->etype = 0;
+ cur->proto = 0;
+ for (i=0; i<6; i++) {
+ cur->sa[i] = 0x00;
+ cur->da[i] = 0xff; // bcast (silly?)
+ }
+ cur->SA = cur->DA = 0;
+ cur->sp = cur->dp = 0;
+
+ cur->payload_type = 0; // both ascii or hex
+ cur->payload = NULL;
+ cur->payload_s = 0;
+ cur->defined_externally = -1; // undefined
+ if (cur->field != NULL) automops_delete_fields (cur);
+ cur->field = NULL;
+}
+
+
+// Returns pointer to new automops element:
+// 1) either insert a new automops element in list
+// 2) or returns same pointer again if current automops element is empty
+// Note that new element N is always PREPENDED to cur:
+// ... = N-2 = N-1 = N = cur = 1 = 2 = ...
+// Therefore, cur should be typically a pointer to the head element
+//
+struct automops * automops_alloc_protocol(struct automops *cur)
+{
+ struct automops *new_automops;
+
+ if (cur->used == -1) // allows to use head element in list
+ {
+ new_automops = cur; // current automops was unused => no need to insert a new one!
+ }
+ else // create new automops element
+ {
+ new_automops = (struct automops *) malloc(sizeof(struct automops));
+ if (new_automops==NULL)
+ {
+ fprintf(stderr, "MZ alert: cannot create new automops entry - memory full?\n");
+ return NULL; // memory full?
+ }
+ new_automops->field=NULL; // don't remove this! See automops_set_defaults() to understand.
+ automops_set_defaults(new_automops);
+ }
+
+ new_automops->used=0;
+
+ // append to doubly linked list
+ new_automops->prev = cur->prev;
+ new_automops->next = cur;
+ cur->prev = new_automops;
+ new_automops->prev->next = new_automops;
+
+ return new_automops;
+}
+
+
+// Delete particular protocol (remove it from list or mops).
+//
+// If amp_head is deleted, makes previous element amp_head.
+// Note that the global amp_head must exist but within MOPS this
+// is always the case.
+//
+// RETURN VALUE:
+//
+// - pointer to previous element in the list
+// - NULL if current automops is used by some mops(es)
+// (in this case, we may still need it, maybe the user wants
+// to modify data or wants other information...?)
+//
+// - NULL if current element is a single element attached to a mops
+//
+struct automops * automops_delete_protocol(struct automops *cur)
+{
+ struct automops *last;
+
+ // Maybe the following is not really practical? /////
+ if (cur->used>0) {
+ return NULL;
+ }
+ /////////////////////////////////////////////////////
+
+ // delete fields list:
+ automops_delete_fields (cur);
+
+ if (cur->payload_s) free (cur->payload);
+
+ if ((cur!=amp_head) && (cur->prev==NULL) && (cur->next==NULL)) {
+ // this one is attached to a mops
+ if (cur!=NULL) free (cur);
+ return NULL;
+ }
+
+ // part of linked list
+ last = cur->prev;
+ cur->next->prev = cur->prev;
+ cur->prev->next = cur->next;
+ if (cur==amp_head) {
+ amp_head = last;
+ }
+ if (cur!=NULL) free (cur);
+
+ return last;
+}
+
+
+
+// Search automops element for a given protocol name
+//
+// Returns pointer to that automops element
+// or NULL if not found
+//
+struct automops * automops_search_protocol(struct automops *list, char *name)
+{
+ struct automops *head = list;
+ struct automops *cur = list;
+
+ do {
+ if ( (strncasecmp(name, cur->name,
+ AUTOMOPS_MAX_NAME_LEN) == 0)) {
+ return cur; // FOUND!
+ }
+ cur = cur->next;
+ } while (head != cur);
+
+ return NULL; // NOT FOUND!
+}
+
+
+
+// Runs through all automops entries and dumps some basic info
+// Returns the number of used protocols
+//
+int automops_dump_all(struct automops* list)
+{
+ struct automops *head = list;
+ struct automops *cur = list;
+ struct fields *f=NULL;
+ int anzmops=0, used=0;
+ char str[64], ft[32];
+ uint32_t SA=0, DA=0;
+ uint8_t *x, *y;
+ char bits_on[18], bits_off[18];
+ int i=0, j=0;
+
+ do {
+ if (cur->used==-1) {
+ fprintf(stderr, "AUTOMOPS: Initial element\n");
+ if ((cur->next==cur)&&(cur->prev==cur))
+ fprintf(stderr, " No other elements found.\n");
+ break;
+ }
+ if (cur->used>0) used++;
+ anzmops++;
+ SA=ntohl(cur->SA); x = (uint8_t*) &SA;
+ DA=ntohl(cur->DA); y = (uint8_t*) &DA;
+ char2bits(cur->layers_on, bits_on);
+ char2bits(cur->layers_off, bits_off);
+ fprintf(stderr, "Protocol %i: %s -- %s\n"
+ " Layercodes: X T U I M Q S E\n"
+ " requires %s (0x%02x)\n"
+ " conflicts %s (0x%02x)\n"
+ " L2: EtherType=%04x, sa=%02x:%02x:%02x:%02x:%02x:%02x, da=%02x:%02x:%02x:%02x:%02x:%02x\n"
+ ,
+ anzmops, cur->name, cur->desc,
+ bits_on, cur->layers_on, bits_off, cur->layers_off,
+ cur->etype, cur->sa[0], cur->sa[1], cur->sa[2], cur->sa[3], cur->sa[4], cur->sa[5],
+ cur->da[0], cur->da[1], cur->da[2], cur->da[3], cur->da[4], cur->da[5]);
+ if (cur->layers_on&MOPS_IP) {
+ fprintf(stderr, " IP: proto=%i, SA=%u.%u.%u.%u, DA=%u.%u.%u.%u\n",
+ cur->proto, *x, *(x+1), *(x+2), *(x+3), *y, *(y+1), *(y+2), *(y+3));
+ } else {
+ fprintf(stderr, " IP: ---\n");
+ }
+ // Walk through field data:
+ f=cur->field; j=0;
+ while (f!=NULL) {
+ j++; // count number of fields
+ if (verbose) {
+ i=0;
+ if (f->longdesc!=NULL) {
+ mz_strncpy(str, f->longdesc, 60);
+ if (strnlen(str,60)>=59) i=1;
+ }
+ else {
+ mz_strncpy(str, "-- no long description specified --", 60);
+ }
+ amp_type2str(f->type, ft);
+ fprintf(stderr, " %02i Field [%i] '%s' -- %s\n"
+ " Description: %s%s\n"
+ " Type: %s %s %s (%lu/%lu) {%lu..%lu..%lu} shift: %i; %i chars\n"
+ ,f->i, f->index, f->name, f->shortdesc,
+ str, (i) ? "..." : "",
+ ft, (f->constant) ? "FIXED" : "",
+ (f->valname!=NULL) ? f->valname : "(no value name)" ,
+ (long unsigned int) f->tlv_type,
+ (long unsigned int) f->tlv_len,
+ (long unsigned int) f->min,
+ (long unsigned int) f->val,
+ (long unsigned int) f->max,
+ f->leftshift, f->str_s);
+ }
+ f=f->next;
+ }
+ if (verbose==0) fprintf(stderr, " %i fields defined.\n", j);
+ //---------------------------------
+ cur = cur->next;
+ } while (head != cur);
+
+ return used;
+}
+
+
+
+// Creates an independent automops element for mops
+// (it will be not part of any linked list so, next=prev=NULL)
+//
+// RETURN VALUE: - Pointer to the cloned automops
+// - NULL upon failure
+//
+struct automops * automops_clone_automops(struct automops * amp)
+{
+ struct automops *new_automops;
+ struct fields *f, *g, *h=NULL;
+ int i;
+
+ // Allocate memory
+ new_automops = (struct automops *) malloc(sizeof(struct automops));
+ if (new_automops==NULL) {
+ fprintf(stderr, "MZ alert: cannot create new automops element - memory full?\n");
+ return NULL; // memory full?
+ }
+
+ // Copy the automops items
+ new_automops->next = NULL;
+ new_automops->prev = NULL;
+
+ strncpy(new_automops->name, amp->name, AUTOMOPS_MAX_NAME_LEN);
+ strncpy(new_automops->desc, amp->desc, AUTOMOPS_MAX_SHORTDESC_LEN);
+ new_automops->layers_on = amp->layers_on;
+ new_automops->layers_off = amp->layers_off;
+ new_automops->etype = amp->etype;
+ new_automops->proto = amp->proto;
+ for (i=0; i<6; i++) {
+ new_automops->da[i] = amp->da[i]; // dst mac
+ new_automops->sa[i] = amp->sa[i]; // src mac
+ }
+ new_automops->DA = amp->DA; // dst IP
+ new_automops->SA = amp->SA; // src IP
+ new_automops->dp = amp->dp; // dst port
+ new_automops->sp = amp->sp; // src port
+ new_automops->defined_externally = amp->defined_externally;
+ new_automops->payload_type = amp->payload_type;
+ if (amp->payload_s) {
+ new_automops->payload = (char*) malloc(amp->payload_s);
+ if (new_automops->payload==NULL) {
+ fprintf(stderr, "MZ alert: cannot create new automops payload element - memory full?\n");
+ return NULL; // memory full?
+ }
+ memcpy((void*) new_automops->payload, amp->payload, amp->payload_s);
+ }
+
+ new_automops->used = amp->used;
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////
+ //
+ // Copy the fields list
+ //
+ new_automops->field = NULL;
+ for (f=amp->field; f!=NULL; f=f->next) {
+ g = (struct fields *) malloc(sizeof(struct fields));
+ if (g==NULL) {
+ fprintf(stderr, "MZ alert: cannot create new field element - memory full?\n");
+ return NULL; // memory full?
+ }
+ if (new_automops->field==NULL) { // first element
+ new_automops->field = g;
+ h = g;
+ } else { // next elements
+ h->next = g;
+ h = g;
+ }
+ // copy all data. From here on 'h' is the new one, 'f' is the existing one
+ mz_strncpy(h->name, f->name, AUTOMOPS_MAX_NAME_LEN);
+ mz_strncpy(h->shortdesc, f->shortdesc, AUTOMOPS_MAX_SHORTDESC_LEN);
+ mz_strncpy(h->valname, f->valname, AUTOMOPS_MAX_NAME_LEN);
+ if (f->longdesc!=NULL) {
+ h->longdesc = (char*)
+ malloc(strnlen(f->longdesc, 1600)); // 80 chars x 20 lines should be enough
+ if (h->longdesc == NULL) {
+ fprintf(stderr, "MZ alert: cannot allocate memory!\n");
+ return NULL; // memory full?
+ }
+ strncpy(h->longdesc, f->longdesc, 1600);
+ }
+ if (f->str_s) {
+ h->str_s = f->str_s;
+ h->str = (u_int8_t *) malloc(f->str_s);
+ if (h->str == NULL) {
+ fprintf(stderr, "MZ alert: cannot allocate memory!\n");
+ return NULL; // memory full?
+ }
+ memcpy((void*) h->str, (void*) f->str, f->str_s);
+ }
+ h->constant = f->constant;
+ h->type = f->type;
+ h->tlv_type = f->tlv_type;
+ h->tlv_len = f->tlv_len;
+ h->val = f->val;
+ h->min = f->min;
+ h->max = f->max;
+ h->leftshift = f->leftshift;
+ h->index = f->index;
+ }
+ return new_automops;
+}
+
+
+// Add a new field object
+struct fields * automops_add_field (struct automops *amp)
+{
+ struct fields *f, *f_prev=NULL, *g;
+ int i=0;
+
+ // jump to the end of the fields list
+ f=amp->field;
+ while (f!=NULL) {
+ f_prev=f;
+ ++i;
+ f=f->next;
+ }
+
+ g = (struct fields *) malloc(sizeof(struct fields));
+ if (g==NULL) {
+ if (verbose) fprintf(stderr, "MZ alert: cannot create new field element - memory full?\n");
+ return NULL; // memory full?
+ }
+
+ if (amp->field==NULL) { // is is first element in amp
+ amp->field = g;
+ } else { // it is just another element in the fields list
+ f_prev->next = g;
+ }
+ g->next=NULL; // 'pointing to NULL' identifies the last element
+ g->i=i; // each field element has a unique internal number
+ g->index=0; // indicates 'empty' field
+ automops_field_set_defaults(g);
+ return g;
+}
+
+
+// Typically only used by automops_add_field()
+// Only call this function after creating a new field element
+void automops_field_set_defaults(struct fields *f)
+{
+ f->name[0]=0x00;
+ f->shortdesc[0]=0x00;
+ f->longdesc=NULL;
+ f->constant=0;
+
+ //NOTE: f->i MUST NOT be reset!
+ f->index=0;
+ f->valname[0]=0x00;
+ f->tlv_type=0;
+ f->tlv_len=0;
+ f->val=0;
+ f->min=0;
+ f->max=0;
+ f->leftshift=0;
+ f->str=NULL;
+ f->str_s=0;
+ f->next=NULL;
+}
+
+
+// Returns integer equivalent for a string of basic protocols.
+// For example returns MOPS_ETH | MOPS_IP for d="eth ip".
+// See the definitions in mops.h.
+//
+// NOTE: Does (and must) NOT verify whether items are conflicting
+// such as "udp tcp". This task MUST be done by callee, otherwise
+// this function's purpose would be not generic enough.
+//
+// RETURN VALUE:
+// The sum of basic protocols
+// or -1 upon failure.
+int mops_str2layers(char *d)
+{
+ int ret=0;
+ char *tok;
+
+ // dissalow too long strings.
+ if (strlen(d)>50) return -1; // TODO: replace 100 to a more reasonable value
+
+ tok=strtok(d, " ");
+ while (tok!=NULL) {
+ if (strncasecmp("eth", d, 10)==0) ret |= MOPS_ETH;
+ else
+ if (strncasecmp("snap", d, 10)==0) ret |= MOPS_SNAP;
+ else
+ if (strncasecmp("dot1q", d, 10)==0) ret |= MOPS_dot1Q;
+ else
+ if (strncasecmp("mpls", d, 10)==0) ret |= MOPS_MPLS;
+ else
+ if (strncasecmp("ip", d, 10)==0) ret |= MOPS_IP;
+ else
+ if (strncasecmp("udp", d, 10)==0) ret |= MOPS_UDP;
+ else
+ if (strncasecmp("tcp", d, 10)==0) ret |= MOPS_TCP;
+ else
+ return -1; // unknown
+ tok=strtok(NULL, " ");
+ }
+ return ret;
+}
+
+// Returns one of 'enum fieldtypes' for a given ascii string
+// or -1 if unknown field type given.
+int amp_str2type(char *d)
+{
+ if (strncasecmp("byte8", d, 10)==0) return Byte8;
+ if (strncasecmp("byte16", d, 10)==0) return Byte16;
+ if (strncasecmp("byte32", d, 10)==0) return Byte32;
+ if (strncasecmp("flaginbyte", d, 16)==0) return Flag_in_Byte;
+ if (strncasecmp("multibytes", d, 16)==0) return MultiBytes;
+ if (strncasecmp("multibyteshex", d, 16)==0) return MultiBytesHex;
+ if (strncasecmp("tlv", d, 10)==0) return TLV;
+ return -1;
+}
+
+// Converts integer field types into ascii string s[32].
+// Returns 0 upon success, 1 if unknown type
+int amp_type2str(int t, char *s)
+{
+ switch (t) {
+ case Byte8:
+ mz_strncpy(s, "Byte8", 32);
+ break;
+ case Byte16:
+ mz_strncpy(s, "Byte16", 32);
+ break;
+ case Byte32:
+ mz_strncpy(s, "Byte32", 32);
+ break;
+ case Flag_in_Byte:
+ mz_strncpy(s, "FlagInByte", 32);
+ break;
+ case MultiBytes:
+ mz_strncpy(s, "MultiBytes", 32);
+ break;
+ case MultiBytesHex:
+ mz_strncpy(s, "MultiBytesHex", 32);
+ break;
+ case TLV:
+ mz_strncpy(s, "TLV", 32);
+ break;
+ default:
+ mz_strncpy(s, "[unknown/same]", 32);
+ return 1;
+ }
+ return 0;
+}
+
+
+// Searches the automops object with specified name 'd'.
+// NOTE: The names are case insensitive!
+//
+// RETURN VALUE: pointer to that object
+// or NULL if not found
+//
+struct automops * amp_getamp_byname(struct automops *head, char *d)
+{
+ struct automops *a;
+ a = head;
+ do {
+ if (strncasecmp(a->name, d, AUTOMOPS_MAX_NAME_LEN)==0) return a;
+ a=a->next;
+ } while (a!=head);
+ return NULL; // not found
+}
+
+
+// Add data 'd' identified by tag 'xntag' to the automops entry 'amp'.
+//
+// RETURN VALUE: 0 upon success, 1 upon failure
+//
+int amp_add_pentry (struct automops *amp, int xntag, char *d)
+{
+ int i=0;
+ char *tok;
+ u_int8_t x[MAX_MOPS_MSG_SIZE];
+ struct automops *g;
+
+ switch (xntag) {
+ case xml_name:
+ if (strpbrk(d," \t")!=NULL) return ampInvalidName; // name must not consist of multiple words!
+ g = amp_getamp_byname(amp_head, d);
+ if (g!=NULL) return ampDuplicateName; // name already exists!
+ mz_strncpy(amp->name, d, AUTOMOPS_MAX_NAME_LEN);
+ if (verbose==2) {
+ fprintf(stderr, "Adding protocol '%s'\n", amp->name);
+ }
+ break;
+
+ case xml_desc:
+ mz_strncpy(amp->desc, d, AUTOMOPS_MAX_SHORTDESC_LEN);
+ break;
+
+ case xml_requires:
+ i = mops_str2layers(d);
+ if (i==-1) return ampInvalidLayer;
+ if ((i&MOPS_UDP) && (i&MOPS_TCP)) return ampTCPandUDP; // cannot require both!
+ amp->layers_on |= i; // must be ORed because several same-tags allowed
+ break;
+
+ case xml_conflicts:
+ i = mops_str2layers(d);
+ if (i==-1) return ampInvalidLayer;
+ amp->layers_off |= i; // must be ORed because several same-tags allowed
+ break;
+
+ case xml_payloadtype: // 0=none, 1=ascii, 2=hex, 3=any
+ tok = strtok (d," ");
+ while (tok!=NULL) {
+ if (strncasecmp("allowed", d, 10)==0) {
+ // only change if payload_type is still zero
+ if (amp->payload_type==0) amp->payload_type=3;
+ } else
+ if (strncasecmp("ascii", d, 10)==0) amp->payload_type|=1;
+ else
+ if (strncasecmp("hex", d, 10)==0) amp->payload_type|=2;
+ else
+ if (strncasecmp("any", d, 10)==0) amp->payload_type=3;
+ else
+ if (strncasecmp("none", d, 10)==0) amp->payload_type=0;
+ else return ampPayloadType; // unknown
+ tok=strtok(NULL, " ");
+ }
+ break;
+
+ case xml_payload:
+ i=strnlen(d,MAX_MOPS_MSG_SIZE);
+ if (i==MAX_MOPS_MSG_SIZE) return ampPayloadLen;
+ amp->payload = (char*) malloc (i+1);
+ mz_strncpy(amp->payload, d, i+1);
+ amp->payload_s = i;
+ break;
+
+ case xml_payloadhex:
+ i=str2hex(d,x,MAX_MOPS_MSG_SIZE);
+ if (i==MAX_MOPS_MSG_SIZE) return ampPayloadLen;
+ if (i==-1) return 1;
+ amp->payload = (char*) malloc (i+1);
+ memcpy((void*)amp->payload, (void*) x, i);
+ amp->payload_s = i;
+ break;
+
+ default:
+ return ampUnknownTag;
+
+ }
+ return 0;
+}
+
+// Checks if given index value would be valid for the specified amp.
+// (Index values must increase monotonic, successive same-values are
+// allowed, step size is 0 or 1 but not greater. First index value
+// must be 1. Example: 1,2,2,2,3,4,5,5,5,5,5,6,7,7,7.)
+//
+// RETURN VALUE: 0 if ok, 1 if wrong
+//
+int amp_checkindex(struct automops *amp, int i)
+{
+ int last_i=0;
+ struct fields *g, *h=NULL;
+
+ g=amp->field;
+ while (g!=NULL) { // jump to last field object P->F1->F2->NULL
+ if (g->index==0) break; // stop if empty field object found
+ h=g;
+ g=g->next;
+ } // now h is the penultimate object
+// printf("CHECKINDEX: try for %i, amp='%s' -- field '%s', index %i, [%i]\n",
+// i, amp->name, h->name, h->index, h->i);
+ if (h==NULL) return 0; // first element, so any i is ok
+ last_i=h->index;
+ if (i<last_i) return 1; // index is decreasing!
+ if ((i-last_i)>1) return 1; // index increase step larger 1!
+ return 0;
+}
+
+
+
+// Searches the field object with specified name 'd'.
+// NOTE: The names ar case insensitive!
+//
+// RETURN VALUE: pointer to that object
+// or NULL if not found
+//
+struct fields * amp_getfield_byname(struct automops *amp, char *d)
+{
+ struct fields *f;
+
+ f = amp->field;
+
+ while (f!=NULL) {
+ if (strncasecmp(f->name, d, AUTOMOPS_MAX_NAME_LEN)==0) return f;
+ f=f->next;
+ }
+ return NULL; // not found
+}
+
+
+
+// This strange function ensures that 'w' consists of a single word.
+// If 'w' consists of multiple words, it removes all but the first
+// word. Additionally surrounding spaces are removed.
+//
+// RETURN VALUE: number of words found
+//
+// EXAMPLE: "Hello world" => "Hello"
+// (return value = 2)
+//
+int ensure_single_word(char *w)
+{
+ char *t, *t0;
+ int i=0;
+
+ t=strtok(w," ");
+ t0=t;
+ while (t!=NULL) {
+ i++;
+ t=strtok(NULL, " ");
+ }
+ mz_strncpy(w, t0, AUTOMOPS_MAX_NAME_LEN);
+ return i;
+}
+
+
+
+
+// Add data 'd' identified by tag 'xntag' to the field entry 'f'
+int amp_add_fentry (struct automops *amp, struct fields *f, int xntag, char *d)
+{
+ int i=0;
+ unsigned long long int ulli=0;
+ struct fields *g=NULL;
+
+ switch(xntag) {
+ case xml_index:
+ i = (int) str2int(d);
+ if (amp_checkindex(amp, i)) return ampInvalidIndex; // invalid index
+ f->index = (int) i;
+ break;
+
+ case xml_name:
+ if (ensure_single_word(d)>1) return ampInvalidName; // name must be single word
+ g = amp_getfield_byname(amp, d);
+ if (g!=NULL) return 1; // name already exists
+ mz_strncpy(f->name, d, AUTOMOPS_MAX_NAME_LEN);
+ break;
+
+ case xml_desc:
+ mz_strncpy(f->shortdesc, d, AUTOMOPS_MAX_SHORTDESC_LEN);
+ break;
+
+ case xml_longdesc:
+ i = strnlen(d, 400);
+ if (i==400) return ampDescTooLong;
+ f->longdesc = (char*) malloc(i+1);
+ mz_strncpy(f->longdesc, d, i+1);
+ break;
+
+ case xml_type:
+ i = amp_str2type(d);
+ if (i==-1) return ampInvalidType;
+ f->type = i;
+ break;
+
+ case xml_constant:
+ if (strncasecmp(d, "yes", 6)==0) f->constant=1;
+ else
+ if (strncasecmp(d, "no", 6)==0) f->constant=0;
+ else return ampUnknownKeyword; // unknown keyword
+ break;
+
+ case xml_valname:
+ if (ensure_single_word(d)>1) return ampSingleWordRequired; // name must be single word
+ i = strnlen(d, AUTOMOPS_MAX_NAME_LEN);
+ if (i==AUTOMOPS_MAX_NAME_LEN) return 1; // too long
+ mz_strncpy(f->valname, d, AUTOMOPS_MAX_NAME_LEN);
+ break;
+
+ case xml_value:
+ ulli = str2lint(d);
+ if (ulli>0xffffffff) return ampRangeError;
+ f->val = (u_int32_t) ulli;
+ break;
+
+ case xml_min:
+ ulli = str2lint(d);
+ if (ulli>0xffffffff) return ampRangeError;
+ f->min = (u_int32_t) ulli;
+ break;
+
+ case xml_max:
+ ulli = str2lint(d);
+ if (ulli>0xffffffff) return ampRangeError;
+ if (ulli<f->min) return 1; // max must be greater or equal min
+ f->max = (u_int32_t) ulli;
+ break;
+
+ case xml_tlvt:
+ ulli = str2lint(d);
+ if (ulli>0xffffffff) return ampRangeError;
+ f->tlv_type = (u_int32_t) ulli;
+ break;
+
+ case xml_tlvl:
+ ulli = str2lint(d);
+ if (ulli>0xffffffff) return ampRangeError;
+ f->tlv_len = (u_int32_t) ulli;
+ break;
+
+ case xml_lshift:
+ i = (int) str2int(d);
+ if (i>7) return ampRangeError;
+ f->leftshift=i;
+ break;
+
+ default:
+ return ampUnknownTag; // unknown tag
+ }
+ return 0;
+}
+
+
+// Delete linked list of field elements for a given automops
+// Returns the number of deleted elements
+int automops_delete_fields (struct automops *amp)
+{
+ struct fields * cur = amp->field;
+ struct fields * tmp;
+ int i=0;
+
+ if (cur==NULL) return 0;
+
+ do {
+ tmp = cur;
+ cur = cur->next;
+ if (tmp->str_s) {
+ if (tmp->str!=NULL) {
+ free (tmp->str);
+ tmp->str=NULL;
+ }
+ }
+ if (tmp->longdesc!=NULL) {
+ free(tmp->longdesc);
+ tmp->longdesc=NULL;
+ }
+ if (tmp!=NULL) {
+ free(tmp);
+ tmp=NULL;
+ }
+ i++;
+ } while (cur!=NULL);
+
+ return i;
+}
+
+
+
+// Deletes all elements except the specified element which us usually
+// the head element. Also 'used' elements will be removed!
+//
+void automops_delete_all (struct automops *list)
+{
+ struct automops *head = list;
+ struct automops *cur = list->next;
+ struct automops *tmp;
+
+ // Delete all but head element:
+ while (head != cur)
+ {
+ tmp = cur->next;
+ if (verbose) {
+ fprintf(stderr, " Deleting '%s'\n",cur->name);
+ }
+ automops_delete_protocol(cur);
+ cur = tmp;
+ }
+ head->next = head;
+ head->prev = head;
+
+ if (verbose) {
+ fprintf(stderr, " Deleting '%s'\n",head->name);
+ }
+
+ if (head->payload_s) {
+ if (head->payload!=NULL) {
+ free (head->payload);
+ head->payload=NULL;
+ }
+ }
+ automops_set_defaults(head);
+}
+
+
+// Completely clean up.
+// After that, there is no automops list anymore.
+// You only need this function when stopping mausezahn.
+//
+void automops_cleanup (struct automops *list)
+{
+ // 1) delete all elements except head:
+ automops_delete_all(list);
+
+ // 2) delete head:
+ automops_delete_fields (list);
+ if (list->payload_s) {
+ if (list->payload!=NULL) {
+ free (list->payload);
+ list->payload=NULL;
+ }
+ }
+ if (list!=NULL) {
+ free(list);
+ list=NULL;
+ }
+}
+
+// Converts amperr error values in 'e' to string messages 's'
+// which must be at least 64 bytes in size.
+//
+// RETURN VALUE: 0 if convertable, 1 else
+//
+int amperr2str (int e, char *s)
+{
+ switch (e) {
+
+ case ampSuccess:
+ break;
+ case ampInvalidIndex:
+ mz_strncpy(s, "invalid index", 64);
+ break;
+ case ampInvalidName:
+ mz_strncpy(s, "invalid name", 64);
+ break;
+
+ case ampDuplicateName:
+ mz_strncpy(s, "duplicate name", 64);
+ break;
+
+ case ampDescTooLong:
+ mz_strncpy(s, "description too long", 64);
+ break;
+
+ case ampInvalidLayer:
+ mz_strncpy(s, "invalid layer", 64);
+ break;
+
+ case ampTCPandUDP:
+ mz_strncpy(s, "either TCP or UDP", 64);
+ break;
+
+
+ case ampInvalidType:
+ mz_strncpy(s, "invalid type", 64);
+ break;
+
+ case ampUnknownKeyword:
+ mz_strncpy(s, "unknown keyword", 64);
+ break;
+
+ case ampSingleWordRequired:
+ mz_strncpy(s, "single word required", 64);
+ break;
+
+ case ampRangeError:
+ mz_strncpy(s, "invalid range", 64);
+ break;
+
+ case ampPayloadType:
+ mz_strncpy(s, "invalid payload type", 64);
+ break;
+
+ case ampPayloadLen:
+ mz_strncpy(s, "payload length exceeded", 64);
+ break;
+
+
+ case ampUnknownTag:
+ mz_strncpy(s, "unknown tag (check mausezahn version?)", 64);
+ break;
+
+ default:
+ mz_strncpy(s, "completely unknown cause", 64);
+ return 1;
+ }
+ return 0;
+}
+
+
+
+
+// Open amp file (containing XML data describing one or more protocols for automops)
+// and copy the data into a char array.
+//
+// NOTE that the char array must be free'd by the caller.
+//
+// RETURN VALUE: - pointer to char array with the XML data
+// - NULL upon failure
+//
+char * mapfile (char *fn)
+{
+ int i, c;
+ long fn_s;
+ FILE *fd;
+ char *blob;
+
+ fd = fopen (fn, "r");
+ if (fd==NULL) return NULL;
+
+ // Determine length of file
+ (void) fseek(fd, 0L, SEEK_END);
+ fn_s = ftell(fd);
+ if (fn_s > AUTOMOPS_MAX_FILE_SIZE) {
+ fprintf(stderr, " File '%s' exceeds max allowed length (%lu>%i)\n",
+ fn, fn_s, AUTOMOPS_MAX_FILE_SIZE);
+ fclose(fd);
+ return NULL;
+ }
+ if (verbose) fprintf(stderr, " Parsing %lu bytes from '%s'...\n", fn_s, fn);
+ rewind(fd);
+
+ blob = (char*) malloc(fn_s+1);
+ if (blob==NULL) {
+ fclose(fd);
+ return NULL;
+ }
+
+ i=0;
+ while ((c=fgetc(fd)) != EOF) {
+ blob[i]=(char) c;
+ i++;
+ if (i>fn_s) {
+ fprintf(stderr, " WARNING: parsing '%s' exceeded EOF\n", fn);
+ break; // should not reach here
+ }
+ }
+ fclose(fd);
+ blob[i]='\0';
+ return blob;
+}
+
+
+
+// Create automops PDU within *mp based on data in *amp
+//
+int automops_update (struct mops *mp, struct automops *amp)
+{
+
+ return 0;
+}
+
diff --git a/staging/cdp.c b/staging/cdp.c
new file mode 100644
index 0000000..d198d96
--- /dev/null
+++ b/staging/cdp.c
@@ -0,0 +1,769 @@
+/*
+ * Mausezahn - A fast versatile traffic generator
+ * Copyright (C) 2008 Herbert Haas
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
+ *
+*/
+
+/////////////////////////////////////////////////////////////////////
+//
+// Send CDP packets
+//
+/////////////////////////////////////////////////////////////////////
+
+
+#include "mz.h"
+#include "cli.h"
+
+
+#define MZ_CDP_HELP \
+ "| CDP type: Send arbitrary CDP packets.\n" \
+ "| Note:\n" \
+ "| - The Ethernet dst and src MAC addresses can be specified but can be also 'rand'.\n" \
+ "| - If dst and src are NOT specified then practical defaults are used (src=own MAC, dst=01:00:0C:CC:CC:CC).\n" \
+ "|\n" \
+ "| ARGUMENT SYNTAX: -t cdp [arguments]\n" \
+ "|\n" \
+ "| ARGUMENTS:\n" \
+ "|\n" \
+ "| version ...... 0-255, default: 2\n" \
+ "| ttl ...... 0-255, default: 180 s\n" \
+ "| sum ...... 0000-ffff, default: automatically computed\n" \
+ "|\n" \
+ "| TLVs: Description: Example:\n" \
+ "|\n" \
+ "| tlv_id ....... Device ID Mausezahn station\n" \
+ "| tlv_address ....... Sending interface address 10.1.1.2\n" \
+ "| tlv_portid ....... Port Identifier 2/23\n" \
+ "| tlv_cap ....... Capabilities (hex<7f) 2a\n" \
+ "| tlv_version ....... Software Version ver3.0\n" \
+ "| tlv_platform ....... Hardware Platform WS-C6509-E\n" \
+ "| tlv_vtpdomain ....... VTP Management Domain MyVTPdomain\n" \
+ "| tlv_native ....... Native VLAN number (0-4095) 42\n" \
+ "| tlv_duplex ....... Full or half duplex full\n" \
+ "| tlv_mgmt ....... Management IP address 192.168.1.2\n" \
+ "|\n" \
+ "| tlv .......... Create ANY TLV using the format: tlv=<type>/<value>, such as tlv=42/mausezahn\n" \
+ "| Note: Currently you must omit spaces within <value>! Use underscore instead.\n" \
+ "| tlvhex .......... Create ANY TLV and specify the value in hexformat, such as tlv=42/ca:fe:ba:be\n" \
+ "| payload|p .......... Optional additional TLVs or any other bytes specified in hex\n" \
+ "|\n" \
+ "| When the tlv* arguments are used, the TLV length parameter is automatically set.\n" \
+ "|\n" \
+ "| The capability flags from MSB to LSB are:\n" \
+ "| 0 - Repeater - IGMP - Host - Switch - SrcRouteBrdg - TranspBrdg - Router\n" \
+ "|\n" \
+ "| Optionally the keyword 'change' will create a different System name TLV every time a CDP\n" \
+ "| packet is sent. This can be used to fill up a CDP database with different test values.\n" \
+ "| Additionally use the '-a rand' command to use different source MAC addresses.\n" \
+ "|\n" \
+ "| EXAMPLES:\n" \
+ "|\n" \
+ "| Announce Device ID 'Espresso3000', Capabilities: Router, native VLAN 301:\n" \
+ "| mz eth0 -t cdp \"tlv_id=Espresso3000, tlv_cap=01, tlv_native=301\"\n" \
+ "|\n" \
+ "| Create another TLV using the payload interface (here voice VLAN 400):\n" \
+ "| mz eth0 -t cdp p=00:0e:00:07:01:01:90\n"
+
+
+
+
+
+u_int16_t checksum16 (u_int16_t len, u_int8_t buff[])
+{
+
+ u_int16_t word16;
+ u_int32_t sum=0;
+ u_int16_t i;
+
+ // make 16 bit words out of every two adjacent 8 bit words in the packet and add them up
+ for (i=0; i<len; i=i+2)
+ {
+ word16 =((buff[i]<<8)&0xFF00)+(buff[i+1]&0xFF);
+ sum = sum + (u_int32_t) word16;
+ }
+
+ // take only 16 bits out of the 32 bit sum and add up the carries
+ while (sum>>16)
+ sum = (sum & 0xFFFF)+(sum >> 16);
+
+ // one's complement the result
+ sum = ~sum;
+
+ return ((u_int16_t) sum);
+}
+
+
+// Creates a TLV and returns the whole length of the TLV
+unsigned int create_tlv (u_int16_t type, // The 16-bit TYPE number
+ u_int8_t *value, // The VALUE as prepared hex-array
+ unsigned int value_len, // needed because VALUE maybe not \0 terminated
+ u_int8_t *target) // the RESULT i. e. the complete TLV
+{
+ unsigned int tlvlen;
+ u_int8_t *x;
+
+ x = (u_int8_t*) &type; // set TYPE
+ target[0] = *(x+1);
+ target[1] = *(x);
+
+ tlvlen = value_len + 4; // set VALUE
+ x = (u_int8_t*) &tlvlen;
+ target[2] = *(x+1);
+ target[3] = *(x);
+
+ target+=4;
+ memcpy((void*) target, (void*) value, (size_t) value_len);
+
+ return tlvlen;
+}
+
+
+
+
+// NOTE: The Length field indicates the total length, in bytes, of the type, length, and value fields!
+//
+// Interesting TLVs:
+//
+// TYPE VALUE
+// 0001 Device-ID
+// 0002 IP Addresses
+// 0003 Port ID such as 2/22
+// 0004 Capabilities (Len=8, consists of flags only: Router, TBrdg, SRBrdgm, Switch, Host, IGMP, Repeater)
+// 0005 SW Version
+// 0006 Platform
+// 0009 VTP Domain
+// 000a Native VLAN, e.g. 00:0a 00:06 01:2d identifies native VLAN number 301 (=01:2d)
+// 000b Duplex
+// 000e VoIP VLAN, e.g. 00:0e 00:07 01 01:90 identifies DATA (=01) and VLAN 400 (=01:90)
+// 0012 Trust Bitmap
+// 0013 Untrusted Port CoS
+// 0014 System Name (!!!)
+// 0015 System Object Identifier
+// 0016 Management Address (!!!), e.g. 0016 0011(=len 17) 00-00-00-01(=one IP only) 01-01-cc-00-04-90-fe-f8-10(=144.254.248.16)
+// 0017 Location
+// 001a Unknown (???)
+//
+// The IP address format is a bit strange as 0016 for example demonstrates...
+
+
+
+int send_cdp ()
+{
+ libnet_t *l;
+ libnet_ptag_t t;
+ char
+ errbuf[LIBNET_ERRBUF_SIZE],
+ argval[1024];
+
+ u_int8_t
+ packet[MAX_PAYLOAD_SIZE], // this one will finally contain the whole cdp packet (without LLC/SNAP!)
+ *x,
+ value[1024], // USE THIS FOR ANYTHING YOU LIKE !!!
+ value1[1024], // This one is reserved for some code - Don't use it again!
+ value2[1024], // This one is reserved for some code - Don't use it again!
+ tlv[1024],
+ default_id[15] = "Mausezahn rules",
+ llcsnap[8]=
+ {
+ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x0c, 0x20, 0x00
+ };
+
+ unsigned int
+ len=0,
+ len1=0,
+ len2=0,
+ type1,
+ type2;
+
+ u_int16_t
+ dummy16=0,
+ tlv_len=0;
+
+ u_int32_t
+ next_pbyte=0, // points to the next free byte in tx.cdp_payload
+ dummy32=0,
+ packet_s;
+
+ char
+ pld[2048];
+
+
+ unsigned int i=0, count, delay;
+ int
+ eth_src_rand=0,
+ change_value=0;
+ long int j=0;
+
+
+ if (tx.dot1Q)
+ {
+ fprintf(stderr," Note: CDP mode does not support 802.1Q builder.\n");
+ exit(1);
+ }
+
+ if (tx.mpls)
+ {
+ fprintf(stderr," Note: CDP mode does not support MPLS builder.\n");
+ exit(1);
+ }
+
+
+ if (getarg(tx.arg_string,"help", NULL)==1)
+ {
+ if (mz_port)
+ {
+ cli_print(gcli, "%s", MZ_CDP_HELP);
+ return -1;
+ }
+ else
+ {
+ fprintf(stderr,"\n"
+ MAUSEZAHN_VERSION
+ "\n%s", MZ_CDP_HELP);
+ exit(0);
+ }
+
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+ // initial defaults:
+ if (tx.cdp_ttl==0) tx.cdp_ttl=0xb4; // 180 seconds
+
+ if (tx.cdp_version==0) tx.cdp_version = 0x02;
+
+ // The ID is the only required TLV
+ // If another function already specified it then it must also set the lenght:
+ if (tx.cdp_tlv_id_len==0) // not set
+ {
+ memcpy((void*) tx.cdp_tlv_id, (void*) default_id, 15);
+ tx.cdp_tlv_id_len=15;
+ }
+
+
+
+
+ ///////////////////////////////////////////////////////////////////////
+ //
+ // Now check for user arguments:
+
+
+ if ( (getarg(tx.arg_string,"version", argval)==1) || (getarg(tx.arg_string,"ver", argval)==1) )
+ {
+ if (str2int(argval)>255)
+ {
+ fprintf(stderr," mz/send_cdp: version range exceeded, adjusted to max value.\n");
+ tx.cdp_version = 0xff;
+ }
+ else
+ {
+ tx.cdp_version = (u_int8_t) str2int(argval);
+ }
+ }
+
+
+ if (getarg(tx.arg_string,"ttl", argval)==1)
+ {
+ if (str2int(argval)>255)
+ {
+ fprintf(stderr," mz/send_cdp: TTL range exceeded, adjusted to max value.\n");
+ tx.cdp_ttl = 0xff;
+ }
+ else
+ {
+ tx.cdp_ttl = (u_int8_t) str2int(argval);
+ }
+ }
+
+ if (getarg(tx.arg_string,"sum", argval)==1)
+ {
+
+ if (strtol(argval,NULL,16)>65535)
+ {
+ fprintf(stderr," mz/send_cdp: checksum range exceeded, adjusted to max value.\n");
+ tx.cdp_sum = 0xffff;
+ }
+ else
+ {
+ tx.cdp_sum = (u_int16_t) strtol(argval,NULL,16);
+ }
+ }
+
+ ////////
+ //
+ // Provide a basic interface for the most important TLVs:
+ //
+
+ if (getarg(tx.arg_string,"tlv_id", argval)==1)
+ {
+ // simply overwrite current content in tx.cdp_tlv_id
+ tx.cdp_tlv_id[0] = '\0';
+ strncpy((char*) tx.cdp_tlv_id, argval,2048);
+ tx.cdp_tlv_id_len = strlen ((char*)tx.cdp_tlv_id);
+ }
+
+
+ //
+ // This is something ugly ;-)
+ //
+
+ if (getarg(tx.arg_string,"change", NULL)==1)
+ {
+ memcpy((void*) tx.cdp_tlv_id, (void*) "Mausezahn 00000000000", 21);
+ tx.cdp_tlv_id_len=21;
+ change_value = 1;
+ }
+
+
+ //
+ // NOW write the ID-TLV; this is the only REQUIRED TLV !!!
+ // and this TLV should be the FIRST one - that's why we
+ // write it immediately here now:
+ //
+ tlv_len = create_tlv (1, tx.cdp_tlv_id, tx.cdp_tlv_id_len, tlv);
+ memcpy((void*) tx.cdp_payload+next_pbyte, (void*) tlv, tlv_len);
+ next_pbyte += tlv_len;
+
+ //
+ // Now the other TLVs may follow:
+ //
+
+ // Format: Type=2, Len=17, NrOfAddr=00:00:00:01, Protocol=01:01:cc:00, AddrLen=4, IP_Address
+ // Example: tlv_address = 192.168.1.10
+ // Note: currently only one address supported
+ if (getarg(tx.arg_string,"tlv_address", argval)==1)
+ {
+ dummy32 = str2ip32 (argval);
+ x = (u_int8_t*) &dummy32;
+ value[0] = 0x00; // NrOfAddr
+ value[1] = 0x00;
+ value[2] = 0x00;
+ value[3] = 0x01;
+
+ value[4] = 0x01; // Protocol
+ value[5] = 0x01;
+ value[6] = 0xcc;
+ value[7] = 0x00;
+
+ value[8] = 0x04; // AddrLen
+
+ value[9] = *(x+3);
+ value[10] = *(x+2);
+ value[11] = *(x+1);
+ value[12] = *(x);
+
+ tlv_len = create_tlv (2, value, 13, tlv);
+ memcpy((void*) tx.cdp_payload+next_pbyte, (void*) tlv, tlv_len);
+ next_pbyte += tlv_len;
+ }
+
+
+
+ // Format: Type=3
+ // Example: tlv_portid = 2/23
+ // Note:
+ if (getarg(tx.arg_string,"tlv_portid", argval)==1)
+ {
+ tlv_len = create_tlv (3, (u_int8_t*) argval, strlen(argval), tlv);
+ memcpy((void*) tx.cdp_payload+next_pbyte, (void*) tlv, tlv_len);
+ next_pbyte += tlv_len;
+ }
+
+ // Format: Type=4
+ // Example: "tlv_cap = 2a" (= 0010 1010)
+ // Flags: MSB=0 - Repeater - IGMP - Host - Switch - SrcRouteBrdg - TranspBrdg - Router(LSB)
+ if (getarg(tx.arg_string,"tlv_cap", argval)==1)
+ {
+ if (strlen(argval)>2)
+ {
+ fprintf(stderr," mz/send_cdp: Capability value must be specified as a two-digit hexadecimal value!\n");
+ exit(1);
+ }
+ else
+ {
+ str2hex(argval, value+3, 1020);
+ if (value[3]>0x7f)
+ {
+ fprintf(stderr," mz/send_cdp: Capability value must not exceed 7F(hex)\n");
+ exit(1);
+ }
+ }
+
+ value[0]=0x00;
+ value[1]=0x00;
+ value[2]=0x00;
+ tlv_len = create_tlv (4, value, 4, tlv);
+ memcpy((void*) tx.cdp_payload+next_pbyte, (void*) tlv, tlv_len);
+ next_pbyte += tlv_len;
+ }
+
+
+ // Format: Type=5
+ // Example: tlv_version = Mausezahn_version_xyz
+ // Note: Avoid spaces, use underscore instead
+ if (getarg(tx.arg_string,"tlv_version", argval)==1)
+ {
+ tlv_len = create_tlv (5, (u_int8_t*) argval, strlen(argval), tlv);
+ memcpy((void*) tx.cdp_payload+next_pbyte, (void*) tlv, tlv_len);
+ next_pbyte += tlv_len;
+ }
+
+
+ // Format: Type=6
+ // Example: tlv_platform = WS-C6509-E
+ // Note:
+ if (getarg(tx.arg_string,"tlv_platform", argval)==1)
+ {
+ tlv_len = create_tlv (6, (u_int8_t*) argval, strlen(argval), tlv);
+ memcpy((void*) tx.cdp_payload+next_pbyte, (void*) tlv, tlv_len);
+ next_pbyte += tlv_len;
+ }
+
+ // Format: Type=9
+ // Example: tlv_vtpdomain = MyVTPdomain
+ // Note:
+ if (getarg(tx.arg_string,"tlv_vtpdomain", argval)==1)
+ {
+ tlv_len = create_tlv (9, (u_int8_t*) argval, strlen(argval), tlv);
+ memcpy((void*) tx.cdp_payload+next_pbyte, (void*) tlv, tlv_len);
+ next_pbyte += tlv_len;
+ }
+
+
+ // Format: Type=10, Len=17
+ // Example: tlv_native = 100
+ // Note:
+ if (getarg(tx.arg_string,"tlv_native", argval)==1)
+ {
+ dummy16 = (u_int16_t) str2int(argval);
+ if (dummy16>4095)
+ {
+ fprintf(stderr," mz/WARNING: native VLAN value exceeds max value (4095) - hope you know what you do!\n");
+ }
+
+ x = (u_int8_t*) &dummy16;
+ value[0] = *(x+1);
+ value[1] = *(x);
+ tlv_len = create_tlv (10, value, 2, tlv);
+ memcpy((void*) tx.cdp_payload+next_pbyte, (void*) tlv, tlv_len);
+ next_pbyte += tlv_len;
+ }
+
+ // Format: Type=11
+ // Example: tlv_duplex = full | half
+ // Note:
+ if (getarg(tx.arg_string,"tlv_duplex", argval)==1)
+ {
+ if (strncmp(argval,"full",10)==0)
+ {
+ value[0]=0x01;
+ }
+ else if (strncmp(argval,"half",10)==0)
+ {
+ value[0]=0x00;
+ }
+ else
+ {
+ value[0]=(u_int8_t) str2int(argval);
+ if (!quiet)
+ {
+ fprintf(stderr," mz/Warning: Only keywords 'half' or 'full' supported."
+ " Will interprete input as integer.\n");
+ }
+
+ }
+
+ tlv_len = create_tlv (11, value, 1, tlv);
+ memcpy((void*) tx.cdp_payload+next_pbyte, (void*) tlv, tlv_len);
+ next_pbyte += tlv_len;
+ }
+
+ // Format: Type=22, Len=17, NrOfAddr=00:00:00:01, Protocol=01:01:cc:00, AddrLen=4, IP_Address
+ // Example: tlv_mgmt = 10.1.1.99
+ // Note: Same format as tlv_address
+ if (getarg(tx.arg_string,"tlv_mgmt", argval)==1)
+ {
+ dummy32 = str2ip32 (argval);
+ x = (u_int8_t*) &dummy32;
+ value[0] = 0x00; // NrOfAddr
+ value[1] = 0x00;
+ value[2] = 0x00;
+ value[3] = 0x01;
+
+ value[4] = 0x01; // Protocol
+ value[5] = 0x01;
+ value[6] = 0xcc;
+ value[7] = 0x00;
+
+ value[8] = 0x04; // AddrLen
+
+ value[9] = *(x+3);
+ value[10] = *(x+2);
+ value[11] = *(x+1);
+ value[12] = *(x);
+
+ tlv_len = create_tlv (22, value, 13, tlv);
+ memcpy((void*) tx.cdp_payload+next_pbyte, (void*) tlv, tlv_len);
+ next_pbyte += tlv_len;
+
+ }
+
+
+
+ //
+ // Eventually there are two generic TLV interfaces: tlv and tlvhex
+ //
+
+ if (getarg(tx.arg_string,"tlv", argval)==1)
+ {
+ // split in TYPE and VALUE
+ sscanf(argval, "%u/%s", &type1, value1);
+ len1 = strlen((const char*) value1);
+
+ }
+
+ if (getarg(tx.arg_string,"tlvhex", argval)==1)
+ {
+ // split in TYPE and VALUE
+ sscanf(argval, "%u/%s", &type2, pld);
+ len2 = str2hex(pld, value2, 1023);
+ }
+
+
+ //
+ // Finally the optional payload interface allows to specify subsequent TLVs or any other bytes:
+ //
+ if ( (getarg(tx.arg_string,"payload", argval)==1) || (getarg(tx.arg_string,"p", argval)==1))
+ {
+ len = str2hex (argval, value, 1023);
+ memcpy((void*) tx.cdp_payload+next_pbyte, (void*) value, len);
+ next_pbyte += len;
+ }
+
+
+
+ ///////////////////////////////////////////////////////////////
+
+
+
+ // Write other TLVs: First the ASCII specified:
+ if (len1)
+ {
+ tlv_len = create_tlv (type1, value1, len1 , tlv);
+ memcpy((void*) tx.cdp_payload+next_pbyte, (void*) tlv, tlv_len);
+ next_pbyte += tlv_len;
+ }
+
+ // Write other TLVs: Then the HEX specified:
+ if (len2)
+ {
+ tlv_len = create_tlv (type2, value2, len2 , tlv);
+ memcpy((void*) tx.cdp_payload+next_pbyte, (void*) tlv, tlv_len);
+ next_pbyte += tlv_len;
+ }
+
+
+ tx.cdp_payload_s = next_pbyte;
+
+ // CHECK:
+ // bs2str(tx.cdp_payload, pld, tx.cdp_payload_s);
+ // printf("PAYLOAD= %s\n",pld);
+
+
+////////////////////////////
+//
+
+ // Open the link - for the intermediate CDP/LLC frame
+ l = libnet_init(LIBNET_LINK_ADV, tx.device, errbuf);
+
+ if (l == NULL)
+ {
+ fprintf(stderr, "%s", errbuf);
+ exit(EXIT_FAILURE);
+ }
+
+ if (check_eth_mac_txt(ETH_DST)) // if '1' then user did not set MAC address (or problem occurred)
+ {
+ str2hex("01:00:0C:CC:CC:CC", tx.eth_dst, 6);
+ }
+
+ if (check_eth_mac_txt(ETH_SRC)) // if '1' then user did not set MAC address (or problem occurred)
+ {
+ // own mac per default (see init.c)
+ }
+
+ count = tx.count;
+ eth_src_rand = tx.eth_src_rand;
+ delay = tx.delay;
+
+ // ---------------------------------------------------
+ // If you want to change CDP fields during a LOOP then
+ // START the loop from HERE:
+ //
+
+ ////////////////////////////////////
+ // Now create the whole CDP packet:
+
+ packet[0] = tx.cdp_version; // VERSION
+ packet[1] = tx.cdp_ttl; // TTL
+ packet[2] = 0x00; // CHECKSUM
+ packet[3] = 0x00;
+
+ // Now add the TLVs
+ memcpy ((void*) packet+4, (void*) tx.cdp_payload, tx.cdp_payload_s);
+ packet_s = tx.cdp_payload_s + 4;
+
+ // Check whether packet is an even length (i.e. is a multiple of 16 bits = 2 bytes);
+ if (packet_s%2>0)
+ {
+ packet[packet_s++]=0x00;
+ packet[packet_s++]=0x17;
+ packet[packet_s++]=0x00;
+ packet[packet_s++]=0x05;
+ packet[packet_s++]=0x00;
+ }
+
+
+ // Now update the checksum:
+ if (tx.cdp_sum == 0) // Otherwise user specified the checksum (usually a wrong one ;-))
+ {
+ tx.cdp_sum = checksum16(packet_s, packet);
+ }
+ x = (u_int8_t *) &tx.cdp_sum;
+ packet[2] = *(x+1);
+ packet[3] = *(x);
+
+ // CHECK the CDP packet
+ //bs2str(packet, pld, packet_s);
+ //printf("CDP= %s\n",pld);
+
+
+// printf("Len = %u Checksum = %04x \n", packet_s-8, tx.cdp_sum);
+
+
+ ///////////////////////////////////////////////////////////////
+ // Now create the whole tx.eth_payload = LLC/SNAP + CDP packet
+ // First the LLC/SNAP header:
+ memcpy ((void*) tx.eth_payload, (void*) llcsnap, 8);
+ memcpy ((void*) tx.eth_payload+8, (void*) packet, packet_s);
+ tx.eth_payload_s = packet_s +8;
+
+
+ // CHECK the whole 802.3 payload
+ // bs2str(tx.eth_payload, pld, tx.eth_payload_s);
+ // printf("PACKET = %s\n",pld);
+
+
+ t = libnet_build_802_3 (tx.eth_dst,
+ tx.eth_src,
+ tx.eth_payload_s,
+ tx.eth_payload,
+ tx.eth_payload_s,
+ l,
+ 0);
+
+
+
+ // this is for the statistics:
+ mz_start = clock();
+ total_d = tx.count;
+
+ if (!count) goto AGAIN;
+
+ for (i=0; i<count; i++)
+ {
+ AGAIN:
+
+ if (eth_src_rand)
+ {
+ tx.eth_src[0] = (u_int8_t) ( ((float) rand()/RAND_MAX)*256) & 0xFE; // keeps bcast-bit zero
+ tx.eth_src[1] = (u_int8_t) ( ((float) rand()/RAND_MAX)*256);
+ tx.eth_src[2] = (u_int8_t) ( ((float) rand()/RAND_MAX)*256);
+ tx.eth_src[3] = (u_int8_t) ( ((float) rand()/RAND_MAX)*256);
+ tx.eth_src[4] = (u_int8_t) ( ((float) rand()/RAND_MAX)*256);
+ tx.eth_src[5] = (u_int8_t) ( ((float) rand()/RAND_MAX)*256);
+
+ t = libnet_build_802_3 (tx.eth_dst,
+ tx.eth_src,
+ tx.eth_payload_s,
+ tx.eth_payload,
+ tx.eth_payload_s,
+ l,
+ t);
+
+ }
+
+
+ libnet_write(l);
+
+ if (verbose)
+ {
+ bs2str(tx.eth_payload+8, pld, tx.eth_payload_s-8);
+ fprintf(stderr," Sent CDP: (Ver=%u, TTL=%u) %s\n", tx.cdp_version, tx.cdp_ttl, pld);
+ }
+
+ if (delay) SLEEP (delay);
+
+ if (change_value)
+ {
+ // Note: this only works when default_id has been used
+ // because otherwise the TLV with the ID might be too short!!!
+
+ // Offset 26-36 contains 00000000000 (of the default id)
+ // ASCII 0x30-0x39 contain numbers 0-9
+
+ tx.eth_payload[26] = (u_int8_t) (0x30+ ((float) rand()/RAND_MAX)*10);
+ tx.eth_payload[27] = (u_int8_t) (0x30+ ((float) rand()/RAND_MAX)*10);
+ tx.eth_payload[28] = (u_int8_t) (0x30+ ((float) rand()/RAND_MAX)*10);
+ tx.eth_payload[29] = (u_int8_t) (0x30+ ((float) rand()/RAND_MAX)*10);
+ tx.eth_payload[30] = (u_int8_t) (0x30+ ((float) rand()/RAND_MAX)*10);
+ tx.eth_payload[31] = (u_int8_t) (0x30+ ((float) rand()/RAND_MAX)*10);
+ tx.eth_payload[32] = (u_int8_t) (0x30+ ((float) rand()/RAND_MAX)*10);
+ tx.eth_payload[33] = (u_int8_t) (0x30+ ((float) rand()/RAND_MAX)*10);
+ tx.eth_payload[34] = (u_int8_t) (0x30+ ((float) rand()/RAND_MAX)*10);
+ tx.eth_payload[35] = (u_int8_t) (0x30+ ((float) rand()/RAND_MAX)*10);
+ tx.eth_payload[36] = (u_int8_t) (0x30+ ((float) rand()/RAND_MAX)*10);
+
+ tx.eth_payload[10] = 0x00; // reset the checksum
+ tx.eth_payload[11] = 0x00;
+ tx.cdp_sum = checksum16(tx.eth_payload_s-8, tx.eth_payload+8);
+ x = (u_int8_t *) &tx.cdp_sum;
+ tx.eth_payload[10] = *(x+1);
+ tx.eth_payload[11] = *(x);
+
+ t = libnet_build_802_3 (tx.eth_dst,
+ tx.eth_src,
+ tx.eth_payload_s,
+ tx.eth_payload,
+ tx.eth_payload_s,
+ l,
+ t);
+
+ j++;
+
+ }
+
+ if (!count) goto AGAIN;
+ }
+
+
+ // Destroy contexts
+ libnet_destroy(l);
+
+
+
+ return t;
+
+
+}
diff --git a/staging/cli.c b/staging/cli.c
new file mode 100644
index 0000000..b74d688
--- /dev/null
+++ b/staging/cli.c
@@ -0,0 +1,570 @@
+/*
+ * Mausezahn - A fast versatile traffic generator
+ * Copyright (C) 2008-2010 Herbert Haas
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
+ *
+*/
+
+
+
+#include "mz.h"
+#include "cli.h"
+#include "mops.h"
+#include "llist.h"
+
+void mz_cli_init()
+{
+ amp_head = automops_init();
+
+ // Initialize default credentials (will be overwritten by mz.cfg)
+ strcpy(mz_username, MZ_DEFAULT_USERNAME);
+ strcpy(mz_password, MZ_DEFAULT_PASSWORD);
+ strcpy(mz_enable, MZ_DEFAULT_ENABLE_PASSWORD);
+
+ // read login credentials from config file
+ if (cli_read_cfg("mz.cfg")) {
+ fprintf(stderr, "mz: Problems opening config file. Will use defaults\n");
+ }
+
+ if ((verbose) && (AUTOMOPS_ENABLED)) {
+ automops_dump_all(amp_head);
+ fprintf(stderr, "------------ MOPS/CLI initialization completed ------------\n");
+ }
+}
+
+
+
+
+// Read in configuration file
+int cli_read_cfg(char *str)
+{
+ char filename[256];
+ char line[256];
+ char path[256];
+ char *ampfile;
+ char dev[256];
+ FILE *fd;
+ int i, j=0, len, found=0, nonspc=0;
+ int user=0, pass=0, ena=0, amp=0, mgmt_only=0, cli=0;
+
+ strncpy(filename, str, 255);
+
+ if (getfullpath_cfg(filename)) return 1;
+
+ if (verbose) {
+ fprintf(stderr, "Opening config file %s...\n", filename);
+ }
+
+ fd = fopen (filename, "r");
+ if (fd==NULL) return 1;
+
+ while (fgets(line, 255, fd) != NULL) {
+ len=strnlen(line, 255);
+ // Take string left side of # (comments)
+ if (len) for(i=0;i<len;i++) if (line[i]=='#') line[i]='\0'; // cut off
+ len=strnlen(line, 255);
+ if (len) for(i=0;i<len;i++) if (!isspace(line[i])) nonspc++;
+ if (nonspc==0) continue; else nonspc=0;
+ if (!user) user = sscanf(line, " user = %s ", mz_username);
+ if (!pass) pass = sscanf(line, " password = %s ", mz_password);
+ if (!ena) ena = sscanf(line, " enable = %s ", mz_enable);
+ if (!cli) cli = sscanf(line, " cli-device = %s ", dev);
+ if (cli==1) {
+ for (i=0; i<device_list_entries; i++) {
+ if (strncmp(device_list[i].dev, dev, 16)==0) {
+ device_list[i].cli=1;
+ found=1;
+ break;
+ }
+ }
+ if (!found) {
+ fprintf(stderr, " Warning: [%s] cli device '%s' does not exist!\n", filename, dev);
+ cli=0; // try again
+ }
+ found=0;
+ cli=0;
+ }
+
+ if (!mgmt_only) mgmt_only = sscanf(line, " management-only = %s ", dev);
+ if (mgmt_only==1) {
+ for (i=0; i<device_list_entries; i++) {
+ if (strncmp(device_list[i].dev, dev, 16)==0) {
+ device_list[i].mgmt_only=1;
+ found=1;
+ break;
+ }
+ }
+ if (!found) fprintf(stderr, " Warning: [%s] management device '%s' does not exist!\n", filename, dev);
+ mgmt_only=0;
+ found=0;
+ }
+
+ if (AUTOMOPS_ENABLED) {
+ // read-in all protocol definitions
+ amp = sscanf(line, " automops = %s ", path);
+ if (amp) {
+ ampfile = mapfile(path);
+ if (ampfile==NULL) fprintf(stderr, " Warning: Cannot read %s\n", path);
+ else {
+ j = 0;
+ j = parse_protocol (ampfile);
+ if (j) {
+ if (verbose) {
+ fprintf(stderr, " Warning: invalid protocol definitions in %s\n", path);
+ }
+ }
+ free(ampfile);
+ amp=0;
+ }
+ }
+ }
+ }
+ fclose(fd);
+
+ if (verbose) {
+ if (user!=1)
+ fprintf(stderr, "%s: No user name specified - will use default.\n", filename);
+
+ if (pass!=1)
+ fprintf(stderr, "%s: No password specified - will use default.\n", filename);
+
+ if (ena!=1)
+ fprintf(stderr, "%s: No enable password specified - will use default.\n", filename);
+ }
+
+ cli_debug = 0;
+ return 0;
+}
+
+
+
+
+
+///// TODO ***************************************************************
+//
+// Process "startup-config" using:
+//
+// cli_file (struct cli_def *cli, FILE *f, int privilege, int mode)
+//
+// This reads and processes every line read from f as if it were entered
+// at the console. The privilege level will be set to privilege and mode
+// set to mode during the processing of the file.
+//
+//
+// Idle timeout or watchdog or whatever:
+//
+// cli_regular (struct cli_def *cli, int(*callback)(struct cli_def *))
+//
+// Adds a callback function which will be called every second that a user
+// is connected to the cli. This can be used for regular processing such
+// as debugging, time counting or implementing idle timeouts.
+//
+// Pass NULL as the callback function to disable this at runtime.
+//
+// ************************************************************************
+
+
+int cli()
+{
+ struct sockaddr_in servaddr;
+ struct cli_command
+ *address,
+ *clear,
+ *debug,
+ *eth_frame,
+ *frame,
+ *ip_packet,
+ *ip_int,
+ *launch,
+ *mac_packet,
+ *macaddr,
+ *mac_int,
+ *pld,
+ *port,
+ *reset,
+ *run,
+ *show,
+ *tag,
+ *tcp_packet,
+ *udp_packet;
+
+ struct cli_def *cli;
+ int on = 1, x, s, cnt=0;
+ int i;
+ char TimeStamp[128];
+
+ (void) signal(SIGINT, clean_up); // to close and free everything upon SIGINT
+
+ // Must be called first to setup data structures
+ cli = cli_init();
+ gcli = cli;
+
+ // Set the hostname (shown in the the prompt)
+ cli_set_hostname(cli, MZ_PROMPT);
+
+ // Set the greeting
+ cli_set_banner(cli, "mausezahn " VERSION_STRING);
+
+ // Enable usernames and passwords
+ cli_allow_user(cli, mz_username, mz_password);
+ cli_allow_enable(cli, mz_enable);
+
+ // Initialize MOPS
+ mp_head = mops_init(); // now mp_head points to the head of the doubly linked list
+
+ // Initialize packet sequences list
+ packet_sequences = mz_ll_create_new_element(NULL);
+
+
+ mops_rx_arp();
+ lookupdev();
+ for (i=0; i<device_list_entries; i++) {
+ get_dev_params(device_list[i].dev);
+ }
+
+ // Initialize sequence list
+
+
+ // **************** THE MAIN CLI COMMANDS ****************
+
+ // ---- DEBUG MODE: ----
+ debug = cli_register_command(cli, NULL, "debug", NULL, PRIVILEGE_PRIVILEGED, MODE_EXEC, "Enter debug mode");
+ cli_register_command(cli, debug, "packet", debug_packet, PRIVILEGE_PRIVILEGED, MODE_EXEC, "Debug packet processing");
+ cli_register_command(cli, debug, "all", debug_all, PRIVILEGE_PRIVILEGED, MODE_EXEC, "Debug all (beware!)");
+
+ // ---- INTERFACE MODE COMMANDS: ---- (these are defaults for the 'device defaults' command)
+ cli_register_command(cli, NULL, "interface", enter_interface, PRIVILEGE_PRIVILEGED, MODE_CONFIG, "Enter interface configuration mode");
+ ip_int = cli_register_command(cli, NULL, "ip", NULL, PRIVILEGE_PRIVILEGED, MZ_MODE_INTERFACE, "Configure interface IP address");
+ cli_register_command(cli, ip_int, "address", conf_ip_address, PRIVILEGE_PRIVILEGED, MZ_MODE_INTERFACE, "Configure interface IP address");
+ mac_int= cli_register_command(cli, NULL, "mac", NULL, PRIVILEGE_PRIVILEGED, MZ_MODE_INTERFACE, "Configure interface MAC address");
+ cli_register_command(cli, mac_int, "address", conf_mac_address, PRIVILEGE_PRIVILEGED, MZ_MODE_INTERFACE, "Configure interface MAC address");
+ tag = cli_register_command(cli, NULL, "tag", NULL, PRIVILEGE_PRIVILEGED, MZ_MODE_INTERFACE, "Configure tags");
+ cli_register_command(cli, tag, "dot1q", conf_tag_dot1q, PRIVILEGE_PRIVILEGED, MZ_MODE_INTERFACE, "Configure 802.1Q and 802.1P parameters");
+ cli_register_command(cli, tag, "mpls", conf_tag_mpls, PRIVILEGE_PRIVILEGED, MZ_MODE_INTERFACE, "Configure mpls label stack");
+
+ // ---- VARIOUS CONFIG MODE COMMANDS : ----
+ frame = cli_register_command(cli, NULL, "frame", NULL, PRIVILEGE_PRIVILEGED, MODE_CONFIG, "Configure global frame settings");
+ cli_register_command(cli, frame, "limit", conf_frame_limit, PRIVILEGE_PRIVILEGED, MODE_CONFIG, "Configure frame size limits");
+ cli_register_command(cli, NULL, "sequence", conf_sequence, PRIVILEGE_PRIVILEGED, MODE_CONFIG, "Configure a sequence of packets");
+
+ // ---- PACKET CONFIG MODE COMMANDS: ----
+ cli_register_command(cli, NULL, "packet", enter_packet, PRIVILEGE_PRIVILEGED, MODE_CONFIG, "Enter packet configuration mode");
+ cli_register_command(cli, NULL, "clone", cmd_packet_clone, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "Clone from another packet");
+ cli_register_command(cli, NULL, "name", cmd_packet_name, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "Assign a unique name");
+ cli_register_command(cli, NULL, "description", cmd_packet_description, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "Assign a packet description text");
+ cli_register_command(cli, NULL, "bind", cmd_packet_bind, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "Select the network interface");
+ cli_register_command(cli, NULL, "count", cmd_packet_count, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "Configure the packet count value");
+ cli_register_command(cli, NULL, "delay", cmd_packet_delay, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "Configure the inter-packet delay");
+ cli_register_command(cli, NULL, "interval", cmd_packet_interval, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "Configure a greater interval");
+ cli_register_command(cli, NULL, "type", cmd_packet_type, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "Specify packet type");
+ mac_packet = cli_register_command(cli, NULL, "mac", NULL, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "Configure packet's MAC addresses");
+ address = cli_register_command(cli, mac_packet, "address", NULL, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "Configure packet's source IP address");
+ cli_register_command(cli, address, "source", cmd_packet_mac_address_source, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "Configure packet's source MAC addresses");
+ cli_register_command(cli, address, "destination", cmd_packet_mac_address_destination, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "Configure packet's destination MAC addresses");
+ tag = cli_register_command(cli, NULL, "tag", NULL, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "Configure tags");
+ cli_register_command(cli, tag, "dot1q", cmd_packet_dot1q, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "Configure 802.1Q (and 802.1P) parameters");
+ cli_register_command(cli, tag, "mpls", cmd_packet_mpls, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "Configure MPLS label stack");
+ pld = cli_register_command(cli, NULL, "payload", NULL, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "Configure a payload");
+ cli_register_command(cli, pld, "hex", cmd_packet_payload_hex, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "Configure a payload in hexadecimal format");
+ cli_register_command(cli, pld, "ascii", cmd_packet_payload_ascii, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "Configure a payload in ascii format");
+ cli_register_command(cli, pld, "raw", cmd_packet_payload_raw, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "Configure a raw payload (whole file as it is)");
+ port = cli_register_command(cli, NULL, "port", NULL, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "Configure packet's port numbers");
+ cli_register_command(cli, port, "source", cmd_port_source, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "Configure packet's source port number");
+ cli_register_command(cli, port, "destination", cmd_port_destination, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "Configure packet's destination port number");
+ cli_register_command(cli, NULL, "end", cmd_packet_end, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "End packet configuration mode");
+
+ // ---------- Ethernet related (for all packets that have Ethernet or LLC/SNAP as link layer)
+ eth_frame = cli_register_command(cli, NULL, "ethernet", NULL, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "Configure frame's Ethernet, 802.2, 802.3, or SNAP settings");
+ macaddr = cli_register_command(cli, eth_frame, "address", NULL, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "Configure frame's source or destination MAC address");
+ cli_register_command(cli, macaddr, "source", cmd_packet_mac_address_source, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "Configure frame's source MAC addresses");
+ cli_register_command(cli, macaddr, "destination", cmd_packet_mac_address_destination, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "Configure frame's destination MAC addresses");
+ cli_register_command(cli, eth_frame, "type", cmd_eth_type, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "Configure Ethernet's type field");
+ cli_register_command(cli, eth_frame, "length", cmd_eth_length, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "Configure IEEE 802.3 length field");
+ cli_register_command(cli, eth_frame, "llc", cmd_eth_llc, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "Configure the IEEE 802.2 field");
+ cli_register_command(cli, eth_frame, "snap", cmd_eth_snap, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "Configure the IEEE 802.2 field");
+
+ // ---------- IP related (for all packets that have IPv4 as network layer)
+ ip_packet = cli_register_command(cli, NULL, "ip", NULL, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "Configure packet's IP settings");
+ address = cli_register_command(cli, ip_packet, "address", NULL, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "Configure packet's source or destination IP address");
+ cli_register_command(cli, address, "source", cmd_ip_address_source, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "Configure packet's source IP address");
+ cli_register_command(cli, address, "destination", cmd_ip_address_destination, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "Configure packet's destination IP address");
+ cli_register_command(cli, ip_packet, "version", cmd_ip_version, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "Configure version field in IPv4 header");
+ cli_register_command(cli, ip_packet, "ttl", cmd_ip_ttl, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "Configure TTL field in IPv4 header");
+ cli_register_command(cli, ip_packet, "protocol", cmd_ip_protocol, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "Configure protocol field in IPv4 header");
+ cli_register_command(cli, ip_packet, "hlen", cmd_ip_hlen, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "Configure header-length (aka IHL) field in IPv4 header");
+ cli_register_command(cli, ip_packet, "length", cmd_ip_len, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "Configure length field in IPv4 header");
+ cli_register_command(cli, ip_packet, "identification", cmd_ip_id, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "Configure identification field in IPv4 header");
+ cli_register_command(cli, ip_packet, "offset", cmd_ip_offset, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "Configure fragment offset field in IPv4 header");
+ cli_register_command(cli, ip_packet, "checksum", cmd_ip_sum, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "Configure checksum field in IPv4 header");
+ cli_register_command(cli, ip_packet, "tos", cmd_ip_tos, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "Configure type-of-service (ToS) field in IPv4 header");
+ cli_register_command(cli, ip_packet, "dscp", cmd_ip_dscp, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "Configure the ToS as DSCP field in IPv4 header");
+ cli_register_command(cli, ip_packet, "reserved", cmd_ip_rsv, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "Configure the reserved flag in IPv4 header");
+ cli_register_command(cli, ip_packet, "dont-fragment", cmd_ip_df, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "Configure the don't fragment flag in IPv4 header");
+ cli_register_command(cli, ip_packet, "more-fragments", cmd_ip_mf, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "Configure the more fragments flag in IPv4 header");
+ cli_register_command(cli, ip_packet, "fragment-size", cmd_ip_fragsize, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "Configure the fragment size to enable fragmentation");
+ cli_register_command(cli, ip_packet, "fragment-overlap", cmd_ip_fragoverlap, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "Configure a fragmentation overlap");
+ cli_register_command(cli, ip_packet, "option", cmd_ip_option, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "Configure IPv4 options");
+ cli_register_command(cli, ip_packet, "auto-delivery", cmd_ip_delivery, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "Enable or disable IP auto-delivery");
+ // --------- IP commands:
+ cli_register_command(cli, NULL, "version", cmd_ip_version, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_IP, "Specify the IP version (default: 4)");
+ cli_register_command(cli, NULL, "ttl", cmd_ip_ttl, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_IP, "Specify the TTL (default: 255)");
+ cli_register_command(cli, NULL, "source-address", cmd_ip_address_source, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_IP, "Specify the source IP address");
+ cli_register_command(cli, NULL, "destination-address", cmd_ip_address_destination, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_IP, "Specify the destination IP address");
+ cli_register_command(cli, NULL, "protocol", cmd_ip_protocol, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_IP, "Specify the IP protocol");
+ cli_register_command(cli, NULL, "hlen", cmd_ip_hlen, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_IP, "Specify the IP header length");
+ cli_register_command(cli, NULL, "len", cmd_ip_len, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_IP, "Specify the IP packet length");
+ cli_register_command(cli, NULL, "identification", cmd_ip_id, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_IP, "Specify the IP identification");
+ cli_register_command(cli, NULL, "offset", cmd_ip_offset, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_IP, "Specify the fragment offset");
+ cli_register_command(cli, NULL, "sum", cmd_ip_sum, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_IP, "Specify the IP header checksum");
+ cli_register_command(cli, NULL, "tos", cmd_ip_tos, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_IP, "Specify the Type of Service");
+ cli_register_command(cli, NULL, "dscp", cmd_ip_dscp, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_IP, "Specify the DSCP");
+ cli_register_command(cli, NULL, "reserved", cmd_ip_rsv, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_IP, "Set or unset the reserved bit");
+ cli_register_command(cli, NULL, "df", cmd_ip_df, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_IP, "Set or unset the Don't Fragment (DF) bit");
+ cli_register_command(cli, NULL, "mf", cmd_ip_mf, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_IP, "Set or unset the More Fragments (MF) bit");
+ cli_register_command(cli, NULL, "fragment-size", cmd_ip_fragsize, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_IP, "Configure the fragment size to enable fragmentation");
+ cli_register_command(cli, NULL, "fragment-overlap", cmd_ip_fragoverlap, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_IP, "Configure a fragmentation overlap");
+ cli_register_command(cli, NULL, "option", cmd_ip_option, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_IP, "Configure an IP option");
+ cli_register_command(cli, NULL, "auto-delivery", cmd_ip_delivery, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_IP, "Enable or disable IP auto-delivery");
+ cli_register_command(cli, NULL, "end", cmd_ip_end, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_IP, "End IP configuration mode");
+
+ // ---------- UDP related (for all packets that have UDP as transport layer)
+ udp_packet = cli_register_command(cli, NULL, "udp", NULL, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "Configure packet's UDP header parameters");
+ cli_register_command(cli, udp_packet, "checksum", cmd_udp_sum, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "Configure the UDP checksum");
+ cli_register_command(cli, udp_packet, "length", cmd_udp_len, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "Configure the UDP length field");
+ // ---------- UDP commands:
+ cli_register_command(cli, NULL, "checksum", cmd_udp_sum, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_UDP, "Configure the UDP checksum");
+ cli_register_command(cli, NULL, "length", cmd_udp_len, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_UDP, "Configure the UDP length field");
+ cli_register_command(cli, NULL, "end", cmd_udp_end, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_UDP, "End UDP configuration mode");
+
+ // ---------- TCP related (for all packets that have TCP as transport layer)
+ tcp_packet = cli_register_command(cli, NULL, "tcp", NULL, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "Configure packet's TCP header parameters");
+ cli_register_command(cli, tcp_packet, "seqnr", cmd_tcp_seqnr, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "Configure the TCP sequence number");
+ cli_register_command(cli, tcp_packet, "acknr", cmd_tcp_acknr, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "Configure the TCP acknowledgement number");
+ cli_register_command(cli, tcp_packet, "hlen", cmd_tcp_offset, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "Configure the TCP header length");
+ cli_register_command(cli, tcp_packet, "reserved", cmd_tcp_res, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "Configure the TCP reserved field");
+ cli_register_command(cli, tcp_packet, "flags", cmd_tcp_flags, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "Configure a combination of TCP flags at once");
+ cli_register_command(cli, tcp_packet, "cwr", cmd_tcp_cwr, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "Set or unset the TCP CWR flag");
+ cli_register_command(cli, tcp_packet, "ece", cmd_tcp_ece, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "Set or unset the TCP ECE flag");
+ cli_register_command(cli, tcp_packet, "urg", cmd_tcp_urg, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "Set or unset the TCP URG flag");
+ cli_register_command(cli, tcp_packet, "ack", cmd_tcp_ack, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "set or unset the TCP ACK flag");
+ cli_register_command(cli, tcp_packet, "psh", cmd_tcp_psh, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "set or unset the TCP PSH flag");
+ cli_register_command(cli, tcp_packet, "rst", cmd_tcp_rst, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "set or unset the TCP RST flag");
+ cli_register_command(cli, tcp_packet, "syn", cmd_tcp_syn, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "set or unset the TCP SYN flag");
+ cli_register_command(cli, tcp_packet, "fin", cmd_tcp_fin, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "set or unset the TCP FIN flag");
+ cli_register_command(cli, tcp_packet, "window", cmd_tcp_window, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "Configure the TCP window size");
+ cli_register_command(cli, tcp_packet, "checksum", cmd_tcp_sum, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "Configure the TCP checksum");
+ cli_register_command(cli, tcp_packet, "urgent-pointer", cmd_tcp_urgptr, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "Configure the TCP urgend pointer");
+ cli_register_command(cli, tcp_packet, "options", cmd_tcp_options, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET, "Configure TCP options");
+ // ---------- TCP commands:
+ cli_register_command(cli, NULL, "seqnr", cmd_tcp_seqnr, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_TCP, "Configure the TCP sequence number");
+ cli_register_command(cli, NULL, "acknr", cmd_tcp_acknr, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_TCP, "Configure the TCP acknowledgement number");
+ cli_register_command(cli, NULL, "hlen", cmd_tcp_offset, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_TCP, "Configure the TCP header length");
+ cli_register_command(cli, NULL, "reserved", cmd_tcp_res, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_TCP, "Configure the TCP reserved field");
+ cli_register_command(cli, NULL, "flags", cmd_tcp_flags, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_TCP, "Configure a combination of TCP flags at once");
+ cli_register_command(cli, NULL, "cwr", cmd_tcp_cwr, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_TCP, "Set or unset the TCP CWR flag");
+ cli_register_command(cli, NULL, "ece", cmd_tcp_ece, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_TCP, "Set or unset the TCP ECE flag");
+ cli_register_command(cli, NULL, "urg", cmd_tcp_urg, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_TCP, "Set or unset the TCP URG flag");
+ cli_register_command(cli, NULL, "ack", cmd_tcp_ack, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_TCP, "set or unset the TCP ACK flag");
+ cli_register_command(cli, NULL, "psh", cmd_tcp_psh, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_TCP, "set or unset the TCP PSH flag");
+ cli_register_command(cli, NULL, "rst", cmd_tcp_rst, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_TCP, "set or unset the TCP RST flag");
+ cli_register_command(cli, NULL, "syn", cmd_tcp_syn, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_TCP, "set or unset the TCP SYN flag");
+ cli_register_command(cli, NULL, "fin", cmd_tcp_fin, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_TCP, "set or unset the TCP FIN flag");
+ cli_register_command(cli, NULL, "window", cmd_tcp_window, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_TCP, "Configure the TCP window size");
+ cli_register_command(cli, NULL, "checksum", cmd_tcp_sum, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_TCP, "Configure the TCP checksum");
+ cli_register_command(cli, NULL, "urgent-pointer", cmd_tcp_urgptr, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_TCP, "Configure the TCP urgend pointer");
+ cli_register_command(cli, NULL, "options", cmd_tcp_options, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_TCP, "Configure TCP options");
+ cli_register_command(cli, NULL, "end", cmd_tcp_end, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_TCP, "End TCP configuration mode");
+
+ // --------- ARP commands:
+ cli_register_command(cli, NULL, "hardware-type", cmd_arp_hwtype, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_ARP, "Specify the hardware type");
+ cli_register_command(cli, NULL, "protocol-type", cmd_arp_prtype, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_ARP, "Specify the protocol type");
+ cli_register_command(cli, NULL, "hw-addr-size", cmd_arp_hwaddrsize, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_ARP, "Specify the hardware address size");
+ cli_register_command(cli, NULL, "pr-addr-size", cmd_arp_praddrsize, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_ARP, "Specify the protocol address size");
+ cli_register_command(cli, NULL, "opcode", cmd_arp_opcode, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_ARP, "Specify the ARP opcode");
+ cli_register_command(cli, NULL, "sender-mac", cmd_arp_smac, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_ARP, "Specify the sender MAC address");
+ cli_register_command(cli, NULL, "sender-ip", cmd_arp_sip, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_ARP, "Specify the sender IP address");
+ cli_register_command(cli, NULL, "target-mac", cmd_arp_tmac, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_ARP, "Specify the target MAC address");
+ cli_register_command(cli, NULL, "target-ip", cmd_arp_tip, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_ARP, "Specify the target IP address");
+ cli_register_command(cli, NULL, "trailer", cmd_arp_trailer, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_ARP, "Specify the trailer length");
+ cli_register_command(cli, NULL, "end", cmd_arp_end, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_ARP, "End ARP configuration mode");
+
+ // --------- BPDU commands:
+ cli_register_command(cli, NULL, "id", cmd_bpdu_id, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_BPDU, "Specify the BPDU identifier");
+ cli_register_command(cli, NULL, "version", cmd_bpdu_version, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_BPDU, "Specify the BPDU version");
+ cli_register_command(cli, NULL, "bpdutype", cmd_bpdu_type, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_BPDU, "Specify the BPDU type");
+ cli_register_command(cli, NULL, "flags", cmd_bpdu_flags, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_BPDU, "Specify the BPDU flags");
+ cli_register_command(cli, NULL, "root-id", cmd_bpdu_rid, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_BPDU, "Specify the BPDU root identifier");
+ cli_register_command(cli, NULL, "path-cost", cmd_bpdu_pc, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_BPDU, "Specify the BPDU root path cost");
+ cli_register_command(cli, NULL, "bridge-id", cmd_bpdu_bid, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_BPDU, "Specify the BPDU bridge identifier");
+ cli_register_command(cli, NULL, "port-id", cmd_bpdu_pid, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_BPDU, "Specify the BPDU port identifier");
+ cli_register_command(cli, NULL, "age", cmd_bpdu_age, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_BPDU, "Specify the BPDU age");
+ cli_register_command(cli, NULL, "maxage", cmd_bpdu_maxage, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_BPDU, "Specify the BPDU maxage");
+ cli_register_command(cli, NULL, "hello-interval", cmd_bpdu_hello, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_BPDU, "Specify the BPDU hello interval");
+ cli_register_command(cli, NULL, "forward-delay", cmd_bpdu_fwd, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_BPDU, "Specify the BPDU forward delay");
+ cli_register_command(cli, NULL, "mode", cmd_bpdu_mode, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_BPDU, "Specify the BPDU mode");
+ cli_register_command(cli, NULL, "vlan", cmd_bpdu_vlan, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_BPDU, "Specify the vlan for PVST+");
+ cli_register_command(cli, NULL, "end", cmd_bpdu_end, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_BPDU, "End BPDU configuration mode");
+
+ // --------- IGMP commands:
+ cli_register_command(cli, NULL, "v2-general-query", cmd_igmpv2_genquery, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_IGMP, "Create an IGMPv2 general query");
+ cli_register_command(cli, NULL, "v2-group-specific-query", cmd_igmpv2_specquery, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_IGMP, "Create an IGMPv2 group-specific query");
+ cli_register_command(cli, NULL, "v2-report", cmd_igmpv2_report, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_IGMP, "Create an IGMPv2 membership report");
+ cli_register_command(cli, NULL, "v2-leave", cmd_igmpv2_leave, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_IGMP, "Create an IGMPv2 leave group message");
+ cli_register_command(cli, NULL, "v1-query", cmd_igmpv1_query, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_IGMP, "Create an IGMPv1 query");
+ cli_register_command(cli, NULL, "v1-report", cmd_igmpv1_report, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_IGMP, "Create an IGMPv1 membership report");
+ cli_register_command(cli, NULL, "end", cmd_ip_end, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_IGMP, "End IGMP configuration mode"); // we reuse cmd_ip_end here!
+
+ cli_register_command(cli, NULL, "conformance", cmd_lldp_conformance, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_LLDP, "Enable or disable LLDP standard conformance");
+ cli_register_command(cli, NULL, "chassis-id", cmd_lldp_chassis_id, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_LLDP, "Configure the LLDP Chassis-ID");
+ cli_register_command(cli, NULL, "port-id", cmd_lldp_port_id, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_LLDP, "Configure the LLDP Port-ID");
+ cli_register_command(cli, NULL, "ttl", cmd_lldp_ttl, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_LLDP, "Configure the LLDP Time-to-Live");
+ cli_register_command(cli, NULL, "vlan", cmd_lldp_vlan, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_LLDP, "Configure the LLDP Port VLAN-ID");
+ cli_register_command(cli, NULL, "generic-tlv", cmd_lldp_opt_tlv, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_LLDP, "Configure a generic LLDP TLV");
+ cli_register_command(cli, NULL, "bad-tlv", cmd_lldp_opt_tlv_bad, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_LLDP, "Configure a bad TLV for testing purposes");
+ cli_register_command(cli, NULL, "organisational-tlv", cmd_lldp_opt_org, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_LLDP, "Configure an organisational LLDP TLV");
+ cli_register_command(cli, NULL, "early-end", cmd_lldp_endtlv, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_LLDP, "Insert an 'early' End-of-LLDPU TLV");
+ cli_register_command(cli, NULL, "reset", cmd_lldp_reset, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_LLDP, "Reset the LLDPU to defaults and clear all optional TLVs");
+ cli_register_command(cli, NULL, "end", cmd_ip_end, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_LLDP, "End IGMP configuration mode"); // we reuse cmd_ip_end here!
+
+ // --------- RTP commands:
+ cli_register_command(cli, NULL, "version", cmd_rtp_version, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_RTP, "Specify the RTP version (default: 2)");
+ cli_register_command(cli, NULL, "padding", cmd_rtp_padding, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_RTP, "Set or unset the padding flag (default: 0)");
+ cli_register_command(cli, NULL, "xten", cmd_rtp_xten, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_RTP, "Set or unset the eXtension flag (default: 0)");
+ cli_register_command(cli, NULL, "marker", cmd_rtp_marker, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_RTP, "Set or unset the marker flag (default: 0)");
+ cli_register_command(cli, NULL, "csrc-count", cmd_rtp_cc, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_RTP, "Configure the CSRC count (default: 0)");
+ cli_register_command(cli, NULL, "csrc-list", cmd_rtp_cclist, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_RTP, "Configure the CSRC list (default: none)");
+ cli_register_command(cli, NULL, "payload-type", cmd_rtp_pt, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_RTP, "Configure the payload type (default: G.711, A-law, 20 msec)");
+ cli_register_command(cli, NULL, "sequence-number", cmd_rtp_sqnr, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_RTP, "Configure the sequence number");
+ cli_register_command(cli, NULL, "timestamp", cmd_rtp_time, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_RTP, "Configure the timestamp");
+ cli_register_command(cli, NULL, "ssrc", cmd_rtp_ssrc, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_RTP, "Configure the SSRC (source identifier)");
+ cli_register_command(cli, NULL, "extension", cmd_rtp_extension, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_RTP, "Configure an extension header");
+ cli_register_command(cli, NULL, "source", cmd_rtp_source, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_RTP, "Specify a media source");
+ cli_register_command(cli, NULL, "end", cmd_ip_end, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_RTP, "End RTP configuration mode"); // we reuse cmd_ip_end here!
+
+ // --------- DNS commands:
+ cli_register_command(cli, NULL, "ttl", cmd_dns_ttl, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_DNS, "Specify the TTL (default: 0)");
+ cli_register_command(cli, NULL, "query", cmd_dns_query, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_DNS, "Specify the query");
+ cli_register_command(cli, NULL, "answer", cmd_dns_answer, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_DNS, "Specify the answer");
+ cli_register_command(cli, NULL, "end", cmd_dns_end, PRIVILEGE_PRIVILEGED, MZ_MODE_PACKET_DNS, "End DNS configuration mode");
+
+
+ // --------- SEQUENCE COMMANDS
+ cli_register_command(cli, NULL, "add", sequence_add, PRIVILEGE_PRIVILEGED, MZ_MODE_SEQUENCE, "Add another packet to the current sequence");
+ cli_register_command(cli, NULL, "delay", sequence_delay, PRIVILEGE_PRIVILEGED, MZ_MODE_SEQUENCE, "Add a delay to the current sequence");
+ cli_register_command(cli, NULL, "show", sequence_show, PRIVILEGE_PRIVILEGED, MZ_MODE_SEQUENCE, "Show current sequence list");
+ cli_register_command(cli, NULL, "remove", sequence_remove, PRIVILEGE_PRIVILEGED, MZ_MODE_SEQUENCE, "Remove a packet or delay from the current sequence");
+ cli_register_command(cli, NULL, "end", cmd_end_to_config, PRIVILEGE_PRIVILEGED, MZ_MODE_SEQUENCE, "End sequence configuration mode");
+ // ---- BENCHMARK CONFIG MODE COMMANDS: ---
+ // ---- SCAN CONFIG MODE COMMANDS: ---
+
+ // ---- CONTROL COMMANDS: ----
+ cli_register_command(cli, NULL, "terminate", stop_mausezahn, PRIVILEGE_PRIVILEGED, MODE_EXEC, "Terminate the Mausezahn server");
+ run = cli_register_command(cli, NULL, "run", NULL, PRIVILEGE_PRIVILEGED, MODE_EXEC, "Run previously configured mops instances or sequences");
+ cli_register_command(cli, run, "id", cmd_run_id, PRIVILEGE_PRIVILEGED, MODE_EXEC, "Run mops packet(s) by specifying packet identifiers");
+ cli_register_command(cli, run, "name", cmd_run_name, PRIVILEGE_PRIVILEGED, MODE_EXEC, "Run mops packet(s) by specifying packet names");
+ cli_register_command(cli, run, "sequence", cmd_run_sequence, PRIVILEGE_PRIVILEGED, MODE_EXEC, "Run a packet sequence");
+ cli_register_command(cli, run, "all", cmd_run_all, PRIVILEGE_PRIVILEGED, MODE_EXEC, "Run all currently configured mops packet(s)");
+ cli_register_command(cli, NULL, "tx", transmit, PRIVILEGE_PRIVILEGED, MODE_EXEC, "Send inline configured packet (legacy mode; not recommended)");
+ cli_register_command(cli, NULL, "stop", cmd_stop, PRIVILEGE_PRIVILEGED, MODE_EXEC, "Stop transmission");
+ cli_register_command(cli, NULL, "load", cmd_load, PRIVILEGE_PRIVILEGED, MODE_EXEC, "Load commands from a file");
+
+ // ---- SET COMMANDS: -----
+ cli_register_command(cli, NULL, "set", cmd_set, PRIVILEGE_PRIVILEGED, MODE_EXEC, "Set global Mausezahn parameters");
+
+ // ---- CLEAR COMMANDS: -----
+ clear = cli_register_command(cli, NULL, "clear", NULL, PRIVILEGE_PRIVILEGED, MODE_EXEC, "Clear something (use '?')");
+ cli_register_command(cli, clear, "all", clear_all, PRIVILEGE_PRIVILEGED, MODE_EXEC, "Re-initialize Mausezahn");
+ cli_register_command(cli, clear, "packet", clear_packet, PRIVILEGE_PRIVILEGED, MODE_EXEC, "Delete a packet (i. e. MOPS entry)");
+
+ // ---- SHOW COMMANDS: -----
+ show = cli_register_command(cli, NULL, "show", NULL, PRIVILEGE_UNPRIVILEGED, MODE_EXEC, "Show something (use '?')");
+ cli_register_command(cli, show, "packet", show_packets, PRIVILEGE_UNPRIVILEGED, MODE_EXEC, "Show defined packets");
+// cli_register_command(cli, show, "system", show_system, PRIVILEGE_UNPRIVILEGED, MODE_EXEC, "Show basic system settings");
+ cli_register_command(cli, show, "interfaces", show_interfaces, PRIVILEGE_UNPRIVILEGED, MODE_EXEC, "Show detailed interface information");
+ cli_register_command(cli, show, "mops", show_mops, PRIVILEGE_UNPRIVILEGED, MODE_EXEC, "Show MOPS details");
+// cli_register_command(cli, show, "processes", cmd_test, PRIVILEGE_UNPRIVILEGED, MODE_EXEC, "List all Mausezahn processes");
+ cli_register_command(cli, show, "set", show_set, PRIVILEGE_UNPRIVILEGED, MODE_EXEC, "List general packet parameters");
+ cli_register_command(cli, show, "arp", show_arp, PRIVILEGE_UNPRIVILEGED, MODE_EXEC, "Show the advanced Mausezahn ARP table");
+
+// cli_register_command(cli, show, "report", cmd_test, PRIVILEGE_UNPRIVILEGED, MODE_EXEC, "Print reports");
+
+ // ---- PRIVILEGE (OTHER) ----
+ reset = cli_register_command(cli, NULL, "reset", NULL, PRIVILEGE_PRIVILEGED, MODE_EXEC, "Reset something...");
+ cli_register_command(cli, reset, "interface", cmd_reset_interface, PRIVILEGE_PRIVILEGED, MODE_EXEC, "Reset interfaces");
+ cli_register_command(cli, reset, "packet", cmd_reset_packet, PRIVILEGE_PRIVILEGED, MODE_EXEC, "Reset interfaces");
+ // ------- LAUNCH ------
+ launch = cli_register_command(cli, NULL, "launch", NULL, PRIVILEGE_PRIVILEGED, MODE_EXEC, "Launch a predefined MOPS process");
+ cli_register_command(cli, launch, "bpdu", launch_bpdu, PRIVILEGE_PRIVILEGED, MODE_EXEC, "Launch a(nother) BPDU process");
+ cli_register_command(cli, launch, "synflood", launch_synflood, PRIVILEGE_PRIVILEGED, MODE_EXEC, "Launch a(nother) SYN-Flood process");
+// cli_register_command(cli, launch, "alot", launch_alot, PRIVILEGE_PRIVILEGED, MODE_EXEC, "Launch lots of traffic");
+// cli_register_command(cli, launch, "rtp", launch_rtp, PRIVILEGE_PRIVILEGED, MODE_EXEC, "Launch rtp stream(s)");
+// cli_register_command(cli, launch, "arp", launch_arp, PRIVILEGE_PRIVILEGED, MODE_EXEC, "Launch a(nother) ARP process");
+// cli_register_command(cli, launch, "lldp", launch_lldp, PRIVILEGE_PRIVILEGED, MODE_EXEC, "Launch a(nother) LLDP process");
+
+
+ // *******************************************************
+
+ // Create a socket
+ s = socket(AF_INET, SOCK_STREAM, 0);
+ setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+
+ // Should we bind the CLI session to a specific interface?
+ // TODO: This does nothing !?
+ for (i=0; i<device_list_entries; i++) {
+ if (device_list[i].cli) {
+ setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, device_list[i].dev, strnlen(device_list[i].dev, 16));
+ break; // can only be one interface
+ }
+ }
+
+
+ // Listen on port mz_port (default: 25542, towel day)
+ memset(&servaddr, 0, sizeof(servaddr));
+ servaddr.sin_family = AF_INET;
+ servaddr.sin_addr.s_addr = htonl(INADDR_ANY); // TODO: specified interface
+ servaddr.sin_port = htons(mz_port);
+ bind(s, (struct sockaddr *)&servaddr, sizeof(servaddr));
+
+ // Wait for a connection
+ listen(s, 50);
+
+ while ((x = accept(s, NULL, 0)))
+ {
+ if (!quiet)
+ {
+ cnt++;
+ timestamp_human(TimeStamp, NULL);
+ fprintf(stderr, "Got incoming connection [%i] at %s.\n", cnt, TimeStamp);
+ fflush(stderr);
+ }
+
+ // Pass the connection off to libcli
+ cli_loop(cli, x);
+
+ if (!quiet)
+ {
+ timestamp_human(TimeStamp, NULL);
+ fprintf(stderr, "Connection [%i] left at %s.\n", cnt, TimeStamp);
+ }
+
+ close(x);
+ }
+
+ // Free data structures
+ cli_done(cli);
+
+ return 0;
+}
+
+
diff --git a/staging/cli.h b/staging/cli.h
new file mode 100644
index 0000000..6c6cccb
--- /dev/null
+++ b/staging/cli.h
@@ -0,0 +1,268 @@
+/*
+ * Mausezahn - A fast versatile traffic generator
+ * Copyright (C) 2008 Herbert Haas
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
+ *
+*/
+
+
+
+#ifndef __MAUSEZAHN_CLI__
+#define __MAUSEZAHN_CLI__
+
+#include <libcli.h>
+#include "mops.h"
+
+#define CLI_DEBUG_PACKET 0x0001
+
+#define MZ_MODE_BENCHMARK 1002
+#define MZ_MODE_SCAN 1003
+
+#define MZ_MODE_PACKET 1100
+
+#define MZ_MODE_PACKET_ARP 1101
+#define MZ_MODE_PACKET_BPDU 1102
+#define MZ_MODE_PACKET_CDP 1103
+#define MZ_MODE_PACKET_DNS 1104
+#define MZ_MODE_PACKET_IP 1105
+#define MZ_MODE_PACKET_ICMP 1106
+#define MZ_MODE_PACKET_LLDP 1107
+#define MZ_MODE_PACKET_RTP 1108
+#define MZ_MODE_PACKET_SYSLOG 1109
+#define MZ_MODE_PACKET_TCP 1110
+#define MZ_MODE_PACKET_UDP 1111
+#define MZ_MODE_PACKET_ETH 1112
+#define MZ_MODE_PACKET_IGMP 1113
+
+#define MZ_MODE_INTERFACE 1200
+#define MZ_MODE_SEQUENCE 1300
+
+#define MZ_PROMPT "mz-" MAUSEZAHN_VERSION_SHORT
+
+#define MZ_DEFAULT_USERNAME "mz"
+#define MZ_DEFAULT_PASSWORD "mz"
+#define MZ_DEFAULT_ENABLE_PASSWORD "mops"
+#define MZ_DEFAULT_PORT 25542 // Towel day and 42
+
+struct cli_def *gcli;
+
+char mz_username[32];
+char mz_password[32];
+char mz_enable[32];
+int mz_port;
+struct mops *clipkt; // actual packet used by CLI thread
+
+int clidev;
+
+// =================================================================
+int cli_debug;
+
+// Flags from 0x0000 to 0xFFFF
+// cli_debug & 8000 => Developer specific debugs
+// cli_debug & 0001 => Packet transmission debugging
+// ...
+
+// =================================================================
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Prototypes
+
+void mz_cli_init();
+int cli_read_cfg(char *str);
+int mz_def16 (char *def, u_int16_t val, char *str256);
+int cli();
+
+int debug_all (struct cli_def *cli, const char *command, char *argv[], int argc);
+int debug_packet (struct cli_def *cli, const char *command, char *argv[], int argc);
+
+int cmd_end_to_config(struct cli_def *cli, const char *command, char *argv[], int argc);
+int tx_switch(struct cli_def *cli);
+int cmd_test(struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_reset_interface (struct cli_def *cli, const char *command, char *argv[], int argc);
+
+int show_system(struct cli_def *cli, const char *command, char *argv[], int argc);
+int show_packets(struct cli_def *cli, const char *command, char *argv[], int argc);
+int show_set(struct cli_def *cli, const char *command, char *argv[], int argc);
+int show_interfaces(struct cli_def *cli, const char *command, char *argv[], int argc);
+int show_mops(struct cli_def *cli, const char *command, char *argv[], int argc);
+int show_arp (struct cli_def *cli, const char *command, char *argv[], int argc);
+
+int cmd_set(struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_run_id (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_run_name (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_run_sequence (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_run_all (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_stop (struct cli_def *cli, const char *command, char *argv[], int argc);
+
+int launch_bpdu (struct cli_def *cli, const char *command, char *argv[], int argc);
+int launch_synflood (struct cli_def *cli, const char *command, char *argv[], int argc);
+
+int stop_mausezahn(struct cli_def *cli, const char *command, char *argv[], int argc);
+int transmit (struct cli_def *cli, const char *command, char *argv[], int argc);
+int clear_all(struct cli_def *cli, const char *command, char *argv[], int argc);
+int clear_packet(struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_reset_packet(struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_load (struct cli_def *cli, const char *command, char *argv[], int argc);
+
+int enter_interface (struct cli_def *cli, const char *command, char *argv[], int argc);
+int conf_ip_address (struct cli_def *cli, const char *command, char *argv[], int argc);
+int conf_mac_address (struct cli_def *cli, const char *command, char *argv[], int argc);
+int conf_tag_dot1q (struct cli_def *cli, const char *command, char *argv[], int argc);
+int conf_tag_mpls (struct cli_def *cli, const char *command, char *argv[], int argc);
+
+int conf_frame_limit (struct cli_def *cli, const char *command, char *argv[], int argc);
+
+int conf_sequence (struct cli_def *cli, const char *command, char *argv[], int argc);
+int sequence_add (struct cli_def *cli, const char *command, char *argv[], int argc);
+int sequence_delay (struct cli_def *cli, const char *command, char *argv[], int argc);
+int sequence_remove (struct cli_def *cli, const char *command, char *argv[], int argc);
+int sequence_show (struct cli_def *cli, const char *command, char *argv[], int argc);
+
+
+int enter_packet (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_packet_type(struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_packet_end(struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_packet_clone (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_packet_name (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_packet_description (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_packet_count (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_packet_delay (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_packet_interval (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_packet_bind (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_packet_mac_address_source (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_packet_mac_address_destination (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_eth_type (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_eth_length (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_eth_llc (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_eth_snap (struct cli_def *cli, const char *command, char *argv[], int argc);
+
+int cmd_packet_dot1q (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_packet_mpls (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_packet_payload_hex (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_packet_payload_ascii (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_packet_payload_raw (struct cli_def *cli, const char *command, char *argv[], int argc);
+
+int cmd_port_source (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_port_destination (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_udp_sum (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_udp_len (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_udp_end(struct cli_def *cli, const char *command, char *argv[], int argc);
+
+int cmd_tcp_seqnr (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_tcp_acknr (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_tcp_offset (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_tcp_res (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_tcp_flags (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_tcp_cwr (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_tcp_ece (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_tcp_urg (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_tcp_ack (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_tcp_psh (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_tcp_rst (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_tcp_syn (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_tcp_fin (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_tcp_window (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_tcp_sum (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_tcp_urgptr(struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_tcp_options (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_tcp_end(struct cli_def *cli, const char *command, char *argv[], int argc);
+
+int cmd_dns_query(struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_dns_answer(struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_dns_ttl(struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_dns_end(struct cli_def *cli, const char *command, char *argv[], int argc);
+
+int cmd_arp_hwtype (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_arp_prtype (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_arp_hwaddrsize (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_arp_praddrsize (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_arp_opcode (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_arp_smac (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_arp_sip (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_arp_tmac (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_arp_tip (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_arp_trailer (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_arp_end(struct cli_def *cli, const char *command, char *argv[], int argc);
+
+int cmd_bpdu_id (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_bpdu_version (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_bpdu_type (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_bpdu_flags (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_bpdu_rid (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_bpdu_pc (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_bpdu_bid (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_bpdu_pid (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_bpdu_age (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_bpdu_maxage (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_bpdu_hello (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_bpdu_fwd (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_bpdu_mode (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_bpdu_vlan(struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_bpdu_end(struct cli_def *cli, const char *command, char *argv[], int argc);
+
+int cmd_igmpv2_genquery (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_igmpv2_specquery (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_igmpv2_report (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_igmpv2_leave (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_igmpv1_query (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_igmpv1_report (struct cli_def *cli, const char *command, char *argv[], int argc);
+
+int cmd_lldp_conformance (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_lldp_chassis_id (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_lldp_port_id (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_lldp_ttl (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_lldp_vlan (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_lldp_opt_tlv (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_lldp_opt_tlv_bad (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_lldp_opt_org (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_lldp_endtlv (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_lldp_reset (struct cli_def *cli, const char *command, char *argv[], int argc);
+
+int cmd_ip_address_source (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_ip_address_destination (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_ip_version (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_ip_ttl (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_ip_protocol (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_ip_hlen (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_ip_len (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_ip_id (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_ip_offset (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_ip_sum (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_ip_tos (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_ip_dscp (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_ip_rsv (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_ip_df (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_ip_mf (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_ip_fragsize (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_ip_fragoverlap (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_ip_option (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_ip_delivery (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_ip_end(struct cli_def *cli, const char *command, char *argv[], int argc);
+
+int cmd_rtp_version (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_rtp_padding (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_rtp_xten (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_rtp_marker (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_rtp_cc (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_rtp_pt (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_rtp_ssrc (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_rtp_sqnr (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_rtp_time (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_rtp_extension (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_rtp_source (struct cli_def *cli, const char *command, char *argv[], int argc);
+int cmd_rtp_cclist (struct cli_def *cli, const char *command, char *argv[], int argc);
+
+#endif
+
diff --git a/staging/cli_arp.c b/staging/cli_arp.c
new file mode 100644
index 0000000..4bf8580
--- /dev/null
+++ b/staging/cli_arp.c
@@ -0,0 +1,232 @@
+/*
+ * Mausezahn - A fast versatile traffic generator
+ * Copyright (C) 2008-2010 Herbert Haas
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
+ *
+*/
+
+
+
+#include "mz.h"
+#include "cli.h"
+#include "mops.h"
+
+
+// ISSUES:
+//
+// - Currently only IP/MAC resolution supported (i.e. hw_size=6, pr_size=4)
+// - Add macro support: commands like request/response should set all params correctly
+
+
+
+
+int cmd_arp_hwtype (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ struct mops_ext_arp * pd = clipkt->p_desc;
+
+ if ( (strncmp(argv[argc-1],"?",1)==0) || (argc!=1) )
+ {
+ cli_print(cli,"Specify the hardware type (0-ffff, default 1=Eth)\n");
+ }
+ else if (mops_pdesc_2byte(&pd->hw_type, argv[0], 1, 0, 0xffff))
+ {
+ cli_print(cli, "Hardware type must be between 0 and ffff\n");
+ }
+
+ return CLI_OK;
+}
+
+
+
+int cmd_arp_prtype (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ struct mops_ext_arp * pd = clipkt->p_desc;
+
+ if ( (strncmp(argv[argc-1],"?",1)==0) || (argc!=1) )
+ {
+ cli_print(cli,"Specify the protocol type (0-ffff, default=800=IP)\n");
+ }
+ else if (mops_pdesc_2byte(&pd->pr_type, argv[0], 1, 0, 0xffff))
+ {
+ cli_print(cli, "Protocol type must be between 0 and ffff\n");
+ }
+
+ return CLI_OK;
+}
+
+
+
+int cmd_arp_hwaddrsize (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ struct mops_ext_arp * pd = clipkt->p_desc;
+
+ if ( (strncmp(argv[argc-1],"?",1)==0) || (argc!=1) )
+ {
+ cli_print(cli,"Specify the hardware address size (0-255, default=6)\n");
+ }
+ else if (mops_pdesc_1byte(&pd->hw_size, argv[0], 0, 0, 255))
+ {
+ cli_print(cli, "Hardware size must be between 0 and 255\n");
+ }
+
+ return CLI_OK;
+}
+
+
+int cmd_arp_praddrsize (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ struct mops_ext_arp * pd = clipkt->p_desc;
+
+ if ( (strncmp(argv[argc-1],"?",1)==0) || (argc!=1) )
+ {
+ cli_print(cli,"Specify the protocol address size (0-255, default=4)\n");
+ }
+ else if (mops_pdesc_1byte(&pd->pr_size, argv[0], 0, 0, 255))
+ {
+ cli_print(cli, "Protocol size must be between 0 and 255\n");
+ }
+
+ return CLI_OK;
+}
+
+
+int cmd_arp_opcode (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ struct mops_ext_arp * pd = clipkt->p_desc;
+
+ if ( (strncmp(argv[argc-1],"?",1)==0) || (argc!=1) )
+ {
+ cli_print(cli,"Specify the ARP operation code (0-ffff)\n");
+ cli_print(cli,"Optional keywords: 'request' (default) or 'response'\n");
+ }
+ else if (mz_strcmp(argv[0],"request", 3)==0)
+ {
+ cli_print(cli, "Set ARP mode to request\n");
+ pd->opcode = 1;
+ }
+ else if (mz_strcmp(argv[0],"response", 3)==0)
+ {
+ cli_print(cli, "Set ARP mode to response\n");
+ pd->opcode = 2;
+ }
+ else
+ {
+ cli_print(cli, "Invalid ARP mode\n");
+ }
+
+ return CLI_OK;
+}
+
+
+
+int cmd_arp_smac (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ struct mops_ext_arp * pd = clipkt->p_desc;
+
+ if ( (strncmp(argv[argc-1],"?",1)==0) || (argc!=1) )
+ {
+ cli_print(cli,"Specify a source MAC address (format: XX:XX:XX:XX:XX:XX)\n");
+ }
+ else
+ {
+ if (mops_pdesc_mac(pd->sender_mac, argv[0]))
+ {
+ cli_print(cli,"Invalid MAC address (use format: XX:XX:XX:XX:XX:XX)\n");
+ }
+ }
+ return CLI_OK;
+}
+
+
+
+int cmd_arp_sip (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ struct mops_ext_arp * pd = clipkt->p_desc;
+
+ if ( (strncmp(argv[argc-1],"?",1)==0) || (argc!=1) )
+ {
+ cli_print(cli,"Specify a source IP address (format: A.B.C.D)\n");
+ }
+ else if (mops_pdesc_ip (pd->sender_ip, argv[0]))
+ {
+ cli_print(cli,"Invalid IP address (use format: A.B.C.D)\n");
+ }
+
+ return CLI_OK;
+}
+
+
+
+int cmd_arp_tmac (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ struct mops_ext_arp * pd = clipkt->p_desc;
+
+ if ( (strncmp(argv[argc-1],"?",1)==0) || (argc!=1) )
+ {
+ cli_print(cli,"Specify a target MAC address (format: XX:XX:XX:XX:XX:XX)\n");
+ }
+ else if (mops_pdesc_mac(pd->target_mac, argv[0]))
+ {
+ cli_print(cli,"Invalid MAC address (use format: XX:XX:XX:XX:XX:XX)\n");
+ }
+
+ return CLI_OK;
+}
+
+
+
+int cmd_arp_tip (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ struct mops_ext_arp * pd = clipkt->p_desc;
+
+ if ( (strncmp(argv[argc-1],"?",1)==0) || (argc!=1) )
+ {
+ cli_print(cli,"Specify a target IP address (format: A.B.C.D)\n");
+ }
+ else if (mops_pdesc_ip (pd->target_ip, argv[0]))
+ {
+ cli_print(cli,"Invalid IP address (use format: A.B.C.D)\n");
+ }
+
+ return CLI_OK;
+}
+
+
+
+int cmd_arp_trailer (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ struct mops_ext_arp * pd = (MOPS_EXT_ARP) clipkt->p_desc;
+
+ if ( (strncmp(argv[argc-1],"?",1)==0) || (argc!=1) )
+ {
+ cli_print(cli,"Specify the trailer length (0-2000, default=18)\n");
+ }
+ else if (mops_pdesc_2byte(&pd->trailer, argv[0], 0, 0, 2000))
+ {
+ cli_print(cli, "Trailer must be between 0 and 2000\n");
+ }
+
+ return CLI_OK;
+}
+
+
+
+int cmd_arp_end(struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ char prompt[16];
+ sprintf(prompt, "pkt-%i",clipkt->id);
+ cli_set_configmode(cli, MZ_MODE_PACKET, prompt);
+ return CLI_OK;
+}
+
diff --git a/staging/cli_bpdu.c b/staging/cli_bpdu.c
new file mode 100644
index 0000000..8cc2a69
--- /dev/null
+++ b/staging/cli_bpdu.c
@@ -0,0 +1,750 @@
+/*
+ * Mausezahn - A fast versatile traffic generator
+ * Copyright (C) 2008-2010 Herbert Haas
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
+ *
+*/
+
+
+
+#include "mz.h"
+#include "cli.h"
+#include "mops.h"
+
+
+
+int cmd_bpdu_id (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ struct mops_ext_bpdu * pd = clipkt->p_desc;
+ char str[256];
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc!=1) )
+ {
+ mz_def16("0x0000", pd->id, str);
+ cli_print(cli, "Specify the BPDU identifier (0..65535)\r");
+ cli_print(cli, "%s\n", str);
+ cli_print(cli, "\n");
+ return CLI_OK;
+ }
+
+ if (mops_pdesc_2byte(&pd->id, argv[0], 0, 0, 65535))
+ {
+ cli_print(cli, "Specify a value between 0 and 65535\n");
+ }
+
+ return CLI_OK;
+}
+
+
+int cmd_bpdu_version (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ struct mops_ext_bpdu * pd = clipkt->p_desc;
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc!=1) )
+ {
+ cli_print(cli, "Specify the BPDU version (0..255)\r");
+ cli_print(cli, "\n");
+ return CLI_OK;
+ }
+
+ if (mops_pdesc_1byte(&pd->version, argv[0], 0, 0, 255))
+ {
+ cli_print(cli, "Specify a value between 0 and 255\n");
+ }
+
+
+ return CLI_OK;
+}
+
+
+
+int cmd_bpdu_type (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ struct mops_ext_bpdu * pd = clipkt->p_desc;
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc!=1) ) {
+ cli_print(cli, "Specify the BPDU type, either via keyword or number (0..255)\n");
+ cli_print(cli, "Keywords:\n");
+ cli_print(cli, " conf .... Configuration BPDU\r");
+ cli_print(cli, " tcn ..... Topology Change BPDU\r");
+ cli_print(cli, "\n");
+ return CLI_OK;
+ }
+
+ if (mz_strcmp(argv[0], "configuration", 1)==0) {
+ pd->bpdu_type = 0x00;
+ } else if (mz_strcmp(argv[0], "tcn", 1)==0) {
+ pd->bpdu_type = 0x80;
+ } else if (mops_pdesc_1byte(&pd->bpdu_type, argv[0], 0, 0, 255)) {
+ cli_print(cli, "Specify a value between 0 and 255\n");
+ }
+
+ return CLI_OK;
+}
+
+
+int cmd_bpdu_flags (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ struct mops_ext_bpdu * pd = clipkt->p_desc;
+ int i;
+ char str[16];
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc>8) )
+ {
+ cli_print(cli, "Specify the BPDU flags by keyword.\r");
+ cli_print(cli, "Note that not-mentioned flags will be set to zero!\n");
+ cli_print(cli, "General keywords:\n");
+ cli_print(cli, " ack .... Topology Change Acknowledgement\r");
+ cli_print(cli, " tcn .... Topology Change Notification\r");
+ cli_print(cli, "\r");
+ cli_print(cli, "RSTP-specific keywords:\n");
+ cli_print(cli, " agree .... Agreement\r");
+ cli_print(cli, " prop .... Proposal\r");
+ cli_print(cli, " fwd .... Forward State\r");
+ cli_print(cli, " learn .... Learn State\r");
+ cli_print(cli, "\r");
+ cli_print(cli, " Port roles:\n");
+ cli_print(cli, " unknown .... Unknown\r");
+ cli_print(cli, " alt .... Alternate or Backup\r");
+ cli_print(cli, " root .... Root\r");
+ cli_print(cli, " desg .... Designated\r");
+ cli_print(cli, "\n");
+ return CLI_OK;
+ }
+
+ // 7 6 5 4 3 2 1 0
+ // tcnack agree fwd learn X X proposal TCN
+ // where XX is 00 unknown
+ // 01 alternate or backup
+ // 10 root
+ // 11 designated
+
+ if (argc)
+ {
+ pd->flags = 0x00; // always reset to zero (= normal Configuration BPDU)
+
+ for (i=0; i<argc; i++)
+ {
+ if (mz_strcmp(argv[i], "ack", 2)==0) pd->flags |= 0x80;
+ else
+ if (mz_strcmp(argv[i], "tcn", 2)==0) pd->flags |= 0x01;
+ else
+ if (mz_strcmp(argv[i], "agree", 2)==0) pd->flags |= 0x40;
+ else
+ if (mz_strcmp(argv[i], "fwd", 2)==0) pd->flags |= 0x20;
+ else
+ if (mz_strcmp(argv[i], "learn", 2)==0) pd->flags |= 0x10;
+ else
+ if (mz_strcmp(argv[i], "proposal", 2)==0) pd->flags |= 0x02;
+ else
+ if (mz_strcmp(argv[i], "unknown", 2)==0) pd->flags &= 0xf3;
+ else
+ if (mz_strcmp(argv[i], "alt", 2)==0) { pd->flags &= 0xf7; pd->flags |= 0x04; }
+ else
+ if (mz_strcmp(argv[i], "root", 2)==0) { pd->flags &= 0xfb; pd->flags |= 0x08; }
+ else
+ if (mz_strcmp(argv[i], "desg", 2)==0) pd->flags |= 0x0c;
+ }
+ // Feedback
+ char2bits(pd->flags, str);
+ cli_print(cli, "Flags: %s\n", str);
+ }
+ else
+ {
+ cli_print(cli, "No flags configured (use '?')\n");
+ }
+
+ return CLI_OK;
+}
+
+
+
+
+
+
+
+
+
+int cmd_bpdu_rid (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+
+ struct mops_ext_bpdu * pd = clipkt->p_desc;
+ char p[64], e[64];
+ int pri, esi, r;
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc>2) )
+ {
+ cli_print(cli, "Specify the BPDU root identifier, using the following format:\n");
+ cli_print(cli, " <priority>[:ext-sys-id] [interface | MAC-Address]\n");
+ cli_print(cli, " <priority> ....... priority (0-15)\r");
+ cli_print(cli, " <ext-sys-id> ....... extended system-id (0-4095)\n");
+ cli_print(cli, "Optionally the MAC address of the root bridge can be given, either directly as arbitrary\r");
+ cli_print(cli, "address (format: XX:XX:XX:XX:XX:XX) or by referring to an existing interface.\n");
+ cli_print(cli, "Per default the MAC address of the default interface is used and a priority of zero.\n");
+ cli_print(cli, "\n");
+ return CLI_OK;
+ }
+
+ if (argc==0) {
+ cli_print(cli, "Please specify at least the priority (use ?)\n");
+ return CLI_OK;
+ }
+
+ mz_tok(argv[0], ":", 2, p, e);
+
+ pri = (int) str2int(p);
+ if (e!=NULL)
+ esi = (int) str2int(e);
+ else
+ esi = 0;
+
+ if (argc==1) // no MAC given
+ {
+ r = mops_create_bpdu_bid (clipkt, pri, esi, NULL, 1); // 1 means RID (0 means BID)
+ }
+ else
+ r = mops_create_bpdu_bid (clipkt, pri, esi, argv[1], 1); // 1 means RID (0 means BID)
+
+
+ // Check return value
+ switch (r)
+ {
+ case 1:
+ cli_print(cli, "Priority must be within 0..15\n");
+ return CLI_OK;
+ break;
+ case 2:
+ cli_print(cli, "Extended System-ID must be within 0..4095\n");
+ return CLI_OK;
+ break;
+ case 3:
+ cli_print(cli, "Invalid MAC address or interface\n");
+ return CLI_OK;
+ break;
+ case 4:
+ cli_print(cli, "Invalid format - use ?\n");
+ return CLI_OK;
+ break;
+ }
+
+
+
+ //---------
+ // Verify:
+ bs2str(pd->root_id, p, 8);
+ cli_print(cli, "RID is now %s\n", p);
+ // -------
+ //
+ return CLI_OK;
+}
+
+
+
+
+
+
+int cmd_bpdu_pc (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ struct mops_ext_bpdu * pd = clipkt->p_desc;
+ unsigned long long int i;
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc>1) )
+ {
+ cli_print(cli, "Specify the BPDU root path cost (0..4294967295)\r");
+ cli_print(cli, "\n");
+ return CLI_OK;
+ }
+
+ if (argc==0)
+ {
+ cli_print(cli, "Missing argument (use ?)\n");
+ return CLI_OK;
+ }
+
+ i = str2lint (argv[0]);
+ if (i>0xffffffff)
+ {
+ cli_print(cli, "Range exceeded (0..4294967295)\n");
+ }
+ else
+ pd->root_pc = (u_int32_t) i;
+
+ return CLI_OK;
+}
+
+
+
+
+int cmd_bpdu_bid (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+
+ struct mops_ext_bpdu * pd = clipkt->p_desc;
+ char p[64], e[64];
+ int pri, esi, r;
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc>2) )
+ {
+ cli_print(cli, "Specify the BPDU bridge identifier, using the following format:\n");
+ cli_print(cli, " <priority>[:ext-sys-id] [interface | MAC-Address]\n");
+ cli_print(cli, " <priority> ....... priority (0-15)\r");
+ cli_print(cli, " <ext-sys-id> ....... extended system-id (0-4095)\n");
+ cli_print(cli, "Optionally the MAC address of the root bridge can be given, either directly as arbitrary\r");
+ cli_print(cli, "address (format: XX:XX:XX:XX:XX:XX) or by referring to an existing interface.\n");
+ cli_print(cli, "Per default the MAC address of the default interface is used and a priority of zero.\n");
+ cli_print(cli, "\n");
+ return CLI_OK;
+ }
+
+
+ if (argc==0)
+ {
+ cli_print(cli, "Please specify at least the priority (use ?)\n");
+ return CLI_OK;
+ }
+
+ mz_tok(argv[0], ":", 2, p, e);
+
+ pri = (int) str2int(p);
+ if (e!=NULL)
+ esi = (int) str2int(e);
+ else
+ esi = 0;
+
+ if (argc==1) // no MAC given
+ {
+ r = mops_create_bpdu_bid (clipkt, pri, esi, NULL, 0); // 0 means BID (1 means RID)
+ }
+ else
+ r = mops_create_bpdu_bid (clipkt, pri, esi, argv[1], 0); // 0 means BID (1 means RID)
+
+
+ // Check return value
+ switch (r)
+ {
+ case 1:
+ cli_print(cli, "Priority must be within 0..15\n");
+ return CLI_OK;
+ break;
+ case 2:
+ cli_print(cli, "Extended System-ID must be within 0..4095\n");
+ return CLI_OK;
+ break;
+ case 3:
+ cli_print(cli, "Invalid MAC address or interface\n");
+ return CLI_OK;
+ break;
+ case 4:
+ cli_print(cli, "Invalid format - use ?\n");
+ return CLI_OK;
+ break;
+ }
+
+
+
+ //---------
+ // Verify:
+ bs2str(pd->bridge_id, p, 8);
+ cli_print(cli, "BID is now %s\n", p);
+ // -------
+ //
+ return CLI_OK;
+}
+
+
+
+
+
+int cmd_bpdu_pid (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ struct mops_ext_bpdu * pd = clipkt->p_desc;
+ u_int32_t i;
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc>1) )
+ {
+ cli_print(cli, "Specify the BPDU port identifier (0..65535)\r");
+ cli_print(cli, "\n");
+ return CLI_OK;
+ }
+
+ if (argc==0)
+ {
+ cli_print(cli, "Missing argument (use ?)\n");
+ return CLI_OK;
+ }
+
+ i = (u_int32_t) str2int (argv[0]);
+
+ if (i>0xffff)
+ {
+ cli_print(cli, "The port identifier must be within 0..65535\n");
+ return CLI_OK;
+ }
+
+ pd->port_id = (u_int16_t) i;
+
+ return CLI_OK;
+}
+
+//
+//
+// NOTE:
+//
+// All timers are multiples of 1/256 sec. Thus times range from 0 to 255 seconds.
+//
+//
+
+int cmd_bpdu_age (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ struct mops_ext_bpdu * pd = clipkt->p_desc;
+ u_int32_t i;
+ char str[256];
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc>2) )
+ {
+ mz_def16("0", pd->message_age, str);
+
+ cli_print(cli, "Specify the message age:\n");
+ cli_print(cli, " - either in seconds (0..256) e. g. '14 sec'\r");
+ cli_print(cli, " - or as multiples of 1/256 seconds (0..65535)\n");
+ cli_print(cli, "%s\n", str);
+ cli_print(cli, "\n");
+ return CLI_OK;
+ }
+
+ if (argc==0)
+ {
+ cli_print(cli, "Missing argument (use ?)\n");
+ return CLI_OK;
+ }
+
+ i = (u_int32_t) str2int (argv[0]);
+
+ if (argc==1) // absolute
+ {
+ if (i>0xffff)
+ cli_print(cli, "The age must be within 0..65535\n");
+ else
+ pd->message_age = (u_int16_t) i;
+ }
+ else if (mz_strcmp(argv[1], "seconds", 1)==0) // in seconds
+ {
+ if (i>256)
+ cli_print(cli, "The age must be within 0..256 seconds\n");
+ else
+ {
+ if (i==256)
+ i = 0xffff; // since 256*256=65536 which exceeds 0xffff but 65535/256 = 255.996
+ else
+ i = i * 256;
+
+ pd->message_age = (u_int16_t) i;
+ }
+
+ }
+ else
+ cli_print(cli, "Invalid argument\n");
+
+ return CLI_OK;
+
+}
+
+
+
+
+
+
+
+int cmd_bpdu_maxage (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ struct mops_ext_bpdu * pd = clipkt->p_desc;
+ u_int32_t i;
+ char str[256];
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc>2) )
+ {
+ mz_def16("20 seconds", pd->max_age, str);
+
+ cli_print(cli, "Specify the maximum message age:\n");
+ cli_print(cli, " - either in seconds (0..256) e. g. '20 sec'\r");
+ cli_print(cli, " - or as multiples of 1/256 seconds (0..65535)\n");
+ cli_print(cli, "%s\n", str);
+ cli_print(cli, "\n");
+ return CLI_OK;
+ }
+
+ if (argc==0)
+ {
+ cli_print(cli, "Missing argument (use ?)\n");
+ return CLI_OK;
+ }
+
+ i = (u_int32_t) str2int (argv[0]);
+
+ if (argc==1) // absolute
+ {
+ if (i>0xffff)
+ cli_print(cli, "The max age must be within 0..65535\n");
+ else
+ pd->max_age = (u_int16_t) i;
+ }
+ else if (mz_strcmp(argv[1], "seconds", 1)==0) // in seconds
+ {
+ if (i>256)
+ cli_print(cli, "The max age must be within 0..256 seconds\n");
+ else
+ {
+ if (i==256)
+ i = 0xffff; // since 256*256=65536 which exceeds 0xffff but 65535/256 = 255.996
+ else
+ i = i * 256;
+
+ pd->max_age = (u_int16_t) i;
+ }
+
+ }
+ else
+ cli_print(cli, "Invalid argument\n");
+
+ return CLI_OK;
+
+}
+
+
+
+
+
+int cmd_bpdu_hello (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ struct mops_ext_bpdu * pd = clipkt->p_desc;
+ u_int32_t i;
+ char str[256];
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc>2) )
+ {
+ mz_def16("2 seconds", pd->hello_time, str);
+
+ cli_print(cli, "Specify the hello interval:\n");
+ cli_print(cli, " - either in seconds (0..256) e. g. '2 sec'\r");
+ cli_print(cli, " - or as multiples of 1/256 seconds (0..65535)\n");
+ cli_print(cli, "%s\n", str); cli_print(cli, "\n");
+ return CLI_OK;
+ }
+
+ if (argc==0)
+ {
+ cli_print(cli, "Missing argument (use ?)\n");
+ return CLI_OK;
+ }
+
+
+ i = (u_int32_t) str2int (argv[0]);
+
+ if (argc==1) // absolute
+ {
+ if (i>0xffff)
+ cli_print(cli, "The hello interval must be within 0..65535\n");
+ else
+ pd->hello_time = (u_int16_t) i;
+ }
+ else if (mz_strcmp(argv[1], "seconds", 1)==0) // in seconds
+ {
+ if (i>256)
+ cli_print(cli, "The hello interval must be within 0..256 seconds\n");
+ else
+ {
+ if (i==256)
+ i = 0xffff; // since 256*256=65536 which exceeds 0xffff but 65535/256 = 255.996
+ else
+ i = i * 256;
+
+ pd->hello_time = (u_int16_t) i;
+ }
+
+ }
+ else
+ cli_print(cli, "Invalid argument\n");
+
+ return CLI_OK;
+
+}
+
+int cmd_bpdu_fwd (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ struct mops_ext_bpdu * pd = clipkt->p_desc;
+ u_int32_t i;
+ char str[256];
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc>2) )
+ {
+ mz_def16("15 seconds", pd->f_delay, str);
+
+ cli_print(cli, "Specify the forward delay:\n");
+ cli_print(cli, " - either in seconds (0..256) e. g. '15 sec'\r");
+ cli_print(cli, " - or as multiples of 1/256 seconds (0..65535)\n");
+ cli_print(cli, "%s\n", str);
+ cli_print(cli, "\n");
+ return CLI_OK;
+ }
+
+ if (argc==0)
+ {
+ cli_print(cli, "Missing argument (use ?)\n");
+ return CLI_OK;
+ }
+
+
+ i = (u_int32_t) str2int (argv[0]);
+
+ if (argc==1) // absolute
+ {
+ if (i>0xffff)
+ cli_print(cli, "The forward delay must be within 0..65535\n");
+ else
+ pd->f_delay = (u_int16_t) i;
+ }
+ else if (mz_strcmp(argv[1], "seconds", 1)==0) // in seconds
+ {
+ if (i>256)
+ cli_print(cli, "The forward delay must be within 0..256 seconds\n");
+ else
+ {
+ if (i==256)
+ i = 0xffff; // since 256*256=65536 which exceeds 0xffff but 65535/256 = 255.996
+ else
+ i = i * 256;
+
+ pd->f_delay = (u_int16_t) i;
+ }
+
+ }
+ else
+ cli_print(cli, "Invalid argument\n");
+
+ return CLI_OK;
+
+}
+
+
+
+int cmd_bpdu_mode (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ struct mops_ext_bpdu * pd = clipkt->p_desc;
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc>1) )
+ {
+ cli_print(cli, "Specify the BPDU mode using the keywords:\n");
+ cli_print(cli, " stp ...... IEEE 802.1d (traditional CST)\r");
+ cli_print(cli, " rstp ...... IEEE 802.1w (Rapid STP)\r");
+ cli_print(cli, " mstp ...... IEEE 802.1s (Multiple STP)\r");
+ cli_print(cli, " pvst ...... Cisco Per-VLAN STP\r");
+ cli_print(cli, " rpvst ...... Cisco Per-VLAN RSTP\r");
+ cli_print(cli, "\n");
+ return CLI_OK;
+ }
+
+ if (argc==0)
+ {
+ cli_print(cli, "Missing argument (use ?)\n");
+ return CLI_OK;
+ }
+
+
+ if (mz_strcmp(argv[0], "stp", 1)==0)
+ {
+ pd->version=0;
+ pd->rstp=0;
+ pd->pvst=0;
+ pd->mstp=0;
+ }
+ else if (mz_strcmp(argv[0], "rstp", 2)==0)
+ {
+ pd->version=2;
+ pd->rstp=1;
+ pd->mstp=0;
+ }
+ else if (mz_strcmp(argv[0], "mstp", 1)==0)
+ {
+ pd->version=3;
+ pd->mstp=1;
+ }
+ else if (mz_strcmp(argv[0], "pvst", 1)==0)
+ {
+ pd->version=0;
+ pd->pvst=1;
+ pd->rstp=0;
+ pd->mstp=0;
+ }
+ else if (mz_strcmp(argv[0], "rpvst", 2)==0)
+ {
+ pd->version=2;
+ pd->rstp=1;
+ pd->pvst=1;
+ pd->mstp=0;
+ }
+
+
+ // TODO: also change version to 2 if RSTP, 0 if legacy
+
+
+ return CLI_OK;
+}
+
+
+
+
+int cmd_bpdu_vlan(struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ u_int32_t i;
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc>1) )
+ {
+ cli_print(cli, "Specify the VLAN number for PVST+ messages (0..4095)\n");
+ cli_print(cli, "\n");
+ return CLI_OK;
+ }
+
+ if (argc==0)
+ {
+ cli_print(cli, "Missing argument (use ?)\n");
+ return CLI_OK;
+ }
+
+ i = (u_int32_t) str2int(argv[0]);
+
+ if (i>65535)
+ {
+ cli_print(cli, "VLAN number is definitely too large! (0..65535 at maximum)\n");
+ return CLI_OK;
+ }
+
+ if (i>4095)
+ {
+ cli_print(cli, "Warning: Invalid VLAN number (0..4095) - but let's try it...\n");
+ }
+
+ mops_create_bpdu_trailer(clipkt, (u_int16_t) i);
+
+ return CLI_OK;
+}
+
+
+
+int cmd_bpdu_end(struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ char prompt[16];
+ sprintf(prompt, "pkt-%i",clipkt->id);
+ cli_set_configmode(cli, MZ_MODE_PACKET, prompt);
+ return CLI_OK;
+}
+
diff --git a/staging/cli_cmds.c b/staging/cli_cmds.c
new file mode 100644
index 0000000..3304410
--- /dev/null
+++ b/staging/cli_cmds.c
@@ -0,0 +1,1428 @@
+/*
+ * Mausezahn - A fast versatile traffic generator
+ * Copyright (C) 2008-2010 Herbert Haas
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
+ *
+*/
+
+
+
+#include "mz.h"
+#include "cli.h"
+#include "mops.h"
+#include "llist.h"
+
+// Callback functions for the commands.
+// __FUNCTION__ contains the name of the current callback function (for troubleshootig)
+
+
+////////////////////////////////////////////////////////////////////////////////
+int cmd_test(struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ cli_print(cli, "called %s with %s\r\n", __FUNCTION__, command);
+ return CLI_OK;
+}
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+int debug_all (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ if ( strncmp(argv[argc-1], "?", 1) == 0)
+ {
+ cli_print(cli, "Will debug everything. (Be careful!)\n");
+ return CLI_OK;
+ }
+
+
+ cli_debug = 0x7fff;
+ cli_print(cli, "Debug all enabled - stop with undebug all\r");
+ cli_print(cli, "Note: _Already_ active packets will not be omitted!\n");
+
+ if (mz_strcmp(argv[argc-1], "dev", 3)==0)
+ {
+ cli_print(cli, "*** Developer mode debugging enabled ***\n");
+ cli_debug = 0xffff;
+ }
+
+ return CLI_OK;
+}
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Clear all _legacy_ Mausezahn settings (reinitialize anything)
+int clear_all(struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ if (argc) {
+ cli_print(cli, "No argument required! Try again.\n");
+ return CLI_OK;
+ }
+
+ reset();
+ cli_print(cli, "All legacy Mausezahn parts have been reinitialized.\r");
+ mops_delete_all(mp_head);
+ mops_reset_packet (mp_head);
+ cli_print(cli, "MOPS has been reinitialized.\n");
+ return CLI_OK;
+}
+
+
+int clear_packet(struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+
+ struct mops *cur;
+ u_int32_t i;
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc!=1) )
+ {
+ cli_print(cli, "Delete a single packet (i. e. MOPS entry).\r");
+ cli_print(cli, "Expects a single argument which is either a packet's ID or name.\r");
+ cli_print(cli, "NOTE: If the name matches an ID then the name has higher preference.\n");
+ return CLI_OK;
+ }
+
+
+ if (argc!=1) {
+ cli_print(cli, "Please specify only the packets ID or name\n");
+ return CLI_OK;
+ }
+
+ cur = mops_search_name (mp_head, argv[0]);
+ if (cur==NULL) {
+ i = (u_int32_t) str2int (argv[0]);
+ cur = mops_search_id (mp_head, i);
+ if (cur==NULL) {
+ cli_print(cli, "No packet found with that ID or name!\n");
+ return CLI_OK;
+ }
+ }
+ clipkt = mops_delete_packet(cur);
+ cli_print(cli, "Packet deleted.\n");
+ return CLI_OK;
+}
+
+
+int cmd_reset_packet(struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ struct mops *cur;
+ u_int32_t i;
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc!=1) )
+ {
+ cli_print(cli, "Resets a single packet (i. e. MOPS entry).\r");
+ cli_print(cli, "Expects a single argument which is either a packet's ID or name.\r");
+ cli_print(cli, "NOTE: If the name matches an ID then the name has higher preference.\n");
+ return CLI_OK;
+ }
+
+
+ if (argc!=1) {
+ cli_print(cli, "Please specify only the packets ID or name\n");
+ return CLI_OK;
+ }
+
+ cur = mops_search_name (mp_head, argv[0]);
+ if (cur==NULL) {
+ i = (u_int32_t) str2int (argv[0]);
+ cur = mops_search_id (mp_head, i);
+ if (cur==NULL) {
+ cli_print(cli, "No packet found with that ID or name!\n");
+ return CLI_OK;
+ }
+ }
+
+ mops_reset_packet(cur);
+ cli_print(cli, "New packet name: %s\n", cur->packet_name);
+ return CLI_OK;
+}
+
+
+
+
+int show_system(struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ cli_print(cli, "Not supported in this version\n");
+ return CLI_OK;
+}
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Run through packet list and print some details about existing packets.
+// SYNTAX:
+//
+// show packet
+// show packet MyPacket
+//
+int show_packets(struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ int a=0, i, j=0, k, v, active_only=0;
+ u_int32_t t;
+ char c,T;
+ char name[32], ds[16], pr[16], ps[16];
+ char myframe[MAX_MOPS_FRAME_SIZE*3];
+ char mystate[32];
+ char line[150], line2[150], line3[150];
+ char delay_str[64];
+ unsigned char *x0, *x1, *x2, *x3;
+
+ struct mops *head = mp_head;
+ struct mops *mp = mp_head;
+
+
+ if (strncmp(argv[argc-1], "?", 2)==0) {
+ cli_print(cli, "<CR> Show list of all defined packets\r");
+ cli_print(cli, "active Only show active packets\r");
+ cli_print(cli, "<PKT_ID> Show detailed info about given packet\r");
+//TODO cli_print(cli, "type <proto> Only list packets r");
+ cli_print(cli, "\n");
+ return CLI_OK;
+ }
+
+ if (argc==1) {
+ if (mz_strcmp(argv[0], "active", 1)==0) {
+ active_only=1;
+ }
+ }
+
+ if ((argc==0) || (active_only)) // show packet summary
+ {
+ cli_print(cli, "Packet layer flags: E=Ethernet, S=SNAP, Q=802.1Q, M=MPLS, I/i=IP/delivery_off, U=UDP, T=TCP\n");
+ cli_print(cli, "PktID PktName Layers Proto Size State Device Delay Count/CntX\n");
+
+ do
+ {
+ if (active_only) {
+ if (mp->state < MOPS_STATE_ACTIVE) {
+ mp = mp->next;
+ j++;
+ continue;
+ }
+ }
+
+ ds[0]='\0';
+ ps[0]='\0';
+ pr[0]='\0';
+
+ if (mp->use_ETHER) strcat(ds,"E"); else strcat(ds,"-");
+ if (mp->use_SNAP) strcat(ds,"S"); else strcat(ds,"-");
+ if (mp->use_dot1Q) strcat(ds,"Q"); else strcat(ds,"-");
+ if (mp->use_MPLS) strcat(ds,"M"); else strcat(ds,"-");
+ if (mp->use_IP) {
+ if (mp->auto_delivery_off)
+ strcat(ds,"i");
+ else
+ strcat(ds,"I");
+ } else strcat(ds,"-");
+
+ if (mp->use_UDP)
+ strcat(ds,"U");
+ else if
+ (mp->use_TCP) strcat(ds,"T");
+ else strcat(ds,"-");
+
+
+
+ switch (mp->p_desc_type)
+ {
+ case MOPS_ARP:
+ strncpy(pr, "ARP", 8);
+ break;
+ case MOPS_BPDU:
+ strncpy(pr, "BPDU", 8);
+ break;
+ case MOPS_CDP:
+ strncpy(pr, "CDP", 8);
+ break;
+ case MOPS_DNS:
+ strncpy(pr, "DNS", 8);
+ break;
+ case MOPS_ICMP:
+ strncpy(pr, "ICMP", 8);
+ break;
+ case MOPS_IGMP:
+ strncpy(pr, "IGMP", 8);
+ break;
+ case MOPS_LLDP:
+ strncpy(pr, "LLDP", 8);
+ break;
+ case MOPS_RTP:
+ strncpy(pr, "RTP", 8);
+ break;
+ case MOPS_SYSLOG:
+ strncpy(pr, "SYSLOG", 8);
+ break;
+ default:
+ break;
+ }
+
+
+ switch (mops_state(mp))
+ {
+ case MOPS_STATE_NULL:
+ strcat(ps, "NULL"); // should never happen!
+ break;
+ case MOPS_STATE_INIT:
+ strcat(ps, "init");
+ break;
+ case MOPS_STATE_CONFIG:
+ strcat(ps, "config");
+ break;
+ case MOPS_STATE_ACTIVE:
+ strcat(ps, "active");
+ a++;
+ break;
+ case MOPS_STATE_SEQACT:
+ strcat(ps, "actseq");
+ a++;
+ break;
+ default:
+ strcat(ps, "unknown");
+ break;
+ }
+
+ switch (mp->interval_used) {
+ case 1: // interval only configured, not started
+ strncat(ps, "-i", 2);
+ break;
+
+ case 2:
+ strncat(ps, "+I", 2);
+ break;
+ default:
+ break;
+ }
+
+
+ strncpy (name, mp->packet_name, 13); // only show first 13 chars
+
+ if (strnlen(mp->packet_name, MAX_MOPS_PACKET_NAME_LEN)>13)
+ {
+ name[13]=0x00;
+ strcat(name, "...");
+ }
+
+ // To determine the actual packet length ***
+ // we must reassemble everything: ***
+ mops_ext_update (mp);
+ mops_update (mp);
+
+ timespec2str(&mp->ndelay, delay_str);
+
+ // ID name lrs prot size state dev del count/cntx/%
+ sprintf(line, "%5i %-16s %s %-8s %4i %-9s %-6s %10s%9lu/%lu (%i%%)\r",
+ mp->id, // ID
+ name, // packet_name
+ ds, // layers
+ pr, // protocol
+ mp->frame_s, // size
+ ps, // state
+ mp->device, // device
+ delay_str, // delay
+ mp->count, // Configured count value
+ mp->cntx, // Current count
+ (mp->count) ? (int) (100 * (mp->count - mp->cntx)/mp->count) : 0 );
+ cli_print(cli, "%s\r", line);
+ mp = mp->next;
+ j++;
+ }
+ while (head != mp);
+
+ cli_print(cli, "\r");
+ cli_print(cli, "%i packets defined, %i active.\n", j, a);
+ }
+ //////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ //////////////////////////////////////////////////////////////////////////////////////////////////////////
+ else if (argc == 1) // show details about a specific packet **********************************************
+ {
+ if ( (mp = mops_search_name (mp_head, argv[0])) == NULL)// not found
+ {
+ if ( (mp = mops_search_id (mp_head, (int) str2int(argv[0]))) == NULL)// not found
+ {
+ cli_print (cli, "Packet not in list.\n");
+ return CLI_OK;
+ }
+ }
+
+ // To determine the actual packet length ***
+ // we must reassemble everything: ***
+ mops_ext_update (mp);
+ mops_update (mp);
+
+ cli_print(cli, "Packet [%i] %s\r", mp->id, mp->packet_name);
+ cli_print(cli, " Description: %s \r",
+ (strnlen(mp->description, MAX_MOPS_DESCRIPTION_LEN)) ? mp->description : "(no description)");
+
+ switch(mp->state)
+ {
+ case MOPS_STATE_NULL:
+ sprintf(mystate, "NULL");
+ break;
+ case MOPS_STATE_INIT:
+ sprintf(mystate, "init");
+ break;
+ case MOPS_STATE_CONFIG:
+ sprintf(mystate, "config");
+ break;
+ case MOPS_STATE_ACTIVE:
+ sprintf(mystate, "active(tx)");
+ break;
+ default:
+ sprintf(mystate, "unknown");
+ }
+
+ timespec2str(&mp->ndelay, delay_str);
+ if (mp->interval_used)
+ timespec2str(&mp->interval, line2);
+ else
+ sprintf(line2, "(undefined)");
+
+ sprintf(line, "State: %s, Count=%lu, delay=%s (%lu s %lu nsec), interval= %s\r",
+ mystate,
+ mp->count,
+ delay_str,
+ mp->ndelay.tv_sec,
+ mp->ndelay.tv_nsec,
+ line2);
+ cli_print(cli, " %s\r", line);
+
+ cli_print(cli, " Headers:\r");
+ i=0;
+ if (mp->use_ETHER)
+ {
+ if (mp->eth_src_israndom)
+ {
+ cli_print(cli, " Ethernet: *** RANDOMIZED SMAC *** => %02x-%02x-%02x-%02x-%02x-%02x [%04x%s]\r",
+ mp->eth_dst[0],mp->eth_dst[1],mp->eth_dst[2],mp->eth_dst[3],mp->eth_dst[4],mp->eth_dst[5],
+ mp->eth_type, (mp->use_dot1Q) ? " after 802.1Q tag" : "");
+ }
+ else
+ {
+ cli_print(cli, " Ethernet: %02x-%02x-%02x-%02x-%02x-%02x => %02x-%02x-%02x-%02x-%02x-%02x [%04x%s]\r",
+ mp->eth_src[0],mp->eth_src[1],mp->eth_src[2],mp->eth_src[3],mp->eth_src[4],mp->eth_src[5],
+ mp->eth_dst[0],mp->eth_dst[1],mp->eth_dst[2],mp->eth_dst[3],mp->eth_dst[4],mp->eth_dst[5],
+ mp->eth_type, (mp->use_dot1Q) ? " after 802.1Q tag" : "");
+ }
+
+ if (mp->use_IP) {
+ if (mp->auto_delivery_off)
+ cli_print(cli, " NOTE: Auto-delivery is OFF (that is, the destination MAC is fixed)\r");
+ else
+ cli_print(cli, " Auto-delivery is ON (that is, the actual MAC is determined upon transmission)\r");
+ }
+ i++;
+ }
+ if (mp->use_SNAP)
+ {
+ bs2str(clipkt->eth_snap, line, clipkt->eth_snap_s);
+ cli_print(cli, " LLC/SNAP: %s\r", line);
+ i++;
+ }
+ if (mp->use_dot1Q)
+ {
+ k = clipkt->dot1Q_s/4; // number of tags
+ sprintf(line, "%i tag(s); ", k);
+ for (j=0; j<k; j++)
+ { // tag format = 0x81 0x00 cosTvvvv vvvvvvvv
+ // x0 x1
+ x0 = (unsigned char*) &clipkt->dot1Q[(j*4)+2];
+ x1 = (unsigned char*) &clipkt->dot1Q[(j*4)+3];
+ v = (*x0 & 0x0f)*256 + *x1; // VLAN
+// c = *x0 & 0xe0; // CoS e0=11100000
+ c = *x0 >> 5;
+ sprintf(ds, "%i:%i%s",
+ v,
+ (unsigned char) c,
+ (*x0 & 0x10) ? "[CFI]" : ""); // CFI
+ strncat(line, ds, 14);
+ if (j<(k-1)) strcat(line, ", ");
+ }
+
+ cli_print(cli, " 802.1Q: %s (VLAN:CoS)\r", line);
+ i++;
+ }
+ if (mp->use_MPLS)
+ {
+ k = clipkt->mpls_s/4; // number of tags
+ sprintf(line, "%i tag(s); ", k);
+ for (j=0; j<k; j++)
+ { // tag format = llllllll llllllll llllcccB TTTTTTTT
+ x0 = (unsigned char*) &clipkt->mpls[(j*4)+0];
+ x1 = (unsigned char*) &clipkt->mpls[(j*4)+1];
+ x2 = (unsigned char*) &clipkt->mpls[(j*4)+2];
+ x3 = (unsigned char*) &clipkt->mpls[(j*4)+3];
+ t = *x0;
+ t <<= 12;
+ t += *x1 * 16;
+ t += (*x2 & 0xf0) >> 4;
+ c = (*x2 & 0x0e) >> 1;
+ T = *x3;
+ sprintf(ds, "%i:%i:%i%s",
+ t,
+ (unsigned char) c,
+ (unsigned char) T,
+ (*x2 & 0x01) ? "[BoS]" : ""); // Bottom of Stack?
+ strncat(line, ds, 20);
+ if (j<(k-1)) strcat(line, ", ");
+ }
+
+ cli_print(cli, " MPLS: %s (Label:CoS:TTL)\r", line);
+
+ i++;
+ }
+ if (mp->use_IP)
+ {
+ // Source IP settings:
+ x0 = (unsigned char*) & clipkt->ip_src;
+ line2[0]=0x00;
+ if (clipkt->ip_src_isrange)
+ {
+ x1 = (unsigned char*) & clipkt->ip_src_start;
+ x2 = (unsigned char*) & clipkt->ip_src_stop;
+ sprintf(line2, "%u.%u.%u.%u-%u.%u.%u.%u",
+ (unsigned char) *(x1+3), (unsigned char) *(x1+2), (unsigned char) *(x1+1) , (unsigned char) *x1,
+ (unsigned char) *(x2+3), (unsigned char) *(x2+2), (unsigned char) *(x2+1) , (unsigned char) *x2);
+ }
+ sprintf(line, "SA=%u.%u.%u.%u %s %s %s",
+ (unsigned char) *(x0+3), (unsigned char) *(x0+2), (unsigned char) *(x0+1) , (unsigned char) *x0,
+ (clipkt->ip_src_israndom) ? "RANDOM" : "(not random)",
+ (clipkt->ip_src_isrange) ? "RANGE:" : "(no range)",
+ line2);
+
+ cli_print(cli, " IP: %s\r", line);
+ //Destination IP settings:
+ x0 = (unsigned char*) & clipkt->ip_dst;
+ line2[0]=0x00;
+ if (clipkt->ip_dst_isrange)
+ {
+ x1 = (unsigned char*) & clipkt->ip_dst_start;
+ x2 = (unsigned char*) & clipkt->ip_dst_stop;
+ sprintf(line2, "%u.%u.%u.%u-%u.%u.%u.%u",
+ (unsigned char) *(x1+3), (unsigned char) *(x1+2), (unsigned char) *(x1+1) , (unsigned char) *x1,
+ (unsigned char) *(x2+3), (unsigned char) *(x2+2), (unsigned char) *(x2+1) , (unsigned char) *x2);
+ }
+
+ sprintf(line, "DA=%u.%u.%u.%u %s %s",
+ (unsigned char) *(x0+3), (unsigned char) *(x0+2), (unsigned char) *(x0+1) , (unsigned char) *x0,
+ (clipkt->ip_dst_isrange) ? "RANGE:" : "(no range)",
+ line2);
+ cli_print(cli, " %s\r", line);
+
+ sprintf(line, "ToS=0x%02x proto=%u TTL=%u ID=%u offset=%u flags: %s|%s|%s",
+ clipkt->ip_tos, clipkt->ip_proto, clipkt->ip_ttl, clipkt->ip_id, clipkt->ip_frag_offset,
+ (clipkt->ip_flags_RS) ? "RS" : "-",
+ (clipkt->ip_flags_DF) ? "DF" : "-",
+ (clipkt->ip_flags_MF) ? "MF" : "-");
+
+ cli_print(cli, " %s\r", line);
+
+ if (clipkt->ip_fragsize) {
+ sprintf(line, "NOTE: Auto-fragmentation is ON! Fragment size %u bytes, overlap %u",
+ clipkt->ip_fragsize,
+ clipkt->ip_frag_overlap);
+ cli_print(cli, " %s\r", line);
+ }
+
+ sprintf(line, "len=%u(%s) checksum=0x%02x%02x(%s)",
+ clipkt->frame[clipkt->begin_IP+2]*256+clipkt->frame[clipkt->begin_IP+3],
+ (clipkt->ip_len_false) ? "false" : "correct",
+ clipkt->frame[clipkt->begin_IP+10],
+ clipkt->frame[clipkt->begin_IP+11],
+ (clipkt->ip_sum_false) ? "false" : "correct");
+
+ cli_print(cli, " %s\r", line);
+
+ i++;
+ }
+ if (mp->use_UDP)
+ {
+ if (clipkt->sp_isrange)
+ sprintf(line2, "RANGE: %u-%u", clipkt->sp_start, clipkt->sp_stop);
+ else
+ sprintf(line2, "(norange)");
+ if (clipkt->dp_isrange)
+ sprintf(line3, "RANGE: %u-%u", clipkt->dp_start, clipkt->dp_stop);
+ else
+ sprintf(line3, "(norange)");
+ sprintf(line, "SP=%i %s %s, DP=%i %s %s\r",
+ clipkt->sp,
+ line2,
+ (clipkt->sp_isrand) ? "RANDOM" : "(not random)",
+ clipkt->dp,
+ line3,
+ (clipkt->dp_isrand) ? "RANDOM" : "(not random)");
+ cli_print(cli, " UDP: %s\r", line);
+ sprintf(line, "checksum= %04x (%s), length= %u (%s)",
+ clipkt->udp_sum, (clipkt->udp_sum_false) ? "false" : "correct",
+ clipkt->udp_len, (clipkt->udp_len_false) ? "false" : "correct");
+ cli_print(cli, " %s\r", line);
+ i++;
+ }
+ if (mp->use_TCP)
+ {
+ sprintf(line, "%u bytes segment size (including TCP header)", mp->tcp_len);
+ cli_print(cli, " TCP: %s\r", line);
+ if (clipkt->sp_isrange)
+ sprintf(line2, "RANGE: %u-%u", clipkt->sp_start, clipkt->sp_stop);
+ else
+ sprintf(line2, "(norange)");
+ if (clipkt->dp_isrange)
+ sprintf(line3, "RANGE: %u-%u", clipkt->dp_start, clipkt->dp_stop);
+ else
+ sprintf(line3, "(norange)");
+ sprintf(line, "SP=%i %s %s, DP=%i %s %s\r",
+ clipkt->sp,
+ line2,
+ (clipkt->sp_isrand) ? "RANDOM" : "(not random)",
+ clipkt->dp,
+ line3,
+ (clipkt->dp_isrand) ? "RANDOM" : "(not random)");
+ cli_print(cli, " %s\r", line);
+ sprintf(line, "SQNR=%u (start %u, stop %u, delta %u) -- ACKNR=%u %s",
+ clipkt->tcp_seq,
+ clipkt->tcp_seq_start,
+ clipkt->tcp_seq_stop,
+ clipkt->tcp_seq_delta,
+ clipkt->tcp_ack,
+ (clipkt->tcp_ctrl_ACK) ? "(valid)" : "(invalid)");
+ cli_print(cli, " %s\r", line);
+ mops_tcp_flags2str(clipkt,line2);
+ sprintf(line, "Flags: %s, reserved field is %02x, urgent pointer= %u",
+ line2,
+ clipkt->tcp_res,
+ clipkt->tcp_urg);
+ cli_print(cli, " %s\r", line);
+ sprintf(line, "Announced window size= %u", clipkt->tcp_win);
+ cli_print(cli, " %s\r", line);
+ sprintf(line, "Offset= %u (times 32 bit; value is %s), checksum= %04x (%s)",
+ clipkt->tcp_offset,
+ (clipkt->tcp_offset_false) ? "FALSE" : "valid",
+ clipkt->tcp_sum,
+ (clipkt->tcp_sum_false) ? "FALSE" : "valid");
+ cli_print(cli, " %s\r", line);
+ sprintf(line, "%s - %u bytes defined",
+ (clipkt->tcp_option_used) ? "TCP options attached" : "(No TCP options attached)",
+ clipkt->tcp_option_s);
+ cli_print(cli, " %s\r", line);
+ i++;
+ }
+
+ if (!i) cli_print(cli, " No headers defined.\r");
+
+ if (mp->msg_s) {
+ cli_print(cli, " Payload size: %i bytes\r", mp->msg_s);
+ }
+
+ cli_print(cli, " Frame size: %i bytes\n", mp->frame_s);
+
+ mops_print_frame(mp, myframe);
+ cli_print(cli, "%s\n", myframe);
+ }
+
+ return CLI_OK;
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+int show_interfaces (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ int i, j=0;
+ char line[100];
+ char ip[20];
+
+
+ if (strncmp(argv[argc-1], "?", 2)==0) {
+ cli_print(cli, "<CR> Show summary list of all interfaces found\r");
+ cli_print(cli, "detailed Additionally show network, mask, default gatway, and MTU\r");
+ cli_print(cli, "\n");
+ return CLI_OK;
+ }
+
+ // Some safety checks
+ if (argc>1) return CLI_OK;
+ if (argc==1) {
+ if (mz_strcmp(argv[0], "detailed", 1)!=0) {
+ cli_print(cli, "invalid keyword (use ?)\n");
+ return CLI_OK;
+ }
+ }
+
+ /* Refresh interface data */
+
+ lookupdev();
+
+ for (i=0; i<device_list_entries; i++) {
+ get_dev_params(device_list[i].dev);
+ }
+
+
+
+ /* No additional keyword */
+ if (argc==0) {
+ cli_print(cli, "Available network interfaces:\n");
+ cli_print(cli, " real real used (fake) used (fake)\r");
+ cli_print(cli, " device IPv4 address MAC address IPv4 address MAC address\r");
+ cli_print(cli, "---------------------------------------------------------------------------------------\r");
+ for (i=0; i<device_list_entries; i++) {
+ sprintf(ip,"%u.%u.%u.%u",
+ device_list[i].ip_mops[0],
+ device_list[i].ip_mops[1],
+ device_list[i].ip_mops[2],
+ device_list[i].ip_mops[3]);
+
+ sprintf(line, "%-10s %-15s %02x:%02x:%02x:%02x:%02x:%02x %-15s %02x:%02x:%02x:%02x:%02x:%02x",
+ device_list[i].dev, device_list[i].ip_str,
+ device_list[i].mac[0],
+ device_list[i].mac[1],
+ device_list[i].mac[2],
+ device_list[i].mac[3],
+ device_list[i].mac[4],
+ device_list[i].mac[5],
+ ip,
+ device_list[i].mac_mops[0],
+ device_list[i].mac_mops[1],
+ device_list[i].mac_mops[2],
+ device_list[i].mac_mops[3],
+ device_list[i].mac_mops[4],
+ device_list[i].mac_mops[5]
+ );
+
+
+ if (strncmp(device_list[i].dev, tx.device, 16)==0) {
+ cli_print(cli, "%s%s> %s\r",
+ (device_list[i].cli) ? "C" : " ",
+ (device_list[i].mgmt_only) ? "!" : "",
+ line);
+ j=i;
+ }
+ else
+ cli_print(cli, "%s%s %s\r",
+ (device_list[i].cli) ? "C" : " ",
+ (device_list[i].mgmt_only) ? "M" : "",
+ line);
+ }
+ }
+ /////////////////////////
+ else
+
+ /* keyword detailed used */
+ if (mz_strcmp(argv[0], "detailed", 1)==0) {
+ cli_print(cli, "Detailed interface list:\n");
+ for (i=0; i<device_list_entries; i++) {
+ sprintf(line, "interface %s [%i] %s%stype %s, MTU=%i bytes", // general HW info
+ device_list[i].dev,
+ device_list[i].index,
+ (device_list[i].cli) ? "[cli] " : "",
+ (device_list[i].mgmt_only) ? "[management-only] " : "",
+ (device_list[i].phy) ? "physical" : "software",
+ device_list[i].mtu);
+ cli_print(cli,"%s\r",line);
+ sprintf(line, "MAC bia: %02x:%02x:%02x:%02x:%02x:%02x\n MAC fake: %02x:%02x:%02x:%02x:%02x:%02x",
+ device_list[i].mac[0],
+ device_list[i].mac[1],
+ device_list[i].mac[2],
+ device_list[i].mac[3],
+ device_list[i].mac[4],
+ device_list[i].mac[5],
+ device_list[i].mac_mops[0],
+ device_list[i].mac_mops[1],
+ device_list[i].mac_mops[2],
+ device_list[i].mac_mops[3],
+ device_list[i].mac_mops[4],
+ device_list[i].mac_mops[5]);
+ cli_print(cli," %s\r",line);
+ sprintf(line,"IP addr: %s mask %u.%u.%u.%u (net %u.%u.%u.%u)",
+ device_list[i].ip_str,
+ device_list[i].mask[0],
+ device_list[i].mask[1],
+ device_list[i].mask[2],
+ device_list[i].mask[3],
+ device_list[i].net[0],
+ device_list[i].net[1],
+ device_list[i].net[2],
+ device_list[i].net[3]);
+ cli_print(cli," %s\r",line);
+ sprintf(line,"IP fake: %u.%u.%u.%u",
+ device_list[i].ip_mops[0],
+ device_list[i].ip_mops[1],
+ device_list[i].ip_mops[2],
+ device_list[i].ip_mops[3]);
+ cli_print(cli, " %s\r", line);
+ sprintf(line,"GW addr: %u.%u.%u.%u (%02x:%02x:%02x:%02x:%02x:%02x)",
+ device_list[i].ip_gw[0],
+ device_list[i].ip_gw[1],
+ device_list[i].ip_gw[2],
+ device_list[i].ip_gw[3],
+ device_list[i].mac_gw[0],
+ device_list[i].mac_gw[1],
+ device_list[i].mac_gw[2],
+ device_list[i].mac_gw[3],
+ device_list[i].mac_gw[4],
+ device_list[i].mac_gw[5]);
+ cli_print(cli," %s\n",line);
+ }
+ }
+
+ /* In any case, print final summary line: */
+ cli_print(cli, "\n%i interfaces found.\nDefault interface is %s.\n",
+ device_list_entries, device_list[j].dev);
+
+ return CLI_OK;
+}
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+int show_set(struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ unsigned char *x;
+ char hexload[3*MAX_PAYLOAD_SIZE];
+
+ cli_print(cli, "----- Packet parameters: ------ -------- Value: ----------\r");
+ cli_print(cli, "Source MAC address (sa) %02x:%02x:%02x:%02x:%02x:%02x [%s]\r",
+ tx.eth_src[0], tx.eth_src[1], tx.eth_src[2],
+ tx.eth_src[3], tx.eth_src[4], tx.eth_src[5],
+ (tx.eth_src_rand) ? "rand" : "spec");
+ cli_print(cli, "Basic MAC address %02x:%02x:%02x:%02x:%02x:%02x\r",
+ tx.eth_mac_own[0], tx.eth_mac_own[1], tx.eth_mac_own[2],
+ tx.eth_mac_own[3], tx.eth_mac_own[4], tx.eth_mac_own[5]);
+ cli_print(cli, "Destination MAC address (da) %02x:%02x:%02x:%02x:%02x:%02x [%s]\r",
+ tx.eth_dst[0], tx.eth_dst[1], tx.eth_dst[2],
+ tx.eth_dst[3], tx.eth_dst[4], tx.eth_dst[5],
+ (tx.eth_dst_rand) ? "rand" : "spec");
+ cli_print(cli, "\r");
+ x = (unsigned char *) &tx.ip_src;
+ cli_print(cli, "Source IP address (SA) %i.%i.%i.%i [%s]\r",
+ *x,*(x+1),*(x+2),*(x+3),
+ (tx.ip_src_rand) ? "rand" : "spec");
+
+ if (tx.ip_src_isrange)
+ {
+ x = (unsigned char *) &tx.ip_src_start;
+ cli_print(cli, "Source IP range start: %i.%i.%i.%i\r",
+ *(x+3), *(x+2), *(x+1), *x);
+ x = (unsigned char *) &tx.ip_src_stop;
+ cli_print(cli, "Source IP range stop: %i.%i.%i.%i\r",
+ *(x+3), *(x+2), *(x+1), *x);
+ }
+ else
+ {
+ cli_print(cli, "No source IP range specified\r");
+ }
+ x = (unsigned char *) &tx.ip_dst;
+ cli_print(cli, "Destination IP address (DA) %i.%i.%i.%i\r",
+ *x,*(x+1),*(x+2),*(x+3));
+
+ if (tx.ip_dst_isrange)
+ {
+ x = (unsigned char *) &tx.ip_dst_start;
+ cli_print(cli, "Destination IP range start: %i.%i.%i.%i\r",
+ *(x+3), *(x+2), *(x+1), *x);
+ x = (unsigned char *) &tx.ip_dst_stop;
+ cli_print(cli, "Destination IP range stop: %i.%i.%i.%i\r",
+ *(x+3), *(x+2), *(x+1), *x);
+ }
+ else
+ {
+ cli_print(cli, "No destination IP range specified\r");
+ }
+
+ if (tx.dot1Q)
+ {
+ cli_print(cli, "802.1Q tags specified: %s\r", tx.dot1Q_txt);
+ }
+
+ if (tx.mpls)
+ {
+ cli_print(cli, "MPLS labels specified: %s\r", tx.mpls_txt);
+ }
+
+ if (tx.ascii)
+ { cli_print(cli, "\r");
+ cli_print(cli, "---- ASCII payload is set: ----- \r");
+ cli_print(cli, ">>>%s<<<\r", tx.ascii_payload);
+ cli_print(cli, "-------------------------------- \n");
+ }
+
+ if (tx.hex_payload_s)
+ { cli_print(cli, "\r");
+ cli_print(cli, "---- Hexadecimal payload is set: ----- \r");
+ bs2str(tx.hex_payload, hexload, tx.hex_payload_s);
+ cli_print(cli, "%s\r", hexload);
+ cli_print(cli, "-------------------------------------- \n");
+ }
+
+ if (tx.padding)
+ {
+ cli_print(cli, "Configured padding: %u\r", tx.padding);
+ }
+
+ cli_print(cli, "\r");
+ cli_print(cli, "Packet count value %u\r", tx.count);
+ cli_print(cli, "Interpacket delay (usec) %u\r", tx.delay);
+ cli_print(cli, "\r");
+ cli_print(cli, "Used network device(s): %s\r", tx.device);
+ cli_print(cli, "\n");
+ return CLI_OK;
+}
+
+
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+int stop_mausezahn (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ if (strncmp(argv[argc-1], "?", 2)==0) {
+ cli_print(cli, "now Terminate the mausezahn server! BEWARE!\n");
+ return CLI_OK;
+ }
+
+ if (argc!=1) {
+ cli_print(cli, "The only allowed argument is 'now' -- anything else is ignored\n");
+ return CLI_OK;
+ }
+
+ if (mz_strcmp(argv[0], "now", 3)==0) {
+ cli_print(cli, "Good bye...\n");
+ cli_done(cli);
+ clean_up(0);
+ return CLI_OK;
+ } else {
+ cli_print(cli, "Invalid argument. If you want to stop the Mausezahn server then\r");
+ cli_print(cli, "enter 'terminate now'. You cannot abbreviate the argument 'now'. \n");
+ }
+
+ return CLI_OK;
+}
+
+
+
+
+int cmd_run_id (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ int i, slot;
+ struct mops *mp;
+
+ if (argc == 0) {
+ cli_print(cli, "Specify one or more packet identifiers to run.\n");
+ return CLI_OK;
+ }
+
+ if ( strncmp(argv[argc-1], "?", 1) == 0) {
+ cli_print(cli, "Run packet transmission processes for given list of packet identifiers\n");
+ return CLI_OK;
+ }
+
+ // User provided packet id numbers
+ if (argc > 0) {
+ for (i=0; i<argc; i++) {
+ slot = (int) str2int(argv[i]);
+ if ( (mp = mops_search_id (mp_head, slot)) == NULL) { // not found
+ cli_print (cli, "Packet %i not in list.\n", slot );
+ return CLI_OK;
+ }
+ else {
+ switch (mops_tx_simple (mp)) {
+ case 1:
+ cli_print(cli, "Cannot create sending process.\r");
+ return CLI_OK;
+ break;
+ case 3:
+ cli_print(cli, "Packet [%i] has already an active sending process\r", mp->id);
+ return CLI_OK;
+ break;
+ default:
+ cli_print (cli, "Activate [%i] ", slot );
+ break;
+ }
+ }
+ }
+ cli_print (cli, "\n");
+ }
+ return CLI_OK;
+}
+
+
+int cmd_run_name (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ int i;
+ struct mops *mp;
+
+ if (argc == 0) {
+ cli_print(cli, "Specify one or more packet name(s) to run.\n");
+ return CLI_OK;
+ }
+
+ if ( strncmp(argv[argc-1], "?", 1) == 0) {
+ cli_print(cli, "Run packet transmission processes for specified packet name(s).\n");
+ return CLI_OK;
+ }
+
+ if (argc > 0) {
+ for (i=0; i<argc; i++) {
+ if ( (mp = mops_search_name (mp_head, argv[i])) == NULL) { // not found
+ cli_print (cli, "Packet %s not in list.\n", argv[i]);
+ return CLI_OK;
+ }
+ else {
+ switch (mops_tx_simple (mp)) {
+ case 1:
+ cli_print(cli, "Cannot create sending process.\r");
+ return CLI_OK;
+ break;
+ case 3:
+ cli_print(cli, "Packet [%i] has already an active sending process\r", mp->id);
+ return CLI_OK;
+ break;
+ default:
+ cli_print (cli, "Activate [%i] ", mp->id );
+ break;
+ }
+ }
+ }
+ cli_print (cli, "\n");
+ }
+ return CLI_OK;
+}
+
+
+int cmd_run_sequence (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ struct mz_ll *cur;
+ int ret=0;
+ if (argc != 1) {
+ cli_print(cli, "Specify one (and only one) packet sequence name to run.\n");
+ return CLI_OK;
+ }
+
+ if ( strncmp(argv[argc-1], "?", 1) == 0) {
+ cli_print(cli, "Run sequence transmission processes for specified sequence name.\n");
+ return CLI_OK;
+ }
+
+ cur = mz_ll_search_name (packet_sequences, argv[0]);
+ if (cur==NULL) { // NOT FOUND !!!
+ cli_print(cli, "Sequence %s does not exist.", argv[0]);
+ return CLI_OK;
+ }
+ ret = mops_tx_sequence(cur);
+ switch (ret) {
+ case 0: cli_print(cli, "Sequence %s is runnning\n", cur->name);
+ break;
+ case 1: cli_print(cli, "Cannot run sequence: All packets must be in config state!\n");
+ break;
+ case 2: cli_print(cli, "Cannot run sequence: All packets must have a finite count!\n");
+ break;
+ case 3: cli_print(cli, "Cannot run sequence: Unable to start sequence transmission process.\n");
+ break;
+ }
+ return CLI_OK;
+}
+
+
+
+int cmd_run_all (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ int i;
+ struct mops *mp;
+ struct mops *head;
+
+ if ( strncmp(argv[argc-1], "?", 1) == 0) {
+ cli_print(cli, "Run all user-specified packets.\n");
+ return CLI_OK;
+ }
+
+ if (argc>0) {
+ cli_print(cli, "No arguments expected!\n");
+ return CLI_OK;
+ }
+
+ // Send all valid packets
+ i=0;
+ head = mp_head;
+ mp = mp_head;
+ do {
+ if ((mp->mz_system==0) && (mops_state(mp) == MOPS_STATE_CONFIG)) {
+ switch (mops_tx_simple (mp)) {
+ case 1:
+ cli_print(cli, "Cannot create sending process.\r");
+ return CLI_OK;
+ break;
+ case 3:
+ cli_print(cli, "Packet [%i] has already an active sending process\r", mp->id);
+ return CLI_OK;
+ break;
+ default:
+ break;
+ }
+ i++;
+ cli_print (cli, "Activate [%i] %s\r", mp->id, mp->packet_name );
+ }
+ mp = mp->next;
+ }
+ while (head != mp);
+ if (i==0) {
+ cli_print (cli, "No valid packets found\n");
+ } else {
+ cli_print (cli, "\r");
+ cli_print (cli, "Activated %i packets \n", i);
+ }
+ return CLI_OK;
+}
+
+
+
+int cmd_stop (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ struct mops *mp;
+ int i, ret=0, slot=0;
+
+ struct mops *head = mp_head;
+ struct mops *cur = mp_head;
+
+ if ((strncmp(argv[argc-1], "?", 2)==0) || (argc==0)) {
+ cli_print(cli, "Stop transmission process(es) or an active sequence.\r");
+ cli_print(cli, "SYNTAX: 1) Either specify one or more packet-ids or packet names of active packets\r");
+ cli_print(cli, " 2) Or enter 'sequence <seq-name>' to stop an active sequence and its associated packets.\n");
+ return CLI_OK;
+ }
+
+ // Did the user specify a sequence? (ONE SEQUENCE ONLY)
+ if ((mz_strcmp(argv[0], "sequence", 3)==0) && (argc==2)) {
+ ret = stop_sequence (argv[1]);
+ switch (ret) {
+ case 0:
+ cli_print(cli, "Sequence '%s' stopped.\n", argv[1]);
+ break;
+
+ case 1:
+ cli_print(cli, "Sequence '%s' does not exist!\n", argv[1]);
+ break;
+ case 2:
+ cli_print(cli, "Sequence '%s' is not active. Nothing to stop.\n", argv[1]);
+ break;
+ }
+ return CLI_OK;
+ }
+
+
+ if (((mz_strcmp(argv[0], "all", 3)==0) || (mz_strcmp(argv[0], "*", 1)==0)) && (argc==1)) {
+ i=0;
+ cli_print(cli, "Stopping ");
+ do {
+ if (mops_destroy_thread (cur)==0) {
+ i++;
+ cli_print(cli, "[%i] %s", cur->id, cur->packet_name);
+ }
+ cur = cur->next;
+ }
+ while (head != cur);
+ cli_print(cli, "\n");
+ if (i) {
+ cli_print(cli, "Stopped %i transmission processe(s)\r", i);
+ }
+ else {
+ cli_print(cli, "No active transmission processes found.\r");
+ }
+
+ i = stop_all_sequences ();
+ if (i) {
+ cli_print(cli, "Stopped %i sequence(s)\n", i);
+ }
+ else {
+ cli_print(cli, "No active sequences found.\n");
+ }
+
+ return CLI_OK;
+ }
+
+ // Stop all specified packets:
+ //
+ for (i=0; i<argc; i++) {
+ mp = NULL;
+ // is argv[i] a numerical pkt-id?
+ if (mz_strisnum(argv[i])) {
+ slot = (int) str2int(argv[i]);
+ mp = mops_search_id (mp_head, slot);
+ }
+ // still not found? Is it a name?
+ if (mp==NULL) mp = mops_search_name (mp_head, argv[i]);
+ if (mp==NULL) cli_print(cli, "Packet '%s' not in list!\r",argv[i]);
+ else { // packet found:
+ if (mops_destroy_thread (mp)) {
+ cli_print(cli, "Packet [%i] '%s' has no associated transmission process (nothing to stop).\r", mp->id, mp->packet_name);
+ } else
+ cli_print (cli, "Stopped transission process for packet [%i] '%s'.\r", mp->id, mp->packet_name);
+ }
+ }
+
+ cli_print(cli, "\r");
+ return CLI_OK;
+}
+
+
+
+int show_mops(struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ char tmp[120];
+
+ if (strncmp(argv[argc-1], "?", 2)==0) {
+ cli_print(cli, "<ENTER> Check MOPS version and details\n");
+ return CLI_OK;
+ }
+
+ cli_print(cli, "-----------------------------------------------------\r");
+ cli_print(cli, "Mops version %s [%s]\n", MOPS_VERSION, MOPS_CODENAME);
+ cli_print(cli, "Maximum packet sequence length is %i packets\r", MAX_PACKET_SEQUENCE_LEN);
+ cli_print(cli, "Maximum frame size is %i bytes\r", MAX_MOPS_FRAME_SIZE);
+ cli_print(cli, "Minimum frame size is %i bytes\r", MIN_MOPS_FRAME_SIZE);
+ cli_print(cli, "PCAP readout delay is %i msec\r", PCAP_READ_TIMEOUT_MSEC);
+ cli_print(cli, "Maximum payload size is %i bytes\r", MAX_MOPS_MSG_SIZE);
+ cli_print(cli, "Maximum chunk size is %i bytes\r", MAX_MOPS_MSG_CHUNK_SIZE);
+ cli_print(cli, "Maximum counters per packet is %i\r", MAX_MOPS_COUNTERS_PER_PACKET);
+ cli_print(cli, "Maximum number of 802.1Q tags is %i\r", MAX_MOPS_DOT1Q_TAGS);
+ cli_print(cli, "Maximum number of MPLS tags is %i\r", MAX_MOPS_MPLS_TAGS);
+ cli_print(cli, "Maximum length of packet names is %i characters\r", MAX_MOPS_PACKET_NAME_LEN);
+ cli_print(cli, "Maximum length of packet descriptions is %i characters\r", MAX_MOPS_DESCRIPTION_LEN);
+ cli_print(cli, "Bytes per line for formatted frame output %i\r", MAX_CLI_LINE_BYTES);
+ cli_print(cli, "Maximum LLDP optional section length is %i bytes\r", MAX_LLDP_OPT_TLVS);
+ if (AUTOMOPS_ENABLED) {
+ cli_print(cli, "Auto-MOPS subsystem is enabled\r");
+ cli_print(cli, " Maximum nesting depth is %i\r", XN_MAX_STACK);
+ cli_print(cli, " Maximum file size for protocol definitions is %i\r", AUTOMOPS_MAX_FILE_SIZE);
+ cli_print(cli, " Maximum names length is %i\r", AUTOMOPS_MAX_NAME_LEN);
+ cli_print(cli, " Maximum short description length is %i\r", AUTOMOPS_MAX_SHORTDESC_LEN);
+ cli_print(cli, " Maximum XML tag length is %i\r", XML_MAX_TAG_LEN);
+ } else cli_print(cli, "Auto-MOPS subsystem is disabled\r");
+
+ if (mops_dump_all(mp_head, tmp)) {
+ cli_print(cli, "No mopses found.\n"); // keine Möpse gefunden ;-)
+ } else {
+ cli_print(cli, "%s\n", tmp);
+ }
+
+ return CLI_OK;
+}
+
+
+
+
+int cmd_reset_interface (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ int i;
+
+ if (strncmp(argv[argc-1], "?", 2)==0) {
+ cli_print(cli, "<ENTER> Check MOPS version and details\n");
+ return CLI_OK;
+ }
+
+ if (argc>0) {
+ cli_print(cli, "Unknown parameter\n");
+ return CLI_OK;
+ }
+
+ lookupdev();
+
+ for (i=0; i<device_list_entries; i++) {
+ get_dev_params(device_list[i].dev);
+ // refresh ARP table i. e. MAC addresses of default GWs
+ service_arp(device_list[i].dev, device_list[i].ip_gw, device_list[i].mac_gw);
+ }
+
+ return CLI_OK;
+}
+
+
+
+
+int conf_frame_limit (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ unsigned int tmp;
+
+ if (strncmp(argv[argc-1], "?", 2)==0)
+ {
+ cli_print(cli, "Configure global frame size limits:\n");
+ cli_print(cli, " <min-frame-size> [max-frame-size]\n");
+ return CLI_OK;
+ }
+
+ if (argc>2)
+ {
+ cli_print(cli, "Two arguments allowed: <min-frame-size> [max-frame-size]\n");
+ return CLI_OK;
+ }
+
+ tmp = (unsigned int) str2int (argv[0]);
+ if (tmp < MIN_MOPS_FRAME_SIZE)
+ {
+ cli_print(cli, "This Mausezahn requires that the minimum frame size is at least %i bytes\n", MIN_MOPS_FRAME_SIZE);
+ return CLI_OK;
+ }
+
+ if (tmp>(max_frame_s-2))
+ {
+ cli_print(cli, "The minimum frame size must be below %i bytes\n", max_frame_s-1);
+ return CLI_OK;
+ }
+
+ min_frame_s = tmp;
+
+ if (argc==2)
+ {
+ tmp = (unsigned int) str2int (argv[1]);
+
+ if (tmp > MAX_MOPS_FRAME_SIZE-MOPS_SIZE_MARGIN)
+ {
+ cli_print(cli, "This Mausezahn requires that the maximum frame size is not greater than %i bytes\n",
+ MAX_MOPS_FRAME_SIZE-MOPS_SIZE_MARGIN);
+ return CLI_OK;
+ }
+
+ if (tmp<(min_frame_s+2))
+ {
+ cli_print(cli, "The maximum frame size must be greater than %i bytes\n", min_frame_s+1);
+ return CLI_OK;
+ }
+
+ max_frame_s = tmp;
+ }
+
+ return CLI_OK;
+}
+
+
+
+
+int cmd_load (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ int i;
+ FILE *fp;
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc!=1) ) {
+ cli_print(cli, "Load commands from one or more specified file(s)\r");
+ cli_print(cli, "\n");
+ return CLI_OK;
+ }
+
+ if (!argc){
+ cli_print(cli, "Specify one or more configuration files\n");
+ return CLI_OK;
+ }
+
+ for (i=0; i<argc; i++) {
+ fp = fopen(argv[i], "r");
+ if (fp==NULL) {
+ cli_print(cli, "Warning: Cannot read %s\n", argv[i]);
+ continue;
+ }
+ cli_print(cli, "Read commands from %s...\n", argv[i]);
+ cli_file (cli, fp, PRIVILEGE_PRIVILEGED, MODE_EXEC);
+ if (fclose(fp) == EOF)
+ {
+ cli_print(cli, "Warning: problems closing %s (errno=%i)\n", argv[i],errno);
+ }
+ }
+
+ return CLI_OK;
+}
+
+
+int show_arp (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ int i;
+ struct arp_table_struct *cur;
+ char s[128], ip[20], uc[16], bc[16], ch[16];
+ struct mz_timestamp now, prev, result;
+
+
+
+ if (strcmp(argv[argc-1],"?")==0) {
+ cli_print(cli, "<CR> shows the advanced Mausezahn ARP table\n");
+ return CLI_OK;
+ }
+
+ if (argc>0) {
+ cli_print(cli, "Unknown parameter\n");
+ return CLI_OK;
+ }
+
+
+ cli_print(cli, "Intf Index IP address MAC address last Ch UCast BCast Info\r");
+ cli_print(cli, "----------------------------------------------------------------------------------\r");
+// ------------------------------------------------------------------------------
+// wlan0 [1] DL 192.168.0.1 at 00:09:5b:9a:15:84 3'42'' 1
+
+ for (i=0; i<device_list_entries; i++) {
+ cur=device_list[i].arp_table;
+ while(cur!=NULL) {
+ sprintf(ip,"%i.%i.%i.%i",cur->sip[0],cur->sip[1],cur->sip[2],cur->sip[3]);
+ if (cur->changed>99999) mz_strncpy(ch,"ALERT",6); else sprintf(ch,"%lu", cur->changed);
+ if (cur->uni_resp>99999) mz_strncpy(uc,"ALERT",6); else sprintf(uc,"%lu", cur->uni_resp);
+ if (cur->bc_resp>99999) mz_strncpy(bc,"ALERT",6); else sprintf(bc,"%lu", cur->bc_resp);
+ sprintf(s, "%-7s [%i] %s%s %15s %02x:%02x:%02x:%02x:%02x:%02x %8s %5s %5s %5s %04x",
+ device_list[i].dev,
+ cur->index,
+ (cur->dynamic) ? "D" : "U",
+ (cur->locked) ? "L" : "",
+ ip,
+ cur->smac[0],
+ cur->smac[1],
+ cur->smac[2],
+ cur->smac[3],
+ cur->smac[4],
+ cur->smac[5],
+ cur->when,
+ ch,
+ uc,
+ bc,
+ cur->flags);
+ cli_print(cli, "%s\r", s);
+ if (cur->changed>1) {
+ now.sec = cur->sec;
+ now.nsec = cur->nsec;
+ prev.sec = cur->sec_prev;
+ prev.nsec= cur->nsec_prev;
+ printf("sec=%u nsec=%u sec=%u nsec=%u\n", cur->sec, cur->nsec, cur->sec_prev, cur->nsec_prev);
+ timestamp_subtract(&now, &prev, &result);
+ sprintf(s," previous MAC was: %02x:%02x:%02x:%02x:%02x:%02x time delta: %u sec %u msec",
+ cur->smac_prev[0],
+ cur->smac_prev[1],
+ cur->smac_prev[2],
+ cur->smac_prev[3],
+ cur->smac_prev[4],
+ cur->smac_prev[5],
+ (unsigned int) result.sec, (unsigned int) result.nsec/1000000);
+ cli_print(cli, " %s\r", s);
+ }
+ cur=cur->next;
+ }
+
+ }
+ return CLI_OK;
+}
+
+
+// general 'end' command to return to global config mode
+int cmd_end_to_config(struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ cli_set_configmode(cli, MODE_CONFIG, NULL);
+ return CLI_OK;
+}
diff --git a/staging/cli_dns.c b/staging/cli_dns.c
new file mode 100644
index 0000000..be1e7ea
--- /dev/null
+++ b/staging/cli_dns.c
@@ -0,0 +1,53 @@
+/*
+ * Mausezahn - A fast versatile traffic generator
+ * Copyright (C) 2008-2010 Herbert Haas
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
+ *
+*/
+
+
+
+#include "mz.h"
+#include "cli.h"
+#include "mops.h"
+
+int cmd_dns_query(struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+
+ return CLI_OK;
+}
+
+
+int cmd_dns_answer(struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+
+ return CLI_OK;
+}
+
+
+int cmd_dns_ttl(struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+
+ return CLI_OK;
+}
+
+
+int cmd_dns_end(struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ char prompt[16];
+ sprintf(prompt, "pkt-%i",clipkt->id);
+ cli_set_configmode(cli, MZ_MODE_PACKET, prompt);
+ return CLI_OK;
+}
+
diff --git a/staging/cli_eth.c b/staging/cli_eth.c
new file mode 100644
index 0000000..668aa95
--- /dev/null
+++ b/staging/cli_eth.c
@@ -0,0 +1,269 @@
+/*
+ * Mausezahn - A fast versatile traffic generator
+ * Copyright (C) 2008-2010 Herbert Haas
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
+ *
+*/
+
+
+#include "mz.h"
+#include "cli.h"
+#include "mops.h"
+
+
+
+
+
+int cmd_packet_mac_address_source (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ int i,j;
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc>1) )
+ {
+ cli_print(cli, "XX:XX:XX:XX:XX:XX Configure a source MAC address\n");
+ cli_print(cli, "Optionally you may use randomly generated (unicast)\r");
+ cli_print(cli, "MAC addresses, using the keyword 'random'\n");
+ return CLI_OK;
+ }
+
+ if (argc==1)
+ {
+ if (mz_strcmp(argv[0], "random", 3)==0)
+ {
+ clipkt->eth_src_israndom = 1;
+ return CLI_OK;
+ }
+
+ if (mz_strcmp(argv[0], "default", 3)==0)
+ {
+ // find index of device_list with the device configured in clipkt:
+ i=0;
+ while (strncmp(device_list[i].dev, clipkt->device, 10) && (i<device_list_entries)) i++;
+ for (j=0;j<6;j++) clipkt->eth_src[j] = device_list[i].mac_mops[j];
+ clipkt->eth_src_israndom = 0;
+ return CLI_OK;
+ }
+
+ if (mops_pdesc_mac(clipkt->eth_src, argv[0]))
+ {
+ cli_print(cli,"Invalid MAC address (use format: XX:XX:XX:XX:XX:XX)\n");
+ }
+ else // MAC was OK
+ {
+ clipkt->eth_src_israndom = 0;
+ }
+ }
+ else
+ cli_print(cli, "Invalid MAC format!\n");
+
+
+ return CLI_OK;
+}
+
+
+
+int cmd_packet_mac_address_destination (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc>1) )
+ {
+ cli_print(cli, "XX:XX:XX:XX:XX:XX Configure a destination MAC address\n");
+ return CLI_OK;
+ }
+ if (argc==1)
+ {
+ if (mz_strcmp(argv[0], "bcast", 2)==0)
+ {
+ mops_pdesc_mac (clipkt->eth_dst, "ff:ff:ff:ff:ff:ff");
+ return CLI_OK;
+ }
+ else if (mz_strcmp(argv[0], "pvst", 2)==0)
+ {
+ mops_pdesc_mac (clipkt->eth_dst, "01:00:0C:CC:CC:CD");
+ return CLI_OK;
+ }
+ else if (mz_strcmp(argv[0], "cisco", 2)==0)
+ {
+ mops_pdesc_mac (clipkt->eth_dst, "01:00:0C:CC:CC:CC");
+ return CLI_OK;
+ }
+ else if (mz_strcmp(argv[0], "stp", 2)==0)
+ {
+ mops_pdesc_mac (clipkt->eth_dst, "01:80:C2:00:00:00");
+ return CLI_OK;
+ }
+
+ if (mops_pdesc_mac(clipkt->eth_dst, argv[0]))
+ {
+ cli_print(cli,"Invalid MAC address (use format: XX:XX:XX:XX:XX:XX)\n");
+ }
+ }
+ else
+ cli_print(cli, "Invalid MAC format!\n");
+
+ return CLI_OK;
+}
+
+
+
+
+
+
+int cmd_eth_type (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ unsigned long int t32;
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc>1) )
+ {
+ cli_print(cli, "Specify the Ethernet type field in hexadecimal format.\n");
+ cli_print(cli, "For example:\n");
+ cli_print(cli, " 800 ......... IP\r");
+ cli_print(cli, " 806 ......... ARP\r");
+ cli_print(cli, " 835 ......... RARP\r");
+ cli_print(cli, " 8100 ......... 802.1Q\r");
+ cli_print(cli, " 888E ......... 802.1X\r");
+ cli_print(cli, "\n");
+ return CLI_OK;
+ }
+
+ if (argc==1)
+ {
+ t32 = xstr2int(argv[0]);
+ if (t32>0xffff)
+ {
+ cli_print(cli, "EtherType must not exceed ffff.\n");
+ return CLI_OK;
+ }
+ if (t32<0x800)
+ {
+ cli_print(cli, "WARNING: 'Officially' the EtherType must be greater or equal 800.\n");
+ }
+
+ clipkt->eth_type = (u_int16_t) t32;
+ }
+ else
+ {
+ cli_print(cli, "Only one parameter accepted.\n");
+ }
+
+ return CLI_OK;
+}
+
+
+
+
+int cmd_eth_length (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ unsigned long int t32;
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc>1) )
+ {
+ cli_print(cli, "Specify the 802.3 length field in decimal notation.\r");
+ cli_print(cli, "\n");
+ return CLI_OK;
+ }
+
+ if (argc==1)
+ {
+ t32 = str2int(argv[0]);
+ if (t32>0xffff)
+ {
+ cli_print(cli, "The length field must not exceed 65535.\n");
+ return CLI_OK;
+ }
+ if (t32>0x7ff)
+ {
+ cli_print(cli, "WARNING: 'Officially' the 802.3 length field must not be greater than 1522.\n");
+ }
+
+ clipkt->eth_len = (u_int16_t) t32;
+ }
+ else
+ {
+ cli_print(cli, "Only one parameter accepted.\n");
+ }
+
+
+
+ return CLI_OK;
+}
+
+
+
+
+
+int cmd_eth_llc (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc>1) )
+ {
+ cli_print(cli, "Specify the IEEE 802.2 Logical Link Control (LLC) in hexadecimal format.\n");
+ return CLI_OK;
+ }
+
+ // DSAP-SSAP-Ctrl
+ // ***** TODO *****
+ cli_print(cli, "Not supported in this version.\n");
+
+ return CLI_OK;
+}
+
+
+
+
+int cmd_eth_snap (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+
+ u_int8_t
+ oui[16],
+ etp[16],
+ t8[16] = {0xAA, 0xAA, 0x03};
+
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc>1) )
+ {
+ cli_print(cli, "Specify the SNAP header (OUI+Type) in hexadecimal format\r");
+ cli_print(cli, "Example: 00:00:0e 08:00\r");
+ cli_print(cli, "\n");
+ return CLI_OK;
+ }
+
+ if (argc!=2)
+ {
+ cli_print(cli, "Two arguments required: 3-byte OUI and 2-byte EtherType\n");
+ return CLI_OK;
+ }
+
+ if (str2hex(argv[0], oui, 15)!=3)
+ {
+ cli_print(cli, "Three bytes required for the OUI\n");
+ return CLI_OK;
+ }
+
+ if (str2hex(argv[1], etp, 15)!=2)
+ {
+ cli_print(cli, "Two bytes required for the EtherType\n");
+ return CLI_OK;
+ }
+
+
+ memcpy(&clipkt->eth_snap[0], &t8, 3);
+ memcpy(&clipkt->eth_snap[3], &oui, 3);
+ memcpy(&clipkt->eth_snap[6], &etp, 2);
+ clipkt->eth_snap_s = 8;
+
+
+
+ return CLI_OK;
+}
diff --git a/staging/cli_igmp.c b/staging/cli_igmp.c
new file mode 100644
index 0000000..cdd1df1
--- /dev/null
+++ b/staging/cli_igmp.c
@@ -0,0 +1,322 @@
+/*
+ * Mausezahn - A fast versatile traffic generator
+ * Copyright (C) 2008-2010 Herbert Haas
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
+ *
+*/
+
+
+
+#include "mz.h"
+#include "cli.h"
+#include "mops.h"
+
+
+int cmd_igmpv2_genquery (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ int mrt, sum;
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc>2) ) {
+ cli_print(cli, "Configure a IGMPv2 general query.\n");
+ cli_print(cli, "ARGUMENTS: [<MRT> [<checksum>]]\n");
+ cli_print(cli, "<MRT> ... maximum response time in 100 msec units (default: 10 s)\r");
+ cli_print(cli, "<checksum> ... user-defined checksum (usually wrong by intention) in \r");
+ cli_print(cli, " hexadecimal notation (e. g. 'c7b3').\n");
+ return CLI_OK;
+ }
+
+ if (argc>=1) {
+ if (mz_strisnum(argv[0])==0) {
+ cli_print(cli, "Maximum response time must only contain numbers!\n");
+ return CLI_OK;
+ }
+ mrt = (int) str2int(argv[0]);
+ } else mrt = 100; // default: 10 s
+
+ if (argc==2) {
+ if (mz_strishex(argv[1])==0) {
+ cli_print(cli, "Checksum must only contain hexadecimal numbers!\n");
+ return CLI_OK;
+ }
+ sum = (int) xstr2int(argv[1]);
+ if (sum>0xffff) {
+ cli_print(cli, "Checksum must be a 2-byte value!\n");
+ return CLI_OK;
+ }
+
+ } else sum = -1;
+
+ clipkt->ip_dst = str2ip32("224.0.0.1");
+ clipkt->ip_ttl = 1;
+ clipkt->ndelay.tv_sec = 125;
+ clipkt->ndelay.tv_nsec = 0;
+ if (mops_create_igmpv2 (clipkt, 0, IGMP_GENERAL_QUERY, mrt, sum, 0))
+ cli_print(cli, "Invalid parameters!\n");
+
+ return CLI_OK;
+}
+
+
+int cmd_igmpv2_specquery (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ int mrt=100, sum=-1;
+ u_int8_t IP[4];
+ u_int32_t mip=0;
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc>3) ) {
+ cli_print(cli, "Configure a IGMPv2 group-specific query.\n");
+ cli_print(cli, "ARGUMENTS: <IP-address> [<MRT> [<checksum>]]\n");
+ cli_print(cli, "<IP-Address> ... multicast group to be queried (can be ANY IP address!)\r");
+ cli_print(cli, "<MRT> ... maximum response time in 100 msec units (default: 10 s)\r");
+ cli_print(cli, "<checksum> ... user-defined checksum (usually wrong by intention) in \r");
+ cli_print(cli, " hexadecimal notation (e. g. 'c7b3').\n");
+ return CLI_OK;
+ }
+
+
+ if (argc==0) {
+ cli_print(cli, "You must at least specify the group address\n");
+ return CLI_OK;
+ }
+
+ if (argc>=1) {
+ if (mops_pdesc_ip (IP, argv[0])==0) // check if format is really an IP address
+ mip = str2ip32(argv[0]);
+ else {
+ cli_print(cli, "Invalid IP address\n");
+ return CLI_OK;
+ }
+ }
+
+ if (argc>=2) {
+ if (mz_strisnum(argv[1])==0) {
+ cli_print(cli, "Maximum response time must only contain numbers!\n");
+ return CLI_OK;
+ }
+ mrt = (int) str2int(argv[1]);
+ }
+
+ if (argc==3) {
+ if (mz_strishex(argv[2])==0) {
+ cli_print(cli, "Checksum must only contain hexadecimal numbers!\n");
+ return CLI_OK;
+ }
+ sum = (int) xstr2int(argv[2]);
+ if (sum>0xffff) {
+ cli_print(cli, "Checksum must be a 2-byte value!\n");
+ return CLI_OK;
+ }
+ }
+
+ clipkt->ip_dst = mip;
+ clipkt->ip_ttl = 1;
+ clipkt->ndelay.tv_sec = 125;
+ clipkt->ndelay.tv_nsec = 0;
+ if (mops_create_igmpv2 (clipkt, 0, IGMP_GSPEC_QUERY, mrt, sum, mip))
+ cli_print(cli, "Invalid parameters!\n");
+
+ return CLI_OK;
+}
+
+
+
+
+
+int cmd_igmpv2_report (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ int sum;
+ u_int8_t IP[4];
+ u_int32_t mip=0;
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc>2) || (argc==0)) {
+ cli_print(cli, "Configure a IGMPv2 membership report.\n");
+ cli_print(cli, "ARGUMENTS: <IP-Address> [<checksum>]\n");
+ cli_print(cli, "<IP-Address> ... multicast group address to be reported (but ANY IP\r");
+ cli_print(cli, " address allowed, Mausezahn is really generous...)\r");
+ cli_print(cli, "<checksum> ... user-defined checksum (usually wrong by intention) in \r");
+ cli_print(cli, " hexadecimal notation (e. g. 'c7b3').\n");
+ return CLI_OK;
+ }
+
+
+ if (argc>=1) {
+ if (mops_pdesc_ip (IP, argv[0])==0) // check if format is really an IP address
+ mip = str2ip32(argv[0]);
+ else {
+ cli_print(cli, "Invalid IP address\n");
+ return CLI_OK;
+ }
+ }
+
+ if (argc==2) {
+ if (mz_strishex(argv[1])==0) {
+ cli_print(cli, "Checksum must only contain hexadecimal numbers!\n");
+ return CLI_OK;
+ }
+ sum = (int) xstr2int(argv[1]);
+ if (sum>0xffff) {
+ cli_print(cli, "Checksum must be a 2-byte value!\n");
+ return CLI_OK;
+ }
+ } else sum = -1;
+
+ clipkt->ip_dst = mip;
+ clipkt->ip_ttl = 1;
+ clipkt->ndelay.tv_sec = 1;
+ clipkt->ndelay.tv_nsec = 0;
+
+ if (mops_create_igmpv2 (clipkt, 0, IGMP_V2_REPORT, 0, sum, mip))
+ cli_print(cli, "Invalid parameters!\n");
+
+ return CLI_OK;
+}
+
+
+int cmd_igmpv2_leave (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ int sum;
+ u_int8_t IP[4];
+ u_int32_t mip=0;
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc>2) || (argc==0)) {
+ cli_print(cli, "Configure a IGMPv2 leave group message.\n");
+ cli_print(cli, "ARGUMENTS: <IP-Address> [<checksum>]\n");
+ cli_print(cli, "<IP-Address> ... multicast group address that should be left; use\r");
+ cli_print(cli, " the special address 0.0.0.0 for a 'general leave'\r");
+ cli_print(cli, "<checksum> ... user-defined checksum (usually wrong by intention) in \r");
+ cli_print(cli, " hexadecimal notation (e. g. 'c7b3').\n");
+ return CLI_OK;
+ }
+
+
+ if (argc>=1) {
+ if (mops_pdesc_ip (IP, argv[0])==0) // check if format is really an IP address
+ mip = str2ip32(argv[0]);
+ else {
+ cli_print(cli, "Invalid IP address\n");
+ return CLI_OK;
+ }
+ }
+
+ if (argc==2) {
+ if (mz_strishex(argv[1])==0) {
+ cli_print(cli, "Checksum must only contain hexadecimal numbers!\n");
+ return CLI_OK;
+ }
+ sum = (int) xstr2int(argv[1]);
+ if (sum>0xffff) {
+ cli_print(cli, "Checksum must be a 2-byte value!\n");
+ return CLI_OK;
+ }
+ } else sum = -1;
+
+ clipkt->ip_dst = str2ip32("224.0.0.2");
+ clipkt->ip_ttl = 1;
+ clipkt->ndelay.tv_sec = 1;
+ clipkt->ndelay.tv_nsec = 0;
+
+ if (mops_create_igmpv2 (clipkt, 0, IGMP_LEAVE, 0, sum, mip))
+ cli_print(cli, "Invalid parameters!\n");
+
+ return CLI_OK;
+}
+
+
+
+
+
+int cmd_igmpv1_query (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ int sum;
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc>1) ) {
+ cli_print(cli, "Configure a IGMPv1 query.\n");
+ cli_print(cli, "OPTIONAL ARGUMENT: [<checksum>]\n");
+ cli_print(cli, "<checksum> ... user-defined checksum (usually wrong by intention) in \r");
+ cli_print(cli, " hexadecimal notation (e. g. 'c7b3').\n");
+ return CLI_OK;
+ }
+
+ if (argc==1) {
+ if (mz_strishex(argv[0])==0) {
+ cli_print(cli, "Checksum must only contain hexadecimal numbers!\n");
+ return CLI_OK;
+ }
+ sum = (int) xstr2int(argv[0]);
+ if (sum>0xffff) {
+ cli_print(cli, "Checksum must be a 2-byte value!\n");
+ return CLI_OK;
+ }
+ } else sum = -1;
+
+ clipkt->ip_dst = str2ip32("224.0.0.1");
+ clipkt->ip_ttl = 1;
+ clipkt->ndelay.tv_sec = 125;
+ clipkt->ndelay.tv_nsec = 0;
+ if (mops_create_igmpv2 (clipkt, 0, IGMP_GENERAL_QUERY, 0, sum, 0))
+ cli_print(cli, "Invalid parameters!\n");
+
+ return CLI_OK;
+}
+
+
+int cmd_igmpv1_report (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ int sum;
+ u_int8_t IP[4];
+ u_int32_t mip=0;
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc>2) || (argc==0)) {
+ cli_print(cli, "Configure a IGMPv1 membership report.\n");
+ cli_print(cli, "ARGUMENTS: <IP-Address> [<checksum>]\n");
+ cli_print(cli, "<IP-Address> ... multicast group address to be reported (but ANY IP\r");
+ cli_print(cli, " address allowed, Mausezahn is really generous...)\r");
+ cli_print(cli, "<checksum> ... user-defined checksum (usually wrong by intention) in \r");
+ cli_print(cli, " hexadecimal notation (e. g. 'c7b3').\n");
+ return CLI_OK;
+ }
+
+
+ if (argc>=1) {
+ if (mops_pdesc_ip (IP, argv[0])==0) // check if format is really an IP address
+ mip = str2ip32(argv[0]);
+ else {
+ cli_print(cli, "Invalid IP address\n");
+ return CLI_OK;
+ }
+ }
+
+ if (argc==2) {
+ if (mz_strishex(argv[1])==0) {
+ cli_print(cli, "Checksum must only contain hexadecimal numbers!\n");
+ return CLI_OK;
+ }
+ sum = (int) xstr2int(argv[1]);
+ if (sum>0xffff) {
+ cli_print(cli, "Checksum must be a 2-byte value!\n");
+ return CLI_OK;
+ }
+ } else sum = -1;
+
+ clipkt->ip_dst = mip;
+ clipkt->ip_ttl = 1;
+ clipkt->ndelay.tv_sec = 1;
+ clipkt->ndelay.tv_nsec = 0;
+
+ if (mops_create_igmpv2 (clipkt, 0, IGMP_V1_REPORT, 0, sum, mip))
+ cli_print(cli, "Invalid parameters!\n");
+
+ return CLI_OK;
+}
+
diff --git a/staging/cli_interface.c b/staging/cli_interface.c
new file mode 100644
index 0000000..65cb46d
--- /dev/null
+++ b/staging/cli_interface.c
@@ -0,0 +1,142 @@
+/*
+ * Mausezahn - A fast versatile traffic generator
+ * Copyright (C) 2008-2010 Herbert Haas
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
+ *
+*/
+
+
+#include "mz.h"
+#include "cli.h"
+#include "mops.h"
+
+
+
+
+// Enter interface config mode:
+//
+int enter_interface (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ int i, j=0;
+ char prompt[10];
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc>1) )
+ {
+ cli_print(cli, "Specify an interface to configure\n");
+ return CLI_OK;
+ }
+
+ if (argc)
+ {
+ for (i=0; i<device_list_entries; i++)
+ {
+ if (strncmp(device_list[i].dev, argv[0], 16)==0)
+ {
+ j=1;
+ sprintf(prompt, "if-%s", device_list[i].dev);
+ clidev = i;
+ break;
+ }
+ }
+
+ if (j)
+ {
+ cli_set_configmode(cli, MZ_MODE_INTERFACE, prompt);
+ }
+ else
+ {
+ cli_print(cli, "Unknown device!\n");
+ }
+ }
+ else
+ {
+ cli_print(cli, "Specify an interface to configure\n");
+ }
+
+ return CLI_OK;
+}
+
+
+
+int conf_ip_address (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc>1) )
+ {
+ cli_print(cli, "A.B.C.D Specify a default interface IP address\n");
+ return CLI_OK;
+ }
+
+ if (argc)
+ {
+ if (mops_pdesc_ip (device_list[clidev].ip_mops, argv[0]))
+ {
+ cli_print(cli,"Invalid IP address (use format: A.B.C.D)\n");
+ }
+ }
+ else
+ cli_print(cli, "A.B.C.D Specify a default interface IP address\n");
+
+ return CLI_OK;
+}
+
+
+
+int conf_mac_address (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc>1) )
+ {
+ cli_print(cli, "XX:XX:XX:XX:XX:XX Configure a default interface MAC address\n");
+ return CLI_OK;
+ }
+
+ if (argc)
+ {
+ if (mops_pdesc_mac (device_list[clidev].mac_mops, argv[0]))
+ {
+ cli_print(cli,"Invalid MAC address (use format: XX:XX:XX:XX:XX:XX)\n");
+ }
+ }
+ else
+ cli_print(cli, "A.B.C.D Specify a default interface IP address\n");
+
+ return CLI_OK;
+}
+
+
+
+int conf_tag_dot1q (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc>1) )
+ {
+ cli_print(cli, "Specify one or more 802.1Q (and optionally 802.1P) tags\n");
+ return CLI_OK;
+ }
+ cli_print(cli, "Not supported in this version\n");
+ return CLI_OK;
+}
+
+int conf_tag_mpls (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc>1) )
+ {
+ cli_print(cli, "Specify one or more MPLS labels (and parameters)\n");
+ return CLI_OK;
+ }
+ cli_print(cli, "Not supported in this version\n");
+ return CLI_OK;
+}
+
+
+
+
diff --git a/staging/cli_ip.c b/staging/cli_ip.c
new file mode 100644
index 0000000..55f5683
--- /dev/null
+++ b/staging/cli_ip.c
@@ -0,0 +1,888 @@
+/*
+ * Mausezahn - A fast versatile traffic generator
+ * Copyright (C) 2008-2010 Herbert Haas
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
+ *
+*/
+
+
+
+#include "mz.h"
+#include "cli.h"
+#include "mops.h"
+
+
+// ------- TOC ---------
+//
+// int cmd_ip_address_source (struct cli_def *cli, char *command, char *argv[], int argc)
+// int cmd_ip_address_destination (struct cli_def *cli, char *command, char *argv[], int argc)
+// int cmd_ip_version (struct cli_def *cli, char *command, char *argv[], int argc)
+// int cmd_ip_ttl (struct cli_def *cli, char *command, char *argv[], int argc)
+// int cmd_ip_protocol (struct cli_def *cli, char *command, char *argv[], int argc)
+// int cmd_ip_hlen (struct cli_def *cli, char *command, char *argv[], int argc)
+// int cmd_ip_len (struct cli_def *cli, char *command, char *argv[], int argc)
+// int cmd_ip_id (struct cli_def *cli, char *command, char *argv[], int argc)
+// int cmd_ip_offset (struct cli_def *cli, char *command, char *argv[], int argc)
+// int cmd_ip_sum (struct cli_def *cli, char *command, char *argv[], int argc)
+// int cmd_ip_tos (struct cli_def *cli, char *command, char *argv[], int argc)
+// int cmd_ip_dscp (struct cli_def *cli, char *command, char *argv[], int argc)
+// int cmd_ip_rsv (struct cli_def *cli, char *command, char *argv[], int argc)
+// int cmd_ip_df (struct cli_def *cli, char *command, char *argv[], int argc)
+// int cmd_ip_mf (struct cli_def *cli, char *command, char *argv[], int argc)
+// int cmd_ip_option (struct cli_def *cli, char *command, char *argv[], int argc)
+
+
+
+// ip-address source default|<IP>|rand|range
+//
+// default
+// random
+// A.B.C.D
+// A.B.C.D /24
+// A.B.C.D E.F.G.H
+int cmd_ip_address_source (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ u_int8_t IP1[4], IP2[4];
+ u_int32_t ip1, ip2;
+ unsigned int prefix;
+ u_int32_t mask, invmask;
+ int i,r;
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc>2) )
+ {
+ cli_print(cli, "A.B.C.D configure a source IP address\n");
+ cli_print(cli, "Optionally you may specify\r");
+ cli_print(cli, "- a range of addresses, such as: 192.168.0.0 /16\r");
+ cli_print(cli, " or: 192.168.0.1 192.168.255.255\r");
+ cli_print(cli, "- 'random' for a randomly generated source address\r");
+ cli_print(cli, "- 'default' for the interface default settings\n");
+ return CLI_OK;
+ }
+
+ switch (argc)
+ {
+ case 1:
+ if (mz_strcmp(argv[0], "default", 3)==0)
+ {
+ // find index of device_list with the device configured in clipkt:
+ i=0;
+ while (strncmp(device_list[i].dev, clipkt->device, 10) && (i<device_list_entries)) i++;
+ clipkt->ip_src = device_list[i].ip_mops[3]
+ + device_list[i].ip_mops[2] * 256
+ + device_list[i].ip_mops[1] * 256 * 256
+ + device_list[i].ip_mops[0] * 256 * 256 * 256;
+ clipkt->ip_src_israndom = 0;
+ clipkt->ip_src_isrange = 0;
+ }
+ else if (mz_strcmp(argv[0], "random", 3)==0)
+ {
+ clipkt->ip_src_israndom = 1;
+ clipkt->ip_src_isrange = 0;
+ }
+ else if (mops_pdesc_ip (IP1, argv[0])==0) // check if format is really an IP address
+ {
+ clipkt->ip_src = str2ip32(argv[0]);
+ clipkt->ip_src_israndom = 0;
+ clipkt->ip_src_isrange = 0;
+ }
+ else // wrong input
+ {
+ cli_print(cli,"Invalid address/keyword\n");
+ }
+ break;
+ case 2: // MUST be either like '10.1.1.0 /24' or '10.1.1.1 10.1.1.254'
+ if (mops_pdesc_ip (IP1, argv[0])==0) // check if format is really an IP address
+ {
+ clipkt->ip_src_start = str2ip32(argv[0]);
+ if (strlen(argv[1])<4) // probably prefix?
+ {
+ r=sscanf(argv[1],"/%u",&prefix);
+ if ((r==EOF) || (r==0) || (prefix<1) || (prefix>31))
+ cli_print(cli, "Invalid prefix!\n");
+ else
+ {
+ mask = 0xffffffff;
+ mask <<= (32-prefix);
+ invmask = 0xffffffff - mask;
+ ip1 = ((str2ip32 (argv[0])) & mask) +1; // the '+1' is to ensure that we do not start with the net-id
+ ip2 = ip1 | invmask;
+ clipkt->ip_src_start = ip1;
+ clipkt->ip_src_stop = ip2;
+ clipkt->ip_src_isrange = 1;
+ clipkt->ip_src_israndom = 0;
+ }
+ }
+ else if (mops_pdesc_ip (IP2, argv[1])==0) // probably 2nd IP address?
+ {
+ if (str2ip32(argv[1]) > clipkt->ip_src_start)
+ {
+ clipkt->ip_src_stop = str2ip32(argv[1]);
+ clipkt->ip_src_isrange = 1;
+ clipkt->ip_src_israndom = 0;
+ }
+ else
+ {
+ cli_print(cli, "Invalid range! The second IP address must be greater than the first!\n");
+ }
+ }
+ else
+ {
+ cli_print(cli, "Second parameter must be either a valid IP address or a prefix length \n");
+ }
+ }
+ else // first string is not a valid IP address
+ {
+ cli_print(cli, "First parameter must be a valid IP address\n");
+ }
+ break;
+ default:
+ cli_print(cli, "Invalid format!\n");
+ }
+
+ return CLI_OK;
+}
+
+
+
+// ip-address destination <IP>|range
+int cmd_ip_address_destination (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ u_int8_t IP1[4], IP2[4];
+ u_int32_t ip1, ip2;
+ unsigned int prefix;
+ u_int32_t mask, invmask;
+ int r;
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc>2) )
+ {
+ cli_print(cli, "A.B.C.D configure a destination IP address\n");
+ cli_print(cli, "Optionally specify a range of addresses, such as: 192.168.0.0 /16\r");
+ cli_print(cli, " or: 192.168.0.1 192.168.255.255\n");
+ return CLI_OK;
+ }
+
+ switch (argc)
+ {
+ case 1:
+ if (mops_pdesc_ip (IP1, argv[0])==0) // check if format is really an IP address
+ {
+ clipkt->ip_dst = str2ip32(argv[0]);
+ clipkt->ip_dst_isrange = 0;
+ }
+ else // wrong input
+ {
+ cli_print(cli,"Invalid address/range\n");
+ }
+ break;
+ case 2: // MUST be either like '10.1.1.0 /24' or '10.1.1.1 10.1.1.254'
+ if (mops_pdesc_ip (IP1, argv[0])==0) // check if format is really an IP address
+ {
+ clipkt->ip_dst_start = str2ip32(argv[0]);
+ if (strlen(argv[1])<4) // probably prefix?
+ {
+ r=sscanf(argv[1],"/%u",&prefix);
+ if ((r==EOF) || (r==0) || (prefix<1) || (prefix>31))
+ cli_print(cli, "Invalid prefix!\n");
+ else
+ {
+ mask = 0xffffffff;
+ mask <<= (32-prefix);
+ invmask = 0xffffffff - mask;
+ ip1 = ((str2ip32 (argv[0])) & mask) +1; // the '+1' is to ensure that we do not start with the net-id
+ ip2 = ip1 | invmask;
+ clipkt->ip_dst_start = ip1;
+ clipkt->ip_dst_stop = ip2;
+ clipkt->ip_dst_isrange = 1;
+ }
+ }
+ else if (mops_pdesc_ip (IP2, argv[1])==0) // probably 2nd IP address?
+ {
+ if (str2ip32(argv[1]) > clipkt->ip_dst_start)
+ {
+ clipkt->ip_dst_stop = str2ip32(argv[1]);
+ clipkt->ip_dst_isrange = 1;
+ }
+ else
+ {
+ cli_print(cli, "Range requirement: The second IP address must be greater than the first!\n");
+ }
+ }
+ else
+ {
+ cli_print(cli, "Second parameter must be either a valid IP address or a prefix length \n");
+ }
+ }
+ else // first string is not a valid IP address
+ {
+ cli_print(cli, "First parameter must be a valid IP address\n");
+ }
+ break;
+ default:
+ cli_print(cli, "Invalid IP or range specification!\n");
+ }
+
+ return CLI_OK;
+}
+
+
+
+
+int cmd_ip_version (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ int ver;
+
+ if (strncmp(argv[argc-1], "?", 2)==0)
+ {
+ cli_print(cli, "Specify the IP version (default: 4).\n");
+ return CLI_OK;
+ }
+
+ ver = (int) str2int(argv[0]);
+
+ if (ver>15)
+ {
+ cli_print(cli, "Version must be within range 0..15\n");
+ return CLI_OK;
+ }
+
+ clipkt->ip_version = ver;
+
+ return CLI_OK;
+}
+
+
+
+int cmd_ip_ttl (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ int ttl;
+
+ if (strncmp(argv[argc-1], "?", 2)==0)
+ {
+ cli_print(cli, "Specify the TTL (default: 255).\n");
+
+ return CLI_OK;
+ }
+
+ ttl = (int) str2int(argv[0]);
+
+ if (ttl>255)
+ {
+ cli_print(cli, "TTL must be within range 0..255\n");
+ return CLI_OK;
+ }
+
+ clipkt->ip_ttl = ttl;
+
+
+ return CLI_OK;
+}
+
+
+
+int cmd_ip_protocol (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ int proto;
+
+ if (strncmp(argv[argc-1], "?", 2)==0)
+ {
+ cli_print(cli, "Specify the protocol number (default: 0).\n");
+
+ return CLI_OK;
+ }
+
+ proto = (int) str2int(argv[0]);
+
+ if (proto>255)
+ {
+ cli_print(cli, "The protocol number must be within range 0..255\n");
+ return CLI_OK;
+ }
+
+ clipkt->ip_proto = proto;
+
+ return CLI_OK;
+}
+
+
+
+
+
+int cmd_ip_hlen (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ int ihl;
+
+ if (strncmp(argv[argc-1], "?", 2)==0)
+ {
+ cli_print(cli, "Specify the header length in multiple of 4 bytes.\n");
+
+ return CLI_OK;
+ }
+
+ ihl = (int) str2int(argv[0]);
+
+ if (ihl>15)
+ {
+ cli_print(cli, "The IHL must be within range 0..15\n");
+ return CLI_OK;
+ }
+
+ clipkt->ip_IHL = ihl;
+
+ return CLI_OK;
+}
+
+
+
+
+
+int cmd_ip_len (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ int len;
+
+ if (strncmp(argv[argc-1], "?", 2)==0)
+ {
+ cli_print(cli, "Specify the total packet length (0..65535).\n");
+
+ return CLI_OK;
+ }
+
+ len = (int) str2int(argv[0]);
+
+ if (len>65535)
+ {
+ cli_print(cli, "The packet length must be within range 0..65535\n");
+ return CLI_OK;
+ }
+
+ clipkt->ip_len = len;
+
+ return CLI_OK;
+}
+
+
+
+
+
+int cmd_ip_id (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+
+ u_int32_t id;
+
+ if (strncmp(argv[argc-1], "?", 2)==0)
+ {
+ cli_print(cli, "Specify the packet identification number (0..4294967295).\n");
+ return CLI_OK;
+ }
+
+ if (mz_strcmp(argv[0], "hex", 2)==0)
+ {
+ id = xstr2int (argv[1]);
+ }
+ else
+ {
+ id = str2int (argv[0]);
+ }
+
+ clipkt->ip_id = id;
+
+ return CLI_OK;
+}
+
+
+
+
+
+
+int cmd_ip_offset (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+
+ int offset;
+
+ if (strncmp(argv[argc-1], "?", 2)==0) {
+ cli_print(cli, "Specify the fragment offset in multiples of 8 bytes.\n");
+ return CLI_OK;
+ }
+
+ offset = (int) str2int(argv[0]);
+
+ if (offset>8191) {
+ cli_print(cli, "The fragment offset must be within range 0..8191\n");
+ return CLI_OK;
+ }
+
+ clipkt->ip_frag_offset = offset;
+
+ return CLI_OK;
+}
+
+
+
+
+
+int cmd_ip_sum (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ int sum;
+
+ if (strncmp(argv[argc-1], "?", 2)==0)
+ {
+ cli_print(cli, "Specify the IP checksum in hexadecimal or use the keyword 'auto'.\r");
+ cli_print(cli, "By default, the checksum is computed automatically.\n");
+ return CLI_OK;
+ }
+
+ if (mz_strcmp(argv[0], "auto", 2)==0)
+ {
+ clipkt->ip_sum_false=0;
+ return CLI_OK;
+ }
+
+ sum = (int) xstr2int(argv[0]);
+
+ if (sum>0xffff)
+ {
+ cli_print(cli, "The checksum must be within range 0..ffff\n");
+ return CLI_OK;
+ }
+
+ clipkt->ip_sum = (u_int16_t) sum;
+ clipkt->ip_sum_false=1;
+
+ return CLI_OK;
+}
+
+
+
+
+
+
+
+int cmd_ip_tos (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ char *tmp;
+
+ if (strncmp(argv[argc-1], "?", 2)==0)
+ {
+ cli_print(cli, "Specify the Type of Service field: <IPP> [<ToS>] [MBZ]\n");
+ cli_print(cli, " - IP precedence (IPP) 0..7\r");
+ cli_print(cli, " - ToS: delay/throughput/reliability/cost 0..15\r");
+ cli_print(cli, " - MBZ ('must be zero' - however, not with Mausezahn...)\r");
+ cli_print(cli, "Or, alternatively, configure the whole byte in hex.\n");
+ cli_print(cli, "EXAMPLES:\n");
+ cli_print(cli, " 5 ... IPP = 5\r");
+ cli_print(cli, " 5 9 ... IPP = 5 and ToS = 9\r");
+ cli_print(cli, " 5 MBZ ... IPP = 5 and MBZ is set\r");
+ cli_print(cli, " 5 9 MBZ ... All three fields configured\r");
+ cli_print(cli, " hex a8 ... the whole byte is set to 10101000\r");
+ cli_print(cli, " 10101000 ... the whole byte in binary\n");
+ return CLI_OK;
+ }
+
+ if ((argc==1) && (mz_strisbinary(argv[0])==8))
+ {
+ clipkt->ip_tos = (u_int8_t) str2bin8 (argv[0]);
+ return CLI_OK;
+ }
+
+ if ((argc==2) && (mz_strcmp(argv[0], "hex", 2)==0))
+ {
+ tmp = argv[1];
+
+ if (strlen(tmp)!=2)
+ {
+ cli_print(cli, "You must specify a 2-digit hexadecimal value\n");
+ return CLI_OK;
+ }
+
+ if (!(isxdigit(tmp[0])) || (!(isxdigit(tmp[1]))))
+ {
+ cli_print(cli, "Non-hexadecimal value!\n");
+ return CLI_OK;
+ }
+
+ clipkt->ip_tos = (u_int8_t) xstr2int (tmp);
+ return CLI_OK;
+ }
+
+ switch (argc)
+ {
+ case 1:
+ if (mz_strcmp(argv[0], "mbz", 1)==0)
+ {
+ mops_ip_tos(clipkt, -1, -1, 1);
+ }
+ else
+ {
+ if (mops_ip_tos(clipkt, (int)str2int(argv[0]), -1, 0))
+ cli_print(cli, "Invalid IP Precedence value\n");
+ }
+ break;
+
+ case 2:
+ if (mz_strcmp(argv[1], "mbz", 1)==0)
+ {
+ if (mops_ip_tos(clipkt, (int)str2int(argv[0]), -1, 1))
+ cli_print(cli, "Invalid IP Precedence value\n");
+ }
+ else
+ {
+ if (mops_ip_tos(clipkt, (int)str2int(argv[0]), (int)str2int(argv[1]), 0))
+ cli_print(cli, "Invalid values\n");
+ }
+ break;
+
+ case 3:
+ if (mz_strcmp(argv[2], "mbz", 1)!=0)
+ cli_print(cli, "In this case the 3rd argument must be 'mbz'\n");
+ else
+ if (mops_ip_tos(clipkt, (int)str2int(argv[0]), (int)str2int(argv[1]), 1))
+ cli_print(cli, "Invalid values\n");
+ break;
+ }
+
+ return CLI_OK;
+}
+
+
+
+
+
+
+
+int cmd_ip_dscp (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ if ((argc!=1) || (strncmp(argv[argc-1], "?", 2)==0))
+ {
+ cli_print(cli, "Specify the Type of Service field using the DSCP format.\r");
+ cli_print(cli, "Multiple notations are supported.\n");
+ cli_print(cli, "Examples:\r");
+ cli_print(cli, " AF32 .... specify AF codepoint with class 3 and drop probability 2\r");
+ cli_print(cli, " EF .... specify Expedited Forwarding\r");
+ cli_print(cli, " CS7 .... specify Code Selector 7\r");
+ cli_print(cli, " 101110 .... specify the DSCP in binary\r");
+ cli_print(cli, " 56 .... specify the DSCP in decimal\r");
+ cli_print(cli, "\r");
+ return CLI_OK;
+ }
+
+ switch (mops_ip_dscp(clipkt, argv[0]))
+ {
+ case -1:
+ cli_print(cli, "Invalid DSCP specification (use '?')\n");
+ break;
+ case 1:
+ cli_print(cli, "Invalid AF code point (use '?')\n");
+ break;
+ case 2:
+ cli_print(cli, "Invalid Code Selector (CS0..CS7)\n");
+ break;
+ case 3:
+ cli_print(cli, "Invalid DSCP value (0..63)\n");
+ break;
+ }
+
+ return CLI_OK;
+}
+
+
+
+
+
+int cmd_ip_rsv (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+
+ if (strncmp(argv[argc-1], "?", 2)==0)
+ {
+ cli_print(cli, "Set or unset the reserved flag.\n");
+ return CLI_OK;
+ }
+
+ if (argc!=1)
+ {
+ cli_print(cli, "Use the 'set' or 'unset' keywords.\n");
+ return CLI_OK;
+ }
+
+
+ if (mz_strcmp(argv[0], "set", 1)==0)
+ {
+ clipkt->ip_flags_RS = 1;
+ return CLI_OK;
+ }
+
+ if (mz_strcmp(argv[0], "unset", 1)==0)
+ {
+ clipkt->ip_flags_RS = 0;
+ return CLI_OK;
+ }
+
+ cli_print(cli, "Unknown keyword. Use the 'set' or 'unset' keywords.\n");
+
+ return CLI_OK;
+
+}
+
+
+
+
+
+int cmd_ip_df (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+
+ if (strncmp(argv[argc-1], "?", 2)==0)
+ {
+ cli_print(cli, "Set or unset the don't fragment flag.\n");
+
+ return CLI_OK;
+ }
+
+ if (argc!=1)
+ {
+ cli_print(cli, "Use the 'set' or 'unset' keywords.\n");
+ return CLI_OK;
+ }
+
+
+ if (mz_strcmp(argv[0], "set", 1)==0)
+ {
+ clipkt->ip_flags_DF = 1;
+ return CLI_OK;
+ }
+
+ if (mz_strcmp(argv[0], "unset", 1)==0)
+ {
+ clipkt->ip_flags_DF = 0;
+ return CLI_OK;
+ }
+
+ cli_print(cli, "Unknown keyword. Use the 'set' or 'unset' keywords.\n");
+
+
+ return CLI_OK;
+
+}
+
+
+
+
+
+int cmd_ip_mf (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+
+ if (strncmp(argv[argc-1], "?", 2)==0)
+ {
+ cli_print(cli, "Set or unset the more fragments flag.\n");
+
+ return CLI_OK;
+ }
+
+ if (argc!=1)
+ {
+ cli_print(cli, "Use the 'set' or 'unset' keywords.\n");
+ return CLI_OK;
+ }
+
+
+ if (mz_strcmp(argv[0], "set", 1)==0)
+ {
+ clipkt->ip_flags_MF = 1;
+ return CLI_OK;
+ }
+
+ if (mz_strcmp(argv[0], "unset", 1)==0)
+ {
+ clipkt->ip_flags_MF = 0;
+ return CLI_OK;
+ }
+
+ cli_print(cli, "Unknown keyword. Use the 'set' or 'unset' keywords.\n");
+
+ return CLI_OK;
+
+}
+
+
+int cmd_ip_fragsize (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ u_int32_t fragsize=0;
+
+ if (strncmp(argv[argc-1], "?", 2)==0) {
+ cli_print(cli, "Enable fragmentation by configuring a fragment size.\n");
+ cli_print(cli, "Note that the fragment size specifies the number of bytes in the IP payload\r");
+ cli_print(cli, "and NOT the assumed MTU on that link. The total packet size of each fragment\r");
+ cli_print(cli, "will be 20 bytes larger (=size of IP header if no IP options are used).\n");
+ cli_print(cli, "WARNING: The fragment size SHOULD be a multiple of 8 bytes if you expect\r");
+ cli_print(cli, " a valid result.\n");
+ cli_print(cli, "ARGUMENTS: <frag-size>\n");
+ return CLI_OK;
+ }
+
+ if (argc!=1) {
+ cli_print(cli, "Specify the fragment size in bytes.\n");
+ return CLI_OK;
+ }
+
+
+ fragsize = (u_int32_t) str2int(argv[0]);
+
+ if ((fragsize<0) || (fragsize>8000)) {
+ cli_print(cli, "The fragment size must be within range 0..8000\n");
+ return CLI_OK;
+ }
+
+ if (fragsize%8) {
+ cli_print(cli, "Warning: The fragment-size is not a multiple of 8.\n");
+ }
+
+ clipkt->ip_fragsize = fragsize;
+
+ return CLI_OK;
+
+}
+
+
+
+int cmd_ip_fragoverlap (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ u_int32_t overlap=0;
+
+ if (strncmp(argv[argc-1], "?", 2)==0) {
+ cli_print(cli, "Specify how many bytes should overlap when IP fragmentation is enabled.\n");
+ cli_print(cli, "NOTE: The number of overlap bytes is either 0 (default, no overlap) or\r");
+ cli_print(cli, " a multiple of 8 bytes but smaller than frag-size.\n");
+ cli_print(cli, "ARGUMENTS: <overlap>\n");
+ return CLI_OK;
+ }
+
+ if (argc!=1) {
+ cli_print(cli, "Specify how many bytes should overlap between successive IP fragments.\n");
+ return CLI_OK;
+ }
+
+
+ overlap = (u_int32_t) str2int(argv[0]);
+
+ if (clipkt->ip_fragsize == 0) {
+ cli_print(cli, "Please configure the fragment size first.\n");
+ return CLI_OK;
+ }
+
+ if ((overlap>clipkt->ip_fragsize) || (overlap%8)) {
+ cli_print(cli, "The overlap MUST be a multiple of 8 and MUST NOT exceed frag-size!\n");
+ return CLI_OK;
+ }
+
+ clipkt->ip_frag_overlap = overlap;
+
+ return CLI_OK;
+}
+
+
+
+
+
+int cmd_ip_option (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ int val=0;
+
+ if ((strncmp(argv[argc-1], "?", 2)==0) || (argc==0)) {
+ cli_print(cli, "Add or delete IP options.\n");
+ cli_print(cli, "You can only add one option after the other; if you want to configure multiple\r");
+ cli_print(cli, "options then repeat this command. The options are added to the IP header in the\r");
+ cli_print(cli, "same order as you configure them.\n");
+ cli_print(cli, "Currently the following options are supported:\n");
+ cli_print(cli, "router-alert [<value>] ... signal transit routers to examine the content of this\r");
+ cli_print(cli, " packet.\r");
+ cli_print(cli, "\n");
+ cli_print(cli, "clear ..................... remove all options from the packet\n");
+ return CLI_OK;
+ }
+
+ if (mz_strcmp(argv[0], "router-alert", 3)==0) {
+ switch (argc) {
+ case 1:
+ val=0;
+ break;
+ case 2:
+ val = (int) str2int(argv[1]);
+ break;
+ default:
+ cli_print(cli, "Too many arguments!\n");
+ return CLI_OK;
+ }
+ if (mops_ip_option_ra (clipkt, val)) {
+ cli_print(cli, "Value must be within 0..65535\n");
+ return CLI_OK;
+ }
+
+ } else if (mz_strcmp(argv[0], "loose-source-route", 3)==0) {
+ cli_print(cli, "Currently not implemented\n");
+ return CLI_OK;
+ } else if (mz_strcmp(argv[0], "record-route", 3)==0) {
+ cli_print(cli, "Currently not implemented\n");
+ return CLI_OK;
+ }
+
+ else if (mz_strcmp(argv[0], "clear", 2)==0) {
+ mops_ip_option_remove_all (clipkt);
+ }
+
+ return CLI_OK;
+}
+
+
+
+// By default we use ARP to determine the destination MAC and therefore support
+// automatic (in)direct delivery of IP packets. Alternatively the user may turn
+// this off and may configure an arbitrary destination MAC address
+//
+int cmd_ip_delivery (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ char str[16];
+ if (strncmp(argv[argc-1], "?", 2)==0) {
+ cli_print(cli, "Enable or disable IP auto-delivery.\n");
+ sprintf(str, "%s", (clipkt->auto_delivery_off) ? "DISABLED" : "ENABLED");
+ cli_print(cli, "Currently, IP auto-delivery is %s\n", str);
+ return CLI_OK;
+ }
+
+ if (argc!=1) {
+ cli_print(cli, "Argument missing. Enter either 'enable' or 'disable'\n");
+ return CLI_OK;
+ }
+
+ if (mz_strcmp(argv[0], "enable", 1)==0)
+ clipkt->auto_delivery_off=0;
+ else if (mz_strcmp(argv[0], "disable", 1)==0)
+ clipkt->auto_delivery_off=1;
+ else {
+ cli_print(cli, "Unknown keyword. Enter either 'enable' or 'disable'\n");
+ return CLI_OK;
+ }
+
+ sprintf(str, "%s", (clipkt->auto_delivery_off) ? "DISABLED" : "ENABLED");
+ cli_print(cli, "IP auto-delivery is now %s\n", str);
+
+ return CLI_OK;
+
+}
+
+
+
+int cmd_ip_end(struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ char prompt[16];
+ sprintf(prompt, "pkt-%i",clipkt->id);
+ cli_set_configmode(cli, MZ_MODE_PACKET, prompt);
+ return CLI_OK;
+}
diff --git a/staging/cli_launch.c b/staging/cli_launch.c
new file mode 100644
index 0000000..19b6ba0
--- /dev/null
+++ b/staging/cli_launch.c
@@ -0,0 +1,141 @@
+/*
+ * Mausezahn - A fast versatile traffic generator
+ * Copyright (C) 2008-2010 Herbert Haas
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
+ *
+*/
+
+
+
+#include "mz.h"
+#include "cli.h"
+#include "mops.h"
+
+
+
+int launch_bpdu (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ int conf=0;
+ struct mops_ext_bpdu * pd;
+
+ if ( (strncmp(argv[argc-1],"?",2)==0) || (argc>1) ) {
+ cli_print(cli, "Launch a(nother) BPDU process:\n");
+ cli_print(cli, "<CR> Per default a TCN-BPDU is sent.\r");
+ cli_print(cli, "conf Use this keyword to emit configuration BPDUs\r");
+ cli_print(cli, " (with this host as root bridge)\n");
+ return CLI_OK;
+ }
+
+ if (argc==1) {
+ if (mz_strcmp(argv[0], "conf", 1)==0) conf=1;
+ }
+
+ if ((clipkt = mops_alloc_packet(mp_head)) == NULL) { // Problem, memory full?
+ cli_print(cli, "Cannot allocate additional memory!\n");
+ return CLI_OK;
+ }
+
+ strncpy (clipkt->packet_name, "sysBPDU", 7);
+ // OK, created a new packet
+ cli_print(cli, "Allocated new packet %s at slot %i",clipkt->packet_name, clipkt->id);
+ mops_set_defaults(clipkt);
+ if (mops_ext_add_pdesc (clipkt, MOPS_BPDU))
+ cli_print(cli, "Cannot configure BPDU parameters!?\n");
+ else {
+ clipkt->use_ETHER = 1;
+ clipkt->use_SNAP = 1;
+ clipkt->count = 0;
+ clipkt->ndelay.tv_sec = 2;
+ clipkt->ndelay.tv_nsec = 0;
+ pd = clipkt->p_desc;
+ if (conf)
+ pd->bpdu_type = 0x00;
+ else
+ pd->bpdu_type = 0x80;
+ mops_set_conf(clipkt);
+ if (mops_tx_simple (clipkt)) {
+ cli_print(cli, "Cannot create sending process.\r");
+ }
+ }
+
+ return CLI_OK;
+}
+
+
+
+int launch_synflood (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ u_int8_t IP[4];
+ int valid_ip=0, valid_port=0;
+
+ if ( (strncmp(argv[argc-1],"?",2)==0) || (argc>2) || (argc==0)) {
+ cli_print(cli, "Launch a(nother) TCP SYN-Flood process:\n");
+ cli_print(cli, "<dst-ip-addr> At least you must specify the destination IP address\r");
+ cli_print(cli, "<dst-ip-addr> <port-nr> Optionally specify the destination port (default: range from 1-1023)\n");
+ return CLI_OK;
+ }
+
+ if (mops_pdesc_ip (IP, argv[0])==0) { // check if format is really an IP address
+ valid_ip=1;
+ } else {
+ cli_print(cli, "Invalid IP address\n");
+ return CLI_OK;
+ }
+
+ if (argc==2) {
+ if (mz_strisnum(argv[1])==0) {
+ cli_print(cli, "Invalid port number\n");
+ return CLI_OK;
+ }
+ valid_port = (int) str2int(argv[1]);
+ if (valid_port>65535) {
+ cli_print(cli, "Invalid port number\n");
+ return CLI_OK;
+ }
+ }
+
+
+ if ((clipkt = mops_alloc_packet(mp_head)) == NULL) { // Problem, memory full?
+ cli_print(cli, "Cannot allocate additional memory!\n");
+ return CLI_OK;
+ }
+
+ strncpy (clipkt->packet_name, "sysFlood_TCPSYN", 15);
+ // OK, created a new packet
+ cli_print(cli, "Allocated new packet %s at slot %i",clipkt->packet_name, clipkt->id);
+ mops_set_defaults(clipkt);
+ clipkt->use_ETHER = 1;
+ clipkt->use_IP = 1;
+ clipkt->use_TCP = 1;
+ clipkt->ip_proto = 6;
+ clipkt->count = 0;
+ clipkt->ip_dst = str2ip32(argv[0]);
+ clipkt->ip_src_israndom=1;
+ if (valid_port) {
+ clipkt->dp = valid_port;
+ } else {
+ clipkt->dp_isrange=1;
+ clipkt->dp_start=1;
+ clipkt->dp_stop=1023;
+ }
+ clipkt->ndelay.tv_sec = 0;
+ clipkt->ndelay.tv_nsec = 0;
+ mops_set_conf(clipkt);
+ mops_tcp_add_option (clipkt,64,0,0,0,0);
+ if (mops_tx_simple (clipkt)) {
+ cli_print(cli, "Cannot create sending process.\r");
+ }
+
+ return CLI_OK;
+}
diff --git a/staging/cli_legacy.c b/staging/cli_legacy.c
new file mode 100644
index 0000000..2adc535
--- /dev/null
+++ b/staging/cli_legacy.c
@@ -0,0 +1,141 @@
+/*
+ * Mausezahn - A fast versatile traffic generator
+ * Copyright (C) 2008 Herbert Haas
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
+ *
+*/
+
+
+#include "mz.h"
+#include "cli.h"
+#include "mops.h"
+
+
+int transmit (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ int i;
+ char argstr[10000];
+
+ argstr[0]='\0';
+
+ if (argc>1)
+ {
+ for (i=1; i<argc; i++)
+ {
+ if ((strlen(argv[i])+strlen(argstr))>10000)
+ {
+ cli_print(cli, "Argument list too long!\n");
+ return CLI_OK;
+ }
+ if (strncmp(argv[i], "?", 1)==0)
+ {
+ strcat(argstr, ",help");
+ }
+ else
+ strncat(argstr, argv[i], 5000); // TODO: This is ugly!
+ }
+ // TEST: cli_print(cli, "argc=%i, got '%s'\n", argc, argstr);
+ }
+
+
+ if (argv[0] == NULL) // raw hex string given
+ {
+ mode = BYTE_STREAM;
+ }
+ else if (strcmp(argv[0],"arp")==0)
+ {
+ mode = ARP;
+ }
+ else if (strcmp(argv[0],"bpdu")==0)
+ {
+ mode = BPDU;
+ }
+ else if (strcmp(argv[0],"ip")==0)
+ {
+ mode = IP;
+ }
+ else if (strcmp(argv[0],"udp")==0)
+ {
+ mode = UDP;
+ }
+ else if (strcmp(argv[0],"icmp")==0)
+ {
+ mode = ICMP;
+ }
+ else if (strcmp(argv[0],"tcp")==0)
+ {
+ mode = TCP;
+ }
+ else if (strcmp(argv[0],"dns")==0)
+ {
+ mode = DNS;
+ }
+ else if (strcmp(argv[0],"cdp")==0)
+ {
+ mode = CDP;
+ }
+ else if (strcmp(argv[0],"syslog")==0)
+ {
+ mode = SYSLOG;
+ }
+ else if (strcmp(argv[0],"lldp")==0)
+ {
+ mode = LLDP;
+ tx.packet_mode=0; // create whole frame by ourself
+ }
+ else if (strcmp(argv[0],"rtp")==0)
+ {
+ mode = RTP;
+ }
+ else if (strcmp(argv[0],"raw")==0)
+ {
+ strncpy(tx.arg_string, argstr, MAX_PAYLOAD_SIZE);
+ send_eth();
+ }
+ else if (strcmp(argv[0],"?")==0)
+ {
+ cli_print(cli,
+ "| The following packet types are currently implemented:\n"
+ "|\n"
+ "| arp ... sends ARP packets\n"
+ "| bpdu ... sends BPDU packets (STP)\n"
+ "| cdp ... sends CDP messages\n"
+ "| ip ... sends IPv4 packets\n"
+ "| udp ... sends UDP datagrams\n"
+ "| tcp ... sends TCP segments\n"
+ "| icmp ... sends ICMP messages\n"
+ "| dns ... sends DNS messages\n"
+ "| rtp ... sends RTP datagrams\n"
+ "| syslog ... sends Syslog messages\n"
+ "| lldp ... sends LLDP datagrams\n"
+ "|\n"
+ "| raw ... raw layer 2 mode (specify whole frame in hex)\n"
+ "\n"
+ );
+ return CLI_OK;
+ }
+ else
+ {
+ cli_print(cli, "Unknown packet type '%s'\r", argv[0]);
+ }
+
+
+ if (mode)
+ {
+ strncpy(tx.arg_string, argstr, MAX_PAYLOAD_SIZE);
+ tx_switch(cli);
+ }
+
+ return CLI_OK;
+}
diff --git a/staging/cli_lldp.c b/staging/cli_lldp.c
new file mode 100644
index 0000000..8991137
--- /dev/null
+++ b/staging/cli_lldp.c
@@ -0,0 +1,437 @@
+/*
+ * Mausezahn - A fast versatile traffic generator
+ * Copyright (C) 2008-2010 Herbert Haas
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
+ *
+*/
+
+
+
+#include "mz.h"
+#include "cli.h"
+#include "mops.h"
+
+
+int cmd_lldp_conformance (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ struct mops_ext_lldp * pd = clipkt->p_desc;
+
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc!=1)) {
+ cli_print(cli, "Enables or disables LLDP standard conformance mode.\n");
+ cli_print(cli, "Keywords: enable | disable\n");
+ cli_print(cli, "Per default, standard LLDP messages are created which require a fixed\r");
+ cli_print(cli, "order of the mandatory TLVs. If the standard conformance mode is disabled\r");
+ cli_print(cli, "then you can configure an arbitrary sequence of LLDP TLVs. \n");
+ cli_print(cli, "Currently, the LLDP standard conformance mode is %s\n", (pd->non_conform) ? "DISABLED" : "ENABLED");
+ return CLI_OK;
+ }
+
+ if (mz_strcmp(argv[0], "enable", 1)==0) {
+ pd->non_conform = 0;
+ return CLI_OK;
+ }
+
+
+ if (mz_strcmp(argv[0], "disable", 1)==0) {
+ pd->non_conform = 1;
+ return CLI_OK;
+ }
+
+ cli_print(cli, "Enter enable or disable\n");
+ return CLI_OK;
+}
+
+
+int cmd_lldp_chassis_id (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ struct mops_ext_lldp * pd = clipkt->p_desc;
+ int subtype = 4;
+ char *cid;
+ int cl, cidl;
+ u_int8_t tmp[512];
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc>2)) {
+ cli_print(cli, "Configure a Chassis ID TLV.\n");
+ cli_print(cli, "ARGUMENTS: [<subtype>] <chassis-id>\n");
+ cli_print(cli, "By default the <subtype> is of kind 'mac address (4)' and the <chassis-id>\r");
+ cli_print(cli, "must be a hexadecimal string (e. g. 00:01:ca:fe:de:ad) of max 255 bytes\n");
+ return CLI_OK;
+ }
+
+ if (argc==2) {
+ subtype = (int) str2int(argv[0]);
+ if ((subtype>255) || (mz_strisnum(argv[0])==0)) {
+ cli_print(cli, "Invalid subtype\n");
+ return CLI_OK;
+ }
+ cid = argv[1];
+ } else
+ cid = argv[0];
+
+ cl=strnlen(cid, 1024);
+
+ if (cl>=1024) {
+ cli_print(cli, "Chassis-ID too long\n");
+ return CLI_OK;
+ } else cidl=str2hex(cid, tmp, 511);
+
+ if (pd->non_conform == 0) {
+ pd->chassis_id_subtype = subtype;
+ memcpy((void*) pd->chassis_id, (void*)tmp, cidl);
+ pd->chassis_id_len = cidl;
+ } else {
+ // non_conform
+ mops_lldp_opt_tlv_chassis (clipkt, subtype, cidl, tmp);
+ }
+
+ return CLI_OK;
+}
+
+
+
+
+int cmd_lldp_port_id (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ struct mops_ext_lldp * pd = clipkt->p_desc;
+ int subtype = 4;
+ char *pid;
+ int pl;
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc>2)) {
+ cli_print(cli, "Configure a Port ID TLV.\n");
+ cli_print(cli, "ARGUMENTS: [<subtype>] <port-id>\n");
+ cli_print(cli, "By default the <subtype> is of kind 'Interface name (5)' and the <port-id>\r");
+ cli_print(cli, "must be a ascii string (usually the name of the interface e. g. eth3) of\r");
+ cli_print(cli, "max 255 bytes.\n");
+ return CLI_OK;
+ }
+
+ if (argc==2) {
+ subtype = (int) str2int(argv[0]);
+ if ((subtype>255) || (mz_strisnum(argv[0])==0)) {
+ cli_print(cli, "Invalid subtype\n");
+ return CLI_OK;
+ }
+ pid = argv[1];
+ } else
+ pid = argv[0];
+
+ pl=strnlen(pid, 256);
+
+ if (pl>255) {
+ cli_print(cli, "Port-ID too long\n");
+ return CLI_OK;
+ }
+
+
+ if (pd->non_conform == 0) {
+ pd->port_id_subtype = subtype;
+ memcpy((void*) pd->port_id, (void*) pid, pl);
+ pd->port_id_len = pl;
+ } else {
+ // non_conform
+ mops_lldp_opt_tlv_port (clipkt, subtype, pl, (u_int8_t*) pid);
+ }
+
+ return CLI_OK;
+}
+
+
+
+int cmd_lldp_ttl (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ struct mops_ext_lldp * pd = clipkt->p_desc;
+ int ttl;
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc!=1)) {
+ cli_print(cli, "Configure the LLDP TTL.\n");
+ cli_print(cli, "ARGUMENTS: <time-to-live>\n");
+ cli_print(cli, "The TTL must be within 0..65535\n");
+ return CLI_OK;
+ }
+
+ ttl = (int) str2int(argv[0]);
+
+ if (mz_strisnum(argv[0])==0) {
+ cli_print(cli, "Invalid argument\n");
+ return CLI_OK;
+ }
+
+ if (ttl>0xffff) {
+ cli_print(cli, "TTL must be within 0..65535\n");
+ return CLI_OK;
+ }
+
+ if (pd->non_conform == 0) {
+ pd->TTL = ttl;
+ } else {
+ // non_conform
+ mops_lldp_opt_tlv_TTL (clipkt, ttl);
+ }
+
+ return CLI_OK;
+}
+
+
+
+int cmd_lldp_vlan (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ int vlan;
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc!=1)) {
+ cli_print(cli, "Configure the LLDP Port VLAN-ID.\n");
+ cli_print(cli, "ARGUMENTS: <vlan-id>\n");
+ cli_print(cli, "The vlan-id must be within 0..65535\n");
+ return CLI_OK;
+ }
+
+ vlan = (int) str2int(argv[0]);
+
+ if (mz_strisnum(argv[0])==0) {
+ cli_print(cli, "Invalid argument\n");
+ return CLI_OK;
+ }
+
+ if (vlan>0xffff) {
+ cli_print(cli, "The VLAN-ID must be within 0..65535\n");
+ return CLI_OK;
+ }
+
+
+ mops_lldp_opt_tlv_vlan (clipkt, vlan);
+
+ return CLI_OK;
+}
+
+
+
+int cmd_lldp_opt_tlv (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ int type=0, len=0;
+ u_int8_t tmp[512];
+
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc!=3)) {
+ cli_print(cli, "Configure an arbitrary optional TLV.\n");
+ cli_print(cli, "ARGUMENTS: ascii|hex <type> <value>\n");
+ cli_print(cli, "The TLV type must be between 0..127, the value length is up to 511 bytes.\n");
+ return CLI_OK;
+ }
+
+
+ if (mz_strcmp(argv[0], "ascii", 1)==0) {
+ if ((len=strnlen(argv[2],512))>511) {
+ cli_print(cli, "<value> must be smaller or equal 511 characters\n");
+ return CLI_OK;
+ }
+ mz_strncpy((char*) tmp, argv[2], 511);
+ } else if (mz_strcmp(argv[0], "hex", 1)==0) {
+ len=str2hex(argv[2], tmp, 512);
+ if (len>511) {
+ cli_print(cli, "<value> must be smaller or equal 511 bytes\n");
+ return CLI_OK;
+ }
+ }
+
+ type = (int) str2int(argv[1]);
+
+ if (mz_strisnum(argv[1])==0) {
+ cli_print(cli, "Invalid type\n");
+ return CLI_OK;
+ }
+
+ if (type>127) {
+ cli_print(cli, "<type> must be within 0..127\n");
+ return CLI_OK;
+ }
+
+
+ if (mops_lldp_opt_tlv (clipkt, type, len, tmp)==0)
+ cli_print(cli, "Invalid TLV values\n");
+
+ return CLI_OK;
+}
+
+
+
+
+int cmd_lldp_opt_tlv_bad (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ int type, len=0, wronglen;
+ u_int8_t tmp[512];
+
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc!=4)) {
+ cli_print(cli, "Configure an arbitrary optional *BAD* TLV.\n");
+ cli_print(cli, "ARGUMENTS: ascii|hex <type> <wrong-length> <value>\n");
+ cli_print(cli, "Using this command you can add a custom TLV with a wrong length parameter.\r");
+ cli_print(cli, "Such TLV can be used to verify whether LLDP receivers are robust enough\r\r");
+ cli_print(cli, "since a too small <wrong-length> could cause a buffer overflow. The TLV type\r");
+ cli_print(cli, "must be between 0..127, the <wrong-length> can be within 0..511 (and can be\r");
+ cli_print(cli, "also the true length of course\n");
+ return CLI_OK;
+ }
+
+
+ if (mz_strcmp(argv[0], "ascii", 1)==0) {
+ if ((len=strnlen(argv[3],512))>511) {
+ cli_print(cli, "<value> must be smaller or equal 511 characters\n");
+ return CLI_OK;
+ }
+ mz_strncpy((char*) tmp, argv[3], 511);
+ } else if (mz_strcmp(argv[0], "hex", 1)==0) {
+ len=str2hex(argv[3], tmp, 512);
+ if (len>511) {
+ cli_print(cli, "<value> must be smaller or equal 511 bytes\n");
+ return CLI_OK;
+ }
+ }
+
+ type = (int) str2int(argv[1]);
+
+ if (mz_strisnum(argv[1])==0) {
+ cli_print(cli, "Invalid type\n");
+ return CLI_OK;
+ }
+
+ if (type>127) {
+ cli_print(cli, "<type> must be within 0..127\n");
+ return CLI_OK;
+ }
+
+ wronglen = (int) str2int(argv[2]);
+
+ if (mz_strisnum(argv[2])==0) {
+ cli_print(cli, "Invalid length\n");
+ return CLI_OK;
+ }
+
+ if (wronglen>511) {
+ cli_print(cli, "<wrong-length> must be within 0..511\n");
+ return CLI_OK;
+ }
+
+ if (mops_lldp_opt_tlv_bad (clipkt, type, wronglen, len, tmp)==0)
+ cli_print(cli, "Invalid TLV values\n");
+
+ return CLI_OK;
+}
+
+
+
+int cmd_lldp_opt_org (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ int subtype, len=0, oui=0;
+ u_int8_t tmp[512];
+
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc!=4)) {
+ cli_print(cli, "Configure an organisational TLV.\n");
+ cli_print(cli, "ARGUMENTS: ascii|hex <oui> <subtype> <value>\n");
+ cli_print(cli, "Using this command you can add an arbitrary organisational TLV. The <oui> represents\r");
+ cli_print(cli, "the 'Organisational Unique Identifier' and consists of exactly three bytes in hexadecimal\r");
+ cli_print(cli, "format, such as '00005e' The <subtype> is a value between <0..255>, and the length of the\r");
+ cli_print(cli, "value is up to 507 bytes.\n");
+ return CLI_OK;
+ }
+
+
+ if (mz_strcmp(argv[0], "ascii", 1)==0) {
+ if ((len=strnlen(argv[3],512))>511) {
+ cli_print(cli, "<value> must be smaller or equal 511 characters\n");
+ return CLI_OK;
+ }
+ mz_strncpy((char*) tmp, argv[3], 511);
+ } else if (mz_strcmp(argv[0], "hex", 1)==0) {
+ len=str2hex(argv[3], tmp, 512);
+ if (len>511) {
+ cli_print(cli, "<value> must be smaller or equal 511 bytes\n");
+ return CLI_OK;
+ }
+ }
+
+ oui = xstr2int(argv[1]);
+ if (mz_strishex(argv[1])==0) {
+ cli_print(cli, "Invalid oui value\n");
+ return CLI_OK;
+ }
+
+ if (oui>0xffffff) {
+ cli_print(cli, "<oui> must be within 0..ffffff\n");
+ return CLI_OK;
+ }
+
+ subtype = (int) str2int(argv[2]);
+
+ if (mz_strisnum(argv[2])==0) {
+ cli_print(cli, "Invalid subtype\n");
+ return CLI_OK;
+ }
+
+ if (subtype>255) {
+ cli_print(cli, "<subtype> must be within 0..255\n");
+ return CLI_OK;
+ }
+
+
+ if (mops_lldp_opt_tlv_org (clipkt, oui, subtype, len, tmp)==0)
+ cli_print(cli, "Invalid TLV values\n");
+
+ return CLI_OK;
+}
+
+
+
+
+
+int cmd_lldp_endtlv (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc>0)) {
+ cli_print(cli, "Add an 'End of LLDP' TLV\n");
+ cli_print(cli, "ARGUMENTS: none\n");
+ cli_print(cli, "This command allows you to insert an 'End of LLDP' TLV at any\r");
+ cli_print(cli, "point within the optional TLV list. You usually want this to\r");
+ cli_print(cli, "create an invalid LLDPU to test the receiver.\n");
+ return CLI_OK;
+ }
+
+
+ mops_lldp_opt_tlv_end (clipkt);
+
+ return CLI_OK;
+}
+
+
+int cmd_lldp_reset (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc>0)) {
+ cli_print(cli, "Reset the LLPDU and clear all optional TLVs.\n");
+ cli_print(cli, "ARGUMENTS: none\n");
+ cli_print(cli, "All optional TLVs are added in the sequence as you configure them.\r");
+ cli_print(cli, "Use this command to reset the LLDP and reconfigure all optional\r");
+ cli_print(cli, "TLVs again. Additionally the parameters of the mandatory TLVs are\r");
+ cli_print(cli, "reset to defaults.\n");
+ return CLI_OK;
+ }
+
+ mops_init_pdesc_lldp(clipkt);
+
+ return CLI_OK;
+}
+
+
+
diff --git a/staging/cli_packet.c b/staging/cli_packet.c
new file mode 100644
index 0000000..03fbd03
--- /dev/null
+++ b/staging/cli_packet.c
@@ -0,0 +1,1121 @@
+/*
+ * Mausezahn - A fast versatile traffic generator
+ * Copyright (C) 2008-2010 Herbert Haas
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
+ *
+*/
+
+
+#include "mz.h"
+#include "cli.h"
+#include "mops.h"
+
+
+int debug_packet (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ cli_debug = CLI_DEBUG_PACKET;
+ cli_print (cli, "Packet debugging enabled\n");
+ return CLI_OK;
+}
+
+
+
+
+// Enter packet config mode:
+//
+// 1) either with an optional packet slot number => modify existing slot
+// 2) or without number to allocate a new slot entry
+//
+int enter_packet (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ char prompt[16];
+
+ if (argc==0) { // Allocate new packet
+ if ((clipkt = mops_alloc_packet(mp_head)) == NULL) { // Problem, memory full?
+ cli_print(cli, "Holy flying spaghetti monster! Cannot allocate additional memory!\n");
+ return CLI_OK;
+ }
+ // OK, created a new packet
+ snprintf(prompt, 16, "pkt-%i",clipkt->id);
+ cli_print(cli, "Allocated new packet %s at slot %i",clipkt->packet_name, clipkt->id);
+ // mops_set_defaults(clipkt); //// implicitly done by mops_alloc_packet
+ } else if ( (strcmp(argv[argc-1],"?")==0) || (argc>1) ) {
+ cli_print(cli, "<CR> create a new packet slot\r");
+ cli_print(cli, "NAME enter packet slot of packet with name NAME\r");
+ cli_print(cli, "ID enter packet slot of packet with number ID\n");
+ return CLI_OK;
+ } else { // user specified a unique packet_name
+ if ( (clipkt = mops_search_name (mp_head, argv[0]))==NULL) { // packet name does not exist
+ if ( (clipkt = mops_search_id (mp_head, (int) str2int(argv[0])))==NULL) { // packet id does not exist
+ cli_print(cli, "Packet does not exist\n");
+ return CLI_OK;
+ }
+ }
+ if (mops_is_any_active(clipkt)) { // don't allow to configure packets which are active!
+ cli_print(cli, "The selected packet is currently in active state!\r");
+ cli_print(cli, "In order to configure this packet, please stop the associated packet process first.\n");
+ return CLI_OK;
+ }
+ snprintf(prompt, 16, "pkt-%i",clipkt->id);
+ cli_print(cli, "Modify packet parameters for packet %s [%i]",clipkt->packet_name, clipkt->id);
+ }
+ cli_set_configmode(cli, MZ_MODE_PACKET, prompt);
+ //cli_print(cli, "Packet configuration mode - called %s with %s\r\n", __FUNCTION__, command);
+ return CLI_OK;
+}
+
+
+
+
+
+
+
+// Specify the type and enter the appropriate configuration mode
+// NOTE that we also reset and create the p_desc here!
+int cmd_packet_type(struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ char prompt[16];
+ int ret=0;
+ char wrn[] = "Error: Could not create mops extension handle\n";
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc!=1) )
+ {
+ cli_print(cli, "Specify a packet type from the following list:\r\n");
+ cli_print(cli, " arp\r");
+ cli_print(cli, " bpdu\r");
+// cli_print(cli, " cdp (not supported in this version)\r");
+// cli_print(cli, " icmp (not supported in this version)\r");
+ cli_print(cli, " igmp\r");
+ cli_print(cli, " ip\r");
+ cli_print(cli, " lldp\r");
+ cli_print(cli, " rtp\r");
+// cli_print(cli, " syslog (not supported in this version)\r");
+ cli_print(cli, " tcp\r");
+ cli_print(cli, " udp\r");
+ return CLI_OK;
+ }
+
+ if (mz_strcmp(argv[0],"arp",3) == 0)
+ {
+ if (mops_ext_add_pdesc (clipkt, MOPS_ARP))
+ cli_print(cli, "%s", wrn);
+ else
+ {
+ ret=mops_clear_layers(clipkt,
+ MOPS_SNAP|MOPS_MPLS|MOPS_IP|MOPS_UDP|MOPS_TCP);
+ clipkt->use_ETHER = 1;
+ clipkt->eth_type = 0x806;
+ sprintf(prompt, "pkt-%i-arp",clipkt->id);
+ cli_set_configmode(cli, MZ_MODE_PACKET_ARP, prompt);
+ mops_update_arp(clipkt);
+ mops_set_conf(clipkt);
+ }
+
+ }
+ else if (mz_strcmp(argv[0],"dns",3) == 0)
+ {
+ if (mops_ext_add_pdesc (clipkt, MOPS_DNS))
+ cli_print(cli, "%s", wrn);
+ else
+ {
+ ret=mops_clear_layers(clipkt, MOPS_SNAP|MOPS_TCP);
+ clipkt->use_ETHER = 1;
+ clipkt->use_IP= 1;
+ clipkt->use_UDP= 1;
+ sprintf(prompt, "pkt-%i-dns",clipkt->id);
+ cli_set_configmode(cli, MZ_MODE_PACKET_DNS, prompt);
+ mops_set_conf(clipkt);
+ }
+ }
+ else if (mz_strcmp(argv[0],"icmp",3) == 0)
+ {
+ if (mops_ext_add_pdesc (clipkt, MOPS_ICMP))
+ cli_print(cli, "%s", wrn);
+ else
+ {
+ ret=mops_clear_layers(clipkt, MOPS_SNAP|MOPS_TCP|MOPS_UDP);
+ clipkt->use_ETHER = 1;
+ clipkt->use_IP= 1;
+ sprintf(prompt, "pkt-%i-icmp",clipkt->id);
+ cli_set_configmode(cli, MZ_MODE_PACKET_ICMP, prompt);
+ mops_set_conf(clipkt);
+ }
+ }
+ else if (mz_strcmp(argv[0],"igmp",3) == 0)
+ {
+ if (mops_ext_add_pdesc (clipkt, MOPS_IGMP))
+ cli_print(cli, "%s", wrn);
+ else
+ {
+ ret=mops_clear_layers(clipkt, MOPS_SNAP|MOPS_TCP|MOPS_UDP);
+ clipkt->use_ETHER = 1;
+ clipkt->use_IP= 1;
+ clipkt->ip_proto = 2;
+ mops_ip_option_ra(clipkt, 0); // add router alert option to IP header
+ sprintf(prompt, "pkt-%i-igmp",clipkt->id);
+ cli_set_configmode(cli, MZ_MODE_PACKET_IGMP, prompt);
+ mops_update_igmp(clipkt);
+ mops_set_conf(clipkt);
+ }
+ }
+
+ else if (mz_strcmp(argv[0],"cdp",3) == 0)
+ {
+ if (mops_ext_add_pdesc (clipkt, MOPS_CDP))
+ cli_print(cli, "%s", wrn);
+ else
+ {
+ ret=mops_clear_layers(clipkt, MOPS_ALL);
+ clipkt->use_ETHER = 1;
+ sprintf(prompt, "pkt-%i-cdp",clipkt->id);
+ cli_set_configmode(cli, MZ_MODE_PACKET_CDP, prompt);
+ mops_set_conf(clipkt);
+ }
+ }
+ else if (mz_strcmp(argv[0],"bpdu",3) == 0)
+ {
+ if (mops_ext_add_pdesc (clipkt, MOPS_BPDU))
+ cli_print(cli, "%s", wrn);
+ else
+ {
+ ret=mops_clear_layers(clipkt, MOPS_MPLS|MOPS_IP|MOPS_UDP|MOPS_TCP);
+ clipkt->use_ETHER = 1;
+ clipkt->use_SNAP = 1;
+ sprintf(prompt, "pkt-%i-bpdu",clipkt->id);
+ cli_set_configmode(cli, MZ_MODE_PACKET_BPDU, prompt);
+ mops_update_bpdu(clipkt);
+ mops_set_conf(clipkt);
+ }
+ }
+ else if (mz_strcmp(argv[0],"ip",2) == 0)
+ {
+ ret=mops_clear_layers(clipkt, MOPS_TCP|MOPS_UDP);
+ clipkt->use_ETHER = 1;
+ clipkt->use_IP = 1;
+ sprintf(prompt, "pkt-%i-ip",clipkt->id);
+ cli_set_configmode(cli, MZ_MODE_PACKET_IP, prompt);
+ mops_set_conf(clipkt);
+ }
+ else if (mz_strcmp(argv[0],"udp",3) == 0)
+ {
+ ret=mops_clear_layers(clipkt, MOPS_SNAP|MOPS_TCP);
+ clipkt->use_ETHER = 1;
+ clipkt->use_IP = 1;
+ clipkt->use_UDP = 1;
+ clipkt->ip_proto = 17;
+ sprintf(prompt, "pkt-%i-udp",clipkt->id);
+ cli_set_configmode(cli, MZ_MODE_PACKET_UDP, prompt);
+ mops_set_conf(clipkt);
+ }
+ else if (mz_strcmp(argv[0],"tcp",3) == 0)
+ {
+ ret=mops_clear_layers(clipkt, MOPS_SNAP|MOPS_UDP);
+ clipkt->use_ETHER = 1;
+ clipkt->use_IP = 1;
+ clipkt->use_TCP = 1;
+ clipkt->ip_proto = 6;
+ sprintf(prompt, "pkt-%i-tcp",clipkt->id);
+ cli_set_configmode(cli, MZ_MODE_PACKET_TCP, prompt);
+ mops_set_conf(clipkt);
+ }
+ else if (mz_strcmp(argv[0],"syslog",3) == 0)
+ {
+ if (mops_ext_add_pdesc (clipkt, MOPS_SYSLOG))
+ cli_print(cli, "%s", wrn);
+ else
+ {
+ ret=mops_clear_layers(clipkt, MOPS_SNAP|MOPS_TCP);
+ clipkt->use_ETHER = 1;
+ clipkt->use_IP = 1;
+ clipkt->use_UDP = 1;
+ sprintf(prompt, "pkt-%i-syslog",clipkt->id);
+ cli_set_configmode(cli, MZ_MODE_PACKET_SYSLOG, prompt);
+ mops_set_conf(clipkt);
+ }
+ }
+ else if (mz_strcmp(argv[0],"lldp",3) == 0)
+ {
+ if (mops_ext_add_pdesc (clipkt, MOPS_LLDP))
+ cli_print(cli, "%s", wrn);
+ else
+ {
+ ret=mops_clear_layers(clipkt, MOPS_SNAP|MOPS_IP|MOPS_UDP|MOPS_TCP);
+ clipkt->use_ETHER = 1;
+ sprintf(prompt, "pkt-%i-lldp",clipkt->id);
+ cli_set_configmode(cli, MZ_MODE_PACKET_LLDP, prompt);
+ mops_set_conf(clipkt);
+ }
+ }
+ else if (mz_strcmp(argv[0],"rtp",3) == 0)
+ {
+ if (mops_ext_add_pdesc (clipkt, MOPS_RTP))
+ cli_print(cli, "%s", wrn);
+ else
+ {
+ ret=mops_clear_layers(clipkt, MOPS_SNAP|MOPS_TCP);
+ clipkt->use_ETHER = 1;
+ clipkt->use_IP = 1;
+ clipkt->use_UDP = 1;
+ sprintf(prompt, "pkt-%i-rtp",clipkt->id);
+ cli_set_configmode(cli, MZ_MODE_PACKET_RTP, prompt);
+ mops_set_conf(clipkt);
+ }
+ }
+
+ else // wrong user input
+ {
+ cli_print(cli, "Unknown type\n");
+ return CLI_OK;
+ }
+
+ if (ret) {
+ cli_print(cli, "Note that the following layer(2) have configured information:\r");
+ if (ret & 1) cli_print(cli, " - Ethernet or 802.3\r");
+ if (ret & 2) cli_print(cli, " - SNAP\r");
+ if (ret & 4) cli_print(cli, " - 802.1Q\r");
+ if (ret & 8) cli_print(cli, " - MPLS\r");
+ if (ret & 16) cli_print(cli, " - IP\r");
+ if (ret & 32) cli_print(cli, " - UDP\r");
+ if (ret & 64) cli_print(cli, " - TCP\r");
+ }
+
+ mops_update(clipkt);
+ return CLI_OK;
+}
+
+
+
+
+
+int cmd_packet_end(struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ cli_set_configmode(cli, MODE_CONFIG, NULL);
+ return CLI_OK;
+}
+
+
+
+
+
+int cmd_packet_clone (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ // TODO
+ return CLI_OK;
+}
+
+
+// Reserved words: "all", "slot"
+int cmd_packet_name (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ if (strncmp(argv[0], "?", 2) == 0)
+ {
+ cli_print(cli, "Assign a packet name (max 16 chars)\n");
+ return CLI_OK;
+ }
+
+ if (argc>1)
+ {
+ cli_print(cli, "Packet name must not contain spaces\n");
+ return CLI_OK;
+ }
+
+ if (strlen(argv[0])>MAX_MOPS_PACKET_NAME_LEN)
+ {
+ cli_print(cli, "Packet name is limited to %i chars. You might use the 'description' command.\n",MAX_MOPS_PACKET_NAME_LEN);
+ return CLI_OK;
+ }
+
+ if (mz_strcmp(argv[0], "all", 3)==0)
+ {
+ cli_print(cli, "This is a reserved word. Please choose another\n");
+ return CLI_OK;
+ }
+
+ strncpy(clipkt->packet_name, argv[0], MAX_MOPS_PACKET_NAME_LEN);
+ clipkt->packet_name[MAX_MOPS_PACKET_NAME_LEN-1] = 0x00;
+// cli_print(cli, "Changed packet name to '%s'\n", clipkt->packet_name);
+
+ return CLI_OK;
+}
+
+int cmd_packet_description (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ if (strncmp(argv[argc-1], "?", 2) == 0)
+ {
+ cli_print(cli, "Assign a packet description (max %i chars)\n", MAX_MOPS_DESCRIPTION_LEN);
+ return CLI_OK;
+ }
+
+ if (mops_pdesc_mstrings (clipkt->description, argv, argc, MAX_MOPS_DESCRIPTION_LEN))
+ {
+ cli_print(cli, "String too long. Currently the description is limited to %i characters.\n",
+ MAX_MOPS_DESCRIPTION_LEN);
+ cli_print(cli, "Current description is:\n%s\n", clipkt->description);
+ }
+
+ return CLI_OK;
+}
+
+int cmd_packet_count (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+
+ if (strncmp(argv[argc-1], "?", 2) == 0)
+ {
+ cli_print(cli,"Specify the packet count. Zero means infinity.\n");
+ return CLI_OK;
+ }
+ else if (argc)
+ {
+ clipkt->count = (unsigned long) str2int(argv[0]);
+ if (clipkt->count)
+ {
+ clipkt->cntx = clipkt->count; // count is finite: cntx will count down
+ }
+ else
+ {
+ clipkt->cntx = 0; // infinity: cntx will count up
+ }
+ return CLI_OK;
+ }
+ cli_print(cli,"Specify a packet count.\n");
+ return CLI_OK;
+}
+
+
+int cmd_packet_delay (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ int ret=0;
+ char str[100];
+
+ if (strncmp(argv[argc-1], "?", 2) == 0) {
+ cli_print(cli, "delay <value> [hour | min | sec | msec | usec | nsec]\n");
+ cli_print(cli, "Specify the inter-packet delay in hours, minutes, seconds, milliseconds, microseconds,\r");
+ cli_print(cli, "or nanoseconds. The default unit is milliseconds (i. e. when no unit is given).\n");
+ return CLI_OK;
+ }
+
+ switch (argc) {
+ case 1: // only one argument, but may contain an unit (such as '314sec')
+ ret = delay_parse(&clipkt->ndelay, argv[0], NULL);
+ break;
+
+ case 2: // user specified two arguments such as '100 msec'
+ ret = delay_parse(&clipkt->ndelay, argv[0], argv[1]);
+ break;
+ default:
+ cli_print(cli, "Too many arguments! Expected delay value and unit, such as '10 msec'\n");
+ return CLI_OK;
+ }
+
+ switch (ret) {
+ case 1:
+ cli_print(cli, "Invalid unit! Use one of {nsec, usec, msec, sec, min, hours}\n");
+ return CLI_OK;
+ break;
+ case 2:
+ cli_print(cli, "Value too large! Supported range is from 0 to 999999999\n");
+ return CLI_OK;
+ break;
+ }
+ sprintf(str, "Inter-packet delay set to %lu sec and %lu nsec", clipkt->ndelay.tv_sec, clipkt->ndelay.tv_nsec);
+ cli_print(cli, "%s\n", str);
+
+ return CLI_OK;
+}
+
+
+
+int cmd_packet_bind (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ int i;
+
+ if (strncmp(argv[argc-1], "?", 2) == 0)
+ {
+ cli_print(cli,"<DEVICE> Change the packet's network interface\r");
+ cli_print(cli,"default Use interface settings as packet default\n");
+ return CLI_OK;
+ }
+ else if (argc)
+ {
+ if (mz_strcmp(argv[0], "default", 3)==0)
+ {
+ i = mops_get_device_index(clipkt->device);
+ // Copy device_list[i].ip_mops and .mac_mops to clipkt->ip_src and ->eth_src
+ memcpy((void *) &clipkt->eth_src, (void *) &device_list[i].mac_mops[0], 6);
+ memcpy((void *) &clipkt->ip_src, (void *) &device_list[i].ip_mops[0], 4);
+ }
+ else
+ {
+ i = mops_get_device_index(argv[0]);
+
+ if (i != -1)
+ {
+ strncpy(clipkt->device, argv[0], 16); // assign device to this mops
+ mops_use_device(clipkt, i);
+ }
+ else
+ cli_print(cli, "Unknown device, will stick on %s\n", clipkt->device);
+ }
+ }
+ else
+ cli_print(cli, "Nothing specified, will stick on %s\n", clipkt->device);
+
+ return CLI_OK;
+}
+
+
+
+
+
+
+
+// FORMAT: <VLAN>:<CoS> such as: "100:3 17:5 ..."
+// NOTE: LEFTMOST TAG = OUTER TAG IN FRAME
+// CFI is set/unset separately (see ? below)
+// Transmission format: 0x8100 plus CoS (3) CFI(1) VLAN(12)
+int cmd_packet_dot1q (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ int i, j, k=0;
+ int n;
+ char Vlan[64], CoS[64];
+ u_int16_t v,c;
+
+ if (strcmp(argv[argc-1],"?")==0)
+ {
+ cli_print(cli, "Configure 802.1Q tags:\n");
+ cli_print(cli, " VLAN[:CoS] [VLAN[:CoS]] ... The leftmost tag is the outer tag in the frame\r");
+ cli_print(cli, " remove <tag-nr> | all Remove one or more tags (<tag-nr> starts with 1),\r");
+ cli_print(cli, " by default the first (=leftmost,outer) tag is removed,\r");
+ cli_print(cli, " keyword 'all' can be used instead of tag numbers.\r");
+ cli_print(cli, " cfi | nocfi [<tag-nr>] Set or unset the CFI-bit in any tag (by default\r");
+ cli_print(cli, " assuming the first tag).\n");
+ return CLI_OK;
+ }
+
+ if (argc==0)
+ {
+ cli_print(cli, "Specify one or more VLAN-IDs, optionally with CoS values\n");
+ return CLI_OK;
+ }
+
+ n = clipkt->dot1Q_s/4; // n = number of tags
+
+//////////////////////////////////////////
+ if (mz_strcmp(argv[0], "remove", 2)==0)
+ {
+
+ if (argc>2)
+ {
+ cli_print(cli, "Too many arguments!\n");
+ return CLI_OK;
+ }
+
+ if (n==0)
+ {
+ cli_print(cli, "No 802.1Q tags present. None to be removed.\n");
+ return CLI_OK;
+ }
+
+ if ((argc==2) && (mz_strcmp(argv[1], "all", 1)==0))
+ {
+ mops_dot1Q_remove(clipkt, 0);
+ return CLI_OK;
+ }
+
+ if (argc==1) // no tag-nr specified => assume first tag
+ {
+ j=1;
+ }
+ else
+ {
+ j = (unsigned int) str2int(argv[1]); // take first argument
+ if (j==0)
+ {
+ cli_print(cli, "The tag-nr must be within {1..%i}\n", n);
+ return CLI_OK;
+ }
+ }
+
+ // now remove tag
+ if (mops_dot1Q_remove(clipkt, j))
+ {
+ cli_print(cli, "The packet only consists of %i tag(s)!\n", n);
+ }
+ return CLI_OK;
+ }
+
+
+/////////////////////////////////////////
+ if (mz_strcmp(argv[0], "nocfi", 2)==0)
+ {
+ if (n==0)
+ {
+ cli_print(cli, "There are no 802.1Q tags yet!\n");
+ return CLI_OK;
+ }
+
+ if (argc>2)
+ {
+ cli_print(cli, "Invalid format!\n");
+ return CLI_OK;
+ }
+
+ if (argc==1) // no tag-nr specified => assume first tag
+ {
+ j=1;
+ }
+ else
+ {
+ j = (unsigned int) str2int(argv[1]);
+ }
+
+ if (mops_dot1Q_nocfi(clipkt, j))
+ {
+ cli_print(cli, "The packet only consists of %i tags!\n",k);
+ }
+ return CLI_OK;
+ }
+
+///////////////////////////////////////
+ if (mz_strcmp(argv[0], "cfi", 2)==0)
+ {
+ if (n==0)
+ {
+ cli_print(cli, "There are no 802.1Q tags yet!\n");
+ return CLI_OK;
+ }
+
+ if (argc>2)
+ {
+ cli_print(cli, "Invalid format!\n");
+ return CLI_OK;
+ }
+
+ if (argc==1) // no tag-nr specified => assume first tag
+ {
+ j=1;
+ }
+ else
+ {
+ j = (unsigned int) str2int(argv[1]);
+ }
+
+ if (mops_dot1Q_cfi(clipkt, j))
+ {
+ cli_print(cli, "The packet only consists of %i tags!\n",k);
+ }
+ return CLI_OK;
+ }
+
+
+/////////////////////////
+ for (i=0; i<argc; i++) // scan through all user tokens
+ {
+ v=0;c=0; k=0;
+
+ if (mz_tok(argv[i],":",2, Vlan, CoS) == -1)
+ {
+ cli_print(cli, "Invalid format. Correct format: VLAN[:CoS] [VLAN[:CoS] ...]\n");
+ return CLI_OK;
+ }
+
+ if (Vlan[0]==0x00)
+ {
+ cli_print(cli, "[tag %i] Missing VLAN number\n", i+1);
+ return CLI_OK;
+ }
+ else
+ {
+ v = (u_int16_t) str2int(Vlan);
+ if (v>4095)
+ {
+ cli_print(cli, "[tag %i] VLAN number must not exceed 4095.\n", i+1);
+ return CLI_OK;
+ }
+ }
+
+ if (CoS[0]==0x00)
+ {
+ c=0;
+ }
+ else
+ {
+ c = (u_int16_t) str2int(CoS);
+ if (c>7)
+ {
+ cli_print(cli, "[tag %i] CoS must not exceed 7.\n", i+1);
+ return CLI_OK;
+ }
+ }
+
+ mops_dot1Q (clipkt, i, 1, v, c); // 3rd param '1' means 'new stack, also set dot1Q_s'
+ }
+ return CLI_OK;
+}
+
+
+// MPLS transmission format: Label(20) EXP(3) BoS(1) TTL(8)
+// -- where BoS=0 indicate MORE labels, BoS=1 means last (bottom) label
+//
+// NOTE: The EtherType must be 0x8847 which identifies 'IP over MPLS' that is
+// we do NOT need to set 0x800 for IP somewhere! Instead, mops_update()
+// will always correctly set the single EtherType, if necessary after
+// 802.1Q tags. For example when VLAN tags are present, the frame looks
+// like this:----------------------------------vvvv-----------------------
+// DMAC-SMAC-8100VLAN1-...-8100VLANn-EtherType(8847)-MPLS1-...-MPLSn-IP...
+//
+// MPLS Multicast packets are indicated by EtherType 8848 (!)
+// See also RFC 5332 which allows both 'Codepoints' to carry MPLS multicast
+// while 0x8848 only indicates multiaccess media.
+//
+// NOTE: If all MPLS labels are removed again, the original EtherType is restored again!
+// The original EtherType is stored in mp->eth_type_backup
+int cmd_packet_mpls (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ int a=0,i,j=0,k;
+ char LabelS[64], ExpS[64], TTLS[64];
+ u_int32_t Label;
+ u_int8_t Exp;
+ u_int8_t TTL;
+
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc==0) )
+ {
+ cli_print(cli, "Configure one or more MPLS labels:\r");
+ cli_print(cli, " LABEL[:EXP[:TTL]] [LABEL[:EXP[:TTL]]] ... The leftmost tag is the outer tag in frame\r");
+ cli_print(cli, " remove <tag-nr> | all Remove tag with number <tag-nr> (starts with 1) or all.\r");
+ cli_print(cli, " bos | nobos [<tag-nr>] Set/unset BoS flag, by default in last (rightmost) label\r");
+ cli_print(cli, " unicast|multicast Choose EtherType 0x8847 or 0x8848 respectively\n");
+ cli_print(cli, "Examples:\r");
+ cli_print(cli, " tag mpls 100 200 300 Specify three tags, 100,200,300 \r");
+ cli_print(cli, " tag mpls 100:5 200:5:1 Let first tag have CoS 5, second tag additionally uses TTL=1\r");
+ cli_print(cli, " tag mpls 100::8 Let first tag have TTL=8\n");
+ cli_print(cli, "Reserved label numbers:\r");
+ cli_print(cli, " 0 ... explicit NULL (IPv4)\r");
+ cli_print(cli, " 1 ... Router Alert\r");
+ cli_print(cli, " 2 ... explicit NULL (IPv6)\r");
+ cli_print(cli, " 3 ... implicit NULL (only announced within LDP)\r");
+ cli_print(cli, " 14 ... OAM Alert (ITU-T Y.1711, RFC 3429)\n");
+ return CLI_OK;
+ }
+
+///////////////////////////////////////////
+ if (mz_strcmp(argv[0], "unicast", 2)==0)
+ {
+ if (clipkt->use_MPLS==0)
+ {
+ cli_print(cli, "First configure an MPLS label stack.");
+ return CLI_OK;
+ }
+
+ if (argc>1)
+ {
+ cli_print(cli, "This command does not support any argument.\n");
+ }
+
+ clipkt->eth_type = 0x8847;
+ return CLI_OK;
+ }
+
+/////////////////////////////////////////////
+ if (mz_strcmp(argv[0], "multicast", 2)==0)
+ {
+ if (clipkt->use_MPLS==0)
+ {
+ cli_print(cli, "First configure an MPLS label stack.");
+ return CLI_OK;
+ }
+
+ if (argc>1)
+ {
+ cli_print(cli, "This command does not support any argument.\n");
+ }
+
+ clipkt->eth_type = 0x8848;
+ return CLI_OK;
+ }
+
+ k = clipkt->mpls_s/4; // number of available tags
+
+//////////////////////////////////////////
+ if (mz_strcmp(argv[0], "remove", 2)==0)
+ {
+ if (argc>2)
+ {
+ cli_print(cli, "Too many arguments!\n");
+ return CLI_OK;
+ }
+
+ if ((argc==2) && (mz_strcmp(argv[1], "all", 1)==0))
+ {
+ if (mops_mpls_remove(clipkt, 0))
+ cli_print(cli, "No MPLS label stack present. Nothing removed\n");
+ return CLI_OK;
+ }
+
+ if (argc==1) // no tag-nr specified => assume first tag
+ {
+ if (k==0)
+ cli_print(cli, "Currently the packet has no tag that can be removed.\n");
+ else
+ j=1;
+ }
+ else
+ {
+ j = (unsigned int) str2int(argv[1]); // take first argument
+ }
+ if (mops_mpls_remove(clipkt, j))
+ cli_print(cli, "The tag number must be within 1..%i\n",k);
+
+ return CLI_OK;
+ }
+
+///////////////////////////////////////
+ if (mz_strcmp(argv[0], "bos", 2)==0)
+ {
+ if (argc>2)
+ {
+ cli_print(cli, "Too many arguments\n");
+ return CLI_OK;
+ }
+ if (argc==2)
+ {
+ i = (int) str2int(argv[1]);
+ if (i>k)
+ {
+ cli_print(cli, "Tag number exceeds actual number of tags (%i)\n",a);
+ return CLI_OK;
+ }
+ }
+ else // argc==1 (no tag number specified)
+ {
+ i = k; // default: last tag!
+ }
+
+ mops_mpls_bos (clipkt, i);
+ return CLI_OK;
+ }
+
+ if (mz_strcmp(argv[0], "nobos", 2)==0)
+ {
+ if (argc>2)
+ {
+ cli_print(cli, "Too many arguments\n");
+ return CLI_OK;
+ }
+ if (argc==2)
+ {
+ i = (int) str2int(argv[1]);
+ if (i>k)
+ {
+ cli_print(cli, "Tag number exceeds actual number of tags (%i)\n",k);
+ return CLI_OK;
+ }
+ }
+ else // argc==1 (no tag number specified)
+ {
+ i = k; // default: last tag!
+ }
+ mops_mpls_nobos (clipkt, i);
+ return CLI_OK;
+ }
+
+
+////////////////////////////////////////////
+ for (i=0;i<argc;i++) // Get all labels
+ {
+ if (mz_tok(argv[i], ":", 3, LabelS, ExpS, TTLS) < 0)
+ {
+ cli_print(cli, "[Tag %i]Incorrect label specification! Use format LABEL[:EXP[:TTL]]\n", i+1);
+ return CLI_OK;
+ }
+
+ // Get Label
+ if (LabelS[0]==0x00)
+ {
+ cli_print(cli, "[Tag %i] Invalid label value!\n", i+1);
+ return CLI_OK;
+ }
+ else
+ {
+ Label = (u_int32_t) str2int (LabelS);
+ if (Label > 1048575)
+ {
+ cli_print(cli, "[Tag %i] Label value cannot exceed 1048575\n", i+1);
+ return CLI_OK;
+ }
+ }
+ // Get EXP
+ if (ExpS[0]==0x00)
+ {
+ Exp=0;
+ }
+ else
+ {
+ Exp = (u_int8_t) str2int(ExpS);
+ if (Exp>7)
+ {
+ cli_print(cli, "[Tag %i] EXP value must be within range 0..7\n", i+1);
+ return CLI_OK;
+ }
+ }
+
+ // Get TTL
+ if (TTLS[0]==0x00)
+ {
+ TTL=255;
+ }
+ else
+ {
+ if (str2int(TTLS)>255)
+ {
+ cli_print(cli, "[Tag%i] TTL value must be within range 0..255\n", i+1);
+ return CLI_OK;
+ }
+ TTL = (u_int8_t) str2int(TTLS);
+ }
+
+ // Now add MPLS tag:
+ mops_mpls(clipkt, i, argc, Label, Exp, TTL);
+ }
+
+ return CLI_OK;
+}
+
+
+// SYNTAX:
+//
+// payload hex ff:00:01:02:aa:bb:cc:dd aa:bb:cc
+// payload hex file tmp/dump.dat
+//
+int cmd_packet_payload_hex (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ char str[MAX_MOPS_MSG_SIZE*3];
+ int len, i;
+
+ if (strncmp(argv[argc-1], "?", 2)==0)
+ {
+ cli_print(cli, "Specify a payload in hexadecimal format:\n");
+ cli_print(cli, " XX:XX:XX:... Either directly as sequence of digits, separated by colon or space\r");
+ cli_print(cli, " file <filename> Or specify a filename with hexadecimal digits as content\r");
+ cli_print(cli, " (Also in the file the separator can be either a colon or a space)\n");
+ cli_print(cli, "Example: \r");
+ cli_print(cli, "payload hex ff:ff:ff:ff:ff:ff 00:12:34:56:67:89 08:00 ca:fe:ba:be\n");
+ return CLI_OK;
+ }
+
+ if (argc==0)
+ {
+ cli_print(cli, "Specify an ascii payload\n");
+ return CLI_OK;
+ }
+
+
+ if (mz_strcmp(argv[0],"file", 2)==0)
+ {
+ // > > > > > ******* TODO: Open file and configure mops with filepointer ******** < < < < < < < <
+ cli_print(cli, "This feature is currently not supported.\n");
+ return CLI_OK;
+ }
+
+ // Get byte sequence - first copy into str
+ if (mops_pdesc_mstrings (str, argv, argc, MAX_MOPS_MSG_SIZE*3))
+ {
+ cli_print(cli, "Payload too long (limited to %i bytes).\n", MAX_MOPS_MSG_SIZE);
+ }
+ else // str contains byte sequence now - convert into msg and set msg_s
+ {
+ len = strlen(str);
+ for (i=0; i<len; i++)
+ {
+ if (str[i]=='?')
+ {
+ cli_print(cli, "Specify hexadecimal digits {1234567890abcdef} or separators\n");
+ return CLI_OK;
+ }
+
+ if ( (!isxdigit(str[i])) && // Only allow "1234567890abcdefABCDEF", ":", ".", "-", and SPACE.
+ (!isspace(str[i])) &&
+ (str[i]!=':') &&
+ (str[i]!='.') &&
+ (str[i]!='-'))
+ {
+ cli_print(cli, "Invalid character at position %i\n", i+1);
+ return CLI_OK;
+ }
+ }
+
+ len = str2hex (str, clipkt->msg, MAX_MOPS_MSG_SIZE);
+ if (len==-1)
+ {
+ cli_print(cli, "Invalid byte sequence. Each byte must be specified with two hexadecimal digits.\n");
+ return CLI_OK;
+ }
+
+ clipkt->msg_s = (u_int32_t) len;
+ }
+
+ return CLI_OK;
+}
+
+
+
+int cmd_packet_payload_ascii (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ char str[MAX_MOPS_MSG_SIZE*3];
+ int len, i;
+
+ if (strncmp(argv[argc-1], "?", 2)==0)
+ {
+ cli_print(cli, "Specify a payload in ascii format.\r");
+ cli_print(cli, "Note that multiple white spaces are replaced by a single white space. If you\r");
+ cli_print(cli, "really want to specify multiple white spaces then use a dash '-' instead of\r");
+ cli_print(cli, "a white space. If you want to specify a dash then use a caret '^' as escape\r");
+ cli_print(cli, "character.\n");
+
+ return CLI_OK;
+ }
+
+ if (argc==0)
+ {
+ cli_print(cli, "Specify an ascii payload\n");
+ return CLI_OK;
+ }
+
+
+ if (mz_strcmp(argv[0],"file", 2)==0)
+ {
+ // > > > > > ******* TODO: Open file and configure mops with filepointer ******** < < < < < < < <
+ cli_print(cli, "This feature is currently not supported.\n");
+ return CLI_OK;
+ }
+
+ // Get byte sequence - first copy into str
+ if (mops_pdesc_mstrings (str, argv, argc, MAX_MOPS_MSG_SIZE))
+ {
+ cli_print(cli, "Payload too long (limited to %i bytes).\n", MAX_MOPS_MSG_SIZE);
+ }
+ else // str contains byte sequence now - convert into msg and set msg_s
+ {
+ len = strlen(str);
+ for (i=0; i<len; i++) // Replace
+ {
+ if (str[i]=='-')
+ {
+ if ((i>0) && (str[i-1]=='^'))
+ {
+ memcpy((void*) &str[i-1], (void*) &str[i], len-i+1);
+ i--; len--;
+ }
+ else
+ {
+ str[i]=' ';
+ }
+ }
+ }
+ len--; // to eliminate the trailing space (created by mops_pdesc_mstring)
+ memcpy((void*) clipkt->msg, (void*) str, len);
+ clipkt->msg_s = len;
+ }
+ return CLI_OK;
+}
+
+
+int cmd_packet_payload_raw (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+
+ return CLI_OK;
+}
+
+
+
+int cmd_packet_interval (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ unsigned long long iv, tv_sec=0;
+
+ if (strncmp(argv[argc-1], "?", 1)==0) {
+ cli_print(cli, "Configure a greater packet interval in days, hours, minutes, or seconds\n");
+ cli_print(cli, "Arguments: <value> <days | hours | minutes | seconds>\n");
+ cli_print(cli, "Use a zero value to disable an interval.\n");
+ return CLI_OK;
+ }
+
+ if (argc!=2) {
+ cli_print(cli,"Enter a value and an unit\n");
+ return CLI_OK;
+ }
+
+
+ if (mz_strisnum(argv[0])==0) {
+ cli_print(cli,"Invalid value\n");
+ return CLI_OK;
+ }
+
+ iv = str2lint(argv[0]);
+
+ if (iv==0) {
+ cli_print(cli,"Interval disabled.\n");
+ clipkt->interval_used = 0;
+ return CLI_OK;
+ }
+
+ if (mz_strcmp(argv[1], "days", 1)==0) {
+ if (iv>365) {
+ cli_print(cli, "Supported range: 1..365 days\n");
+ return CLI_OK;
+ }
+ tv_sec = 86400 * iv;
+ }
+
+ if (mz_strcmp(argv[1], "hours", 1)==0) {
+ if (iv>1000) {
+ cli_print(cli, "Supported range: 1..1000 hours\n");
+ return CLI_OK;
+ }
+ tv_sec = 3600 * iv;
+ }
+
+ if (mz_strcmp(argv[1], "minutes", 1)==0) {
+ if (iv>1000) {
+ cli_print(cli, "Supported range: 1..1000 minutes\n");
+ return CLI_OK;
+ }
+ tv_sec = 60 * iv;
+ }
+
+ if (mz_strcmp(argv[1], "seconds", 1)==0) {
+ if (iv>999999) {
+ cli_print(cli, "Supported range: 1..999999 seconds\n");
+ return CLI_OK;
+ }
+ tv_sec = iv;
+ }
+
+ if (clipkt->count==0) {
+ cli_print(cli, "Note: reconfigured count value from 0 (infinity) to 1.\n");
+ clipkt->count=1;
+ }
+
+ if ((clipkt->count * clipkt->ndelay.tv_sec)>tv_sec) {
+ cli_print(cli, "Error: intervals are smaller than packet trains.\r");
+ cli_print(cli, "Reduce either count or delay, or both\n");
+ return CLI_OK;
+ }
+
+ clipkt->interval.tv_sec = tv_sec;
+ clipkt->interval_used = 1;
+
+ return CLI_OK;
+}
+
diff --git a/staging/cli_rtp.c b/staging/cli_rtp.c
new file mode 100644
index 0000000..28a6c2b
--- /dev/null
+++ b/staging/cli_rtp.c
@@ -0,0 +1,343 @@
+/*
+ * Mausezahn - A fast versatile traffic generator
+ * Copyright (C) 2008-2010 Herbert Haas
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
+ *
+*/
+
+
+
+#include "mz.h"
+#include "cli.h"
+#include "mops.h"
+
+
+int cmd_rtp_version (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ struct mops_ext_rtp * pd = clipkt->p_desc;
+ int v=2;
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc!=1)) {
+ cli_print(cli, "Set the RTP version (0..3, default: v2).\n");
+ return CLI_OK;
+ }
+ if (mz_strisnum(argv[0])==0) {
+ cli_print(cli, "Invalid number.\n");
+ return CLI_OK;
+ }
+ v = (int) str2int(argv[0]);
+ if (v>3) {
+ cli_print(cli, "Range exceeded (0..3).\n");
+ return CLI_OK;
+ }
+ pd->v = v;
+ return CLI_OK;
+}
+
+int cmd_rtp_padding (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ struct mops_ext_rtp * pd = clipkt->p_desc;
+ char state[8];
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc!=1)) {
+ cli_print(cli, "Sets or unsets the RTP padding flag (default: disabled).\n");
+ cli_print(cli, "Use the keywords 'set' or 'unset'.\n");
+ sprintf(state, "%s", (pd->p) ? "SET" : "UNSET");
+ cli_print(cli, "Current state of the padding flag: %s\n",state);
+ return CLI_OK;
+ }
+
+ if (mz_strcmp(argv[0], "set", 1)==0) {
+ pd->p = 1;
+ } else if (mz_strcmp(argv[0], "unset", 1)==0) {
+ pd->p = 0;
+ }
+ else {
+ cli_print(cli, "Invalid keyword. Use 'set' or 'unset'.\n");
+ }
+
+ return CLI_OK;
+}
+
+int cmd_rtp_xten (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ struct mops_ext_rtp * pd = clipkt->p_desc;
+ char state[8];
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc!=1)) {
+ cli_print(cli, "Sets or unsets the RTP extension flag (default: disabled).\n");
+ cli_print(cli, "NOTE: This command only sets the extension flag in the RTP header.\r");
+ cli_print(cli, "If you really want an extension header use the 'extension' command.\n");
+ cli_print(cli, "Use the keywords 'set' or 'unset'.\n");
+ sprintf(state, "%s", (pd->x) ? "SET" : "UNSET");
+ cli_print(cli, "Current state of the extension flag: %s\n",state);
+ return CLI_OK;
+ }
+
+ if (mz_strcmp(argv[0], "set", 1)==0) {
+ pd->x = 1;
+ } else if (mz_strcmp(argv[0], "unset", 1)==0) {
+ pd->x = 0;
+ }
+ else {
+ cli_print(cli, "Invalid keyword. Use 'set' or 'unset'.\n");
+ }
+
+ return CLI_OK;
+}
+
+
+int cmd_rtp_marker (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ struct mops_ext_rtp * pd = clipkt->p_desc;
+ char state[8];
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc!=1)) {
+ cli_print(cli, "Sets or unsets the RTP marker flag (default: disabled).\n");
+ cli_print(cli, "Use the keywords 'set' or 'unset'.\n");
+ sprintf(state, "%s", (pd->m) ? "SET" : "UNSET");
+ cli_print(cli, "Current state of the marker flag: %s\n",state);
+ return CLI_OK;
+ }
+ if (mz_strcmp(argv[0], "set", 1)==0) {
+ pd->m = 1;
+ } else if (mz_strcmp(argv[0], "unset", 1)==0) {
+ pd->m = 0;
+ }
+ else {
+ cli_print(cli, "Invalid keyword. Use 'set' or 'unset'.\n");
+ }
+ return CLI_OK;
+}
+
+
+int cmd_rtp_cc (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ struct mops_ext_rtp * pd = clipkt->p_desc;
+ int cc=0;
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc!=1)) {
+ cli_print(cli, "Configure the RTP CSRC count (0..15, default: 0).\n");
+ cli_print(cli, "NOTE: This command only configures the CSRC value in the RTP header.\r");
+ cli_print(cli, "If you want to add a valid CSRC list use the 'csrc-list' command.\r");
+ cli_print(cli, "The main purpose of this command is to create an invalid RTP packet.\r");
+ return CLI_OK;
+ }
+ if (mz_strisnum(argv[0])==0) {
+ cli_print(cli, "Invalid number.\n");
+ return CLI_OK;
+ }
+ cc = (int) str2int(argv[0]);
+ if (cc>15) {
+ cli_print(cli, "Range exceeded (0..15).\n");
+ return CLI_OK;
+ }
+ pd->cc = cc;
+ return CLI_OK;
+}
+
+
+int cmd_rtp_pt (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ struct mops_ext_rtp * pd = clipkt->p_desc;
+ int pt=0;
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc!=1)) {
+ cli_print(cli, "Configure the RTP payload type (0..127, default: 8 (G.711, A-law)).\n");
+ // TODO: provide a list with well-known PT values
+ return CLI_OK;
+ }
+ if (mz_strisnum(argv[0])==0) {
+ cli_print(cli, "Invalid number.\n");
+ return CLI_OK;
+ }
+ pt = (int) str2int(argv[0]);
+ if (pt>127) {
+ cli_print(cli, "Range exceeded (0..127).\n");
+ return CLI_OK;
+ }
+ pd->pt = pt;
+ return CLI_OK;
+}
+
+int cmd_rtp_ssrc (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ struct mops_ext_rtp * pd = clipkt->p_desc;
+ unsigned long long int ssrc = 0xcafefeed;
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc!=1)) {
+ cli_print(cli, "Configure the RTP SSRC (source identifier) (0..ffffffff, default: random!).\n");
+ cli_print(cli, "NOTE: The SSRC value is used by another Mausezahn receiver to identify a original\r");
+ cli_print(cli, "Mausezahn RTP stream. By default, Mausezahn receivers check for the magic number\r");
+ cli_print(cli, "'cafebabe' (hex). Use another number for another RTP stream (e. g. bidirectional\r");
+ cli_print(cli, "measurements).\n");
+ return CLI_OK;
+ }
+
+ if (mz_strishex(argv[0])==0) {
+ cli_print(cli, "Invalid number.\n");
+ return CLI_OK;
+ }
+
+ ssrc = xstr2lint(argv[0]);
+ if (ssrc>0xffffffff) {
+ cli_print(cli, "Range exceeded (0..ffffffff).\n");
+ return CLI_OK;
+ }
+ pd->ssrc = (u_int32_t) ssrc;
+ return CLI_OK;
+}
+
+
+int cmd_rtp_sqnr (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ struct mops_ext_rtp * pd = clipkt->p_desc;
+ unsigned long long int sqnr = 0;
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc!=1)) {
+ cli_print(cli, "Configure the RTP initial sequence number (0..ffffffff, default: 0).\n");
+ return CLI_OK;
+ }
+
+ if (mz_strishex(argv[0])==0) {
+ cli_print(cli, "Invalid number.\n");
+ return CLI_OK;
+ }
+ sqnr = xstr2lint(argv[0]);
+ if (sqnr>0xffffffff) {
+ cli_print(cli, "Range exceeded (0..ffffffff).\n");
+ return CLI_OK;
+ }
+ pd->sqnr = (u_int32_t) sqnr;
+ return CLI_OK;
+}
+
+
+int cmd_rtp_time (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ struct mops_ext_rtp * pd = clipkt->p_desc;
+ unsigned long long int t = 0;
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc!=1)) {
+ cli_print(cli, "Configure the RTP initial timestamp (0..ffffffff, default: 0).\n");
+ return CLI_OK;
+ }
+
+ if (mz_strishex(argv[0])==0) {
+ cli_print(cli, "Invalid number.\n");
+ return CLI_OK;
+ }
+ t = xstr2lint(argv[0]);
+ if (t>0xffffffff) {
+ cli_print(cli, "Range exceeded (0..ffffffff).\n");
+ return CLI_OK;
+ }
+ pd->tst = (u_int32_t) t;
+ return CLI_OK;
+}
+
+
+int cmd_rtp_extension (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ struct mops_ext_rtp * pd = clipkt->p_desc;
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc!=1)) {
+ cli_print(cli, "Configure an RTP extension header (default: none).\n");
+ cli_print(cli, "Currently supported RTP extension headers:\n");
+ cli_print(cli, "none Don't use any extension.\r");
+ cli_print(cli, "mausezahn Use the new Mausezahn jitter/RTT measurement extension.\r");
+ cli_print(cli, " (Note that this is incompatible with Mausezahn's direct\r");
+ cli_print(cli, " mode jitter measurement.)\r");
+ cli_print(cli, "\n");
+ return CLI_OK;
+ }
+
+ if (mz_strcmp(argv[0], "none", 1)==0) {
+ pd->x_type = 0;
+ pd->x = 0; // X bit in header
+ } else if (mz_strcmp(argv[0], "mausezahn", 1)==0) {
+ pd->x_type = 42;
+ pd->x = 1; // X bit in header
+ pd->ssrc = 0xcafefeed;
+ } else {
+ cli_print(cli, "Unknown keyword.\n");
+ return CLI_OK;
+
+ }
+
+ mops_update_rtp (clipkt); // re-build RTP packet (for proper show commands)
+ return CLI_OK;
+}
+
+
+
+int cmd_rtp_source (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+// struct mops_ext_rtp * pd = clipkt->p_desc;
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc!=1)) {
+ cli_print(cli, "Specify a RTP media source.\n");
+ return CLI_OK;
+ }
+
+ // [TODO] -- Allow to use /dev/dsp or a mixer source ...
+ //
+ cli_print(cli, "Currently not supported.\n");
+
+ return CLI_OK;
+}
+
+
+int cmd_rtp_cclist (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ struct mops_ext_rtp * pd = clipkt->p_desc;
+ unsigned long long int csrc=0;
+ char str[80];
+ int i=0, n=0;
+
+
+ if ((strcmp(argv[argc-1],"?")==0) || (argc==0)) {
+ cli_print(cli, "Specify a CSRC list consisting of 1-15 CSRC values.\r");
+ cli_print(cli, "Each CSRC is a 4-byte value and must be specified in hexadecimal notation,\r");
+ cli_print(cli, "hence each value must be within 0..ffffffff.\n");
+ return CLI_OK;
+ }
+
+ if ((n=argc)>15) {
+ cli_print(cli, "The CSRC list must not exceed 15 items!\n");
+ return CLI_OK;
+ }
+
+ for (i=0; i<n; i++) {
+ if (mz_strishex(argv[i])==0) {
+ sprintf(str, "Parameter %i: Invalid number!", i);
+ cli_print(cli, "%s\n", str);
+ return CLI_OK;
+ }
+ csrc = xstr2lint(argv[i]);
+ if (csrc>0xffffffff) {
+ sprintf(str, "Parameter %i: Range exceeded (0..ffffffff)", i);
+ cli_print(cli, "%s\n", str);
+ return CLI_OK;
+ }
+ pd->csrc[i] = (u_int32_t) csrc;
+ }
+ pd->cc = n; // this one can be accessed and modified to "wrong" values by the user
+ pd->cc_real = n;
+
+ return CLI_OK;
+}
+
+
+
diff --git a/staging/cli_sequence.c b/staging/cli_sequence.c
new file mode 100644
index 0000000..0a55251
--- /dev/null
+++ b/staging/cli_sequence.c
@@ -0,0 +1,263 @@
+/*
+ * Mausezahn - A fast versatile traffic generator
+ * Copyright (C) 2010 Herbert Haas
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
+ *
+*/
+
+
+#include "mz.h"
+#include "cli.h"
+#include "mops.h"
+#include "llist.h"
+
+// PURPOSE: Enter sequence configuration mode
+// either a) create new or b) edit old or c) delete old sequence
+//
+// # sequence MY_SEQUENCE
+// # sequence OLD_SEQUENCE delete
+//
+int conf_sequence (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ struct mz_ll *cur;
+ char str[512];
+ int ret=0;
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc<1) || (argc>2)) {
+
+ cli_print(cli, "Configure a sequence of packets.\n");
+ cli_print(cli, "ARGUMENTS: <sequence_name> [delete]\n");
+
+ cli_print(cli, "Current list of packet sequences:\n");
+ while (mops_dump_sequence(str)) cli_print(cli, "%s\r", str);
+ return CLI_OK;
+ }
+
+ switch (argc) {
+ case 1:
+ cur = mz_ll_search_name (packet_sequences, argv[0]);
+ if (cur==NULL) { // create NEW sequence
+ cli_print(cli, "Sequence does not exist; creating new sequence named '%s'\n", argv[0]);
+ cur = mops_create_sequence(argv[0]);
+ if (cur==NULL) {
+ cli_print(cli, "ERROR: Cannot allocate another sequence!\n");
+ return CLI_OK;
+ }
+ } // else ENTER EXISTING (cur already points to it)
+ cli_seq = cur;
+ cli_set_configmode(cli, MZ_MODE_SEQUENCE, "config-seq");
+ break;
+
+ case 2: // otherwise DELETE?
+ if (mz_strcmp(argv[1], "delete", 3)==0) {
+ ret = mops_delete_sequence(argv[0]);
+ switch (ret) {
+ case 1:
+ cli_print(cli, "Sequence '%s' does not exist\n", argv[0]);
+ break;
+ case 2:
+ cli_print(cli, "Sequence '%s' is currently active! Cannot delete it.\n", argv[0]);
+ break;
+ default:
+ cli_print(cli, "Sequence '%s' deleted.\n", argv[0]);
+ }
+ }
+ break;
+ default:
+ // nothing
+ break;
+ }
+ return CLI_OK;
+}
+
+
+// add packet to current sequence
+int sequence_add (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ struct mops *mp;
+ int ret=0;
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc!=1) ) {
+
+ cli_print(cli, "Add a packet to the current sequence.\n");
+ cli_print(cli, "ARGUMENT: <packet name> OR <packet-identifier>\n");
+ return CLI_OK;
+ }
+
+ // first assume argument is a name
+ mp = mops_search_name (mp_head, argv[0]);
+ if (mp==NULL) { // but packet name does not exist
+ if (mz_strisnum(argv[0])!=0) // arg is really a number?
+ mp = mops_search_id (mp_head, (int) str2int(argv[0]));
+ if (mp==NULL) { // also packet ID not found
+ cli_print(cli, "Packet does not exist!\n");
+ return CLI_OK;
+ }
+ }
+
+ // packet found, so add to current sequence
+ ret = mops_add_packet_to_sequence (cli_seq, mp);
+ if (ret==1) cli_print(cli, "Cannot add packet (unknown error, maybe report this)!\n");
+ if (ret==-1) cli_print(cli, "Cannot add packet: sequence already full!\n");
+ if (ret==-2) cli_print(cli, "Cannot add packet with infinite count!\n");
+ return CLI_OK;
+}
+
+
+// add a delay
+int sequence_delay (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ int ret=0, ret2=0;
+ struct timespec t;
+ char str[128];
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc<1) || (argc>2)) {
+ cli_print(cli, "Add a delay to the current sequence.\n");
+ cli_print(cli, "ARGUMENTS: <delay> [hour | min | sec | msec | usec | nsec]\n");
+ cli_print(cli, "The default unit is milliseconds (i. e. when no unit is given).\n");
+ return CLI_OK;
+ }
+
+ switch (argc) {
+ case 1: // only one argument, but may contain an unit (such as '314sec')
+ ret = delay_parse(&t, argv[0], NULL);
+ break;
+
+ case 2: // user specified two arguments such as '100 msec'
+ ret = delay_parse(&t, argv[0], argv[1]);
+ break;
+ default:
+ cli_print(cli, "Too many arguments! Expected delay value and unit, such as '10 msec'\n");
+ return CLI_OK;
+ }
+
+ switch (ret) {
+ case 1:
+ cli_print(cli, "Invalid unit! Use one of {nsec, usec, msec, sec, min, hours}\n");
+ return CLI_OK;
+ break;
+ case 2:
+ cli_print(cli, "Value too large! Supported range is from 0 to 999999999\n");
+ return CLI_OK;
+ break;
+ }
+
+
+ ret2 = mops_add_delay_to_sequence (cli_seq, &t);
+ if (ret2==-1) {
+ cli_print(cli, "You must add a packet first.\n");
+ return CLI_OK;
+ }
+ if (ret2==-2) {
+ cli_print(cli, "Cannot add delay (array full).\n");
+ return CLI_OK;
+ }
+
+ sprintf(str, "Delay set to %lu sec and %lu nsec",
+ ((struct pseq*) cli_seq->data)->gap[ret2].tv_sec,
+ ((struct pseq*) cli_seq->data)->gap[ret2].tv_nsec);
+ cli_print(cli, "%s\n", str);
+
+ return CLI_OK;
+}
+
+
+// remove one packet
+int sequence_remove (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ int ret=0;
+ int i=0;
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc!=1)) {
+ cli_print(cli, "Remove a packet (and any associated pause configuration) from the current sequence.\n");
+ cli_print(cli, "ARGUMENT: <sequence-list-index> | last | all\n");
+ cli_print(cli, "FYI: Use the 'show' command to see the current packet list with indexes.\n");
+ return CLI_OK;
+ }
+
+ if (mz_strcmp(argv[0], "last", 1)==0) {
+ ret = mops_delete_packet_from_pseq (cli_seq, -1);
+ } else if (mz_strcmp(argv[0], "all", 1)==0) {
+ ret = mops_delete_all_packets_from_pseq (cli_seq);
+ i=1;
+ } else { // index number given
+ if (mz_strisnum(argv[0])==0) {
+ cli_print(cli, "Invalid parameter. Please specify a packet index number or 'last'\n");
+ return CLI_OK;
+ }
+ ret = mops_delete_packet_from_pseq (cli_seq, (int) str2int(argv[0]));
+ }
+ switch (ret) {
+ case 0:
+ if (i) cli_print(cli, "Removed all entries.\n");
+ else cli_print(cli, "Removed one entry.\n");
+ break;
+ case 1:
+ cli_print(cli, "List empty or invalid packet index.\n");
+ break;
+ case 2:
+ cli_print(cli, "Packet index too large.\n");
+ break;
+
+ }
+ return CLI_OK;
+}
+
+
+// show packet list of that sequence
+int sequence_show (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ char str[512], name[32], layers[16], proto[16];
+ struct pseq *seq;
+ int i;
+
+ if (strcmp(argv[argc-1],"?")==0) {
+ cli_print(cli, "Shows all packets of the current sequence.\n");
+ return CLI_OK;
+ }
+
+ if (argc>0) {
+ cli_print(cli, "This command has currently no arguments!\n");
+ return CLI_OK;
+ }
+
+ seq = (struct pseq*) cli_seq->data;
+
+ if (seq->count==0) {
+ cli_print(cli, "Current sequence '%s' has no entries.\n", cli_seq->name);
+ }
+ else { // show all packets in this sequence
+ cli_print(cli, "%i sequence(s) defined.\r", packet_sequences->refcount-1); // total info
+ snprintf(str,512, "Current sequence '%s' has %i entries:", cli_seq->name, seq->count); // num entries here
+ cli_print(cli, "%s\n", str);
+ cli_print(cli, "Nr PId PktName Layers Protocol Device");
+ for (i=0; i<seq->count; i++) {
+ strncpy (name, seq->packet[i]->packet_name, 13); // only show first 13 chars
+ if (strnlen(seq->packet[i]->packet_name, MAX_MOPS_PACKET_NAME_LEN)>13) {
+ name[13]=0x00;
+ strcat(name, "...");
+ }
+ mops_get_proto_info(seq->packet[i], layers, proto);
+ snprintf(str,512, "%2i %4i %-16s %s %-8s %-6s", i+1, seq->packet[i]->id, name, layers, proto, seq->packet[i]->device);
+ cli_print(cli, "%s\r", str);
+ if ((seq->gap[i].tv_sec !=0) || (seq->gap[i].tv_nsec !=0)) { // gap also defined?
+ timespec2str(&seq->gap[i], str);
+ cli_print(cli, " \\___ %s pause ___/\r", str);
+ }
+ }
+ }
+ return CLI_OK;
+}
+
+
diff --git a/staging/cli_set.c b/staging/cli_set.c
new file mode 100644
index 0000000..8b365fc
--- /dev/null
+++ b/staging/cli_set.c
@@ -0,0 +1,350 @@
+/*
+ * Mausezahn - A fast versatile traffic generator
+ * Copyright (C) 2008 Herbert Haas
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
+ *
+*/
+
+
+#include "mz.h"
+#include "cli.h"
+
+
+int cmd_set(struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ libnet_t *l;
+ unsigned int time_factor;
+ int i, cnt, found_dev;
+ char *dum;
+ unsigned char *x;
+
+
+ if (argc < 2) {
+ cli_print(cli, "Specify a variable to set:\r\n");
+ cli_print(cli, "device specify the primary network device\r");
+
+ cli_print(cli, "NOTE: The following options are non-MOPS and deprecated:\n");
+
+ cli_print(cli, "a|sa specify a MAC source address\r");
+ cli_print(cli, "b|da specify a MAC destination address\r");
+ cli_print(cli, "A|SA specify a IP source address\r");
+ cli_print(cli, "B|DA specify a IP destination address\r");
+ cli_print(cli, "c|count specify a packet count value\r");
+ cli_print(cli, "d|delay specify an interpacket delay (usec, msec, or sec)\r");
+ cli_print(cli, "P|payload specify an ASCII payload\r");
+ cli_print(cli, "H|hexload specify a hexadecimal payload\r");
+ cli_print(cli, "p|padding specify a number of padding bytes (total for raw, added otherwise)\r");
+ cli_print(cli, "Q|vlan specify one ore more 802.1Q vlan tags\r");
+ cli_print(cli, "M|mpls specify one ore more MPLS labels\r");
+ cli_print(cli, "\n");
+ return CLI_OK;
+ }
+
+ // set primary device
+ if (strncmp(argv[0], "device", 2)==0)
+ {
+ if (strncmp(argv[1],"?",1)==0)
+ {
+ cli_print(cli,"Specify the primary network device (use 'show dev' for a list)\n");
+ }
+ else
+ {
+ if (strlen(argv[1]))
+ {
+ found_dev = 0;
+ for (i=0; i<device_list_entries; i++)
+ {
+ if (strncmp(device_list[i].dev, argv[1], 16)==0)
+ {
+ found_dev=1;
+ break;
+ }
+ }
+ if (found_dev)
+ {
+ strncpy(tx.device, argv[1], 16);
+ }
+ else
+ cli_print(cli, "Unknown device, will stick on %s\n", tx.device);
+ }
+ else
+ cli_print(cli, "Nothing specified, will stick on %s\n", tx.device);
+ }
+ }
+
+
+ // set source MAC address
+ else if ( (strncmp(argv[0], "a", 10)==0) ||
+ (strncmp(argv[0], "sa", 10)==0) )
+ {
+ if (strncmp(argv[1],"?",1)==0)
+ {
+ cli_print(cli,"Specify a source MAC address (format: XX:XX:XX:XX:XX:XX)\n");
+ }
+ else
+ {
+ strncpy(tx.eth_src_txt, argv[1], 32);
+ if (check_eth_mac_txt(ETH_SRC))
+ {
+ cli_print(cli, "Invalid MAC address! Format: XX:XX:XX:XX:XX:XX\r");
+ cli_print(cli, "Current setting: sa = %02x:%02x:%02x:%02x:%02x:%02x\r",
+ tx.eth_src[0], tx.eth_src[1], tx.eth_src[2],
+ tx.eth_src[3], tx.eth_src[4], tx.eth_src[5]);
+ }
+
+ tx.packet_mode = 0;
+
+ }
+ }
+
+ // set destination MAC address
+ else if ( (strncmp(argv[0], "b", 10)==0) ||
+ (strncmp(argv[0], "da", 10)==0) )
+ {
+ if (strncmp(argv[1],"?",1)==0)
+ {
+ cli_print(cli,"Specify a destination MAC address (format: XX:XX:XX:XX:XX:XX)\n");
+ }
+ else
+ {
+ strncpy(tx.eth_dst_txt, argv[1], 32);
+ if (check_eth_mac_txt(ETH_DST))
+ {
+ cli_print(cli, "Invalid MAC address! Format: XX:XX:XX:XX:XX:XX\r");
+ cli_print(cli, "Current setting: da = %02x:%02x:%02x:%02x:%02x:%02x\r",
+ tx.eth_dst[0], tx.eth_dst[1], tx.eth_dst[2],
+ tx.eth_dst[3], tx.eth_dst[4], tx.eth_dst[5]);
+ }
+
+ tx.packet_mode = 0;
+ }
+ }
+
+ // set source IP address
+ else if ( (strncmp(argv[0], "A", 10)==0) ||
+ (strncmp(argv[0], "SA", 10)==0) )
+ {
+ if (strncmp(argv[1],"?",1)==0)
+ {
+ cli_print(cli,"Specify a source IP address, a FQDN, 'rand', or a range\n");
+ }
+ else
+ {
+ if (strcmp(argv[1], "rand") == 0)
+ {
+ tx.ip_src_rand = 1;
+ tx.ip_src_h = (u_int32_t) ( ((float) rand()/RAND_MAX)*0xE0000000); //this is 224.0.0.0
+// TODO: mops_hton32 (&tx.ip_src_h, &tx.ip_src);
+ }
+ else if (get_ip_range_src(argv[1])) // returns 1 when no range has been specified
+ {
+ l = libnet_init (LIBNET_LINK_ADV, tx.device, NULL);
+ if (l == NULL)
+ {
+ cli_print(cli, "Error: could not access the network device!\n");
+ return CLI_OK;
+ }
+ // name2addr4 accepts a DOTTED DECIMAL ADDRESS or a FQDN:
+ tx.ip_src = libnet_name2addr4 (l, argv[1], LIBNET_RESOLVE);
+ x = (unsigned char *) &tx.ip_src;
+ cli_print(cli, "Set source IP address to %i.%i.%i.%i\n",
+ *x,*(x+1),*(x+2),*(x+3));
+// TODO: mops_hton32 (&tx.ip_src, &tx.ip_src_h);
+ libnet_destroy(l);
+ }
+ }
+ }
+
+ // set destination IP address
+ else if ( (strncmp(argv[0], "B", 10)==0) ||
+ (strncmp(argv[0], "DA", 10)==0) )
+ {
+ if (strncmp(argv[1],"?",1)==0)
+ {
+ cli_print(cli,"Specify a destination IP address, a FQDN, or a range\n");
+ }
+ else
+ {
+ if (get_ip_range_dst(argv[1])) // returns 1 when no range has been specified
+ {
+ l = libnet_init (LIBNET_LINK_ADV, tx.device, NULL);
+ if (l == NULL)
+ {
+ cli_print(cli, "Error: could not access the network device!\n");
+ return CLI_OK;
+ }
+ // name2addr4 accepts a DOTTED DECIMAL ADDRESS or a FQDN:
+ tx.ip_dst = libnet_name2addr4 (l, argv[1], LIBNET_RESOLVE);
+ x = (unsigned char *) &tx.ip_src;
+ cli_print(cli, "Set destination IP address to %i.%i.%i.%i\n",
+ *x,*(x+1),*(x+2),*(x+3));
+// TODO: mops_hton32 (&tx.ip_dst, &tx.ip_dst_h);
+ libnet_destroy(l);
+ }
+ }
+ }
+
+ // set packet count
+ else if ( (strncmp(argv[0], "c", 10)==0) ||
+ (strncmp(argv[0], "count", 10)==0) )
+ {
+ if (strncmp(argv[1],"?",1)==0)
+ {
+ cli_print(cli,"Specify a packet count value\n");
+ }
+ else
+ {
+ cnt = (unsigned int) str2int (argv[1]);
+ if (cnt==0)
+ {
+ cli_print(cli, "Warning: A packet count of zero means an infinite number of packets.\r");
+ cli_print(cli, "Infinite packets are only supported via MOPS (use the 'packet' command\r");
+ cli_print(cli, "in global configuration mode) or when running Mausezahn from the shell.\n");
+ cli_print(cli, "Note: The count value has NOT been changed.\n");
+ }
+ else
+ {
+ tx.count = cnt;
+ }
+ }
+ }
+
+ // set interpacket delay
+ else if ( (strncmp(argv[0], "d", 10)==0) ||
+ (strncmp(argv[0], "delay", 10)==0) )
+ {
+ if (strncmp(argv[1],"?",1)==0)
+ {
+ cli_print(cli,"Specify an interpacket delay (usec, msec, or sec)\n");
+ }
+ else
+ {
+ // determine whether seconds or msecs are used
+ // default is usec!!!
+ time_factor=1;
+ if (exists(argv[1],"s") || exists(argv[1],"sec")) time_factor=1000000;
+ if (exists(argv[1],"m") || exists(argv[1],"msec")) time_factor=1000;
+ dum = strtok(argv[1],"ms");
+ tx.delay = strtol(dum, (char **)NULL, 10) * time_factor;
+ if ((errno == ERANGE && (tx.delay == LONG_MAX || tx.delay == LONG_MIN))
+ || (errno != 0 && tx.delay == 0))
+ {
+ cli_print(cli, "Value out of range!\n");
+ }
+ if (tx.delay<0) tx.delay=0; // no delay
+
+ cli_print(cli, "Set interpacket delay to %u usec\n", tx.delay);
+ }
+
+ }
+
+ // set ASCII payload
+ else if ( (strncmp(argv[0], "P", 10)==0) ||
+ (strncmp(argv[0], "payload", 10)==0) )
+ {
+ if (strncmp(argv[1],"?",1)==0)
+ {
+ cli_print(cli,"Specify an ASCII payload enclosed in quotes\n");
+ }
+ else
+ {
+ strncpy((char *)tx.ascii_payload, argv[1], MAX_PAYLOAD_SIZE);
+ tx.ascii=1;
+ }
+ }
+
+
+ // set HEX payload
+ else if ( (strncmp(argv[0], "H", 10)==0) ||
+ (strncmp(argv[0], "hexload", 10)==0) )
+ {
+ if (strncmp(argv[1],"?",1)==0)
+ {
+ cli_print(cli,"Specify a hexadecimal payload (using ':' or '.' as delimiters)\n");
+ }
+ else
+ {
+ tx.hex_payload_s = str2hex (argv[1], tx.hex_payload, 8192);
+ if (tx.hex_payload_s==0)
+ cli_print(cli, "Invalid hexadecimal string. Try something like aa:bb:cc:45:99:00:de:ad:be:ef: ...\n");
+ }
+ }
+
+
+ // set MPLS labels
+ else if ( (strncmp(argv[0], "M", 10)==0) ||
+ (strncmp(argv[0], "mpls", 10)==0) )
+ {
+ if (strncmp(argv[1],"?",1)==0)
+ {
+ cli_print(cli,"Specify one or more MPLS labels\n");
+ }
+ else
+ {
+ if (strlen(argv[1])) // TODO: Better verification of 802.1Q syntax
+ {
+ strncpy(tx.mpls_txt, argv[1], 128);
+ tx.mpls=1;
+ }
+ }
+ }
+
+
+ // set 802.1Q tags
+ else if ( (strncmp(argv[0], "Q", 10)==0) ||
+ (strncmp(argv[0], "vlan", 10)==0) )
+ {
+ if (strncmp(argv[1],"?",1)==0)
+ {
+ cli_print(cli,"Specify one or more 802.1Q VLAN tags (and optionally 801.1P values)\n");
+ }
+ else
+ {
+ if (strlen(argv[1])) // TODO: Better verification of 802.1Q syntax
+ {
+ strncpy(tx.dot1Q_txt, argv[1], 32);
+ tx.dot1Q=1;
+ }
+ }
+ }
+
+
+ // set padding
+ else if ( (strncmp(argv[0], "p", 10)==0) ||
+ (strncmp(argv[0], "padding", 10)==0) )
+ {
+ if (strncmp(argv[1],"?",1)==0)
+ {
+ cli_print(cli,"Specify a number of padding bytes\n");
+ }
+ else
+ {
+ tx.padding = (unsigned int) str2int(argv[1]);
+ if (tx.padding > MAX_PAYLOAD_SIZE)
+ {
+ cli_print(cli, "Note: Padding too big! However, let's try and see what happens...\n");
+ }
+ }
+ }
+
+
+
+ // DEFAULT ANSWER:
+ else
+ {
+ cli_print(cli, "Unknown variable '%s'\n",argv[0]);
+ }
+
+ return CLI_OK;
+}
diff --git a/staging/cli_tcp.c b/staging/cli_tcp.c
new file mode 100644
index 0000000..16dc5a0
--- /dev/null
+++ b/staging/cli_tcp.c
@@ -0,0 +1,679 @@
+/*
+ * Mausezahn - A fast versatile traffic generator
+ * Copyright (C) 2008-2010 Herbert Haas
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
+ *
+*/
+
+
+#include "mz.h"
+#include "cli.h"
+#include "mops.h"
+
+
+
+// NOTE: The port numbers are maintained for both TCP and UDP.
+// See cli_udp.c.
+
+
+int cmd_tcp_seqnr (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ u_int32_t txs;
+ unsigned long long int tmp;
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc>3) ) {
+ cli_print(cli, "Specify the TCP sequence number (0-4294967295)\n");
+ cli_print(cli, "You may specify up to three parameters:\n");
+ cli_print(cli, " <sqnr>\r");
+ cli_print(cli, " <sqnr_start> <sqnr_stop>\r");
+ cli_print(cli, " <sqnr_start> <sqnr_stop> <sqnr_delta>\n");
+ cli_print(cli, "If a range is specified without step size 'sqnr_delta' (2nd case)\r");
+ cli_print(cli, "then sqnr_delta is per default set to one.\r");
+ cli_print(cli, "\n");
+ return CLI_OK;
+ }
+
+ tmp = str2lint(argv[0]);
+ if (tmp<=0xffffffff)
+ clipkt->tcp_seq = (u_int32_t) tmp;
+ else {
+ cli_print(cli, "Argument 1 must not exceed 4294967295\n");
+ return CLI_OK;
+ }
+ clipkt->tcp_seq_delta = 0;
+
+ if (argc>1) {
+ tmp = str2lint(argv[1]);
+ if (tmp<=0xffffffff) {
+ clipkt->tcp_seq_start = clipkt->tcp_seq;
+ clipkt->tcp_seq_stop = (u_int32_t) tmp;
+ } else {
+ cli_print(cli, "Argument 2 must not exceed 4294967295\n");
+ return CLI_OK;
+ }
+ clipkt->tcp_seq_delta = 1;
+ }
+
+ if (argc>2) {
+ tmp = str2lint(argv[2]);
+ if (tmp<=0xffffffff) {
+ clipkt->tcp_seq_delta = (u_int32_t) tmp;
+ } else {
+ cli_print(cli, "Argument 3 must not exceed 4294967295\n");
+ return CLI_OK;
+ }
+
+ if (argv[2]==0) {
+ cli_print(cli, "Note that a zero step size disables the range feature\n");
+ return CLI_OK;
+ }
+ }
+
+ txs = mops_tcp_complexity_sqnr (clipkt);
+ cli_print(cli, "FYI: Packet runs through %lu sequence numbers\n", (long unsigned int) txs);
+
+ return CLI_OK;
+}
+
+
+
+
+
+int cmd_tcp_acknr (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ u_int32_t txs;
+ unsigned long long int tmp;
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc>3) ) {
+ cli_print(cli, "Specify the TCP acknowledgement number (0-4294967295)\n");
+ cli_print(cli, "You may specify up to three parameters:\n");
+ cli_print(cli, " <acknr>\r");
+ cli_print(cli, " <acknr_start> <acknr_stop>\r");
+ cli_print(cli, " <acknr_start> <acknr_stop> <acknr_delta>\n");
+ cli_print(cli, "If a range is specified without step size 'acknr_delta' (2nd case)\r");
+ cli_print(cli, "then acknr_delta is per default set to one.\r");
+ cli_print(cli, "\n");
+ return CLI_OK;
+ }
+
+ tmp = str2lint(argv[0]);
+ if (tmp<=0xffffffff)
+ clipkt->tcp_ack = (u_int32_t) tmp;
+ else {
+ cli_print(cli, "Argument 1 must not exceed 4294967295\n");
+ return CLI_OK;
+ }
+ clipkt->tcp_ack_delta = 0;
+
+ if (argc>1) {
+ tmp = str2lint(argv[1]);
+ if (tmp<=0xffffffff) {
+ clipkt->tcp_ack_start = clipkt->tcp_ack;
+ clipkt->tcp_ack_stop = (u_int32_t) tmp;
+ } else {
+ cli_print(cli, "Argument 2 must not exceed 4294967295\n");
+ return CLI_OK;
+ }
+ clipkt->tcp_ack_delta = 1;
+ }
+
+ if (argc>2) {
+ tmp = str2lint(argv[2]);
+ if (tmp<=0xffffffff) {
+ clipkt->tcp_ack_delta = (u_int32_t) tmp;
+ } else {
+ cli_print(cli, "Argument 3 must not exceed 4294967295\n");
+ return CLI_OK;
+ }
+
+ if (argv[2]==0) {
+ cli_print(cli, "Note that a zero step size disables the range feature\n");
+ return CLI_OK;
+ }
+ }
+
+ txs = mops_tcp_complexity_acknr (clipkt);
+ cli_print(cli, "FYI: Packet runs through %lu acknowledge numbers\n", (long unsigned int) txs);
+
+
+ return CLI_OK;
+}
+
+
+
+
+
+
+int cmd_tcp_offset (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ unsigned int tmp;
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc>1) )
+ {
+ cli_print(cli, "Specify the TCP offset (=header length, 0..15) \r");
+ cli_print(cli, "\n");
+ return CLI_OK;
+ }
+
+ tmp = (unsigned int) str2int(argv[0]);
+ if (tmp<=15)
+ clipkt->tcp_offset = (u_int8_t) tmp;
+ else
+ {
+ cli_print(cli, "The TCP offset must not exceed 15\n");
+ }
+
+ return CLI_OK;
+}
+
+
+
+
+int cmd_tcp_res (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ int tmp;
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc>1) )
+ {
+ cli_print(cli, "Specify the TCP reserved field in binary format (4 bits)\n");
+ cli_print(cli, "\n");
+ return CLI_OK;
+ }
+
+ tmp = str2bin8 (argv[0]);
+ if ((tmp==-1)||(tmp>15))
+ {
+ cli_print(cli, "Invalid binary value! Allowed range: 0000 - 1111\n");
+ }
+ else
+ clipkt->tcp_res = (u_int8_t) tmp;
+
+ return CLI_OK;
+}
+
+
+int cmd_tcp_flags (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ int i, j=0;
+ char str[64];
+
+ if (strcmp(argv[argc-1],"?")==0)
+ {
+ cli_print(cli, "Configure a combination of TCP flags at once. All mentioned \r");
+ cli_print(cli, "flags are set, while not mentioned flags remain unset.\r");
+ cli_print(cli, "Flag keywords: cwr, ece, urg, ack, psh, rst, syn, fin.\r");
+ cli_print(cli, "NOTE: The flags command alone resets all flags to zero!\n");
+ cli_print(cli, "Example:\n");
+ cli_print(cli, " mz(config-pkt-1-tcp)# flags syn fin ack \n");
+ cli_print(cli, "\n");
+ mops_tcp_flags2str (clipkt, str);
+ cli_print(cli,"Current setting is: %s\n",str);
+ return CLI_OK;
+ }
+
+ if (argc>8)
+ {
+ cli_print(cli, "Up to 8 arguments are allowed using the keywords:\r");
+ cli_print(cli, "cwr, ece, urg, ack, psh, rst, syn, fin.\n");
+ return CLI_OK;
+ }
+
+ clipkt->tcp_ctrl_CWR = 0;
+ clipkt->tcp_ctrl_ECE = 0;
+ clipkt->tcp_ctrl_URG = 0;
+ clipkt->tcp_ctrl_ACK = 0;
+ clipkt->tcp_ctrl_PSH = 0;
+ clipkt->tcp_ctrl_RST = 0;
+ clipkt->tcp_ctrl_SYN = 0;
+ clipkt->tcp_ctrl_FIN = 0;
+
+
+
+ for (i=0; i<argc; i++) {
+ if (mz_strcmp(argv[i], "cwr", 1)==0) {
+ clipkt->tcp_ctrl_CWR = 1;
+ j=1;
+ }
+
+ if (mz_strcmp(argv[i], "ece", 1)==0) {
+ clipkt->tcp_ctrl_ECE = 1;
+ j=1;
+ }
+
+ if (mz_strcmp(argv[i], "urg", 1)==0) {
+ clipkt->tcp_ctrl_URG = 1;
+ j=1;
+ }
+
+ if (mz_strcmp(argv[i], "ack", 1)==0) {
+ clipkt->tcp_ctrl_ACK = 1;
+ j=1;
+ }
+
+ if (mz_strcmp(argv[i], "psh", 1)==0) {
+ clipkt->tcp_ctrl_PSH = 1;
+ j=1;
+ }
+
+ if (mz_strcmp(argv[i], "rst", 1)==0) {
+ clipkt->tcp_ctrl_RST = 1;
+ j=1;
+ }
+
+ if (mz_strcmp(argv[i], "syn", 1)==0) {
+ clipkt->tcp_ctrl_SYN = 1;
+ j=1;
+ }
+
+ if (mz_strcmp(argv[i], "fin", 1)==0) {
+ clipkt->tcp_ctrl_FIN = 1;
+ j=1;
+ }
+
+ if (!j) {
+ cli_print(cli, "Unknown keyword at position %i\n", i+1);
+ return CLI_OK;
+ }
+ else { // flag matched, continue
+ j=0;
+ }
+ }
+
+ mops_tcp_flags2str (clipkt, str);
+ cli_print(cli,"Current setting is: %s\n",str);
+
+ return CLI_OK;
+}
+
+
+
+int cmd_tcp_cwr (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ char str[64];
+
+ if (strcmp(argv[argc-1],"?")==0)
+ {
+ cli_print(cli, "Set or unset the TCP Congestion Window Reduced flag (CWR)\r");
+ mops_tcp_flags2str (clipkt, str);
+ cli_print(cli,"Current setting is: %s\n",str);
+ return CLI_OK;
+ }
+
+ if (argc!=1)
+ {
+ cli_print(cli, "Use the 'set' or 'unset' keywords.\n");
+ return CLI_OK;
+ }
+
+
+ if (mz_strcmp(argv[0], "set", 1)==0)
+ clipkt->tcp_ctrl_CWR = 1;
+ else if (mz_strcmp(argv[0], "unset", 1)==0)
+ clipkt->tcp_ctrl_CWR = 0;
+ else
+ cli_print(cli, "Unknown keyword. Use the 'set' or 'unset' keywords.\n");
+
+ mops_tcp_flags2str (clipkt, str);
+ cli_print(cli,"Current setting is: %s\n",str);
+
+ return CLI_OK;
+}
+
+
+
+int cmd_tcp_ece (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ char str[64];
+
+ if (strcmp(argv[argc-1],"?")==0) {
+ cli_print(cli, "Set or unset the TCP ECN-Echo flag (ECE)\r");
+ mops_tcp_flags2str (clipkt, str);
+ cli_print(cli,"Current setting is: %s\n",str);
+ return CLI_OK;
+ }
+
+ if (argc!=1) {
+ cli_print(cli, "Use the 'set' or 'unset' keywords.\n");
+ return CLI_OK;
+ }
+
+ if (mz_strcmp(argv[0], "set", 1)==0)
+ clipkt->tcp_ctrl_ECE = 1;
+ else if (mz_strcmp(argv[0], "unset", 1)==0)
+ clipkt->tcp_ctrl_ECE = 0;
+ else
+ cli_print(cli, "Unknown keyword. Use the 'set' or 'unset' keywords.\n");
+
+ mops_tcp_flags2str (clipkt, str);
+ cli_print(cli,"Current setting is: %s\n",str);
+
+ return CLI_OK;
+}
+
+
+
+int cmd_tcp_urg (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ char str[64];
+
+ if (strcmp(argv[argc-1],"?")==0) {
+ cli_print(cli, "Set or unset the TCP urgent flag (URG)\r");
+ mops_tcp_flags2str (clipkt, str);
+ cli_print(cli,"Current setting is: %s\n",str);
+ return CLI_OK;
+ }
+
+ if (argc!=1) {
+ cli_print(cli, "Use the 'set' or 'unset' keywords.\n");
+ return CLI_OK;
+ }
+
+ if (mz_strcmp(argv[0], "set", 1)==0)
+ clipkt->tcp_ctrl_URG = 1;
+ else if (mz_strcmp(argv[0], "unset", 1)==0)
+ clipkt->tcp_ctrl_URG = 0;
+ else
+ cli_print(cli, "Unknown keyword. Use the 'set' or 'unset' keywords.\n");
+
+ mops_tcp_flags2str (clipkt, str);
+ cli_print(cli,"Current setting is: %s\n",str);
+
+ return CLI_OK;
+}
+
+
+
+
+int cmd_tcp_ack (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ char str[64];
+
+ if (strcmp(argv[argc-1],"?")==0) {
+ cli_print(cli, "Set or unset the TCP acknowledgement flag (ACK)\r");
+ mops_tcp_flags2str (clipkt, str);
+ cli_print(cli,"Current setting is: %s\n",str);
+ return CLI_OK;
+ }
+
+ if (argc!=1) {
+ cli_print(cli, "Use the 'set' or 'unset' keywords.\n");
+ return CLI_OK;
+ }
+
+
+ if (mz_strcmp(argv[0], "set", 1)==0)
+ clipkt->tcp_ctrl_ACK = 1;
+ else if (mz_strcmp(argv[0], "unset", 1)==0)
+ clipkt->tcp_ctrl_ACK = 0;
+ else
+ cli_print(cli, "Unknown keyword. Use the 'set' or 'unset' keywords.\n");
+
+ mops_tcp_flags2str (clipkt, str);
+ cli_print(cli,"Current setting is: %s\n",str);
+
+ return CLI_OK;
+}
+
+
+
+int cmd_tcp_psh (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ char str[64];
+
+ if (strcmp(argv[argc-1],"?")==0) {
+ cli_print(cli, "Set or unset the TCP push flag (PSH)\r");
+ mops_tcp_flags2str (clipkt, str);
+ cli_print(cli,"Current setting is: %s\n",str);
+ return CLI_OK;
+ }
+
+ if (argc!=1) {
+ cli_print(cli, "Use the 'set' or 'unset' keywords.\n");
+ return CLI_OK;
+ }
+
+ if (mz_strcmp(argv[0], "set", 1)==0)
+ clipkt->tcp_ctrl_PSH = 1;
+ else if (mz_strcmp(argv[0], "unset", 1)==0)
+ clipkt->tcp_ctrl_PSH = 0;
+ else
+ cli_print(cli, "Unknown keyword. Use the 'set' or 'unset' keywords.\n");
+
+ mops_tcp_flags2str (clipkt, str);
+ cli_print(cli,"Current setting is: %s\n",str);
+
+ return CLI_OK;
+}
+
+
+
+int cmd_tcp_rst (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ char str[64];
+
+ if (strcmp(argv[argc-1],"?")==0) {
+ cli_print(cli, "Set or unset the TCP reset flag (RST)\r");
+ mops_tcp_flags2str (clipkt, str);
+ cli_print(cli,"Current setting is: %s\n",str);
+ return CLI_OK;
+ }
+
+ if (argc!=1) {
+ cli_print(cli, "Use the 'set' or 'unset' keywords.\n");
+ return CLI_OK;
+ }
+
+ if (mz_strcmp(argv[0], "set", 1)==0)
+ clipkt->tcp_ctrl_RST = 1;
+ else if (mz_strcmp(argv[0], "unset", 1)==0)
+ clipkt->tcp_ctrl_RST = 0;
+ else
+ cli_print(cli, "Unknown keyword. Use the 'set' or 'unset' keywords.\n");
+
+ mops_tcp_flags2str (clipkt, str);
+ cli_print(cli,"Current setting is: %s\n",str);
+
+ return CLI_OK;
+}
+
+
+
+int cmd_tcp_syn (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ char str[64];
+
+ if (strcmp(argv[argc-1],"?")==0) {
+ cli_print(cli, "Set or unset the TCP synchronisation flag (SYN)\r");
+ mops_tcp_flags2str (clipkt, str);
+ cli_print(cli,"Current setting is: %s\n",str);
+ return CLI_OK;
+ }
+
+ if (argc!=1) {
+ cli_print(cli, "Use the 'set' or 'unset' keywords.\n");
+ return CLI_OK;
+ }
+
+ if (mz_strcmp(argv[0], "set", 1)==0)
+ clipkt->tcp_ctrl_SYN = 1;
+ else if (mz_strcmp(argv[0], "unset", 1)==0)
+ clipkt->tcp_ctrl_SYN = 0;
+ else
+ cli_print(cli, "Unknown keyword. Use the 'set' or 'unset' keywords.\n");
+
+ mops_tcp_flags2str (clipkt, str);
+ cli_print(cli,"Current setting is: %s\n",str);
+
+ return CLI_OK;
+}
+
+
+
+int cmd_tcp_fin (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ char str[64];
+
+ if (strcmp(argv[argc-1],"?")==0) {
+ cli_print(cli, "Set or unset the TCP finalisation flag (FIN)\r");
+ mops_tcp_flags2str (clipkt, str);
+ cli_print(cli,"Current setting is: %s\n",str);
+ return CLI_OK;
+ }
+
+ if (argc!=1) {
+ cli_print(cli, "Use the 'set' or 'unset' keywords.\n");
+ return CLI_OK;
+ }
+
+ if (mz_strcmp(argv[0], "set", 1)==0)
+ clipkt->tcp_ctrl_FIN = 1;
+ else if (mz_strcmp(argv[0], "unset", 1)==0)
+ clipkt->tcp_ctrl_FIN = 0;
+ else
+ cli_print(cli, "Unknown keyword. Use the 'set' or 'unset' keywords.\n");
+
+ mops_tcp_flags2str (clipkt, str);
+ cli_print(cli,"Current setting is: %s\n",str);
+
+ return CLI_OK;
+}
+
+
+
+int cmd_tcp_window (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ unsigned long int tmp;
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc>1) )
+ {
+ cli_print(cli, "Specify the TCP window size (0..65535)\r");
+ cli_print(cli, "\n");
+ return CLI_OK;
+ }
+
+ tmp = (unsigned long int) str2int (argv[0]);
+ if (tmp<65535)
+ {
+ clipkt->tcp_win = (u_int16_t) tmp;
+ }
+ else
+ {
+ cli_print(cli, "The TCP window size must not exceed 65535\n");
+ }
+
+ return CLI_OK;
+}
+
+
+
+int cmd_tcp_sum (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ int sum;
+
+ if (strncmp(argv[argc-1], "?", 2)==0)
+ {
+ cli_print(cli, "Specify the TCP checksum in hexadecimal or use the keyword 'auto'.\r");
+ cli_print(cli, "By default, the checksum is computed automatically.\n");
+ return CLI_OK;
+ }
+
+ if (mz_strcmp(argv[0], "auto", 2)==0)
+ {
+ clipkt->tcp_sum_false=0;
+ return CLI_OK;
+ }
+
+ sum = (int) xstr2int(argv[0]);
+
+ if (sum>0xffff)
+ {
+ cli_print(cli, "The checksum must be within range 0..ffff\n");
+ return CLI_OK;
+ }
+
+ clipkt->tcp_sum = (u_int16_t) sum;
+ clipkt->tcp_sum_false=1;
+
+ return CLI_OK;
+}
+
+
+
+int cmd_tcp_urgptr(struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+
+ unsigned long int tmp;
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc>1) )
+ {
+ cli_print(cli, "Specify the TCP urgent pointer (0..65535)\r");
+ cli_print(cli, "\n");
+ return CLI_OK;
+ }
+
+ tmp = (unsigned long int) str2int (argv[0]);
+ if (tmp<65535)
+ {
+ clipkt->tcp_urg = (u_int16_t) tmp;
+ }
+ else
+ {
+ cli_print(cli, "The TCP urgent pointer must not exceed 65535\n");
+ }
+
+ return CLI_OK;
+}
+
+
+
+int cmd_tcp_options (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ int mss=0, sack=0, scale=0;
+ u_int32_t tsval=0, tsecr=0;
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc>1) ) {
+ cli_print(cli, "Specify TCP options\n");
+ cli_print(cli, "Option parameters:\n");
+ cli_print(cli, "[ mss <0..65535> ] [sack] [tsval <0..4294967295> [tsecr <0..4294967295>]] [nop] [scale <0..14>]\n");
+ cli_print(cli, "NOTE: Only a set of default options are supported in this version\r");
+ cli_print(cli, "(20 bytes, consisting of MSS=1452 bytes, SACK permitted, a Timestamp,\r");
+ cli_print(cli, "NOP, and Window Scale 5)\r");
+ cli_print(cli, "\n");
+ return CLI_OK;
+ }
+
+ if (clipkt->tcp_option_used) {
+ // turn off
+ clipkt->tcp_option_used = 0;
+ } else {
+ // turn on
+ mops_tcp_add_option (clipkt, mss, sack, scale, tsval, tsecr);
+
+ cli_print(cli, "NOTE: Only a set of default options are supported in this version\r");
+ cli_print(cli, "(20 bytes, consisting of MSS=1452 bytes, SACK permitted, a Timestamp,\r");
+ cli_print(cli, "NOP, and Window Scale 5)\n");
+ }
+
+ return CLI_OK;
+}
+
+
+
+int cmd_tcp_end(struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ char prompt[16];
+ sprintf(prompt, "pkt-%i",clipkt->id);
+ cli_set_configmode(cli, MZ_MODE_PACKET, prompt);
+ return CLI_OK;
+}
diff --git a/staging/cli_tools.c b/staging/cli_tools.c
new file mode 100644
index 0000000..20ce50e
--- /dev/null
+++ b/staging/cli_tools.c
@@ -0,0 +1,40 @@
+/*
+ * Mausezahn - A fast versatile traffic generator
+ * Copyright (C) 2008-2010 Herbert Haas
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
+ *
+*/
+
+
+
+
+
+#include "mz.h"
+
+
+// Returns a nice string with default and current value of a given variable
+//
+// EXAMPLE:
+//
+// char mystring[256];
+// mz_def16 ("20 seconds", pd->max_age, mystring)
+//
+int mz_def16 (char *def, u_int16_t val, char *str256)
+{
+ str256[0]=0x00;
+ sprintf(str256, "The default value is %s. The current value is %u (0x%04x).", def, val, val);
+ return 0;
+}
+
+
diff --git a/staging/cli_udp.c b/staging/cli_udp.c
new file mode 100644
index 0000000..9d29f4c
--- /dev/null
+++ b/staging/cli_udp.c
@@ -0,0 +1,204 @@
+/*
+ * Mausezahn - A fast versatile traffic generator
+ * Copyright (C) 2008-2010 Herbert Haas
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
+ *
+*/
+
+
+#include "mz.h"
+#include "cli.h"
+#include "mops.h"
+
+
+
+int cmd_port_source (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ u_int32_t t32=0;
+ int validport=0;
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc>2) ) {
+ cli_print(cli, "Specify the source port number:\n");
+ cli_print(cli, " <port> [<end-port>]\r");
+ cli_print(cli, " random [norandom]\r");
+ cli_print(cli, "\n");
+ return CLI_OK;
+ }
+
+ if (mz_strcmp(argv[0], "random",1)==0) {
+ clipkt->sp_isrand = 1;
+ clipkt->sp_isrange = 0;
+ } else if (mz_strcmp(argv[0], "norandom",1)==0) {
+ clipkt->sp_isrand = 0;
+ } else {
+ if (!mz_strisnum(argv[0])) {
+ cli_print(cli, "Unknown keyword\n");
+ return CLI_OK;
+ }
+ t32 = str2int(argv[0]);
+ if (t32>65535) {
+ cli_print(cli, "Port number cannot exceed 65535\n");
+ return CLI_OK;
+ } else {
+ clipkt->sp= (u_int16_t) t32;
+ validport=1;
+ clipkt->sp_isrange = 0;
+ }
+ }
+
+ if ((argc==2) && (validport)) {
+ if (!mz_strisnum(argv[1])) {
+ cli_print(cli, "Invalid number\n");
+ return CLI_OK;
+ }
+ t32 = str2int(argv[1]);
+ if (t32>65535) {
+ cli_print(cli, "Port number cannot exceed 65535\n");
+ } else {
+ clipkt->sp_start = clipkt->sp;
+ clipkt->sp_stop = (u_int16_t) t32;
+ clipkt->sp_isrange = 1;
+ }
+ }
+
+ return CLI_OK;
+}
+
+
+
+
+int cmd_port_destination (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ u_int32_t t32=0;
+ int validport=0;
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc>2) ) {
+ cli_print(cli, "Specify the destination port number\r");
+ cli_print(cli, " <port> [<end-port>]\r");
+ cli_print(cli, " random [norandom]\r");
+ cli_print(cli, "\n");
+ return CLI_OK;
+ }
+
+ if (mz_strcmp(argv[0], "random",1)==0) {
+ clipkt->dp_isrand = 1;
+ clipkt->dp_isrange = 0;
+ } else if (mz_strcmp(argv[0], "norandom",1)==0) {
+ clipkt->dp_isrand = 0;
+ } else {
+ if (!mz_strisnum(argv[0])) {
+ cli_print(cli, "Unknown keyword\n");
+ return CLI_OK;
+
+ }
+ t32 = str2int(argv[0]);
+ if (t32>65535) {
+ cli_print(cli, "Port number cannot exceed 65535\n");
+ return CLI_OK;
+ } else {
+ clipkt->dp= (u_int16_t) t32;
+ validport=1;
+ clipkt->dp_isrange = 0;
+ }
+ }
+
+ if ((argc==2) && (validport)) {
+ if (!mz_strisnum(argv[1])) {
+ cli_print(cli, "Invalid number\n");
+ return CLI_OK;
+ }
+ t32 = str2int(argv[1]);
+ if (t32>65535) {
+ cli_print(cli, "Port number cannot exceed 65535\n");
+ } else {
+ clipkt->dp_start = clipkt->dp;
+ clipkt->dp_stop = (u_int16_t) t32;
+ clipkt->dp_isrange = 1;
+ }
+ }
+
+ return CLI_OK;
+}
+
+
+
+int cmd_udp_sum (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ int sum;
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc>1) )
+ {
+ cli_print(cli, "Specify the UDP checksum:\n");
+ cli_print(cli, " - either in hexadecimal format (0-ffff)\r");
+ cli_print(cli, " - or use the keyword 'auto' (default)\r");
+ cli_print(cli, " - or use the keyword 'unset'\r");
+ cli_print(cli, "\r");
+ cli_print(cli, "By default, the checksum is computed automatically. The keyword\r");
+ cli_print(cli, "'unset' signals the receiver that the checksum has not be computed\r");
+ cli_print(cli, "and should be ignored.\n");
+ return CLI_OK;
+ }
+
+ if (mz_strcmp(argv[0], "auto", 2)==0)
+ {
+ clipkt->udp_sum_false=0;
+ return CLI_OK;
+ }
+
+ if (mz_strcmp(argv[0], "unset", 2)==0)
+ {
+ clipkt->udp_sum_false=1;
+ clipkt->udp_sum = 0xffff;
+ return CLI_OK;
+ }
+
+ sum = (int) xstr2int(argv[0]);
+
+ if (sum>0xffff)
+ {
+ cli_print(cli, "The checksum must be within range 0..ffff\n");
+ return CLI_OK;
+ }
+
+ clipkt->udp_sum = (u_int16_t) sum;
+ clipkt->udp_sum_false=1;
+
+ return CLI_OK;
+}
+
+
+
+int cmd_udp_len (struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+
+ if ( (strcmp(argv[argc-1],"?")==0) || (argc>1) )
+ {
+ cli_print(cli, "Specify the UDP length\r");
+ cli_print(cli, "\n");
+ return CLI_OK;
+ }
+
+ cli_print(cli, "Not supported in this version.\n");
+
+ return CLI_OK;
+}
+
+
+int cmd_udp_end(struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ char prompt[16];
+ sprintf(prompt, "pkt-%i",clipkt->id);
+ cli_set_configmode(cli, MZ_MODE_PACKET, prompt);
+ return CLI_OK;
+}
diff --git a/staging/directmops.c b/staging/directmops.c
new file mode 100644
index 0000000..5d95bd3
--- /dev/null
+++ b/staging/directmops.c
@@ -0,0 +1,30 @@
+/*
+ * Mausezahn - A fast versatile traffic generator
+ * Copyright (C) 2008-2010 Herbert Haas
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
+ *
+*/
+
+
+#include "mz.h"
+#include "cli.h"
+#include "mops.h"
+
+
+int mops_direct(char* dev, int mops_type, char* argstring)
+{
+ printf("Got device {%s} type {%i} and argstring {%s}\n", dev, mops_type, argstring);
+
+ return 0;
+}
diff --git a/staging/dns.c b/staging/dns.c
new file mode 100644
index 0000000..5f9203c
--- /dev/null
+++ b/staging/dns.c
@@ -0,0 +1,817 @@
+/*
+ * Mausezahn - A fast versatile traffic generator
+ * Copyright (C) 2008 Herbert Haas
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
+ *
+*/
+
+
+
+////////////////////////////////////////////////////////////////////
+//
+// DNS: Only UDP-based here
+//
+////////////////////////////////////////////////////////////////////
+
+#include "mz.h"
+#include "cli.h"
+
+
+#define MZ_DNS_HELP \
+ "| DNS type: Send Domain Name System Messages.\n" \
+ "|\n" \
+ "| Generally there are two interesting general DNS messages: queries and answers. The easiest\n" \
+ "| way is to use the following syntax:\n" \
+ "|\n" \
+ "| query|q = <name>[:<type>] ............. where type is per default \"A\"\n" \
+ "| (and class is always \"IN\")\n" \
+ "|\n" \
+ "| answer|a = [<type>:<ttl>:]<rdata> ...... ttl is per default 0.\n" \
+ "| = [<type>:<ttl>:]<rdata>/[<type>:<ttl>:]<rdata>/...\n" \
+ "|\n" \
+ "| Note: If you only use the 'query' option then a query is sent. If you additonally add\n" \
+ "| an 'answer' option then an answer is sent.\n" \
+ "|\n" \
+ "| Examples: \n" \
+ "|\n" \
+ "| q = www.xyz.com\n" \
+ "| q = www.xyz.com, a=192.168.1.10\n" \
+ "| q = www.xyz.com, a=A:3600:192.168.1.10\n" \
+ "| q = www.xyz.com, a=CNAME:3600:abc.com/A:3600:192.168.1.10\n" \
+ "|\n" \
+ "| Note: <type> can be: A, CNAME, or any integer\n" \
+ "|\n" \
+ "|\n" \
+ "| OPTIONAL parameter hacks: (if you don't know what you do this might cause invalid packets)\n" \
+ "|\n" \
+ "| Parameter Description query / reply)\n" \
+ "| -------------------------------------------------------------------------------------\n" \
+ "|\n" \
+ "| request/response|reply ..... flag only request / n.a. \n" \
+ "| id ......................... packet id (0-65535) random / random\n" \
+ "| opcode (or op) ............. accepts values 0..15 or one of std / 0 \n" \
+ "| these keywords: \n" \
+ "| = std ................... Standard Query\n" \
+ "| = inv ................... Inverse Query\n" \
+ "| = sts ................... Server Status Request\n" \
+ "| aa or !aa .................. Authoritative Answer UNSET / SET\n" \
+ "| tc or !tc .................. Truncation UNSET / UNSET\n" \
+ "| rd or !rd .................. Recursion Desired SET / SET\n" \
+ "| ra or !ra .................. Recursion Available UNSET / SET\n" \
+ "| z .......................... Reserved (takes values 0..7) 0 / 0 \n" \
+ "| (z=2...authenticated)\n" \
+ "| rcode ...................... Response Code (0..15); interesting 0 / 0 \n" \
+ "| values are:\n" \
+ "| = 0 ...................... No Error Condition\n" \
+ "| = 1 ...................... Unable to interprete query due to format error\n" \
+ "| = 2 ...................... Unable to process due to server failure\n" \
+ "| = 3 ...................... Name in query does not exist\n" \
+ "| = 4 ...................... Type of query not supported\n" \
+ "| = 5 ...................... Query refused\n" \
+ "|\n" \
+ "| Count values (values 0..65535) will be set automatically! You should not set these\n" \
+ "| values manually except you are interested in invalid packets.\n" \
+ "| qdcount (or qdc) ........... Number of entries in question section 1 / 1\n" \
+ "| ancount (or anc) ........... Number of RRs in answer records section 0 / 1\n" \
+ "| nscount (or nsc) ........... Number of name server RRs in authority 0 / 0\n" \
+ "| records section\n" \
+ "| arcount (or arc) ........... Number of RRs in additional records section 0 / 0\n" \
+ "\n"
+
+
+int dns_get_query (char* argval);
+int dns_get_answer (char* argval);
+
+
+
+// Note: I do NOT use libnet here (had problems with bugs there...)
+int create_dns_packet ()
+{
+
+ char *token, *tokenptr, argval[MAX_PAYLOAD_SIZE];
+
+ int i=0,j=0;
+
+ unsigned char *x;
+ u_int16_t tmp;
+
+
+ // 16 bit values:
+ u_int8_t
+ dns_id0 =0, // DNS packet ID
+ dns_id1 =0,
+ dns_flags0 =0, // consists of the flags below
+ dns_flags1 =0,
+ dns_num_q0 =0, // number of questions
+ dns_num_q1 =0,
+ dns_num_ans0 =0, // number of answer resource records
+ dns_num_ans1 =0,
+ dns_num_aut0 =0, // number of authority resource records
+ dns_num_aut1 =0,
+ dns_num_add0 =0, // number of additional resource records
+ dns_num_add1 =0,
+ dns_type0 =0,
+ dns_type1 =0;
+
+
+ // bit fields for dns_flags1: Q/R(1), OPCODE(4), AA(1), TC(1), RD(1)
+ // bit fields for dns_flags0: RA(1), Z(3), RCODE(4)
+ u_int8_t
+ dns_flags_qr, // 1 bit
+ dns_flags_opcode, // 4 bits
+ dns_flags_aa, // 1 bit
+ dns_flags_tc, // 1 bit
+ dns_flags_rd, // 1 bit
+ // ---- next byte -----
+ dns_flags_ra, // 1 bit
+ dns_flags_z, // 3 bits
+ dns_flags_rcode; // 4 bits
+
+
+ u_int8_t
+ dns_packet[MAX_PAYLOAD_SIZE], // finally the whole packet with all sections
+ section[MAX_PAYLOAD_SIZE]; // contains only a section (intermediately)
+ u_int32_t
+ dns_packet_s;
+
+
+
+ if ( (getarg(tx.arg_string,"help", NULL)==1) && (mode==DNS) )
+ {
+ if (mz_port)
+ {
+ cli_print(gcli, "%s", MZ_DNS_HELP);
+ return -1;
+ }
+ else
+ {
+ fprintf(stderr,"\n"
+ MAUSEZAHN_VERSION
+ "\n%s", MZ_DNS_HELP);
+ exit(0);
+ }
+ }
+
+
+ // general defaults:
+ // TODO: define globals in case dns is called by external functions!)
+ // MOST SAFEST AND EASIEST METHOD: define tx.dns_xxxx for default-initialization
+ //
+ dns_id0 = 0x42; // dns_id0 = (u_int8_t) ( ((float) rand()/RAND_MAX)*255);
+ dns_id1 = 0x42;
+
+ dns_flags_qr = 0; // request
+ dns_flags_opcode = 0; // 'standard query' (also for response!)
+
+ dns_type0 = 1; // A record
+ dns_type1 = 0;
+
+
+ i=0;
+
+
+ /////////////////////////////////////////////////////////////////////////////////
+ // Evaluate CLI parameters:
+
+
+ // Handle the query //
+
+ if ( (getarg(tx.arg_string,"query", argval)==1) ||
+ (getarg(tx.arg_string,"q", argval)==1) )
+ {
+
+ (void) dns_get_query (argval); // returns the length in byte dns_num_q0=1;
+
+ // copy the result from gbuf to our local buffer 'section':
+ for (j=0;j<gbuf_s;j++)
+ {
+ section[j]=gbuf[j];
+ }
+
+ i = gbuf_s;
+
+ // Set defaults if not already set by callee.
+ // !! But ONLY set these if there is no additional answer section
+ // !! because then the answer section should set the defaults !!!
+ if ( (getarg(tx.arg_string,"answer", NULL)==0) && // no answer
+ (getarg(tx.arg_string,"a", NULL)==0) )
+ {
+ if (!tx.dp) tx.dp = 53;
+ if (!tx.sp) tx.sp = 42000;
+ }
+
+
+ // These are the defaults for a query:
+ dns_flags_aa = 1; // authoritative answer
+ dns_flags_tc = 0; // not truncated
+ dns_flags_rd = 1; // recursion desired
+ dns_flags_ra = 0; // recursion available
+ dns_flags_z = 0; // FYI: if 010 = 2 = authenticated
+ dns_flags_rcode = 0; // no errors
+ dns_num_q0 = 1; // number of questions
+ }
+
+
+
+ // Handle the answer:
+ //
+ // answer|a = <name>[:<type>[:<class>]]/[<ttl>:]<rdata>\n"
+ if ( (getarg(tx.arg_string,"answer", argval)==1) ||
+ (getarg(tx.arg_string,"a", argval)==1) )
+ {
+
+ // In case there are multiple answer sections seperate them with / or |
+ token = strtok_r(argval,"/|",&tokenptr);
+ do
+ {
+ //then the corresponding answer section:
+ //first create a pointer to the <name>:
+ section[i]=0xc0; // a pointer always starts with MSB=11xxxxxx xxxxxxx = 0xc0
+ i++;
+ section[i]=0x0c; // this number always points to the first query entry
+ i++;
+ //then add rdata
+ dns_num_ans0 += dns_get_answer (token);
+ //NOTE: 'i' points to the next free byte in section[] (see the query handling above)
+ for (j=0;j<gbuf_s;j++)
+ {
+ section[j+i]=gbuf[j];
+ }
+ i=i+gbuf_s; // so 'i' again points to the next free byte in section[]
+ } while ( (token = strtok_r(NULL,"/|",&tokenptr))!=NULL);
+
+ if (!tx.sp) tx.sp = 53;
+ if (!tx.dp) tx.dp = 42000; // should be set by user
+ dns_flags_qr = 1; // response
+ dns_flags_aa = 0; // no authoritative answer
+ dns_flags_tc = 0; // not truncated
+ dns_flags_rd = 1; // recursion desired
+ dns_flags_ra = 0; // recursion not available
+ dns_flags_z = 0; // FYI: if 010 = 2 = authenticated
+ dns_flags_rcode = 0; // no errors
+ }
+
+
+
+ // *** NOTE ***
+ // Now 'i' contains the number of DNS payload bytes = valid bytes in section[]
+ //
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ // Now let's handle the optional other commands, if some user really changed them...
+ //
+ //
+
+ if (getarg(tx.arg_string,"id",argval)==1)
+ {
+ tmp = (u_int16_t) str2int (argval);
+ x = (unsigned char*) &tmp;
+
+ dns_id1 = *x;
+ x++;
+ dns_id0 = *x;
+ }
+
+
+ if ( (getarg(tx.arg_string,"opcode", argval)==1) || (getarg(tx.arg_string,"op", argval)==1))
+ {
+ if (strncmp(argval,"std",3)==0) // standard query
+ {
+ dns_flags_opcode = 0;
+ }
+ else if (strncmp(argval,"inv",3)==0) // inverse query
+ {
+ dns_flags_opcode = 1;
+ }
+ else if (strncmp(argval,"sts",3)==0) // status server request
+ {
+ dns_flags_opcode = 2;
+ }
+ else // specified as integer
+ {
+ dns_flags_opcode = (u_int8_t) str2int (argval);
+ if (dns_flags_opcode > 15)
+ {
+ if (!quiet)
+ {
+ fprintf(stderr, "mz/dns: [Warning] Opcode cannot exceed 15 => will reduce to 15!\n");
+ }
+ dns_flags_opcode = 15;
+ }
+ }
+ }
+
+
+
+
+ if (getarg(tx.arg_string,"aa",NULL)==1)
+ {
+ dns_flags_aa = 1;
+ }
+
+ if (getarg(tx.arg_string,"!aa",NULL)==1)
+ {
+ dns_flags_aa = 0;
+ }
+
+ if (getarg(tx.arg_string,"tc",NULL)==1)
+ {
+ dns_flags_tc = 1;
+ }
+
+ if (getarg(tx.arg_string,"!tc",NULL)==1)
+ {
+ dns_flags_tc = 0;
+ }
+
+ if (getarg(tx.arg_string,"rd",NULL)==1)
+ {
+ dns_flags_rd = 1;
+ }
+
+ if (getarg(tx.arg_string,"!rd",NULL)==1)
+ {
+ dns_flags_rd = 0;
+ }
+
+ if (getarg(tx.arg_string,"ra",NULL)==1)
+ {
+ dns_flags_ra = 1;
+ }
+
+ if (getarg(tx.arg_string,"!ra",NULL)==1)
+ {
+ dns_flags_ra = 0;
+ }
+
+ if (getarg(tx.arg_string,"z", argval)==1)
+ {
+ dns_flags_z = (u_int8_t) str2int (argval);
+ if (dns_flags_z > 7)
+ {
+ if (!quiet)
+ {
+ fprintf(stderr, "mz/dns: [Warning] z cannot exceed 7 => will reduce to 7!\n");
+ }
+ dns_flags_z = 7;
+ }
+ }
+
+
+
+ if (getarg(tx.arg_string,"rcode", argval)==1)
+ {
+ dns_flags_rcode = (u_int8_t) str2int (argval);
+ if (dns_flags_rcode > 15)
+ {
+ if (!quiet)
+ {
+ fprintf(stderr, "mz/dns: [Warning] rcode cannot exceed 15 => will reduce to 15!\n");
+ }
+ dns_flags_rcode = 7;
+ }
+ }
+
+
+ if ( (getarg(tx.arg_string,"qdcount", argval)==1) ||
+ (getarg(tx.arg_string,"qdc", argval)==1) ||
+ (getarg(tx.arg_string,"qc", argval)==1) )
+
+ {
+ tmp = (u_int16_t) str2int (argval);
+ x = (unsigned char*) &tmp;
+ dns_num_q1 = *x;
+ x++;
+ dns_num_q0 = *x;
+ }
+
+ if ( (getarg(tx.arg_string,"ancount", argval)==1) ||
+ (getarg(tx.arg_string,"anc", argval)==1) )
+ {
+ tmp = (u_int16_t) str2int (argval);
+ x = (unsigned char*) &tmp;
+ dns_num_ans1 = *x;
+ x++;
+ dns_num_ans0 = *x;
+ }
+
+ if ( (getarg(tx.arg_string,"nscount", argval)==1) ||
+ (getarg(tx.arg_string,"nsc", argval)==1) )
+ {
+ tmp = (u_int16_t) str2int (argval);
+ x = (unsigned char*) &tmp;
+ dns_num_aut1 = *x;
+ x++;
+ dns_num_aut0 = *x;
+ }
+
+ if ( (getarg(tx.arg_string,"arcount", argval)==1) ||
+ (getarg(tx.arg_string,"arc", argval)==1) )
+ {
+ tmp = (u_int16_t) str2int (argval);
+ x = (unsigned char*) &tmp;
+ dns_num_add1 = *x;
+ x++;
+ dns_num_add0 = *x;
+ }
+
+ //
+ // End of optional parameter handling
+ //
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+
+
+
+
+ /////////////////////////////////////////////////////////
+ // Now put all together i. e. create the UDP payload
+ //
+ // bit fields for dns_flags1: Q/R(1), OPCODE(4), AA(1), TC(1), RD(1)
+ // bit fields for dns_flags0: RA(1), Z(3), RCODE(4)
+ //
+ // 7 6 5 4 3 2 1 0
+ // +--+--+--+--+--+--+--+--+
+ // |QR| OPCODE |AA|TC|RD|
+ // +--+--+--+--+--+--+--+--+
+ //
+ //
+ // 7 6 5 4 3 2 1 0
+ // +--+--+--+--+--+--+--+--+
+ // |RA| Z | RCODE |
+ // +--+--+--+--+--+--+--+--+
+ //
+
+ //// Flags: MSB
+ dns_flags_qr <<= 7;
+ dns_flags1 |= dns_flags_qr;
+
+ dns_flags_opcode <<= 3;
+ dns_flags1 |= dns_flags_opcode;
+
+ dns_flags_aa <<= 2;
+ dns_flags1 |= dns_flags_aa;
+
+ dns_flags_tc <<= 1;
+ dns_flags1 |= dns_flags_tc;
+
+ dns_flags1 |= dns_flags_rd;
+
+ //// Flags: LSB
+
+ dns_flags_ra <<= 7;
+ dns_flags0 |= dns_flags_ra;
+
+ dns_flags_z <<= 4;
+ dns_flags0 |= dns_flags_z;
+
+ dns_flags0 |= dns_flags_rcode;
+
+ //// Add header bytes to dns_packet:
+
+ dns_packet[0]=dns_id1;
+ dns_packet[1]=dns_id0;
+
+ dns_packet[2]=dns_flags1;
+ dns_packet[3]=dns_flags0;
+
+ dns_packet[4]=dns_num_q1;
+ dns_packet[5]=dns_num_q0;
+
+ dns_packet[6]=dns_num_ans1;
+ dns_packet[7]=dns_num_ans0;
+
+ dns_packet[8]=dns_num_aut1;
+ dns_packet[9]=dns_num_aut0;
+
+ dns_packet[10]=dns_num_add1;
+ dns_packet[11]=dns_num_add0;
+
+ //// Add sections to dns_packet:
+
+
+ for (j=0; j<i; j++)
+ {
+ dns_packet[12+j] = section[j];
+ }
+
+ //
+ //////////////////////////////////////////////////////////
+
+ dns_packet_s = i+12;
+ tx.udp_payload_s = dns_packet_s;
+
+ // copy the dns_paylod to the udp_payload
+
+ for (j=0; j<tx.udp_payload_s; j++)
+ {
+ tx.udp_payload[j] = dns_packet[j];
+ }
+
+ tx.udp_len = 8 + tx.udp_payload_s;
+
+ return dns_packet_s;
+}
+
+
+
+////////////////////////////////////////////////////////////////////////////////////////////
+// Accepts a string like "www.perihel.at:A" or "www.perihel.at"
+// and creates a valid query section using the global gbuf[] and gbuf_s
+//
+// query|q = <name>[:<type>]\n"
+// Return value:
+// number of queries (currently only 1 query accepted,
+// hence return value is 1 on success or 0 upon failure
+//
+int dns_get_query(char* argval)
+{
+ char *token, *field, *saveptr1=NULL, *saveptr2=NULL;
+ int i,j, cnt;
+ u_int16_t tmp;
+ unsigned char *x;
+
+ i=0;
+
+ // now get first field: <name>
+ field = strtok_r(argval, ":", &saveptr1);
+
+ // decompose <name> into labels:
+ token = strtok_r(field, ".", &saveptr2);
+
+ do // loop through all labels
+ {
+ cnt = strlen(token);
+ gbuf[i] = cnt;
+ i++;
+ for (j=i; j<(i+cnt);j++)
+ {
+ gbuf[j] = *token;
+ token++;
+ }
+ i+=cnt;
+
+ } while ( (token = strtok_r(NULL, ".", &saveptr2)) != NULL);
+
+ gbuf[i]=0x00;
+ i++; // (always point to next empty byte)
+
+
+ // lets see if <type> has also been specified:
+ if ( (field = strtok_r(NULL, ":", &saveptr1)) !=NULL)
+ {
+ if ( (strncmp(field, "A",1)==0) || (strncmp(field, "a",1)==0) )
+ {
+ tmp = 1;
+ }
+ else
+ {
+ tmp = (u_int16_t) str2int (field);
+ }
+
+ x = (unsigned char*) &tmp;
+
+ gbuf[i] = *(x+1);
+ i++;
+ gbuf[i] = *x;
+ i++;
+ }
+ else // use default type=A
+ {
+ gbuf[i] = 0x00; i++;
+ gbuf[i] = 0x01; i++;
+ }
+
+ // finally add the class=IN:
+ gbuf[i] = 0x00; i++;
+ gbuf[i] = 0x01; i++;
+
+ // this is the number of used bytes:
+ gbuf_s = i;
+
+ //////// TEST
+ /*
+ for (j=0; j<i; j++)
+ {
+ printf("%02x \n",gbuf[j]);
+ }
+ printf("i=%u\n",i);
+ */
+
+ return 1;
+}
+
+
+
+
+
+
+//
+// Given a label (e. g. www.google.com) creates correct bytes in *buf
+// and returns number of bytes created.
+// NOTE: Label MUST NOT be longer than 512 characters.
+//
+int dns_process_label(char* label, u_int8_t *buf)
+{
+ char *saveptr=NULL, *token;
+ int i=0, j=0, cnt=0, avoid_buffer_overflow=0;
+
+ token = strtok_r(label, ".", &saveptr);
+
+ do // loop through all labels
+ {
+ cnt = strlen(token);
+ i++;
+ *buf = cnt;
+ buf++;
+ avoid_buffer_overflow++;
+ for (j=0; j<cnt ;j++)
+ {
+ *buf = *token;
+ buf++;
+ avoid_buffer_overflow++;
+ if (avoid_buffer_overflow == 512) return 512;
+ token++;
+ }
+ i+=cnt;
+
+ } while ( (token = strtok_r(NULL, ".", &saveptr)) != NULL);
+ *buf=0x00;
+ i++; // number of total bytes written
+ return i;
+}
+
+
+
+
+
+// Accepts a valid triple of type:ttl:rdata and writes anything in gbuf[] and gbuf_s.
+//
+// Syntax examples:
+//
+// CNAME:3600:abc.com => Depending on type the rdata must be handled differently
+// A:86400:192.168.1.33 => Up to 3 parameters
+// A:192.168.1.33 => TTL may be omitted, then TTL=0
+// 192.168.1.44 => Single parameter can only be an A record
+//
+// Other TYPES than A and CNAME are currently not supported and therefore the user must
+// specify RDATA in hex.
+//
+
+int dns_get_answer(char* argval)
+{
+ char *field, *saveptr1=NULL;
+ char field1[512], field2[512], field3[512];
+ int i, len, num_params;
+ u_int16_t TYPE=1; // A
+ u_int8_t *ptrTYPE;
+ u_int32_t TTL=0;
+ u_int8_t *ptrTTL;
+ u_int16_t RDLEN;
+ u_int8_t *ptrRDLEN;
+ u_int8_t rdata[512];
+
+ field1[0]='\0';
+ field2[0]='\0';
+ field3[0]='\0';
+
+ len = strlen (argval);
+
+ // determine number of occurences of ':'
+ num_params=1;
+ for (i=0; i<len; i++)
+ {
+ if (argval[i]==':') num_params++;
+ }
+ if (num_params>3) return 0; // Error!
+
+ // now get the fields (type, ttl, rdata)
+ field = strtok_r(argval, ":", &saveptr1);
+ strncpy(field1, field, 512);
+ if (num_params>1) // 2 or 3
+ {
+ field = strtok_r(NULL, ":", &saveptr1);
+ strncpy(field2, field, 512);
+ if (num_params==3)
+ {
+ field = strtok_r(NULL, ":", &saveptr1);
+ strncpy(field3, field, 512);
+ }
+ }
+
+
+ // Now we have all parameters in field1, field2, and field3.
+ // But field2 and/or field3 might be empty.
+
+ switch (num_params)
+ {
+ case 1: // only RDATA specified
+ strncpy(field3, field1, 512);
+ strcpy(field1, "A");
+ strcpy(field2, "0");
+ break;
+ case 2: // TYPE and RDATA
+ strncpy(field3, field2, 512);
+ strcpy(field2, "0");
+ break;
+ }
+
+ //CHECK:
+ //printf("fields: [%s] [%s] [%s]\n",field1,field2,field3);
+
+ //////////////////////////////////////////////////////////////////////
+ // Now create the whole answer section: Type, Class, TTL, RDLEN, RDATA
+
+ //// TYPE
+ if ( (strcmp(field1,"CNAME")==0) ||
+ (strcmp(field1,"cname")==0) )
+ {
+ TYPE=5;
+ gbuf[0]=0x00;
+ gbuf[1]=0x05;
+ }
+ else if ( (strcmp(field1,"A")==0) ||
+ (strcmp(field1,"a")==0) )
+ {
+ TYPE=1;
+ gbuf[0]=0x00;
+ gbuf[1]=0x01;
+ }
+ else // type must be given as number
+ {
+ TYPE = (u_int16_t) str2int(field1);
+ ptrTYPE = (u_int8_t*) &TYPE;
+ gbuf[0]=*(ptrTYPE+1);
+ gbuf[1]=*(ptrTYPE);
+ }
+
+
+ //// CLASS = IN = 0x00 01
+ gbuf[2]= 0x00; gbuf[3]=0x01;
+
+ //// TTL
+ TTL = (u_int32_t) str2int(field2);
+ ptrTTL = (u_int8_t*) &TTL;
+ gbuf[4]= *(ptrTTL+3);
+ gbuf[5]= *(ptrTTL+2);
+ gbuf[6]= *(ptrTTL+1);
+ gbuf[7]= *(ptrTTL+0);
+
+
+ //// RDLEN and RDATA
+ if (TYPE==1) // A
+ {
+ RDLEN = num2hex(field3, rdata); // should be 4 if IP address
+ if (RDLEN!=4)
+ {
+ fprintf(stderr," mz/dns_get_answer: [WARNING] RDATA of A record should contain an IPv4 address (4 bytes).\n");
+ }
+ }
+ else if (TYPE==5) // CNAME
+ {
+ RDLEN = dns_process_label (field3, rdata);
+ if (RDLEN==0)
+ {
+ fprintf(stderr," mz/dns_get_answer: [WARNING] RDATA must contain a domain name.\n");
+ }
+ }
+ else // Any other type
+ {
+ RDLEN = str2hex(field3, rdata, 512); // should be 4 if IP address
+ }
+
+ ptrRDLEN = (u_int8_t*) &RDLEN;
+ gbuf[8] = *(ptrRDLEN+1);
+ gbuf[9] = *(ptrRDLEN+0);
+
+
+ // finally write rdata
+ for (i=0; i<RDLEN; i++)
+ {
+ gbuf[10+i] = rdata[i];
+ }
+ gbuf_s = 10+RDLEN;
+
+ //////// TEST
+ /*
+ for (i=0; i<gbuf_s; i++)
+ {
+ printf("%02x \n",gbuf[i]);
+ }
+ printf("i=%u\n",i);
+ */
+
+ return 1;
+
+}
diff --git a/staging/hextools.c b/staging/hextools.c
new file mode 100644
index 0000000..0328600
--- /dev/null
+++ b/staging/hextools.c
@@ -0,0 +1,322 @@
+/*
+ * Mausezahn - A fast versatile traffic generator
+ * Copyright (C) 2008 Herbert Haas
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
+ *
+*/
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+//
+// Contains various tools for hex-based conversions and manipulation of bytestrings
+//
+// str2hex_mac ..... converts "00:01:02:0a:ff:ff" into u_int8_t dst[6]
+// str2hex ..... converts "1a 00:00-2f" into u_int8_t dst[n] (any length)
+// num2hex ..... converts "192.16.1.1" into u_int8_t dst[4]
+// bs2str ..... converts {0,1,10} into "00-01-0A"
+// getbytes ..... a stupid implementation of memcpy - prefer memcpy instead !!!
+// str2ip32 ..... converts "192.168.0.1" into 3232235521 (u_int32_t)
+// str2ip32_rev ..... same but assumes network byte order
+// type2str ..... converts a u_int16_t into a string, e. g. 0x800 into "08:00"
+//
+////////////////////////////////////////////////////////////////////////////////////////////
+
+
+#include "mz.h"
+
+
+
+// converts MAC address specified in str into u_int8_t array
+// Usage: str2hex_mac ( "00:01:02:aa:ff:ee", src_addr )
+// Returns 1 if specified MAC address string is invalid, 0 upon success.
+int str2hex_mac(char* str, u_int8_t *addr)
+{
+ char *hs;
+ int i;
+ unsigned int test;
+ char tmp[32];
+
+ strcpy(tmp,str); // necessary because strtok cannot operate on fixed strings
+
+ hs=(char*)strtok(tmp,"-:., ");
+
+ for (i=0; i<6; i++)
+ {
+ test = (unsigned int) strtol (hs, NULL, 16);
+ if (test>0xff) return 1;
+ addr[i]=(u_int8_t) strtol (hs, NULL, 16);
+ hs = strtok(NULL,"-:., ");
+ if ( (hs == NULL ) && (i!=5) )
+ {
+ // Not a valid MAC address
+ return 1;
+ }
+ }
+
+ if (hs!=NULL) return 1; // more than 6 bytes
+
+ return 0;
+}
+
+
+
+
+// Converts ascii hex values (string) into integer array
+// For example "1a 00:00-2f" will be converted to {26, 0, 0, 47}
+//
+// NOTE: n ist the max number of bytes to be converted
+//
+// RETURN VALUE: number of bytes converted
+// or -1 upon failure
+//
+int str2hex(char* str, u_int8_t *hp, int n)
+{
+ char *hs;
+ int curval,i;
+
+
+ if (strlen(str)==0) return 0;
+
+ char tmp[8192]=""; //for very long payloads
+
+ strncpy(tmp,str,8191); // necessary because strtok cannot operate on fixed strings
+
+ hs=(char*)strtok(tmp,"-:., ");
+
+ i=0;
+ do
+ { n--;
+ curval=strtol(hs,NULL,16);
+ if (curval>0xff) return -1;
+ hp[i]=(u_int8_t) curval;
+ i++;
+ }
+ while ((n) && ((hs=(char*)strtok(NULL,"-:., "))!= NULL));
+
+ return i; // return the length of the array
+}
+
+
+
+// Converts ascii numbers (terminated string) into integer array
+// Every byte can be specified as integers {0..255}
+// For example "192.16.1.1" will be converted to {C0, 10, 01, 01}
+//
+// NOTE: Returns the number of converted bytes!
+int num2hex(char* str, u_int8_t *hp)
+{
+ char *hs;
+ int i;
+ unsigned int curval;
+
+ if (strlen(str)==0) return 0;
+
+ char tmp[8192]=""; //for very long payloads
+
+ strncpy(tmp,str,8192); // necessary because strtok cannot operate on fixed strings
+
+ hs = (char*) strtok (tmp,"-:., ");
+
+ i=0;
+ do
+ {
+ curval = (unsigned int) str2int(hs);
+ if (curval<256)
+ {
+ hp[i] = (u_int8_t) curval;
+ i++;
+ }
+ }
+ while ((hs=(char*)strtok(NULL,"-:., "))!= NULL);
+ //hp[i]='\0'; // termination not necessary
+
+ return i;
+}
+
+
+
+// Convert array of integers into string of hex
+// E.g. {0,1,10} => "00-01-0A"
+// Useful for verification messages.
+int bs2str(u_int8_t *bs, char* str, int len)
+{
+ int i;
+ char t[4];
+
+ str[0]='\0';
+
+ for (i=0; i<len; i++)
+ {
+// if (bs[i]<16) strcat(str,"0"); // enforce two hex digits (e.g. "0a")
+
+ sprintf(t,"%02x:",bs[i]);
+ strcat(str,t);
+ }
+ str[strlen(str)-1]='\0'; //remove the last ":"
+ return 1;
+}
+
+
+// Extract contiguous sequence of bytes from an array
+// NOTE: first element has number 1 !!!
+// THIS IS DEPRECATED: PREFER memcpy INSTEAD !!!
+int getbytes(u_int8_t *source,
+ u_int8_t *target,
+ int from,
+ int to)
+
+{
+ int i;
+
+ // Check wrong arguments
+ if (from<1)
+ {
+ return -1;
+ }
+
+ // copy bytes
+ for (i=0; i<(to-from+1); i++)
+ {
+ target[i]=source[from-1+i];
+ }
+
+ return 1;
+}
+
+
+// Converts an IP address given in 'dotted decimal' into an unsigned 32-bit integer
+// Example: "192.168.0.1" => 3232235521
+u_int32_t str2ip32 (char* str)
+{
+ u_int32_t ip = 0;
+ unsigned int a,b,c,d;
+ int r;
+
+ // check whether str really contains an IP address
+ if (strlen(str)<3) return 0;
+ if (str==NULL) return 0;
+
+ if ((r=sscanf(str,"%i.%i.%i.%i",&a,&b,&c,&d))==0) return 0;
+ if (r==EOF) return 0;
+
+ /* or an alternative method...
+ // these are the four bytes of a dotted decimal notation IP address:
+ a = (unsigned int) strtol(strtok(str,"."), (char **)NULL, 10);
+ b = (unsigned int) strtol(strtok(NULL,"."), (char **)NULL, 10);
+ c = (unsigned int) strtol(strtok(NULL,"."), (char **)NULL, 10);
+ d = (unsigned int) strtol(strtok(NULL,"."), (char **)NULL, 10);
+ */
+
+ if ((a>255)||(b>255)||(c>255)||(d>255)) return 0;
+
+ ip = d + 256*c + 256*256*b + 256*256*256*a;
+
+ //check with:
+ //printf("str2ip32 got 4 bytes: %i %i %i %i\n",a,b,c,d);
+ //printf("str2ip32 returned %u\n",ip);
+
+ return ip;
+}
+
+
+// Converts an IP address given in 'dotted decimal' into an unsigned 32-bit integer
+// This version does the same as str2ip32() but in 'network byte order'
+u_int32_t str2ip32_rev (char* str)
+{
+ u_int32_t ip = 0;
+ unsigned int a,b,c,d;
+ int r;
+
+ // check whether str really contains an IP address
+ if (strlen(str)<3) return 0;
+ if (str==NULL) return 0;
+
+ if ((r=sscanf(str,"%i.%i.%i.%i",&a,&b,&c,&d))==0) return 0;
+ if (r==EOF) return 0;
+
+ /* or an alternative method...
+ // these are the four bytes of a dotted decimal notation IP address:
+ a = (unsigned int) strtol(strtok(str,"."), (char **)NULL, 10);
+ b = (unsigned int) strtol(strtok(NULL,"."), (char **)NULL, 10);
+ c = (unsigned int) strtol(strtok(NULL,"."), (char **)NULL, 10);
+ d = (unsigned int) strtol(strtok(NULL,"."), (char **)NULL, 10);
+ */
+
+ if ((a>255)||(b>255)||(c>255)||(d>255)) return 0;
+
+ ip = a + b*256 + c*256*256 + d*256*256*256;
+
+ //check with:
+ //printf("str2ip32 got 4 bytes: %i %i %i %i\n",a,b,c,d);
+ //printf("str2ip32 returned %u\n",ip);
+
+ return ip;
+}
+
+
+// Converts a 2-byte value (e. g. a EtherType field)
+// into a nice string using hex notation.
+// Useful for verification messages.
+// Example: type2str (tx.eth_type, msg) may result in msg="08:00"
+// Return value: how many hex digits have been found.
+int type2str(u_int16_t type, char *str)
+{
+ char hex[8];
+ int i=0;
+
+ (void) sprintf (hex, "%x",type);
+ i=strlen(hex);
+
+ switch (i)
+ {
+ case 1:
+ str[0]='0';
+ str[1]='0';
+ str[2]=':';
+ str[3]='0';
+ str[4]=hex[0];
+ str[5]='\0';
+ break;
+ case 2:
+ str[0]='0';
+ str[1]='0';
+ str[2]=':';
+ str[3]=hex[0];
+ str[4]=hex[1];
+ str[5]='\0';
+ break;
+ case 3:
+ str[0]='0';
+ str[1]=hex[0];
+ str[2]=':';
+ str[3]=hex[1];
+ str[4]=hex[2];
+ str[5]='\0';
+ break;
+ case 4:
+ str[0]=hex[0];
+ str[1]=hex[1];
+ str[2]=':';
+ str[3]=hex[2];
+ str[4]=hex[3];
+ str[5]='\0';
+ break;
+
+ }
+ return i;
+}
+
diff --git a/staging/layer1.c b/staging/layer1.c
new file mode 100644
index 0000000..f671bb5
--- /dev/null
+++ b/staging/layer1.c
@@ -0,0 +1,383 @@
+/*
+ * Mausezahn - A fast versatile traffic generator
+ * Copyright (C) 2008 Herbert Haas
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
+ *
+*/
+
+
+
+// ****************************************************************************
+//
+// This section contains functions to send an arbitrary byte stream out of
+// the network card. Currently it works perfect for Ethernet cards.
+//
+// TODO: Access to the 802.11 header
+//
+// ****************************************************************************
+
+#include "mz.h"
+#include "cli.h"
+
+int send_eth()
+{
+ // Tasks:
+ // 1. Check 'eth_src_txt' and 'eth_dst_txt' which contain either a MAC address or a keyword
+ // 'eth_dst' can be set without having 'eth_src_txt' specified (the next 6 bytes of the
+ // 'arg_string' will be used). But if 'eth_src_txt' is given then also 'eth_dst_txt'
+ // should have been specified, otherwise a default (ff-ff-ff-ff-ff-ff) will be used.
+ // 2. Check whether 'arg_string' contains a hex-string. If YES then convert it into an
+ // 'eth_payload' and extract eth_type.
+ // 3. Apply 'padding' if specified
+ // 4. Check if frame has at least minimum length (14 Bytes).
+ // 5. Send frame 'count' times and
+ // 6. Apply 'delay' (make precautions for better delay functions)
+
+ int
+ src, // flag telling whether user has specified a source address
+ dst, // flag telling whether user has specified a destination address
+ src_random=0,
+ dst_random=0,
+ byte_ptr=1,
+ bytestring_s=0,
+ min_size=15,
+ pad=0,
+ repeat, loop, update,
+ i=0,
+ j=0;
+ char
+ err_buf[LIBNET_ERRBUF_SIZE],
+ message[MAX_PAYLOAD_SIZE*3];
+
+ u_int8_t bytestring[MAX_PAYLOAD_SIZE];
+ libnet_ptag_t t;
+ libnet_t *l;
+
+
+
+ if (tx.dot1Q)
+ {
+ fprintf(stderr," Note: raw layer 2 mode does not support 802.1Q builder.\n"
+ " If you want to create VLAN tags then you must do it by hand.\n");
+ exit(1);
+ }
+
+ if (tx.mpls)
+ {
+ fprintf(stderr," Note: raw layer 2 mode does not support MPLS builder.\n"
+ " If you want to create MPLS labels then you must do it by hand.\n");
+ exit(1);
+ }
+
+
+
+
+ // So other functions can use this function for sending Ethernet frames
+ // These other functions must set dst, src, type and payload!
+ if (tx.eth_params_already_set) goto ALL_SPECIFIED;
+
+
+ if ((tx.padding) && (tx.padding<15)) // Note: ignored if padding==0
+ {
+ tx.padding=15;
+ if (mz_port) {
+ cli_print(gcli, "Note: Set padding to 15 bytes (total length)\n");
+ } else
+ fprintf(stderr, " mz/send_eth: [Note] adjusted minimum frame size to 15 bytes.\n");
+ }
+
+ // Create a temporal, local bytestring:
+ //
+ for (i=0; i<MAX_PAYLOAD_SIZE; i++) bytestring[i]=0x00;
+ bytestring_s = str2hex (tx.arg_string, bytestring, MAX_PAYLOAD_SIZE);
+
+ // Set the flags to shorten subsequent decisions:
+ src = strlen(tx.eth_src_txt);
+ dst = strlen(tx.eth_dst_txt);
+
+
+ // IN ANY CASE if src has been specified:
+ //
+ if (src)
+ {
+ // Evaluate Ethernet CLI options (-a and -b)
+ if (check_eth_mac_txt(ETH_SRC)) // if true then problem!
+ {
+ // use own (already set in init.c)
+ }
+ src_random = tx.eth_src_rand; // local vars are faster
+ }
+
+ // IN ANY CASE if dst has been specified:
+ //
+ if (dst)
+ {
+ // Evaluate Ethernet CLI options (-a and -b)
+ if (check_eth_mac_txt(ETH_DST)) // if true then problem!
+ {
+ str2hex("ff:ff:ff:ff:ff:ff",tx.eth_dst, 6); // the default
+ }
+ dst_random = tx.eth_dst_rand; // local vars are faster
+ }
+
+
+ // Catch errors with too short bytestrings:
+ //
+ if (src)
+ {
+ // bytestring only needs to contain eth_type
+ min_size-=12;
+ }
+ else if (dst)
+ {
+ // bytstring must contain src and type
+ min_size-=6;
+ }
+ if (bytestring_s < min_size)
+ {
+ j = min_size - bytestring_s; // this is what's missing
+ bytestring_s += j; // note that bytestring has been filled up with 0x00, so we can do that
+ }
+
+
+ // ADDENDUM: If src specified, dst missing:
+ //
+ if ( (!dst) && (src) )
+ {
+ str2hex_mac ("ff:ff:ff:ff:ff:ff", tx.eth_dst);
+ }
+
+
+
+ // ADDENDUM: If dst specified, src missing:
+ //
+ if ((dst) && (!src))
+ {
+ // Get eth_src from bytestring:
+ if (bytestring_s>=6) {
+ (void) getbytes (bytestring, tx.eth_src, byte_ptr, byte_ptr+5);
+ byte_ptr=7; // now points to eth_type within bytestring
+ }
+ }
+
+ // FINALLY: If both dst and src have NOT been specified:
+ //
+ if ((!dst) && (!src))
+ {
+ if (bytestring_s>=6) {
+ (void) getbytes (bytestring, tx.eth_dst, byte_ptr, byte_ptr+5);
+ byte_ptr=7;
+ }
+
+ if (bytestring_s>=12) {
+ (void) getbytes (bytestring, tx.eth_src, byte_ptr, byte_ptr+5);
+ byte_ptr=13; // points to eth_type
+ }
+ }
+
+ // Set eth_type:
+ //
+ if (bytestring_s>=2) {
+ tx.eth_type = 256 * bytestring[byte_ptr-1] + bytestring[byte_ptr]; // don't forget: byte_ptr counts from 1 not 0
+ byte_ptr+=2; // points to first payload byte (if available)
+ }
+
+
+ // Get remaining payload:
+ //
+ if ( (tx.eth_payload_s = bytestring_s - byte_ptr +1) > 0 ) // if there are any remaining bytes
+ {
+ (void) getbytes (bytestring, tx.eth_payload, byte_ptr, bytestring_s);
+ }
+
+
+
+ // Add padding if desired.
+ // Note: padding means 'extend to given length' (not 'add these number of bytes')
+ if (tx.padding)
+ {
+ pad = tx.padding - (14 + tx.eth_payload_s); // number of additonal pad bytes required
+ for (i=0; i<pad; i++)
+ {
+ // tx.eth_payload[i+tx.eth_payload_s] = (u_int8_t) ( ((float) rand()/RAND_MAX)*256);
+ tx.eth_payload[i+tx.eth_payload_s] = 0x00;
+ }
+ tx.eth_payload_s += pad;
+ }
+
+
+
+ ALL_SPECIFIED:
+ // *** All Ethernet parameters have been determined !
+ // *** Now let's send the frame!
+
+ l = libnet_init (LIBNET_LINK_ADV, tx.device, err_buf );
+
+ if (l == NULL)
+ {
+ fprintf(stderr, " mz/send_eth: libnet_init() failed (%s)", err_buf);
+ return -1;
+ }
+
+ repeat=1;
+
+ if (tx.count == 0)
+ {
+ loop = 1000000;
+ if (!quiet)
+ fprintf(stderr, " mz: !!! Infinite mode! Will send frames until you stop Mausezahn!!!\n");
+ }
+ else
+ loop = tx.count;
+
+ if ( (!quiet) && (!tx.delay) && (tx.count==0) )
+ fprintf(stderr, " mz: !!! Will send at maximum frame rate without feedback!!!\n");
+
+ t=0;
+ update=1;
+
+ // this is for the statistics:
+ mz_start = clock();
+ total_d = tx.count;
+
+ while (repeat)
+ {
+ if (tx.count!=0) repeat=0; // count=0 means repeat ad inifinitum
+
+ for (i=0; i<loop; i++)
+ {
+ if (src_random)
+ {
+ tx.eth_src[0] = (u_int8_t) ( ((float) rand()/RAND_MAX)*256) & 0xFE;
+ tx.eth_src[1] = (u_int8_t) ( ((float) rand()/RAND_MAX)*256);
+ tx.eth_src[2] = (u_int8_t) ( ((float) rand()/RAND_MAX)*256);
+ tx.eth_src[3] = (u_int8_t) ( ((float) rand()/RAND_MAX)*256);
+ tx.eth_src[4] = (u_int8_t) ( ((float) rand()/RAND_MAX)*256);
+ tx.eth_src[5] = (u_int8_t) ( ((float) rand()/RAND_MAX)*256);
+ update=1;
+ }
+
+ if (dst_random)
+ {
+ tx.eth_dst[0] = (u_int8_t) ( ((float) rand()/RAND_MAX)*256);
+ tx.eth_dst[1] = (u_int8_t) ( ((float) rand()/RAND_MAX)*256);
+ tx.eth_dst[2] = (u_int8_t) ( ((float) rand()/RAND_MAX)*256);
+ tx.eth_dst[3] = (u_int8_t) ( ((float) rand()/RAND_MAX)*256);
+ tx.eth_dst[4] = (u_int8_t) ( ((float) rand()/RAND_MAX)*256);
+ tx.eth_dst[5] = (u_int8_t) ( ((float) rand()/RAND_MAX)*256);
+ update=1;
+ }
+
+ if (update) // new frame parameters
+ {
+ t = libnet_build_ethernet (tx.eth_dst,
+ tx.eth_src,
+ tx.eth_type,
+ tx.eth_payload,
+ tx.eth_payload_s,
+ l,
+ t);
+
+ if (t == -1)
+ {
+ fprintf(stderr, " mz/send_eth: %s", libnet_geterror(l));
+ return -1;
+ }
+
+ if (verbose)
+ {
+ bs2str (tx.eth_dst, message, 6); // DA
+ fprintf(stderr, " mz: send %s",message);
+
+ bs2str (tx.eth_src, message, 6); // SA
+ fprintf(stderr, " %s",message);
+
+ type2str(tx.eth_type, message);
+ fprintf(stderr, " %s",message); // Type
+
+ bs2str (tx.eth_payload, message, tx.eth_payload_s); // Payload
+ fprintf(stderr, " %s\n",message);
+ }
+ update=0;
+ if (verbose==2)
+ {
+ fprintf(stderr, "\n");
+ fprintf(stderr, "*** NOTE: Simulation only! Nothing has been sent! ***\n");
+ libnet_destroy(l);
+ return 0;
+ }
+
+
+ }
+
+ libnet_write(l);
+
+ if (tx.delay)
+ {
+ SLEEP (tx.delay);
+ if ( (verbose) && (!src_random) && (!dst_random) )
+ {
+ fprintf(stderr, ".");
+ }
+ }
+
+ } // end for
+
+ } // end while
+
+ if (verbose)
+ {
+ if ((tx.delay) || (tx.count==0))
+ {
+ fprintf(stderr,"\n");
+ }
+
+ fprintf(stderr, " mz: sent %u frames.\n",loop);
+ }
+
+
+
+ libnet_destroy(l);
+
+
+ return 0;
+}
+
+
+
+// ==========================================================================================
+
+ /*
+ if (verbose)
+ {
+ fprintf(stderr," mz/send_bytes: \n");
+ bs2str(da,dast,6);
+ fprintf(stderr," DA = %s", dast);
+ bs2str(sa,sast,6);
+ fprintf(stderr," SA = %s", sast);
+ fprintf(stderr," type = %x",et);
+ bs2str(payload,pl,payload_s);
+ fprintf(stderr," data = %s\n",pl);
+ }
+ */
+
+
+
+
+
+
+
+
+
+
diff --git a/staging/layer2.c b/staging/layer2.c
new file mode 100644
index 0000000..ebbc7d8
--- /dev/null
+++ b/staging/layer2.c
@@ -0,0 +1,902 @@
+/*
+ * Mausezahn - A fast versatile traffic generator
+ * Copyright (C) 2008-2010 Herbert Haas
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
+ *
+*/
+
+
+
+// ***************************************************************************
+// This sections contains functions to send various L2-based PDUs such as
+// * ARP
+// * BPDU
+// ***************************************************************************
+
+#include "mz.h"
+#include "cli.h"
+
+
+
+#define MZ_ARP_HELP \
+ "| ARP type: Send arbitrary ARP packets.\n" \
+ "| Note:\n" \
+ "| - The Ethernet dst and src MAC addresses can be specified but can be also 'rand'.\n" \
+ "| - If dst and src are NOT specified then practical defaults are used (src=own MAC, dst=bc).\n" \
+ "|\n" \
+ "| ARGUMENT SYNTAX: <command> [<parameters>]\n" \
+ "| | |\n" \
+ "| help, request, reply --+ |\n" \
+ "| +-- sendermac, senderip, targetmac, targetip\n" \
+ "| smac sip tmac tip\n" \
+ "|\n" \
+ "| EXAMPLES:\n" \
+ "| 1. Legitimate ARP response to broadcast:\n" \
+ "| # mz eth0 -t arp \"reply\"\n" \
+ "| 2. ARP cache poisoning, claiming to be 192.168.0.1, telling a target PC:\n" \
+ "| # mz eth0 -t arp \"reply, senderip=192.168.0.1, targetmac=00:00:0c:01:02:03, targetip=172.16.1.50\"\n" \
+ "\n"
+
+
+#define MZ_BPDU_HELP \
+ "| BPDU type: Send arbitrary BPDU packets (spanning tree).\n" \
+ "|\n" \
+ "| ARGUMENT SYNTAX: <command> [<parameters>]\n" \
+ "| | \n" \
+ "| conf, tcn --+ \n" \
+ "| \n" \
+ "| Parameters:\n" \
+ "|\n" \
+ "| id = 0-65535 ..... default: 0, identifies 'Spanning Tree Protocol'\n" \
+ "| version = 0-255 ..... default: 0\n" \
+ "| type = 0-255 ..... BPDU Type: 0=CONF, 1=TCN (default: CONF)\n" \
+ "| flags = 0-255 ..... 1=TC, 128=ACK (default: 0 = No TC, No ACK)\n" \
+ "| rootid = <pri>:<mac> ..... 8 byte Root-ID (default: 00:00:<own-mac>)\n" \
+ "| rootpc = 0-4294967295 ..... root path cost (default: 0)\n" \
+ "| bid = <mac> ..... 6 byte MAC address (default: own-mac)\n" \
+ "| pid = 0-65535 ..... port identifier (default: 0)\n" \
+ "| age = 0-65535 ..... message age (default: 0)\n" \
+ "| maxage = 0-65535 ..... max age (default: 20)\n" \
+ "| hello = 0-65535 ..... hello time (default: 2)\n" \
+ "| fwd = 0-65535 ..... forward delay (default: 15)\n" \
+ "| tag - ..... Keyword to enforce 802.1Q VLAN tag; use this\n" \
+ "| together with the 'vlan' parameter below.\n" \
+ "|\n" \
+ "| PVST+ extensions:\n" \
+ "|\n" \
+ "| vlan ..... VLAN number (default: 0)\n" \
+ "| pri ..... 802.1P-Priority (0-7, default: 0)\n" \
+ "| notag ..... Omit 802.1Q VLAN tag\n" \
+ "| \n" \
+ "|\n" \
+ "| DEFAULTS: mz sends standard IEEE 802.1d (CST) BPDUs and assumes that your computer\n" \
+ "| wants to become the root bridge (rid=bid). Configuration BPDUs are the default but\n" \
+ "| can be changed using the 'tcn' keyword. Optionally the 802.3 source and destination\n" \
+ "| MAC addresses can be specified using the -a and -b options. Per default, the correct\n" \
+ "| STP or PVST+ destination addresses are used (same as '-b stp' or '-b pvst', \n" \
+ "| respectively).\n" \
+ "| \n" \
+ "| Note that the parameter 'vlan' only selects the PVST+ mode if the parameter 'tag' is\n" \
+ "| NOT used.\n" \
+ "\n"
+
+
+
+// Send arbitrary ARP packets.
+// Note:
+// - The Ethernet dst and src MAC addresses can be specified,
+// the eth_src_txt can be 'rand'
+// - If eth_dst and eth_src are NOT specified then practical defaults are used
+//
+// arg_string syntax: <command>, <param>, ... , <param>
+// - commands: 'request' OR 'reply'
+// - params: 'sendermac', 'senderip', 'targetmac', 'targetip'
+//
+// Example arg_string for ARP cache poisoning:
+// "reply, senderip=192.168.0.1, targetmac=00:00:0c:01:02:03, targetip=172.16.1.50"
+// where sendermac will be automatically replaced by own mac,
+// senderip is the spoofed IP,
+// targetmac and targetip identifies the receiver.
+//
+int send_arp ()
+{
+ libnet_t *l;
+ libnet_ptag_t t;
+
+ char
+ argval[64],
+ t1[64],
+ t2[64],
+ src,
+ dst,
+ errbuf[LIBNET_ERRBUF_SIZE];
+
+ int
+ i,
+ arpmode=0,
+ arpop=0,
+ loop,
+ tm=0;
+
+ u_int8_t
+ *packet,
+ sendermac[6],
+ targetmac[6];
+
+
+
+ u_int32_t
+ packet_s,
+ senderip=0,
+ targetip=0;
+
+
+ if (tx.dot1Q)
+ {
+ fprintf(stderr," Note: ARP mode does not support 802.1Q builder.\n");
+ exit(1);
+ }
+
+ if (tx.mpls)
+ {
+ fprintf(stderr," Note: ARP mode does not support MPLS builder.\n");
+ exit(1);
+ }
+
+ if (getarg(tx.arg_string,"help", NULL)==1)
+ {
+ if (mz_port)
+ {
+ cli_print(gcli, "%s", MZ_ARP_HELP);
+ return -1;
+ }
+ else
+ {
+ fprintf(stderr,"\n"
+ MAUSEZAHN_VERSION
+ "\n%s", MZ_ARP_HELP);
+ exit(0);
+ }
+ }
+
+
+ // Set the flags to shorten subsequent decisions:
+ src = strlen(tx.eth_src_txt);
+ dst = strlen(tx.eth_dst_txt);
+
+ l = libnet_init(LIBNET_LINK_ADV, tx.device, errbuf);
+
+ if (l == NULL)
+ {
+ fprintf(stderr, "%s", errbuf);
+ exit(EXIT_FAILURE);
+ }
+
+
+
+ if (getarg(tx.arg_string,"request", NULL)==1)
+ {
+ arpmode=1;
+ arpop = ARPOP_REQUEST;
+ }
+ else
+ if (getarg(tx.arg_string, "reply", NULL)==1)
+ {
+ arpmode=2;
+ arpop = ARPOP_REPLY;
+ }
+ else
+ { // Default:
+ arpmode=2;
+ arpop = ARPOP_REPLY;
+ }
+
+
+
+ if ( (getarg(tx.arg_string,"sendermac", argval)==1) || (getarg(tx.arg_string,"smac", argval)==1) )
+ {
+ //TODO: Allow 'rand' as sendermac
+ str2hex(argval,sendermac,6);
+ }
+ else
+ {
+ // sendermac is usually ALWAYS own MAC:
+ getbytes(tx.eth_src, sendermac,1,6);
+ }
+
+
+ if ( (getarg(tx.arg_string,"targetmac", argval)==1) || (getarg(tx.arg_string,"tmac", argval)==1) )
+ {
+ str2hex(argval,targetmac,6);
+ tm=1;
+ }
+ else
+ {
+ // targetmac is either zero (request) or bcast (reply=>gratitious ARP)
+ if (arpmode==1) //request
+ str2hex("00:00:00:00:00:00",targetmac, 6);
+ else //reply
+ str2hex("ff:ff:ff:ff:ff:ff",targetmac, 6);
+ }
+
+
+ if ( (getarg(tx.arg_string,"senderip", argval)==1) || (getarg(tx.arg_string,"sip", argval)==1) )
+ {
+ senderip = str2ip32_rev(argval);
+ }
+ else
+ {
+ // senderip is usually ALWAYS the own IP
+ senderip = libnet_get_ipaddr4(l); // TODO - use tx.ip_src
+ }
+
+
+
+ if ( (getarg(tx.arg_string,"targetip", argval)==1) || (getarg(tx.arg_string,"tip", argval)==1) )
+ {
+ targetip = str2ip32_rev(argval);
+ }
+ else
+ {
+ // if targetip is missing also use own IP because it may be used for duplicate IP detection
+ targetip = libnet_get_ipaddr4(l);
+ }
+
+
+
+ // NOTE: Now all ARP parameters are set (possibly defaults used!)
+
+ bs2str(sendermac,t1,6);
+ bs2str(targetmac,t2,6);
+ //Check:
+ //printf("-- sendermac=%s targetmac=%s senderip=%u targetip=%u\n",t1,t2,senderip,targetip);
+
+
+
+ // Build the ARP header
+
+ t = libnet_autobuild_arp(arpop, /* operation type */
+ sendermac, /* sender hardware addr */
+ (u_int8_t *)&senderip, /* sender protocol addr */
+ targetmac, /* target hardware addr */
+ (u_int8_t *)&targetip, /* target protocol addr */
+ l); /* libnet context */
+
+ if (t == -1)
+ {
+ fprintf(stderr, " mz/send_arp: Can't build ARP header: %s\n", libnet_geterror(l));
+ exit(EXIT_FAILURE);
+ }
+
+
+ // Finally build the Ethernet header
+
+ if ((!dst) && (!src)) // ... user does not care about addresses (both eth_dst and eth_src NOT specified)
+ {
+ if (arpmode==1)
+ str2hex("ff:ff:ff:ff:ff:ff", tx.eth_dst, 6);
+ else
+ getbytes(targetmac, tx.eth_dst, 1, 6); // either also bcast or specific MAC
+
+ t = libnet_autobuild_ethernet(tx.eth_dst, /* ethernet destination */
+ ETHERTYPE_ARP, /* protocol type */
+ l); /* libnet handle */
+
+ if (t == -1)
+ {
+ fprintf(stderr, " mz/send_arp: Can't build ethernet header: %s\n",
+ libnet_geterror(l));
+ exit(EXIT_FAILURE);
+ }
+ }
+ else // EITHER eth_dst OR eth_src OR BOTH specified:
+ {
+ if (!dst)
+ {
+ if (arpmode==1)
+ str2hex("ff:ff:ff:ff:ff:ff", tx.eth_dst, 6);
+ else
+ getbytes(targetmac, tx.eth_dst, 1, 6); // either also bcast when reply or specific MAC
+ }
+ else // eth_dst specified
+ {
+ if (check_eth_mac_txt(ETH_DST)) // if true then problem!
+ {
+ str2hex("ff:ff:ff:ff:ff:ff",tx.eth_dst, 6); // the default
+ }
+ }
+
+
+ if (!src)
+ {
+ // tx.eth_src contains own MAC by default!
+ }
+ else // use specified source MAC address
+ {
+ if (check_eth_mac_txt(ETH_SRC)) // if true then problem!
+ {
+ str2hex("ff:ff:ff:ff:ff:ff",tx.eth_src, 6); // the default
+ }
+ }
+
+ t = libnet_build_ethernet (tx.eth_dst, tx.eth_src, ETHERTYPE_ARP, NULL, 0, l, 0); // Note: payload=NULL, payload_s=0
+ }
+
+ if (libnet_adv_cull_packet(l, &packet, &packet_s) == -1)
+ {
+ fprintf(stderr, "%s", libnet_geterror(l));
+ }
+ else
+ {
+ libnet_adv_free_packet(l, packet);
+ }
+
+ // this is for the statistics:
+ mz_start = clock();
+ total_d = tx.count;
+
+
+ again:
+
+ if (tx.count==0)
+ loop=1000000;
+ else
+ loop=tx.count;
+
+ for (i=1; i<=loop; i++)
+ {
+
+ if (!simulate) libnet_write(l);
+
+ if (verbose)
+ {
+ fprintf(stderr," sent ARP: %s smac=%s sip=%s tmac=%s tip=%s\n",
+ (arpmode==1) ? "request" : "reply",
+ t1,
+ libnet_addr2name4(senderip,LIBNET_DONT_RESOLVE),
+ t2,
+ libnet_addr2name4(targetip,LIBNET_DONT_RESOLVE));
+ }
+
+
+ if (tx.delay) SLEEP (tx.delay);
+ }
+
+ if (tx.count==0)
+ {
+ goto again;
+ }
+
+
+ libnet_destroy(l);
+
+ return 0;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////
+// Send arbitrary BPDU frames.
+//
+// commands:
+// conf|tcn ...when specifying everything yourself
+//
+// params:
+// id, version, type, flags, rootid, rootpc, bid, pid, age, maxage, hello, fwd,
+// vlan
+//
+// defaults:
+// mz assumes you want to become root bridge! (rid=bid)
+//
+int send_bpdu ()
+{
+
+ // BPDU parameters:
+ u_int16_t
+ id=0;
+ u_int8_t
+ version=0,
+ bpdu_type=0, // 0=conf, 1=topology change (actually in big endian!)
+ flags=0, // 1=TC, 128=TCAck
+ root_id[8], // Root BID
+ bridge_id[8]; // Own BID
+ u_int32_t
+ root_pc=0; // Root Path Cost
+ u_int16_t
+ port_id=0, // Port Identifier
+ message_age=0, // All timers are multiples of 1/256 sec. Thus times range from 0 to 256 seconds.
+ max_age=20,
+ hello_time=2, //
+ f_delay=15;
+
+ // LLC Parameters:
+ u_int8_t
+ dsap=0x42,
+ ssap=0x42,
+ control=0x3;
+
+ // Optional payload (needed for PVST+)
+ u_int8_t
+ bpdu_payload[64],
+ snap_oui[3];
+ u_int32_t
+ bpdu_payload_s=0;
+ u_int16_t
+ vlan=0;
+ u_int8_t
+ priority=0x00,
+ *x;
+ int
+ tag=0;
+
+
+ // Standard libnet variables:
+ libnet_t *l;
+ libnet_ptag_t t;
+ char errbuf[LIBNET_ERRBUF_SIZE];
+
+ // Other variables:
+ unsigned int i, loop;
+ int bpdumode=0;
+ char argval[64];
+ char dum1[32], dum2[32];
+
+
+ if (tx.dot1Q)
+ {
+ fprintf(stderr," Note: BPDU mode does not support 802.1Q builder.\n");
+ exit(1);
+ }
+
+ if (tx.mpls)
+ {
+ fprintf(stderr," Note: BPDU mode does not support MPLS builder.\n");
+ exit(1);
+ }
+
+
+ // HELP TEXT
+ if (getarg(tx.arg_string,"help", NULL)==1)
+ {
+ if (mz_port)
+ {
+ cli_print(gcli, "%s", MZ_BPDU_HELP);
+ return -1;
+ }
+ else
+ {
+ fprintf(stderr,"\n"
+ MAUSEZAHN_VERSION
+ "\n%s", MZ_BPDU_HELP);
+ exit(0);
+ }
+ }
+
+ /////////////////////////////////////////////////////////
+ // Default Destination Address
+ if (check_eth_mac_txt(ETH_DST)) // if true then problem!
+ {
+ str2hex("01:80:C2:00:00:00",tx.eth_dst, 6); // if '1' then user did not set MAC address (or problem occurred)
+ }
+
+ // Default Bridge-ID
+ bridge_id[0]=0x00;
+ bridge_id[1]=0x00;
+ for (i=0; i<6; i++) bridge_id[2+i]=tx.eth_src[i];
+ for (i=0; i<8; i++) root_id[i]=bridge_id[i];
+ /////////////////////////////////////////////////////////
+
+
+
+
+ // determine BPDU type:
+ if (getarg(tx.arg_string,"conf", NULL)==1)
+ {
+ bpdumode=1;
+ tx.eth_len = LIBNET_802_2_H + LIBNET_STP_CONF_H;
+ }
+ else
+ if (getarg(tx.arg_string, "tcn", NULL)==1)
+ {
+ bpdumode=2;
+ tx.eth_len = LIBNET_802_2_H + LIBNET_STP_TCN_H;
+ bpdu_type=0x80;
+ }
+ else // default
+ {
+ bpdumode=1;
+ tx.eth_len = LIBNET_802_2_H + LIBNET_STP_CONF_H;
+ }
+
+
+// Commands summary:
+// id, version, type, flags, rid, rootpc, bid, pid, age, maxage, hello, fwd
+
+ if (getarg(tx.arg_string,"id", argval)==1)
+ {
+ id = (u_int16_t) str2int(argval);
+ }
+
+ if (getarg(tx.arg_string,"version", argval)==1)
+ {
+ version = (u_int8_t) str2int(argval);
+ }
+
+ if (getarg(tx.arg_string,"bpdu_type", argval)==1)
+ {
+ bpdu_type = (u_int8_t) str2int(argval);
+ }
+
+ if (getarg(tx.arg_string,"flags", argval)==1)
+ {
+ flags = (u_int8_t) str2int(argval);
+ }
+
+ if (getarg(tx.arg_string,"rid", argval)==1)
+ {
+ if (str2hex(argval,root_id, 8)!=8)
+ {
+ fprintf(stderr," mz/send_bpdu: [ERROR] The root-id must be exactly 8 bytes!\n");
+ exit (-1);
+ }
+ }
+
+ if (getarg(tx.arg_string,"rootpc", argval)==1)
+ {
+ root_pc = (u_int32_t) str2int(argval);
+ }
+
+ if (getarg(tx.arg_string,"bid", argval)==1)
+ {
+ if (str2hex(argval,bridge_id, 6)!=6)
+ {
+ fprintf(stderr," mz/send_bpdu: [ERROR] The bridge-id must be exactly 6 bytes!\n");
+ exit (-1);
+ }
+ }
+
+ if (getarg(tx.arg_string,"pid", argval)==1)
+ {
+ port_id = (u_int16_t) str2int(argval);
+ }
+
+ if (getarg(tx.arg_string,"age", argval)==1)
+ {
+ message_age = (u_int16_t) str2int(argval);
+ }
+
+ if (getarg(tx.arg_string,"maxage", argval)==1)
+ {
+ max_age = (u_int16_t) str2int(argval);
+ }
+
+ if (getarg(tx.arg_string,"hello", argval)==1)
+ {
+ hello_time = (u_int16_t) str2int(argval);
+ }
+
+ if (getarg(tx.arg_string,"fwd", argval)==1)
+ {
+ f_delay = (u_int16_t) str2int(argval);
+ }
+
+
+
+ if (getarg(tx.arg_string,"vlan", argval)==1)
+ {
+ // PVST+ uses TLVs of type=0x00, len=0x02, and Value=0xVV which is the VLAN ID
+ // The DA must be 0100.0ccc.cccd instead of the standard 0180.c200.0000
+ //
+ if (check_eth_mac_txt(ETH_DST)) // if '1' then user did not set MAC address (or problem occurred)
+ {
+ str2hex("01:00:0C:CC:CC:CD",tx.eth_dst, 6); // Cisco PVST+ address
+ }
+
+/* // OLD TLV, maybe wrong, maybe obsolete, I don't know.
+
+ bpdu_payload[0] = 0x34;
+ bpdu_payload[1] = 0x00;
+ bpdu_payload[2] = 0x02;
+ vlan = (u_int16_t) str2int(argval);
+
+ x = (u_int8_t*) &vlan;
+ bpdu_payload[3] = *(x+1);
+ bpdu_payload[4] = *(x);
+ bpdu_payload[5] = 0x00;
+ bpdu_payload[6] = 0x00;
+ bpdu_payload_s = 7;
+*/
+ // Updated PVST+ TLV:
+ bpdu_payload[0] = 0x00;
+ bpdu_payload[1] = 0x00;
+ bpdu_payload[2] = 0x00;
+ bpdu_payload[3] = 0x00;
+ bpdu_payload[4] = 0x02;
+ vlan = (u_int16_t) str2int(argval);
+ x = (u_int8_t*) &vlan;
+ bpdu_payload[5] = *(x+1);
+ bpdu_payload[6] = *(x);
+ bpdu_payload_s = 7;
+
+ tag=1; // set the default: Use 802.1Q tag !!!
+ }
+ else // even a normal BPDU must be padded to 60 bytes (total)
+ {
+ bpdu_payload[0] = 0x00;
+ bpdu_payload[1] = 0x00;
+ bpdu_payload[2] = 0x00;
+ bpdu_payload[3] = 0x00;
+ bpdu_payload[4] = 0x00;
+ bpdu_payload[5] = 0x00;
+ bpdu_payload[6] = 0x00;
+ bpdu_payload[7] = 0x00;
+ bpdu_payload_s = 8;
+
+ tag=0; // set the default: send untagged !!!
+ }
+
+
+ // Note: The order is important because above the defaults for 'tag' has been set.
+ //
+ if (getarg(tx.arg_string,"notag", NULL)==1)
+ {
+ tag=0;
+ }
+
+
+ // Send normal BPDU with VLAN tag
+ if (getarg(tx.arg_string,"tag", NULL)==1)
+ {
+ tag=2;
+ bpdu_payload[0] = 0x00;
+ bpdu_payload[1] = 0x00;
+ bpdu_payload[2] = 0x00;
+ bpdu_payload[3] = 0x00;
+ bpdu_payload[4] = 0x00;
+ bpdu_payload[5] = 0x00;
+ bpdu_payload[6] = 0x00;
+ bpdu_payload[7] = 0x00;
+ bpdu_payload_s = 8;
+
+ // Rewrite to standard 0180.c200.0000
+ //
+ if (check_eth_mac_txt(ETH_DST)) // if '1' then user did not set MAC address (or problem occurred)
+ {
+ str2hex("01:80:C2:00:00:00",tx.eth_dst, 6);
+ }
+ vlan = (u_int16_t) str2int(argval);
+ }
+
+
+ if (getarg(tx.arg_string,"pri", argval)==1)
+ {
+ priority = (u_int8_t) str2int(argval);
+ if (priority>7)
+ {
+ fprintf(stderr, " mz/send_bpdu: Priority must be between 0 and 7.\n");
+ exit(1);
+ }
+
+ if (tag==0)
+ {
+ fprintf(stderr, " mz/send_bpdu: Priority cannot be used together with the 'notag' keyword.\n");
+ exit(1);
+ }
+ }
+
+
+ // Open the link - get libnet handle
+ l = libnet_init(LIBNET_LINK_ADV, tx.device, errbuf);
+
+ if (l == NULL)
+ {
+ fprintf(stderr, "%s", errbuf);
+ exit(EXIT_FAILURE);
+ }
+
+
+ if (bpdumode==1) // Prepare CONFIGURATION BPDU:
+ {
+
+ t = libnet_build_stp_conf (id,
+ version,
+ bpdu_type,
+ flags,
+ root_id,
+ root_pc,
+ bridge_id,
+ port_id,
+ message_age,
+ max_age,
+ hello_time,
+ f_delay,
+ (bpdu_payload_s) ? bpdu_payload : NULL,
+ bpdu_payload_s,
+ l,
+ 0);
+
+ if (t == -1)
+ {
+ fprintf(stderr, " mz/send_bpdu: Can't build BPDU header: %s\n",
+ libnet_geterror(l));
+ exit(EXIT_FAILURE);
+ }
+ }
+ else // Topology Change BPDU
+ {
+ t = libnet_build_stp_tcn(id,
+ version,
+ bpdu_type,
+ (bpdu_payload_s) ? bpdu_payload : NULL,
+ bpdu_payload_s,
+ l,
+ 0);
+ if (t == -1)
+ {
+
+ fprintf(stderr, " mz/send_bpdu: Can't build BPDU header: %s\n",
+ libnet_geterror(l));
+ exit(EXIT_FAILURE);
+ }
+ }
+
+
+
+ if ( (vlan==0) || (tag==2) ) // normal BPDU
+ {
+ // normal LLC without SNAP
+ t = libnet_build_802_2 (dsap,
+ ssap,
+ control,
+ NULL,
+ 0,
+ l,
+ 0);
+
+ if (t == -1)
+ {
+ fprintf(stderr, " mz/send_bpdu: Can't build LLC header: %s\n",
+ libnet_geterror(l));
+ exit(EXIT_FAILURE);
+ }
+ }
+ else // PVST+ => LLC with SNAP
+ {
+ snap_oui[0]=0x00;
+ snap_oui[1]=0x00;
+ snap_oui[2]=0x0c;
+
+ // requires a SNAP header with oui=0x00000c and type=0x010b
+ t = libnet_build_802_2snap(0xAA,
+ 0xAA,
+ 0x03,
+ snap_oui,
+ 0x010b,
+ NULL,
+ 0,
+ l,
+ 0);
+
+ if (t == -1)
+ {
+ fprintf(stderr, " mz/send_bpdu: Can't build SNAP header: %s\n",
+ libnet_geterror(l));
+ exit(EXIT_FAILURE);
+ }
+ }
+
+
+ if (tag==0)
+ {
+ // Normal 802.3 header without VLAN tag
+ t = libnet_build_802_3 (tx.eth_dst,
+ tx.eth_src,
+ (vlan) ? 0x36 : tx.eth_len, // NOTE the LENGTH field => 802.3 header!
+ NULL,
+ 0,
+ l,
+ 0);
+
+ }
+ else // PVST+ => 802.3 with 802.1Q
+ {
+ t = libnet_build_802_1q(tx.eth_dst,
+ tx.eth_src,
+ 0x8100,
+ priority,
+ 0x00, // CFI
+ vlan,
+ 0x32, //tx.eth_len,
+ NULL,
+ 0,
+ l,
+ 0);
+ }
+
+
+ if (t == -1)
+ {
+ fprintf(stderr, " mz/send_bpdu: Can't build 802.3 header: %s\n",
+ libnet_geterror(l));
+ exit(EXIT_FAILURE);
+ }
+
+
+ // This is ugly but it works good ;-)
+ if (tx.count==0)
+ loop=1000000;
+ else
+ loop=tx.count;
+
+ // this is for the statistics:
+ mz_start = clock();
+ total_d = tx.count;
+
+
+ again:
+
+ for (i=1; i<=loop; i++)
+ {
+ if (!simulate) libnet_write(l);
+
+ if (verbose)
+ {
+ bs2str(root_id,dum1,8);
+ bs2str(bridge_id,dum2,8);
+ fprintf(stderr," sent BPDU: ");
+ fprintf(stderr,"%s ", (bpdumode==1) ? "conf" : "tcn ");
+ fprintf(stderr," id=%u ver=%u flags=%x rid=%s bid=%s\n"
+ " rpc=%u pid=%u age=%u maxage=%u hello=%u fwd_delay=%u\n",
+ id,
+ version,
+ flags,
+ dum1,
+ dum2,
+ root_pc,
+ port_id,
+ message_age,
+ max_age,
+ hello_time,
+ f_delay);
+
+ fprintf(stderr,"\n");
+ }
+
+
+ if (tx.delay) SLEEP (tx.delay);
+ }
+
+ if (tx.count==0)
+ {
+ goto again;
+ }
+
+
+ libnet_destroy(l);
+
+ return 0;
+}
+
diff --git a/staging/layer3.c b/staging/layer3.c
new file mode 100644
index 0000000..d05aa3c
--- /dev/null
+++ b/staging/layer3.c
@@ -0,0 +1,734 @@
+/*
+ * Mausezahn - A fast versatile traffic generator
+ * Copyright (C) 2008-2010 Herbert Haas
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
+ *
+*/
+
+
+
+// ***************************************************************************
+// This sections contains functions to send various L3-based PDUs such as
+//
+// * IP
+//
+// (ahem, yes this is currently all here...)
+//
+// ***************************************************************************
+
+#include "mz.h"
+#include "cli.h"
+
+#define MZ_IP_HELP \
+ "| IP type: Send raw IP packets.\n" \
+ "|\n" \
+ "| Supports L3 mode (automatic L2 creation) or 'L2-L3' mode (MAC addresses must be provided).\n" \
+ "| In L3 mode the IP checksum and length cannot be manipulated to wrong values (currently).\n" \
+ "| The L2-L3 mode is activated when specifying any MAC addresses on the command line\n" \
+ "| (options -a, -b). \n" \
+ "|\n" \
+ "| The IP addresses can be specified via the -A and -B options, which identify the source\n" \
+ "| and destination addresses, respectively. A dotted decimal notation, an IP range, or a\n" \
+ "| FQDN can be used. The source address can also be random (-A rand).\n" \
+ "|\n" \
+ "| ARGUMENT SYNTAX: [<comma separated parameter list>]\n" \
+ "|\n" \
+ "| Parameters:\n" \
+ "|\n" \
+ "| len 0-65535 Only accessible in L2 mode\n" \
+ "| sum 0-65535 Only accessible in L2 mode (0 means auto-calculation)\n" \
+ "| tos 00-ff Full 8-bit control via hex input (use this also for ECN bits).\n" \
+ "| dscp 0-63 Allows easier specification of DSCP (PHB and Drop Propability)\n" \
+ "| ttl 0-255\n" \
+ "| proto 0-255\n" \
+ "| frag 0-65535 Includes flags (MSB) and offset (LSB)\n" \
+ "| df Sets the \"Don't Fragment\" flag\n" \
+ "| mf Sets the \"More Fragments\" flag\n" \
+ "| rf Sets the reserved flag.\n" \
+ "| id 0-65535\n" \
+ "| loose <addresses> Loose Source Route (LSR) option; specify a sequence of hops\n" \
+ "| using the notation: 1.1.1.1+2.2.2.2+3.3.3.3+...\n" \
+ "| strict <addresses> Strict Source Route (SSR) option; same address notation as above\n" \
+ "| option <hex_string> Specify any IP option using a hexadecimal string (aa:bb:cc:...)\n" \
+ "|\n" \
+ "| Additionally the Ethertype can be specified:\n" \
+ "|\n" \
+ "| ether_type 00:00-ff:ff Only accessible in L2 mode (default = 08:00 = IPv4)\n" \
+ "| \n"
+
+
+#define MZ_IP6_HELP \
+ "| IP type: Send raw IPv6 packets.\n" \
+ "|\n" \
+ "| Supports L3 mode (automatic L2 creation) or 'L2-L3' mode (MAC addresses must be provided).\n" \
+ "| In L3 mode the IP checksum and length cannot be manipulated to wrong values (currently).\n" \
+ "| The L2-L3 mode is activated when specifying any MAC addresses on the command line\n" \
+ "| (options -a, -b). \n" \
+ "|\n" \
+ "| ARGUMENT SYNTAX: [<comma separated parameter list>]\n" \
+ "|\n" \
+ "| Parameters:\n" \
+ "|\n" \
+ "| len 0-65535 Only accessible in L2 mode\n" \
+ "| sum 0-65535 Only accessible in L2 mode (0 means auto-calculation)\n" \
+ "| tos 00-ff Full 8-bit control via hex input (use this also for ECN bits).\n" \
+ "| dscp 0-63 Allows easier specification of DSCP (PHB and Drop Propability)\n" \
+ "| flow 0-1048575 Flow label\n" \
+ "| hop 0-255 Hop limit\n" \
+ "| next 0-255 Next protocol or header type\n" \
+ "| frag 0-65535 Includes flags (MSB) and offset (LSB)\n" \
+ "| mf Sets the \"More Fragments\" flag\n" \
+ "| frag_res1 Sets the reserved flag 1.\n" \
+ "| frag_res2 Sets the reserved flag 2.\n" \
+ "| id 0-65535 Fragment ID\n" \
+ "| loose <addresses> Source Routing Header\n" \
+ "| rtype 0,2 Source Routing Type: 0 (Deprecated in RFC 5095) or 2 for Mobile IP\n" \
+ "| segments 0-255 Number of route segments left, used by RH0\n" \
+ "|\n" \
+ "| Additionally the Ethertype can be specified:\n" \
+ "|\n" \
+ "| ether_type 00:00-ff:ff Only accessible in L2 mode (default = 86:dd = IPv6)\n" \
+ "| \n"
+
+
+// Only used to simplify initialization of libnet
+// Return pointer to context
+libnet_t* get_link_context()
+{
+ libnet_t * l;
+ char errbuf[LIBNET_ERRBUF_SIZE];
+
+ // Don't open context if only a help text is requested
+ if (getarg(tx.arg_string,"help", NULL)==1)
+ {
+ return NULL;
+ }
+
+
+ if (tx.packet_mode)
+ { // Let libnet create an appropriate Ethernet frame
+ if (ipv6_mode)
+ l = libnet_init (LIBNET_RAW6_ADV, tx.device, errbuf);
+ else
+ l = libnet_init (LIBNET_RAW4_ADV, tx.device, errbuf);
+ }
+ else // User specified Ethernet header details (src or dst)
+ {
+ l = libnet_init (LIBNET_LINK_ADV, tx.device, errbuf);
+ }
+
+ if (l == NULL)
+ {
+ fprintf(stderr, "%s", errbuf);
+ exit(EXIT_FAILURE);
+ }
+ return l;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+// Prepare IP packet
+libnet_ptag_t create_ip_packet (libnet_t *l)
+{
+ libnet_ptag_t t;
+ char argval[MAX_PAYLOAD_SIZE];
+ int i, T; // only an abbreviation for tx.packet_mode
+
+ if (ipv6_mode)
+ return create_ip6_packet(l);
+
+ // Default IP header fields
+ tx.ip_len = LIBNET_IPV4_H; // Don't forget to add payload length
+ tx.ip_id = 0;
+ tx.ip_frag = 0; // Flags and Offset !!!
+ tx.ip_sum = 0; // default: automatically calculate checksum
+ tx.ip_tos = 0;
+ tx.ip_ttl = 255;
+
+
+ // temporary variables
+ unsigned int dummy;
+ size_t len;
+ char *s;
+
+
+ T = tx.packet_mode; // >0 means automatic L2 creation
+
+ if ( (getarg(tx.arg_string,"help", NULL)==1) && (mode==IP) )
+ {
+ if (mz_port)
+ {
+ cli_print(gcli, "%s", MZ_IP_HELP);
+ return -1;
+ }
+ else
+ {
+
+ fprintf(stderr,"\n"
+ MAUSEZAHN_VERSION
+ "\n%s", MZ_IP_HELP);
+
+ exit(0);
+ }
+ }
+
+ // Check if hex_payload already specified (externally)
+ if (tx.hex_payload_s)
+ {
+ memcpy( (void*) tx.ip_payload, (void*) tx.hex_payload, tx.hex_payload_s);
+ tx.ip_payload_s = tx.hex_payload_s;
+ }
+
+
+ // Evaluate CLI parameters:
+
+ if ( (getarg(tx.arg_string,"payload", argval)==1) || (getarg(tx.arg_string,"p", argval)==1))
+ {
+ if (mode==IP)
+ tx.ip_payload_s = str2hex (argval, tx.ip_payload, MAX_PAYLOAD_SIZE);
+ }
+ // else payload has been specified as ASCII text via -P option
+
+
+ // NOTE: If 'mode' is NOT IP (e. g. UDP or TCP or something else)
+ // then the argument 'len' and 'sum' is NOT meant for the IP header!
+ // Instead the user can use 'iplen' and 'ipsum'.
+ if (mode==IP)
+ {
+ if (getarg(tx.arg_string,"len", argval)==1)
+ {
+ if (T) fprintf(stderr, " IP_Warning: 'len' cannot be set in this mode.\n");
+ tx.ip_len = (u_int16_t) str2int(argval);
+ }
+ else
+ {
+ tx.ip_len = LIBNET_IPV4_H + tx.ip_payload_s;
+ }
+
+ if (getarg(tx.arg_string,"sum", argval)==1)
+ {
+ if (T) fprintf(stderr, " IP_Warning: 'sum' cannot be set in this mode.\n");
+ tx.ip_sum = (u_int16_t) str2int(argval);
+ }
+ }
+ else // mode is NOT IP
+ {
+ if (getarg(tx.arg_string,"iplen", argval)==1)
+ {
+ if (T) fprintf(stderr, " IP_Warning: 'len' cannot be set in this mode.\n");
+ tx.ip_len = (u_int16_t) str2int(argval);
+ }
+ else
+ {
+ tx.ip_len = LIBNET_IPV4_H + tx.ip_payload_s;
+ }
+
+ if (getarg(tx.arg_string,"ipsum", argval)==1)
+ {
+ if (T) fprintf(stderr, " IP_Warning: 'sum' cannot be set in this mode.\n");
+ tx.ip_sum = (u_int16_t) str2int(argval);
+ }
+ }
+
+
+ if (getarg(tx.arg_string,"tos", argval)==1)
+ {
+ tx.ip_tos = (u_int8_t) strtol(argval,NULL,16);
+ dummy = (unsigned int) strtol(argval,NULL,16);
+ if (dummy > 255) fprintf(stderr, " IP_Warning: 'tos' too big, adjusted to LSBs\n");
+ }
+
+ if (getarg(tx.arg_string,"dscp", argval)==1)
+ {
+ dummy = (unsigned int) str2int(argval);
+ if (dummy > 63)
+ {
+ fprintf(stderr, " IP_Warning: 'dscp' too big, adjusted to 63\n");
+ dummy = 63;
+ }
+ tx.ip_tos = (u_int8_t) dummy*4;
+ }
+
+ if (getarg(tx.arg_string,"id", argval)==1)
+ {
+ tx.ip_id = (u_int16_t) str2int(argval);
+ }
+
+ if (getarg(tx.arg_string,"frag", argval)==1)
+ {
+ tx.ip_frag = (u_int16_t) str2int(argval);
+ }
+
+ if (getarg(tx.arg_string,"df", NULL)==1)
+ {
+ tx.ip_frag |= 0x4000;
+ }
+
+ if (getarg(tx.arg_string,"mf", NULL)==1)
+ {
+ tx.ip_frag |= 0x2000;
+ }
+
+ if (getarg(tx.arg_string,"rf", NULL)==1)
+ {
+ tx.ip_frag |= 0x8000;
+ }
+
+
+ if (getarg(tx.arg_string,"ttl", argval)==1)
+ {
+ tx.ip_ttl = (u_int8_t) str2int(argval);
+ }
+
+ if (getarg(tx.arg_string,"proto", argval)==1)
+ {
+ tx.ip_proto = (u_int8_t) str2int(argval);
+ }
+
+
+ if ((tx.ascii)&&(mode==IP)) // ASCII PAYLOAD overrides hex payload
+ {
+ strncpy((char *)tx.ip_payload, (char *)tx.ascii_payload, MAX_PAYLOAD_SIZE);
+ tx.ip_payload_s = strlen((char *)tx.ascii_payload);
+ tx.ip_len += tx.ip_payload_s;
+ }
+
+
+ /////////
+ // Want some padding? The specified number of padding bytes are ADDED to the
+ // payload. Note that this is only evaluated if we are in IP mode because
+ // UDP and TCP already might have been padded and set the ip_payload_s.
+ // (Note the difference in send_eth() where you specified the total number
+ // of bytes in the frame)
+ //
+ if ((tx.padding)&&(mode==IP))
+ {
+ for (i=0; i<tx.padding; i++)
+ {
+ tx.ip_payload[tx.ip_payload_s+i] = 0x42; // pad with THE ANSWER (why random?)
+ }
+ tx.ip_payload_s += tx.padding;
+ tx.ip_len += tx.padding;
+ }
+
+
+
+
+
+ // Loose and Strict Source Route
+ // See RFC 791 for most the detailed description
+ //
+ if ( (getarg(tx.arg_string,"loose", argval)==1) ||
+ (getarg(tx.arg_string,"strict", argval)==1) )
+ {
+ len = strlen(argval);
+
+ if (len<7) // not even a single dotted decimal IP address given!
+ {
+ fprintf(stderr, " IP_Warning: Source route option requires at least one IP address!\n");
+ // But we allow this :-)
+ }
+
+
+ // determine how many IP addresses have been specified
+ dummy=0;
+ for (i=0; i<len; i++)
+ {
+ if (ispunct(*(argval+i))) dummy++ ;
+ }
+ dummy = (dummy+1) / 4; // the number of IP addresses
+
+ // Specify: type code, length, pointer
+ if (getarg(tx.arg_string,"loose", argval)==1)
+ {
+ tx.ip_option[0] = 131; // loose source route
+ }
+ else
+ {
+ tx.ip_option[0] = 137; // strict source route
+ }
+ tx.ip_option[1] = 3+(dummy*4); // length
+ tx.ip_option[2] = 4; // Use first IP address as next hop
+ //tx.ip_option[2] = 4+4*dummy; // smallest pointer, points to first address, which is
+ // the 4th byte within this option
+
+ tx.ip_option_s = 3;
+ s = strtok(argval, ".+-:;/>");
+ do
+ {
+ len--;
+ tx.ip_option[tx.ip_option_s] = (u_int8_t) str2int(s);
+ tx.ip_option_s++;
+ } while ( (s=strtok(NULL, ".+-:;/>")) != NULL );
+
+ tx.ip_option_s++; // EOL
+
+ // add empty space for record route: //// NONSENSE? /////
+ /*
+ for (i=0; i<(4*dummy); i++)
+ {
+ tx.ip_option[tx.ip_option_s] = 0x00;
+ tx.ip_option_s++;
+ }
+ */
+ }
+
+
+
+ // Allow any IP option specified as hex string
+ // An option can be a single byte or consist of multiple bytes in which case
+ // a length field is needed, see RFC 791.
+ if (getarg(tx.arg_string,"option", argval)==1)
+ {
+ // check if conflicting with argument "loose" or "strict"
+ if (tx.ip_option_s)
+ {
+ fprintf(stderr, " IP_Error: Another IP option already specified. Please check your arguments.\n");
+ exit(1);
+ }
+
+ tx.ip_option_s = str2hex (argval, tx.ip_option, 1023);
+ }
+
+
+
+ if (tx.ip_option_s)
+ {
+ t = libnet_build_ipv4_options (tx.ip_option,
+ tx.ip_option_s,
+ l,
+ 0);
+ tx.ip_len += tx.ip_option_s;
+ }
+
+
+ ///////
+ // Did the user specify ANY payload? We require at least one byte!
+ /*
+ if (!tx.ip_payload_s)
+ {
+ tx.ip_payload[0] = 0x42;
+ tx.ip_payload_s = 1;
+ }
+ */
+
+ t = libnet_build_ipv4 (tx.ip_len,
+ tx.ip_tos,
+ tx.ip_id,
+ tx.ip_frag,
+ tx.ip_ttl,
+ tx.ip_proto,
+ tx.ip_sum,
+ tx.ip_src, // init.c defaults this to own SA
+ tx.ip_dst, // init.c defaults this to 255.255.255.255
+ (mode==IP) ? (tx.ip_payload_s) ? tx.ip_payload : NULL : NULL, // if e.g. mode=UDP ignore payload argument
+ (mode==IP) ? tx.ip_payload_s : 0,
+
+ /*
+ (mode==IP) ? tx.ip_payload : NULL, // if e.g. mode=UDP ignore payload argument
+ (mode==IP) ? tx.ip_payload_s : 0,
+ */
+ l,
+ 0);
+
+
+ if (t == -1)
+ {
+ fprintf(stderr, " mz/create_ip_packet: Can't build IP header: %s\n", libnet_geterror(l));
+ exit (0);
+ }
+
+
+ return t;
+
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Prepare IPv6 packet
+libnet_ptag_t create_ip6_packet (libnet_t *l)
+{
+ libnet_ptag_t t;
+ char argval[MAX_PAYLOAD_SIZE];
+ int i, T; // only an abbreviation for tx.packet_mode
+
+ // Default IP header fields
+ tx.ip_len = 0;
+ tx.ip_id = 0;
+ tx.ip6_segs = 0;
+ tx.ip6_rtype = 0;
+ tx.ip6_id = 0;
+ tx.ip_frag = 0; // Flags and Offset !!!
+ tx.ip_tos = 0;
+ tx.ip_ttl = 255;
+
+ // temporary variables
+ unsigned int dummy;
+ size_t len;
+ char *s;
+
+ T = tx.packet_mode; // >0 means automatic L2 creation
+
+ if ( (getarg(tx.arg_string,"help", NULL)==1) && (mode==IP) )
+ {
+ if (mz_port)
+ {
+ cli_print(gcli, "%s", MZ_IP6_HELP);
+ return -1;
+ }
+ else
+ {
+ fprintf(stderr,"\n"
+ MAUSEZAHN_VERSION
+ "\n%s", MZ_IP6_HELP);
+
+ exit(0);
+ }
+ }
+
+ // Check if hex_payload already specified (externally)
+ if (tx.hex_payload_s)
+ {
+ memcpy( (void*) tx.ip_payload, (void*) tx.hex_payload, tx.hex_payload_s);
+ tx.ip_payload_s = tx.hex_payload_s;
+ }
+
+ // Evaluate CLI parameters:
+ if ( (getarg(tx.arg_string,"payload", argval)==1) || (getarg(tx.arg_string,"p", argval)==1))
+ {
+ if (mode==IP)
+ tx.ip_payload_s = str2hex (argval, tx.ip_payload, MAX_PAYLOAD_SIZE);
+ }
+ // else payload has been specified as ASCII text via -P option
+
+ // NOTE: If 'mode' is NOT IP (e. g. UDP or TCP or something else)
+ // then the argument 'len' and 'sum' is NOT meant for the IP header!
+ // Instead the user can use 'iplen' and 'ipsum'.
+ if (mode==IP)
+ {
+ if (getarg(tx.arg_string,"len", argval)==1)
+ {
+ if (T) fprintf(stderr, " IP_Warning: 'len' cannot be set in this mode.\n");
+ tx.ip_len = (u_int16_t) str2int(argval);
+ }
+ else
+ {
+ tx.ip_len += tx.ip_payload_s;
+ }
+ }
+ else // mode is NOT IP
+ {
+ if (getarg(tx.arg_string,"iplen", argval)==1)
+ {
+ if (T) fprintf(stderr, " IP_Warning: 'len' cannot be set in this mode.\n");
+ tx.ip_len = (u_int16_t) str2int(argval);
+ }
+ else
+ {
+ tx.ip_len += tx.ip_payload_s;
+ }
+ }
+
+
+ if (getarg(tx.arg_string,"tos", argval)==1)
+ {
+ tx.ip_tos = (u_int8_t) strtol(argval,NULL,16);
+ dummy = (unsigned int) strtol(argval,NULL,16);
+ if (dummy > 255) fprintf(stderr, " IP_Warning: 'tos' too big, adjusted to LSBs\n");
+ }
+
+ if (getarg(tx.arg_string,"flow", argval)==1)
+ {
+ dummy = (unsigned int) strtol(argval,NULL,16);
+ if (dummy > 1048575)
+ {
+ fprintf(stderr, " IP_Warning: 'flow label' too big, adjusted to 0xfffff\n");
+ dummy = 0xfffff;
+ }
+ tx.ip_flow = dummy;
+ }
+
+ if (getarg(tx.arg_string,"dscp", argval)==1)
+ {
+ dummy = (unsigned int) str2int(argval);
+ if (dummy > 63)
+ {
+ fprintf(stderr, " IP_Warning: 'dscp' too big, adjusted to 63\n");
+ dummy = 63;
+ }
+ tx.ip_tos = (u_int8_t) dummy*4;
+ }
+
+ if (getarg(tx.arg_string,"id", argval)==1)
+ {
+ tx.ip6_id = str2int(argval);
+ }
+
+ if (getarg(tx.arg_string,"frag", argval)==1)
+ {
+ tx.ip_frag = ((u_int16_t) str2int(argval)) << 3;
+ }
+
+ if (getarg(tx.arg_string,"mf", NULL)==1)
+ {
+ tx.ip_frag |= 0x0001;
+ }
+
+ if (getarg(tx.arg_string,"frag_res1", NULL)==1)
+ {
+ tx.ip_frag |= 0x0002;
+ }
+
+ if (getarg(tx.arg_string,"frag_res2", NULL)==1)
+ {
+ tx.ip_frag |= 0x0004;
+ }
+
+ if (getarg(tx.arg_string,"hop", argval)==1)
+ {
+ tx.ip_ttl = (u_int8_t) str2int(argval);
+ }
+
+ if (getarg(tx.arg_string,"next", argval)==1)
+ {
+ tx.ip_proto = (u_int8_t) str2int(argval);
+ }
+ else if (mode==IP)
+ {
+ tx.ip_proto = 59; // No Next Header for IPv6
+ }
+
+
+ if ((tx.ascii)&&(mode==IP)) // ASCII PAYLOAD overrides hex payload
+ {
+ strncpy((char *)tx.ip_payload, (char *)tx.ascii_payload, MAX_PAYLOAD_SIZE);
+ tx.ip_payload_s = strlen((char *)tx.ascii_payload);
+ tx.ip_len += tx.ip_payload_s;
+ }
+
+
+ /////////
+ // Want some padding? The specified number of padding bytes are ADDED to the
+ // payload. Note that this is only evaluated if we are in IP mode because
+ // UDP and TCP already might have been padded and set the ip_payload_s.
+ // (Note the difference in send_eth() where you specified the total number
+ // of bytes in the frame)
+ //
+ if ((tx.padding)&&(mode==IP))
+ {
+ for (i=0; i<tx.padding; i++)
+ {
+ tx.ip_payload[tx.ip_payload_s+i] = 0x42; // pad with THE ANSWER (why random?)
+ }
+ tx.ip_payload_s += tx.padding;
+ tx.ip_len += tx.padding;
+ }
+
+ if (tx.ip6_id) {
+ t = libnet_build_ipv6_frag (tx.ip_proto,
+ 0,
+ htons(tx.ip_frag),
+ htonl(tx.ip6_id),
+ (mode==IP) ? (tx.ip_payload_s) ? tx.ip_payload : NULL : NULL,
+ (mode==IP) ? tx.ip_payload_s : 0,
+ l,
+ 0);
+ tx.ip_len += LIBNET_IPV6_FRAG_H;
+ tx.ip_payload_s = 0;
+ tx.ip_proto = LIBNET_IPV6_NH_FRAGMENT;
+ }
+
+ // See RFC 2460 Routing Header
+ //
+ if ( (getarg(tx.arg_string,"segments", argval)==1) )
+ {
+ dummy = (unsigned int) str2int(argval);
+ if (dummy > 255) {
+ fprintf(stderr, " IP_Error: Maximal Routing Segments are 255!\n");
+ exit(1);
+ }
+ tx.ip6_segs = dummy;
+ }
+
+ if ( (getarg(tx.arg_string,"rtype", argval)==1) )
+ {
+ dummy = (unsigned int) str2int(argval);
+ if (dummy > 255) {
+ fprintf(stderr, " IP_Error: Maximum Routing Type is 255!\n");
+ exit(1);
+ }
+ tx.ip6_segs = dummy;
+ }
+
+ if ( (getarg(tx.arg_string,"loose", argval)==1) )
+ {
+ // Fill reserved
+ memset(tx.ip_option, 0, 4);
+ tx.ip_option_s=4;
+
+ len = strlen(argval);
+ s = strtok(argval, ".+-;/>");
+ do
+ {
+ len--;
+ *((struct libnet_in6_addr *) &tx.ip_option[tx.ip_option_s]) = libnet_name2addr6 (l, s, LIBNET_DONT_RESOLVE);
+ tx.ip_option_s += 16;
+ } while ( (s=strtok(NULL, ".+-;/>")) != NULL );
+
+ if (!tx.ip_option_s) {
+ fprintf(stderr, " IP_Error: No Routing Hops found!\n");
+ exit(1);
+ }
+
+ if (mode==IP && tx.ip_payload_s)
+ memmove(tx.ip_payload+tx.ip_option_s, tx.ip_payload, tx.ip_payload_s);
+ else
+ tx.ip_payload_s = 0;
+
+ memcpy(tx.ip_payload, tx.ip_option, tx.ip_option_s);
+ tx.ip_payload_s += tx.ip_option_s;
+
+ t = libnet_build_ipv6_routing(tx.ip_proto,
+ (tx.ip_option_s -4) / 8,
+ tx.ip6_rtype,
+ tx.ip6_segs,
+ tx.ip_payload,
+ tx.ip_payload_s,
+ l,
+ 0);
+ tx.ip_len += LIBNET_IPV6_ROUTING_H + tx.ip_option_s;
+ tx.ip_payload_s = 0;
+ tx.ip_proto = LIBNET_IPV6_NH_ROUTING;
+ }
+
+ t = libnet_build_ipv6 (tx.ip_tos,
+ tx.ip_flow,
+ tx.ip_len,
+ tx.ip_proto,
+ tx.ip_ttl,
+ tx.ip6_src,
+ tx.ip6_dst,
+ (mode==IP) ? (tx.ip_payload_s) ? tx.ip_payload : NULL : NULL,
+ (mode==IP) ? tx.ip_payload_s : 0,
+ l,
+ 0);
+
+ if (t == -1)
+ {
+ fprintf(stderr, " mz/create_ip_packet: Can't build IPv6 header: %s\n", libnet_geterror(l));
+ exit (0);
+ }
+
+ return t;
+}
+
diff --git a/staging/layer4.c b/staging/layer4.c
new file mode 100644
index 0000000..ca4d229
--- /dev/null
+++ b/staging/layer4.c
@@ -0,0 +1,884 @@
+/*
+ * Mausezahn - A fast versatile traffic generator
+ * Copyright (C) 2008-2010 Herbert Haas
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
+ *
+*/
+
+
+
+////////////////////////////////////////////////////////////////////
+//
+// Layer 4 packet types
+//
+// 1. UDP
+// 2. ICMP
+// 3. TCP
+//
+////////////////////////////////////////////////////////////////////
+
+#include "mz.h"
+#include "cli.h"
+
+
+#define MZ_UDP_HELP \
+ "| UDP type: Send raw UDP packets.\n" \
+ "|\n" \
+ "| Parameters: \n" \
+ "|\n" \
+ "| sp 0-65535\n" \
+ "| dp 0-65535\n" \
+ "| len 0-65535\n" \
+ "| udp_sum 0-65535\n" \
+ "| payload|p <hex payload>\n" \
+ "|\n" \
+ "| Optionally the port numbers can be specified as ranges, e. g. \"dp=1023-33700\",\n" \
+ "| in which case one packet per port number is sent.\n" \
+ "|\n" \
+ "| Note that the UDP length must include the header length. If you do NOT specify the len\n" \
+ "| parameter (or specify len=0) then Mausezahn will compute the correct length.\n" \
+ "|\n" \
+ "| Note that all IP parameters can be modified (see IP help, i. e. '-t ip \"help\")\n" \
+ "| except that (to avoid confusion) the IP length is 'iplen' and the IP checksum is 'ipsum'.\n" \
+ "| Of course all Ethernet fields can also be accessed.\n" \
+ "|\n" \
+ "\n"
+
+
+#define MZ_ICMP_HELP \
+ "| ICMP type: Send raw ICMP packets.\n" \
+ "|\n" \
+ "| ARGUMENT SYNTAX: [type] <optional parameters> \n" \
+ "| \n" \
+ "| Per default an echo reply is sent (type=0, code=0)\n" \
+ "|\n" \
+ "| TYPE OPTIONAL PARAMETERS\n" \
+ "| =========== ====================================================================\n" \
+ "| Ping: \"ping\" or \"echoreq\" \n" \
+ "| 'id' (0-65535) is the optional identification number\n" \
+ "| 'seq' (0-65535) is the optional packet sequence number\n" \
+ "|\n" \
+ "| Redirect: \"redir, code=0, gw=192.168.1.10, p=aa:bb:cc\"\n" \
+ "| 'gw' (or 'gateway') is the announced gateway, by default your own\n" \
+ "| IP address.\n" \
+ "| 'code' can be:\n" \
+ "| 0 ... redirect datagram for the network\n" \
+ "| 1 ... redirect datagram for the host\n" \
+ "| 2 ... redirect datagram for ToS and network\n" \
+ "| 3 ... redirect datagram for ToS and host\n" \
+ "| 'p' (or 'payload') is the payload of the ICMP packet, tpyically an IP\n" \
+ "| header. Note that - at the moment - you must prepare this payload by\n" \
+ "| yourself.\n" \
+ "|\n" \
+ "| Unreachable \"unreach, code=2\"\n" \
+ "| 'code' can be:\n" \
+ "| 0 ... network unreachable\n" \
+ "| 1 ... host unreachable\n" \
+ "| 2 ... protocol unreachable\n" \
+ "| 3 ... port unreachable\n" \
+ "| 4 ... fragmentation needed but DF-bit is set\n" \
+ "| 5 ... source route failed\n" \
+ "|\n" \
+ "|\n" \
+ "| (other ICMP types will follow)\n" \
+ "|\n" \
+ "\n"
+
+#define MZ_ICMP6_HELP \
+ "| ICMPv6 type: Send raw ICMPv6 packets.\n" \
+ "|\n" \
+ "| Parameters Values Explanation \n" \
+ "| ---------- ------------------------------------ -------------------\n" \
+ "| type 0-255 ICMPv6 Type\n" \
+ "| code 0-255 ICMPv6 Code\n" \
+ "| id 0-65535 optional identification number\n" \
+ "| seq 0-65535 optional packet sequence number\n" \
+ "| icmpv6_sum 0-65535 optional checksum\n" \
+ "\n"
+
+#define MZ_TCP_HELP \
+ "| TCP type: Send raw TCP packets.\n" \
+ "|\n" \
+ "| Parameters Values Explanation \n" \
+ "| ---------- ------------------------------------ -------------------\n" \
+ "| sp 0-65535 Source Port\n" \
+ "| dp 0-65535 Destination Port\n" \
+ "| flags fin|syn|rst|psh|ack|urg|ecn|cwr\n" \
+ "| s 0-4294967295 Sequence Nr.\n" \
+ "| a 0-4294967295 Acknowledgement Nr.\n" \
+ "| win 0-65535 Window Size\n" \
+ "| urg 0-65535 Urgent Pointer\n" \
+ "| tcp_sum 0-65535 Checksum\n" \
+ "|\n" \
+ "| The port numbers can be specified as ranges, e. g. \"dp=1023-33700\".\n" \
+ "| Multiple flags can be specified such as \"flags=syn|ack|urg\".\n" \
+ "|\n" \
+ "| Also the sequence number can be specified as a range, for example:\n" \
+ "|\n" \
+ "| s=10000-50000 ... send 40000 packets with SQNRs in that range. If the second\n" \
+ "| value is lower than the first then it is assumed that the\n" \
+ "| SQNRs should 'wrap around'.\n" \
+ "| ds=30000 ........ use this increment within a SQNR-range.\n" \
+ "|\n" \
+ "| Note that all IP parameters can be modified (see IP help, i. e. '-t ip \"help\")\n" \
+ "| except that (to avoid confusion) the IP length is 'iplen' and the IP checksum is 'ipsum'.\n" \
+ "| Of course all Ethernet fields can also be accessed.\n"\
+ "|\n"
+
+
+
+// Note: If another function specified tx.udp_payload then it must also
+// set tx.udp_payload_s AND tx.udp_len = tx.udp_payload_s + 8
+libnet_ptag_t create_udp_packet (libnet_t *l)
+{
+ libnet_ptag_t t;
+ char argval[MAX_PAYLOAD_SIZE];
+ int T; // only an abbreviation for tx.packet_mode
+ int i;
+
+ /////////////////////////////
+ // Default UDP header fields
+ // Already reset in init.c
+ /////////////////////////////
+
+ T = tx.packet_mode; // >0 means automatic L2 creation
+
+ if ( (getarg(tx.arg_string,"help", NULL)==1) && (mode==UDP) )
+ {
+ if (mz_port)
+ {
+ cli_print(gcli, "%s", MZ_UDP_HELP);
+ return -1;
+ }
+ else
+ {
+
+ fprintf(stderr,"\n"
+ MAUSEZAHN_VERSION
+ "\n%s", MZ_UDP_HELP);
+
+ exit(0);
+ }
+
+ }
+
+
+ // Evaluate CLI parameters:
+
+ if (getarg(tx.arg_string,"dp", argval)==1)
+ {
+ if (get_port_range (DST_PORT, argval)) // problem
+ {
+ tx.dp = 0;
+ }
+ }
+
+ if (getarg(tx.arg_string,"sp", argval)==1)
+ {
+ if (get_port_range (SRC_PORT, argval)) // problem
+ {
+ tx.sp = 0;
+ }
+ }
+
+
+ // Check if hex_payload already specified (externally)
+ if (tx.hex_payload_s)
+ {
+ memcpy( (void*) tx.udp_payload, (void*) tx.hex_payload, tx.hex_payload_s);
+ tx.udp_payload_s = tx.hex_payload_s;
+ }
+
+ if ( (getarg(tx.arg_string,"payload", argval)==1) || (getarg(tx.arg_string,"p", argval)==1))
+ {
+ tx.udp_payload_s = str2hex (argval, tx.udp_payload, MAX_PAYLOAD_SIZE);
+ }
+
+
+
+ if (getarg(tx.arg_string,"sum", argval)==1)
+ {
+ if (T) fprintf(stderr, " IP_Warning: 'sum' cannot be set in this mode.\n");
+ tx.ip_sum = (u_int16_t) str2int(argval);
+ }
+
+ if (getarg(tx.arg_string,"udp_sum", argval)==1)
+ {
+ tx.udp_sum = (u_int16_t) str2int(argval);
+ }
+
+
+ if (tx.ascii) // ASCII PAYLOAD overrides hex payload
+ {
+ strncpy((char *)tx.udp_payload, (char *)tx.ascii_payload, MAX_PAYLOAD_SIZE);
+ tx.udp_payload_s = strlen((char *)tx.ascii_payload);
+ printf("[%s]\n", tx.ascii_payload);
+ }
+
+
+ /////////
+ // Want some padding? The specified number of padding bytes are ADDED to the
+ // payload.
+ // (Note the difference in send_eth() where you specified the total number
+ // of bytes in the frame)
+ //
+ if (tx.padding)
+ {
+ for (i=0; i<tx.padding; i++)
+ {
+ tx.udp_payload[tx.udp_payload_s+i] = 0x42; // pad with THE ANSWER (why random?)
+ }
+ tx.udp_payload_s += tx.padding;
+ }
+
+
+
+ ////////
+ // The following is VERY IMPORTANT because the ip_payload_s is also set!
+ if (getarg(tx.arg_string,"len", argval)==1)
+ {
+ tx.udp_len = (u_int16_t) str2int(argval);
+ tx.ip_payload_s = tx.udp_len;
+ }
+ else // len NOT specified by user
+ {
+ if (tx.udp_len == 0) // len also not specified by another function (e. g. create_dns_packet...)
+ {
+ tx.udp_len = 8 + tx.udp_payload_s;
+ tx.ip_payload_s = tx.udp_len;
+ }
+ else // len (and payload and payload_s) has been specified by another function
+ {
+ tx.ip_payload_s = tx.udp_len;
+ }
+
+ }
+
+
+
+ t = libnet_build_udp(tx.sp,
+ tx.dp,
+ tx.udp_len,
+ tx.udp_sum,
+ (tx.udp_payload_s) ? tx.udp_payload : NULL,
+ tx.udp_payload_s,
+ l,
+ 0);
+
+ // Checksum overwrite? Libnet IPv6 checksum calculation can't deal with extension headers, we have to do it ourself...
+ libnet_toggle_checksum(l, t, (tx.udp_sum || ipv6_mode) ? LIBNET_OFF : LIBNET_ON);
+
+ if (t == -1)
+ {
+ fprintf(stderr, " mz/create_udp_packet: Can't build UDP header: %s\n", libnet_geterror(l));
+ exit (0);
+ }
+
+
+
+ return t;
+
+}
+
+
+
+
+
+
+
+
+///////////////////////////////////////////////////
+///////////////////////////////////////////////////
+///////////////////////////////////////////////////
+///////////////////////////////////////////////////
+///////////////////////////////////////////////////
+
+
+
+libnet_ptag_t create_icmp_packet (libnet_t *l)
+{
+
+ libnet_ptag_t t;
+ char argval[MAX_PAYLOAD_SIZE];
+ unsigned char *x;
+
+ int i;
+
+ enum
+ {
+ NONE,
+ ECHO_REQUEST,
+ REDIRECT,
+ UNREACHABLE
+ }
+ icmp; // which ICMP Type?
+
+
+ if ( (getarg(tx.arg_string,"help", NULL)==1) && (mode==ICMP) )
+ {
+ if (mz_port)
+ {
+ cli_print(gcli, "%s", MZ_ICMP_HELP);
+ return -1;
+ }
+ else
+ {
+
+ fprintf(stderr,"\n"
+ MAUSEZAHN_VERSION
+ "\n%s", MZ_ICMP_HELP);
+ exit(0);
+ }
+ }
+
+
+ /////////////////////////////////////////
+ //
+ // Which ICMP Type has been specified?
+ //
+ // Note: to allow invalid type values we need the enum 'icmp' tp specify the sending function
+ // and the 'type' variable seperately.
+
+ if ( (getarg(tx.arg_string,"redirect", NULL)==1) || (getarg(tx.arg_string,"redir", NULL)==1) )
+ {
+ icmp = REDIRECT;
+ tx.icmp_type = ICMP_REDIRECT;
+ tx.icmp_code=ICMP_REDIRECT_HOST;
+ }
+
+
+ if ( (getarg(tx.arg_string,"ping", NULL)==1) || (getarg(tx.arg_string,"echoreq", NULL)==1) )
+ {
+ icmp = ECHO_REQUEST;
+ tx.icmp_type = ICMP_ECHO;
+ tx.icmp_code = 0;
+ }
+
+
+ if (getarg(tx.arg_string,"unreach", NULL)==1)
+ {
+ icmp = UNREACHABLE;
+ tx.icmp_type = ICMP_UNREACH;
+ tx.icmp_code = 0; // network unreachable
+ }
+
+
+ /////////////////////////////////////////
+ //
+ // Which parameters have been specified?
+
+
+ if (getarg(tx.arg_string,"type", argval)==1)
+ {
+ tx.icmp_type = (u_int8_t) str2int(argval);
+ }
+
+ if (getarg(tx.arg_string,"code", argval)==1)
+ {
+ tx.icmp_code = (u_int8_t) str2int(argval);
+ }
+ else
+ {
+ // Use appropriate defaults depending on ICMP type
+ }
+
+
+ if (getarg(tx.arg_string,"icmp_sum", argval)==1)
+ {
+ tx.icmp_chksum = (u_int16_t) str2int(argval);
+ }
+
+ if ( (getarg(tx.arg_string,"gateway", argval)==1) || (getarg(tx.arg_string,"gw", argval)==1) )
+ {
+ tx.icmp_gateway = str2ip32 (argval);
+ }
+ else
+ {
+ tx.icmp_gateway = tx.ip_src; // prefer own address
+ }
+
+
+ if (getarg(tx.arg_string,"id", argval)==1)
+ {
+ tx.icmp_ident = (u_int16_t) str2int(argval);
+ }
+
+ if (getarg(tx.arg_string,"seq", argval)==1)
+ {
+ tx.icmp_sqnr = (u_int16_t) str2int(argval);
+ }
+
+
+ // Check if hex_payload already specified (externally)
+ if (tx.hex_payload_s)
+ {
+ memcpy( (void*) tx.icmp_payload, (void*) tx.hex_payload, tx.hex_payload_s);
+ tx.icmp_payload_s = tx.hex_payload_s;
+ }
+
+
+ if ( (getarg(tx.arg_string,"payload", argval)==1) || (getarg(tx.arg_string,"p", argval)==1))
+ {
+ tx.icmp_payload_s = str2hex (argval, tx.icmp_payload, MAX_PAYLOAD_SIZE);
+ }
+ else
+ {
+ tx.icmp_payload_s = 0;
+ }
+
+
+ if (tx.ascii) // ASCII PAYLOAD overrides hex payload
+ {
+ strncpy((char *)tx.icmp_payload, (char *)tx.ascii_payload, MAX_PAYLOAD_SIZE);
+ tx.icmp_payload_s = strlen((char *)tx.ascii_payload);
+ }
+
+
+ /////////
+ // Want some padding? The specified number of padding bytes are ADDED to the
+ // payload.
+ // (Note the difference in send_eth() where you specified the total number
+ // of bytes in the frame)
+ //
+ if (tx.padding)
+ {
+ for (i=0; i<tx.padding; i++)
+ {
+ tx.icmp_payload[tx.icmp_payload_s+i] = 0x42; // pad with THE ANSWER (why random?)
+ }
+ tx.icmp_payload_s += tx.padding;
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ //
+ // Now determine which type of ICMP packet to send.
+ //
+ // NOTE: Every section (icmp-type) must provide
+ //
+ // 1. a build function
+ // 2. tx.ip_payload_s which indicates the whole ICMP packet size
+ // 3. tx.icmp_verbose_string containing details about the ICMP packet (verbose mode)
+ //
+ ////////////////////////////////////////////////////////////////////////////////////////////
+
+ switch (icmp)
+ {
+ case REDIRECT: // +++++++++++++++
+ t = libnet_build_icmpv4_redirect (tx.icmp_type,
+ tx.icmp_code,
+ tx.icmp_chksum,
+ tx.icmp_gateway,
+ (tx.icmp_payload_s) ? tx.icmp_payload : NULL,
+ tx.icmp_payload_s,
+ l,
+ 0);
+ tx.ip_payload_s = LIBNET_ICMPV4_REDIRECT_H + tx.icmp_payload_s; // for send_ip
+ if (verbose)
+ {
+ x = (unsigned char*) &tx.icmp_gateway;
+ sprintf(tx.icmp_verbose_txt,"ICMP Redirect, GW=%u.%u.%u.%u",
+ *(x),*(x+1),*(x+2),*(x+3));
+ }
+ break; // ++++++++++++++++++++++
+ case NONE:
+ case ECHO_REQUEST:
+ t = libnet_build_icmpv4_echo(tx.icmp_type,
+ tx.icmp_code,
+ tx.icmp_chksum,
+ tx.icmp_ident,
+ tx.icmp_sqnr,
+ (tx.icmp_payload_s) ? tx.icmp_payload : NULL,
+ tx.icmp_payload_s,
+ l,
+ 0);
+ tx.ip_payload_s = LIBNET_ICMPV4_REDIRECT_H + tx.icmp_payload_s; // for send_ip
+ if (verbose)
+ {
+ if (icmp == NONE)
+ sprintf(tx.icmp_verbose_txt,"ICMP Type %u Code %u\n",tx.icmp_type,tx.icmp_code);
+ else
+ sprintf(tx.icmp_verbose_txt,"ICMP Echo Request (id=%u seq=%u)\n",tx.icmp_ident,tx.icmp_sqnr);
+ }
+ break; // ++++++++++++++++++++++
+ case UNREACHABLE:
+ t = libnet_build_icmpv4_unreach(tx.icmp_type,
+ tx.icmp_code,
+ tx.icmp_chksum,
+ (tx.icmp_payload_s) ? tx.icmp_payload : NULL,
+ tx.icmp_payload_s,
+ l,
+ 0);
+ if (verbose)
+ {
+ sprintf(tx.icmp_verbose_txt,"ICMP unreachable (code=%u)\n",tx.icmp_code);
+ }
+ break; // ++++++++++++++++++++++
+ default:
+ (void) fprintf(stderr," mz/icmp: unknown mode! Stop.\n");
+ return (1);
+ }
+
+ libnet_toggle_checksum(l, t, tx.icmp_chksum ? LIBNET_OFF : LIBNET_ON);
+
+ if (t == -1)
+ {
+ fprintf(stderr, " mz/create_icmp_packet: Can't build ICMP header: %s\n", libnet_geterror(l));
+ exit (0);
+ }
+
+
+ return t;
+}
+
+libnet_ptag_t create_icmp6_packet (libnet_t *l)
+{
+ libnet_ptag_t t;
+ char argval[MAX_PAYLOAD_SIZE];
+
+ int i;
+ tx.icmp_ident = 0;
+ tx.icmp_sqnr = 0;
+
+ if ( (getarg(tx.arg_string,"help", NULL)==1) && (mode==ICMP) )
+ {
+ if (mz_port)
+ {
+ cli_print(gcli, "%s", MZ_ICMP6_HELP);
+ return -1;
+ }
+ else
+ {
+ fprintf(stderr,"\n"
+ MAUSEZAHN_VERSION
+ "\n%s", MZ_ICMP6_HELP);
+ exit(0);
+ }
+ }
+
+
+ /////////////////////////////////////////
+ //
+ // Which parameters have been specified?
+
+
+ if (getarg(tx.arg_string,"type", argval)==1)
+ {
+ tx.icmp_type = (u_int8_t) str2int(argval);
+ }
+
+ if (getarg(tx.arg_string,"code", argval)==1)
+ {
+ tx.icmp_code = (u_int8_t) str2int(argval);
+ }
+
+ if (getarg(tx.arg_string,"id", argval)==1)
+ {
+ tx.icmp_ident = (u_int16_t) str2int(argval);
+ }
+
+ if (getarg(tx.arg_string,"seq", argval)==1)
+ {
+ tx.icmp_sqnr = (u_int16_t) str2int(argval);
+ }
+
+ if (getarg(tx.arg_string,"icmpv6_sum", argval)==1)
+ {
+ tx.icmp_chksum = (u_int16_t) str2int(argval);
+ }
+
+ // Check if hex_payload already specified (externally)
+ if (tx.hex_payload_s)
+ {
+ memcpy( (void*) tx.icmp_payload, (void*) tx.hex_payload, tx.hex_payload_s);
+ tx.icmp_payload_s = tx.hex_payload_s;
+ }
+
+ if ( (getarg(tx.arg_string,"payload", argval)==1) || (getarg(tx.arg_string,"p", argval)==1))
+ {
+ tx.icmp_payload_s = str2hex (argval, tx.icmp_payload, MAX_PAYLOAD_SIZE);
+ }
+ else
+ {
+ tx.icmp_payload_s = 0;
+ }
+
+ if (tx.ascii) // ASCII PAYLOAD overrides hex payload
+ {
+ strncpy((char *)tx.icmp_payload, (char *)tx.ascii_payload, MAX_PAYLOAD_SIZE);
+ tx.icmp_payload_s = strlen((char *)tx.ascii_payload);
+ }
+
+ /////////
+ // Want some padding? The specified number of padding bytes are ADDED to the
+ // payload.
+ // (Note the difference in send_eth() where you specified the total number
+ // of bytes in the frame)
+ //
+ if (tx.padding)
+ {
+ for (i=0; i<tx.padding; i++)
+ {
+ tx.icmp_payload[tx.icmp_payload_s+i] = 0x42; // pad with THE ANSWER (why random?)
+ }
+ tx.icmp_payload_s += tx.padding;
+ }
+
+ sprintf(tx.icmp_verbose_txt,"ICMPv6 Type %u Code %u\n",tx.icmp_type,tx.icmp_code);
+
+ t = libnet_build_icmpv4_echo (tx.icmp_type,
+ tx.icmp_code,
+ tx.icmp_chksum,
+ tx.icmp_ident,
+ tx.icmp_sqnr,
+ tx.icmp_payload_s ? tx.icmp_payload : NULL,
+ tx.icmp_payload_s,
+ l,
+ 0);
+ tx.ip_payload_s = LIBNET_ICMPV6_H + tx.icmp_payload_s; // for send_ip
+
+ // Libnet IPv6 checksum calculation can't deal with extension headers, we have to do it ourself...
+ libnet_toggle_checksum(l, t, (tx.icmp_chksum || ipv6_mode) ? LIBNET_OFF : LIBNET_ON);
+
+ if (t == -1)
+ {
+ fprintf(stderr, " mz/create_icmp_packet: Can't build ICMPv6 header: %s\n", libnet_geterror(l));
+ exit (0);
+ }
+
+ return t;
+}
+
+
+
+///////////////////////////////////////////////////
+///////////////////////////////////////////////////
+///////////////////////////////////////////////////
+///////////////////////////////////////////////////
+///////////////////////////////////////////////////
+
+
+// Note: If another function specified tx.tcp_payload then it must also
+// set tx.tcp_payload_s AND tx.tcp_len = tx.tcp_payload_s + 20
+libnet_ptag_t create_tcp_packet (libnet_t *l)
+{
+ libnet_ptag_t t, t2;
+ char argval[MAX_PAYLOAD_SIZE], *dummy1, *dummy2;
+ int T; // only an abbreviation for tx.packet_mode
+ int i;
+
+ u_int8_t tcp_default_options[] =
+ {
+ 0x02, 0x04, 0x05, 0xac, // MSS
+ 0x04, 0x02, // SACK permitted
+ 0x08, 0x0a, 0x19, 0x35, 0x90, 0xc3, 0x00, 0x00, 0x00, 0x00, // Timestamps
+ 0x01, // NOP
+ 0x03, 0x03, 0x05 // Window Scale 5
+ };
+
+
+
+ /////////////////////////////
+ // Default TCP header fields
+ // Already reset in init.c
+ /////////////////////////////
+
+ T = tx.packet_mode; // >0 means automatic L2 creation
+
+ if ( (getarg(tx.arg_string,"help", NULL)==1) && (mode==TCP) )
+ {
+ if (mz_port)
+ {
+ cli_print(gcli, "%s", MZ_TCP_HELP);
+ return -1;
+ }
+ else
+ {
+ fprintf(stderr,"\n"
+ MAUSEZAHN_VERSION
+ "\n%s", MZ_TCP_HELP);
+ exit(0);
+ }
+ }
+
+
+ // Evaluate CLI parameters:
+
+ if (getarg(tx.arg_string,"dp", argval)==1)
+ {
+ if (get_port_range (DST_PORT, argval)) // problem
+ {
+ tx.dp = 0;
+ }
+ }
+
+
+ if (getarg(tx.arg_string,"sp", argval)==1)
+ {
+ if (get_port_range (SRC_PORT, argval)) // problem
+ {
+ tx.sp = 0;
+ }
+ }
+
+
+ if (getarg(tx.arg_string,"s", argval)==1)
+ {
+ //check whether a range has been specified:
+ dummy1 = strtok(argval, "-");
+ tx.tcp_seq = (u_int32_t) str2int (dummy1);
+ if ( (dummy2 = strtok(NULL, "-")) == NULL ) // no additional value
+ {
+ tx.tcp_seq_stop = tx.tcp_seq;
+ }
+ else // range
+ {
+ tx.tcp_seq_stop = (u_int32_t) str2int (dummy2);
+ tx.tcp_seq_start = tx.tcp_seq; // initially tcp_seq = tcp_seq_start
+ tx.tcp_seq_delta = 1; // an initialization only in case 'ds' not specified
+ }
+ }
+
+ if (getarg(tx.arg_string,"ds", argval)==1)
+ {
+ tx.tcp_seq_delta = (u_int32_t) str2int (argval);
+ }
+
+ if (getarg(tx.arg_string,"a", argval)==1)
+ {
+ tx.tcp_ack = (u_int32_t) str2int (argval);
+ }
+
+ if (getarg(tx.arg_string,"win", argval)==1)
+ {
+ tx.tcp_win = (u_int16_t) str2int (argval);
+ }
+
+ if (getarg(tx.arg_string,"urg", argval)==1)
+ {
+ tx.tcp_urg = (u_int16_t) str2int (argval);
+ }
+
+
+ if ( (getarg(tx.arg_string,"flags", argval)==1) ||
+ (getarg(tx.arg_string,"flag", argval)==1) ) // because everybody confuses this
+ {
+ if (get_tcp_flags(argval)) // problem
+ {
+ tx.tcp_control=2; // Assume SYN as default
+ }
+ }
+
+ if (getarg(tx.arg_string,"tcp_sum", argval)==1)
+ {
+ tx.tcp_sum = (u_int16_t) str2int(argval);
+ }
+
+ // Check if hex_payload already specified (externally)
+ if (tx.hex_payload_s)
+ {
+ memcpy( (void*) tx.tcp_payload, (void*) tx.hex_payload, tx.hex_payload_s);
+ tx.tcp_payload_s = tx.hex_payload_s;
+ }
+
+
+ if ( (getarg(tx.arg_string,"payload", argval)==1) || (getarg(tx.arg_string,"p", argval)==1))
+ {
+ tx.tcp_payload_s = str2hex (argval, tx.tcp_payload, MAX_PAYLOAD_SIZE);
+ }
+
+
+ if (tx.ascii) // ASCII PAYLOAD overrides hex payload
+ {
+ strncpy((char *)tx.tcp_payload, (char *)tx.ascii_payload, MAX_PAYLOAD_SIZE);
+ tx.tcp_payload_s = strlen((char *)tx.ascii_payload);
+ tx.tcp_len = 20 + tx.tcp_payload_s; // only needed by libnet to calculate checksum
+ tx.ip_payload_s = tx.tcp_len; // for create_ip_packet
+ }
+
+
+
+ /////////
+ // Want some padding? The specified number of padding bytes are ADDED to the
+ // payload.
+ // (Note the difference in send_eth() where you specified the total number
+ // of bytes in the frame)
+ //
+ if (tx.padding)
+ {
+ for (i=0; i<tx.padding; i++)
+ {
+ tx.tcp_payload[tx.tcp_payload_s+i] = 0x42; // pad with THE ANSWER (why random?)
+ }
+ tx.tcp_payload_s += tx.padding;
+
+ }
+
+
+
+ tx.tcp_len = 20 + tx.tcp_payload_s; // only needed by libnet to calculate checksum
+ tx.ip_payload_s = tx.tcp_len; // for create_ip_packet
+
+ if (tx.tcp_control & 0x02) // packets with syn require an MSS option
+ {
+ t2 = libnet_build_tcp_options(tcp_default_options,
+ 20,
+ l,
+ 0);
+
+ if (t2 == -1)
+ {
+ fprintf(stderr, " mz/create_tcp_packet: Can't build TCP options: %s\n", libnet_geterror(l));
+ exit (0);
+ }
+
+ tx.tcp_len += 20;
+ tx.tcp_offset = 10;
+ tx.ip_payload_s = tx.tcp_len; // for create_ip_packet
+ tx.tcp_sum_part = libnet_in_cksum((u_int16_t *) tcp_default_options, 20);
+ }
+ else
+ {
+ tx.tcp_offset = 5;
+ tx.tcp_sum_part = 0;
+ }
+
+ t = libnet_build_tcp (tx.sp,
+ tx.dp,
+ tx.tcp_seq,
+ tx.tcp_ack,
+ tx.tcp_control,
+ tx.tcp_win,
+ tx.tcp_sum,
+ tx.tcp_urg,
+ tx.tcp_len,
+ (tx.tcp_payload_s) ? tx.tcp_payload : NULL,
+ tx.tcp_payload_s,
+ l,
+ 0);
+
+
+
+ // Libnet IPv6 checksum calculation can't deal with extension headers, we have to do it ourself...
+ libnet_toggle_checksum(l, t, (tx.tcp_sum || ipv6_mode) ? LIBNET_OFF : LIBNET_ON);
+
+ if (t == -1)
+ {
+ fprintf(stderr, " mz/create_tcp_packet: Can't build TCP header: %s\n", libnet_geterror(l));
+ exit (0);
+ }
+
+
+ return t;
+}
diff --git a/staging/llist.c b/staging/llist.c
new file mode 100644
index 0000000..d729e46
--- /dev/null
+++ b/staging/llist.c
@@ -0,0 +1,176 @@
+/*
+ * Mausezahn - A fast versatile traffic generator
+ * Copyright (C) 2010 Herbert Haas
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
+ *
+*/
+
+
+#include "mz.h"
+#include "cli.h"
+#include "mops.h"
+#include "llist.h"
+
+/* PURPOSE:
+ * General doubly linked list with management functions.
+ *
+ * NOTE:
+ * There is no dummy head element. Every element may contain data!
+ * Therefore there is only one general "create_new_element" function.
+ *
+ * You cannot delete the head element except you want to delete the whole list.
+ * Usually you delete the head element at last.
+ *
+ * head->refcount always contains the number of elements.
+ *
+ * Each element has a unique index number.
+ *
+ * The user must assign her/his data to (void*) elem->data.
+ *
+ */
+
+
+// Create new list element - may be the first one (list==NULL)
+//
+struct mz_ll * mz_ll_create_new_element(struct mz_ll *list)
+{
+ struct mz_ll *new_element;
+ new_element = (struct mz_ll*) malloc (sizeof(struct mz_ll));
+ if (new_element==NULL) return NULL;
+ _mz_ll_set_default(new_element);
+ if (list==NULL) {
+ new_element->next=new_element;
+ new_element->prev=new_element;
+ new_element->head=new_element;
+ new_element->refcount=1;
+ new_element->index=0;
+ new_element->index_last=0;
+ } else {
+ new_element->prev=list->prev;
+ new_element->next=list;
+ new_element->prev->next=new_element;
+ list->prev = new_element;
+ new_element->head=list;
+ list->refcount++;
+ list->index_last++;
+ new_element->index=list->index_last;
+ }
+
+ return new_element;
+}
+
+// Delete ONE list element.
+int mz_ll_delete_element (struct mz_ll *cur)
+{
+ if ((cur==NULL)||(cur==cur->head)) return -1; // don't delete head!
+ if (cur->data!=NULL) { free(cur->data); cur->data=NULL; }
+
+ if ((cur->next!=cur)&&(cur->prev!=cur)) {
+ cur->prev->next=cur->next;
+ cur->next->prev=cur->prev;
+ }
+ cur->head->refcount--;
+ if (cur!=NULL) { free(cur); cur=NULL; }
+ return 0;
+}
+
+
+int mz_ll_delete_list (struct mz_ll *list)
+{
+ struct mz_ll *cur=list,
+ *tmp;
+
+ if (cur==NULL) return 1;
+ while (cur!=cur->next) {
+ tmp=cur->next;
+ mz_ll_delete_element(cur);
+ cur=tmp;
+ }
+ // Finally free list head:
+ if (list->data!=NULL) { free(list->data); list->data=NULL; }
+ free(list);
+ list=NULL;
+ return 0;
+}
+
+struct mz_ll * mz_ll_search_name (struct mz_ll *list, char *str)
+{
+ struct mz_ll *cur=list;
+ do {
+ if (strncmp(cur->name, str, MZ_LL_NAME_LEN)==0) return cur;
+ cur=cur->next;
+ }
+ while (cur!=list);
+ return NULL;
+}
+
+struct mz_ll * mz_ll_search_index (struct mz_ll *list, int i)
+{
+ struct mz_ll *cur=list;
+ do {
+ if (cur->index==i) return cur;
+ cur=cur->next;
+ }
+ while (cur!=list);
+ return NULL;
+}
+
+int mz_ll_size(struct mz_ll *list)
+{
+ int i=0;
+ struct mz_ll *cur=list;
+
+ if (list==NULL) return 0;
+
+ do {
+ i++;
+ cur=cur->next;
+ }
+ while (cur!=list);
+ if (i!=list->refcount) fprintf(stderr, "MZ_LL_SIZE: Anomalous situation. Report this.\n");
+ return i;
+}
+
+
+int mz_ll_dump_all(struct mz_ll *list)
+{
+ int i=0;
+ struct mz_ll *cur=list;
+
+ if (list==NULL) return 0;
+
+ do {
+ i++;
+ fprintf(stdout, "Element %i: '%s', index=%i\n",i,cur->name, cur->index);
+ cur=cur->next;
+ }
+ while (cur!=list);
+ return i;
+}
+
+
+
+// ------ PRIVATE: initialize list-element
+void _mz_ll_set_default (struct mz_ll *cur)
+{
+ cur->refcount = 0;
+ cur->data = NULL;
+ cur->name[0]='\0';
+ cur->index=0;
+ cur->state=0;
+}
+
+
+
+
diff --git a/staging/llist.h b/staging/llist.h
new file mode 100644
index 0000000..49a87c7
--- /dev/null
+++ b/staging/llist.h
@@ -0,0 +1,75 @@
+/*
+ * Mausezahn - A fast versatile traffic generator
+ * Copyright (C) 2010 Herbert Haas
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
+ *
+*/
+
+
+
+#ifndef MZ_LINKED_LIST
+#define MZ_LINKED_LIST
+
+#define MAX_PACKET_SEQUENCE_LEN 20 // how many packets can be defined in a sequence at maximum
+
+// A packet sequence -- this is the list data (each list element corresponds to one sequence)
+struct pseq {
+ struct mops *packet[MAX_PACKET_SEQUENCE_LEN]; // pointer to the packets
+ struct timespec gap[MAX_PACKET_SEQUENCE_LEN]; // optional delay between different packets
+ int count; // total number of current members (=packets)
+};
+
+
+// --------------- Mausezahn Multipurpose Linked List: -------------------
+
+#define MZ_LL_NAME_LEN 64
+
+// one list element
+struct mz_ll {
+ struct mz_ll *prev;
+ struct mz_ll *next;
+ struct mz_ll *head; // always points to head element
+ int refcount; // head element: total number of list items! (Otherwise can be used as refcount.)
+ char name[MZ_LL_NAME_LEN];
+ pthread_t sequence_thread;
+ int state; // 0 = inactive, 1 = active
+ int index; // monotonically increasing;
+ int index_last; //head always stores the last value!
+ void *data; // points to your data
+};
+
+struct mz_ll *packet_sequences;
+struct mz_ll *cli_seq; // currently edited packet sequence used by CLI
+
+// prototypes
+struct mz_ll * mz_ll_create_new_element(struct mz_ll *list);
+int mz_ll_delete_element (struct mz_ll *cur);
+int mz_ll_delete_list(struct mz_ll *list);
+struct mz_ll * mz_ll_search_name (struct mz_ll *list, char *str);
+void _mz_ll_set_default (struct mz_ll *cur);
+int mz_ll_dump_all(struct mz_ll *list);
+int mops_tx_sequence (struct mz_ll *seq);
+
+// convenience functions using the above in a more intelligent way
+int mops_delete_sequence(char *name);
+struct mz_ll * mops_create_sequence (char *name);
+int mops_dump_sequence (char* str);
+int mops_add_packet_to_sequence (struct mz_ll *seq, struct mops *mp);
+int mops_add_delay_to_sequence (struct mz_ll *seq, struct timespec *t);
+int mops_delete_packet_from_pseq (struct mz_ll *seq, int index);
+int mops_delete_all_packets_from_pseq (struct mz_ll *seq);
+int stop_sequence (char *name);
+int stop_all_sequences ();
+#endif
+
diff --git a/staging/lookupdev.c b/staging/lookupdev.c
new file mode 100644
index 0000000..dfca239
--- /dev/null
+++ b/staging/lookupdev.c
@@ -0,0 +1,357 @@
+/*
+ * Mausezahn - A fast versatile traffic generator
+ * Copyright (C) 2008-2010 Herbert Haas
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
+ *
+*/
+
+
+
+
+#include "mz.h"
+#include "mops.h"
+
+#include <netpacket/packet.h>
+#include <netinet/ether.h>
+
+
+// PURPOSE: Find usable network devices
+//
+// NOTE:
+//
+// 1. Ignores devices without IP address
+// 2. Ignores loopback (etc)
+//
+// RETURN VALUES:
+//
+// 0 if usable device found (device_list[] and tx.device set)
+// 1 if no usable device found
+//
+int lookupdev()
+{
+ // char *tx.device is global, see as.h
+
+ char
+ ipaddress[IPADDRSIZE+1],
+ errbuf[PCAP_ERRBUF_SIZE];
+
+ pcap_if_t
+ *alldevs,
+ *index = NULL;
+
+ pcap_addr_t *pcap_addr;
+
+ int i=0;
+
+
+ // FIRST get a list of all available devices
+ //
+ if (pcap_findalldevs(&alldevs, errbuf) == -1)
+ {
+ fprintf(stderr," mz: %s\n",errbuf);
+ return 1;
+ }
+
+ index = (pcap_if_t *) alldevs;
+
+ while (index)
+ {
+ if (index->addresses)
+ {
+ pcap_addr = index->addresses;
+ while(pcap_addr)
+ {
+ if (pcap_addr->addr && (pcap_addr->addr->sa_family==AF_INET))
+ {
+ if (inet_ntop(pcap_addr->addr->sa_family,
+ (void *)&pcap_addr->addr->sa_data[2],
+ ipaddress,
+ IPADDRSIZE))
+ {
+ if (verbose)
+ {
+ fprintf(stderr," mz: device %s got assigned %s ",
+ index->name, ipaddress);
+ }
+
+ if (strncmp(ipaddress, "127", 3)==0)
+ {
+ if (verbose) fprintf(stderr, "(loopback)\n");
+ strncpy(device_list[i].dev, index->name, 9);
+ strncpy(device_list[i].ip_str, ipaddress, IPADDRSIZE);
+ device_list[i].phy=0;
+ get_if_addr(index->name, device_list[i].ip, device_list[i].mac);
+ get_if_addr(index->name, device_list[i].ip_mops, device_list[i].mac_mops);
+ i++;
+ }
+ else if (strncmp(ipaddress, "169.254", 7)==0)
+ {
+ if (verbose) fprintf(stderr, "but IGNORED (cause: host-scope address)\n");
+ }
+ else // FOUND VALID INTERFACE
+ {
+ if (verbose) fprintf(stderr, "and is a possible candidate.\n");
+ strncpy(device_list[i].dev, index->name, 9);
+ strncpy(device_list[i].ip_str, ipaddress, IPADDRSIZE);
+ device_list[i].phy=1;
+ get_if_addr(index->name, device_list[i].ip, device_list[i].mac);
+ get_if_addr(index->name, device_list[i].ip_mops, device_list[i].mac_mops);
+ i++;
+ }
+
+ // Select only interfaces with IP addresses
+ // but avoid those that start with 127 or 169.254
+ // Put the remaining on a list. If this list has more than one entry
+ // ask the user which interface to listen to.
+ }
+ else
+ {
+ return 1;
+ }
+ }
+ pcap_addr = pcap_addr->next;
+ } // closes while(pcap_addr)
+ }
+ index = index->next;
+ } // closes while (index)
+
+ device_list_entries = i;
+
+ /*
+ if (verbose)
+ {
+ for (i=0; i<device_list_entries; i++)
+ {
+ fprintf(stderr, " mz: Found device %s with IP %s\n", device_list[i].dev, device_list[i].ip_str);
+ }
+ }
+ */
+
+ // No device found:
+ if (device_list_entries==0) return 1;
+
+ // Else device found:
+ // initialize tx.device with first entry of the device_list
+ strncpy (tx.device, device_list[0].dev, 16);
+
+ return 0;
+}
+
+
+
+
+
+
+
+
+// Determines ip and mac address of specified interface 'ifname'
+// Caller must provide an unsigned char ip[4], mac[6]
+//
+int get_if_addr (char *ifname, u_int8_t *ip, u_int8_t *mac)
+{
+ int fd, i;
+ struct ifreq ifr;
+ struct sockaddr_in saddr;
+ u_int8_t *x;
+
+ ifr.ifr_addr.sa_family = AF_INET;
+ strncpy(ifr.ifr_name, ifname , IFNAMSIZ-1);
+
+ // we must open a socket to get the addresses
+ fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (fd == -1) return 1;
+
+ // get mac
+ ioctl(fd, SIOCGIFHWADDR, &ifr);
+ for (i=0; i<6; i++) mac[i]= (u_int8_t) ifr.ifr_hwaddr.sa_data[i];
+
+ // get IP
+ ioctl(fd, SIOCGIFADDR, &ifr);
+ saddr=*((struct sockaddr_in *)(&(ifr.ifr_addr)));
+ x = (u_int8_t*)&saddr.sin_addr;
+ ip[0]=*x; ip[1]=*(x+1); ip[2]=*(x+2); ip[3]=*(x+3);
+
+ close(fd);
+
+
+ return 0;
+}
+
+
+
+
+// For a given device name, find out the following parameters:
+//
+// - MTU
+// - Network
+// - Mask
+// - Default GW (IP)
+// - Default GW (MAC)
+// - Open packet socket (if not already done)
+//
+int get_dev_params (char *name)
+{
+ FILE *fd;
+
+ char f[10][16], line[256];
+ int in=0, nw=1, gw=2, mk=7; // default columns in /proc/net/route for interface, network, gateway, and mask.
+ unsigned int tmp[4], net[4]={0,0,0,0}, dgw[4], mask[4]={0,0,0,0};
+ int i=0, flag=0, nw_found=0, gw_found=0, devind=0, dev_found=0;
+
+ struct ifreq si;
+ struct sockaddr_ll psock;
+ int ps, index, mtu;
+ struct arp_table_struct *cur;
+ // 1. Check if device is already present in our device_list
+
+ for (i=0; i<device_list_entries; i++) {
+ if (strncmp(device_list[i].dev, name, 16)==0) {
+ devind=i;
+ dev_found=1;
+ break;
+ }
+ }
+ if (dev_found==0) return 1; // ERROR: device name not found !!!!
+
+
+
+ // 2. find network, gateway, and mask
+
+ fd = fopen("/proc/net/route", "r");
+ while (fgets(line, 255, fd)!=NULL) {
+ sscanf(line, " %s %s %s %s %s %s %s %s %s %s", f[0], f[1], f[2], f[3], f[4], f[5], f[6], f[7], f[8], f[9]);
+ if (!flag) { // find columns (we do NOT assume that the order of columns is the same everywhere)
+ for (i=0; i<10; i++) {
+ if (strncasecmp(f[i],"iface", 16)==0) in=i;
+ if (strncasecmp(f[i],"destination", 16)==0) nw=i;
+ if (strncasecmp(f[i],"gateway", 16)==0) gw=i;
+ if (strncasecmp(f[i],"mask", 16)==0) mk=i;
+ }
+ flag=1;
+ }
+
+ if (strncmp(f[in], name, 16)==0) { // interface found
+ // Determine network
+ if ((strncmp(f[nw],"00000000",8)!=0) && (strncmp(f[gw],"00000000",8)==0)) {
+ // ignore 169.254 and 127 networks
+ sscanf(f[nw],"%02x%02x%02x%02x",&tmp[3], &tmp[2], &tmp[1], &tmp[0]);
+ if ((tmp[0]!=127) && (tmp[0]!=169)) {
+ nw_found=1;
+ net[0]=tmp[0];
+ net[1]=tmp[1];
+ net[2]=tmp[2];
+ net[3]=tmp[3];
+ // also get mask for that network
+ sscanf(f[mk],"%02x%02x%02x%02x",&tmp[3], &tmp[2], &tmp[1], &tmp[0]);
+ mask[0]=tmp[0];
+ mask[1]=tmp[1];
+ mask[2]=tmp[2];
+ mask[3]=tmp[3];
+ }
+ }
+ // Determine gateway
+ if ((strncmp(f[nw],"00000000",8)==0) && (strncmp(f[gw],"00000000",8)!=0)) {
+ sscanf(f[gw],"%02x%02x%02x%02x",&dgw[3], &dgw[2], &dgw[1], &dgw[0]);
+ gw_found=1;
+ }
+ }
+ }
+
+ fclose(fd);
+
+
+ // 3. Get device index, determine MTU,
+ // and bind socket to device for later TX and RX
+
+ // if socket is already open, then close and re-open it!
+ if (device_list[devind].ps>=0) {
+ close(device_list[devind].ps);
+ device_list[devind].ps=-1;
+ }
+
+ if (device_list[devind].ps<0) {
+ ps = socket (PF_PACKET, SOCK_RAW, htons(ETH_P_IP)); //ETH_P_ALL, ETH_P_802_3);
+ if (ps<0) {
+ fprintf(stderr, " Warning: [lookupdev.c get_dev_params()] Cannot open socket!\n");
+ return 1;
+ }
+
+ // Get device index
+ strncpy(si.ifr_name, name, IFNAMSIZ);
+ if (ioctl(ps, SIOCGIFINDEX, &si)==-1) {
+ perror("ioctl");
+ close(ps);
+ return 1;
+ }
+ index=si.ifr_ifindex;
+
+ // Get MTU
+ if (ioctl(ps, SIOCGIFMTU, &si)==-1) {
+ perror("ioctl");
+ close(ps);
+ return 1;
+ }
+ mtu = si.ifr_mtu;
+
+ // ***** bind socket for later TX and RX ****
+ psock.sll_family = AF_PACKET; // evident
+ // psock.sll_protocol = 0; // unsigned short - Physical layer protocol
+ psock.sll_ifindex = index; // int - Interface number
+ psock.sll_hatype = 0; // unsigned short - Header type //ARPHRD_ETHER
+ psock.sll_pkttype = 0; // unsigned char - Packet type
+ psock.sll_halen = 6; // unsigned char - Length of address
+ bind(ps, (const struct sockaddr *) &psock, sizeof(psock)); // <= !!!
+ device_list[devind].ps = ps; // Note that close(ps) must be done upon termination
+ }
+
+ // Get MAC of default gateway
+ service_arp(name, device_list[devind].ip_gw, device_list[devind].mac_gw);
+
+ usleep(200); // this is a VERY short delay but it usually works in today's LANs
+ cur=device_list[devind].arp_table;
+ while(cur!=NULL) {
+ if ((cur->sip[0]==dgw[0]) &&
+ (cur->sip[1]==dgw[1]) &&
+ (cur->sip[2]==dgw[2]) &&
+ (cur->sip[3]==dgw[3])) { // entry found!
+ for (i=0; i<6; i++) {
+ device_list[devind].mac_gw[i] = cur->smac[i];
+ }
+ }
+ cur=cur->next;
+ }
+
+ // FINALLY: Copy findings in device_list
+
+ if (device_list[devind].phy) {
+ for (i=0; i<4; i++) {
+ device_list[devind].net[i] = net[i];
+ device_list[devind].mask[i] = mask[i];
+ device_list[devind].ip_gw[i] = dgw[i];
+ }
+ }
+ else {
+ for (i=0; i<4; i++) {
+ device_list[devind].net[i] = 0;
+ device_list[devind].mask[i] = 0;
+ device_list[devind].ip_gw[i] = 0;
+ }
+ }
+
+ device_list[devind].index = index;
+ device_list[devind].mtu = mtu;
+
+ return 0;
+}
+
diff --git a/staging/mausezahn.c b/staging/mausezahn.c
new file mode 100644
index 0000000..7f712b7
--- /dev/null
+++ b/staging/mausezahn.c
@@ -0,0 +1,1013 @@
+/*
+ * netsniff-ng - the packet sniffing beast
+ * Mausezahn, a fast versatile traffic generator
+ * Copyright 2008, 2009, 2010 Herbert Haas.
+ * Subject to the GPL, version 2.
+ */
+
+#define _GNU_SOURCE
+#include <libnet.h>
+#include <pcap/pcap.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <limits.h>
+#include <sys/time.h>
+#include <time.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <stdarg.h>
+
+#include "mz.h"
+#include "cli.h"
+#include "mops.h"
+#include "llist.h"
+#include "die.h"
+
+int verbose_level = 0;
+
+static const char *short_options = "46hqvVSxra:A:b:B:c:d:E:f:F:p:P:t:T:M:Q:X:";
+
+static void signal_handler(int number)
+{
+ clean_up(number);
+}
+
+void clean_up(int sig)
+{
+ int i;
+ struct arp_table_struct *cur, *next;
+
+ if (!quiet) fprintf(stderr, "\nMausezahn cleans up...\n");
+
+ if (fp != NULL) {
+ verbose_l1(" close files (1) ...\n");
+
+ fflush(fp);
+ fclose(fp);
+ }
+
+ if (fp2!=NULL) {
+ if (verbose) fprintf(stderr, " close files (2) ...\n");
+ (void) fflush(fp2);
+ (void) fclose(fp2);
+ }
+
+ // interactive mode?
+ if (mz_port) {
+ if (verbose) fprintf(stderr, " clear mops list...\n");
+ mops_cleanup(mp_head);
+ if (verbose) fprintf(stderr, " clear automops list...\n");
+ automops_cleanup(amp_head);
+ if (verbose) fprintf(stderr, " clear packet sequences...\n");
+ mz_ll_delete_list(packet_sequences);
+ }
+
+ for (i=0; i<device_list_entries; i++) {
+ if (device_list[i].p_arp!=NULL) {
+ pcap_close(device_list[i].p_arp);
+ fprintf(stderr, " stopped ARP process for device %s\n", device_list[i].dev);
+ }
+ if (device_list[i].arprx_thread!=0) {
+ pthread_cancel(device_list[i].arprx_thread);
+ if (verbose)
+ fprintf(stderr, " (ARP thread for device %s done)\n", device_list[i].dev);
+ }
+
+ if (device_list[i].arp_table!=NULL) {
+ cur=device_list[i].arp_table;
+ while (cur!=NULL) {
+ next = cur->next;
+ if (cur!=NULL) free(cur);
+ cur=next;
+ }
+ }
+
+ // close packet sockets
+ if (device_list[i].ps>=0) {
+ close(device_list[i].ps);
+ }
+
+ }
+
+ if (verbose) fprintf(stderr, "finished.\n");
+ exit(sig);
+}
+
+
+static void help(void)
+{
+ printf("\nmausezahn %s, a fast versatile traffic generator\n", VERSION_STRING);
+ puts("http://www.netsniff-ng.org\n\n"
+ "Usage: mausezahn [options] [interface] <keyword>|<arg-string>|<hex-string>\n"
+ "Options:\n"
+ " -x <port> Interactive mode with telnet CLI, default port: 25542\n"
+ " -4 IPv4 mode (default)\n"
+ " -6 IPv6 mode\n"
+ " -c <count> Send packet count times, default:1, infinite:0\n"
+ " -d <delay> Apply delay between transmissions. The delay value can be\n"
+ " specified in usec (default, no additional unit needed), or in\n"
+ " msec (e.g. 100m or 100msec), or in seconds (e.g. 100s or 100sec)\n"
+ " -r Multiplies the specified delay with a random value\n"
+ " -p <length> Pad the raw frame to specified length (using random bytes)\n"
+ " -a <srcmac|keyword> Use specified source mac address, no matter what has\n"
+ " been specified with other arguments; keywords see below,\n"
+ " Default is own interface\n"
+ " -b <dstmac|keyword> Same with destination mac address; keywords:\n"
+ " rand Use a random MAC address\n"
+ " bc Use a broadcast MAC address\n"
+ " own Use own interface MAC address (default for source MAC)\n"
+ " stp Use IEEE 802.1d STP multicast address\n"
+ " cisco Use Cisco multicast address as used for CDP, VTP, or PVST+\n"
+ " -A <srcip> Use specified source IP address (default is own interface IP)\n"
+ " -B <dstip|dnsname> Send packet to specified destination IP or domain name\n"
+ " -P <ascii payload> Use the specified ASCII payload\n"
+ " -f <filename> Read the ASCII payload from a file\n"
+ " -F <filename> Read the hexadecimal payload from a file\n"
+ " -Q <[CoS:]vlan> Specify 802.1Q VLAN tag and optional Class of Service, you can\n"
+ " specify multiple 802.1Q VLAN tags (QinQ...) by separating them\n"
+ " via a comma or a period (e.g. '5:10,20,2:30')\n"
+ " -t <packet-type> Specify packet type for autobuild (you don't need to care for\n"
+ " encapsulations in lower layers, most packet types allow/require\n"
+ " additional packet-specific arguments in an <arg-string>;\n"
+ " Currently supported types: arp, bpdu, cdp, ip, icmp, udp, tcp,\n"
+ " dns, rtp, syslog, lldp and more;\n"
+ " For context-help use 'help' as <arg-string>!\n"
+ " -T <packet-type> Specify packet type for server mode, currently only rtp is supported;\n"
+ " Enter -T help or -T rtp help for further information\n"
+ " -M <MPLS-label> Insert a MPLS label, enter '-M help' for a syntax description\n"
+ " -V|VV|... Verbose and more verbose mode\n"
+ " -q Quiet mode, even omit 'important' standard short messages\n"
+ " -S Simulation mode: DOES NOT put anything on the wire, this is\n"
+ " typically combined with one of the verbose modes (v or V)\n"
+ " -v Show version\n"
+ " -h Print this help\n\n"
+ "Examples:\n"
+ " mausezahn -x 99\n"
+ " mausezahn -c 0 -d 2s -t bpdu conf\n"
+ " mausezahn -t cdp change -c 0\n"
+ " mausezahn -t syslog sev=3 -P \"You have been mausezahned.\" -A 10.1.1.109 -B 192.168.7.7\n"
+ " mausezahn eth0 -A rand -B 1.1.1.1 -c 0 -t tcp \"dp=1-1023, flags=syn\"\n\n"
+ "Note:\n"
+ " This tool is targeted for network developers! You should\n"
+ " be aware of what you are doing and what these options above\n"
+ " mean! Only use this tool in an isolated LAN that you own!\n\n"
+ "Please report bugs to <bugs@netsniff-ng.org>\n"
+ "Copyright (C) 2008-2010 Herbert Haas <herbert@perihel.at>,\n"
+ "Copyright (C) 2011 Daniel Borkmann <dborkma@tik.ee.ethz.ch>,\n"
+ "Swiss federal institute of technology (ETH Zurich)\n"
+ "License: GNU GPL version 2.0\n"
+ "This is free software: you are free to change and redistribute it.\n"
+ "There is NO WARRANTY, to the extent permitted by law.\n");
+ die();
+}
+
+static void version(void)
+{
+ printf("\nmausezahn %s, a fast versatile traffic generator\n", VERSION_STRING);
+ puts("http://www.netsniff-ng.org\n\n"
+ "Please report bugs to <bugs@netsniff-ng.org>\n"
+ "Copyright (C) 2008-2010 Herbert Haas <herbert@perihel.at>,\n"
+ "Copyright (C) 2011 Daniel Borkmann <dborkma@tik.ee.ethz.ch>,\n"
+ "Swiss federal institute of technology (ETH Zurich)\n"
+ "License: GNU GPL version 2.0\n"
+ "This is free software: you are free to change and redistribute it.\n"
+ "There is NO WARRANTY, to the extent permitted by law.\n");
+ die();
+}
+
+int reset()
+{
+ int i;
+ time_t t;
+
+ // Determine platform type sizes:
+ MZ_SIZE_LONG_INT = sizeof(long int);
+
+ mz_default_config_path[0] = 0x00;
+ mz_default_log_path[0] = 0x00;
+
+ // Reset globals:
+ quiet = 0;
+ ipv6_mode = 0;
+ verbose = 0;
+ simulate = 0;
+ filename[0] = '\0';
+ path[0] = '\0';
+ gind=0;
+ gind_max = TIME_COUNT;
+ fp = NULL;
+ fp2 = NULL;
+ mz_port = 0;
+ mz_rand = 0;
+ mp_head = NULL;
+
+ for (i=0;i<TIME_COUNT_MAX;i++) jitter[i] = 0;
+
+ time0_flag = 0; // If set then time0 has valid data
+ sqnr0_flag = 0; // If set then sqnr_last and sqnr_next has valid data
+ rtp_log = 0;
+ mz_ssrc[0]=0; mz_ssrc[1]=0; mz_ssrc[2]=0; mz_ssrc[3]=0;
+
+ // Reset mgmt parameters of TX:
+ tx.packet_mode = 1; // assume we don't care about L2
+ tx.count = 1;
+ tx.delay = DEFAULT_DELAY;
+ tx.arg_string[0] = '\0';
+
+ // Reset Ethernet parameters of TX:
+ tx.eth_params_already_set = 0;
+ for (i=0; i<6; i++) tx.eth_dst[i] = 0xff;
+ for (i=0; i<6; i++) tx.eth_src[i] = 0; // TODO: Get own MAC !!!
+ tx.eth_dst_txt[0] = '\0';
+ tx.eth_src_txt[0] = '\0';
+ tx.eth_dst_rand = 0;
+ tx.eth_src_rand = 0;
+
+ tx.eth_type = 0x800;
+ tx.eth_len = 0;
+ tx.eth_payload[0] = '\0';
+ tx.eth_payload_s = 0;
+ tx.padding = 0;
+
+ // Reset CDP parameters for TX:
+ tx.cdp_sum = 0;
+ tx.cdp_version = 0;
+ tx.cdp_ttl = 0;
+ tx.cdp_payload[0] = '\0';
+ tx.cdp_payload_s = 0;
+ tx.cdp_tlv_id[0] = '\0';
+ tx.cdp_tlv_id_len = 0;
+
+ // Reset 802.1Q parameters of TX:
+ tx.dot1Q=0;
+ tx.dot1Q_txt[0] = '\0';
+
+ // ASCII Payload:
+ tx.ascii = 0; // 1 if specified
+ tx.ascii_payload[0]= '\0';
+
+ // HEX Payload:
+ tx.hex_payload_s = 0;
+
+ // Reset MPLS parameters of TX:
+ tx.mpls = 0;
+ tx.mpls_txt[0] = '\0';
+ tx.mpls_label = 0;
+ tx.mpls_exp = 0;
+ tx.mpls_bos = 1;
+ tx.mpls_ttl = 255;
+ tx.mpls_verbose_string[0] = '\0';
+
+ // Reset IP parameters of TX:
+ tx.ip_src_txt[0] = '\0';
+ tx.ip_src_rand = 0;
+ tx.ip_dst_txt[0] = '\0';
+ tx.ip_src_isrange = 0;
+ tx.ip_src_start = 0;
+ tx.ip_src_stop = 0;
+
+ tx.ip_dst_start = 0;
+ tx.ip_dst_stop = 0;
+ tx.ip_dst_isrange = 0;
+
+ tx.ip_len = 0;
+ tx.ip_payload[0]= '\0';
+ tx.ip_payload_s = 0;
+ tx.ip_option[0]= '\0';
+ tx.ip_option_s = 0;
+
+ // Reset ICMP parameters:
+ tx.icmp_type=0;
+ tx.icmp_code=0;
+ tx.icmp_chksum=0; // 0=autofill
+ tx.icmp_ident=0x42;
+ tx.icmp_sqnr=0x1;
+ tx.icmp_payload_s=0;
+
+ // Reset general L4 parameters:
+ tx.sp = 0;
+ tx.dp = 0;
+ tx.sp_start = 0;
+ tx.sp_stop = 0;
+ tx.dp_start = 0;
+ tx.dp_stop = 0;
+ tx.sp_isrange = 0;
+ tx.dp_isrange = 0;
+
+ // Reset UDP parameters of TX:
+
+ tx.udp_len = 0; // If set to zero then create_udp_packet will calculate it
+ tx.udp_sum = 0;
+ tx.udp_payload[0] = '\0';
+ tx.udp_payload_s = 0;
+
+ // Reset TCP parameters of TX:
+
+ tx.tcp_seq = 42;
+ tx.tcp_seq_stop = 42;
+ tx.tcp_seq_delta = 0; // also used as 'isrange' meaning
+ tx.tcp_ack = 42;
+ tx.tcp_control = 0;
+ tx.tcp_win = 10000;
+ tx.tcp_sum = 0;
+ tx.tcp_urg = 0;
+ tx.tcp_len = 20; // Least size (TCP header only)
+ tx.tcp_payload[0] = '\0';
+ tx.tcp_payload_s = 0;
+
+ // Reset RTP parameters of TX:
+ tx.rtp_sqnr = 0;
+ tx.rtp_stmp = 0;
+
+ // Initialize random generator
+ time(&t);
+ srand((unsigned int)t);
+
+ // Reset device_list
+ for (i=0; i<MZ_MAX_DEVICES; i++) {
+ device_list[i].arprx_thread = 0;
+ device_list[i].p_arp = NULL;
+ device_list[i].arp_table = NULL;
+ device_list[i].ps=-1;
+ device_list[i].cli=0;
+ device_list[i].mgmt_only=0;
+ }
+
+ return 0;
+}
+
+
+
+// Purpose: Properly handle arguments and configure global structs (tx)
+int getopts (int argc, char *argv[])
+{
+ int i, c, rargs, RX=0, count_set=0, delay_set=0;
+ unsigned int time_factor;
+ char *packet_type=NULL, *mops_type=NULL;
+ char *dum;
+ unsigned char *dum1, *dum2;
+
+ libnet_t *l;
+ char err_buf[LIBNET_ERRBUF_SIZE];
+ struct libnet_ether_addr *mymac;
+
+ FILE *afp;
+ char hexpld[MAX_PAYLOAD_SIZE*2];
+ int hexpld_specified=0;
+
+ opterr = 1; // let getopt print error message if necessary
+
+
+ while ((c = getopt(argc, argv, short_options)) != -1)
+ switch (c) {
+ case '4':
+ tx.eth_type = 0x0800;
+ ipv6_mode=0;
+ break;
+ case '6':
+ tx.eth_type = 0x86dd;
+ ipv6_mode=1;
+ break;
+ case 'h':
+ help();
+ break;
+ case 'q':
+ quiet=1;
+ break;
+ case 'v':
+ version();
+ break;
+ case 'V':
+ verbose++;
+ break;
+ case 'S':
+ simulate=1;
+ break;
+ case 'x':
+ mz_port = MZ_DEFAULT_PORT;
+ break;
+ case 'a':
+ strncpy (tx.eth_src_txt, optarg, 32);
+ tx.packet_mode = 0;
+ break;
+ case 'A':
+ strncpy (tx.ip_src_txt, optarg, sizeof(tx.ip_src_txt));
+ break;
+ case 'b':
+ strncpy (tx.eth_dst_txt, optarg, 32);
+ tx.packet_mode = 0;
+ break;
+ case 'B':
+ strncpy (tx.ip_dst_txt, optarg, sizeof(tx.ip_dst_txt));
+ break;
+ case 'c':
+ errno=0;
+ tx.count = strtol(optarg, (char **)NULL, 10);
+ if ((errno == ERANGE && (tx.count == LONG_MAX || tx.count == LONG_MIN))
+ || (errno != 0 && tx.count == 0)) {
+ perror("strtol");
+ return (-1);
+ }
+ if (tx.count<0) tx.count=1; //TODO: Allow count=0 which means infinity (need to update all send_functions)
+ count_set=1;
+ break;
+ case 'd':
+ errno=0;
+ // determine whether seconds or msecs are used
+ // default is usec!!!
+ time_factor=1;
+ if (exists(optarg,"s") || exists(optarg,"sec")) time_factor=1000000;
+ if (exists(optarg,"m") || exists(optarg,"msec")) time_factor=1000;
+ dum = strtok(optarg,"ms");
+ tx.delay = strtol(dum, (char **)NULL, 10) * time_factor;
+ if ((errno == ERANGE && (tx.delay == LONG_MAX || tx.delay == LONG_MIN))
+ || (errno != 0 && tx.delay == 0)) {
+ perror("strtol");
+ return (-1);
+ }
+ if (tx.delay<0) tx.delay=0; // no delay
+ delay_set=1;
+ break;
+ case 'p':
+ errno=0;
+ tx.padding = strtol(optarg, (char **)NULL, 10);
+ if ((errno == ERANGE && (tx.padding == LONG_MAX || tx.padding == LONG_MIN))
+ || (errno != 0 && tx.padding == 0)) {
+ perror("strtol");
+ return (-1);
+ }
+ if (tx.padding>10000) {
+ fprintf(stderr, " Warning: Padding must not exceed 10000!\n");
+ return -1;
+ }
+ break;
+ case 't':
+ packet_type = optarg; // analyzed below
+ break;
+ case 'X':
+ mops_type = optarg; // MOPS TRANSITION STRATEGY -- analyzed below
+ break;
+ case 'T':
+ packet_type = optarg;
+ RX = 1;
+ break;
+ case 'r':
+ mz_rand = 1;
+ break;
+ case 'M':
+ if (strncmp(optarg,"help",4)==0) {
+ (void) get_mpls_params("help ");
+ }
+ else {
+ strncpy (tx.mpls_txt, optarg, 128);
+ tx.eth_type = ETHERTYPE_MPLS;
+ tx.packet_mode = 0;
+ tx.mpls=1;
+ }
+ break;
+ case 'P': // ASCII payload
+ strncpy((char*)tx.ascii_payload, optarg, MAX_PAYLOAD_SIZE);
+ tx.ascii = 1;
+ break;
+ case 'f': // ASCII payload in FILE
+ afp = fopen(optarg, "r");
+ if (fgets((char*)tx.ascii_payload, MAX_PAYLOAD_SIZE, afp) == NULL)
+ fprintf(stderr, " mz/getopts: File empty?\n");
+ fclose(afp);
+ tx.ascii = 1;
+ break;
+ case 'F': // HEX payload in FILE
+ afp = fopen(optarg, "r");
+ i=0;
+ while ( (hexpld[i]=fgetc(afp))!=EOF ) {
+ if (isspace(hexpld[i])) {
+ hexpld[i]=':';
+ }
+ i++;
+ }
+ hexpld[i]='\0';
+ fclose(afp);
+ hexpld_specified=1;
+ break;
+ case 'Q': // VLAN TAG
+ if (strncmp(optarg,"help",4)==0) {
+ print_dot1Q_help(); // ugly but most simple and safe solution
+ }
+ else {
+ strncpy (tx.dot1Q_txt, optarg, 32);
+ tx.dot1Q=1;
+ // determine number of VLAN tags
+ for (i=0; i<strlen(tx.dot1Q_txt); i++) {
+ if (tx.dot1Q_txt[i]==',') tx.dot1Q++;
+ }
+ tx.packet_mode = 0;
+ }
+ break;
+ case '?':
+ if ((optopt == 'a') || (optopt == 'b') || (optopt = 'c') ||
+ (optopt == 'd') || (optopt == 'f') || (optopt = 'p') ||
+ (optopt == 't') || (optopt == 'm'))
+ fprintf (stderr, " mz/getopts: Option -%c requires an argument.\n", optopt);
+ else if (isprint (optopt))
+ fprintf (stderr, " mz/getopts: Unknown option -%c'.\n", optopt);
+ else
+ fprintf (stderr, " mz/getopts: Unknown option character \\x%x'.\n", optopt);
+ return 1;
+ default:
+ fprintf (stderr," mz/getopts: Could not handle arguments properly!\n");
+ return 1;
+ }
+
+ // ********************************************
+ // Handle additional arguments
+ // ********************************************
+ //
+ // Greeting text
+ if (verbose) {
+ fprintf(stderr,"\n"
+ MAUSEZAHN_VERSION
+ "\n"
+ "Use at your own risk and responsibility!\n"
+ "-- Verbose mode --\n"
+ "\n");
+ }
+
+ if (argc<2) {
+ help();
+ }
+
+ if ((rargs=argc-optind)>2) { // number of remaining arguments
+ fprintf(stderr," mz/getopts: Too many arguments!\n");
+ return -1;
+ }
+
+
+ // There can be 0-2 additional arguments
+ switch (rargs) {
+ case 0:
+ if (lookupdev()) { // no device found
+ if (verbose) fprintf(stderr, " mz: no active interfaces found!\n");
+ strcpy(tx.device, "lo");
+ }
+ if (verbose) // device found
+ fprintf(stderr," mz: device not given, will use %s\n",tx.device);
+ break;
+ case 1: // arg_string OR device given => find out!
+ if ( (strncmp(argv[optind],"eth",3)==0)
+ || (strncmp(argv[optind],"ath",3)==0)
+ || ((strncmp(argv[optind],"lo",2)==0)&&(strncmp(argv[optind],"log",3)!=0))
+ || (strncmp(argv[optind],"vmnet",5)==0)
+ || (strncmp(argv[optind],"wifi",4)==0) ) {
+ // device has been specified!
+ strncpy (tx.device, argv[optind], 16);
+ }
+ else { /// arg_string given => no device has been specified -- let's find one!
+ strncpy (tx.arg_string, argv[optind], MAX_PAYLOAD_SIZE);
+ if (lookupdev()) { // no device found
+ if (verbose) fprintf(stderr, " mz: no active interfaces found!\n");
+ strcpy(tx.device, "lo");
+ }
+ if (verbose)
+ fprintf(stderr," mz: device not given, will use %s\n",tx.device);
+ }
+ break;
+ case 2: // both device and arg_string given
+ strncpy (tx.device, argv[optind], 16);
+ strncpy (tx.arg_string, argv[optind+1], MAX_PAYLOAD_SIZE);
+ break;
+ default:
+ fprintf(stderr," mz/getopts: Unknown argument problem!\n");
+ return 1;
+ }
+
+ if (hexpld_specified) {
+ strcat(tx.arg_string, ",p=");
+ strcat(tx.arg_string, hexpld);
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////
+ //
+ // Initialize MAC and IP Addresses.
+ //
+ // - tx.eth_src = own interface MAC
+ // - tx.ip_src = own interface IP or user specified
+ // - tx.ip_dst = 255.255.255.255 or user specified (can be a range)
+ // - tx.ip_src_rand ... is set if needed.
+ //
+
+ // Get own device MAC address:
+ // Don't open context if only a help text is requested
+ if (getarg(tx.arg_string,"help", NULL)!=1) {
+ l = libnet_init (LIBNET_LINK_ADV, tx.device, err_buf );
+ if (l == NULL) {
+ fprintf(stderr, " mz/getopts: libnet_init() failed (%s)", err_buf);
+ return -1;
+ }
+ mymac = libnet_get_hwaddr(l);
+ for (i=0; i<6; i++) {
+ tx.eth_src[i] = mymac->ether_addr_octet[i];
+ tx.eth_mac_own[i] = mymac->ether_addr_octet[i];
+ }
+
+ // Set source IP address:
+ if (strlen(tx.ip_src_txt)) { // option -A has been specified
+ if (mz_strcmp(tx.ip_src_txt, "bcast", 2)==0) {
+ tx.ip_src = libnet_name2addr4 (l, "255.255.255.255", LIBNET_DONT_RESOLVE);
+ } else if (strcmp(tx.ip_src_txt, "rand") == 0) {
+ tx.ip_src_rand = 1;
+ tx.ip_src_h = (u_int32_t) ( ((float) rand()/RAND_MAX)*0xE0000000); //this is 224.0.0.0
+ }
+ else if (get_ip_range_src(tx.ip_src_txt)) { // returns 1 when no range has been specified
+ // name2addr4 accepts a DOTTED DECIMAL ADDRESS or a FQDN:
+ if (ipv6_mode)
+ tx.ip6_src = libnet_name2addr6 (l, tx.ip_src_txt, LIBNET_RESOLVE);
+ else
+ tx.ip_src = libnet_name2addr4 (l, tx.ip_src_txt, LIBNET_RESOLVE);
+ }
+ }
+ else { // no source IP specified: by default use own IP address
+ if (ipv6_mode) {
+ tx.ip6_src = libnet_get_ipaddr6(l);
+ if (strncmp((char*)&tx.ip6_src,(char*)&in6addr_error,sizeof(in6addr_error))==0)
+ printf("Failed to set source IPv6 address: %s", l->err_buf);
+ }
+ else
+ tx.ip_src = libnet_get_ipaddr4(l);
+ }
+
+ // Set destination IP address:
+ if (strlen(tx.ip_dst_txt)) { // option -B has been specified
+ if (mz_strcmp(tx.ip_dst_txt, "rand", 2)==0) {
+ fprintf(stderr, "Option -B does not support random destination IP addresses currently.\n");
+ return 1;
+ }
+
+ if (mz_strcmp(tx.ip_dst_txt, "bcast", 2)==0) {
+ tx.ip_dst = libnet_name2addr4 (l, "255.255.255.255", LIBNET_DONT_RESOLVE);
+ } else if (get_ip_range_dst(tx.ip_dst_txt)) { // returns 1 when no range has been specified
+ // name2addr4 accepts a DOTTED DECIMAL ADDRESS or a FQDN:
+ if (ipv6_mode)
+ tx.ip6_dst = libnet_name2addr6 (l, tx.ip_dst_txt, LIBNET_RESOLVE);
+ else
+ tx.ip_dst = libnet_name2addr4 (l, tx.ip_dst_txt, LIBNET_RESOLVE);
+ }
+ }
+ else { // no destination IP specified: by default use broadcast
+ tx.ip_dst = libnet_name2addr4 (l, "255.255.255.255", LIBNET_DONT_RESOLVE);
+ }
+
+ // Initialize tx.ip_src_h and tx.ip_dst_h which are used by 'print_frame_details()'
+ // in verbose mode. See 'modifications.c'.
+
+ if (tx.ip_src_rand) { // ip_src_h already given, convert to ip_src
+ dum1 = (unsigned char*) &tx.ip_src_h;
+ dum2 = (unsigned char*) &tx.ip_src;
+ }
+ else { // ip_src already given, convert to ip_src_h
+ dum1 = (unsigned char*) &tx.ip_src;
+ dum2 = (unsigned char*) &tx.ip_src_h;
+ }
+
+ *dum2 = *(dum1+3);
+ dum2++;
+ *dum2 = *(dum1+2);
+ dum2++;
+ *dum2 = *(dum1+1);
+ dum2++;
+ *dum2 = *dum1;
+
+ dum1 = (unsigned char*) &tx.ip_dst;
+ dum2 = (unsigned char*) &tx.ip_dst_h;
+
+ *dum2 = *(dum1+3);
+ dum2++;
+ *dum2 = *(dum1+2);
+ dum2++;
+ *dum2 = *(dum1+1);
+ dum2++;
+ *dum2 = *dum1;
+
+ libnet_destroy(l);
+ }
+
+ //
+ // END OF ADDRESS INITIALIZATION
+ //
+ //////////////////////////////////////////////////////////////////////////
+
+
+ ////// retrieve interface parameters ///////
+
+ for (i=0; i<device_list_entries; i++) {
+ get_dev_params(device_list[i].dev);
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////
+ //
+ // Mausezahn CLI desired?
+ if (mz_port) {
+ // has port number been specified?
+ if (strlen(tx.arg_string)) {
+ mz_port = (int) str2int (tx.arg_string);
+ }
+
+ if (!quiet) {
+ fprintf(stderr, "Mausezahn accepts incoming Telnet connections on port %i.\n", mz_port);
+ }
+
+ mz_cli_init();
+ cli();
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ //
+ // Mode decision
+ //
+ // Consider -t and -m option (used exclusively)
+ // -t => special packet types, stateless
+ //
+ // If -t not present then evaluate arg_string which must
+ // contain a byte-string in hexadecimal notation.
+ //
+ //
+
+ // ***** NEW: MOPS TRANSITION STRATEGY *****
+ if (mops_type != NULL) {
+
+ if (mz_strcmp(mops_type,"lldp",4)==0) {
+ mops_direct(tx.device, MOPS_LLDP, tx.arg_string);
+ }
+ }
+
+
+ if (packet_type == NULL) { // raw hex string given
+ mode = BYTE_STREAM;
+ }
+ else if (strcmp(packet_type,"arp")==0) {
+ mode = ARP;
+ }
+ else if (strcmp(packet_type,"bpdu")==0) {
+ mode = BPDU;
+ }
+ else if (strcmp(packet_type,"ip")==0) {
+ mode = IP;
+ }
+ else if (strcmp(packet_type,"udp")==0) {
+ mode = UDP;
+ }
+ else if (strcmp(packet_type,"icmp")==0) {
+ mode = ICMP;
+ }
+ else if (strcmp(packet_type,"icmp6")==0) {
+ mode = ICMP6;
+ }
+ else if (strcmp(packet_type,"tcp")==0) {
+ mode = TCP;
+ }
+ else if (strcmp(packet_type,"dns")==0) {
+ mode = DNS;
+ }
+ else if (strcmp(packet_type,"cdp")==0) {
+ mode = CDP;
+ }
+ else if (strcmp(packet_type,"syslog")==0) {
+ mode = SYSLOG;
+ }
+ else if (strcmp(packet_type,"lldp")==0) {
+ mode = LLDP;
+ tx.packet_mode=0; // create whole frame by ourself
+ }
+ else if (strcmp(packet_type,"rtp")==0) {
+ if (RX) {
+ mode = RX_RTP;
+ }
+ else {
+ mode = RTP;
+ if (!count_set) tx.count = 0;
+ if (!delay_set) tx.delay = 20000; // 20 msec inter-packet delay for RTP
+ }
+ }
+ else if (strcmp(packet_type,"help")==0) {
+ fprintf(stderr, "\n"
+ MAUSEZAHN_VERSION
+ "\n"
+ "| The following packet types are currently implemented:\n"
+ "|\n"
+ "| arp ... sends ARP packets\n"
+ "| bpdu ... sends BPDU packets (STP or PVST+)\n"
+ "| cdp ... sends CDP messages\n"
+ "| ip ... sends IPv4 packets\n"
+ "| udp ... sends UDP datagrams\n"
+ "| tcp ... sends TCP segments\n"
+ "| icmp ... sends ICMP messages\n"
+ "| dns ... sends DNS messages\n"
+ "| rtp ... sends RTP datagrams\n"
+ "| syslog ... sends Syslog messages\n"
+ "|\n"
+ "| Of course you can build any other packet type 'manually' using the direct layer 2 mode.\n"
+ "| FYI: The interactive mode supports additional protocols. (Try mz -x <port>)\n"
+ "\n"
+ );
+ exit(1);
+ }
+ else {
+ fprintf(stderr, " mz: you must specify a valid packet type!\n");
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////
+
+ // TODO: Implement macro support
+ // Check macro types here
+
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ // These handles are only used when creating L3 and above packets.
+ libnet_t *l; // the context
+ libnet_ptag_t t2=0, t3=0, t4=0; // handles to layers
+ double cpu_time_used;
+
+ reset();
+
+ if ( getopts(argc, argv) )
+ {
+ (void) fprintf(stderr, " Invalid command line parameters!\n");
+ help();
+ }
+
+ // Check whether hires timers are supported or not:
+ (void) check_timer();
+
+ signal(SIGINT, signal_handler); // to close all file pointers etc upon SIGINT
+
+ switch (mode)
+ {
+ case BYTE_STREAM:
+ send_eth();
+ break;
+
+ case ARP:
+ (void) send_arp();
+ break;
+
+ case BPDU:
+ (void) send_bpdu();
+ break;
+
+ case CDP:
+ (void) send_cdp();
+ break;
+
+ case IP: // From now on a new much more modular method is used:
+ l = get_link_context();
+ t3 = create_ip_packet(l); // t3 can be used for later header changes
+ if (!quiet) complexity();
+ if (tx.packet_mode==0) // Ethernet manipulation features does NOT use ARP to determine eth_dst
+ t2 = create_eth_frame(l, t3, t4); // t2 can be used for later header changes
+ else
+ send_frame (l, t3, t4); // NOTE: send_frame also destroys context finaly
+ break;
+
+ case ICMP:
+ tx.ip_proto = 1;
+ l = get_link_context();
+ t4 = create_icmp_packet(l); // t4 can be used for later header changes
+ t3 = create_ip_packet(l); // t3 can be used for later header changes
+ if (!quiet) complexity();
+ if (tx.packet_mode==0) // Ethernet manipulation features does NOT use ARP to determine eth_dst
+ t2 = create_eth_frame(l, t3, t4); // t2 can be used for later header changes
+ else
+ send_frame (l, t3, t4); // NOTE: send_frame also destroys context finaly
+ break;
+
+ case ICMP6:
+ tx.ip_proto = 58;
+ l = get_link_context();
+ t4 = create_icmp6_packet(l); // t4 can be used for later header changes
+ t3 = create_ip_packet(l); // t3 can be used for later header changes
+ if (ipv6_mode)
+ update_ISUM(l, t4);
+ if (!quiet) complexity();
+ if (tx.packet_mode==0) // Ethernet manipulation features does NOT use ARP to determine eth_dst
+ t2 = create_eth_frame(l, t3, t4); // t2 can be used for later header changes
+ else
+ send_frame (l, t3, t4); // NOTE: send_frame also destroys context finaly
+ break;
+
+ case UDP:
+ tx.ip_proto = 17;
+ l = get_link_context();
+ t4 = create_udp_packet(l); // t4 can be used for later header changes
+ t3 = create_ip_packet(l); // t3 can be used for later header changes
+ if (ipv6_mode)
+ update_USUM(l, t4);
+ if (!quiet) complexity();
+ if (tx.packet_mode==0) // Ethernet manipulation features does NOT use ARP to determine eth_dst
+ t2 = create_eth_frame(l, t3, t4); // t2 can be used for later header changes
+ else
+ send_frame (l, t3, t4); // NOTE: send_frame also destroys context finaly
+ break;
+
+ case TCP:
+ tx.ip_proto = 6;
+ l = get_link_context();
+ t4 = create_tcp_packet(l); // t4 can be used for later header changes
+ t3 = create_ip_packet(l); // t3 can be used for later header changes
+ if (ipv6_mode)
+ update_TSUM(l, t4);
+ if (!quiet) complexity();
+ if (tx.packet_mode==0) // Ethernet manipulation features does NOT use ARP to determine eth_dst
+ t2 = create_eth_frame(l, t3, t4); // t2 can be used for later header changes
+ else
+ send_frame (l, t3, t4); // NOTE: send_frame also destroys context finaly
+ break;
+
+ case DNS:
+ tx.ip_proto = 17;
+ l = get_link_context();
+ (void) create_dns_packet();
+ t4 = create_udp_packet(l); // t4 can be used for later header changes
+ t3 = create_ip_packet(l); // t3 can be used for later header changes
+ if (!quiet) complexity();
+ if (tx.packet_mode==0) // Ethernet manipulation features does NOT use ARP to determine eth_dst
+ t2 = create_eth_frame(l, t3, t4); // t2 can be used for later header changes
+ else
+ send_frame (l, t3, t4); // NOTE: send_frame also destroys context finaly
+ break;
+
+ case RTP:
+ tx.ip_proto = 17;
+ l = get_link_context();
+ if (!quiet) fprintf(stderr, " mz: RTP mode! (count=%u, delay=%u usec)\n\n", tx.count, tx.delay);
+ (void) create_rtp_packet();
+ t4 = create_udp_packet(l); // t4 can be used for later header changes
+ t3 = create_ip_packet(l); // t3 can be used for later header changes
+ if (!quiet) complexity();
+ if (tx.packet_mode==0) // Ethernet manipulation features does NOT use ARP to determine eth_dst
+ t2 = create_eth_frame(l, t3, t4); // t2 can be used for later header changes
+ else
+ send_frame (l, t3, t4); // NOTE: send_frame also destroys context finaly
+ break;
+
+ case RX_RTP: // Receive RTP packets
+ rcv_rtp_init();
+ rcv_rtp();
+ break;
+
+ case SYSLOG:
+ tx.ip_proto = 17;
+ l = get_link_context();
+ (void) create_syslog_packet();
+ t4 = create_udp_packet(l); // t4 can be used for later header changes
+ t3 = create_ip_packet(l); // t3 can be used for later header changes
+ if (!quiet) complexity();
+
+ if (tx.packet_mode==0) // Ethernet manipulation features does NOT use ARP to determine eth_dst
+ t2 = create_eth_frame(l, t3, t4); // t2 can be used for later header changes
+ else
+ send_frame (l, t3, t4); // NOTE: send_frame also destroys context finaly
+ break;
+
+ case LLDP: // start with a new concept here
+ //l = get_link_context();
+ //(void) create_lldp_packet();
+ // // // printf("SIZE=%lu\n",sizeof(struct tx_struct));
+ fprintf(stderr, "LLDP is currently only supported via the interactive mode\n");
+ exit(1);
+ break;
+
+
+ default:
+ (void) fprintf(stderr," mz/main: unknown mode! Stop.\n");
+ return (1);
+ }
+
+ if (!quiet)
+ {
+ mz_stop = clock();
+ cpu_time_used = ((double) (mz_stop - mz_start)) / CLOCKS_PER_SEC;
+ if (cpu_time_used > 0)
+ {
+ total_d /= cpu_time_used;
+ fprintf(stderr, "%.2f seconds (%.Lf packets per second)\n",cpu_time_used,total_d);
+ }
+ else
+ {
+ fprintf(stderr, "\n");
+ }
+ }
+
+ return(0);
+}
diff --git a/staging/modifications.c b/staging/modifications.c
new file mode 100644
index 0000000..3dc2abf
--- /dev/null
+++ b/staging/modifications.c
@@ -0,0 +1,698 @@
+/*
+ * Mausezahn - A fast versatile traffic generator
+ * Copyright (C) 2008-2010 Herbert Haas
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
+ *
+*/
+
+
+
+
+// ***************************************************************************
+//
+// This sections contains functions to manipulate headers of
+// Eth, MPLS, 802.1Q, IP, UDP, and TCP:
+//
+// int update_Eth_SA (libnet_t *l, libnet_ptag_t t)
+// int update_IP_SA (libnet_t *l, libnet_ptag_t t)
+// int update_IP_DA (libnet_t *l, libnet_ptag_t t)
+// int update_DPORT (libnet_t *l, libnet_ptag_t t)
+// int update_SPORT (libnet_t *l, libnet_ptag_t t)
+// int update_TCP_SQNR (libnet_t *l, libnet_ptag_t t)
+//
+// and finally:
+//
+// int print_frame_details()
+//
+// ***************************************************************************
+
+#include "mz.h"
+#include "mops.h"
+
+///////////////////////////////////////////////////////////////////////////
+// Applies another random Ethernet source address to a given Ethernet-PTAG.
+// (The calling function should check 'tx.eth_src_rand' whether the SA
+// should be randomized.)
+//
+int update_Eth_SA(libnet_t *l, libnet_ptag_t t)
+{
+ tx.eth_src[0] = (u_int8_t) ( ((float) rand()/RAND_MAX)*256) & 0xFE; // keeps bcast-bit zero
+ tx.eth_src[1] = (u_int8_t) ( ((float) rand()/RAND_MAX)*256);
+ tx.eth_src[2] = (u_int8_t) ( ((float) rand()/RAND_MAX)*256);
+ tx.eth_src[3] = (u_int8_t) ( ((float) rand()/RAND_MAX)*256);
+ tx.eth_src[4] = (u_int8_t) ( ((float) rand()/RAND_MAX)*256);
+ tx.eth_src[5] = (u_int8_t) ( ((float) rand()/RAND_MAX)*256);
+
+ t = libnet_build_ethernet (tx.eth_dst,
+ tx.eth_src,
+ tx.eth_type,
+ NULL, // the payload
+ 0,
+ l,
+ t);
+
+ if (t == -1)
+ {
+ fprintf(stderr, " mz/update_Eth_SA: Can't build Ethernet header: %s\n",
+ libnet_geterror(l));
+ exit(EXIT_FAILURE);
+ }
+
+ return 0;
+}
+
+
+// Update official timestamp, own timestamp and sequence number in the RTP header.
+// The actual RTP message is stored in tx.udp_payload.
+int update_RTP(libnet_t *l, libnet_ptag_t t)
+{
+ u_int8_t *ptr;
+ struct mz_timestamp ts;
+
+ tx.rtp_sqnr++;
+ tx.rtp_stmp+=160; // TODO: different values for different codecs
+
+ // update SQNR
+ ptr = (u_int8_t*) &tx.rtp_sqnr;
+ tx.udp_payload[2] = *(ptr+1);
+ tx.udp_payload[3] = *ptr;
+
+ // update official timestamp
+ ptr = (u_int8_t*) &tx.rtp_stmp;
+ tx.udp_payload[4] = *(ptr+3);
+ tx.udp_payload[5] = *(ptr+2);
+ tx.udp_payload[6] = *(ptr+1);
+ tx.udp_payload[7] = *ptr;
+
+
+ // update own timestamp
+ getcurtime(&ts); // Now add TX timestamp:
+ mops_hton4 ((u_int32_t*) &ts.sec, &tx.udp_payload[16]);
+ mops_hton4 ((u_int32_t*) &ts.nsec, &tx.udp_payload[20]);
+
+ t = libnet_build_udp(tx.sp,
+ tx.dp,
+ tx.udp_len,
+ tx.udp_sum,
+ tx.udp_payload,
+ tx.udp_payload_s,
+ l,
+ t);
+
+ if (t == -1) {
+ fprintf(stderr," mz/send_frame: RTP header update failed!\n");
+ exit (1);
+ }
+ return 0;
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+// Applies another SOURCE IP address,
+// - either a random one (tx.ip_src_rand==1)
+// - or from a specified range (tx.ip_src_isrange==1)
+// to a given IP-PTAG.
+//
+// Note: tx.ip_src MUST be already initialized with tx.ip_src_start.
+// This is done by 'get_ip_range_src()' in tools.c.
+//
+//
+// RETURNS '1' if tx.ip_src restarts
+//
+int update_IP_SA (libnet_t *l, libnet_ptag_t t)
+{
+ u_int8_t *x, *y;
+ int i=0;
+
+ if (tx.ip_src_rand)
+ {
+ tx.ip_src_h = (u_int32_t) ( ((float) rand()/RAND_MAX)*0xE0000000); //this is 224.0.0.0
+ i=1;
+ }
+ else if (tx.ip_src_isrange)
+ {
+ tx.ip_src_h++;
+ if (tx.ip_src_h > tx.ip_src_stop) // reached the end of the range => restart!
+ {
+ tx.ip_src_h = tx.ip_src_start;
+ i=1;
+ }
+ }
+
+ // Now convert "tx.ip_src_h" into "tx.ip_src" which is in 'Network Byte Order':
+ x = (unsigned char*) &tx.ip_src_h;
+ y = (unsigned char*) &tx.ip_src;
+
+ *y = *(x+3);
+ y++;
+ *y = *(x+2);
+ y++;
+ *y = *(x+1);
+ y++;
+ *y = *x;
+
+ // TODO: Omit certain IP addresses:
+ // E.g. if (rand_ip == tx.ip_src) goto rand_again; // never use true interface IP
+ // TODO: Check other address exceptions ...
+
+ t = libnet_build_ipv4 (tx.ip_len,
+ tx.ip_tos,
+ tx.ip_id,
+ tx.ip_frag,
+ tx.ip_ttl,
+ tx.ip_proto,
+ tx.ip_sum,
+ tx.ip_src, // possibly now random
+ tx.ip_dst,
+ (mode==IP) ? (tx.ip_payload_s) ? tx.ip_payload : NULL : NULL, // if e.g. mode=UDP ignore payload argument
+ (mode==IP) ? tx.ip_payload_s : 0,
+ l,
+ t);
+
+ if (t == -1)
+ {
+ fprintf(stderr," mz/update_IP_SA: IP address manipulation failed!\n");
+ exit (1);
+ }
+
+ return i;
+}
+
+
+
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Applies another DESTINATION IP address from a specified range (tx.ip_dst_isrange==1)
+// to a given IP-PTAG.
+//
+// Note: tx.ip_dst MUST be already initialized with tx.ip_dst_start.
+// tx.ip_dst_h 'mirrors' tx.ip_dst
+// (i. e. tx.ip_dst_h is NOT in network byte order => easy to count)
+// This is done by 'get_ip_range_dst()' in tools.c.
+//
+// RETURN VALUE: '1' if tx.ip_dst restarts
+//
+int update_IP_DA(libnet_t *l, libnet_ptag_t t)
+{
+ u_int8_t *x, *y;
+ int i=0;
+
+
+ if (tx.ip_dst_isrange)
+ {
+ tx.ip_dst_h++;
+ if (tx.ip_dst_h > tx.ip_dst_stop) // we reached the end of the range => restart!
+ {
+ tx.ip_dst_h = tx.ip_dst_start;
+ i=1;
+ }
+ }
+
+
+ // Now convert "tx.ip_dst_h" into "tx.ip_dst" which is in 'Network Byte Order':
+
+ x = (unsigned char*) &tx.ip_dst_h;
+ y = (unsigned char*) &tx.ip_dst;
+
+ *y = *(x+3);
+ y++;
+ *y = *(x+2);
+ y++;
+ *y = *(x+1);
+ y++;
+ *y = *x;
+
+
+ // TODO: Omit certain IP addresses:
+ // E.g. if (rand_ip == tx.ip_src) goto rand_again; // never use true interface IP
+ // TODO: Check other address exceptions ...
+
+ t = libnet_build_ipv4 (tx.ip_len,
+ tx.ip_tos,
+ tx.ip_id,
+ tx.ip_frag,
+ tx.ip_ttl,
+ tx.ip_proto,
+ tx.ip_sum,
+ tx.ip_src,
+ tx.ip_dst,
+ (mode==IP) ? (tx.ip_payload_s) ? tx.ip_payload : NULL : NULL, // if e.g. mode=UDP ignore payload argument
+ (mode==IP) ? tx.ip_payload_s : 0,
+ l,
+ t);
+
+ if (t == -1)
+ {
+ fprintf(stderr," mz/update_IP_DA: IP address manipulation failed!\n");
+ exit (1);
+ }
+
+ return i;
+}
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////
+//
+// Applies another DESTINATION PORT from a specified range to a given UDP- or TCP-PTAG.
+//
+// Note: tx.dp MUST be already initialized with tx.dp_start
+// This is done by 'get_port_range()' in tools.c.
+//
+// RETURN VALUE: '1' if tx.dp restarts
+//
+int update_DPORT(libnet_t *l, libnet_ptag_t t)
+{
+ // u_int32_t DP;
+ int i=0;
+
+ // DP = (u_int32_t) tx.dp;
+ // DP++;
+ tx.dp++;
+
+
+ // Exceeded range => restart:
+ if ((tx.dp > tx.dp_stop) || // we exceeded the end of the range
+ (tx.dp == 65535) ) // or exceeded the 16-bit range
+ {
+ tx.dp = tx.dp_start;
+ i=1;
+ }
+
+
+ if (mode==UDP)
+ {
+ t = libnet_build_udp(tx.sp,
+ tx.dp,
+ tx.udp_len,
+ tx.udp_sum,
+ (tx.udp_payload_s) ? tx.udp_payload : NULL,
+ tx.udp_payload_s,
+ l,
+ t);
+
+ if (t == -1)
+ {
+ fprintf(stderr," mz/send_frame: UDP header manipulation failed!\n");
+ exit (1);
+ }
+ }
+ else // TCP
+ {
+ t = libnet_build_tcp (tx.sp,
+ tx.dp,
+ tx.tcp_seq,
+ tx.tcp_ack,
+ tx.tcp_control,
+ tx.tcp_win,
+ tx.tcp_sum,
+ tx.tcp_urg,
+ tx.tcp_len,
+ (tx.tcp_payload_s) ? tx.tcp_payload : NULL,
+ tx.tcp_payload_s,
+ l,
+ t);
+
+ if (t == -1)
+ {
+ fprintf(stderr, " mz/update_DPORT: Can't build TCP header: %s\n", libnet_geterror(l));
+ exit (0);
+ }
+ }
+
+ return i;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////
+//
+// Applies another SOURCE PORT from a specified range to a given UDP- or TCP-PTAG.
+//
+// Note: tx.sp MUST be already initialized with tx.sp_start
+// This is done by 'get_port_range()' in tools.c.
+//
+// RETURN VALUE: '1' if tx.sp restarts
+//
+int update_SPORT(libnet_t *l, libnet_ptag_t t)
+{
+
+// u_int32_t SP;
+ int i=0;
+
+// SP = (u_int32_t) tx.sp;
+// SP++;
+ tx.sp++;
+
+
+ // Exceeded range => restart:
+ if ((tx.sp > tx.sp_stop) || // we exceeded the end of the range
+ (tx.sp == 65535) ) // or exceeded the 16-bit range
+ {
+ tx.sp = tx.sp_start;
+ i=1;
+ }
+
+ if (mode==UDP)
+ {
+ t = libnet_build_udp(tx.sp,
+ tx.dp,
+ tx.udp_len,
+ tx.udp_sum,
+ (tx.udp_payload_s) ? tx.udp_payload : NULL,
+ tx.udp_payload_s,
+ l,
+ t);
+
+ if (t == -1)
+ {
+ fprintf(stderr," mz/send_frame: UDP header manipulation failed!\n");
+ exit (1);
+ }
+ }
+ else // TCP
+ {
+ t = libnet_build_tcp (tx.sp,
+ tx.dp,
+ tx.tcp_seq,
+ tx.tcp_ack,
+ tx.tcp_control,
+ tx.tcp_win,
+ tx.tcp_sum,
+ tx.tcp_urg,
+ tx.tcp_len,
+ (tx.tcp_payload_s) ? tx.tcp_payload : NULL,
+ tx.tcp_payload_s,
+ l,
+ t);
+
+ if (t == -1)
+ {
+ fprintf(stderr, " mz/update_DPORT: Can't build TCP header: %s\n", libnet_geterror(l));
+ exit (0);
+ }
+ }
+
+ return i;
+}
+
+#define LIBNET_CKSUM_CARRY(x) \
+ (x = (x >> 16) + (x & 0xffff), (~(x + (x >> 16)) & 0xffff))
+
+int update_USUM(libnet_t *l, libnet_ptag_t t)
+{
+ int sum = 0;
+ unsigned int tmp;
+
+ if (tx.udp_sum != 0)
+ return 0;
+
+ sum += libnet_in_cksum((u_int16_t *) &tx.ip6_src, 16);
+ if (tx.ip_option_s && tx.ip6_segs)
+ sum += libnet_in_cksum((u_int16_t *) &tx.ip_option[tx.ip_option_s - 16], 16); // Use last IP address
+ else
+ sum += libnet_in_cksum((u_int16_t *) &tx.ip6_dst, 16);
+
+ tmp = htonl(tx.udp_len);
+ sum += libnet_in_cksum((u_int16_t *) &tmp, 4);
+ tmp = htonl(IPPROTO_UDP);
+ sum += libnet_in_cksum((u_int16_t *) &tmp, 4);
+
+ tmp = ((htons(tx.sp) << 16) + htons(tx.dp));
+ sum += libnet_in_cksum((u_int16_t *) &tmp, 4);
+
+ tmp = htons(tx.udp_len) << 16;
+ sum += libnet_in_cksum((u_int16_t *) &tmp, 4);
+
+ if (tx.udp_payload_s)
+ sum += libnet_in_cksum((u_int16_t *) tx.udp_payload, tx.udp_payload_s);
+
+ tx.udp_sum = ntohs(LIBNET_CKSUM_CARRY(sum));
+
+ t = libnet_build_udp(tx.sp,
+ tx.dp,
+ tx.udp_len,
+ tx.udp_sum,
+ tx.udp_payload_s ? tx.udp_payload : NULL,
+ tx.udp_payload_s,
+ l,
+ t);
+ return t;
+}
+
+int update_TSUM(libnet_t *l, libnet_ptag_t t)
+{
+ int sum = 0;
+ unsigned int tmp;
+
+ if (tx.tcp_sum != 0)
+ return 0;
+
+ sum += libnet_in_cksum((u_int16_t *) &tx.ip6_src, 16);
+ if (tx.ip_option_s && tx.ip6_segs)
+ sum += libnet_in_cksum((u_int16_t *) &tx.ip_option[tx.ip_option_s - 16], 16); // Use last IP address
+ else
+ sum += libnet_in_cksum((u_int16_t *) &tx.ip6_dst, 16);
+
+ tmp = htonl(tx.tcp_len);
+ sum += libnet_in_cksum((u_int16_t *) &tmp, 4);
+ tmp = htonl(IPPROTO_TCP);
+ sum += libnet_in_cksum((u_int16_t *) &tmp, 4);
+
+ tmp = ((htons(tx.sp) << 16) + htons(tx.dp));
+ sum += libnet_in_cksum((u_int16_t *) &tmp, 4);
+
+ tmp = htonl(tx.tcp_seq);
+ sum += libnet_in_cksum((u_int16_t *) &tmp, 4);
+ tmp = htonl(tx.tcp_ack);
+ sum += libnet_in_cksum((u_int16_t *) &tmp, 4);
+
+ tmp = ((ntohs(((tx.tcp_offset) << 12) + tx.tcp_control) << 16) + htons(tx.tcp_win));
+ sum += libnet_in_cksum((u_int16_t *) &tmp, 4);
+
+ tmp = htonl(tx.tcp_urg);
+ sum += libnet_in_cksum((u_int16_t *) &tmp, 4);
+
+ sum += tx.tcp_sum_part;
+
+ if (tx.tcp_payload_s)
+ sum += libnet_in_cksum((u_int16_t *) tx.tcp_payload, tx.tcp_payload_s);
+
+ tx.tcp_sum = ntohs(LIBNET_CKSUM_CARRY(sum));
+
+ t = libnet_build_tcp (tx.sp,
+ tx.dp,
+ tx.tcp_seq,
+ tx.tcp_ack,
+ tx.tcp_control,
+ tx.tcp_win,
+ tx.tcp_sum,
+ tx.tcp_urg,
+ tx.tcp_len,
+ tx.tcp_payload_s ? tx.tcp_payload : NULL,
+ tx.tcp_payload_s,
+ l,
+ t);
+
+ return t;
+}
+
+int update_ISUM(libnet_t *l, libnet_ptag_t t)
+{
+ int sum = 0;
+ unsigned int tmp;
+
+ if (tx.icmp_chksum != 0)
+ return 0;
+
+ sum += libnet_in_cksum((u_int16_t *) &tx.ip6_src, 16);
+ if (tx.ip_option_s && tx.ip6_segs)
+ sum += libnet_in_cksum((u_int16_t *) &tx.ip_option[tx.ip_option_s - 16], 16); // Use last IP address
+ else
+ sum += libnet_in_cksum((u_int16_t *) &tx.ip6_dst, 16);
+
+ tmp = htonl(LIBNET_ICMPV6_H + tx.icmp_payload_s);
+ sum += libnet_in_cksum((u_int16_t *) &tmp, 4);
+ tmp = htonl(IPPROTO_ICMP6);
+ sum += libnet_in_cksum((u_int16_t *) &tmp, 4);
+
+ tmp = htonl(((tx.icmp_type << 8) + tx.icmp_code));
+ sum += libnet_in_cksum((u_int16_t *) &tmp, 4);
+
+ if (tx.icmp_payload_s)
+ sum += libnet_in_cksum((u_int16_t *) tx.icmp_payload, tx.icmp_payload_s);
+
+ tx.icmp_chksum = ntohs(LIBNET_CKSUM_CARRY(sum));
+
+ t = libnet_build_icmpv4_echo (tx.icmp_type,
+ tx.icmp_code,
+ tx.icmp_chksum,
+ tx.icmp_ident,
+ tx.icmp_sqnr,
+ tx.icmp_payload_s ? tx.icmp_payload : NULL,
+ tx.icmp_payload_s,
+ l,
+ t);
+
+ return t;
+}
+
+///////////////////////////////////////////////////////////////////////
+//
+// Applies another TCP SQNR from a specified range to a given TCP-PTAG
+//
+// RETURN VALUE: '1' if tx.txp_seq restarts
+//
+int update_TCP_SQNR(libnet_t *l, libnet_ptag_t t)
+{
+
+ u_int32_t diff;
+ int i=0;
+
+ tx.tcp_seq += tx.tcp_seq_delta;
+ diff = tx.tcp_seq_stop - tx.tcp_seq_start;
+
+ if (diff < tx.tcp_seq_stop) // start < stop
+ {
+ if (tx.tcp_seq > tx.tcp_seq_stop)
+ {
+ tx.tcp_seq = tx.tcp_seq_start;
+ i=1;
+ }
+ }
+ else // stop < start
+ {
+ if ( (tx.tcp_seq<tx.tcp_seq_start) &&
+ (tx.tcp_seq>tx.tcp_seq_stop) )
+ {
+ tx.tcp_seq = tx.tcp_seq_start;
+ i=1;
+ }
+
+ }
+
+ t = libnet_build_tcp (tx.sp,
+ tx.dp,
+ tx.tcp_seq,
+ tx.tcp_ack,
+ tx.tcp_control,
+ tx.tcp_win,
+ tx.tcp_sum,
+ tx.tcp_urg,
+ tx.tcp_len,
+ (tx.tcp_payload_s) ? tx.tcp_payload : NULL,
+ tx.tcp_payload_s,
+ l,
+ t);
+
+ if (t == -1)
+ {
+ fprintf(stderr, " mz/update_TCP_SQNR: Can't build TCP header: %s\n", libnet_geterror(l));
+ exit (0);
+ }
+
+ return i;
+}
+
+
+////////////////////////////////////////////////////////////////////////
+//
+//
+
+int print_frame_details()
+{
+ unsigned char *dum1, *dum2;
+ char pld[65535];
+ char sa[32], da[32];
+
+ if (!tx.packet_mode)
+ {
+ bs2str(tx.eth_dst, da, 6);
+ bs2str(tx.eth_src, sa, 6);
+ fprintf(stderr, " Eth: DA = %s, SA = %s\n",da,sa);
+ }
+
+
+ if (tx.dot1Q)
+ {
+ fprintf(stderr, " 802.1Q VLAN-TAG = %s\n", tx.dot1Q_txt);
+ }
+
+ if (tx.mpls)
+ {
+ fprintf(stderr," MPLS labels (label:exp:bos:ttl): %s\n",tx.mpls_verbose_string);
+
+ }
+
+
+ dum1 = (unsigned char*) &tx.ip_src_h;
+ dum2 = (unsigned char*) &tx.ip_dst_h;
+ (mode==IP) ? (void) bs2str(tx.ip_payload, pld, tx.ip_payload_s) : strcpy(pld, "[see next layer]");
+
+ if (ipv6_mode) {
+ char src6[64]; char dst6[64];
+ libnet_addr2name6_r(tx.ip6_src, LIBNET_DONT_RESOLVE, src6, 64);
+ libnet_addr2name6_r(tx.ip6_dst, LIBNET_DONT_RESOLVE, dst6, 64);
+
+ fprintf(stderr," IP: ver=6, dscp=%u, flow=%u, len=%u, next=%u, hop=%u "
+ "SA=%s, DA=%s\n payload=%s\n", tx.ip_tos, tx.ip_flow,
+ tx.ip_len, tx.ip_proto, tx.ip_ttl, src6, dst6, pld);
+ }
+ else {
+ fprintf(stderr," IP: ver=4, len=%u, tos=%u, id=%u, frag=%u, ttl=%u, proto=%u, sum=%u, "
+ "SA=%u.%u.%u.%u, DA=%u.%u.%u.%u,\n"
+ " payload=%s\n", tx.ip_len, tx.ip_tos,
+ tx.ip_id, tx.ip_frag, tx.ip_ttl, tx.ip_proto, tx.ip_sum,
+ *(dum1+3),*(dum1+2),*(dum1+1),*(dum1), *(dum2+3),*(dum2+2),*(dum2+1),*(dum2+0), pld);
+ }
+
+ if ((mode==UDP)||(mode==DNS)||(mode==RTP))
+ {
+ bs2str(tx.udp_payload, pld, tx.udp_payload_s);
+ fprintf(stderr, " UDP: sp=%u, dp=%u, len=%u, sum=%u, \n"
+ " payload=%s\n", tx.sp, tx.dp, tx.udp_len, tx.udp_sum, pld);
+ }
+ if (mode==TCP) // TODO: Improve message details (flags, ...)
+ {
+ bs2str(tx.tcp_payload, pld, tx.tcp_payload_s);
+ fprintf(stderr, " TCP: sp=%u, dp=%u, S=%u, A=%u, flags=%x, win=%u, len=%u, sum=%u, \n"
+ " payload=%s\n",
+ tx.sp, tx.dp, tx.tcp_seq, tx.tcp_ack, tx.tcp_control, tx.tcp_win, tx.tcp_len, tx.tcp_sum, pld);
+ }
+
+ // send_icmp must prepare the verbose string because there are many
+ // different types of ICMP packets...
+ if (mode==ICMP)
+ {
+ fprintf(stderr, " %s\n", tx.icmp_verbose_txt);
+ }
+
+ if (mode==ICMP6)
+ {
+ fprintf(stderr, " %s\n", tx.icmp_verbose_txt);
+ }
+
+ // libnet_diag_dump_pblock(l);
+ fprintf(stderr,"\n");
+
+ if (simulate)
+ {
+ fprintf(stderr, "*** NOTE: Simulation only! Nothing has been sent! ***\n");
+ exit(0);
+ }
+
+
+ return 0;
+}
+
diff --git a/staging/mops.c b/staging/mops.c
new file mode 100644
index 0000000..f56deff
--- /dev/null
+++ b/staging/mops.c
@@ -0,0 +1,769 @@
+/*
+ * Mausezahn - A fast versatile traffic generator
+ * Copyright (C) 2008-2010 Herbert Haas
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
+ *
+*/
+
+
+
+
+// -- TOC: --
+//
+// struct mops * mops_init ()
+// struct mops * mops_alloc_packet (struct mops *cur)
+// struct mops * mops_delete_packet (struct mops *cur)
+// int mops_reset_packet (struct mops *cur)
+//
+// int mops_dump_all (struct mops* list)
+// struct mops * mops_search_name (struct mops* list, char* key)
+// struct mops * mops_search_id (struct mops* list, int key)
+// void mops_delete_all (struct mops* list)
+// void mops_cleanup (struct mops* list)
+//
+// int mops_set_defaults (struct mops *mp)
+// int mops_print_frame (struct mops *mp, char *str)
+//
+// int mops_get_new_pkt_id (struct mops *mp)
+// int mops_clear_layers (struct mops *mp)
+
+// int mops_get_device_index (char *devname)
+// int mops_use_device (struct mops * mp, int i)
+
+// int mops_get_proto_info (struct mops * mp, char *layers, char *proto)
+
+#include "mz.h"
+#include "mops.h"
+
+
+
+
+// Creates first element, aka "head" element
+// This element can also be used! See mops_alloc_packet!
+//
+struct mops * mops_init()
+{
+ // these defaults can be changed by the user:
+ min_frame_s = MIN_MOPS_FRAME_SIZE; // important global; depends on used packet tx subsystem such as libnet
+ max_frame_s = MAX_MOPS_FRAME_SIZE-MOPS_SIZE_MARGIN;
+
+ // Create initial mops element:
+ struct mops *new_mops = (struct mops*) malloc(sizeof(struct mops));
+ new_mops->next = new_mops;
+ new_mops->prev = new_mops;
+ new_mops->state = MOPS_STATE_NULL;
+ new_mops->id = 0; // importante!
+ mops_set_defaults (new_mops);
+ strncpy(new_mops->packet_name, "-------", 8);
+
+ return new_mops;
+}
+
+
+
+
+
+// Returns pointer to new mops element:
+// 1) either insert a new mops element in list
+// 2) or returns same pointer again if current mops element is empty
+// Note that new element N is always PREPENDED to cur:
+// ... = N-2 = N-1 = N = cur = 1 = 2 = ...
+//
+//
+// RETURN VALUE: + Pointer to new mops
+// - NULL upon failure
+struct mops * mops_alloc_packet(struct mops *cur)
+{
+ int j;
+ struct mops *new_mops;
+ int new_pkt_id, pkt_id_name;
+ char pname[MAX_MOPS_PACKET_NAME_LEN];
+
+ if (cur->state == MOPS_STATE_NULL) { // allows to use first packet in list
+ new_mops = cur; // current mops was unused => no need to insert a new mops!
+ }
+ else { // create new mops element
+ new_mops = (struct mops *) malloc(sizeof(struct mops));
+ if (new_mops==NULL) {
+ fprintf(stderr, "MZ alert: cannot create new mops entry - memory full?\n");
+ return NULL; // memory full?
+ }
+ }
+
+ new_mops->state = MOPS_STATE_INIT;
+
+ // Assign unique packet id
+ new_pkt_id = mops_get_new_pkt_id (cur);
+ if (new_pkt_id==-1) return NULL;
+ new_mops->id = new_pkt_id;
+
+ // Assign unique packet name
+ pkt_id_name = new_pkt_id;
+ do {
+ sprintf(pname, "PKT%04d", pkt_id_name);
+ pkt_id_name++;
+ } while (mops_search_name (mp_head, pname)); // check if this name is really unique
+
+ strncpy(new_mops->packet_name, pname, MAX_MOPS_PACKET_NAME_LEN);
+
+ // append to doubly linked list
+ new_mops->prev = cur->prev;
+ new_mops->next = cur;
+ cur->prev = new_mops;
+ new_mops->prev->next = new_mops;
+
+ mops_set_defaults (new_mops); // set header parametes (addresses etc)
+
+ // Reset protocol descriptor
+ new_mops->p_desc = NULL;
+ new_mops->p_desc_type = MOPS_NO_PDESC;
+
+ // clear counter values
+ new_mops->used_counters=0;
+ for (j=0; j<MAX_MOPS_COUNTERS_PER_PACKET; j++) {
+ new_mops->counter[j].use = 0;
+ new_mops->counter[j].offset = 0;
+ new_mops->counter[j].random = 0;
+ }
+
+ return new_mops;
+}
+
+
+
+// Delete particular packet (remove it from list).
+//
+// If mp_head is deleted, makes previous element mp_head.
+// Note that the global mp_head must exist but within MOPS this
+// is always the case.
+//
+// Returns pointer to previous element in the list
+// or NULL if packet is active
+struct mops * mops_delete_packet(struct mops *cur)
+{
+ struct mops *last;
+
+ if (mops_is_active(cur)) {
+ mops_destroy_thread(cur);
+ }
+
+ mops_ext_del_pdesc (cur); // delete p_desc (if available)
+
+ // remove automops data if available
+ if (cur->amp != NULL) {
+ free(cur->amp);
+ cur->amp=NULL;
+ }
+ if (cur->amp_pdu != NULL) {
+ free (cur->amp_pdu);
+ cur->amp_pdu=NULL;
+ }
+
+ last = cur->prev;
+ cur->next->prev = cur->prev;
+ cur->prev->next = cur->next;
+ if (cur==mp_head) {
+ mp_head = last;
+ }
+ if (cur!=NULL) {
+ free (cur);
+ cur=NULL;
+ }
+ return last;
+}
+
+
+
+// Erase all data of a mops entry and even chooses a new standard name
+// DOES NOT delete the entry from the list
+//
+int mops_reset_packet(struct mops *cur)
+{
+ int i=0;
+ char pname[16];
+
+ // stop thread if necessary
+ if (mops_is_active(cur)) {
+ mops_destroy_thread(cur);
+ }
+
+ // remove pdesc if available
+ mops_ext_del_pdesc (cur);
+ cur->state = MOPS_STATE_NULL;
+
+ // remove automops data if available
+ if (cur->amp != NULL) {
+ free(cur->amp);
+ cur->amp=NULL;
+ }
+ if (cur->amp_pdu != NULL) {
+ free (cur->amp_pdu);
+ cur->amp_pdu=NULL;
+ }
+ // find another name
+ do {
+ sprintf(pname, "PKT%04d", i);
+ i++;
+ } while (mops_search_name (mp_head, pname)); // check if this name is really unique
+ strncpy(cur->packet_name, pname, MAX_MOPS_PACKET_NAME_LEN);
+
+ // Place everything else in this function:
+ mops_set_defaults (cur);
+
+ return 0;
+}
+
+
+
+
+// Runs through all packets and dumps some statistics into 'str'
+// Returns 1 if only the uninitialized head is available
+//
+int mops_dump_all(struct mops* list, char *str)
+{
+ struct mops *head = list;
+ struct mops *cur = list;
+
+ char output[100];
+ int anzmops=0, active=0, config=0, raw=0, ival=0;
+
+ do {
+ if (cur->state == MOPS_STATE_ACTIVE) {
+ active++;
+ } else if (cur->state == MOPS_STATE_CONFIG) {
+ config++;
+ } else if (cur->interval_used==2) {
+ ival++;
+ }
+ if (cur->use_ETHER == 0) raw++;
+
+ anzmops++;
+ cur = cur->next;
+ } while (head != cur);
+
+ snprintf(output, 99, "%i Mopse(s) (interval: %i, active: %i, config: %i, raw: %i)",
+ anzmops, ival, active, config, raw);
+
+ strncpy(str, output, 99);
+
+ if ((!active) && (!config)) return 1;
+
+ return 0;
+}
+
+
+
+
+
+// Search for key = name and return pointer to that mops
+// Return NULL if not found
+struct mops * mops_search_name (struct mops* list, char *key)
+{
+ struct mops *head = list;
+ struct mops *cur = list;
+ do {
+ if ( (strncasecmp(key,
+ cur->packet_name,
+ MAX_MOPS_PACKET_NAME_LEN) == 0)) {
+ return cur; // FOUND!
+ }
+ cur = cur->next;
+ }
+ while (head != cur);
+ return NULL; // NOT FOUND!
+}
+
+
+
+// Search for key = id and return pointer to that mops
+// Return NULL if not found
+struct mops * mops_search_id (struct mops* list, u_int32_t key)
+{
+ struct mops *head = list;
+ struct mops *cur = list;
+ do {
+ if ( cur->id == key ) {
+ return cur; // FOUND!
+ }
+ cur = cur->next;
+ }
+ while (head != cur);
+ return NULL; // NOT FOUND!
+}
+
+
+
+
+// Deletes all elements except the specified element which us usually
+// the head element. Also ACTIVE elements will be removed and the
+// corresponding threads will be stopped.
+//
+// Thus the list can grow again later via mops_alloc_packet
+//
+void mops_delete_all(struct mops* list)
+{
+ struct mops *head = list;
+ struct mops *cur = list->next;
+ struct mops *tmp;
+
+ // Delete all but head element:
+ while (head != cur)
+ {
+ tmp = cur->next;
+ mops_ext_del_pdesc (cur); // delete p_desc (if available)
+ mops_destroy_thread(cur);
+
+ // remove automops data if available
+ if (cur->amp != NULL) {
+ free(cur->amp);
+ cur->amp=NULL;
+ }
+ if (cur->amp_pdu != NULL) {
+ free (cur->amp_pdu);
+ cur->amp_pdu=NULL;
+ }
+ cur->amp_pdu_s=0;
+
+ if (cur!=NULL) {
+ free(cur);
+ cur=NULL;
+ }
+ cur = tmp;
+ }
+
+ head->next = head;
+ head->prev = head;
+
+ head->state = MOPS_STATE_NULL;
+}
+
+
+
+// Same as mops_delete_all but also destroys the head element:
+void mops_cleanup(struct mops* list)
+{
+ mops_delete_all(list);
+ mops_ext_del_pdesc (list); // delete p_desc (if available)
+ mops_destroy_thread(list);
+ if (list!=NULL) {
+ free(list);
+ list=NULL;
+ }
+}
+
+
+
+
+// Set default MOPS and protocol header parameters
+// Currently most parameters are taken from the legacy tx-structure
+//
+// NOTE: Does NOT and should NOT change the packet_name !!!
+// Because user might be confused if it is changed to something
+// unexpected such as 'PKT0341'.
+//
+// TODO: find out MAC of default GW
+int mops_set_defaults (struct mops *mp)
+{
+ // Initialize frame arrays with zero bytes
+ memset(mp->frame, 0x00, MAX_MOPS_FRAME_SIZE);
+ memset(mp->msg, 0x00, MAX_MOPS_MSG_SIZE);
+
+ // Basics -- MOPS Management Parameters
+ pthread_mutex_init (& mp->mops_mutex, NULL);
+// mp->mops_thread = 0; // TODO
+// mp->interval_thread = 0; // TODO
+ mp->verbose = 1; // normal verbosity
+ mp->use_ETHER = 0;
+ mp->use_SNAP = 0;
+ mp->use_dot1Q = 0;
+ mp->use_MPLS = 0;
+ mp->use_IP = 0;
+ mp->use_UDP = 0;
+ mp->use_TCP = 0;
+ mp->frame_s = 0;
+ mp->msg_s = 0;
+ mp->description[0]='\0';
+ mp->auto_delivery_off = 0;
+ mp->mz_system = 0;
+ strncpy (mp->device, tx.device, 16);
+ mp->count = 0;
+ mp->cntx = 0;
+
+ mp->ndelay.tv_sec = 0;
+ mp->ndelay.tv_nsec = 100000000L; // 100 ms default delay
+
+ mp->interval_used = 0;
+ mp->interval.tv_sec = 0;
+ mp->interval.tv_nsec = 0;
+
+ mp->delay_sigma.tv_sec = 0;
+ mp->delay_sigma.tv_nsec = 0;
+
+ mp->MSG_use_RAW_FILE=0;
+ mp->MSG_use_HEX_FILE=0;
+ mp->MSG_use_ASC_FILE=0;
+ mp->fp=NULL;
+ mp->chunk_s = MAX_MOPS_MSG_CHUNK_SIZE;
+
+ // TODO: check if amp and amp_header is free()'d in any case!!!
+ mp->amp = NULL;
+ mp->amp_pdu = NULL;
+ mp->amp_pdu_s = 0;
+
+ // Ethernet defaults:
+ memcpy((void *) &mp->eth_dst, (void *) &tx.eth_dst, 6);
+ memcpy((void *) &mp->eth_src, (void *) &tx.eth_src, 6);
+ mp->eth_type = 0x800;
+ mp->eth_src_israndom = 0;
+
+ mp->dot1Q_isrange = 0;
+ mp->mpls_isrange = 0;
+
+ // IP defaults:
+ // abuse our hton: here we actually convert from net to host order:
+ mops_hton4 ((u_int32_t*) &tx.ip_dst, (u_int8_t*) &mp->ip_dst);
+ mops_hton4 ((u_int32_t*) &tx.ip_src, (u_int8_t*) &mp->ip_src);
+ // Note that the IP address of the "default interface" is assigned to that mops.
+ // If the mops is bind to another interface then use the associated interface.
+ // Implement this in cli_packet and function cmd_packet_bind
+ //
+ mp->ip_version = 4;
+ mp->ip_IHL = 0;
+ mp->ip_len = 20;
+ mp->ip_tos = 0;
+ mp->ip_flags_RS=0; // 0|1 ... Reserved flag "must be zero"
+ mp->ip_flags_DF=0; // 0|1 ... Don't Fragment
+ mp->ip_flags_MF=0; // 0|1 ... More Fragments
+ mp->ip_frag_offset=0;
+ mp->ip_fragsize=0; // fragmentation OFF
+ mp->ip_frag_overlap=0; // no overlapping fragments
+ mp->ip_ttl = 255;
+ mp->ip_proto = 17; // UDP
+ mp->ip_src_israndom = 0;
+ mp->ip_src_isrange = 0;
+ mp->ip_dst_isrange = 0;
+ mp->ip_option_used = 0;
+ mp->ip_IHL_false = 0;
+ mp->ip_len_false = 0;
+ mp->ip_sum_false = 0;
+ mp->ip_option_used = 0;
+ mp->ip_option_s = 0;
+ // L4 defaults (port numbers)
+ mp->sp=0;
+ mp->sp_start=0;
+ mp->sp_stop=0;
+ mp->sp_isrand=0;
+ mp->sp_isrange=0;
+
+ mp->dp=0;
+ mp->dp_start=0;
+ mp->dp_stop=0;
+ mp->dp_isrand=0;
+ mp->dp_isrange=0;
+
+ // UDP defaults
+ //
+ mp->udp_len_false = 0;
+ mp->udp_sum_false = 0;
+ mp->udp_sum = 0xffff; // this default means "transmitter didn't compute checksum"
+
+ // TCP defaults
+ //
+ mp->tcp_seq = 0xcafebabe;
+ mp->tcp_seq_delta = 0; // no range
+ mp->tcp_seq_start = 0;
+ mp->tcp_seq_stop = 0xffffffff;
+ mp->tcp_ack = 0;
+ mp->tcp_ack_delta = 0; // no range
+ mp->tcp_ack_start = 0;
+ mp->tcp_ack_stop = 0xffffffff;
+ mp->tcp_win = 100;
+ mp->tcp_sum_false = 0;
+ mp->tcp_offset_false = 0;
+ mp->tcp_offset = 0;
+ mp->tcp_sum = 0xffff; // this default means "transmitter didn't compute checksum"
+ mp->tcp_option_used = 0;
+ mp->tcp_option_s =0;
+ mp->tcp_ctrl_CWR =0;
+ mp->tcp_ctrl_ECE =0;
+ mp->tcp_ctrl_URG =0;
+ mp->tcp_ctrl_ACK =0;
+ mp->tcp_ctrl_PSH =0;
+ mp->tcp_ctrl_RST =0;
+ mp->tcp_ctrl_SYN =1; // assume that we begin with a TCP SYN
+ mp->tcp_ctrl_FIN =0;
+ mp->tcp_urg =0;
+ mp->tcp_ack =0;
+ mp->tcp_res =0;
+ return 0;
+}
+
+
+
+
+
+
+
+int mops_print_frame (struct mops *mp, char *str)
+{
+ int i=0, fs;
+ char octet[8], lnr[8], hex[MAX_MOPS_FRAME_SIZE*3];
+
+ hex[0]=0x00;
+
+ if (! (fs = mp->frame_s) ) return -1; // frame length zero (no frame?)
+
+ if (fs>1)
+ {
+ sprintf(lnr,"%4i ",i+1);
+ strcat(hex, lnr);
+
+ for (i=0; i<fs; i++)
+ {
+ if ((i>0) && (!(i%8)))
+ {
+ strcat(hex, " "); // insert space after each 8 bytes
+ hex[strlen(hex)-2]=' ';
+ }
+
+ if ((i>0) && (!(i%MAX_CLI_LINE_BYTES)))
+ {
+ sprintf(lnr,"\n%4i ",i+1);
+ strcat(hex, lnr);
+ }
+
+ sprintf(octet, "%02x:", mp->frame[i]);
+ strcat(hex, octet);
+ }
+ }
+
+ hex[strlen(hex)-1]=' ';
+ strcpy(str, hex);
+
+ return 0;
+}
+
+
+
+
+
+
+
+
+// Find and returns a new unique packet id
+// If none can be found, returns -1.
+//
+int mops_get_new_pkt_id (struct mops *list)
+{
+ struct mops *head = list;
+ struct mops *cur = list;
+ int i, min=0xffffffff, max=0;
+
+ do {
+ if (cur->id < min) min = cur->id; // determine current min id
+ if (cur->id > max) max = cur->id; // determine current max id
+ cur = cur->next;
+ }
+ while (head != cur);
+
+ if (min>0)
+ i= min-1;
+ else
+ i = max+1;
+
+ // just for paranoia: check again if unique!
+ do {
+ if (cur->id == i) {
+ return -1; //
+ }
+ cur = cur->next;
+ }
+ while (head != cur);
+
+ return i;
+}
+
+
+// Simply sets specified 'layer switches' in mops struct
+// (use_ETHER, use_IP, ...) to zero.
+//
+// RETURN VALUE: tells which layers had been configured before clearing.
+//
+// The presence of the layers is indicated via binary coding:
+//
+// MOPS_ALL 127 // clear all
+// MOPS_ETH 1
+// MOPS_SNAP 2 // either LLC, LLC+SNAP
+// MOPS_dot1Q 4
+// MOPS_MPLS 8
+// MOPS_IP 16
+// MOPS_UDP 32
+// MOPS_TCP 64
+//
+int mops_clear_layers (struct mops *mp, int l)
+{
+ int ret=0;
+
+ if (l & MOPS_ETH) {
+ if (mp->use_ETHER) ret+=1;
+ mp->use_ETHER = 0;
+ }
+
+ if (l & MOPS_SNAP) {
+ if (mp->use_SNAP) ret+=2;
+ mp->use_SNAP = 0;
+ }
+
+ if (l & MOPS_dot1Q) {
+ if (mp->use_dot1Q) ret+=4;
+ mp->use_dot1Q = 0;
+ }
+
+ if (l & MOPS_MPLS) {
+ if (mp->use_MPLS) ret+=8;
+ mp->use_MPLS = 0;
+ }
+
+ if (l & MOPS_IP) {
+ if (mp->use_IP) ret+=16;
+ mp->use_IP = 0;
+ }
+
+ if (l & MOPS_UDP) {
+ if (mp->use_UDP) ret+=32;
+ mp->use_UDP = 0;
+ }
+
+ if (l & MOPS_TCP) {
+ if (mp->use_TCP) ret+=64;
+ mp->use_TCP = 0;
+ }
+
+ return ret;
+}
+
+
+// Get global device index for a given device name.
+//
+// RETURN VALUE:
+// Either the desired device index or -1 if not found.
+//
+// EXAMPLE:
+// i = mops_get_device_index("eth0")
+//
+int mops_get_device_index(char *devname)
+{
+ int i;
+
+ for (i=0; i<device_list_entries; i++) {
+ if (strncmp(device_list[i].dev, devname, 16)==0) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+
+
+// Assign device-specific values (source IP and MAC addresses),
+// drawn from global device table, to the specified MOPS entry
+// with index i.
+//
+int mops_use_device(struct mops * mp, int i)
+{
+ // Assign source MAC address
+ // Assign source IP address
+ // TODO? Assign default gateway
+
+ memcpy((void *) &mp->eth_src, (void *) &device_list[i].mac_mops[0], 6);
+ memcpy((void *) &mp->ip_src, (void *) &device_list[i].ip_mops[0], 4);
+
+ return 0;
+}
+
+
+// Creates two strings as used by the 'show packet' command,
+// 1) one identifying all used layers of a packet,
+// 2) the other which higher layer protocol is used
+//
+// caller must define:
+// char layers[16], proto[16];
+//
+// RETURNS 0 upon success, 1 upon failure.
+//
+int mops_get_proto_info(struct mops *mp, char *layers, char *proto)
+{
+ char ds[16], pr[16];
+
+ if (mp==NULL) return 1;
+
+ ds[0]='\0';
+ pr[0]='\0';
+
+ if (mp->use_ETHER) strcat(ds,"E"); else strcat(ds,"-");
+ if (mp->use_SNAP) strcat(ds,"S"); else strcat(ds,"-");
+ if (mp->use_dot1Q) strcat(ds,"Q"); else strcat(ds,"-");
+ if (mp->use_MPLS) strcat(ds,"M"); else strcat(ds,"-");
+ if (mp->use_IP) {
+ if (mp->auto_delivery_off)
+ strcat(ds,"i");
+ else
+ strcat(ds,"I");
+ } else strcat(ds,"-");
+
+ if (mp->use_UDP)
+ strcat(ds,"U");
+ else if
+ (mp->use_TCP) strcat(ds,"T");
+ else strcat(ds,"-");
+
+ switch (mp->p_desc_type) {
+ case MOPS_ARP:
+ strncpy(pr, "ARP", 8);
+ break;
+ case MOPS_BPDU:
+ strncpy(pr, "BPDU", 8);
+ break;
+ case MOPS_CDP:
+ strncpy(pr, "CDP", 8);
+ break;
+ case MOPS_DNS:
+ strncpy(pr, "DNS", 8);
+ break;
+ case MOPS_ICMP:
+ strncpy(pr, "ICMP", 8);
+ break;
+ case MOPS_IGMP:
+ strncpy(pr, "IGMP", 8);
+ break;
+ case MOPS_LLDP:
+ strncpy(pr, "LLDP", 8);
+ break;
+ case MOPS_RTP:
+ strncpy(pr, "RTP", 8);
+ break;
+ case MOPS_SYSLOG:
+ strncpy(pr, "SYSLOG", 8);
+ break;
+ default:
+ break;
+ }
+
+ strncpy(layers, ds, 16);
+ strncpy(proto, pr, 16);
+ return 0;
+}
+
+
diff --git a/staging/mops.h b/staging/mops.h
new file mode 100644
index 0000000..fd9884c
--- /dev/null
+++ b/staging/mops.h
@@ -0,0 +1,1023 @@
+/*
+ * Mausezahn - A fast versatile traffic generator
+ * Copyright (C) 2008-2010 Herbert Haas
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
+ *
+*/
+
+
+#ifndef __MOPS__
+#define __MOPS__
+
+
+#define MOPS_VERSION "0.3"
+#define MOPS_CODENAME "Cyanistes caeruleus (DE+150)"
+#define AUTOMOPS_ENABLED 0 // Automops subsystem (currently in development)
+#define MAX_MOPS_FRAME_SIZE 8192 // total max frame size (=all headers plus payload)
+#define MIN_MOPS_FRAME_SIZE 15 // total min frame size
+#define MOPS_SIZE_MARGIN 50 // User limit: MAX_MOPS_FRAME_SIZE - MOPS_SIZE_MARGIN
+#define MAX_MOPS_MSG_SIZE 7500 // payload limit
+#define MAX_MOPS_MSG_CHUNK_SIZE 1000 // Chunks size when read data from a file for the payload
+#define MAX_MOPS_COUNTERS_PER_PACKET 10 // number of user-defined counters per packet
+#define MAX_MOPS_PACKET_NAME_LEN 32 // Each packet must have an unique name
+#define MAX_MOPS_DESCRIPTION_LEN 80 // Max length of packet description string
+#define MAX_MOPS_DOT1Q_TAGS 64 // Max number of 802.1Q tags within a frame (too many, practically ;-))
+#define MAX_MOPS_MPLS_TAGS 64 // Max number of MPLS tags within a frame (again too many, practically)
+#define XN_MAX_STACK 7 // max nesting depth
+
+#define AUTOMOPS_MAX_FILE_SIZE 200000 // Max file size in bytes for AMP protocol definitions
+#define AUTOMOPS_MAX_NAME_LEN 32 // used for all names (valname, field name, protocol name)
+#define AUTOMOPS_MAX_SHORTDESC_LEN 64
+
+#define XML_MAX_TAG_LEN 16
+#define XML_STRLEN 64 // required length of user string to hold tag
+ // but also alternatively an error message
+
+
+#define MAX_LLDP_OPT_TLVS 500 // How many bytes are reserved for optional TLVs within an LLDP message?
+
+//#define MAX_MOPS_PACKETS 1000 // number of packet slots *** DEPRECATED ***
+#define MAX_CLI_LINE_BYTES 32 // How many bytes 'mops_print_frame' should print before line break
+
+// Basic layers; see mops_clear_layers()
+// Also used by automops (see layers_on, layers_off)
+#define MOPS_ALL 127
+#define MOPS_ETH 1
+#define MOPS_SNAP 2 // either LLC, LLC+SNAP
+#define MOPS_dot1Q 4
+#define MOPS_MPLS 8
+#define MOPS_IP 16
+#define MOPS_UDP 32
+#define MOPS_TCP 64
+
+// The following definitions are needed as values for (int) p_desc_type
+// which identifies the exact type of (void *) p_desc.
+#define MOPS_NO_PDESC 100
+#define MOPS_ARP 101
+#define MOPS_BPDU 102
+#define MOPS_CDP 103
+#define MOPS_DNS 104
+#define MOPS_ICMP 105
+#define MOPS_LLDP 106
+#define MOPS_RTP 107
+#define MOPS_SYSLOG 108
+#define MOPS_IGMP 109
+
+// packet states (variable 'state')
+// NOTE: every state >2 (i. e. 3, 4, ...) is an active state, i. e. packet should
+// be blocked from configurations etc.
+#define MOPS_STATE_NULL 0 // transition state, only initially
+#define MOPS_STATE_INIT 1
+#define MOPS_STATE_CONFIG 2 // normal state (when configured)
+#define MOPS_STATE_ACTIVE 3 // has associated sending thread
+#define MOPS_STATE_SEQACT 4 // packet is member of an active sequence
+
+// Return values of mops_pdesc utility functions (see mops_ext.c)
+#define MOPS_PDESC_SUCCESS 0 // Value assigned properly | string present
+#define MOPS_PDESC_FAILURE 1 // Unspecified problem | string not present
+#define MOPS_PDESC_LOW 2 // Value smaller than lower bound - but will set
+#define MOPS_PDESC_HIGH 3 // Value larger than upper bound - but will set
+#define MOPS_PDESC_OVERFLOW 4 // Value exceeded possible range
+#define MOPS_PDESC_NO_MAC 5 // Invalid MAC address
+#define MOPS_PDESC_NO_IP 6 // Invalid IP address
+
+// These definitions are (should be) only used in mops_ext.c
+#define MOPS_EXT_ARP struct mops_ext_arp *
+#define MOPS_EXT_BPDU struct mops_ext_bpdu *
+#define MOPS_EXT_CDP struct mops_ext_cdp *
+#define MOPS_EXT_DNS struct mops_ext_dns *
+#define MOPS_EXT_ICMP struct mops_ext_icmp *
+#define MOPS_EXT_LLDP struct mops_ext_lldp *
+#define MOPS_EXT_RTP struct mops_ext_rtp *
+#define MOPS_EXT_SYSLOG struct mops_ext_syslog *
+#define MOPS_EXT_IGMP struct mops_ext_igmp *
+
+// Very specific definitions here:
+#define MOPS_RTP_EXT_MZID 0xcaca // first 16 bit of the Mausezahn RTP extension header
+#define DSP_SOURCE 100 // any number >0 indicating /dev/dsp to be used as RTP payload
+#define MOPS_RTP_MAX_PAYLOAD_SIZE 200
+
+#include <pthread.h>
+
+
+// These are initialized with the definitions MIN_MOPS_FRAME_SIZE and
+// MAX_MOPS_FRAME_SIZE above but can be overridden by the user (without
+// extending these limits)
+unsigned int min_frame_s;
+unsigned int max_frame_s;
+
+struct mops_counter
+{
+ int use; // 1 = counter active
+ int offset; // points to counter location in *msg*
+ int random; // 1=random, 0=use start/stop/step
+ u_int32_t start; // HOST BYTE ORDER
+ u_int32_t stop; // HOST BYTE ORDER
+ u_int32_t step; // HOST BYTE ORDER
+ u_int32_t cur; // current value (HOST BYTE ORDER)
+ int bytes; // number of bytes used (1|2|4) - selects hton2 or hton4
+ // and enables proper wraparounds (mod 256, mod 65536, ...)
+};
+
+
+enum amperr {
+ ampSuccess,
+ ampInvalidIndex,
+ ampInvalidName,
+ ampDuplicateName,
+ ampDescTooLong,
+ ampInvalidType,
+ ampInvalidLayer,
+ ampTCPandUDP,
+ ampUnknownKeyword,
+ ampSingleWordRequired,
+ ampRangeError,
+ ampPayloadLen,
+ ampPayloadType,
+ ampUnknownTag
+};
+
+enum fieldtypes {
+ Byte8, Byte16, Byte32, Flag_in_Byte, MultiBytes, MultiBytesHex,
+ TLV // TODO: different/standard TLV formats (Cisco CDP, LLCP, ...)
+};
+
+
+struct fields {
+ struct fields *next;
+ char name[AUTOMOPS_MAX_NAME_LEN+1]; // Official name of field -- CASE INSENSITIVE
+ char shortdesc[AUTOMOPS_MAX_SHORTDESC_LEN+1]; // One-line description
+ char * longdesc; // Long (multiline) description (helptext)
+ enum fieldtypes type; // Field type corresponds to length
+ int constant; // 1: only default value allowed, not changeable
+
+ int i; // unique internal field entry index (strongly monotonic increasing!)
+ // Note: first entry starts with 0.
+
+ int index; // protocol field index; Note: First field has index 1.
+ // successive fields have same index in two cases:
+ // 1) several flags within same byte
+ // 2) several different valname/val pairs for same field index. In this
+ // case the successive field-entries must only contain the valname
+ // and a corresponding value.
+
+ // may contain a reserved value *name*, usually used with multiple
+ // successive fields with same field index N.
+ char valname[AUTOMOPS_MAX_NAME_LEN+1];
+
+ u_int32_t
+ tlv_type,
+ tlv_len,
+ val, // default initial value
+ min, // range min value
+ max; // range max value
+
+ int leftshift; // when type=Flag_in_Byte
+
+ u_int8_t *str; // default initial characters or hex values (when type=MultiByte or TLV)
+ int str_s; // length of str
+};
+
+
+// Each automops object identifies another dynamically specified protocol.
+//
+// Usage and structure:
+//
+// 1) Doubly linked list to store new (dynamically defined) protocols.
+// Protocol definitions are typically loaded from a file and converted
+// to an automops entry via parse_protocol() defined in parse_xml.c
+//
+// 2) When the user chooses one of these protocols to be used for a mops
+// then best is to copy the whole automops to the current mops; this
+// way the protocol's field values can be easily modified and
+// automops_update() can be directly applied to that automops entity.
+//
+// If you cannot understand anything you are maybe already mausezahn'ed ;-)
+//
+struct automops {
+ struct automops *next;
+ struct automops *prev;
+
+ char name[AUTOMOPS_MAX_NAME_LEN+1]; // Protocol name
+ char desc[AUTOMOPS_MAX_SHORTDESC_LEN+1]; // One-line description
+
+ // Specify required and allowed layers using the definitions above
+ // for example MOPS_ETH, MOPS_SNAP, MOPS_dot1Q, MOPS_MPLS,
+ // MOPS_IP, MOPS_UDP, and MOPS_TCP
+ int
+ layers_on, // which layers are REQUIRED
+ layers_off; // which layers MUST be DISABLED because of conflicts
+ // Not mentioned layers are arbitrary (e. g. MOPS_dot1Q)
+ // Protocol-specific addresses
+ // Usually only destination address/port is specific but there are some
+ // exceptions (e. g. DHCP uses well known sp/dp pair).
+ // Value zero means ignore; otherwise copy to mops.
+ u_int16_t etype; // EtherType
+ u_int8_t proto; // IP protocol number
+ u_int8_t sa[6], da[6]; // source/destination MAC address
+ u_int32_t SA, DA; // source/destination IPv4 address
+ int sp, dp; // Well-known port numbers
+
+
+ int payload_type; // 0=none, 1=ascii, 2=hex, 3=any
+ char *payload; // default payload data (if above is true)
+ int payload_s;
+
+ struct fields *field; // points to single linked list describing each field
+ // or NULL
+
+ /// ---- internal data -----
+ int defined_externally; // 0=built-in, 1=file, -1=undefined
+ int used; // number of mopses using this automops;
+ // = -1 when allocated
+ // = 0 when got valid data
+ // = >0 when used by some mopses
+};
+
+
+struct automops * amp_head;
+
+
+struct mops
+{
+ struct mops *next;
+ struct mops *prev;
+
+ // *** The Header ***
+ // Management issues for TX
+ int state; // see above
+ int id; // UNIQUE Identifier (NOTE: MUST ALLOW -1)
+ int mz_system; // identifies user and system packets (such as ARP)
+ int verbose; // Be more or less verbose when processing that MOPS
+ char packet_name[MAX_MOPS_PACKET_NAME_LEN]; // Each packet must have unique name
+ char description[MAX_MOPS_DESCRIPTION_LEN]; // An optional short packet description
+
+ pthread_t mops_thread; // associated transmission thread
+ pthread_t interval_thread;
+
+ pthread_mutex_t mops_mutex; // mutex to savely access mops data
+
+ char device[16]; // every packet could be sent through a different device
+ // NOTE that we do NOT store the index of device_list[] because after
+ // a re-discovery of the network interfaces the same index could map
+ // to a different physical network device. Instead the device's name
+ // does not change (however, might be not available, but then we report
+ // an error message and the user can assign another interface)
+ //
+ // See function mops_get_device_index()
+
+ unsigned long count; // Desired number of packets to be sent. 0 means infinite.
+ unsigned long cntx; // This value actually counts sent packets.
+ // NOTE: Count _down_ for finite count, count _up_ for infinite count.
+
+ struct timespec ndelay; // Inter-packet delay; contains two members:
+ // tv_sec and tv_nsec (0 to 999999999)
+
+ struct timespec interval; // An optional global interval
+ int interval_used; // 0=none, 1=configured, 2=active (i. e. interval_thread is valid)
+
+ struct timespec delay_sigma; // Standard deviation
+
+ int delay_pd; // Which propability distribution (density)
+ // MOPS_DELAY_GAUSS
+ // MOPS_DELAY_EXP will result in a Poisson process with lambda=delay
+
+
+ int auto_delivery_off; // 0 means, the destination MAC address will be chosen automatically (for IP packets)
+ // depending on the IP destination address ('direct or indirect delivery', i. e. based
+ // on ARP).
+ //
+ // 1 means, the user-provided destination MAC address will be used.
+
+ // ******************
+
+ // Data section
+
+ int
+ use_ETHER, // if unset (=0) then complete raw frame given in frame[]
+ use_SNAP, // NOTE: use_SNAP=1 may indicate either 802.3+LLC alone or 802.3+LLC+SNAP
+ use_dot1Q,
+ use_MPLS,
+ use_IP,
+ use_UDP,
+ use_TCP;
+
+ int // pointers to important positions
+ begin_IP, // marks byte position of IP header within frame
+ begin_UDP, // marks byte position of UDP header within frame
+ begin_TCP, // marks byte position of TCP header within frame
+ begin_MSG; // marks byte position of first message byte (=payload) within frame
+
+ int // **** get payload (message) from a file ****
+ MSG_use_RAW_FILE, // 1 means update function should copy next chunk from file
+ MSG_use_HEX_FILE, // same but assumes file content such as "aa:bb:cc:f3:1e:..."
+ MSG_use_ASC_FILE; // same but interpretes file content as ASCII characters
+ // NOTE: if one of these are set to 1 then a filepointer is open !!!
+
+ // A protocol descriptor (p_desc) is only used for some statically
+ // defined protocols. Originally intended for more complicated protocols
+ // such as DNS.
+ void * p_desc; // optionally points to protocol descriptor (e. g. for DNS, CDP, etc)
+ int p_desc_type; // identifies the exact type of p_desc
+
+
+
+ // AutoMOPS provides a dynamic method to define new protocols. Here we need a pointer
+ // to the protocol definition for convenience and the complete protocol header field
+ // which is created by automops_update()
+ //
+ // Note: The used 'amp' should be memcpy'd for this particular mops
+ // because then we can store current PDU values here and the
+ // user can modify it later arbitrarily.
+ //
+ // Use automops_clone_automops() in automops.c for this.
+ //
+ struct automops *amp; // points to protocol definition
+ u_int8_t *amp_pdu; // contains the complete PDU as bytestring
+ int amp_pdu_s;
+
+
+ // Resulting frame:
+ u_int8_t frame[MAX_MOPS_FRAME_SIZE]; // will hold the complete frame
+ u_int32_t frame_s; // indicates the total frame size
+
+
+ // Ethernet parameters:
+ u_int8_t eth_dst[6];
+ u_int8_t eth_src[6];
+ int eth_src_israndom; // if set to 1 then the source address is to be randomized
+ u_int16_t eth_type;
+ u_int16_t eth_type_backup; // if original type must be restored (e. g. when removing MPLS labels)
+
+ // 802.3 parameters: LLC/SNAP
+ u_int16_t eth_len;
+ u_int8_t eth_snap[16]; // AA-AA-03-<OUI>-<TYPE>
+ int eth_snap_s; // usually 8 bytes
+
+
+ // 802.1Q VLAN Tag !!! NOTE: outer tag has lower index number (same byte-order as in frame[]) !!!
+ u_int8_t dot1Q[MAX_MOPS_DOT1Q_TAGS*4]; // All successive 802.1Q/P headers, 4 bytes per header: 0x8100, pri, cfi, id
+ int dot1Q_s; // how many bytes from above are really used
+ int dot1Q_isrange; // if 1, only the outer tag loops through the range.
+ int dot1Q_start;
+ int dot1Q_stop;
+
+
+ // MPLS label stack
+ u_int8_t mpls[MAX_MOPS_MPLS_TAGS*4]; // All successive labels
+ int mpls_s; // how many bytes from above are really used
+ int mpls_isrange; // if 1, only the outer tag loops through the range.
+ int mpls_start;
+ int mpls_stop;
+
+ // IP parameters -- NOTE: Everything here is in HOST BYTE ORDER !!!
+
+ u_int32_t ip_src; // By default interface address
+ u_int32_t ip_src_start; // start of range (HOST byte order => easy to count)
+ u_int32_t ip_src_stop; // stop of range (HOST byte order => easy to count)
+ int ip_src_isrange; // if set to 1 then the start/stop values above are valid.
+ int ip_src_israndom; // if set to 1 then the source address is to be randomized
+ u_int32_t ip_dst; // (HOST byte order)
+ u_int32_t ip_dst_start; // start of range (NOT network byte order => easy to count)
+ u_int32_t ip_dst_stop; // stop of range (NOT network byte order => easy to count)
+ int ip_dst_isrange; // if set to 1 then the start/stop values above are valid.
+ u_int16_t
+ ip_len,
+ ip_id,
+ ip_frag_offset, // 13 bit Offset: allowed values: 0..8191
+ ip_sum; // TODO: provide variable 'ip_sum_false' to create false checksum for various tests
+ int ip_IHL_false; // Default=0, set to 1 if user configured own (typically false) header length
+ int ip_len_false; // Default=0, set to 1 if user configured own (typically false) total length
+ int ip_sum_false; // Default=0, set to 1 if user configured own (typcially false) checksum
+ u_int8_t
+ ip_version,
+ ip_IHL, // header length (4 bits = 0..15)
+ ip_tos,
+ ip_flags_RS, // 0|1 ... Reserved flag "must be zero"
+ ip_flags_DF, // 0|1 ... Don't Fragment
+ ip_flags_MF, // 0|1 ... More Fragments
+ ip_fragsize, // if >0 it activates auto-fragmentation
+ ip_frag_overlap, // if >0 then all fragments overlap. Must be multiple of 8 but smaller than fragsize.
+ ip_ttl,
+ ip_proto;
+ u_int8_t
+ ip_option[1024]; // Any IP Option used?
+ int ip_option_used; // >0 if yes. The exact number also indicates which option(s) used - see mops_ip.c
+ u_int32_t
+ ip_option_s;
+
+
+ // General L4 parameters:
+ u_int16_t
+ sp, dp,
+ sp_start, sp_stop,
+ dp_start, dp_stop;
+ int
+ sp_isrand, // if set to 1 then use random port number for each sent packet
+ dp_isrand, // if set to 1 then use random port number for each sent packet
+ sp_isrange, // if set to 1 then start/stop values above are valid
+ dp_isrange; // if set to 1 then start/stop values above are valid
+
+ // UDP parameters
+ u_int16_t
+ udp_len, // includes header size (8 bytes)
+ udp_sum;
+ int udp_sum_false; // Default=0, set to 1 if user configured own (typcially false) checksum
+ int udp_len_false; // Default=0, set to 1 if user configured own (typcially false) length
+
+ // TCP parameters (RFC 793)
+ //
+ // 0 1 2 3
+ // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // | Source Port | Destination Port |
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // | Sequence Number |
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // | Acknowledgment Number |
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // | Data | |U|A|P|R|S|F| |
+ // | Offset| Reserved |R|C|S|S|Y|I| Window |
+ // | | |G|K|H|T|N|N| |
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // | Checksum | Urgent Pointer |
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // | Options | Padding |
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // | data |
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ //
+ u_int32_t
+ tcp_seq,
+ tcp_seq_start,
+ tcp_seq_stop,
+ tcp_seq_delta, // Also used instead of an 'isrange' variable
+ tcp_ack,
+ tcp_ack_start,
+ tcp_ack_stop,
+ tcp_ack_delta; // Also used instead of an 'isrange' variable
+ u_int8_t
+ tcp_offset, // Header length in multiples of 32 bit (4 bit value, 0..15)
+ tcp_res, // reserved (4 bits)
+ tcp_ctrl_CWR, // 0|1 - Congestion Window Reduced [RFC-3168]
+ tcp_ctrl_ECE, // 0|1 - ECN-Echo [RFC-3168]
+ tcp_ctrl_URG, // 0|1
+ tcp_ctrl_ACK, // 0|1
+ tcp_ctrl_PSH, // 0|1
+ tcp_ctrl_RST, // 0|1
+ tcp_ctrl_SYN, // 0|1
+ tcp_ctrl_FIN; // 0|1
+ u_int16_t
+ tcp_win,
+ tcp_sum,
+ tcp_urg,
+ tcp_len; // Only needed for the checksum calculation and is not transmitted (host order!)
+
+ int
+ tcp_sum_false, // Default=0, set to 1 if user configured own (typcially false) checksum
+ tcp_offset_false; // Default=0, set to 1 if user configured own (typcially false) offset
+ u_int8_t
+ tcp_option[1024];
+ u_int32_t
+ tcp_option_s;
+ int tcp_option_used; // >0 if yes. The exact number also indicates which option(s) used - see mops_tcp.c
+
+
+ // Message:
+ u_int8_t msg[MAX_MOPS_MSG_SIZE];
+ u_int32_t msg_s;
+ FILE *fp; // points to file if MSG_use_RAW_FILE or MSG_use_HEX_FILE or MSG_use_ASC_FILE is set to 1
+ u_int32_t chunk_s; // max chunk size to be copied from file
+
+
+ // User-defined counters:
+ struct mops_counter counter[MAX_MOPS_COUNTERS_PER_PACKET];
+ int used_counters; // number of currently defined counters
+
+};
+
+
+
+struct mops_ext_arp
+{
+ u_int16_t hw_type;
+ u_int16_t pr_type;
+ u_int8_t hw_size;
+ u_int8_t pr_size;
+ u_int16_t opcode;
+ u_int8_t sender_mac[6];
+ u_int8_t sender_ip[4];
+ u_int8_t target_mac[6];
+ u_int8_t target_ip[4];
+ u_int16_t trailer;
+};
+
+
+
+struct mops_ext_bpdu // TODO
+{
+ u_int16_t id;
+ u_int8_t version; // 0=802.1D, 2=RSTP(802.1w)
+ u_int8_t bpdu_type; // 0=conf, 1=topology change (actually in big endian!), 2=RSTP/MSTP
+ u_int8_t flags; // X... .... = TCN ACK
+ // .X.. .... = Agreement
+ // ..X. .... = Forwarding
+ // ...X .... = Learning
+ // .... XX.. = Port Role (e. g. 11=Desgn)
+ // .... ..X. = Proposal
+ // .... ...X = TCN
+ u_int8_t root_id[8]; // Root BID
+ u_int32_t root_pc; // Root Path Cost
+ u_int8_t bridge_id[8]; // Own BID
+ u_int16_t port_id; // Port Identifier
+ u_int16_t message_age; // All timers are multiples of 1/256 sec. Thus times range from 0 to 256 seconds.
+ u_int16_t max_age;
+ u_int16_t hello_time;
+ u_int16_t f_delay;
+ u_int8_t trailer[8]; // either all-zero or 34:00:02:VLAN(16bit):00:00 when PVST+
+
+ int rstp; // 1 = RSTP
+ int pvst; // 1=PVST+ , 0 = 802.1D
+ int mstp; // 1 = Multiple Instance STP
+
+};
+
+struct mops_ext_lldp {
+ int non_conform; // if 1 then the order of TLVs is arbitrary
+ int chassis_id_subtype;
+ int chassis_id_len;
+ u_int8_t *chassis_id;
+ int port_id_subtype;
+ int port_id_len;
+ u_int8_t *port_id;
+ int TTL;
+ int optional_tlvs_s;
+ u_int8_t *optional_tlvs;
+
+};
+
+enum igmp_type {IGMP_GENERAL_QUERY,
+ IGMP_GSPEC_QUERY,
+ IGMP_V2_REPORT,
+ IGMP_V1_REPORT,
+ IGMP_LEAVE};
+
+struct igmp_sa_struct { // For single linked list to hold unicast addresses for IGMPv3 query
+ u_int32_t sa;
+ struct igmp_sa_struct *next;
+};
+
+struct igmp_aux_struct { // For single linked list to hold auxilary data for IGMPv3 report
+ u_int32_t aux_data;
+ struct igmp_aux_struct *next;
+};
+
+
+struct igmp_group_struct { // For single linked list to hold IGMPv3 group records
+ u_int8_t record_type;
+ u_int8_t aux_data_len;
+ u_int16_t nr_sources;
+ u_int32_t mcast_addr;
+ struct igmp_sa_struct *sa_list;
+ struct igmp_aux_struct *aux_list;
+ struct igmp_group_struct *next;
+};
+
+
+
+struct mops_ext_igmp {
+ int version; // internal, not in header
+ u_int8_t type;
+ u_int8_t max_resp_code; // equally: 'max response time' for IGMPv2
+ u_int16_t sum;
+ int sum_false; // if '1' then sum contains user-provided checksum; if '0' then autocompute!
+ u_int32_t group_addr;
+ u_int8_t
+ resv4, // resv4 + S + QRV => one byte in IGMPv3 query
+ S, // S = Suppress Router-Side Processing
+ QRV; // QRV = Querier's Robustness Variable
+ u_int8_t resv8; // needed in IGMPv3 response AND IGMPv1 query+response
+ u_int16_t resv16; // needed in IGMPv3 response
+ u_int8_t QQIC; // Querier's Query Interval Code
+ u_int16_t nr_entries; // either number of sources (=query) or group records (=response)
+ struct igmp_sa_struct *sa_list;
+};
+
+
+struct mops_ext_cdp // TODO
+{
+ u_int8_t id;
+ u_int16_t hw_type;
+};
+
+struct mops_ext_dns // TODO: complete
+{
+ // Main 16-bit fields
+ u_int16_t id;
+ u_int16_t num_queries;
+ u_int16_t num_answers;
+ u_int16_t num_author;
+ u_int16_t num_add;
+ u_int16_t type;
+
+ // Flags (1 bit, except where noted)
+ u_int8_t qr;
+ u_int8_t opcode; // 4 bits
+ u_int8_t aa;
+ u_int8_t tc;
+ u_int8_t rd;
+ u_int8_t ra;
+ u_int8_t z; // 3 bits
+ u_int8_t rcode; // 4 bits
+
+};
+
+
+struct mops_ext_icmp // TODO
+{
+ u_int8_t id;
+ u_int16_t hw_type;
+};
+
+struct mops_ext_rtp
+{
+ // Vars to hold flag values:
+ u_int8_t v,
+ p,
+ x, // only sets the flag; if you really want an extension header also set "x_type" (see below)
+ cc, // csrc_count visible in header (has no further meaning, thus support for "wrong" headers)
+ cc_real, // real csrc_count (only used internally to create CSRC list)
+ m,
+ pt; // selects inter-packet delay and payload_s;
+
+ u_int16_t sqnr; // initial sqnr
+ u_int32_t tst; // initial timestamp
+ u_int32_t ssrc; // !!! also used to identify measurement streams !!!
+ u_int32_t csrc[16]; // NOTE: only up to 15 CSRC's are allowed according RFC 3550
+
+ // additionally:
+ int tst_inc; // The increment of the tst (depends on codec)
+ u_int8_t payload[MOPS_RTP_MAX_PAYLOAD_SIZE]; //
+ int payload_s; // is the same as tst_inc when codec is G.711 but different with other codecs!
+ int source; // Optionally draw data from file or /dev/dsp or such [TODO]
+ int rtp_header_len; // will be set by mops_update_rtp()
+ // one optional header extension:
+ int x_type; // IMPORTANT: which extension header to use: 0 = none, 42 = Mausezahn, 1 = Aero
+ u_int8_t extension[64]; // a user configurable extension header [CURRENTLY UNUSED]
+};
+
+
+
+struct mops_ext_syslog //TODO
+{
+ u_int16_t hw_type;
+ u_int16_t pr_type;
+};
+
+
+/////////////////////////////////////////////////////////////////
+
+struct mops *mp_head; // This global will point to the head of the mops list
+
+/////////////////////////////////////////////////////////////////
+// MOPS Prototypes:
+
+void mops_hton2 (u_int16_t *host16, u_int8_t *net16);
+void mops_hton4 (u_int32_t *host32, u_int8_t *net32);
+
+int mops_get_proto_info (struct mops *mp, char *layers, char *proto);
+
+// Inserts value in 'flag' (up to 7 bits are useful) into the target
+// with an optional left-shift. For example if flag contains a 4-bit value
+// and should be placed within the target in bit positions 3-6 like:
+//
+// 7 6 5 4 3 2 1 0
+// +--+--+--+--+--+--+--+--+
+// | | FLAGS | | | |
+// +--+--+--+--+--+--+--+--+
+//
+// then simply call:
+//
+// (void) mops_flags ( &target, &flag, 3 );
+//
+// Note:
+// 1) shift=0 means no shift
+// 2) Because of speed we do not check if the arguments are reasonable
+//
+void mops_flags (u_int8_t *target, u_int8_t *flag, int shift);
+
+u_int16_t mops_sum16 (u_int16_t len, u_int8_t buff[]);
+
+struct mops * mops_init ();
+struct mops * mops_alloc_packet (struct mops *cur);
+struct mops * mops_delete_packet (struct mops *cur);
+int mops_reset_packet(struct mops *cur);
+
+int mops_dump_all (struct mops* list, char* str);
+struct mops * mops_search_name (struct mops* list, char *key);
+struct mops * mops_search_id (struct mops* list, u_int32_t key);
+
+void mops_delete_all (struct mops* list);
+void mops_cleanup (struct mops* list);
+
+// State functions
+int mops_state (struct mops *mp);
+int mops_is_active (struct mops *mp);
+void mops_set_conf (struct mops *mp);
+void mops_set_active (struct mops *mp);
+void mops_set_seqact (struct mops *mp);
+int mops_is_seqact (struct mops *mp);
+int mops_is_any_active (struct mops *mp);
+
+// For debugging purposes
+int mops_print_frame (struct mops *mp, char *str);
+
+// sets UDP or TCP checksum within mp->frame
+// TODO: copying the whole segment is ugly and slow;
+// make it more efficient and realize it in-place.
+//
+int mops_get_transport_sum (struct mops *mp);
+
+// returns new counter index for given packet
+// or -1 if all counters used already
+int mops_get_counter (struct mops *mp);
+
+// This is the very basic MOPS update function. It simply updates the whole
+// MOPS frame specified by pointer mp. If you only want to update specific
+// details then please see the other related specialized functions which are
+// faster.
+int mops_update (struct mops *mp);
+
+int mops_set_defaults (struct mops *mp);
+
+// Get global device index for a given device name.
+int mops_get_device_index(char *devname);
+
+// Assign device-specific addresses to packet.
+int mops_use_device(struct mops * clipkt, int i);
+
+// Find and returns a new unique packet id
+// If none can be found, returns -1.
+int mops_get_new_pkt_id (struct mops *mp);
+
+// Simply sets specified 'layer switches' in struct mops to zero
+int mops_clear_layers (struct mops *mp, int l);
+
+// Transmission functions
+int mops_tx_simple (struct mops *mp);
+void *mops_tx_thread_native (void *arg);
+void *mops_interval_thread (void *arg);
+void *mops_sequence_thread (void *arg);
+
+
+int mops_destroy_thread (struct mops *mp);
+
+// Utility functions for packet headers (aka *** METHODS *** for the object-oriented nerds)
+int mops_dot1Q_remove (struct mops *mp, int k);
+int mops_dot1Q_nocfi (struct mops *mp, int k);
+int mops_dot1Q_cfi (struct mops *mp, int k);
+int mops_dot1Q (struct mops *mp, int i, int m, u_int16_t v, u_int16_t c);
+
+int mops_mpls_remove (struct mops *mp, int j);
+int mops_mpls_bos (struct mops *mp, int k);
+int mops_mpls_nobos (struct mops *mp, int k);
+int mops_mpls(struct mops *mp, int i, int m, u_int32_t Label, u_int8_t Exp, u_int8_t TTL);
+
+int mops_ip_get_dst_mac(struct device_struct *dev, u_int8_t *ip, u_int8_t *mac);
+int mops_ip_dscp(struct mops *mp, char *argv);
+int mops_ip_tos (struct mops* mp, int ipp, int tos, int mbz);
+int mops_ip_option_ra (struct mops* mp, int value);
+int mops_ip_option_remove_all (struct mops* mp);
+
+u_int32_t mops_tcp_complexity_sqnr (struct mops * mp);
+u_int32_t mops_tcp_complexity_acknr (struct mops * mp);
+
+// Prints current flag settings in the provided string 'str'.
+int mops_tcp_flags2str (struct mops* mp, char *str);
+
+int mops_tcp_add_option (struct mops* mp,
+ int mss,
+ int sack,
+ int scale,
+ u_int32_t tsval,
+ u_int32_t tsecr);
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// ****** The following are important to easily create new packet types ******
+//
+//////////////////////////////////////////////////////////////////////////////
+
+// Adds single byte to msg
+int mops_msg_add_byte (struct mops *mp, u_int8_t data);
+
+// Adds bit field in *previous* msg-byte using optional left-shift
+int mops_msg_add_field (struct mops *mp, u_int8_t data, int shift);
+
+// Adds two bytes in network byte order to msg
+int mops_msg_add_2bytes (struct mops *mp, u_int16_t data);
+
+// Adds four bytes in network byte order to msg
+int mops_msg_add_4bytes (struct mops *mp, u_int32_t data);
+
+// Adds string of bytes with lenght len
+int mops_msg_add_string (struct mops *mp, u_int8_t *str, int len);
+
+// Add counter to message
+int mops_msg_add_counter (struct mops *mp,
+ int random, // 1=random, 0=use start/stop/step
+ u_int32_t start, // HOST BYTE ORDER
+ u_int32_t stop, // HOST BYTE ORDER
+ u_int32_t step, // HOST BYTE ORDER
+ int bytes // number of bytes used (1|2|4) - selects hton2 or hton4
+ );
+
+// Returns 0 if identical, 1 if different
+int compare_ip (u_int8_t *ip1, u_int8_t *ip2);
+
+// Returns 0 if identical, 1 if different
+int compare_mac (u_int8_t *mac1, u_int8_t *mac2);
+
+// Converts a 'struct timespec' value into a human readable string
+int timespec2str(struct timespec *t, char *str);
+
+// -------------------------------------------------------------------------------
+
+// Add protocol descriptor of type ptype
+//
+// Smart behaviour: If a p_desc has been already assigned, this function
+// clears and frees everything before assigning another p_desc structure.
+//
+int mops_ext_add_pdesc (struct mops *mp, int ptype);
+
+// Create msg based on p_desc data.
+// After that call mops_update and the frame is complete.
+int mops_ext_update (struct mops *mp);
+
+// Delete any protocol descriptor
+int mops_ext_del_pdesc (struct mops *mp);
+
+// Initialization functions for p_desc
+int mops_init_pdesc_arp(struct mops *mp);
+int mops_init_pdesc_bpdu(struct mops *mp);
+int mops_init_pdesc_cdp(struct mops *mp);
+int mops_init_pdesc_dns(struct mops *mp);
+int mops_init_pdesc_icmp(struct mops *mp);
+int mops_init_pdesc_igmp(struct mops *mp);
+int mops_init_pdesc_lldp(struct mops *mp);
+int mops_init_pdesc_syslog(struct mops *mp);
+int mops_init_pdesc_rtp(struct mops *mp);
+
+int mops_create_igmpv2 (struct mops *mp,
+ int override, // normally zero, but if '1' the user want to override defaults
+ int igmp_type, // IGMP_GENERAL_QUERY, IGMP_GSPEC_QUERY, IGMP_V2_REPORT, IGMP_V1_REPORT, IGMP_LEAVE
+ int mrt, // max response time
+ int sum, //-1 means auto-compute, other values means 'use this user-defined value'
+ u_int32_t group_addr);
+
+
+// Update functions for p_desc => msg
+int mops_update_arp(struct mops * mp);
+int mops_update_bpdu(struct mops * mp);
+int mops_update_igmp (struct mops * mp);
+int mops_update_lldp (struct mops * mp);
+int mops_update_rtp (struct mops * mp);
+int mops_update_rtp_dynamics (struct mops * mp);
+
+// Utility functions for p_desc
+int mops_pdesc_mstrings (char *dst, char* argv[], int argc, int max);
+int mops_pdesc_1byte (u_int8_t *dst, char* usr, int spec, int min, int max);
+int mops_pdesc_2byte (u_int16_t *dst, char* usr, int spec, int min, int max);
+int mops_pdesc_4byte (u_int32_t *dst, char* usr, int spec, unsigned long int min, unsigned long int max);
+int mops_pdesc_mac (u_int8_t *dst, char* usr);
+int mops_pdesc_ip (u_int8_t *dst, char* usr);
+
+// Other p_desc related functions
+int mops_create_bpdu_bid(struct mops * mp, int pri, int esi, char *mac, int bid_or_rid);
+int mops_create_bpdu_trailer (struct mops * mp, u_int16_t vlan);
+int mops_lldp_tlv (u_int8_t *tlv, int type, int len, u_int8_t *value);
+int mops_lldp_tlv_chassis (u_int8_t *tlv, int subtype, int len, u_int8_t *cid);
+int mops_lldp_tlv_port (u_int8_t *tlv, int subtype, int len, u_int8_t *pid);
+int mops_lldp_tlv_TTL (u_int8_t *tlv, int ttl);
+int mops_lldp_tlv_end (u_int8_t *tlv);
+int mops_lldp_opt_tlv_bad (struct mops *mp, int type, int badlen, int len, u_int8_t *value);
+int mops_lldp_opt_tlv_org (struct mops *mp, int oui, int subtype, int len, u_int8_t *inf);
+int mops_lldp_opt_tlv_chassis (struct mops *mp, int subtype, int len, u_int8_t *cid);
+int mops_lldp_opt_tlv_port (struct mops *mp, int subtype, int len, u_int8_t *pid);
+int mops_lldp_opt_tlv_TTL (struct mops *mp, int ttl);
+int mops_lldp_opt_tlv_vlan (struct mops *mp, int vlan);
+int mops_lldp_opt_tlv (struct mops *mp, int type, int len, u_int8_t *value);
+int mops_lldp_opt_tlv_end (struct mops *mp) ;
+
+
+/////////////////////////// Services /////////////////////////////
+
+// ARP Service: Resolves MAC address of given IP address and interface
+int service_arp(char *dev, u_int8_t *ip, u_int8_t *mac);
+
+int mops_rx_arp ();
+void *rx_arp (void *arg);
+void got_arp_packet (u_char *args, const struct pcap_pkthdr *header, const u_char *packet);
+
+
+//////////////////// directmops prototypes: ///////////////////////////
+int mops_direct(char* dev, int mops_type, char* argstring);
+
+
+//////////////////// automops prototypes: //////////////////////////////////
+
+
+struct automops * automops_init();
+struct automops * automops_alloc_protocol();
+struct automops * automops_delete_protocol();
+struct automops * automops_search_protocol();
+int automops_dump_all (struct automops* list);
+void automops_set_defaults(struct automops * cur);
+struct fields * automops_add_field (struct automops *amp);
+void automops_field_set_defaults(struct fields *f);
+int automops_delete_fields (struct automops *amp);
+int mops_str2layers(char *d);
+int amp_add_pentry (struct automops *amp, int xntag, char *d);
+int amp_add_fentry (struct automops *amp, struct fields *f, int xntag, char *d);
+int amp_checkindex(struct automops *amp, int i);
+int amp_str2type(char *d);
+int amp_type2str(int t, char *s);
+struct fields * amp_getfield_byname(struct automops *amp, char *d);
+struct automops * amp_getamp_byname(struct automops *head, char *d);
+// Creates an independent automops element for mops
+// (it will be not part of any linked list so, next=prev=NULL)
+struct automops * automops_clone_automops(struct automops * amp);
+int amperr2str (int e, char *s);
+
+// Create automops PDU within *mp based on data in *amp
+//
+int automops_update (struct mops *mp, struct automops *amp);
+void automops_cleanup (struct automops *list);
+
+char * mapfile (char *fn);
+
+////////////////////////// XML support //////////////////////////////
+//
+//
+
+
+// Simple stack needed to check proper XML nesting.
+// The corresponding methods are defined at the bottom.
+struct xnstack {
+ int data[XN_MAX_STACK];
+ int cursize;
+};
+
+enum xml_tags { // mention all allowed tags here!
+ xml_protocol,
+ xml_field,
+ xml_name,
+ xml_desc,
+ xml_requires,
+ xml_conflicts,
+ xml_payloadtype,
+ xml_payload,
+ xml_payloadhex,
+ xml_index,
+ xml_longdesc,
+ xml_type,
+ xml_constant,
+ xml_value,
+ xml_valname,
+ xml_min,
+ xml_max,
+ xml_tlvt,
+ xml_tlvl,
+ xml_lshift
+};
+
+
+int xml_check_parent(int t, int p);
+int xml_tag2int (char *t);
+
+int parse_protocol (char *p);
+int xml_getnext_tag (char *p, char *t);
+int xml_canonic (char *p);
+int xml_get_data (char *p, char *t);
+int xml_readin (struct automops *amp, char *p);
+
+void xnstack_init(struct xnstack *s);
+int xnstack_get_top(struct xnstack *s);
+int xnstack_push(struct xnstack *s, int d);
+int xnstack_pop(struct xnstack *s);
+int xnstack_size(struct xnstack *s);
+
+#endif
+
diff --git a/staging/mops_checksums.c b/staging/mops_checksums.c
new file mode 100644
index 0000000..be20f21
--- /dev/null
+++ b/staging/mops_checksums.c
@@ -0,0 +1,128 @@
+/*
+ * Mausezahn - A fast versatile traffic generator
+ * Copyright (C) 2008-2010 Herbert Haas
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
+ *
+*/
+
+#include "mz.h"
+#include "mops.h"
+
+
+
+
+// -- TOC: --
+//
+// u_int16_t mops_sum16 (u_int16_t len, u_int8_t buff[])
+// int mops_get_transport_sum (struct mops *mp)
+
+
+//////////////////////////////////////////////////////////////////////////////////
+//
+// See also:
+//
+// RFC1071 - Computing the Internet checksum
+//
+//////////////////////////////////////////////////////////////////////////////////
+
+
+
+// Generic 16-bit checksum code as required for IP and other headers.
+// The checksum is calculated over buff[] which is of length len.
+//
+// RETURN VALUE: The checksum! (Validated - correct!!!)
+//
+// Example: t16 = mops_sum16 (20, &mp->frame[fp]);
+//
+u_int16_t mops_sum16 (u_int16_t len, u_int8_t buff[])
+{
+
+ u_int16_t word16;
+ u_int32_t sum=0;
+ u_int16_t i;
+
+ // make 16 bit words out of every two adjacent 8 bit words in the packet and add them up
+ for (i=0; i<len; i=i+2)
+ {
+ word16 =((buff[i]<<8)&0xFF00)+buff[i+1];
+ sum = sum + (u_int32_t) word16;
+ }
+
+ // take only 16 bits out of the 32 bit sum and add up the carries
+ while (sum>>16)
+ sum = (sum & 0xFFFF)+(sum >> 16);
+
+ // one's complement the result
+ sum = ~sum;
+
+ return ((u_int16_t) sum);
+}
+
+
+
+
+
+// sets UDP or TCP checksum within mp[]->frame
+// TODO: copying the whole segment is ugly and slow;
+// make it more efficient and realize it in-place.
+//
+int mops_get_transport_sum(struct mops *mp)
+{
+ u_int8_t buf[MAX_PAYLOAD_SIZE];
+ u_int16_t len;
+ int udp_used;
+
+ u_int16_t sum;
+
+ udp_used = mp->use_UDP; // 0 or 1, 0 means TCP
+
+ // IP Pseudoheader (12 Bytes)
+ mops_hton4(&mp->ip_src, &buf[0]);
+ mops_hton4(&mp->ip_dst, &buf[4]);
+ buf[9]=0x00;
+
+
+ // Copy segment
+ if (udp_used)
+ {
+ buf[10]=0x11; // proto UDP (17 dec)
+ len = mp->udp_len;
+ mops_hton2(&len, &buf[11]);
+ memcpy(&buf[13], &mp->frame[mp->begin_UDP], len);
+ // reset checksum to zero
+ buf[19] = 0x00;
+ buf[20] = 0x00;
+ sum = mops_sum16(len+12, buf);
+ // insert checksum in UDP header (in frame)
+ mops_hton2 (&sum, &mp->frame[(mp->begin_UDP)+7]);
+
+ }
+ else
+ {
+ buf[10]=0x06; // proto TCP
+ len = mp->ip_len - mp->ip_IHL;
+ mops_hton2((u_int16_t*)&len, &buf[11]);
+ memcpy(&buf[13], &mp->frame[mp->begin_TCP], len);
+ // reset checksum to zero
+ buf[29] = 0x00;
+ buf[30] = 0x00;
+ sum = mops_sum16(len+12, buf);
+ // insert checksum in TCP header (in frame)
+ mops_hton2 (&sum, &mp->frame[(mp->begin_TCP)+17]);
+ }
+
+
+ return 0;
+}
+
diff --git a/staging/mops_dot1Q.c b/staging/mops_dot1Q.c
new file mode 100644
index 0000000..1a22439
--- /dev/null
+++ b/staging/mops_dot1Q.c
@@ -0,0 +1,131 @@
+/*
+ * Mausezahn - A fast versatile traffic generator
+ * Copyright (C) 2008-2010 Herbert Haas
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
+ *
+*/
+
+#include "mz.h"
+#include "mops.h"
+
+
+// Remove 802.1Q tags from packet mp
+//
+// k indicates which tag to be removed (1..n)
+// k=0 means: remove all tags!
+//
+// RETURN VALUE: 1 upon failure, 0 upon success
+int mops_dot1Q_remove (struct mops *mp, int k)
+{
+ int a,b,n;
+
+ if (k==0) {
+ mp->dot1Q_s=0;
+ mp->use_dot1Q=0;
+ return 0;
+ }
+
+ n = mp->dot1Q_s/4; // n = total number of tags
+ if (k>n) return 1;
+
+ if (k==1) { // only delete the single tag
+ mp->dot1Q_s=0;
+ mp->use_dot1Q=0;
+ return 0;
+ }
+
+ // we have more than one tag:
+ //
+ if (k==n) { // remove last tag (of several)
+ mp->dot1Q_s -=4;
+ return 0;
+ }
+
+ // remove some non-ending tag: 0, 1, 2, 3
+ a = (k-1)*4; // target
+ b = k*4; // source (what should be copied)
+ memcpy(&mp->dot1Q[a], &mp->dot1Q[b], (n-k)*4);
+ mp->dot1Q_s -=4;
+
+ return 0;
+}
+
+
+// Unset CFI in tag k where k=1..n
+int mops_dot1Q_nocfi (struct mops *mp, int k)
+{
+ int n;
+
+ n = mp->dot1Q_s/4; // n = total number of tags
+ if (k>n) return 1;
+
+ mp->dot1Q[((k-1)*4)+2] &=0xef; // unset CFI (0xef = 1110 1111)
+ return 0;
+}
+
+
+// Set CFI in tag k where k=1..n
+int mops_dot1Q_cfi (struct mops *mp, int k)
+{
+ int n;
+
+ n = mp->dot1Q_s/4; // n = total number of tags
+ if (k>n) return 1;
+
+ mp->dot1Q[((k-1)*4)+2] |=0x10; // set CFI (0x10 = 0001 0000)
+ return 0;
+}
+
+
+// Assign 802.1Q tag with
+// v ... VLAN
+// c ... CoS
+// i ... tag position (starting from zero!)
+//
+// m ... modification: 1 = dot1Q_s is not changed
+//
+// NOTE:
+// When called from for-loop to add all tags the total size dot1Q_s
+// is updated continuously, therefore use m=1.
+//
+// But when changing a particular tag within an existing 802.1Q stack
+// the total number of tags does not change, therefore use m=0.
+//
+// RETURN VALUE: 0 upon success, 1 upon failure
+//
+int mops_dot1Q (struct mops *mp, int i, int m, u_int16_t v, u_int16_t c)
+{
+ u_int8_t *ptr, c8;
+
+ if (i>=MAX_MOPS_DOT1Q_TAGS) return 1; // max number of tags, see definitions in mops.h
+ if ((v>4095)||(c>7)) return 1; // greater values do not make sense
+
+ // Format: 0x8100 CoS-CFI-VLAN
+ // where c=CoS, v=VLAN
+ c8 = (u_int8_t) c;
+ mp->dot1Q[4*i+0]= 0x81;
+ mp->dot1Q[4*i+1]= 0x00;
+ ptr = (u_int8_t*) &v;
+ mp->dot1Q[4*i+3]=*ptr;
+ mp->dot1Q[4*i+2]=*(ptr+1);
+ mp->dot1Q[4*i+2]^= (c8 << 5);
+
+ if (m) {
+ mp->dot1Q_s=4*(1+i); // NOTE: dot1Q_s = current tag position + 1
+ if (mp->dot1Q_s) mp->use_dot1Q = 1;
+ }
+
+ return 0;
+}
+
diff --git a/staging/mops_ext.c b/staging/mops_ext.c
new file mode 100644
index 0000000..0a32a05
--- /dev/null
+++ b/staging/mops_ext.c
@@ -0,0 +1,466 @@
+/*
+ * Mausezahn - A fast versatile traffic generator
+ * Copyright (C) 2008-2010 Herbert Haas
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
+ *
+*/
+
+
+
+#include "mz.h"
+#include "mops.h"
+
+
+
+// Add protocol descriptor of type ptype
+//
+// Smart behaviour:
+//
+// - If the desired p_desc has been assigned already, we leave everything
+// as it is and return to the calling function (return 0).
+//
+// - If a p_desc of another type has been already assigned, this function
+// clears and frees everything before assigning another p_desc structure.
+//
+int mops_ext_add_pdesc (struct mops *mp, int ptype)
+{
+
+ // 1. check if desired p_desc is already assigned
+ if ( (mp->p_desc != NULL) && (mp->p_desc_type == ptype) ) {
+ return 0;
+ }
+
+ // 2. remove older p_desc
+ if (mp->p_desc_type != MOPS_NO_PDESC) {
+ if (mops_ext_del_pdesc (mp)) return 1;
+ }
+
+ // 3. allocate and assign a p_desp
+ switch (ptype) {
+ case MOPS_ARP:
+ mp->p_desc = ( MOPS_EXT_ARP ) malloc ( sizeof (struct mops_ext_arp ) );
+ mp->p_desc_type = MOPS_ARP;
+ mops_init_pdesc_arp(mp);
+ break;
+ case MOPS_BPDU:
+ mp->p_desc = ( MOPS_EXT_BPDU ) malloc ( sizeof (struct mops_ext_bpdu ) );
+ mp->p_desc_type = MOPS_BPDU;
+ mops_init_pdesc_bpdu(mp);
+ break;
+ case MOPS_CDP:
+ mp->p_desc = ( MOPS_EXT_CDP ) malloc ( sizeof (struct mops_ext_cdp ) );
+ mp->p_desc_type = MOPS_CDP;
+ mops_init_pdesc_cdp(mp);
+ break;
+ case MOPS_DNS:
+ mp->p_desc = ( MOPS_EXT_DNS ) malloc ( sizeof (struct mops_ext_dns ) );
+ mp->p_desc_type = MOPS_DNS;
+ mops_init_pdesc_dns(mp);
+ break;
+ case MOPS_ICMP:
+ mp->p_desc = ( MOPS_EXT_ICMP ) malloc ( sizeof (struct mops_ext_icmp ) );
+ mp->p_desc_type = MOPS_ICMP;
+ mops_init_pdesc_icmp(mp);
+ break;
+ case MOPS_IGMP:
+ mp->p_desc = ( MOPS_EXT_IGMP ) malloc ( sizeof (struct mops_ext_igmp ) );
+ mp->p_desc_type = MOPS_IGMP;
+ mops_init_pdesc_igmp(mp);
+ break;
+ case MOPS_RTP:
+ mp->p_desc = ( MOPS_EXT_RTP ) malloc ( sizeof (struct mops_ext_rtp ) );
+ mp->p_desc_type = MOPS_RTP;
+ mops_init_pdesc_rtp(mp);
+ break;
+ case MOPS_LLDP:
+ mp->p_desc = ( MOPS_EXT_LLDP ) malloc ( sizeof (struct mops_ext_lldp ) );
+ ((struct mops_ext_lldp *)mp->p_desc)->chassis_id = NULL;
+ ((struct mops_ext_lldp *)mp->p_desc)->port_id = NULL;
+ ((struct mops_ext_lldp *)mp->p_desc)->optional_tlvs = NULL;
+ mp->p_desc_type = MOPS_LLDP;
+ mops_init_pdesc_lldp(mp);
+ break;
+ case MOPS_SYSLOG:
+ mp->p_desc = ( MOPS_EXT_SYSLOG ) malloc ( sizeof (struct mops_ext_syslog ) );
+ mp->p_desc_type = MOPS_SYSLOG;
+ mops_init_pdesc_syslog(mp);
+ break;
+ default:
+ return 1; // unknown protocol
+ }
+
+ if (mp->p_desc == NULL) {
+ fprintf (stderr, "mz/mops: could not allocate memory for mops element!\n");
+ mp->p_desc_type = MOPS_NO_PDESC;
+ return 1;
+ }
+
+ return 0;
+}
+
+
+// Delete any protocol descriptor
+// 1) Free memory
+// 2) Reset p_desc and p_desc_type
+//
+int mops_ext_del_pdesc (struct mops *mp)
+{
+
+ mp->p_desc_type = MOPS_NO_PDESC;
+ if (mp->p_desc==NULL) return 1; // already NULL pointer, nothing to free()
+
+ switch (mp->p_desc_type) {
+ case MOPS_ARP:
+ free ( (MOPS_EXT_ARP) mp->p_desc );
+ break;
+ case MOPS_BPDU:
+ free ( (MOPS_EXT_BPDU) mp->p_desc );
+ break;
+ case MOPS_CDP:
+ free ( (MOPS_EXT_CDP) mp->p_desc );
+ break;
+ case MOPS_DNS:
+ free ( (MOPS_EXT_DNS) mp->p_desc );
+ break;
+ case MOPS_ICMP:
+ free ( (MOPS_EXT_ICMP) mp->p_desc );
+ break;
+ case MOPS_IGMP:
+ free ( (MOPS_EXT_IGMP) mp->p_desc );
+ break;
+ case MOPS_RTP:
+ free ( (MOPS_EXT_RTP) mp->p_desc );
+ break;
+ case MOPS_LLDP:
+ if ( ((struct mops_ext_lldp *) mp->p_desc)->chassis_id != NULL)
+ free ( ((struct mops_ext_lldp *) mp->p_desc)->chassis_id);
+ if ( ((struct mops_ext_lldp *) mp->p_desc)->port_id != NULL)
+ free ( ((struct mops_ext_lldp *) mp->p_desc)->port_id);
+ if ( ((struct mops_ext_lldp *) mp->p_desc)->optional_tlvs != NULL)
+ free ( ((struct mops_ext_lldp *) mp->p_desc)->optional_tlvs);
+ free ( (MOPS_EXT_LLDP) mp->p_desc );
+ break;
+ case MOPS_SYSLOG:
+ free ( (MOPS_EXT_SYSLOG) mp->p_desc );
+ break;
+ case MOPS_NO_PDESC: // already cleared?
+ break;
+
+ /* nothing */
+ }
+
+ mp->p_desc = NULL;
+ return 0;
+}
+
+
+// Create msg based on p_desc data.
+// After that call mops_update and the frame is complete.
+int mops_ext_update (struct mops *mp)
+{
+
+ switch (mp->p_desc_type) {
+ case MOPS_ARP:
+ mops_update_arp(mp);
+ break;
+ case MOPS_BPDU:
+ mops_update_bpdu(mp);
+ break;
+ case MOPS_CDP:
+ break;
+ case MOPS_DNS:
+ break;
+ case MOPS_ICMP:
+ break;
+ case MOPS_IGMP:
+ mops_update_igmp(mp);
+ break;
+ case MOPS_RTP:
+ mops_update_rtp(mp);
+ break;
+ case MOPS_LLDP:
+ mops_update_lldp(mp);
+ break;
+ case MOPS_SYSLOG:
+ break;
+ case MOPS_NO_PDESC:
+ return 0; // OK!
+ break;
+ default:
+ return 1; // Unknown value!?
+ }
+
+ return 0;
+}
+
+
+//////// General parameter update functions - modify a single parameter of p_desc structure
+//
+// 'Standardized' return values:
+//
+// MOPS_PDESC_LOW Value smaller than lower bound - but will set
+// MOPS_PDESC_HIGH Value larger than upper bound - but will set
+//
+// MOPS_PDESC_OVERFLOW Value exceeded possible range
+//
+// MOPS_PDESC_NO_MAC Invalid MAC address
+// MOPS_PDESC_NO_IP Invalid IP address
+//
+// MOPS_PDESC_FAILURE Unspecified problem
+// MOPS_PDESC_SUCCESS = 0 Value assigned properly
+//
+// 'Standardized' format:
+//
+// mops_pdesc_function ( *PDESC_VAR , USER_STRING , LIMITS )
+
+
+
+
+// Assign one or more strings to a single string
+// Practical example: Concatenate multiple tokens from the CLI
+// Will never copy more than 'max' bytes to 'dst'
+//
+// EXAMPLE:
+//
+// mops_pdesc_mstrings (clipkt->description, argv, argc, 20);
+//
+int mops_pdesc_mstrings (char *dst, char* argv[], int argc, int max)
+{
+ int i;
+ char tmp[10000]; // should be sufficient for all purposes here
+
+ dst[0]=0x00;
+ tmp[0]=0x00;
+
+ for (i=0; i<argc; i++)
+ { // check if next word would exceed tmp:
+ if ((1+strlen(argv[i]))>(10000-strlen(tmp))) // The '1+' counts for the additional space
+ return MOPS_PDESC_OVERFLOW;
+ else
+ {
+ strncat(tmp, argv[i], 80); // Enforcing a maximum word length
+ strcat(tmp, " "); // We get only the tokens, not the spaces inbetween
+ }
+ }
+
+ strncpy(dst, tmp, max);
+ if (strlen(tmp)>max) return MOPS_PDESC_OVERFLOW;
+
+ return MOPS_PDESC_SUCCESS;
+}
+
+
+
+
+
+// Assign decimal or hexadecimal u_int8_t value, depending on spec
+// spec can be 0=dec or 1=hex
+int mops_pdesc_1byte (u_int8_t *dst, char* usr, int spec, int min, int max)
+{
+ u_int32_t i;
+ int retval = MOPS_PDESC_SUCCESS;
+
+ if ((max>255)||(min>255)) return MOPS_PDESC_FAILURE;
+
+ if (spec==0)
+ {
+ i = (u_int32_t) str2int (usr);
+ }
+ else
+ {
+ i = (u_int32_t) xstr2int (usr);
+ }
+
+ if (i>255) return MOPS_PDESC_OVERFLOW;
+ if (i<min)
+ retval = MOPS_PDESC_LOW;
+ else if (i>max)
+ retval = MOPS_PDESC_HIGH;
+
+ *dst = (u_int8_t) i;
+
+ return retval;
+}
+
+
+
+// Assign decimal or hexadecimal u_int16_t value, depending on spec
+// spec can be 0=dec or 1=hex
+int mops_pdesc_2byte (u_int16_t *dst, char* usr, int spec, int min, int max)
+{
+ u_int32_t i;
+ int retval = MOPS_PDESC_SUCCESS;
+
+ if ((max>0xffff)||(min>0xffff)) return MOPS_PDESC_FAILURE;
+
+ if (spec==0)
+ {
+ i = (u_int32_t) str2int (usr);
+ }
+ else
+ {
+ i = (u_int32_t) xstr2int (usr);
+ }
+
+ if (i>0xffff) return MOPS_PDESC_OVERFLOW;
+ if (i<min)
+ retval = MOPS_PDESC_LOW;
+ else if (i>max)
+ retval = MOPS_PDESC_HIGH;
+
+ *dst = (u_int16_t) i;
+
+ return retval;
+}
+
+
+// Assign decimal or hexadecimal u_int32_t value, depending on spec
+// spec can be 0=dec or 1=hex
+int mops_pdesc_4byte (u_int32_t *dst, char* usr, int spec, unsigned long int min, unsigned long int max)
+{
+ unsigned long int i;
+ int retval = MOPS_PDESC_SUCCESS;
+
+ if ((max>0xffffffff)||(min>0xffffffff)) return MOPS_PDESC_FAILURE;
+
+ if (spec==0)
+ {
+ i = str2int (usr);
+ }
+ else
+ {
+ i = xstr2int (usr);
+ }
+
+ if (i>0xffffffff) return MOPS_PDESC_OVERFLOW;
+ if (i<min)
+ retval = MOPS_PDESC_LOW;
+ else if (i>max)
+ retval = MOPS_PDESC_HIGH;
+
+ *dst = (u_int32_t) i;
+
+ return retval;
+}
+
+
+
+// Maps MAC address given in 'usr' (e. g. 00:11:22:aa:bb:cc) into 'dst'
+// which is an u_int8_t array.
+//
+// Returns MOPS_PDESC_FAILURE (=1) upon invalid MAC address
+//
+int mops_pdesc_mac (u_int8_t *dst, char* usr)
+{
+ u_int8_t tmp[6];
+
+ // temporarily backup current value
+ memcpy ((void*) tmp, (void*) dst, 6);
+
+ if (str2hex_mac (usr, dst))
+ {
+ // restore original value
+ memcpy ((void*) dst, (void*) tmp, 6);
+ return MOPS_PDESC_FAILURE;
+ };
+
+ return MOPS_PDESC_SUCCESS;
+}
+
+
+// Maps an IP address string into an byte-array u_int8_t ip[4]
+// Note: the destination is NOT an u_int32_t !!!
+int mops_pdesc_ip (u_int8_t *dst, char* usr)
+{
+ u_int8_t tmp[4];
+ int i, len, j=0;
+
+ // Check if format is correct IPv4:
+ len = strlen(usr);
+ for (i=0; i<len; i++)
+ {
+ if (usr[i]=='.')
+ j++;
+ else if (!isdigit(usr[i]))
+ return MOPS_PDESC_FAILURE;
+ }
+ if (j!=3) return MOPS_PDESC_FAILURE;
+
+ // temporarily backup current value
+ memcpy ((void*) tmp, (void*) dst, 4);
+
+ if (num2hex (usr, dst)!=4)
+ {
+ // restore original value
+ memcpy ((void*) dst, (void*) tmp, 4);
+ return MOPS_PDESC_FAILURE;
+ };
+
+ return MOPS_PDESC_SUCCESS;
+}
+
+
+
+
+
+
+//////// Initialization functions for each protocol descriptor ///////////
+//// Each function expects that an appropriate p_desc is already assigned
+//// Also the p_desc_type should be set already.
+
+
+
+
+
+
+int mops_init_pdesc_cdp(struct mops *mp)
+{
+ if (mp->p_desc == NULL) return 1; // p_desc not properly assigned
+
+
+ return 0;
+}
+
+
+int mops_init_pdesc_dns(struct mops *mp)
+{
+ if (mp->p_desc == NULL) return 1; // p_desc not properly assigned
+
+
+ return 0;
+}
+
+
+int mops_init_pdesc_icmp(struct mops *mp)
+{
+ if (mp->p_desc == NULL) return 1; // p_desc not properly assigned
+
+
+ return 0;
+}
+
+
+
+int mops_init_pdesc_syslog(struct mops *mp)
+{
+ if (mp->p_desc == NULL) return 1; // p_desc not properly assigned
+
+ return 0;
+}
+
+
+
+
+
+
diff --git a/staging/mops_ext_arp.c b/staging/mops_ext_arp.c
new file mode 100644
index 0000000..79c33a4
--- /dev/null
+++ b/staging/mops_ext_arp.c
@@ -0,0 +1,239 @@
+/*
+ * Mausezahn - A fast versatile traffic generator
+ * Copyright (C) 2008-2010 Herbert Haas
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
+ *
+*/
+
+
+
+#include "mz.h"
+#include "mops.h"
+
+
+// Initialization function - specify defaults here!
+//
+int mops_init_pdesc_arp(struct mops *mp)
+{
+
+ struct mops_ext_arp * pd;
+
+ char tmac[6] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+ if (mp->p_desc == NULL) return 1; // p_desc not properly assigned
+
+ pd = mp->p_desc;
+
+ pd->hw_type = 0x0001;
+ pd->pr_type = 0x800;
+ pd->hw_size = 6;
+ pd->pr_size = 4;
+ pd->opcode = 0x0001; // request
+ memcpy ((void*) pd->sender_mac, (void*) tx.eth_src, 6);
+ memcpy ((void*) pd->target_mac, (void*) tmac, 6);
+ memcpy ((void*) pd->sender_ip, (void*) &tx.ip_src, 4);
+ memcpy ((void*) pd->target_ip, (void*) &tx.ip_src, 4);
+
+ pd->trailer = 18; // default is 18 byte trailer to get a 60 byte packet (instead of only 42)
+
+ return 0;
+}
+
+
+
+
+
+
+
+
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////// Update functions ////////////////////////////////
+//
+// **** Here is a summary of mops tool functions: ****
+//
+// Adds single byte to msg
+// int mops_msg_add_byte (struct mops *mp, u_int8_t data);
+//
+// Adds bit field in *previous* msg-byte using optional left-shift
+// int mops_msg_add_field (struct mops *mp, u_int8_t data, int shift);
+//
+// Adds two bytes in network byte order to msg
+// int mops_msg_add_2bytes (struct mops *mp, u_int16_t data);
+//
+// Adds four bytes in network byte order to msg
+// int mops_msg_add_4bytes (struct mops *mp, u_int32_t data);
+//
+// Adds string of bytes with lenght len
+// int mops_msg_add_string (struct mops *mp, u_int8_t *str, int len);
+//
+// Add counter to message
+// int mops_msg_add_counter (struct mops *mp,
+// int random, // 1=random, 0=use start/stop/step
+// u_int32_t start, // HOST BYTE ORDER
+// u_int32_t stop, // HOST BYTE ORDER
+// u_int32_t step, // HOST BYTE ORDER
+// int bytes // number of bytes used (1|2|4) - selects hton2 or hton4
+// );
+//
+//
+
+
+int mops_update_arp(struct mops * mp)
+{
+
+ struct mops_ext_arp * pd;
+ int i;
+
+ pd = mp->p_desc;
+ if (pd==NULL) return 1; // no valid pointer to a p_desc
+
+ mp->msg_s = 0; // important! Otherwise the msg would get longer and longer after each call!
+
+ mops_msg_add_2bytes (mp, pd->hw_type);
+ mops_msg_add_2bytes (mp, pd->pr_type);
+ mops_msg_add_byte (mp, pd->hw_size);
+ mops_msg_add_byte (mp, pd->pr_size);
+ mops_msg_add_2bytes (mp, pd->opcode);
+ mops_msg_add_string (mp, pd->sender_mac, 6);
+ mops_msg_add_string (mp, pd->sender_ip, 4);
+ mops_msg_add_string (mp, pd->target_mac, 6);
+ mops_msg_add_string (mp, pd->target_ip, 4);
+
+ // Avoid buffer problems:
+ if (pd->trailer>2000)
+ {
+ pd->trailer=2000;
+ }
+
+ for (i=0; i<pd->trailer; i++)
+ {
+ mops_msg_add_byte (mp, 0x00);
+ }
+
+ return 0;
+}
+
+
+
+// ARP Service: Resolves MAC address of given IP address and interface
+// The result is stored in the last argument 'mac'.
+//
+// EXAMPLE:
+//
+// u_int8_t mymac[6];
+// int ip[4]={192,186,0,1};
+//
+// service_arp("eth0", ip, mymac);
+// /* now mymac should contain the MAC address */
+//
+// RETURN VALUE: 0 upon success
+// 1 upon error
+//
+int service_arp(char *dev, u_int8_t *ip, u_int8_t *mac)
+{
+ int i, devind=0, dev_found=0;
+ struct mops * mp;
+ struct mops_ext_arp * pd;
+ char tmac[6] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+ struct arp_table_struct *cur;
+
+ // MOPS framework already available?
+ if (mp_head==NULL) return 1;
+
+ // Get list index for that device:
+ for (i=0; i<device_list_entries; i++) {
+ if (strncmp(device_list[i].dev, dev, 16)==0) {
+ devind=i;
+ dev_found=1;
+ break;
+ }
+ }
+ if (dev_found==0) {
+ fprintf(stderr, " Warning: Unknown device (sysARP_service)\n");
+ return 1; // ERROR: device name not found !!!!
+ } else {
+ if (verbose) {
+ fprintf(stderr, " sysARP_service triggered through interface %s\n", dev);
+ }
+ }
+
+ // Look up mops table if already a sysARP packet is available
+ mp = mops_search_name (mp_head, "sysARP_service");
+ if (mp!=NULL) { // entry exists...stop if active!
+ if (mops_state(mp)==MOPS_STATE_ACTIVE) {
+ if (verbose==2) fprintf(stderr, " Warning: Stop active MOPS (sysARP_service)\n");
+ mops_destroy_thread(mp);
+ }
+ } else {
+ // Allocate a new packet
+ if ((mp = mops_alloc_packet(mp_head)) == NULL) {
+ fprintf(stderr, " sysARP_service: ERROR -- cannot allocate MOPS\n");
+ return 1; // Problem, memory full?
+ } else {
+ strncpy (mp->packet_name, "sysARP_service", 15);
+ mp->mz_system=1; // indicates MZ private packet
+ if (mops_ext_add_pdesc (mp, MOPS_ARP)) {
+ return 1; // error
+ }
+ }
+ }
+
+ // Configure ARP request:
+ mops_clear_layers(mp, MOPS_ALL);
+ mops_init_pdesc_arp(mp);
+
+ mp->verbose = 0;
+ mp->use_ETHER = 1;
+ mp->count = 1;
+ mp->eth_type = 0x806;
+ mz_strncpy(mp->device, dev, 16);
+
+ pd = mp->p_desc;
+ memcpy ((void*) pd->sender_mac, (void*) device_list[devind].mac_mops, 6);
+ memcpy ((void*) pd->target_mac, (void*) tmac, 6);
+ memcpy ((void*) pd->sender_ip, (void*) device_list[devind].ip_mops, 4);
+ pd->target_ip[0]=ip[0];
+ pd->target_ip[1]=ip[1];
+ pd->target_ip[2]=ip[2];
+ pd->target_ip[3]=ip[3];
+
+ mops_update_arp(mp);
+ mops_set_conf(mp);
+
+ // Send ARP request
+
+ if (mops_tx_simple (mp)) {
+ fprintf(stderr, " Warning: sysARP_service failed!\n");
+ return 1;
+ }
+
+ usleep(100000); // wait 100 ms
+ // Now hopefully we got an ARP response;
+ // look up in ARP cache
+
+ cur=device_list[devind].arp_table;
+ while(cur!=NULL) {
+ if ((cur->sip[0]==ip[0]) &&
+ (cur->sip[1]==ip[1]) &&
+ (cur->sip[2]==ip[2]) &&
+ (cur->sip[3]==ip[3])) { // entry found!
+ for (i=0; i<6; i++) {
+ mac[i] = cur->smac[i];
+ }
+ }
+ cur=cur->next;
+ }
+
+ return 0;
+}
diff --git a/staging/mops_ext_bpdu.c b/staging/mops_ext_bpdu.c
new file mode 100644
index 0000000..8cb180d
--- /dev/null
+++ b/staging/mops_ext_bpdu.c
@@ -0,0 +1,242 @@
+/*
+ * Mausezahn - A fast versatile traffic generator
+ * Copyright (C) 2008-2010 Herbert Haas
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
+ *
+*/
+
+
+
+#include "mz.h"
+#include "mops.h"
+
+
+// Initialization function - specify defaults here!
+//
+int mops_init_pdesc_bpdu(struct mops *mp)
+{
+ struct mops_ext_bpdu * pd;
+ int i;
+
+
+ if (mp->p_desc == NULL) return 1; // p_desc not properly assigned
+ pd = mp->p_desc;
+
+ // 1. - Initialize Ethernet header
+ str2hex("01:80:C2:00:00:00",mp->eth_dst, 6);
+
+ // 2. - Initialize BPDU fields
+ pd->id = 0;
+ pd->version = 0; // 0=802.1D, 2=RSTP(802.1w)
+ pd->bpdu_type = 0x80; // 0=conf, 0x80=topology change, 2=RSTP/MSTP
+ pd->flags = 0; // X... .... = TCN ACK
+ // .X.. .... = Agreement
+ // ..X. .... = Forwarding
+ // ...X .... = Learning
+ // .... XX.. = Port Role (e. g. 11=Desgn)
+ // .... ..X. = Proposal
+ // .... ...X = TCN
+
+ i = mops_get_device_index(tx.device);
+ if (i!=-1) { // found
+ memcpy((void*) &pd->root_id[2], (void*) device_list[i].mac_mops, 6);
+ memcpy((void*) &pd->bridge_id[2], (void*) device_list[i].mac_mops, 6);
+ } else {
+ str2hex("00:00:00:00:00:00", &pd->root_id[2], 6);
+ str2hex("00:00:00:00:00:00", &pd->bridge_id[2], 6);
+ }
+
+ pd->root_id[0] = 0x00;
+ pd->root_id[1] = 0x00;
+
+ pd->bridge_id[0] = 0x00;
+ pd->bridge_id[1] = 0x00;
+
+ pd->root_pc = 0; // Root Path Cost
+ pd->port_id = 0; // Port Identifier
+ pd->message_age = 0; // All timers are multiples of 1/256 sec. Thus times range from 0 to 256 seconds.
+ pd->max_age = 5120; // 20 seconds
+ pd->hello_time = 512;
+ pd->f_delay = 3840;
+
+ str2hex("00:00:00:00:00:00:00:00", pd->trailer, 8);
+ // either all-zero or 00:00:00:00:02:VLAN(16bit) when PVST+
+ pd->rstp = 0; // 1 = RSTP
+ pd->pvst = 0; // 1=PVST+ , 0 = 802.1D
+ pd->mstp = 0; // 1 = Multiple Instance STP
+
+ return 0;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////// Update functions ////////////////////////////////
+//
+// **** Here is a summary of mops tool functions: ****
+//
+// Adds single byte to msg
+// int mops_msg_add_byte (struct mops *mp, u_int8_t data);
+//
+// Adds bit field in *previous* msg-byte using optional left-shift
+// int mops_msg_add_field (struct mops *mp, u_int8_t data, int shift);
+//
+// Adds two bytes in network byte order to msg
+// int mops_msg_add_2bytes (struct mops *mp, u_int16_t data);
+//
+// Adds four bytes in network byte order to msg
+// int mops_msg_add_4bytes (struct mops *mp, u_int32_t data);
+//
+// Adds string of bytes with lenght len
+// int mops_msg_add_string (struct mops *mp, u_int8_t *str, int len);
+
+int mops_update_bpdu(struct mops * mp)
+{
+
+ struct mops_ext_bpdu * pd;
+
+ pd = mp->p_desc;
+ if (pd==NULL) return 1; // no valid pointer to a p_desc
+ mp->msg_s = 0; // important! Otherwise the msg would get longer and longer after each call!
+
+
+ // NOTE: the length field does not include the trailer!
+ if (pd->pvst)
+ {
+ str2hex("01:00:0C:CC:CC:CD", mp->eth_dst, 6);
+ mp->eth_len=50;
+ str2hex("aa:aa:03:00:00:0c:01:0b",mp->eth_snap, 8);
+ mp->eth_snap_s = 8;
+ }
+ else
+ {
+ str2hex("01:80:C2:00:00:00",mp->eth_dst, 6);
+ mp->eth_len=38;
+ str2hex("42:42:03",mp->eth_snap, 3);
+ mp->eth_snap_s = 3;
+ }
+
+ mops_msg_add_2bytes (mp, pd->id);
+ mops_msg_add_byte (mp, pd->version);
+ mops_msg_add_byte (mp, pd->bpdu_type);
+
+ if (pd->bpdu_type & 0x80) // if TCN then don't add more fields
+ {
+ if (pd->pvst) mp->eth_len=12; else mp->eth_len=7;
+ }
+ else
+ {
+ mops_msg_add_byte (mp, pd->flags);
+ mops_msg_add_string (mp, pd->root_id, 8);
+ mops_msg_add_4bytes (mp, pd->root_pc);
+ mops_msg_add_string (mp, pd->bridge_id, 8);
+ mops_msg_add_2bytes (mp, pd->port_id);
+ mops_msg_add_2bytes (mp, pd->message_age);
+ mops_msg_add_2bytes (mp, pd->max_age);
+ mops_msg_add_2bytes (mp, pd->hello_time);
+ mops_msg_add_2bytes (mp, pd->f_delay);
+ }
+
+ // we always add the trailer
+ mops_msg_add_string (mp, pd->trailer, 8);
+
+ return 0;
+}
+
+
+
+// Create RID or BID based on priority, ext-sys-id, and MAC address.
+// The last parameter selects BID (0) or RID (1)
+//
+// pri .... 0-15
+// esi .... 0-4095
+// mac .... XX:XX:XX:XX:XX:XX or interface name
+//
+// NOTE: Invalid parameters will result in default values
+//
+// RETURN VALUE: Only informational; identifies which parameter
+// was errourness, using the following values:
+//
+// 0 ... all parameters valid
+// 1 ... priority exceeded range
+// 2 ... ext-sys-id exceeded range
+// 3 ... invalid MAC address or invalid interface
+// 4 ... other
+
+int mops_create_bpdu_bid(struct mops * mp, int pri, int esi, char *mac, int bid_or_rid)
+{
+ int i;
+ struct mops_ext_bpdu * pd = mp->p_desc;
+ u_int8_t rid[8];
+ u_int16_t p16;
+
+ if ((pri<0)||(pri>15)) return 1;
+ if ((esi<0)||(esi>4095)) return 2;
+
+ if (mac!=NULL) {
+ // first check if an interface is specified:
+ i = mops_get_device_index(mac);
+ if (i!=-1) { // found
+ memcpy((void*) &rid[2], (void*) device_list[i].mac_mops, 6);
+ }
+ else { // MAC address given?
+ if (mops_pdesc_mac(&rid[2], mac)) {
+ return 3;
+ }
+ }
+ } else { // mac==NULL
+ // use MAC of default interface!
+ i = mops_get_device_index(tx.device);
+ if (i!=-1) { // found
+ memcpy((void*) &rid[2], (void*) device_list[i].mac_mops, 6);
+ }
+ else {
+ str2hex("00:00:00:00:00:00", &rid[2], 6);
+ return 4;
+ }
+ }
+
+ // now prepend pri, esi
+
+ p16 = pri;
+ p16 <<= 12;
+ p16 |= esi;
+
+ mops_hton2 (&p16, &rid[0]);
+ if (bid_or_rid)
+ memcpy((void*) pd->root_id, (void*) rid, 8);
+ else
+ memcpy((void*) pd->bridge_id, (void*) rid, 8);
+ return 0;
+}
+
+
+int mops_create_bpdu_trailer (struct mops * mp, u_int16_t vlan)
+{
+ struct mops_ext_bpdu * pd = mp->p_desc;
+
+ // PVST+ requires a trailer with either all-zero
+ // or 00:00:00:00:02:VLAN(16bit)
+
+ // trailer already initialized with zeroes
+ pd->trailer[0]=0x00;
+ pd->trailer[1]=0x00;
+ pd->trailer[2]=0x00;
+ pd->trailer[3]=0x00;
+ pd->trailer[4]=0x02;
+ pd->trailer[5]=0x00;
+ pd->trailer[6]=0x00;
+ mops_hton2 (&vlan, &pd->trailer[5]);
+
+ return 0;
+}
diff --git a/staging/mops_ext_igmp.c b/staging/mops_ext_igmp.c
new file mode 100644
index 0000000..3bd83fa
--- /dev/null
+++ b/staging/mops_ext_igmp.c
@@ -0,0 +1,270 @@
+/*
+ * Mausezahn - A fast versatile traffic generator
+ * Copyright (C) 2008-2010 Herbert Haas
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
+ *
+*/
+
+#include "mz.h"
+#include "mops.h"
+#include "cli.h"
+
+
+
+// Initialization function - specify defaults here!
+//
+int mops_init_pdesc_igmp(struct mops *mp)
+{
+ struct mops_ext_igmp * pd;
+
+ if (mp->p_desc == NULL) return 1; // p_desc not properly assigned
+ pd = mp->p_desc;
+
+ pd->version = 2;
+ pd->type = IGMP_V2_REPORT;
+ pd->max_resp_code = 0;
+ pd->sum_false = 0;
+ pd->group_addr = 0; // TODO: consider initialization with well-known mcast address?
+ pd->sa_list = NULL;
+
+ return 0;
+}
+
+
+
+
+// IGMPv2 query and report (see RFC 2236)
+//
+// 0 1 2 3
+// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | Type | Max Resp Time | Checksum |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | Group Address |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//
+//
+// IGMPv1 query and report (see RFC 1112)
+//
+// 0 1 2 3
+// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// |Version| Type | Unused | Checksum |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | Group Address |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//
+// Therefore IGMPv1 only uses IGMP_GENERAL_QUERY or IGMP_V1_REPORT and mrt=0.
+//
+int mops_create_igmpv2 (struct mops *mp,
+ int override, // normally zero, but if '1' the user want to override defaults
+ int igmp_type, // IGMP_GENERAL_QUERY, IGMP_GSPEC_QUERY, IGMP_V2_REPORT, IGMP_V1_REPORT, IGMP_LEAVE
+ int mrt, // max response time (unused == 0 for IGMPv1)
+ int sum, //-1 means auto-compute, other values means 'use this user-defined value'
+ u_int32_t group_addr)
+{
+ struct mops_ext_igmp * pd;
+
+ // --- sanity check params ---
+ // Do we have a valid pointer?
+ if (mp->p_desc == NULL) return 1; // p_desc not properly assigned
+ pd = mp->p_desc;
+ if (mrt>255) return 1;
+ if (sum>65535) return 1;
+ // ---------------------------
+
+ // +++ Set values in pdesc ++++++++++++++++++++++++
+ pd->version = 2;
+
+ switch (igmp_type) {
+ case IGMP_GENERAL_QUERY:
+ pd->type = 0x11;
+ pd->group_addr = 0;
+ pd->max_resp_code = mrt;
+ break;
+ case IGMP_GSPEC_QUERY:
+ pd->type = 0x11;
+ pd->group_addr = group_addr;
+ pd->max_resp_code = mrt;
+ break;
+ case IGMP_V2_REPORT:
+ pd->type = 0x16;
+ pd->group_addr = group_addr;
+ if (override) pd->max_resp_code = mrt; else pd->max_resp_code = 0;
+ break;
+ case IGMP_V1_REPORT:
+ pd->type = 0x12;
+ pd->group_addr = group_addr;
+ if (override) pd->max_resp_code = mrt; else pd->max_resp_code = 0;
+ break;
+ case IGMP_LEAVE:
+ pd->type = 0x17;
+ pd->group_addr = group_addr;
+ if (override) pd->max_resp_code = mrt; else pd->max_resp_code = 0;
+ break;
+ default:
+ return 1; // unknown type
+ }
+
+ if (sum==-1) {
+ pd->sum_false = 0;
+ } else {
+ pd->sum_false = 1;
+ pd->sum = sum; // mops_update_igmp() will process this!
+ }
+
+ // ++++++++++++++++++++++++++++++++++++++++++++++++
+
+ return 0;
+}
+
+
+
+
+
+
+
+
+
+int mops_update_igmp (struct mops * mp)
+{
+ struct mops_ext_igmp * pd;
+
+ pd = mp->p_desc;
+ if (pd==NULL) return 1; // no valid pointer to a p_desc
+ mp->msg_s = 0; // important! Otherwise the msg would get longer and longer after each call!
+ u_int16_t sum;
+
+ switch (pd->version) {
+
+ case 1:
+ break;
+
+ case 2:
+ // IGMPv2 query and report (see RFC 2236)
+ //
+ // 0 1 2 3
+ // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // | Type | Max Resp Time | Checksum |
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // | Group Address |
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ //
+ mops_msg_add_byte (mp, pd->type);
+ mops_msg_add_byte (mp, pd->max_resp_code);
+ if (pd->sum_false)
+ mops_msg_add_2bytes (mp, pd->sum); // used defined (typically wrong) checksum
+ else // must be set to zero before checksum computation
+ mops_msg_add_2bytes (mp, 0x0000);
+ mops_msg_add_4bytes (mp, pd->group_addr);
+ if (pd->sum_false==0) {
+ sum = mops_sum16 (mp->msg_s, mp->msg);
+ mops_hton2(&sum, &mp->msg[2]);
+ }
+ break;
+
+ case 3:
+ break;
+
+
+ default:
+ return 1;
+ }
+
+
+
+ return 0;
+}
+
+
+
+
+
+
+
+
+// IGMP messages are encapsulated in IPv4 datagrams, with an IP protocol
+// number of 2. Every IGMP message described in this document is sent
+// with an IP Time-to-Live of 1, IP Precedence of Internetwork Control
+// (e.g., Type of Service 0xc0), and carries an IP Router Alert option
+// [RFC-2113] in its IP header.
+
+
+
+//
+//
+// IGMPv3 report message (see RFC 3376)
+//
+// 0 1 2 3
+// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | Type = 0x22 | Reserved | Checksum |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | Reserved | Number of Group Records (M) |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | |
+// . .
+// . Group Record [1] .
+// . .
+// | |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | |
+// . .
+// . Group Record [2] .
+// . .
+// | |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | . |
+// . . .
+// | . |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | |
+// . .
+// . Group Record [M] .
+// . .
+// | |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//
+//
+//
+//
+// IGMPv3 query message (see RFC 3376)
+//
+// 0 1 2 3
+// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | Type = 0x11 | Max Resp Code | Checksum |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | Group Address |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | Resv |S| QRV | QQIC | Number of Sources (N) |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | Source Address [1] |
+// +- -+
+// | Source Address [2] |
+// +- . -+
+// . . .
+// . . .
+// +- -+
+// | Source Address [N] |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//
+//
+//
+
+//
+//
+//
+//
diff --git a/staging/mops_ext_lldp.c b/staging/mops_ext_lldp.c
new file mode 100644
index 0000000..d11fab0
--- /dev/null
+++ b/staging/mops_ext_lldp.c
@@ -0,0 +1,430 @@
+/*
+ * Mausezahn - A fast versatile traffic generator
+ * Copyright (C) 2008-2010 Herbert Haas
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
+ *
+*/
+
+
+#include "mz.h"
+#include "mops.h"
+#include "cli.h"
+
+
+
+// Initialization function - specify defaults here!
+//
+int mops_init_pdesc_lldp(struct mops *mp)
+{
+ struct mops_ext_lldp * pd;
+ int i=0;
+
+ if (mp->p_desc == NULL) return 1; // p_desc not properly assigned
+ pd = mp->p_desc;
+
+ mp->eth_type = 0x88cc;
+ str2hex("01:80:c2:00:00:0e", mp->eth_dst, 6);
+ mp->ndelay.tv_sec = 30;
+ mp->ndelay.tv_nsec = 0;
+
+ // get interface index for that packet
+ i = mops_get_device_index(mp->device);
+
+ pd->non_conform = 0;
+ pd->chassis_id_subtype = 4; // MAC address
+ if (pd->chassis_id==NULL) pd->chassis_id = malloc(255);
+ if (pd->chassis_id==NULL) return 1;
+ memcpy((void*) pd->chassis_id, (void*) device_list[i].mac_mops, 6);
+ pd->chassis_id_len = 6;
+ pd->port_id_subtype = 5; // interface name
+ pd->port_id_len = strnlen(mp->device, 15);
+ if (pd->port_id==NULL) pd->port_id = malloc(255);
+ if (pd->port_id==NULL) return 1;
+ memcpy((void*) pd->port_id, (void*) mp->device, pd->port_id_len);
+ pd->TTL = 120;
+ pd->optional_tlvs_s = 0;
+ if (pd->optional_tlvs==NULL) pd->optional_tlvs = malloc(MAX_LLDP_OPT_TLVS);
+ if (pd->optional_tlvs == NULL) return 1;
+ return 0;
+}
+
+
+
+int mops_update_lldp (struct mops * mp)
+{
+ struct mops_ext_lldp * pd;
+
+ pd = mp->p_desc;
+ if (pd==NULL) return 1; // no valid pointer to a p_desc
+ mp->msg_s = 0; // important! Otherwise the msg would get longer and longer after each call!
+
+ switch (pd->non_conform) {
+
+ case 0: // Derive mandatory TLVs from struct entries and insert optional_tlvs
+ mp->msg_s += mops_lldp_tlv_chassis(mp->msg,
+ pd->chassis_id_subtype,
+ pd->chassis_id_len,
+ pd->chassis_id);
+ mp->msg_s += mops_lldp_tlv_port(&mp->msg[mp->msg_s],
+ pd->port_id_subtype,
+ pd->port_id_len,
+ pd->port_id);
+ mp->msg_s += mops_lldp_tlv_TTL(&mp->msg[mp->msg_s],
+ pd->TTL);
+ if (pd->optional_tlvs_s) {
+ memcpy((void*) &mp->msg[mp->msg_s],
+ (void*) pd->optional_tlvs,
+ pd->optional_tlvs_s);
+ mp->msg_s += pd->optional_tlvs_s;
+ }
+ mp->msg_s += mops_lldp_tlv_end(&mp->msg[mp->msg_s]);
+ break;
+
+ case 1: // User defined ALL TLVs (i. e. ignore struct entries)
+ if (pd->optional_tlvs_s) {
+ memcpy((void*) &mp->msg[mp->msg_s],
+ (void*) pd->optional_tlvs,
+ pd->optional_tlvs_s);
+ mp->msg_s += pd->optional_tlvs_s;
+ }
+ mp->msg_s += mops_lldp_tlv_end(&mp->msg[mp->msg_s]);
+ break;
+ default:
+ return 1;
+ }
+ return 0;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// //
+// Below are utility functions to creade the LLDPU. From these, the //
+// following can be used for the optional part: //
+// //
+// //
+// //
+// //
+
+/*
+
+int mops_lldp_opt_tlv (struct mops *mp, int type, int len, u_int8_t *value)
+int mops_lldp_opt_tlv_chassis (struct mops *mp, int subtype, int len, u_int8_t *cid)
+int mops_lldp_opt_tlv_port (struct mops *mp, int subtype, int len, u_int8_t *pid)
+int mops_lldp_opt_tlv_TTL (struct mops *mp, int ttl)
+int mops_lldp_opt_tlv_vlan (struct mops *mp, int vlan)
+int mops_lldp_opt_tlv_end (struct mops *mp)
+int mops_lldp_opt_tlv_bad (struct mops *mp, int type, int badlen, int len, u_int8_t *value)
+int mops_lldp_opt_tlv_org (struct mops *mp, int oui, int subtype, int len, u_int8_t *inf)
+
+*/
+
+
+// //
+// //
+// //
+// //
+// //
+// //
+// //
+// //
+///////////////////////////////////////////////////////////////////////////////
+
+
+
+
+
+// Creates a LLDP TLV for a given type number and value string. The result will
+// be written into 'tlv'.
+//
+// NOTE: len must be given and indicates the length of value.
+//
+// RETURN VALUE: - Total number of bytes of this tlv
+// - 0 upon error
+//
+int mops_lldp_tlv (u_int8_t *tlv, int type, int len, u_int8_t *value)
+{
+ u_int16_t tl=0, tln=0;
+
+ if ((type>127) || (len>511)) return 0;
+
+ tl = type << 9;
+ tl |= len;
+
+ tln = htons(tl);
+ memcpy((void*) tlv, (void*) &tln, 2);
+ memcpy((void*) &tlv[2], (void*) value, len);
+
+ return len+2;
+}
+
+
+// Same as above but **adds the TLVs to the 'pd->optional_tlvs' string.**
+// It also checks if MAX_LLDP_OPT_TLVS is exceeded.
+//
+// NOTE: first argument is a pointer to that mops!
+//
+// RETURN VALUE: - 0 upon error (no more space)
+// - Total number of bytes written
+//
+int mops_lldp_opt_tlv (struct mops * mp, int type, int len, u_int8_t *value)
+{
+ struct mops_ext_lldp * pd;
+ u_int8_t tmp[MAX_LLDP_OPT_TLVS]; // this *must* be sufficient in length
+ int l;
+
+ if (mp->p_desc == NULL) return 1; // p_desc not properly assigned
+ pd = mp->p_desc;
+
+ l = mops_lldp_tlv (tmp, type, len, value);
+
+ if ((MAX_LLDP_OPT_TLVS - pd->optional_tlvs_s)< (l+1)) return -1; // not enough space
+ memcpy((void*) (pd->optional_tlvs + pd->optional_tlvs_s), (void*) tmp, l);
+ pd->optional_tlvs_s += l;
+ return l;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// //
+// //
+// //
+///////////////////////////////////////////////////////////////////////////////
+
+
+
+// Creates a Chassis ID TLV -- the first mandatory TLV.
+// The result will be written into 'tlv'.
+//
+// RETURN VALUE: - Total number of bytes within tlv
+// - 0 upon error
+//
+int mops_lldp_tlv_chassis (u_int8_t *tlv, int subtype, int len, u_int8_t *cid)
+{
+ u_int8_t tmp[256];
+
+ if ((len>255) || (subtype>255)) return 0;
+
+ tmp[0] = (u_int8_t) subtype;
+ memcpy((void*) (tmp+1), (void*) cid, len);
+ return mops_lldp_tlv(tlv, 1, len+1, tmp);
+
+}
+
+// Same but for optional tlv string
+int mops_lldp_opt_tlv_chassis (struct mops *mp, int subtype, int len, u_int8_t *cid)
+{
+ u_int8_t tmp[256];
+
+ if ((len>255) || (subtype>255)) return 0;
+ tmp[0] = (u_int8_t) subtype;
+ memcpy((void*) (tmp+1), (void*) cid, len);
+ return mops_lldp_opt_tlv(mp, 1, len+1, tmp);
+}
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+// //
+// //
+// //
+///////////////////////////////////////////////////////////////////////////////
+
+
+
+// Creates a Port ID TLV -- the second mandatory TLV.
+// The result will be written into 'tlv'.
+//
+// RETURN VALUE: - Total number of bytes within tlv
+// - 0 upon error
+//
+int mops_lldp_tlv_port (u_int8_t *tlv, int subtype, int len, u_int8_t *pid)
+{
+ u_int8_t tmp[256];
+
+ if ((len>255) || (subtype>255)) return 0;
+
+ tmp[0] = (u_int8_t) subtype;
+ memcpy((void*) (tmp+1), (void*) pid, len);
+ return mops_lldp_tlv(tlv, 2, len+1, tmp);
+}
+
+// Same but for optional tlv string
+int mops_lldp_opt_tlv_port (struct mops *mp, int subtype, int len, u_int8_t *pid)
+{
+ u_int8_t tmp[256];
+
+ if ((len>255) || (subtype>255)) return 0;
+ tmp[0] = (u_int8_t) subtype;
+ memcpy((void*) (tmp+1), (void*) pid, len);
+ return mops_lldp_opt_tlv(mp, 2, len+1, tmp);
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// //
+// //
+// //
+///////////////////////////////////////////////////////////////////////////////
+
+
+// Creates a TTL TLV -- the third mandatory TLV.
+// The result will be written into 'tlv'.
+//
+// RETURN VALUE: - Total number of bytes within tlv
+// - 0 upon error
+//
+int mops_lldp_tlv_TTL (u_int8_t *tlv, int ttl)
+{
+ u_int16_t ttlh=0, ttln=0;
+
+ if (ttl>0xffff) return 0;
+
+ ttlh = (u_int16_t) ttl;
+ ttln = htons(ttlh);
+
+ return mops_lldp_tlv(tlv, 3, 2, (u_int8_t*) &ttln);
+}
+
+
+// Same but for optional tlv string
+int mops_lldp_opt_tlv_TTL (struct mops *mp, int ttl)
+{
+ u_int16_t ttlh=0, ttln=0;
+
+ if (ttl>0xffff) return 0;
+
+ ttlh = (u_int16_t) ttl;
+ ttln = htons(ttlh);
+
+ return mops_lldp_opt_tlv(mp, 3, 2, (u_int8_t*) &ttln);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// //
+// //
+// //
+///////////////////////////////////////////////////////////////////////////////
+
+
+// Creates an End of LLDPDU TLV -- the last mandatory TLV.
+// The result will be written into 'tlv'.
+//
+// RETURN VALUE: - Total number of bytes within tlv
+// - 0 upon error
+//
+int mops_lldp_tlv_end (u_int8_t *tlv)
+{
+ tlv[0] = 0x00;
+ tlv[1] = 0x00;
+ return 2;
+}
+
+// Same but for optional tlv string
+int mops_lldp_opt_tlv_end (struct mops *mp)
+{
+ struct mops_ext_lldp * pd;
+
+ if (mp->p_desc == NULL) return 1; // p_desc not properly assigned
+ pd = mp->p_desc;
+
+ if ((MAX_LLDP_OPT_TLVS - pd->optional_tlvs_s) > 2) {
+ pd->optional_tlvs[pd->optional_tlvs_s++] = 0x00;
+ pd->optional_tlvs[pd->optional_tlvs_s++] = 0x00;
+ return 2;
+ } else
+ return 0;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// //
+// //
+// //
+///////////////////////////////////////////////////////////////////////////////
+
+
+// Creates a 'bad' LLDP TLV for a given type number and value string.
+// The result will be appended into 'pd->optional_tlvs'
+//
+// NOTE: 'len' must be given and indicates the TRUE length of value.
+// 'badlen' can be any number and is used as official length within the TLV
+//
+// RETURN VALUE: - Total number of bytes within tlv
+// - 0 upon error
+//
+int mops_lldp_opt_tlv_bad (struct mops *mp,
+ int type,
+ int badlen,
+ int len,
+ u_int8_t *value)
+{
+ u_int16_t tl=0, tln=0;
+ u_int8_t tlv[512];
+ struct mops_ext_lldp * pd = mp->p_desc;
+
+ if ((type>127) || (len>511) || (badlen>511)) return 0;
+ if ((MAX_LLDP_OPT_TLVS - pd->optional_tlvs_s) < (len+3)) return 0;
+
+ tl = type << 9;
+ tl |= badlen;
+
+ tln = htons(tl);
+ memcpy((void*) tlv, (void*) &tln, 2);
+ memcpy((void*) &tlv[2], (void*) value, len);
+ // this detour has historical reasons ;-)
+ memcpy((void*) (pd->optional_tlvs + pd->optional_tlvs_s), (void*) tlv, len+2);
+ pd->optional_tlvs += len+2;
+
+ return len+2;
+}
+
+
+
+// Creates a Organisational-specific TLV -- the second mandatory TLV.
+// The result will be appended into 'pd->optional_tlvs'
+//
+// RETURN VALUE: - Total number of bytes within tlv
+// - 0 upon error
+//
+int mops_lldp_opt_tlv_org (struct mops *mp,
+ int oui,
+ int subtype,
+ int len,
+ u_int8_t *inf)
+{
+ u_int8_t tmp[512];
+ u_int8_t *x;
+ u_int32_t oui_n = (u_int32_t) oui;
+
+ if ((len>507) || (subtype>255) || (oui_n>0xffffff)) return 0;
+
+ x = (u_int8_t *) &oui_n;
+ tmp[0] = *(x+2);
+ tmp[1] = *(x+1);
+ tmp[2] = *x;
+ tmp[3] = (u_int8_t) subtype;
+ memcpy((void*) (tmp+4), (void*) inf, len);
+ return mops_lldp_opt_tlv(mp, 127, len+4, tmp);
+}
+
+
+int mops_lldp_opt_tlv_vlan (struct mops *mp,
+ int vlan)
+{
+ u_int16_t vid;
+ if (vlan>0xffff) return 0; // yes, we also allow VLAN IDs > 4095
+ vid = htons(vlan);
+ return mops_lldp_opt_tlv_org (mp, 0x80c2, 1, 2, (u_int8_t*) &vid);
+}
+
diff --git a/staging/mops_ext_rtp.c b/staging/mops_ext_rtp.c
new file mode 100644
index 0000000..2bc3813
--- /dev/null
+++ b/staging/mops_ext_rtp.c
@@ -0,0 +1,243 @@
+/*
+ * Mausezahn - A fast versatile traffic generator
+ * Copyright (C) 2008-2010 Herbert Haas
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
+ *
+*/
+
+#include "mz.h"
+#include "mops.h"
+#include "cli.h"
+
+
+
+// Initialization function - specify defaults here!
+//
+int mops_init_pdesc_rtp(struct mops *mp)
+{
+ struct mops_ext_rtp * pd;
+
+ if (mp->p_desc == NULL) return 1; // p_desc not properly assigned
+ pd = mp->p_desc;
+
+ // set RTP defaults
+ pd->v = 2;
+ pd->p = 0;
+ pd->x = 0;
+ pd->cc = 0;
+ pd->m = 0;
+
+ pd->pt = 8; // 0=PCMU, 8=PCMA
+ pd->sqnr = 0;
+ pd->tst = 0;
+ pd->tst_inc = 160;
+ pd->ssrc = mz_rand32(); // Default Mausezahn stream would be 0xCAFEBABE
+ pd->source = 0; // don't use /dev/dsp (but user may configure source = DSP_SOURCE)
+ pd->cc_real = 0;
+
+ pd->x_type = 0; // no extension by default
+
+ // General packet parameters
+ mp->dp = 30000;
+ mp->sp = 30002;
+ mp->ndelay.tv_sec = 0;
+ mp->ndelay.tv_nsec = 20000000;
+
+ memset(&pd->payload, 0x00, MOPS_RTP_MAX_PAYLOAD_SIZE);
+
+ return 0;
+}
+
+
+/*
+ * Standard RTP header according RFC 3550
+ *
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |V=2|P|X| CC |M| PT | sequence number |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | timestamp |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | synchronization source (SSRC) identifier |
+ * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+ * | contributing source (CSRC) identifiers |
+ * | .... |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * !!! NOTE !!! -- This function should be used only to prepare the RTP
+ * header once. It does not update dynamic fields. To update dynamic fields
+ * each time a subsequent RTP packet is sent, use the function
+ * mops_update_rtp_dynamics().
+ *
+ */
+int mops_update_rtp (struct mops * mp)
+{
+ struct mops_ext_rtp * pd;
+ int i,j;
+
+ pd = mp->p_desc;
+ if (pd==NULL) return 1; // no valid pointer to a p_desc
+ mp->msg_s = 0; // !! IMPORTANT !! Otherwise the msg would get longer and longer after each call!
+
+ // 1st byte
+ mops_msg_add_byte (mp, pd->cc);
+ mops_msg_add_field (mp, pd->v, 6);
+ mops_msg_add_field (mp, pd->p, 5);
+ mops_msg_add_field (mp, pd->x, 4);
+
+ // 2nd byte
+ mops_msg_add_byte (mp, pd->pt);
+ mops_msg_add_field (mp, pd->m, 7);
+
+ // remaining
+ mops_msg_add_2bytes (mp, pd->sqnr);
+ mops_msg_add_4bytes (mp, pd->tst);
+ mops_msg_add_4bytes (mp, pd->ssrc);
+
+ // Add CSRC list?
+ if ((j=pd->cc_real)) {
+ if (j>16) { j=16; pd->cc_real=16; } // silent self healing if desired :-)
+ for (i=0; i<j; i++)
+ mops_msg_add_4bytes (mp, pd->csrc[i]);
+ }
+ pd->rtp_header_len = 12 + j*4;
+
+ /*
+ * Add Extension header?
+ *
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | defined by profile | length |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | header extension |
+ * | .... |
+ */
+
+ switch (pd->x_type) {
+ case 0: // none
+ break;
+ case 1: // set aero, 8 bytes in total -- TODO --
+ break;
+ case 42: // Mausezahn extension header:
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // | MOPS_RTP_EXT_MZID | length=4 |
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // | TX-timestamp sec |
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // | TX-timestamp nsec |
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // | Estimated Peer TX-timestamp sec |
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // | Estimated Peer TX-timestamp nsec |
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+ mops_msg_add_2bytes (mp, MOPS_RTP_EXT_MZID);
+ mops_msg_add_2bytes (mp, 2);
+ mops_msg_add_4bytes (mp, 0); // only placeholders, must be updated each packet
+ mops_msg_add_4bytes (mp, 0); // only placeholders, must be updated each packet
+ mops_msg_add_4bytes (mp, 0); // only placeholders, must be updated each packet
+ mops_msg_add_4bytes (mp, 0); // only placeholders, must be updated each packet
+
+ pd->rtp_header_len += 20;
+ break;
+ default:
+ return 1;
+ break; // paranoid?
+ }
+
+ // Now add the payload
+ switch (pd->pt) {
+ case 0:
+ case 8:
+ mp->msg_s = 160 + pd->rtp_header_len; // simply set total RTP PDU length (the RTP payload is still undefined)
+ mp->ndelay.tv_sec = 0;
+ mp->ndelay.tv_nsec = 20000000;
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+
+
+// This function directly updates the dynamic RTP fields
+// within the mops frame (=be quick here).
+//
+// This function is typically called from within the transmission loops,
+// see e. g. mops_tx_thread_native()
+//
+// This includes:
+//
+// - RTP SQNR
+// - RTP Timestamp
+// - Mausezahn extension header if any
+// - The RTP payload
+//
+int mops_update_rtp_dynamics (struct mops * mp)
+{
+ struct mops_ext_rtp * pd;
+ struct timespec ct;
+ int j, i = mp->begin_MSG;
+
+ pd = mp->p_desc; if (pd==NULL) return 1;
+
+
+ // The following variables must be incremented AFTER assignment to frame,
+ // so the initial values are also used!
+ //
+ mops_hton2 (&pd->sqnr, &mp->frame[i+2]);
+ pd->sqnr++;
+
+ mops_hton4 (&pd->tst, &mp->frame[i+4]);
+ pd->tst += pd->tst_inc;
+
+
+ // Extension header:
+ // Timestamp must be updated BEFORE assignment to frame
+ //
+ switch (pd->x_type) {
+ case 42: // Mausezahn extension header: Update timestamps
+ j = i + pd->rtp_header_len; // points to first byte of timestamp of MZ extension header
+ clock_gettime(CLOCK_MONOTONIC, &ct);
+ mops_hton4 ((u_int32_t*) &ct.tv_sec, &mp->frame[j-16]);
+ mops_hton4 ((u_int32_t*) &ct.tv_nsec, &mp->frame[j-12]);
+//[TODO] **** estimated peer timestamp **** PSEUDOCODE FOLLOWING:
+// if (peer_exists) {
+// get_peer_timestamp_estimation(&est);
+// mops_hton4 ((u_int32_t*) &est.sec, &mp->frame[j-8]);
+// mops_hton4 ((u_int32_t*) &est.nsec, &mp->frame[j-4]);
+// }
+ break;
+ default:
+ return 0;
+ break;
+ }
+
+ // The pd->payload contains either zeroes or realtime voice data
+ // The pd->payload is initialized with zeroes and IFF a reading thread
+ // exists, it may copy voice segments (e. g. from /dev/dsp) to
+ // pd->payload.
+ // NOTE that there is NO NEED to protect pd->payload with mutexes, because
+ // only if the reading thread is finished it (itself!) will call THIS function.
+ if (pd->source == DSP_SOURCE) {
+ memcpy((void*) &mp->frame[j], (void*) pd->payload, pd->payload_s);
+ }
+
+ return 0;
+}
+
diff --git a/staging/mops_ip.c b/staging/mops_ip.c
new file mode 100644
index 0000000..46102d7
--- /dev/null
+++ b/staging/mops_ip.c
@@ -0,0 +1,447 @@
+/*
+ * Mausezahn - A fast versatile traffic generator
+ * Copyright (C) 2008-2010 Herbert Haas
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
+ *
+*/
+
+
+#include "mz.h"
+#include "mops.h"
+#include "cli.h"
+
+
+// PURPOSE
+//
+// Determine destination MAC address to provide direct or indirect
+// delivery of IP packets, depending on which is appropriate.
+//
+// Doing this, the caller must provide
+// 1) A pointer to the interface (within the device_list)
+// 2) The destination IP address
+// 3) A pointer to the destination MAC address
+//
+// If a Class D (multicast) address is given, a proper IEEE multicast MAC
+// address is derived.
+//
+// EXAMPLE
+//
+// u_int8_t ip[4],
+// mac[6];
+//
+// mops_hton4 (mp->ip_src, ip);
+//
+// mops_ip_get_dst_mac(&device_list[0], ip, mac);
+//
+// RETURN VALUES
+//
+// 0 upon success
+// 1 upon error
+//
+int mops_ip_get_dst_mac(struct device_struct *dev, u_int8_t *ip, u_int8_t *mac)
+{
+ int i;
+ u_int8_t dst_net[4];
+
+ if ((dev==NULL)||(ip==NULL)||(mac==NULL)) return 1;
+
+ // Multicast address?
+ if ((0xe0 & ip[0]) == 0xe0) {
+ mac[0] = 0x01;
+ mac[1] = 0x00;
+ mac[2] = 0x5e;
+ mac[3] = ip[1] & 127;
+ mac[4] = ip[2];
+ mac[5] = ip[3];
+ return 0;
+ }
+
+ // Is destination network == local network?
+ for (i=0; i<4; i++) {
+ dst_net[i] = ip[i] & (u_int8_t) dev->mask[i];
+ }
+
+ if (compare_ip(dst_net, dev->net)==0) {
+ // dst is on local LAN => resolve MAC!
+ service_arp(dev->dev, ip, mac);
+ } else { // dst is on a remote network => use default gw!
+ for (i=0; i<6; i++) mac[i] = dev->mac_gw[i];
+ }
+
+ return 0;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////
+//
+// PURPOSE
+//
+// Accept a DSCP specification as string argument
+// and configure the IP-ToS field accordingly.
+//
+// EXAMPLE STRINGS
+//
+// AF32 .... specify AF codepoint with class 3 and drop probability 2
+// EF .... specify Expedited Forwarding
+// CS7 .... specify Code Selector 7
+// 101110 .... specify the DSCP in binary
+// 56 .... specify the DSCP in decimal
+//
+// RETURN VALUES
+//
+// -1 general bad argument format
+// 0 upon success
+// 1 Invalid AF format (Format: AFxy, e. g. af31 or AF23)
+// 2 Invalid CS format
+// 3 Invalid decimal DSCP value
+//
+int mops_ip_dscp (struct mops* mp, char *argv)
+{
+ int i;
+ char cs[4], ps[4], str[16];
+ u_int8_t c=0, p=0, dscp=0;
+
+ if (strlen(argv)==0) return -1;
+ strncpy(str,argv,15);
+
+ if (strncasecmp(str, "af", 2)==0) // e.g. 'AF32' or 'af41'
+ {
+ if (strlen(str)!=4) return 1; // ERROR: Invalid AF codepoint
+ i=sscanf(str, "%*[afAF]%c%c", cs, ps);
+ cs[1]=0x00; ps[1]=0x00;
+ c=(u_int8_t) str2int(cs);
+ p=(u_int8_t) str2int(ps);
+ if ((c<1)||(c>4)||(p<1)||(p>3)) return 1;
+ // Now create correct ToS-byte representation: This is simple, since if a=3 and b=1
+ // we have in binary already a=0000 0011 and b=0000 0001 and with bit-shifting we
+ // get the desired dscp=011 01 000 (the least signfificant three bits are always 0).
+ c <<=5;
+ p <<=3;
+ dscp = c | p;
+ }
+ else if (strncasecmp(str, "cs", 2)==0) // e.g. 'CS7' or 'cs4'
+ {
+ if (strlen(str)!=2) return 2; // ERROR: Invalid Code Selector
+ i=sscanf(str, "%*[afAF]%c", cs);
+ cs[1]=0x00;
+ c=(u_int8_t) str2int(cs);
+ if (c>7) return 2;
+ c <<=5;
+ dscp = c;
+ }
+ else if (mz_strcmp(str, "ef", 2)==0) // e.g. 'ef' or 'EF'
+ {
+ dscp = 0xb8; // = DSCP 46 = 101110 00 or 1011 1000
+ }
+ else if (mz_strisbinary(str)==6) // binary, e. g. 101110
+ {
+ for (i=0; i<6; i++) if (str[i]=='1') dscp |= ( 0x01 << (5-i) );
+ dscp <<= 2;
+ }
+ else if (strlen(str)==2) // decimal DSCP value
+ {
+ if ( !(isdigit(str[0])) || !(isdigit(str[1]))) return 3;
+ dscp = (u_int8_t) str2int(str);
+ if (dscp>63) return 3;
+ dscp <<= 2;
+ }
+ else return -1;
+
+ // TEST: printf("dscp=%02x\n",dscp);
+ mp->ip_tos = dscp;
+
+ return 0;
+}
+
+
+
+
+
+
+
+
+//
+// IP TOS-FIELD FORMAT
+//
+// MSB LSB
+// 0 1 2 3 4 5 6 7
+// +-----+-----+-----+-----+-----+-----+-----+-----+ Note that the bit numbering is usually from right
+// | | Del Trp Rel Cst | | to left, but here is the original pic of the RFC
+// | PRECEDENCE | TOS | MBZ | 1349. Also here, the MSB is left (strangely bit 0)
+// | | | | and the LSB is right (strangely bit 7).
+// +-----+-----+-----+-----+-----+-----+-----+-----+
+//
+// ARGUMENTS
+// if unused
+// ipp ... IP Precedence (0..7) or -1
+// tos ... Type of Service (0..15) or -1
+// mbz ... if 1 sets MBZ or 0
+int mops_ip_tos (struct mops* mp, int ipp, int tos, int mbz)
+{
+ u_int8_t TOS=0;
+
+ if (ipp!=-1)
+ {
+ if (ipp>7) return 1; // Invalid IPP value
+ TOS |= (ipp << 5);
+ }
+
+ if (tos!=-1)
+ {
+ if (tos>15) return 2; // Invalid ToS value
+ TOS |= (tos << 1);
+ }
+
+ if (mbz==1) // not used if mbz is either 0 or -1
+ {
+ TOS |= 0x01; // set
+ }
+
+ mp->ip_tos = TOS;
+
+ return 0;
+}
+
+
+
+//
+//
+// =================== ONLY IP OPTION HANDLING FUNCTION BELOW ================
+//
+///////////////////////////////////////////////////////////////////////////////
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// There are two cases for the format of an option:
+//
+// Case 1: A single octet of option-type.
+// Case 2: An option-type octet, an option-length octet, and the
+// actual option-data octets.
+//
+// The option-length octet counts the WHOLE number of bytes of the option
+//
+// The option-type consists of:
+//
+// +--------+--------+--------+--------+--------+--------+--------+--------+
+// | copied | option class | number (identifies option) |
+// | flag | | |
+// +--------+-----------------+--------------------------------------------+
+//
+//
+// The following Internet options are defined in RFC 791:
+//
+// CLASS NUMBER LENGTH DESCRIPTION
+// ----- ------ ------ -----------
+// 0 0 - End of Option list. This option occupies only
+// 1 octet; it has no length octet.
+// 0 1 - No Operation. This option occupies only 1
+// octet; it has no length octet.
+// 0 2 11 Security. Used to carry Security,
+// Compartmentation, User Group (TCC), and
+// Handling Restriction Codes compatible with DOD
+// requirements.
+// 0 3 var. Loose Source Routing. Used to route the
+// internet datagram based on information
+// supplied by the source.
+// 0 9 var. Strict Source Routing. Used to route the
+// internet datagram based on information
+// supplied by the source.
+// 0 7 var. Record Route. Used to trace the route an
+// internet datagram takes.
+// 0 8 4 Stream ID. Used to carry the stream
+// identifier.
+// 2 4 var. Internet Timestamp.
+//
+//
+// Possible options and associated number in mp->ip_option_used
+//
+// 1 - Security and handling restrictions (for military applications)
+// 2 - Record route
+// 4 - Timestamp
+// 8 - Loose source routing
+// 16 - Strict source routing
+//
+//
+
+// *** See RFCs 791, 1071, 1108 ***
+
+// Remove all options
+int mops_ip_option_remove_all (struct mops* mp)
+{
+ mp->ip_option_used = 0;
+ mp->ip_option_s = 0;
+ return 0;
+}
+
+
+// Add no-option
+int mops_ip_option_nop (struct mops* mp)
+{
+
+ return 0;
+}
+
+// Add end of option list
+int mops_ip_option_eol (struct mops* mp)
+{
+
+ return 0;
+}
+
+
+
+// Add loose source route option
+int mops_ip_option_lsr (struct mops* mp)
+{
+
+ return 0;
+}
+
+// Add strict source route option
+int mops_ip_option_ssr (struct mops* mp)
+{
+
+ return 0;
+}
+
+// Add record route option
+int mops_ip_option_rr (struct mops* mp)
+{
+
+ return 0;
+}
+
+// Add time stamp option
+int mops_ip_option_ts (struct mops* mp)
+{
+
+ return 0;
+}
+
+
+
+// Add security option.
+//
+// This option provides a way for hosts to send security, compartmentation,
+// handling restrictions, and TCC (closed user group) parameters. The format
+// for this option is as follows:
+//
+// +--------+--------+---//---+---//---+---//---+---//---+
+// |10000010|00001011|SSS SSS|CCC CCC|HHH HHH| TCC |
+// +--------+--------+---//---+---//---+---//---+---//---+
+// Type=130 Length=11
+//
+// Security (S field): 16 bits
+//
+// Specifies one of 16 levels of security (eight of which are
+// reserved for future use).
+//
+// 00000000 00000000 - Unclassified
+// 11110001 00110101 - Confidential
+// 01111000 10011010 - EFTO
+// 10111100 01001101 - MMMM
+// 01011110 00100110 - PROG
+// 10101111 00010011 - Restricted
+// 11010111 10001000 - Secret
+// 01101011 11000101 - Top Secret
+// 00110101 11100010 - (Reserved for future use)
+// 10011010 11110001 - (Reserved for future use)
+// 01001101 01111000 - (Reserved for future use)
+// 00100100 10111101 - (Reserved for future use)
+// 00010011 01011110 - (Reserved for future use)
+// 10001001 10101111 - (Reserved for future use)
+// 11000100 11010110 - (Reserved for future use)
+// 11100010 01101011 - (Reserved for future use)
+//
+//
+// Compartments (C field): 16 bits
+//
+// An all zero value is used when the information transmitted is not
+// compartmented. Other values for the compartments field may be obtained
+// from the Defense Intelligence Agency.
+//
+// Handling Restrictions (H field): 16 bits
+//
+// The values for the control and release markings are alphanumeric digraphs
+// and are defined in the Defense Intelligence Agency Manual DIAM 65-19,
+// "Standard Security Markings".
+//
+// Transmission Control Code (TCC field): 24 bits
+//
+// Provides a means to segregate traffic and define controlled communities
+// of interest among subscribers. The TCC values are trigraphs, and are available
+// from HQ DCA Code 530.
+//
+// Must be copied on fragmentation. This option appears at most
+// once in a datagram.
+
+int mops_ip_option_sec (struct mops* mp)
+{
+
+ return 0;
+}
+
+
+// Add the IP Router Alert Option - a method to efficiently signal
+// transit routers to more closely examine the contents of an IP packet.
+// See RFC 2113, and FYI also 3175 (RSVP Aggregation), and RFC 5350
+// (new IANA-defined Router Alert Options (RAO)).
+//
+// The Router Alert option has the following format:
+//
+// +--------+--------+--------+--------+
+// |10010100|00000100| 2 octet value |
+// +--------+--------+--------+--------+
+//
+// Type:
+// Copied flag: 1 (all fragments must carry the option)
+// Option class: 0 (control)
+// Option number: 20 (decimal)
+//
+// Length: 4
+//
+// Value: A two octet code with the following values:
+// 0 - Router shall examine packet
+// 1-65535 - Reserved
+//
+// RETURN VALUE: 0 upon success
+// 1 upon failure
+//
+int mops_ip_option_ra (struct mops* mp, int value)
+{
+ int ptr;
+ u_int16_t val;
+
+ if ((mp==NULL) || (value>0xffff)) return 1;
+
+ val = (u_int16_t) value;
+
+ ptr = mp->ip_option_s; // add option at the end of existing option list (if any)
+ mp->ip_option_used=20;
+
+ // create option header
+ mp->ip_option[ptr] = 0x94;
+
+ ptr++;
+ mp->ip_option[ptr] = 0x04;
+
+ ptr++;
+ mops_hton2 (&val, &mp->ip_option[ptr]);
+ ptr+=2;
+ mp->ip_option_s=4;
+
+ return 0;
+}
diff --git a/staging/mops_mpls.c b/staging/mops_mpls.c
new file mode 100644
index 0000000..5a03a0a
--- /dev/null
+++ b/staging/mops_mpls.c
@@ -0,0 +1,149 @@
+/*
+ * Mausezahn - A fast versatile traffic generator
+ * Copyright (C) 2008-2010 Herbert Haas
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
+ *
+*/
+
+
+#include "mz.h"
+#include "mops.h"
+
+// Assigns MPLS tag at position i (starting at zero!) with values:
+//
+// m ... total number of tags (important to set BoS in last tag)
+// Label ... label value
+// Exp ... EXP field (typically CoS)
+// TTL ... Time To Live
+//
+// NOTE: Two usage possibilities!
+//
+// 1.) When called from for-loop to add all tags the total size mpls_s
+// is updated continuously and the BoS is set in the last tag.
+// Therefore set m = total number of tags!
+//
+// 2.) But when changing a particular tag within an existing MPLS stack
+// the total number of tags does not change, therefore use m=0.
+//
+// RETURN VALUE: 0 upon success, 1 upon failure
+//
+int mops_mpls(struct mops *mp, int i, int m, u_int32_t Label, u_int8_t Exp, u_int8_t TTL)
+{
+ u_int8_t *ptr;
+
+ if ((m) && (i>=m)) return 1; // label index greater than number of labels!
+ if (Label > 1048575) return 1;
+ if (Exp > 7) return 1;
+
+ // Create binary tag: Label(20) EXP(3) BoS(1) TTL(8)
+ Label <<= 4;
+ ptr = (u_int8_t *) &Label;
+ mp->mpls[4*i+0] = *(ptr+2);
+ mp->mpls[4*i+1] = *(ptr+1);
+ mp->mpls[4*i+2] = *(ptr+0);
+ Exp <<= 1;
+ mp->mpls[4*i+2] |= Exp;
+ mp->mpls[4*i+3] = TTL;
+
+ if ((m) && (i==(m-1))) // reached last tag!
+ {
+ mp->mpls[4*i+2] |= 0x01; // set BoS in last tag
+ mp->mpls_s =4*m;
+ mp->use_MPLS = 1;
+ if ( (mp->eth_type != 0x8847) && (mp->eth_type != 0x8848) )
+ {
+ mp->eth_type_backup = mp->eth_type;
+ }
+ mp->eth_type = 0x8847;
+ }
+ return 0;
+}
+
+
+// Remove MPLS tags from packet mp
+//
+// j indicates which tag to be removed (1..n)
+// j=0 means: remove all tags!
+//
+// RETURN VALUE: 1 upon failure, 0 upon success
+int mops_mpls_remove (struct mops *mp, int j)
+{
+ int a, b, k;
+
+
+ if (j==0) // remove all tags
+ {
+ if (mp->use_MPLS)
+ {
+ mp->mpls_s=0;
+ mp->use_MPLS=0;
+ mp->eth_type = mp->eth_type_backup; // restore original ethertype
+ return 0;
+ }
+ else
+ return 1;
+ }
+
+ k = mp->mpls_s/4;
+ if (j>k) return 1; // The packet only consists of k tag(s)
+
+ if (k==1) // only delete the single tag
+ {
+ mp->mpls_s=0;
+ mp->use_MPLS=0;
+ mp->eth_type = mp->eth_type_backup; // restore original ethertype
+ return 0;
+ }
+
+ // if we got here we have more than one tag:
+
+ if (j==k) // remove last tag (of several)
+ {
+ mp->mpls_s -=4;
+ return 0;
+ }
+
+ // remove some non-ending tag: 0, 1, 2, 3
+ a = (j-1)*4; // target
+ b = j*4; // source (what should be copied)
+ memcpy(&mp->mpls[a], &mp->mpls[b], (k-j)*4);
+ mp->mpls_s -=4;
+ return 0;
+}
+
+
+// Set BOS in tag k where k=1..n
+int mops_mpls_bos (struct mops *mp, int k)
+{
+ int n;
+
+ n = mp->mpls_s/4; // n = total number of tags
+ if (k>n) return 1;
+
+ mp->mpls[(k-1)*4+2] |= 0x01;
+ return 0;
+}
+
+
+// Unset BOS in tag k where k=1..n
+int mops_mpls_nobos (struct mops *mp, int k)
+{
+ int n;
+
+ n = mp->mpls_s/4; // n = total number of tags
+ if (k>n) return 1;
+
+ mp->mpls[(k-1)*4+2] &= 0xfe;
+ return 0;
+}
diff --git a/staging/mops_sequence.c b/staging/mops_sequence.c
new file mode 100644
index 0000000..32e7895
--- /dev/null
+++ b/staging/mops_sequence.c
@@ -0,0 +1,303 @@
+/*
+ * Mausezahn - A fast versatile traffic generator
+ * Copyright (C) 2010 Herbert Haas
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
+ *
+*/
+
+
+#include "mz.h"
+#include "cli.h"
+#include "mops.h"
+#include "llist.h"
+
+
+///////////////////// TOC /////////////////////
+//
+// int mops_delete_sequence (char *name)
+// struct mz_ll * mops_create_sequence (char *name)
+// int mops_dump_sequence (char* str)
+// int mops_add_packet_to_sequence (struct mz_ll *seq, struct mops *mp)
+// int mops_add_delay_to_sequence (struct mz_ll *seq, struct timespec *t)
+// int mops_delete_packet_from_pseq (struct mz_ll *seq, int index)
+// int stop_sequence (char *name)
+// int stop_all_sequences ()
+
+
+// delete one sequence element (from the global packet_sequence list)
+// which must be specified by its name
+//
+int mops_delete_sequence (char *name)
+{
+ struct mz_ll *v;
+
+ v = mz_ll_search_name (packet_sequences, name);
+ if (v==NULL) return 1; // name not found
+
+ if (v->state) return 2; // sequence is currently active!
+
+ if (mz_ll_delete_element (v))
+ return -1; // cannot delete head element!
+ return 0;
+}
+
+
+
+struct mz_ll * mops_create_sequence (char *name)
+{
+ struct mz_ll *cur;
+ struct pseq *seq;
+ int i;
+
+ cur = mz_ll_create_new_element(packet_sequences);
+ if (cur==NULL) return NULL;
+ strncpy(cur->name, name, MZ_LL_NAME_LEN);
+ // add data
+ cur->data = (struct pseq*) malloc (sizeof(struct pseq));
+ // initialize data
+ seq = (struct pseq*) cur->data;
+ seq->count = 0;
+ for (i=0; i<MAX_PACKET_SEQUENCE_LEN; i++) {
+ seq->packet[i] = NULL; // pointer to the packets
+ seq->gap[i].tv_sec = 0;
+ seq->gap[i].tv_nsec = 0;
+ }
+ return cur;
+}
+
+
+
+// PURPOSE: dumps all sequence objects line-by-line
+//
+// ARGUMENTS: Caller must provide a pointer to a string of size MZ_LL_NAME_LEN+(MAX_PACKET_SEQUENCE_LEN*6)
+// (recommendation: 512 bytes !)
+//
+// RETURN VALUE: 0 if list is finished, 1 otherwise
+//
+// EXAMPLE: char str[512];
+// while (mops_dump_sequence(str)
+// printf("%s\n", str);
+//
+int mops_dump_sequence (char* str)
+{
+ static int init=0;
+ static struct mz_ll *cur;
+ struct pseq *seq;
+ struct mops *pkt;
+
+ char tmp[256], t[16];
+ int i, c;
+
+ tmp[0]='\0';
+
+ if (init==-1) { // last turn said stop now!
+ init=0;
+ return 0;
+ }
+
+ if (init==0) {
+ cur=packet_sequences->next;
+ if (cur==NULL) {
+ str[0]='\0';
+ return 0;
+ }
+ init=1;
+ }
+
+ seq = (struct pseq*) cur->data;
+ if (seq==NULL) {
+ init=-1;
+ sprintf(str, "(no sequences found)");
+ return 1;
+ }
+
+ c = seq->count; // amount of currently stored packets in this sequence object
+
+ // create string with all packet IDs:
+ for (i=0; i<c; i++) {
+ pkt = seq->packet[i];
+ if (pkt == NULL) break;
+ snprintf(t, 15, "%i", pkt->id);
+ if (strnlen(tmp,256)>249) break;
+ strncat(tmp, t, 6);
+ if (i<c-1) strncat(tmp,", ", 2);
+ }
+
+ snprintf(str, 512, "%s {%s}", cur->name, tmp);
+
+ cur=cur->next;
+ if (cur==packet_sequences) init=-1; // stop next turn!
+ return 1;
+}
+
+
+// finds next free slot in sequence seq and adds packet mp
+//
+// RETURN VALUE: 0 upon success
+// -1 failure: array full
+// -2 failure: cannot add packets with infinite count
+//
+int mops_add_packet_to_sequence (struct mz_ll *seq, struct mops *mp)
+{
+ struct pseq *cur;
+ int i;
+
+ if (seq==NULL) return 1;
+
+ // don't add packets with count=0
+ if (mp->count==0) return -2;
+
+ cur = (struct pseq*) seq->data;
+ if (cur->count >= MAX_PACKET_SEQUENCE_LEN) return -1; // packet array full!
+ for (i=0; i<MAX_PACKET_SEQUENCE_LEN; i++) {
+ if (cur->packet[i]==NULL) { // found empty slot
+ cur->packet[i]=mp;
+ cur->count++;
+ return 0;
+ }
+ }
+ return 1; // never reach here
+}
+
+
+// adds the given delay 't' to the last packet in the sequence's pseq
+//
+// NOTE: return index number of pseq where delay had been added
+// or upon failure: -1 if there is no packet yet defined
+// -2 if array is full
+int mops_add_delay_to_sequence (struct mz_ll *seq, struct timespec *t)
+{
+ struct pseq *cur;
+ int i;
+
+ if (seq==NULL) return 1;
+
+ cur = (struct pseq*) seq->data;
+ i = cur->count;
+ if (i>= MAX_PACKET_SEQUENCE_LEN) return -2; // packet array full!
+
+ cur->gap[i-1].tv_sec = t->tv_sec;
+ cur->gap[i-1].tv_nsec = t->tv_nsec;
+
+ return i-1; // note: is -1 if there is no packet yet (count=0)
+}
+
+
+// Deletes packet and associated delay from a pseq for given index
+// If index == -1 then the last packet/delay is removed
+//
+// NOTE: index range is {1..count}
+//
+// RETURN VALUES: 0 upon success
+// 1 upon failure
+// 2 upon failure, index too big
+//
+int mops_delete_packet_from_pseq (struct mz_ll *seq, int index)
+{
+ struct pseq *cur;
+ int i;
+
+ if (seq==NULL) return 1;
+ cur = (struct pseq*) seq->data;
+ if (cur->count==0) return 1; // list is empty, nothing to delete
+ if (index>cur->count) return 2;
+ if ((index==0) || (index<-1)) return 1; // total invalid index values
+ if (index==-1) { // remove last element
+ cur->packet[cur->count-1]=NULL;
+ cur->gap[cur->count-1].tv_sec=0;
+ cur->gap[cur->count-1].tv_nsec=0;
+ } else {
+ for (i=index-1; i<(cur->count-1); i++) {
+ cur->packet[i] = cur->packet[i+1];
+ cur->gap[i].tv_sec = cur->gap[i+1].tv_sec;
+ cur->gap[i].tv_nsec=cur->gap[i+1].tv_nsec;
+ }
+ }
+ cur->count--;
+ return 0;
+}
+
+
+int mops_delete_all_packets_from_pseq (struct mz_ll *seq)
+{
+ struct pseq *cur;
+ int i;
+
+ if (seq==NULL) return 1;
+ cur = (struct pseq*) seq->data;
+ if (cur->count==0) return 1; // list is empty, nothing to delete
+ // DELETE ALL:
+ cur->count = 0;
+ for (i=0; i<MAX_PACKET_SEQUENCE_LEN; i++) {
+ cur->packet[i] = NULL; // pointer to the packets
+ cur->gap[i].tv_sec = 0;
+ cur->gap[i].tv_nsec = 0;
+ }
+ return 0;
+}
+
+
+
+// Stops an active sequence and sets all involved packets from state SEQACT to CONFIG.
+//
+// RETURN VALUE: 0 upon success
+// 1 if sequence does not exist
+// 2 if sequence is not actice
+int stop_sequence (char *name)
+{
+ struct mz_ll *v;
+ struct pseq *cur;
+ int i;
+
+ v = mz_ll_search_name (packet_sequences, name);
+ if (v==NULL) return 1; // name not found
+ if (!v->state) return 2; // sequence is not currently active!
+
+ // now stop thread:
+ pthread_cancel(v->sequence_thread);
+
+ // reset packet states:
+ cur = (struct pseq*) v->data;
+ for (i=0; i<cur->count; i++)
+ cur->packet[i]->state=MOPS_STATE_CONFIG;
+
+ // reset sequence state:
+ v->state = 0;
+ return 0;
+}
+
+
+// runs through 'packet_sequences' and cancels all active sequences
+// (i. e. stops threads and sets states appropriately)
+//
+// Comment: It might seem a bit inefficient to call 'stop_sequence' for the
+// detailed work, but this is the more safer way and it is fast enough.
+//
+// RETURN VALUE: Number of stopped sequences.
+//
+int stop_all_sequences ()
+{
+ struct mz_ll *cur=packet_sequences->next;
+ int i=0;
+
+ while (cur!=packet_sequences) {
+ if (cur!=packet_sequences) { // just for safety
+ if (stop_sequence(cur->name)==0) i++;
+ }
+ cur=cur->next;
+ }
+
+ return i;
+}
+
diff --git a/staging/mops_tcp.c b/staging/mops_tcp.c
new file mode 100644
index 0000000..4d788bd
--- /dev/null
+++ b/staging/mops_tcp.c
@@ -0,0 +1,154 @@
+/*
+ * Mausezahn - A fast versatile traffic generator
+ * Copyright (C) 2008-2010 Herbert Haas
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
+ *
+*/
+
+
+#include "mz.h"
+#include "mops.h"
+#include "cli.h"
+
+// Calculates the number of TCP transmissions based on SQNR range
+u_int32_t mops_tcp_complexity_sqnr (struct mops * mp)
+{
+ u_int32_t a,b,t,result;
+
+ a = mp->tcp_seq_start;
+ b = mp->tcp_seq_stop;
+ t = mp->tcp_seq_delta;
+
+ if (!t) return 1; // delta set to zero means no range
+
+ if (a<b) // regular case
+ result = ceill ((b-a)/t);
+ else // range wraps around
+ result = ceill (((0xffffffff-a) + b)/t);
+
+ return result;
+}
+
+
+// Calculates the number of TCP transmissions based on SQNR range
+u_int32_t mops_tcp_complexity_acknr (struct mops * mp)
+{
+ u_int32_t a,b,t,result;
+
+ a = mp->tcp_ack_start;
+ b = mp->tcp_ack_stop;
+ t = mp->tcp_ack_delta;
+
+ if (!t) return 1; // delta set to zero means no range
+
+ if (a<b) // regular case
+ result = ceill ((b-a)/t);
+ else // range wraps around
+ result = ceill (((0xffffffff-a) + b)/t);
+
+ return result;
+}
+
+
+
+
+// *****TODO: TCP Options ******
+
+// Remove all options
+int mops_tcp_option_remove_all (struct mops* mp)
+{
+
+ return 0;
+}
+
+
+// Prints current flag settings in the provided string 'str'.
+// NOTE that str must be at least 32 bytes!
+// *** BETTER USE 64 bytes (for future compatibility) ***
+//
+int mops_tcp_flags2str (struct mops* mp, char *str)
+{
+ if (mp==NULL) {
+ sprintf(str, "(no valid mops)\n");
+ return 1;
+ }
+
+ sprintf(str, "%s-%s-%s-%s-%s-%s-%s-%s",
+ (mp->tcp_ctrl_CWR) ? "CRW" : "---",
+ (mp->tcp_ctrl_ECE) ? "ECE" : "---",
+ (mp->tcp_ctrl_URG) ? "URG" : "---",
+ (mp->tcp_ctrl_ACK) ? "ACK" : "---",
+ (mp->tcp_ctrl_PSH) ? "PSH" : "---",
+ (mp->tcp_ctrl_RST) ? "RST" : "---",
+ (mp->tcp_ctrl_SYN) ? "SYN" : "---",
+ (mp->tcp_ctrl_FIN) ? "FIN" : "---");
+
+ return 0;
+}
+
+// Add TCP options
+//
+// TODO: currently all params are ignored and a default option combination is added.
+//
+int mops_tcp_add_option (struct mops* mp,
+ int mss,
+ int sack,
+ int scale,
+ u_int32_t tsval,
+ u_int32_t tsecr)
+{
+
+ u_int8_t tcp_default_options[] = {
+ 0x02, 0x04, 0x05, 0xac, // MSS
+ 0x04, 0x02, // SACK permitted
+ 0x08, 0x0a, 0x19, 0x35, 0x90, 0xc3, 0x00, 0x00, 0x00, 0x00, // Timestamps
+ 0x01, // NOP
+ 0x03, 0x03, 0x05 // Window Scale 5
+ };
+
+
+ /* Kind: 8
+ Length: 10 bytes
+
+ +-------+-------+---------------------+---------------------+
+ |Kind=8 | 10 | TS Value (TSval) |TS Echo Reply (TSecr)|
+ +-------+-------+---------------------+---------------------+
+ 1 1 4 4
+ *
+ * The Timestamps option carries two four-byte timestamp fields. The
+ * Timestamp Value field (TSval) contains the current value of the
+ * timestamp clock of the TCP sending the option.
+ *
+ * The Timestamp Echo Reply field (TSecr) is only valid if the ACK bit
+ * is set in the TCP header; if it is valid, it echos a times- tamp
+ * value that was sent by the remote TCP in the TSval field of a
+ * Timestamps option. When TSecr is not valid, its value must be zero.
+ * The TSecr value will generally be from the most recent Timestamp
+ * option that was received; however, there are exceptions that are
+ * explained below.
+ *
+ * A TCP may send the Timestamps option (TSopt) in an initial <SYN>
+ * segment (i.e., segment containing a SYN bit and no ACK bit), and
+ * may send a TSopt in other segments only if it re- ceived a TSopt in
+ * the initial <SYN> segment for the connection.
+ *
+ */
+
+ memcpy((void*) mp->tcp_option, (void*) tcp_default_options, 20);
+ mp->tcp_option_s = 20;
+ mp->tcp_option_used = 1;
+
+ return 0;
+}
+
diff --git a/staging/mops_threads.c b/staging/mops_threads.c
new file mode 100644
index 0000000..69893db
--- /dev/null
+++ b/staging/mops_threads.c
@@ -0,0 +1,639 @@
+/*
+ * Mausezahn - A fast versatile traffic generator
+ * Copyright (C) 2008-2010 Herbert Haas
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
+ *
+*/
+
+#include "mz.h"
+#include "mops.h"
+#include "cli.h"
+#include "llist.h"
+
+
+
+void mops_set_active (struct mops *mp)
+{
+ pthread_mutex_lock (& (mp->mops_mutex) );
+ mp->state = MOPS_STATE_ACTIVE;
+ pthread_mutex_unlock (& (mp->mops_mutex) );
+}
+
+void mops_set_seqact (struct mops *mp)
+{
+ pthread_mutex_lock (& (mp->mops_mutex) );
+ mp->state = MOPS_STATE_SEQACT;
+ pthread_mutex_unlock (& (mp->mops_mutex) );
+}
+
+
+void mops_set_conf (struct mops *mp)
+{
+ pthread_mutex_lock (& (mp->mops_mutex) );
+ mp->state = MOPS_STATE_CONFIG;
+ pthread_mutex_unlock (& (mp->mops_mutex) );
+}
+
+
+int mops_is_active (struct mops *mp)
+{
+ int i=0;
+ pthread_mutex_lock (& (mp->mops_mutex) );
+ if (mp->state == MOPS_STATE_ACTIVE) i=1;
+ pthread_mutex_unlock (& (mp->mops_mutex) );
+ return i;
+}
+
+// Returns 1 if the packet is in any running state
+// such as MOPS_STATE_ACTIVE or MOPS_STATE_SEQACT
+int mops_is_any_active (struct mops *mp)
+{
+ int i=0;
+ pthread_mutex_lock (& (mp->mops_mutex) );
+ if (mp->state > MOPS_STATE_CONFIG) i=1;
+ pthread_mutex_unlock (& (mp->mops_mutex) );
+ return i;
+}
+
+
+int mops_is_seqact (struct mops *mp)
+{
+ int i=0;
+ pthread_mutex_lock (& (mp->mops_mutex) );
+ if (mp->state == MOPS_STATE_SEQACT) i=1;
+ pthread_mutex_unlock (& (mp->mops_mutex) );
+ return i;
+}
+
+
+
+// return mops state (0=MOPS_STATE_NULL, 1=MOPS_STATE_INIT, 2=MOPS_STATE_CONFIG, 3=MOPS_STATE_ACTIVE, 4=MOPS_STATE_SEQACT)
+int mops_state (struct mops *mp)
+{
+ int i=0;
+ pthread_mutex_lock (& (mp->mops_mutex) );
+ i = mp->state;
+ pthread_mutex_unlock (& (mp->mops_mutex) );
+ return i;
+}
+
+
+int mops_tx_simple (struct mops *mp)
+{
+
+ if (mops_is_active(mp)) {
+ return 3;
+ }
+
+ if (mp->interval_used) {
+ if ( pthread_create( &(mp->interval_thread), NULL, mops_interval_thread, mp) ) {
+ mp->interval_used=1; // 1 means interval only configured
+ return 1; // Error creating thread
+ }
+ } else // normal packet train
+ if ( pthread_create( &(mp->mops_thread), NULL, mops_tx_thread_native, mp) ) {
+ return 1; // Error creating thread
+ }
+
+ return 0;
+}
+
+
+// Starts a packet sequence.
+//
+// RETURN VALUES: 0 upon success
+// 1 failure: packet not in CONFIG state
+// 2 failure: packet has infinite count
+int mops_tx_sequence (struct mz_ll *seq)
+{
+ struct pseq *cur;
+ int i;
+
+ // verify 1) that all packets are in config state
+ // 2) and have finite count:
+ cur = (struct pseq*) seq->data;
+ for (i=0; i<cur->count; i++) {
+ if (cur->packet[i]->state!=MOPS_STATE_CONFIG) return 1;
+ if (cur->packet[i]->count==0) return 2;
+ }
+
+ // Set all packets in this sequence into state SEQACT:
+ for (i=0; i<cur->count; i++)
+ mops_set_seqact (cur->packet[i]);
+
+ if ( pthread_create( &(seq->sequence_thread), NULL, mops_sequence_thread, seq) ) {
+ return 3; // Error creating thread
+ }
+ seq->state=1;
+ return 0;
+}
+
+
+// This is the sequence sending thread
+void *mops_sequence_thread (void *arg)
+{
+ struct mz_ll *seq = (struct mz_ll*) arg;
+ struct pseq *cur;
+ int i;
+
+ cur = (struct pseq*) seq->data;
+
+ // Send one packet after each other, possibly with gaps inbetween:
+ for (i=0; i<cur->count; i++) {
+ mops_tx_thread_native (cur->packet[i]);
+ // if gap exists...
+ if ((cur->gap[i].tv_sec) || (cur->gap[i].tv_nsec)) {
+ nanosleep(&cur->gap[i], NULL); //...apply it.
+ }
+ }
+
+ // Finally:
+ // 1) reset all packets into config state
+ for (i=0; i<cur->count; i++)
+ cur->packet[i]->state=MOPS_STATE_CONFIG;
+ // 2) join to main
+ pthread_exit(NULL);
+ // 3) set sequence state to inactive (=0)
+ seq->state=0;
+
+ return NULL;
+}
+
+// This is the interval management thread which starts
+// packet transmission threads by itself.
+//
+// Note how this works: After the while statement below we have actually
+// two threads, mops_tx_thread_native (sending the packet) and mops_interval_thread which
+// starts mops_tx_thread_native every mp->interval. If mp->interval is smaller than
+// mp->delay (and mp->count > 1) then multiple transmission threads will be active at the
+// same time which is usually not what the user wants. We do not catch this case here
+// but the user interface should do that (it is done in 'cmd_packet_interval').
+//
+void *mops_interval_thread (void *arg)
+{
+ struct mops *mp = (struct mops*) arg;
+
+ mp->interval_used=2; // 2 means active interval
+ while (1) {
+ if ( pthread_create( &(mp->mops_thread), NULL, mops_tx_thread_native, mp) ) {
+ mp->interval_used=1;
+ pthread_exit(NULL);
+ }
+ nanosleep(&mp->interval, NULL);
+ }
+
+ pthread_exit(NULL); // hmm...does this make sense?
+ return NULL;
+}
+
+
+// General MOPS sending thread using packet sockets.
+//
+void *mops_tx_thread_native (void *arg)
+{
+ struct mops *mp = (struct mops*) arg;
+ struct mops_ext_rtp * pd;
+ int ps, i, n=0;
+ u_int8_t DA[4];
+ // Local vars are faster --------------------------
+ struct timespec tv;
+ register int infinity, devind;
+ int ip_src_isrange = mp->use_IP & mp->ip_src_isrange;
+ int ip_dst_isrange = mp->use_IP & mp->ip_dst_isrange;
+ int sp_isrange = (mp->use_UDP | mp->use_TCP) & mp->sp_isrange;
+ int dp_isrange = (mp->use_UDP | mp->use_TCP) & mp->dp_isrange;
+ int ip_src_israndom = mp->use_IP & mp->ip_src_israndom;
+ int sp_isrand = (mp->use_UDP | mp->use_TCP) & mp->sp_isrand;
+ int dp_isrand = (mp->use_UDP | mp->use_TCP) & mp->dp_isrand;
+
+
+ u_int32_t
+ ip_src_start = mp->ip_src_start,
+ ip_src_stop = mp->ip_src_stop,
+ ip_dst_start = mp->ip_dst_start,
+ ip_dst_stop = mp->ip_dst_stop,
+ tcp_seq_delta = mp->tcp_seq_delta,
+ tcp_seq_range = 0,
+ tcp_ack_delta = mp->tcp_ack_delta,
+ tcp_ack_range = 0,
+ tcp_ack_count = 0,
+ tcp_seq_count = 0;
+
+ int
+ sp_start = mp->sp_start,
+ dp_start = mp->dp_start,
+ sp_stop = mp->sp_stop,
+ dp_stop = mp->dp_stop;
+
+ int
+ rtp_mode = 0; // RTP not used
+
+ int
+ fragsize = 0,
+ frag_overlap = 0,
+ fragptr = 0,
+ offset = 0,
+ offset_delta = 0,
+ begin_ip_payload = 0,
+ ip_payload_s = 0,
+ original_msg_s = 0,
+ whats_used = 0; // store use_UDP or use_TCP here to clean up packet parameters finally
+ char
+ original_msg[MAX_MOPS_MSG_SIZE+1], // temporary buffer when fragmentation is needed
+ ip_payload[MAX_MOPS_MSG_SIZE+1]; // temporary buffer when fragmentation is needed
+
+
+ // -------------------------------------------------
+
+
+ /////////////////////////////
+ // NOTE: If packet is part of a sequence, then this function is already part of a sequence thread
+ // and all packets are already in state SEQACT. Otherwise we set the packet in state ACTIVE.
+ if (!mops_is_seqact(mp))
+ mops_set_active (mp);
+ /////////////////////////////
+
+
+ // infinite or not? Count up or down?
+ if (mp->count == 0) {
+ infinity = 1;
+ mp->cntx = 0;
+ }
+ else {
+ infinity = 0;
+ mp->cntx = mp->count; // count down
+ }
+
+ // Which delay?
+ tv.tv_sec = mp->ndelay.tv_sec;
+ tv.tv_nsec = mp->ndelay.tv_nsec;
+
+ // Which interface?
+ for (i=0; i<device_list_entries; i++) {
+ if (strncmp(device_list[i].dev, mp->device, 15)==0) break;
+ }
+ devind=i;
+
+ // Packet socket already existing and valid?
+ ps = device_list[devind].ps; // the packet socket
+ if (ps<0) goto FIN;
+
+ // Automatic direct or indirect delivery for IP packets?
+ if ((mp->use_IP) && (mp->auto_delivery_off == 0)) {
+ if (mp->ip_dst_isrange)
+ mops_hton4(&mp->ip_dst_start, DA);
+ else
+ mops_hton4(&mp->ip_dst, DA);
+
+ mops_ip_get_dst_mac(&device_list[devind], DA, mp->eth_dst);
+ }
+
+
+ // Impossible settings
+ if (((ip_src_isrange) && (ip_src_israndom)) ||
+ ((sp_isrand) && (sp_isrange)) ||
+ ((dp_isrand) && (dp_isrange))) {
+ fprintf(stderr, "[ERROR] (mops_tx_thread_native) -- conflicting requirements: both range and random!\n");
+ goto FIN;
+ }
+
+ // Initialize start values when ranges have been defined
+ if (ip_src_isrange) mp->ip_src = mp->ip_src_start;
+ if (ip_dst_isrange) mp->ip_dst = mp->ip_dst_start;
+ if (sp_isrange) mp->sp = mp->sp_start;
+ if (dp_isrange) mp->dp = mp->dp_start;
+ if (tcp_seq_delta) {
+ tcp_seq_range = mops_tcp_complexity_sqnr(mp);
+ mp->tcp_seq = mp->tcp_seq_start;
+ tcp_seq_count = tcp_seq_range;
+ }
+ if (tcp_ack_delta) {
+ tcp_ack_range = mops_tcp_complexity_acknr(mp);
+ mp->tcp_ack = mp->tcp_ack_start;
+ tcp_ack_count = tcp_ack_range;
+ }
+
+ // RTP special message treatment
+ if (mp->p_desc_type == MOPS_RTP) {
+ pd = mp->p_desc;
+ if (pd==NULL) return NULL;
+ if (pd->source == DSP_SOURCE)
+ rtp_mode = 2; // dsp payload
+ else
+ rtp_mode = 1; // zero payload
+
+ mops_update_rtp (mp); // initialize RTP packet here
+ }
+
+ // TODO: VLAN, MPLS - ranges
+
+ //
+ // ---------------------- The holy transmission loop ---------------- //
+ //
+
+ // Update whole packet (once before loop!)
+ mops_ext_update (mp);
+ mops_update(mp);
+
+
+ // Check if IP fragmentation is desired.
+ // If yes, set local 'fragsize' and 'begin_ip_payload' pointer.
+ if (mp->ip_fragsize) {
+ if (mp->use_IP) {
+ fragsize = mp->ip_fragsize;
+ frag_overlap = mp->ip_frag_overlap;
+ offset = mp->ip_frag_offset;
+ offset_delta = (fragsize-frag_overlap)/8;
+ if (mp->use_UDP) {
+ begin_ip_payload = mp->begin_UDP;
+ whats_used = 1;
+ } else if (mp->use_TCP) {
+ begin_ip_payload = mp->begin_TCP;
+ whats_used = 2;
+ } else {
+ begin_ip_payload = mp->begin_MSG;
+ whats_used = 0;
+ }
+ ip_payload_s = mp->frame_s - begin_ip_payload;
+ memcpy((void*) original_msg, (void*) mp->msg, mp->msg_s);
+ original_msg_s = mp->msg_s;
+ memcpy((void*) ip_payload, (void*) &mp->frame[begin_ip_payload], ip_payload_s);
+ }
+ }
+
+
+ goto START; // looks like a dirty hack but reduces a few cpu cycles each loop
+
+ do {
+ INLOOP:
+ nanosleep(&tv, NULL); // don't apply this before first and after last packet.
+ START:
+
+ // +++++++++++++++++++++++++++++++++++
+
+
+ // ------ IP fragmentation required? ------------------------------------------------------
+ //
+ // Basic idea: At this point we assume that all updates have been already applied
+ // so mp->frame contains a valid packet. But now we do the following:
+ //
+ // 1. Determine first byte after end of IP header (IP options may be used) [done above]
+ // 2. Store the 'IP payload' in the temporary buffer 'ip_payload' [done above]
+ // 3. Create a new IP payload but take only the first fragsize bytes out of 'ip_payload'
+ // 4. This new IP payload is copied into mp->msg
+ // 5. Set the IP parameters: MF=1, offset=0
+ // 6. Call mops_update() and send the packet
+ // 7. offset = offset + fragsize/8
+ // 8. Increment the IP identification number
+ // 9. Repeat this until the last fragment is reached. For the last fragment
+ // set the flag MF=0.
+ // 10. Restore the original IP parameters (use_UDP or use_TCP)
+ if (fragsize) {
+ mp->use_UDP=0;
+ mp->use_TCP=0;
+ fragptr=0; // NOTE: by intention we do not set mp->ip_frag_offset to 0 here !!! The user knows what she does!
+ mp->ip_flags_MF=1;
+ mp->ip_id++; // automatically wraps around correctly (u_int16_t)
+ // send all fragments except the last one:
+ while(fragptr+fragsize < ip_payload_s) {
+ memcpy((void*) mp->msg, (void*) ip_payload+fragptr, fragsize);
+ mp->msg_s = fragsize;
+ mops_update(mp);
+ n = write(ps, mp->frame, mp->frame_s);
+ if (n!=mp->frame_s) {
+ fprintf(stderr, "ERROR: Could not send IP fragment through interface %s\n", mp->device);
+ // LOG error msg
+ goto FIN;
+ }
+ fragptr+=fragsize;
+ mp->ip_frag_offset += offset_delta;
+ }
+ // send last fragment:
+ mp->ip_flags_MF=0;
+ memcpy((void*) mp->msg, (void*) ip_payload+fragptr, ip_payload_s-fragptr);
+ mp->msg_s = ip_payload_s-fragptr;
+ mops_update(mp);
+ n = write(ps, mp->frame, mp->frame_s);
+ if (n!=mp->frame_s) {
+ fprintf(stderr, "ERROR: Could not send IP fragment through interface %s\n", mp->device);
+ // LOG error msg
+ goto FIN;
+ }
+
+ // -- restore original mops parameters --
+ switch (whats_used) {
+ case 1: mp->use_UDP = 1; break;
+ case 2: mp->use_TCP = 1; break;
+ }
+ memcpy((void*) mp->msg, (void*) original_msg, original_msg_s);
+ mp->msg_s = original_msg_s;
+ mp->ip_frag_offset=offset;
+ goto NEXT;
+ }
+
+ // -- send unfragmented packets here: --
+ n = write(ps, mp->frame, mp->frame_s);
+ if (n!=mp->frame_s) {
+ fprintf(stderr, "ERROR: Could not send packet through interface %s\n", mp->device);
+ // LOG error msg
+ goto FIN;
+ }
+
+ NEXT:
+
+ /* [ RTP TODO: ] Use another thread reading from /dev/dsp and signalling us to continue!
+ * It should work like this: (pseudocode below)
+ *
+ * if (rtp_mode == DSP_SOURCE) {
+ * pthread_cond_wait ( &mycond, &mymutex ); // wait until pthread condition is signaled
+ * // now, frame should contain 160 bytes from /dev/dsp
+ * goto INLOOP;
+ * }
+ *
+ * The reading thread will do something like this: (again fuzzy code only)
+ *
+ * loop:
+ * read(fd, pd->rtp_payload, 160); // this takes 20 msec anyway
+ * mops_update_rtp_dynamics (mp); // also updates dynamic header fields
+ * pthread_cond_broadcast (&mycond); // wake up TX thread
+ * goto loop;
+ *
+ * See also
+ * http://www.oreilly.de/catalog/multilinux/excerpt/ch14-05.htm
+ *
+ * NOTE that we must not reach nanosleep below because the 20 msec delay is
+ * done implicitely by reading 160 bytes from /dev/dsp
+ */
+
+ switch (rtp_mode) {
+ case 1: // dummy payload => segmentation delay is controlled by nanosleep below!
+ mops_update_rtp_dynamics (mp);
+ break;
+ case 2: // await data from /dev/dsp => segmentation delay is controlled by a reading thread!
+ /* pthread_cond_wait ( &mycond, &mymutex ); // wait until pthread condition is signaled
+ * // now, frame should contain 160 bytes from /dev/dsp
+ * goto INLOOP;
+ */
+ break;
+ default:
+ // no RTP, continue as usual
+ break;
+ }
+
+
+ // +++++++++++++++++++++++++++++++++++
+ //
+ // *** begin of modifiers -- order is important! *** *************** //
+ //
+ if (tcp_seq_delta) {
+ if (--tcp_seq_count) {
+ mp->tcp_seq += tcp_seq_delta;
+ mops_update(mp);
+ goto INLOOP;
+ } else {
+ tcp_seq_count = tcp_seq_range;
+ mp->tcp_seq = mp->tcp_seq_start;
+ mops_update(mp);
+ }
+ }
+
+ if (tcp_ack_delta) {
+ if (--tcp_ack_count) {
+ mp->tcp_ack += tcp_ack_delta;
+ mops_update(mp);
+ goto INLOOP;
+ } else {
+ tcp_ack_count = tcp_ack_range;
+ mp->tcp_ack = mp->tcp_ack_start;
+ mops_update(mp);
+ }
+ }
+
+ if (ip_src_isrange) {
+ if (++mp->ip_src > ip_src_stop) {
+ mp->ip_src = ip_src_start;
+ mops_update(mp);
+ }
+ else {
+ mops_update(mp);
+ goto INLOOP;
+ }
+ }
+
+ if (ip_src_israndom) {
+ mp->ip_src = 0x01000001 + (u_int32_t) ( ((float) rand()/RAND_MAX)*0xE0000000); //latter is 224.0.0.0
+ }
+
+ if (ip_dst_isrange) {
+ if (++mp->ip_dst > ip_dst_stop) {
+ mp->ip_dst = ip_dst_start;
+ if (mp->auto_delivery_off == 0) {
+ mops_hton4(&mp->ip_dst, DA);
+ mp->eth_dst[0] = 0x01;
+ mp->eth_dst[1] = 0x00;
+ mp->eth_dst[2] = 0x5e;
+ mp->eth_dst[3] = DA[1] & 127;
+ mp->eth_dst[4] = DA[2];
+ mp->eth_dst[5] = DA[3];
+ }
+ mops_update(mp);
+ }
+ else {
+ if (mp->auto_delivery_off == 0) {
+ mops_hton4(&mp->ip_dst, DA);
+ mp->eth_dst[0] = 0x01;
+ mp->eth_dst[1] = 0x00;
+ mp->eth_dst[2] = 0x5e;
+ mp->eth_dst[3] = DA[1] & 127;
+ mp->eth_dst[4] = DA[2];
+ mp->eth_dst[5] = DA[3];
+ }
+ mops_update(mp);
+ goto INLOOP;
+ }
+ }
+
+ if (dp_isrange) {
+ if (++mp->dp > dp_stop) {
+ mp->dp = dp_start;
+ mops_update(mp);
+ }
+ else {
+ mops_update(mp);
+ goto INLOOP;
+ }
+ }
+
+ if (dp_isrand) {
+ mp->dp = (u_int16_t) ( ((float) rand()/RAND_MAX)*0xffff);
+ }
+
+
+ if (sp_isrange) {
+ if (++mp->sp > sp_stop) {
+ mp->sp = sp_start;
+ mops_update(mp);
+ }
+ else {
+ mops_update(mp);
+ goto INLOOP;
+ }
+ }
+
+ if (sp_isrand) {
+ mp->sp = (u_int16_t) ( ((float) rand()/RAND_MAX)*0xffff);
+ }
+
+
+ // *** end of modifiers ******************************************** //
+ if (infinity) {
+ mp->cntx++; // count up
+ goto INLOOP;
+ }
+ } while (--mp->cntx);
+
+ FIN:
+ if (!mops_is_seqact(mp)) {
+ // only [change state and close thread] if packet is NOT part of a sequence.
+ // If the packet is part of a sequence then THIS function is already part of
+ // a sequence thread and it will be closed in 'mops_sequence_thread'.
+ mops_set_conf (mp);
+ pthread_exit(NULL);
+ }
+ return NULL;
+}
+
+
+
+
+
+int mops_destroy_thread (struct mops *mp)
+{
+ int r=1;
+
+ if (mp->interval_used==2) {
+ pthread_cancel(mp->interval_thread);
+ mp->interval_used=1;
+ r=0;
+ }
+
+ if (mops_is_active(mp)) {
+ pthread_cancel(mp->mops_thread);
+ pthread_mutex_destroy(& mp->mops_mutex);
+ mops_set_conf(mp);
+ r=0;
+ }
+
+ return r;
+}
diff --git a/staging/mops_tools.c b/staging/mops_tools.c
new file mode 100644
index 0000000..022f45b
--- /dev/null
+++ b/staging/mops_tools.c
@@ -0,0 +1,259 @@
+/*
+ * Mausezahn - A fast versatile traffic generator
+ * Copyright (C) 2008,2009 Herbert Haas
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
+ *
+*/
+
+
+#include "mz.h"
+#include "mops.h"
+
+// Inserts value in 'flag' (up to 7 bits are useful) into the target
+// with an optional left-shift. For example if flag contains a 4-bit value
+// and should be placed within the target in bit positions 3-6 like:
+//
+// 7 6 5 4 3 2 1 0
+// +--+--+--+--+--+--+--+--+
+// | | FLAGS | | | |
+// +--+--+--+--+--+--+--+--+
+//
+// then simply call:
+//
+// (void) mops_flags ( &target, &flag, 3 );
+//
+// Note that shift=0 means no shift.
+inline void mops_flags (u_int8_t *target, u_int8_t *flag, int shift)
+{
+ *target |= (*flag << shift);
+}
+
+
+
+inline void mops_hton2 (u_int16_t *host16, u_int8_t *net16)
+{
+ char *x;
+
+ x = (char*) host16;
+
+ *(net16++) = *(x+1);
+ *net16 = *x;
+}
+
+
+inline void mops_hton4 (u_int32_t *host32, u_int8_t *net32)
+{
+ char *x;
+
+ x = (char*) host32;
+
+ *(net32++) = *(x+3);
+ *(net32++) = *(x+2);
+ *(net32++) = *(x+1);
+ *(net32) = *x;
+}
+
+
+
+
+// returns new counter index for given packet
+// or -1 if all counters used already
+int mops_get_counter (struct mops *mp)
+{
+ int i=0;
+
+ while (mp->counter[i].offset)
+ {
+ i++;
+ if (i==MAX_MOPS_COUNTERS_PER_PACKET) // exceeded range
+ return -1;
+ }
+ return i;
+}
+
+
+// Adds single byte to msg
+int mops_msg_add_byte (struct mops *mp, u_int8_t data)
+{
+ mp->msg[mp->msg_s++] = data;
+ return 0;
+}
+
+
+// Adds bit field in *previous* msg-byte using optional left-shift
+int mops_msg_add_field (struct mops *mp, u_int8_t data, int shift)
+{
+ mp->msg[mp->msg_s -1] |= (data << shift);
+ return 0;
+}
+
+
+// Adds two bytes in network byte order to msg
+int mops_msg_add_2bytes (struct mops *mp, u_int16_t data)
+{
+ char *x;
+ x = (char*) &data;
+ mp->msg[mp->msg_s++] = *(x+1);
+ mp->msg[mp->msg_s++] = *(x);
+ return 0;
+}
+
+
+// Adds four bytes in network byte order to msg
+int mops_msg_add_4bytes (struct mops *mp, u_int32_t data)
+{
+ char *x;
+ x = (char*) &data;
+ mp->msg[mp->msg_s++] = *(x+3);
+ mp->msg[mp->msg_s++] = *(x+2);
+ mp->msg[mp->msg_s++] = *(x+1);
+ mp->msg[mp->msg_s++] = *(x);
+ return 0;
+}
+
+// Adds string of bytes with lenght len
+int mops_msg_add_string (struct mops *mp, u_int8_t *str, int len)
+{
+ memcpy((void *) &mp->msg[mp->msg_s], (void *) str, len);
+ mp->msg_s += len;
+
+ return 0;
+}
+
+
+
+// Add counter to message
+int mops_msg_add_counter (struct mops *mp,
+ int random, // 1=random, 0=use start/stop/step
+ u_int32_t start, // HOST BYTE ORDER
+ u_int32_t stop, // HOST BYTE ORDER
+ u_int32_t step, // HOST BYTE ORDER
+ int bytes // number of bytes used (1|2|4) - selects hton2 or hton4
+ )
+{
+
+ int i;
+
+ // check if unsupported byte count
+ if ( (bytes!=1) &&
+ (bytes!=2) &&
+ (bytes!=4) )
+ return 1;
+
+ // get new counter
+ i = mops_get_counter(mp);
+ if (i==-1) return 1;
+
+ // configure counter values
+ mp->counter[i].offset = mp->msg_s;
+ mp->counter[i].random = random;
+ mp->counter[i].start = start;
+ mp->counter[i].stop = stop;
+ mp->counter[i].step = step;
+ mp->counter[i].bytes = bytes;
+ mp->counter[i].cur = start;
+ mp->counter[i].use = 1;
+
+
+ // configure first pointer value
+ switch (bytes)
+ {
+ case 1:
+ mops_msg_add_byte(mp, (u_int8_t) start);
+ break;
+ case 2:
+ mops_msg_add_2bytes(mp, (u_int16_t) start);
+ break;
+ case 4:
+ mops_msg_add_4bytes(mp, start);
+ break;
+ default: // never be reached
+ return 1;
+ }
+
+ return 0;
+}
+
+
+
+// Compares two IP addresses byte by byte
+// returns 0 if identical, 1 if different
+//
+// Note that this works independent of endianess
+// as long as both addresses have same endianess.
+//
+int compare_ip (u_int8_t *ip1, u_int8_t *ip2)
+{
+ if (*ip1 != *ip2) return 1;
+ if (*(ip1+1) != *(ip2+1)) return 1;
+ if (*(ip1+2) != *(ip2+2)) return 1;
+ if (*(ip1+3) != *(ip2+3)) return 1;
+
+ return 0;
+}
+
+
+// Compares two MAC addresses byte by byte
+// returns 0 if identical, 1 if different
+int compare_mac (u_int8_t *mac1, u_int8_t *mac2)
+{
+ if (*mac1 != *mac2) return 1;
+ if (*(mac1+1) != *(mac2+1)) return 1;
+ if (*(mac1+2) != *(mac2+2)) return 1;
+ if (*(mac1+3) != *(mac2+3)) return 1;
+ if (*(mac1+4) != *(mac2+4)) return 1;
+ if (*(mac1+5) != *(mac2+5)) return 1;
+
+ return 0;
+}
+
+
+// Converts a 'struct timespec' value into a human readable string
+// This stringt is written into 'str' which must be at least a 32 byte
+// array.
+int timespec2str(struct timespec *t, char *str)
+{
+ unsigned int d=0, h, m, s;
+
+ // zero delay
+ if ((t->tv_sec==0) && (t->tv_nsec==0)) {
+ sprintf(str, "(none)");
+ return 0;
+ }
+
+ h = t->tv_sec/3600;
+ m = (t->tv_sec - h*3600)/60;
+ s = t->tv_sec - h*3600 - m*60;
+
+ if (h>24) {
+ d = h/24;
+ h = h - d*24;
+ sprintf(str, "%u days %02u:%02u:%02u", d, h, m, s);
+ return 0;
+ }
+
+ if (h|m)
+ sprintf(str, "%02u:%02u:%02u", h, m, s); // ignore nanoseconds if delay is in order of hours
+ else if (s)
+ sprintf(str, "%u%s sec", s, (t->tv_nsec>1000000) ? "+" : "");
+ else if (t->tv_nsec>1000000)
+ sprintf(str, "%u msec", (unsigned int) t->tv_nsec/1000000);
+ else if (t->tv_nsec>1000)
+ sprintf(str, "%u usec", (unsigned int) t->tv_nsec/1000);
+ else
+ sprintf(str, "%lu nsec", t->tv_nsec);
+
+ return 0;
+}
+
diff --git a/staging/mops_update.c b/staging/mops_update.c
new file mode 100644
index 0000000..4fa1b3a
--- /dev/null
+++ b/staging/mops_update.c
@@ -0,0 +1,422 @@
+/*
+ * Mausezahn - A fast versatile traffic generator
+ * Copyright (C) 2008-2010 Herbert Haas
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
+ *
+*/
+
+
+
+
+// -- TOC: --
+// int mops_update (stuct mops *mp)
+
+
+#include "mz.h"
+#include "mops.h"
+
+
+
+// This is the very basic MOPS update function. It simply updates the whole
+// MOPS frame specified by the pointer mp. If you only want to update specific
+// details then please see the other related specialized functions which are
+// more effcient.
+//
+int mops_update (struct mops *mp)
+{
+ int
+ i, // the standard loop variable; outside a loop fully undetermined!
+ t, // temp
+ fp=0; // frame pointer; always points to NEXT byte
+
+ char *x;
+ u_int8_t t8=0; // temp 8 bits
+ u_int16_t t16; // temp 16 bits
+
+ u_int8_t ip_pseudo_header[12];
+
+
+ // set MAC addresses?
+ if (mp->use_ETHER)
+ {
+ for (i=0; i<6; i++)
+ {
+ mp->frame[i] = mp->eth_dst[i];
+ mp->frame[i+6] = mp->eth_src[i];
+ }
+ fp = 12; // next byte
+ }
+
+
+
+ // VLAN tags?
+ if (mp->use_dot1Q)
+ {
+ t = mp->dot1Q_s;
+ for (i=0; i<t; i++)
+ {
+ mp->frame[fp++] = mp->dot1Q[i];
+ }
+ }
+
+
+
+ // Standard Ethernet or SNAP? (SNAP includes 802.3, see comments in mops.h)
+ if (mp->use_SNAP) // note that if use_SNAP is set, then the 'else if' below is ignored!
+ {
+ // 802.3 length
+ x = (char*) &mp->eth_len;
+ mp->frame[fp++] = *(x+1);
+ mp->frame[fp++] = *x;
+ // SNAP
+ t = mp->eth_snap_s;
+ for (i=0; i<t; i++)
+ {
+ mp->frame[fp++] = mp->eth_snap[i];
+ }
+ }
+ else if (mp->use_ETHER) // add TYPE field (note the ELSE IF here!)
+ {
+ // EtherType
+ x = (char*) &mp->eth_type;
+ mp->frame[fp++] = *(x+1);
+ mp->frame[fp++] = *x;
+ }
+ // alternatively the user specified whole raw frame
+ //
+ //
+ //
+ // MPLS?
+ if (mp->use_MPLS)
+ {
+ t = mp->mpls_s;
+ for (i=0; i<t; i++)
+ {
+ mp->frame[fp++] = mp->mpls[i];
+ }
+ }
+
+
+
+
+ // IP?
+ if (mp->use_IP)
+ {
+ mp->begin_IP = fp; // marks byte position of IP header within frame
+
+ // ----- 1st row: -----
+ //
+ mp->frame[fp] = (mp->ip_version << 4); // version
+ mp->frame[fp++] |= mp->ip_IHL; // IHL (user value - corrected at end of function if required)
+ mp->frame[fp++] = mp->ip_tos; // ToS
+ mops_hton2 ( &mp->ip_len, &mp->frame[fp] ); // Total Length (user value - corrected at end of function if required)
+ fp+=2;
+
+ // ----- 2nd row: -----
+ //
+ mops_hton2 ( &mp->ip_id, &mp->frame[fp] ); // Fragment Identification
+ fp+=2;
+
+ mops_hton2 ( &mp->ip_frag_offset, &mp->frame[fp] ); // Fragment Identification
+ // set flags:
+ if (mp->ip_flags_MF) mp->frame[fp] |= 0x20; else mp->frame[fp] &= 0xDF; // More Frag
+ if (mp->ip_flags_DF) mp->frame[fp] |= 0x40; else mp->frame[fp] &= 0xBF; // Don't Frag
+ if (mp->ip_flags_RS) mp->frame[fp] |= 0x80; else mp->frame[fp] &= 0x7F; // reserved
+ fp+=2;
+
+ // ----- 3rd row: -----
+
+ mp->frame[fp++] = mp->ip_ttl; // TTL
+ mp->frame[fp++] = mp->ip_proto; // Protocol
+ mops_hton2 ( &mp->ip_sum, &mp->frame[fp] ); // Checksum (user value - corrected at end of function if required)
+ fp+=2;
+
+ // ----- 4th and 5th row: -----
+ //
+ mops_hton4 ( &mp->ip_src, &mp->frame[fp] ); // SA
+ fp+=4;
+ mops_hton4 ( &mp->ip_dst, &mp->frame[fp] ); // DA
+ fp+=4;
+
+ // ----- options -----
+ //
+ if (mp->ip_option_used)
+ {
+ t = mp->ip_option_s;
+ for (i=0; i<t; i++)
+ {
+ mp->frame[fp++] = mp->ip_option[i];
+ }
+ }
+ }
+
+
+
+
+ // UDP?
+ if (mp->use_UDP)
+ {
+ mp->begin_UDP = fp; // marks byte position of UDP header within frame
+
+ mops_hton2 ( &mp->sp, &mp->frame[fp] ); // Source Port
+ fp+=2;
+ mops_hton2 ( &mp->dp, &mp->frame[fp] ); // Destination Port
+ fp+=2;
+ mops_hton2 ( &mp->udp_len, &mp->frame[fp] ); // Length (user value - corrected at end of function if required)
+ fp+=2;
+ mops_hton2 ( &mp->udp_sum, &mp->frame[fp] ); // CheckSum (user value - corrected at end of function if required)
+ fp+=2;
+ }
+
+
+
+ // TCP?
+ if (mp->use_TCP)
+ {
+ mp->begin_TCP = fp; // marks byte position of TCP header within frame
+
+ // ----- 1st row: -----
+ //
+ mops_hton2 ( &mp->sp, &mp->frame[fp] ); // Source Port
+ fp+=2;
+ mops_hton2 ( &mp->dp, &mp->frame[fp] ); // Destination Port
+ fp+=2;
+
+ // ----- 2nd and 3rd row: -----
+ //
+ mops_hton4 ( &mp->tcp_seq, &mp->frame[fp] ); // SQNR
+ fp+=4;
+ mops_hton4 ( &mp->tcp_ack, &mp->frame[fp] ); // ACKNR
+ fp+=4;
+
+ // ----- 4th row: -----
+ //
+// t16 = (mp->tcp_offset<<12) + (mp->tcp_res<<8); // Data Offset (HLEN) and 4 reserved bits
+ t16 = mp->tcp_res<<8; // Data Offset (HLEN) and 4 reserved bits
+ // (user value - corrected at end of function if required)
+ //
+ if (mp->tcp_ctrl_CWR) t16 |= 0x0080; else t16 &= 0xff7f; // URG Flag
+ if (mp->tcp_ctrl_ECE) t16 |= 0x0040; else t16 &= 0xffbf; // URG Flag
+ if (mp->tcp_ctrl_URG) t16 |= 0x0020; else t16 &= 0xffdf; // URG Flag
+ if (mp->tcp_ctrl_ACK) t16 |= 0x0010; else t16 &= 0xffef; // ACK Flag
+ if (mp->tcp_ctrl_PSH) t16 |= 0x0008; else t16 &= 0xfff7; // PSH Flag
+ if (mp->tcp_ctrl_RST) t16 |= 0x0004; else t16 &= 0xfffb; // RST Flag
+ if (mp->tcp_ctrl_SYN) t16 |= 0x0002; else t16 &= 0xfffd; // SYN Flag
+ if (mp->tcp_ctrl_FIN) t16 |= 0x0001; else t16 &= 0xfffe; // FIN Flag
+
+ mops_hton2 ( &t16, &mp->frame[fp] ); // copy HLEN, reserved bits, and flags to frame
+ fp+=2;
+
+
+ mops_hton2 ( &mp->tcp_win, &mp->frame[fp] ); // Window
+ fp+=2;
+
+ // ----- 5th row: -----
+ //
+ mops_hton2 ( &mp->tcp_sum, &mp->frame[fp] ); // Checksum
+ fp+=2;
+
+ mops_hton2 ( &mp->tcp_urg, &mp->frame[fp] ); // Urgent pointer
+ fp+=2;
+
+
+ // ----- options: -----
+ //
+ if (mp->tcp_option_used) {
+ t=mp->tcp_option_s;
+ for (i=0; i<t; i++) {
+ mp->frame[fp++] = mp->tcp_option[i];
+ }
+ }
+ }
+
+ // Eventually the payload:
+ if ((t = mp->msg_s))
+ {
+ mp->begin_MSG = fp;
+ for (i=0; i<t; i++) {
+ mp->frame[fp++] = mp->msg[i];
+ }
+ }
+
+ mp->frame_s = fp; // finally set the total frame length
+
+
+ //////////////////////////////////////////////////////////////
+ // Protect TX subsystem from too short or long packets //
+ // TODO: Consider to support mops-specific limits
+ // (which are itself limited by these global limits)
+ if (fp < min_frame_s)
+ mp->frame_s = min_frame_s;
+ else
+ if (fp > max_frame_s)
+ mp->frame_s = max_frame_s;
+ // //
+ //////////////////////////////////////////////////////////////
+
+
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ //
+ // Now update "derivable" fields if required:
+ //
+ // IP: ip_IHL, ip_len, ip_sum
+ // UDP: udp_len, udp_sum
+ // TCP: tcp_offset, tcp_sum
+ //
+ //
+ if (mp->use_IP)
+ {
+ fp = mp->begin_IP; // marks byte position of IP header within frame
+
+ /// HLEN
+ if (!mp->ip_IHL_false) { // user has NOT set an own header length
+ t8 = 5;
+ if (mp->ip_option_used) { // add option length if option exists
+ t8 += mp->ip_option_s/4;
+ }
+ t8 &= 0x0f; // set most significant 4 bits to zero because reserved for IP version
+ mp->frame[fp] |= t8;
+ }
+
+ /// LEN
+ if (!mp->ip_len_false) { // user has NOT set an own total length
+ t16 = mp->frame_s-fp;
+ mops_hton2 ( &t16, &mp->frame[fp+2] ); // Calculated total Length
+ }
+
+ /// SUM
+ if (!mp->ip_sum_false) { // user has NOT set an own header checksum
+ mp->frame[fp+10]=0x00;
+ mp->frame[fp+11]=0x00;
+ t16 = mops_sum16 (t8*4, &mp->frame[fp]);
+ mops_hton2 ( &t16, &mp->frame[fp+10] ); // Checksum (user value - corrected at end of function if required)
+ }
+ }
+
+
+ if (mp->use_UDP)
+ {
+ fp = mp->begin_UDP; // marks byte position of UDP header within frame
+
+ /// LEN
+ if (!mp->udp_len_false) { // user has NOT set an own total length
+ t16 = mp->frame_s-fp;
+ mops_hton2 ( &t16, &mp->frame[fp+4] ); // Calculated total Length
+ }
+
+ /// SUM
+ //
+ // The pseudo header conceptually prefixed to the UDP header contains the
+ // source address, the destination address, the protocol, and the UDP
+ // length. [RFC 768]
+ //
+ // 0 7 8 15 16 23 24 31
+ // +--------+--------+--------+--------+
+ // | source address |
+ // +--------+--------+--------+--------+
+ // | destination address |
+ // +--------+--------+--------+--------+
+ // | zero |protocol| UDP length |
+ // +--------+--------+--------+--------+
+ //
+ //
+ if (!mp->udp_sum_false) // user has NOT set an own checksum
+ {
+ // Create IP pseudoheader
+ memcpy(&ip_pseudo_header[0], &mp->frame[mp->begin_IP+12], 4); // copy SA to pseudoheader
+ memcpy(&ip_pseudo_header[4], &mp->frame[mp->begin_IP+16], 4); // copy DA to pseudoheader
+ ip_pseudo_header[8]=0x00;
+ ip_pseudo_header[9]=mp->ip_proto;
+ memcpy(&ip_pseudo_header[10], &mp->frame[fp+4], 2); // copy UDP length to pseudoheader
+
+ mp->frame[fp+6]=0x00; // set checksum to 0x0000
+ mp->frame[fp+7]=0x00;
+
+ t = 12+mp->frame_s-fp; // udp datagram length (including 12 byte pseudoheader)
+
+ // Pad one extra byte if length is odd, and append the
+ // pseudoheader at the end of mp->frame (only for checksum computation)
+ if (t%2)
+ {
+ t++;
+ mp->frame[mp->frame_s]=0x00;
+ memcpy(&mp->frame[mp->frame_s+1], ip_pseudo_header, 12);
+ }
+ else
+ memcpy(&mp->frame[mp->frame_s], ip_pseudo_header, 12);
+
+ t16 = mops_sum16 (t, &mp->frame[fp]);
+ mops_hton2 ( &t16, &mp->frame[fp+6] );
+ }
+ }
+
+
+
+
+ if (mp->use_TCP)
+ {
+ fp = mp->begin_TCP; // marks byte position of TCP header within frame
+
+ /// OFFSET (=HLEN)
+ if (!mp->tcp_offset_false) // user has NOT set an own header length
+ {
+ t8 = 5;
+ if (mp->tcp_option_used) {// add option length if option exists
+ t8 += mp->tcp_option_s/4;
+ }
+ t8 <<=4;
+ mp->frame[fp+12] |= t8;
+ }
+
+ // The TCP checksum is calculated similarily as the UDP checksum (see above).
+ // (The TCP length is needed instead of the UDP length of course, although
+ // the TCP length is not part of the header)
+ //
+ if (!mp->tcp_sum_false) {
+ // Create IP pseudoheader
+ memcpy(&ip_pseudo_header[0], &mp->frame[mp->begin_IP+12], 4); // copy SA to pseudoheader
+ memcpy(&ip_pseudo_header[4], &mp->frame[mp->begin_IP+16], 4); // copy DA to pseudoheader
+ ip_pseudo_header[8]=0x00;
+ ip_pseudo_header[9]=mp->ip_proto;
+ mp->tcp_len = mp->frame_s-fp; // TCP segment length
+ t16 = htons (mp->tcp_len);
+ memcpy(&ip_pseudo_header[10], &t16, 2); // copy TCP length to pseudoheader
+
+ mp->frame[fp+16]=0x00; // set checksum to 0x0000
+ mp->frame[fp+17]=0x00;
+
+ t = mp->tcp_len+12; // TCP segment length plus pseudoheader length
+
+ // Pad one extra byte if length is odd, and append the
+ // pseudoheader at the end of mp->frame (only for checksum computation)
+ if (t%2) {
+ t++;
+ mp->frame[mp->frame_s]=0x00;
+ memcpy(&mp->frame[mp->frame_s+1], ip_pseudo_header, 12);
+ }
+ else
+ memcpy(&mp->frame[mp->frame_s], ip_pseudo_header, 12);
+
+ t16 = mops_sum16 (t, &mp->frame[fp]);
+ mops_hton2 ( &t16, &mp->frame[fp+16] );
+ }
+ }
+
+
+ return 0;
+}
+
+
diff --git a/staging/mopsrx_arp.c b/staging/mopsrx_arp.c
new file mode 100644
index 0000000..0aac152
--- /dev/null
+++ b/staging/mopsrx_arp.c
@@ -0,0 +1,301 @@
+/*
+ * Mausezahn - A fast versatile traffic generator
+ * Copyright (C) 2008-2010 Herbert Haas
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
+ *
+*/
+
+#include "mz.h"
+#include "mops.h"
+#include "cli.h"
+
+// Starts an ARP RX thread for *every* device in the device_list.
+// (Except for the loopback interface)
+//
+// RETURN VALUE: 0 upon success,
+// 1 upon error.
+//
+int mops_rx_arp ()
+{
+ int i;
+
+ for (i=0; i<device_list_entries; i++) {
+ if (mz_strcmp(device_list[i].dev, "lo", 2)==0) continue; // omit loopback!
+ if (pthread_create( &(device_list[i].arprx_thread),
+ NULL,
+ rx_arp,
+ &device_list[i])) { // give thread a pointer to that device_list entry
+ printf("xxxxxxxxxx\n");
+ return 1; // Error creating thread
+ } else {
+ if (verbose) {
+ fprintf(stderr, " Started ARP monitor on device %s.\n",
+ device_list[i].dev);
+ }
+ }
+ }
+ return 0;
+}
+
+
+// Thread function to receive ARP responses for a given device.
+// Runs forever - until Mausezahn stops (see clean_up())
+//
+// Argument: pointer to device_struct!
+//
+//
+//
+void *rx_arp (void *arg)
+{
+ char errbuf[PCAP_ERRBUF_SIZE];
+ struct pcap *p_arp;
+ struct bpf_program filter;
+ char filter_str[] = "arp"; // We want to analyze both requests and responses!
+ struct device_struct *dev = (struct device_struct*) arg;
+
+ // FYI, possible filter string is also:
+ // "eth.dst==00:05:4e:51:01:b5 and arp and arp.opcode==2";
+
+ p_arp = pcap_open_live (dev->dev,
+ 100, // max num of bytes to read
+ 1, // 1 if promiscuous mode
+ PCAP_READ_TIMEOUT_MSEC, // read timeout 'until error' (-1 = indefinitely)
+ errbuf);
+
+ if (p_arp == NULL) {
+ fprintf(stderr," rx_arp: [ERROR] %s\n",errbuf);
+ return NULL; // TODO: Should return pointer to error message or something similar
+ }
+
+ dev->p_arp = p_arp; // also assign pointer to a global which is needed for clean_up
+
+ if ( pcap_compile(p_arp,
+ &filter, // the compiled version of the filter
+ filter_str, // text version of filter
+ 0, // 1 = optimize
+ 0) // netmask
+ == -1) {
+ fprintf(stderr," rx_arp: [ERROR] Error calling pcap_compile\n");
+ return NULL;
+ }
+
+ if ( pcap_setfilter(p_arp, &filter) == -1) {
+ fprintf(stderr," rx_arp: [ERROR] Error setting pcap filter\n");
+ pcap_perror(p_arp, " rx_arp: ");
+ return NULL;
+ }
+
+ if (pcap_setdirection(p_arp, PCAP_D_IN) == -1) {
+ pcap_perror(p_arp, " rx_arp: ");
+ return NULL;
+ }
+
+ again:
+ pcap_loop (p_arp,
+ 1, // number of packets to wait
+ got_arp_packet, // name of callback function
+ (u_char*) dev); // optional additional arguments for callback function
+ goto again;
+
+ pthread_exit(NULL); // destroy thread
+ return NULL;
+}
+
+
+void got_arp_packet (u_char *args,
+ const struct pcap_pkthdr *header, // statistics about the packet (see 'struct pcap_pkthdr')
+ const u_char *packet) // the bytestring sniffed
+{
+ const struct struct_ethernet *ethernet;
+ const struct struct_arp *arp;
+ int size_ethernet = sizeof(struct struct_ethernet);
+ struct device_struct *dev = (struct device_struct*) args;
+
+ u_int8_t
+ da[6], // eth da
+ sa[6], // eth sa
+ smac[6], // source hw address
+ sip[4], // source protocol address
+ tmac[6], // target hw address
+ tip[4]; // target protocol address
+ u_int16_t op; // operation
+ u_int32_t sec, nsec;
+ u_int8_t *x;
+
+ // These are the most important lines here:
+ ethernet = (struct struct_ethernet*)(packet);
+ arp = (struct struct_arp*)(packet+size_ethernet);
+ sec = (u_int32_t) header->ts.tv_sec;
+ nsec = (u_int32_t) ((header->ts.tv_usec) * 1000);
+
+ op = arp->arp_op; // note that we don't have network byte order anymore!
+ // tmact is:
+ // 100 instead of 00:01 (request)
+ // 200 instead of 00:02 (response)
+
+ memcpy((void*) da, (void*) ethernet->eth_da, 6);
+ memcpy((void*) sa, (void*) ethernet->eth_sa, 6);
+ memcpy((void*) smac, (void*) arp->arp_smac, 6);
+ memcpy((void*) sip, (void*) arp->arp_sip, 4);
+ memcpy((void*) tmac, (void*) arp->arp_tmac, 6);
+ memcpy((void*) tip, (void*) arp->arp_tip, 4);
+
+ // Only handle the packet if it is really an ARP response!
+ ////AND if it is not sent by THIS host! (not possible, we only scan inbound!)
+ x = (u_int8_t*) & op;
+ if (*(x+1) == 0x02) {
+ // ARP RESPONSE: Update ARP table
+ arptable_add(dev, sa, da, smac, sip, sec, nsec);
+ } else if (*(x+1) == 0x01) {
+ // ARP REQUEST: Detect poisoning attacks
+ arpwatch(dev, sa, da, smac, sip, tmac, tip, sec, nsec);
+ }
+
+
+
+
+ // ARP binding consists of: sip (IP) - smac (MAC)
+ //
+ // User alert, 2 possibilities:
+ //
+ // 1. Learned new binding: does smac belong to sip?
+ //
+ // 2. Alert: Mismatch of stored versus announced sip-to-smac binding
+ //
+ // In both cases user action: [Learn] [Ignore] [Attack] [Amok Attack]
+ // Countermeasures: Mausezahn him!
+ //
+ // ALSO correct ARP tables of other hosts, especially on the default gateway
+ // that is, send arp replies with true binding
+ //
+ // Finally: Create logging message
+
+}
+
+
+
+// Add new entry in device-specific ARP table
+// but first check if already existing or change.
+//
+// RETURN VALUE: 0 upon success
+// 1 upon error
+//
+int arptable_add(struct device_struct *dev,
+ u_int8_t *sa,
+ u_int8_t *da,
+ u_int8_t *smac,
+ u_int8_t *sip,
+ u_int32_t sec,
+ u_int32_t nsec)
+{
+ struct arp_table_struct *prev=NULL, *cur = dev->arp_table;
+ int i=0, alert=0;
+
+ // If SA and SMAC are different this might be a MITM !!!
+ if (compare_mac(smac, sa)) alert=1;
+
+ // Check if IP (sip) is already existing in arp table:
+ while (cur!=NULL) {
+ if (compare_ip(sip, cur->sip)==0) { // IP found!
+ timestamp_hms(cur->when);
+ if (da[0]==0xff) cur->bc_resp++;
+ else cur->uni_resp++;
+ if (compare_mac(smac, cur->smac)==0) {
+ // entry identical !
+ cur->sec=sec;
+ cur->nsec=nsec;
+ return 0;
+ } else {
+ // entry with other MAC address found !
+ if (cur->locked==0) {
+ cur->changed++;
+ memcpy((void*) cur->smac_prev, (void*) cur->smac, 6);
+ memcpy((void*) cur->smac, (void*) smac, 6);
+ cur->sec_prev=cur->sec;
+ cur->nsec_prev=cur->nsec;
+ cur->sec=sec;
+ cur->nsec=nsec;
+ if (alert) cur->flags|=0x02;
+ }
+ return 0;
+ }
+ }
+ prev = cur;
+ cur = cur->next;
+ i++;
+ }
+
+ // If we get here, then there was no entry for that IP yet!
+ // Create new arp_table entry:
+ cur = (struct arp_table_struct *) malloc(sizeof(struct arp_table_struct));
+ if (cur==NULL) return 1;
+
+ // Append element:
+ if (dev->arp_table==NULL) dev->arp_table = cur;
+ else prev->next = cur;
+
+ memcpy((void*) cur->sa, (void*) sa, 6);
+ memcpy((void*) cur->smac, (void*) smac, 6);
+ cur->smac_prev[0]=0x00;
+ cur->smac_prev[1]=0x00;
+ cur->smac_prev[2]=0x00;
+ cur->smac_prev[3]=0x00;
+ cur->smac_prev[4]=0x00;
+ cur->smac_prev[5]=0x00;
+ memcpy((void*) cur->sip, (void*) sip, 4);
+ if (da[0]==0xff) {
+ cur->bc_resp=1;
+ cur->uni_resp=0;
+ } else {
+ cur->bc_resp=0;
+ cur->uni_resp=1;
+ }
+ cur->changed=1;
+ cur->locked=0;
+ cur->dynamic=1;
+ cur->flags=0;
+ cur->sec=sec;
+ cur->nsec=nsec;
+ cur->sec_prev=0;
+ cur->nsec_prev=0;
+ cur->index=i+1; // I assume users prefer to count from 1.
+ timestamp_hms(cur->when);
+ if (alert) cur->flags|=0x02;
+ cur->next=NULL;
+ return 0;
+}
+
+
+
+// Validate ARP requests
+int arpwatch(struct device_struct *dev,
+ u_int8_t *sa,
+ u_int8_t *da,
+ u_int8_t *smac,
+ u_int8_t *sip,
+ u_int8_t *tmac,
+ u_int8_t *tip,
+ u_int32_t sec,
+ u_int32_t nsec)
+{
+ // Unicast requests are considered as anomaly
+
+ if ((da[0]&0x01)==0) { // broadcast bit NOT set?
+ fprintf(stderr, "NOTE: Non-broadcast ARP request from %02x:%02x:%02x:%02x:%02x:%02x\n",
+ sa[0], sa[1], sa[2], sa[3], sa[4], sa[5]);
+ }
+
+ return 0;
+}
+
diff --git a/staging/mz.h b/staging/mz.h
new file mode 100644
index 0000000..cad091f
--- /dev/null
+++ b/staging/mz.h
@@ -0,0 +1,931 @@
+/*
+ * Mausezahn - A fast versatile traffic generator
+ * Copyright (C) 2008-2010 Herbert Haas
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
+ *
+*/
+
+
+
+#ifndef __MAUSEZAHN__
+#define __MAUSEZAHN__
+
+#define _GNU_SOURCE
+#include <libnet.h>
+#include <pcap/pcap.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <limits.h>
+#include <sys/time.h>
+#include <time.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <stdarg.h>
+#include <math.h>
+
+extern int verbose_level;
+
+static inline void verbose_l1(const char *format, ...)
+{
+ va_list vl;
+
+ if (verbose_level < 1)
+ return;
+
+ va_start(vl, format);
+ vfprintf(stderr, format, vl);
+ va_end(vl);
+}
+
+static inline void verbose_l2(const char *format, ...)
+{
+ va_list vl;
+
+ if (verbose_level < 2)
+ return;
+
+ va_start(vl, format);
+ vfprintf(stderr, format, vl);
+ va_end(vl);
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//
+//
+#define MAUSEZAHN_VERSION "Mausezahn 0.40 - (C) 2007-2010 by Herbert Haas - http://www.perihel.at/sec/mz/"
+#define MAUSEZAHN_VERSION_SHORT "0.40"
+//
+//
+////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+// "Dies ist ein schrecklicher Ort."
+
+#define MZ_DEFAULT_CONFIG_PATH "/etc/mausezahn/" // see also mz_default_config_path below
+#define MZ_DEFAULT_LOG_PATH "/var/log/mausezahn/" // see also mz_default_log_path below
+
+#define SLEEP usleep // The sleep function to use. Consider 'nanosleep' in future.
+#define DEFAULT_DELAY 0
+#define PCAP_READ_TIMEOUT_MSEC 1 // The read timeout for pcap_open_live()
+#define MZ_MAX_DEVICES 10 // Max number of network devices supported
+#define MAX_PAYLOAD_SIZE 3*8192
+#define MAX_DNS_NAME 256
+#define MAX_8021Q_TAGS 16
+#define TIME_COUNT_MAX 10000 // the size of the timestamp arrays timeRX and timeTX upon creation
+#define TIME_COUNT 100 // the default used-size of the timestamp arrays timeRX and timeTX
+#define MAX_DATA_BLOCKS 1000 // how many data blocks of size TIME_COUNT-1 should be written per file
+#define MAXBYTES_TO_READ 1500 // how many bytes the pcap routine should read from net
+#define RCV_RTP_MAX_BAR_WIDTH 500 // max line-width printed in BAR mode (see rcv_rtp.c)
+
+#define ETH_SRC 1 // These are only some symbols used by some functions. (Don't touch)
+#define ETH_DST 2 // These are only some symbols used by some functions.
+#define SRC_PORT 1 // These are only some symbols used by some functions.
+#define DST_PORT 2 // These are only some symbols used by some functions.
+
+#define TEST fprintf(stderr, "HERE at line %i in file %s\n", __LINE__,__FILE__ ); fflush(stderr);
+
+
+// ----- PCAP-specific definitions: ---------------------
+#define IPADDRSIZE 46
+
+
+int MZ_SIZE_LONG_INT;
+
+char mz_default_config_path[256];
+char mz_default_log_path[256];
+
+
+struct arp_table_struct {
+ int index; // an entry index (1, 2, ...) for easier user access
+ u_int8_t sa[6]; // sent by this MAC SA
+ u_int8_t smac[6]; // announced MAC
+ u_int8_t smac_prev[6]; // previously announced MAC
+ u_int8_t sip[4]; // announced IP
+ unsigned long int uni_rq; // count unidirectional ARP requests for this IP
+ unsigned long int bc_resp; // count broadcast ARP responses for this IP
+ unsigned long int uni_resp; // count normal (unidir) ARP responses for this IP
+ unsigned long int changed; // count how often the MAC address has changed!
+ int locked; // 1=this entry cannot be overidden anymore
+ int dynamic; // 1=learned dynamically, 0=configured by user
+ int flags; // anomaly information (length anomaly: bit 0, sa!=smac: bit 1 , ...)
+ int gw; // 1=Default GW
+ char when[10]; // human readable timestamp (e. g. "11:42:53")
+ u_int32_t sec, nsec; // timestamp of last ARP response
+ u_int32_t sec_prev, nsec_prev; // timestamp of previous ARP response
+ //-----------------//
+ struct arp_table_struct *next;
+};
+
+// Device list
+struct device_struct
+{
+ char dev[16]; // Device name
+ int index; // Device index (assigned by OS)
+ int phy; // 1 if physical, 0 if not (e. g. loopback)
+ int mtu;
+ int cli; // if set to 1 then the CLI connection must terminate here
+ int mgmt_only; // if set to 1 then no data traffic is allowed through that interface
+ // ---- MAC addresses ----
+ u_int8_t mac[6]; // Real MAC address
+ u_int8_t mac_mops[6]; // MAC address to be used
+ // ---- IP related -----
+ char ip_str[IPADDRSIZE+1]; // Real IP address as string in dotted decimal notation
+ u_int8_t ip[4]; // Real IP address
+ u_int8_t net[4]; // Real network
+ u_int8_t mask[4]; // Real mask
+ u_int8_t ip_mops[4]; // IP address to be used
+ // ---- Default Gateway per interface:
+ u_int8_t mac_gw[6]; // MAC address of default gateway
+ u_int8_t ip_gw[4]; // IP address of default gateway
+ // ---- various device-specific handles ----
+ pthread_t arprx_thread;
+ struct pcap *p_arp; // pcap handle
+ struct arp_table_struct *arp_table; // dedicated ARP table
+ int ps; // packet socket
+} device_list[MZ_MAX_DEVICES];
+
+int device_list_entries;
+
+
+#pragma pack(1)
+struct struct_ethernet
+{
+ u_int8_t eth_da[6];
+ u_int8_t eth_sa[6];
+ u_int16_t eth_type;
+};
+
+struct struct_arp
+{
+ u_int16_t arp_hrd; // hardware address format
+ u_int16_t arp_pro; // protocol address format
+ u_int8_t arp_hln; // hardware address length
+ u_int8_t arp_pln; // protocol address length
+ u_int16_t arp_op; // ARP operation type
+ u_int8_t arp_smac[6]; // sender's hardware address
+ u_int8_t arp_sip[4]; // sender's protocol address
+ u_int8_t arp_tmac[6]; // target hardware address
+ u_int8_t arp_tip[4]; // target protocol address
+};
+
+
+
+//#pragma pack(1)
+struct struct_ip
+{
+ u_int8_t
+ hlen :4,
+ ver :4;
+ u_int8_t
+ tos;
+ u_int16_t
+ len;
+
+ u_int16_t
+ id,
+ offset; // flags and fragment offset field
+
+ u_int8_t
+ ttl,
+ proto;
+ u_int16_t
+ sum;
+
+ u_int8_t src[4];
+ u_int8_t dst[4];
+};
+
+//#pragma pack(1)
+struct struct_udp {
+ u_int16_t
+ sp,
+ dp,
+ len,
+ sum;
+};
+
+//#pragma pack(1)
+struct struct_rtp {
+ u_int8_t
+ byte1,
+ ptype;
+ u_int16_t
+ sqnr;
+ u_int32_t
+ timestamp, // official timestamp, created by codecs
+ ssrc;
+ // csrc, // only used by mixers
+ u_int16_t
+ ext_id,
+ ext_len;
+ u_int32_t
+ time_sec,
+ time_nsec,
+ time_sec2,
+ time_nsec2;
+};
+
+// ---------End of PCAP-specific definitions---------------
+
+
+
+
+// ************************************
+//
+// Global variables
+//
+// ************************************
+
+enum operating_modes
+{
+ BYTE_STREAM,
+ ARP,
+ BPDU,
+ IP,
+ ICMP,
+ ICMP6,
+ UDP,
+ TCP,
+ DNS,
+ CDP,
+ RTP,
+ RX_RTP,
+ SYSLOG,
+ LLDP
+} mode;
+
+
+int ipv6_mode;
+int quiet; // don't even print 'important standard short messages'
+int verbose; // report character
+int simulate; // if 1 then don't really send frames
+
+char path[256];
+char filename[256];
+FILE *fp, *fp2; // global multipurpose file pointer
+
+long double total_d;
+clock_t mz_start, mz_stop;
+
+enum rtp_display_mode {
+ BAR, NCURSES, TEXT
+} rtp_dm;
+
+
+int mz_rand;
+int bwidth;
+
+struct mz_timestamp {
+ u_int32_t sec;
+ u_int32_t nsec;
+};
+
+struct mz_timestamp
+ tv,
+ timeTX[TIME_COUNT_MAX],
+ timeRX[TIME_COUNT_MAX];
+
+int32_t
+ time0,
+ jitter_rfc,
+ jitter[TIME_COUNT_MAX];
+
+int
+ rtp_log,
+ time0_flag, // If set then time0 has valid data
+ sqnr0_flag;
+
+u_int8_t
+ mz_ssrc[4]; // holds RTP stream identifier for rcv_rtp()
+
+u_int16_t
+ sqnr_cur,
+ sqnr_last,
+ sqnr_next;
+
+u_int32_t
+ drop, // packet drop count
+ dis, // packet disorder count
+ gind, // a global index to run through deltaRX, deltaTX, and jitter
+ gind_max, // the amount of entries used in the (ugly oversized) arrays; per default set to TIME_COUNT
+ gtotal; // counts number of file write cycles (see "got_rtp_packet()")
+
+
+char rtp_filter_str[64];
+
+struct tx_struct
+{
+ // Management issues for TX
+ char device[16]; // every packet could be sent through a different device
+ int packet_mode; // 0 means use LIBNET_LINK_ADV, 1 means LIBNET_RAW4
+ unsigned int count; // 0 means infinite, 1 is default
+ unsigned int delay; // Delay in microseconds, 0 means no delay (default)
+ char arg_string[MAX_PAYLOAD_SIZE]; // Argument-string when -t is used
+
+ // Ethernet and 802.3 parameters
+ int eth_params_already_set; // if set to 1 then send_eth should only send the frame
+ u_int8_t eth_mac_own[6]; // Contains own interface MAC if needed by some modules
+ char eth_dst_txt[32]; // Text version of eth_dst (or keyword such as 'rand')
+ u_int8_t eth_dst[6];
+ int eth_dst_rand; // 1 if random
+ char eth_src_txt[32]; // Text version of eth_src (or keyword such as 'rand')
+ u_int8_t eth_src[6];
+ int eth_src_rand; // 1 if random
+ u_int16_t eth_type;
+ u_int16_t eth_len;
+ u_int8_t eth_payload[MAX_PAYLOAD_SIZE];
+ u_int32_t eth_payload_s;
+ unsigned int padding;
+
+ // CDP parameters
+ u_int8_t
+ cdp_version,
+ cdp_ttl,
+ cdp_payload[MAX_PAYLOAD_SIZE],
+ cdp_tlv_id[2048]; // The ID is the only required TLV
+ u_int16_t
+ cdp_sum;
+ u_int32_t
+ cdp_tlv_id_len,
+ cdp_payload_s;
+
+ // 802.1Q VLAN Tag
+ int dot1Q; // 1 if specified
+ char dot1Q_txt[32]; // contains 802.1p(CoS) and VLAN-ID ("5:130" or only VLAN "130")
+ u_int8_t dot1Q_CoS;
+ u_int16_t dot1Q_vlan;
+ u_int8_t dot1Q_header[256]; // Contains the complete 802.1Q/P headers (but NOT the Ethernet header!)
+ u_int8_t dot1Q_header_s;
+ int dot1Q_at_least_two_headers; // If '1' then we have at least QinQ (or more VLAN tags)
+
+ // ASCII PAYLOAD
+ int ascii; // 1 if specified
+ u_int8_t ascii_payload[MAX_PAYLOAD_SIZE];
+
+ // HEX PAYLOAD
+ u_int8_t hex_payload[MAX_PAYLOAD_SIZE];
+ u_int32_t hex_payload_s; // >0 if hex payload is specified
+
+ // MPLS Parameters
+ char mpls_txt[128]; // contains MPLS parameters (label, exp, S, TTL)
+ char mpls_verbose_string[1024]; // contains all labels for print_frame_details()
+ int mpls; // 1 if specified
+ u_int32_t mpls_label;
+ u_int8_t mpls_exp;
+ u_int8_t mpls_bos;
+ u_int8_t mpls_ttl;
+
+ // IP parameters
+ u_int32_t ip_src; // has always network byte order(!)
+ struct libnet_in6_addr ip6_src;
+ char ip_src_txt[256];
+ int ip_src_rand; // if set to 1 then SA should be random
+ u_int32_t ip_src_h; // mirror of ip_src (NOT network byte order => easy to count)
+ u_int32_t ip_src_start; // start of range (NOT network byte order => easy to count)
+ u_int32_t ip_src_stop; // stop of range (NOT network byte order => easy to count)
+ int ip_src_isrange; // if set to 1 then the start/stop values above are valid.
+ u_int32_t ip_dst; // has always network byte order(!)
+ struct libnet_in6_addr ip6_dst;
+ char ip_dst_txt[256];
+ u_int32_t ip_dst_h; // mirror of ip_dst (NOT network byte order => easy to count)
+ u_int32_t ip_dst_start; // start of range (NOT network byte order => easy to count)
+ u_int32_t ip_dst_stop; // stop of range (NOT network byte order => easy to count)
+ int ip_dst_isrange; // if set to 1 then the start/stop values above are valid.
+ u_int16_t
+ ip_len,
+ ip_id,
+ ip_frag, // Flags and Offset !!!
+ ip_sum;
+ u_int8_t
+ ip_tos,
+ ip_ttl,
+ ip6_rtype,
+ ip6_segs,
+ ip_proto;
+ u_int8_t
+ ip_option[1024],
+ ip_payload[MAX_PAYLOAD_SIZE];
+ u_int32_t
+ ip_flow,
+ ip6_id,
+ ip_option_s,
+ ip_payload_s;
+
+ // ICMP
+ char
+ icmp_verbose_txt[256]; // used for verbose messages in send.c
+ u_int8_t
+ icmp_type,
+ icmp_code;
+ u_int16_t icmp_ident; // ATTENTION: libnet.h already #defines 'icmp_id', 'icmp_sum', and 'icmp_num'
+ u_int16_t icmp_chksum; // therefore I needed a renaming here -- be careful in future...
+ u_int16_t icmp_sqnr; //
+ u_int32_t
+ icmp_gateway,
+ icmp_payload_s;
+ u_int8_t
+ icmp_payload[MAX_PAYLOAD_SIZE];
+
+ // General L4 parameters:
+ char *layer4;
+ u_int16_t
+ sp, dp,
+ sp_start, sp_stop,
+ dp_start, dp_stop;
+ int
+ sp_isrange, // if set to 1 then start/stop values above are valid
+ dp_isrange; // if set to 1 then start/stop values above are valid
+
+ // UDP parameters
+ u_int16_t
+ udp_len, // includes header size (8 bytes)
+ udp_sum;
+ u_int8_t
+ udp_payload[MAX_PAYLOAD_SIZE];
+ u_int32_t
+ udp_payload_s;
+
+ // TCP parameters
+ u_int32_t
+ tcp_seq,
+ tcp_seq_start,
+ tcp_seq_stop, // is always set! Usually seq_start = seq_stop (=no range)
+ tcp_seq_delta, // Also used instead of an 'isrange' variable
+ tcp_ack;
+ u_int8_t
+ tcp_offset,
+ tcp_control;
+ u_int16_t
+ tcp_win,
+ tcp_sum,
+ tcp_urg,
+ tcp_len; // only needed by libnet and must include header size
+ u_int8_t
+ tcp_payload[MAX_PAYLOAD_SIZE];
+ u_int32_t
+ tcp_sum_part,
+ tcp_payload_s;
+
+ // RTP parameters
+ u_int32_t
+ rtp_sqnr,
+ rtp_stmp;
+
+} tx; // NOTE: tx elements are considered as default values for MOPS
+
+
+
+
+
+u_int8_t gbuf[MAX_PAYLOAD_SIZE]; // This is only a generic global buffer to handover data more easily
+u_int32_t gbuf_s; //
+
+
+// ************************************
+//
+// Prototypes: General Tools
+//
+// ************************************
+
+void clean_up(int sig);
+int getopts(int argc, char *argv[]);
+int getarg(char *str, char *arg_name, char *arg_value);
+unsigned long int str2int(char *str); // converts "65535" to 65535
+unsigned long long int str2lint(char *str); // same but allows 64-bit integers
+unsigned long int xstr2int(char *str); // converts "ffff" to 65535
+unsigned long long int xstr2lint(char *str); // same but allows 64-bit integers
+int mz_strisbinary(char *str);
+int mz_strisnum(char *str);
+int mz_strishex(char *str);
+int str2bin8 (char *str);
+long int str2bin16 (char *str);
+int char2bits (char c, char *str);
+int mz_strcmp(char* usr, char* str, int min);
+int mz_tok(char * str, char * delim, int anz, ...);
+int delay_parse (struct timespec *t, char *a, char *b);
+int reset();
+
+// ************************************
+//
+// Prototypes: Layer1
+//
+// ************************************
+
+int send_eth(void);
+libnet_ptag_t create_eth_frame (libnet_t *l, libnet_ptag_t t3, libnet_ptag_t t4);
+
+// ************************************
+//
+// Prototypes: Layer 2
+//
+// ************************************
+
+int send_arp (void);
+int send_bpdu (void);
+int send_cdp (void);
+
+// ************************************
+//
+// Prototypes: Layer 3
+//
+// ************************************
+
+
+libnet_t* get_link_context(void);
+libnet_ptag_t create_ip_packet (libnet_t *l);
+libnet_ptag_t create_ip6_packet (libnet_t *l);
+int send_frame (libnet_t *l, libnet_ptag_t t3, libnet_ptag_t t4);
+
+
+
+// ************************************
+//
+// Prototypes: Layer 4
+//
+// ************************************
+libnet_ptag_t create_udp_packet (libnet_t *l);
+libnet_ptag_t create_icmp_packet (libnet_t *l);
+libnet_ptag_t create_icmp6_packet (libnet_t *l);
+libnet_ptag_t create_tcp_packet (libnet_t *l);
+
+
+// ************************************
+//
+// Prototypes: Layer 7
+//
+// ************************************
+int create_dns_packet (void);
+int create_rtp_packet(void);
+int create_syslog_packet(void);
+
+// ************************************
+//
+// Prototypes: Helper functions for
+// byte manipulation,
+// address conversion,
+// etc
+//
+// ************************************
+
+// Converts MAC address specified in str into u_int8_t array
+// Usage: str2hex_mac ( "00:01:02:aa:ff:ee", src_addr )
+int str2hex_mac (char* str, u_int8_t *addr);
+
+// Converts ascii hex values (string) into integer array, similarly as above but for any size.
+// Example: "1a 00:00-2f" => {26, 0, 0, 47}
+// Note: apply any improvements here and prefer this function in future!
+// Return value: Number of converted elements (=length of array)
+int str2hex (char* str, u_int8_t *hp, int n);
+
+// Converts ascii numbers (string) into integer array
+// Every byte can be specified as integers {0..255}
+// For example "192.16.1.1" will be converted to {C0, 10, 01, 01}
+int num2hex(char* str, u_int8_t *hp);
+
+// Convert array of integers into string of hex. Useful for verification messages.
+// Example: {0,1,10} => "00-01-0A"
+// Usage: bs2str ( src_mac, src_mac_txt, 6 )
+int bs2str (u_int8_t *bs, char* str, int len);
+
+// Extract contiguous sequence of bytes from an array. First element has index 1 !!!
+// Usage: getbytes (bs, da, 1, 6);
+int getbytes(u_int8_t *source, u_int8_t *target, int from, int to);
+
+// For any IP address given in 'dotted decimal' returns an unsigned 32-bit integer.
+// Example: "192.168.0.1" => 3232235521
+// Note: Result is in LITTLE ENDIAN but usually with IP you need BIG ENDIAN, see next.
+u_int32_t str2ip32 (char* str);
+
+// For any IP address given in 'dotted decimal' into an unsigned 32-bit integer
+// This version does the same as str2ip32() but in BIG ENDIAN.
+// Note: With netlib you need this one, not the previous function.
+u_int32_t str2ip32_rev (char* str);
+
+// Converts a 2-byte value (e. g. a EtherType field)
+// into a nice string using hex notation.
+// Useful for verification messages.
+// Example: type2str (tx.eth_type, msg) may result in msg="08:00"
+// Return value: how many hex digits have been found.
+int type2str(u_int16_t type, char *str);
+
+
+// Parses string 'arg' for an IP range and finds start and stop IP addresses.
+// Return value: 0 upon success, 1 upon failure.
+//
+// NOTE: The results are written in the following variables:
+//
+// (u_int32_t) tx.ip_dst_start ... contains start value
+// (u_int32_t) tx.ip_dst_stop ... contains stop value
+// int tx.ip_dst_isrange ... set to 1 if above values valid
+//
+// The other function does the same for the source address!
+//
+// Possible range specifications:
+//
+// 1) 192.168.0.0-192.168.0.12
+// 2) 10.2.11.0-10.55.13.2
+// 3) 172.18.96.0/19
+//
+// That is:
+//
+// FIRST detect a range by scanning for the "-" OR "/" chars
+// THEN determine start and stop value and store them as normal unsigned integers
+//
+int get_ip_range_dst (char *arg);
+int get_ip_range_src (char *arg);
+
+// Sets a random SA for a given IP packet.
+// Return value: 0 upon success, 1 upon failure
+//
+int set_rand_SA (libnet_t *l, libnet_ptag_t t3);
+
+// Scans tx.eth_dst_txt or tx.eth_src_txt and sets the corresponding
+// MAC addresses (tx.eth_dst or tx.eth_src) accordingly.
+// Argument: What string should be checked, ETH_SRC or ETH_DST.
+// Return value:
+// 0 when a MAC address has been set or
+// 1 upon failure.
+// Currently eth_src|dst_txt can be:
+// 'rand', 'own', 'bc'|'bcast', 'stp', 'pvst',
+// or a real mac address.
+//
+int check_eth_mac_txt(int src_or_dst);
+
+// Scans argument for a port number or range
+// and sets the corresponding values in the
+// tx struct.
+//
+// Arguments: sp_or_dp is either SRC_PORT or DST_PORT
+// Return value: 0 on success, 1 upon failure
+//
+int get_port_range (int sp_or_dp, char *arg);
+
+// Return a 4-byte unsigned int random number
+u_int32_t mz_rand32 (void);
+
+// Scans argument for TCP flags and sets
+// tx.tcp_control accordingly.
+//
+// Valid keywords are: fin, syn, rst, psh, ack, urg, ecn, cwr
+// Valid delimiters are: | or + or -
+// Return value: 0 on success, 1 upon failure
+//
+int get_tcp_flags (char* flags);
+
+// Scans string 'params' for MPLS parameters
+// and sets tx.mpls_* accordingly.
+//
+// CLI Syntax Examples:
+//
+// -M help .... shows syntax
+//
+// -M 800 .... label=800
+// -M 800:S .... label=800 and BOS flag set
+// -M 800:S:64 .... label=800, BOS, TTL=64
+// -M 800:64:S .... same
+// -M 64:77 .... label=64, TTL=77
+// -M 64:800 .... INVALID
+// -M 800:64 .... label=800, TTL=64
+// -M 800:3:S:64 .... additionall the experimental bits are set (all fields required!)
+//
+// Note: S = BOS(1), s = NOT-BOS(0)
+//
+// Valid delimiters: :-.,+
+// Return value: 0 on success, 1 upon failure
+int get_mpls_params(char *params);
+
+// Parses str for occurence of character or sequence ch.
+// Returns number of occurences
+int exists(char* str, char* ch);
+
+
+// Applies another random Ethernet source address to a given Ethernet-PTAG.
+// (The calling function should check 'tx.eth_src_rand' whether the SA
+// should be randomized.)
+int update_Eth_SA(libnet_t *l, libnet_ptag_t t);
+
+
+// Update timestamp and sequence number in the RTP header.
+// The actual RTP message is stored in tx.udp_payload.
+int update_RTP(libnet_t *l, libnet_ptag_t t);
+
+
+// Applies another SOURCE IP address,
+// - either a random one (tx.ip_src_rand==1)
+// - or from a specified range (tx.ip_src_isrange==1)
+// to a given IP-PTAG.
+//
+// Note: tx.ip_src MUST be already initialized with tx.ip_src_start.
+// This is done by 'get_ip_range_src()' in tools.c.
+//
+// RETURNS '1' if tx.ip_src restarts
+int update_IP_SA (libnet_t *l, libnet_ptag_t t);
+
+
+// Applies another DESTINATION IP address from a specified range (tx.ip_dst_isrange==1)
+// to a given IP-PTAG.
+//
+// Note: tx.ip_dst MUST be already initialized with tx.ip_dst_start.
+// This is done by 'get_ip_range_dst()' in tools.c.
+//
+// RETURN VALUE: '1' if tx.ip_dst restarts
+int update_IP_DA(libnet_t *l, libnet_ptag_t t);
+
+
+// Applies another DESTINATION PORT from a specified range to a given UDP- or TCP-PTAG.
+//
+// Note: tx.dp MUST be already initialized with tx.dp_start
+// This is done by 'get_port_range()' in tools.c.
+//
+// RETURN VALUE: '1' if tx.dp restarts
+int update_DPORT(libnet_t *l, libnet_ptag_t t);
+
+
+// Applies another SOURCE PORT from a specified range to a given UDP- or TCP-PTAG.
+//
+// Note: tx.sp MUST be already initialized with tx.sp_start
+// This is done by 'get_port_range()' in tools.c.
+//
+// RETURN VALUE: '1' if tx.sp restarts
+int update_SPORT(libnet_t *l, libnet_ptag_t t);
+
+
+// Applies another TCP SQNR from a specified range to a given TCP-PTAG
+//
+// RETURN VALUE: '1' if tx.txp_seq restarts
+//
+int update_TCP_SQNR(libnet_t *l, libnet_ptag_t t);
+
+int update_ISUM(libnet_t *l, libnet_ptag_t t);
+int update_USUM(libnet_t *l, libnet_ptag_t t);
+int update_TSUM(libnet_t *l, libnet_ptag_t t);
+
+//
+//
+int print_frame_details(void);
+
+
+// Calculates the number of frames to be sent.
+// Should be used as standard output except the
+// 'quiet' option (-q) has been specified.
+int complexity(void);
+
+
+// Purpose: Calculate time deltas of two timestamps stored in struct timeval.
+// Subtract the "struct timeval" values X and Y, storing the result in RESULT.
+// Return 1 if the difference is negative, otherwise 0.
+int timestamp_subtract (struct mz_timestamp *x,
+ struct mz_timestamp *y,
+ struct mz_timestamp *result);
+
+void timestamp_add (struct mz_timestamp *x,
+ struct mz_timestamp *y,
+ struct mz_timestamp *result);
+
+// Returns a human readable timestamp in the string result.
+// Optionally a prefix can be specified, for example if the
+// timestamp is part of a filename.
+//
+// Example:
+// char myTimeStamp[128];
+//
+// timestamp_human(myTimeStamp, NULL);
+//
+// => "20080718_155521"
+//
+// /* or with prefix */
+//
+// timestamp_human(myTimeStamp, "MZ_RTP_jitter_");
+//
+// => MZ_RTP_jitter_20080718_155521
+//
+int timestamp_human(char* result, const char* prefix);
+
+// Returns a human readable timestamp in the string result.
+// Optionally a prefix can be specified, for example if the
+// timestamp is part of a filename.
+//
+// Example:
+// char myTimeStamp[8];
+//
+// timestamp_hms (myTimeStamp);
+//
+// => "15:55:21"
+int timestamp_hms(char* result);
+
+// Initialize the rcv_rtp process: Read user parameters and initialize globals
+int rcv_rtp_init(void);
+
+// Defines the pcap handler and the callback function
+int rcv_rtp(void);
+
+// Print current RFC-Jitter on screen
+void print_jitterbar (long int j, unsigned int d);
+
+// Compares two 4-byte variables byte by byte
+// returns 0 if identical, 1 if different
+int compare4B (u_int8_t *ip1, u_int8_t *ip2);
+
+// PURPOSE: Find usable network devices
+//
+// NOTE:
+//
+// 1. Ignores devices without IP address
+// 2. Ignores loopback (etc)
+//
+// RETURN VALUES:
+//
+// 0 if usable device found (device_list[] and tx.device set)
+// 1 if no usable device found
+//
+int lookupdev(void);
+
+
+// For a given device name, find out the following parameters:
+//
+// - MTU
+// - Network
+// - Mask
+// - Default GW (IP)
+//
+int get_dev_params (char *name);
+
+// Handler function to do something when RTP messages are received
+void got_rtp_packet(u_char *args,
+ const struct pcap_pkthdr *header, // statistics about the packet (see 'struct pcap_pkthdr')
+ const u_char *packet); // the bytestring sniffed
+
+
+// Check if current system supports the nanosecond timer functions.
+// Additionally, measure the precision.
+// This function should be called upon program start.
+//
+int check_timer(void);
+
+// This is the replacement for gettimeofday() which would result in 'jumps' if
+// the system clock is adjusted (e. g. via a NTP process) and finally the jitter
+// measurement would include wrong datapoints.
+//
+// Furthermore the function below utilizes the newer hi-res nanosecond timers.
+void getcurtime (struct mz_timestamp *t);
+
+// Only print out the help text for the 02.1Q option
+void print_dot1Q_help(void);
+
+// Determines ip and mac address of specified interface 'ifname'
+// Caller must provide an unsigned char ip[4], mac[6]
+//
+int get_if_addr (char *ifname, unsigned char *ip, unsigned char *mac);
+
+// Takes filename and prepends valid configuration/logging directory
+// NOTE: filename is overwritten and must be big enough to hold full path!
+int getfullpath_cfg (char *filename);
+int getfullpath_log (char *filename);
+
+// A safer replacement for strncpy which ensures \0-termination
+char * mz_strncpy(char *dest, const char *src, size_t n);
+
+// Helper function to count the number of arguments
+// in the Mausezahn argument string (comma separated args)
+// RETURN VALUE: Number of arguments
+int number_of_args (char *str);
+
+int arptable_add(struct device_struct *dev,
+ u_int8_t *sa,
+ u_int8_t *da,
+ u_int8_t *smac,
+ u_int8_t *sip,
+ u_int32_t sec,
+ u_int32_t nsec);
+
+// Validate ARP requests
+int arpwatch(struct device_struct *dev,
+ u_int8_t *sa,
+ u_int8_t *da,
+ u_int8_t *smac,
+ u_int8_t *sip,
+ u_int8_t *tmac,
+ u_int8_t *tip,
+ u_int32_t sec,
+ u_int32_t nsec);
+
+
+#endif
diff --git a/staging/parse_xml.c b/staging/parse_xml.c
new file mode 100644
index 0000000..2189b83
--- /dev/null
+++ b/staging/parse_xml.c
@@ -0,0 +1,568 @@
+/*
+ * Mausezahn - A fast versatile traffic generator
+ * Copyright (C) 2008-2010 Herbert Haas
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
+ *
+*/
+
+
+#include "mz.h"
+#include "mops.h"
+#include "cli.h"
+
+
+
+// Returns integer number for given tag string
+// For example xml_tag2int("field") => xml_field == 1
+//
+// Returns -1 when tag not known
+int xml_tag2int (char *t)
+{
+ if (!strncasecmp(t, "protocol", XML_MAX_TAG_LEN))
+ return xml_protocol;
+
+ if (!strncasecmp(t, "field", XML_MAX_TAG_LEN))
+ return xml_field;
+
+ if (!strncasecmp(t, "name", XML_MAX_TAG_LEN))
+ return xml_name;
+
+ if (!strncasecmp(t, "desc", XML_MAX_TAG_LEN))
+ return xml_desc;
+
+ if (!strncasecmp(t, "requires", XML_MAX_TAG_LEN))
+ return xml_requires;
+
+ if (!strncasecmp(t, "conflicts", XML_MAX_TAG_LEN))
+ return xml_conflicts;
+
+ if (!strncasecmp(t, "payloadtype", XML_MAX_TAG_LEN))
+ return xml_payloadtype;
+
+ if (!strncasecmp(t, "payload", XML_MAX_TAG_LEN))
+ return xml_payload;
+
+ if (!strncasecmp(t, "payloadhex", XML_MAX_TAG_LEN))
+ return xml_payloadhex;
+
+ if (!strncasecmp(t, "index", XML_MAX_TAG_LEN))
+ return xml_index;
+
+ if (!strncasecmp(t, "longdesc", XML_MAX_TAG_LEN))
+ return xml_longdesc;
+
+ if (!strncasecmp(t, "type", XML_MAX_TAG_LEN))
+ return xml_type;
+
+ if (!strncasecmp(t, "constant", XML_MAX_TAG_LEN))
+ return xml_constant;
+
+ if (!strncasecmp(t, "value", XML_MAX_TAG_LEN))
+ return xml_value;
+
+ if (!strncasecmp(t, "valname", XML_MAX_TAG_LEN))
+ return xml_valname;
+
+ if (!strncasecmp(t, "min", XML_MAX_TAG_LEN))
+ return xml_min;
+
+ if (!strncasecmp(t, "max", XML_MAX_TAG_LEN))
+ return xml_max;
+
+ if (!strncasecmp(t, "tlvt", XML_MAX_TAG_LEN))
+ return xml_tlvt;
+
+ if (!strncasecmp(t, "tlvl", XML_MAX_TAG_LEN))
+ return xml_tlvl;
+
+ if (!strncasecmp(t, "lshift", XML_MAX_TAG_LEN))
+ return xml_lshift;
+
+ return -1;
+}
+
+
+// For a given pair of tag t and parent p check
+// if t is really an allowed child of p.
+// RETURN VALUE: 0 if correct, -1 otherwise
+//
+int xml_check_parent(int t, int p)
+{
+ // For given tag t specify allowed parent p
+ switch (t) {
+
+ // no parent allowed
+ case xml_protocol:
+ if (p==-1) return 0;
+ break;
+
+ // has protocol as parent
+ case xml_field:
+ case xml_requires:
+ case xml_conflicts:
+ case xml_payloadtype:
+ case xml_payload:
+ case xml_payloadhex:
+ if (p==xml_protocol) return 0;
+ break;
+
+ // has field OR protocol as parent
+ case xml_name:
+ case xml_desc:
+ if ((p==xml_protocol)||(p==xml_field)) return 0;
+ break;
+
+ // has field as parent
+ case xml_longdesc:
+ case xml_type:
+ case xml_constant:
+ case xml_valname:
+ case xml_value:
+ case xml_min:
+ case xml_max:
+ case xml_index:
+ case xml_lshift:
+ case xml_tlvt:
+ case xml_tlvl:
+ if (p==xml_field) return 0;
+
+ }
+ return -1;
+}
+
+
+// Parse a single protocol definition.
+// The string 'p' must start with '<protocol>' and end with </protocol>
+//
+// RETURN VALUE: 0 upon success, >0 otherwise.
+//
+int parse_protocol (char *p)
+{
+ int i;
+ char p_clone[AUTOMOPS_MAX_FILE_SIZE+1];
+ struct automops *new_amp;
+
+ // Make a local copy of the protocol definition
+ strncpy(p_clone, p, AUTOMOPS_MAX_FILE_SIZE);
+ p_clone[AUTOMOPS_MAX_FILE_SIZE]='\0';
+
+ // Check if XML form is correct.
+ // I thought that this check should be done separately (and not during
+ // the xml_readin() function) for safety reasons. If read-in plus
+ // validation would be combined, we would have more to clean-up at in
+ // case the XML data is corrupt.
+ i = xml_canonic (p_clone);
+
+ // If incorrect, tell where error is:
+ if ((!quiet) && (i)) {
+ p_clone[i+1]='\0';
+ fprintf(stderr, "(EE) Mausezahn automops xml parse error:\n"
+ "========================================\n"
+ "%s <<ERROR>>\n", p_clone);
+ fprintf(stderr, "(EE) Error occured at character number %i\n", i);
+ fprintf(stderr," --- (printed all valid data until error position) ---\n");
+ }
+
+ if (verbose) {
+ fprintf(stderr, "...XML verification finished.\n");
+ }
+
+ // XML is correct, now create automops entry
+
+ if (i==0) {
+ strncpy(p_clone, p, AUTOMOPS_MAX_FILE_SIZE);
+ p_clone[AUTOMOPS_MAX_FILE_SIZE]='\0';
+ new_amp = automops_alloc_protocol(amp_head);
+ i = xml_readin(new_amp, p_clone);
+
+ if ((!quiet) && (i)) {
+ if (verbose) {
+ p_clone[i+1]='\0';
+ fprintf(stderr, "(EE) Invalid XML data at position %i: %s <<ERROR>>\n",
+ i, p_clone);
+ fprintf(stderr," --- (printed all valid data until error position) ---\n");
+ }
+ automops_delete_protocol(new_amp);
+ }
+ }
+ return i;
+}
+
+
+
+// Scans p until the next tag is found and stores
+// tag name in t which must be a string of size
+// XML_STRLEN (at least).
+//
+// Returns
+// >0 if opening tag is found
+// 0 if no tag is found or other problem
+// <0 if closing tag is found
+//
+// If any tag is found the absolut return value
+// indicates the position AFTER the tag, e. g.
+// ...<tag>... or ...</tag>...
+// ^here ^here
+//
+// Upon problem, the errorness char number is
+// stored as string within t along with the
+// error reason as string.
+//
+int xml_getnext_tag (char *p, char *t)
+{
+ int i=0,j=0,k=0,
+ sign=1,
+ len;
+
+ // are there non-white characters left?
+ len = strnlen(p, AUTOMOPS_MAX_FILE_SIZE);
+ for (i=0; i<len; i++) if (!isspace(p[i])) j=1; // flag for first non-space character found
+ if (!j) { // no more characters found
+ t[0]=0x00;
+ return 0;
+ }
+
+ // basic length checks
+ i=0; j=0;
+ if ((len<3)||(len==AUTOMOPS_MAX_FILE_SIZE)) { // 3 is minimum tag length
+ snprintf(t, XML_STRLEN, "invalid length (%u)",len);
+ return 0;
+ }
+
+
+ // find first opening ('<') bracket
+ do {
+ if (p[i]=='<') break;
+ i++;
+ } while (i<len);
+
+ // tag too close to end
+ if (i>(len-3)) {
+ snprintf(t, XML_STRLEN, "%4i - no end", i);
+ return 0; // no tag found (smallest tag is '<x>')
+ }
+
+ j=++i;
+
+ // closing tag?
+ if (p[i]=='/') {
+ i++;
+ j++;
+ sign=-1;
+ }
+
+ // find closing bracket
+ // and get tag name
+ do {
+ if (p[i]=='>') {
+ k=i; // =found
+ break;
+ }
+ i++;
+ if (i==len) {
+ snprintf(t, XML_STRLEN, "%4i - no end?", i);
+ return 0;
+ }
+ } while (i<(j+XML_MAX_TAG_LEN+1));
+
+ // closing '>' really found?
+ if (!k) {
+ sprintf(t, "%4i - closing bracket missing", i);
+ return 0;
+ }
+
+ // now the tag name is from p[j]..p[k-1]
+
+ memcpy((void*) t, (void*) &p[j], k-j);
+ t[k-j]='\0';
+
+ return sign*(k+1);
+}
+
+
+// Copies data between opening and closing XML tags
+// into 't' and returns the length of the data in bytes
+// or zero if nothing found
+// or -1 if protocol or data length is too long
+// Note: Assumes that *p points to first byte after opening tag!
+int xml_get_data (char *p, char *t)
+{
+ int i=0, len;
+
+ // basic length checks
+ len = strnlen(p, AUTOMOPS_MAX_FILE_SIZE);
+ if (len==0) return 0;
+
+ if (len>AUTOMOPS_MAX_FILE_SIZE) {
+ snprintf(t, XML_STRLEN, "invalid length (%u)",len);
+ return -1;
+ }
+
+ // find closing tag
+ // i. e. next opening ('<') bracket
+ do {
+ if (p[i]=='<') break;
+ i++;
+ } while (i<len);
+
+ // Set limit on data length
+ if (i>1500) return -1; // TODO: consider more reasonable limit
+
+ // copy data
+ memcpy((void*) t, (void*) &p[0], i);
+ t[i]='\0';
+ return i;
+}
+
+
+
+// Make some simple checks whether XML data correct
+// Currently only checks if
+// - every opening tag has an ending tag (only via verbose now)
+// - tags are properly nested (only 1st order tests now)
+//
+// RETURN VALUE: 0 upon success
+// or position of mistake
+//
+int xml_canonic (char *p)
+{
+ int i=0, l, dlen=0, plen, xntag=-1;
+ char t[XML_STRLEN];
+ char d[1500];
+
+ struct xnstack stack, *s;
+
+ s=&stack;
+ xnstack_init(s);
+
+ if (verbose==2) {
+ fprintf(stderr, "Parsing {%s}\n\n", p);
+ }
+
+ plen = strnlen(p, AUTOMOPS_MAX_FILE_SIZE);
+
+ do {
+ l = xml_getnext_tag (p, t); // Now t contains next tag name and l tells whether open or closing
+ if (l==0) {
+ if (t[0]==0x00) // no more tag found
+ return 0;
+ else { // general failure
+ fprintf(stderr, "%s\n", t);
+ return i;
+ }
+
+ }
+ i += abs(l);
+ if (verbose==2) {
+ fprintf(stderr, "%4i %4i stack=%i %s%s>\n",i,l,xnstack_size(s),
+ (l>0) ? "<" : "</", t);
+ }
+ if (i>=plen) { // break condition (regular, not an error!)
+ i=plen-1;
+ }
+ p+=abs(l); // now p points to first byte after tag
+
+ if (xml_tag2int(t)<0) {
+ fprintf(stderr, "mz/xml_canonic: UNKNOWN TAG at position %i\n", i);
+ return i;
+ }
+
+ // Closing tag found: does it match last opening tag?
+ if (l<0) {
+ if (xml_tag2int(t)!=xnstack_pop(s)) {
+ if (verbose) {
+ fprintf(stderr, "mz/xml_canonic: Incoherent nesting at position %i\n", i);
+ }
+ return i;
+ }
+ }
+
+ // Opening tag found: store it in last_tag!
+ if (l>0) {
+ xntag=xml_tag2int(t);
+ // Check if this tag has proper parent
+ if (xml_check_parent(xntag, xnstack_get_top(s))) {
+ fprintf(stderr, "mz/xml_canonic: Wrong parent tag\n");
+ return i;
+ }
+ if (xnstack_push(s, xntag)==-1) {
+ if (verbose) {
+ fprintf(stderr, "mz/xml_canonic: max nesting depth exceeded\n");
+ }
+ return i;
+ }
+ // also print data:
+ dlen = xml_get_data (p, d);
+ if (dlen==-1) {
+ if (verbose) {
+ fprintf(stderr, "mz/xml_canonic: %s\n", d);
+ }
+ return i;
+ }
+ if ((dlen>0) && (verbose==2)) {
+ fprintf(stderr, " %s\n", d); // the data
+ }
+
+ }
+
+ if (i==plen-1) return 0;
+ } while (l!=0);
+
+ if (xnstack_size(s)!=0) {
+ fprintf(stderr,"mz/xml_canonic: number of opening and closing tags does not match!\n");
+ return i;
+ }
+
+ return 0;
+}
+
+
+
+// Copy data elements of *p into struct *amp
+// =============================================================
+// NOTE: THE XML STRUCTURE MUST BE CORRECT !!!
+// NO XML CHECKS ARE DONE TO KEEP THIS FUNCTION SMALL !!!
+// THEREFORE ALWAYS RUN xml_canonic() FIRST !!!
+// =============================================================
+//
+// However, this function checks if the *data* is valid.
+//
+// RETURN VALUE: 0 upon success,
+// otherwise character position of wrong data
+//
+int xml_readin (struct automops *amp, char *p)
+{
+ int i=0, l, dlen=0, plen, xntag=-1, parent=-1, err=0;
+ char t[XML_STRLEN];
+ char d[1500], errmsg[64];
+
+ struct xnstack stack, *s;
+ struct fields *f=NULL;
+
+ s=&stack;
+ xnstack_init(s);
+
+ plen = strnlen(p, AUTOMOPS_MAX_FILE_SIZE);
+
+ do {
+ l = xml_getnext_tag (p, t); // Now t contains next tag name and l tells whether open or closing
+ if (l==0) {
+ if (t[0]==0x00) return 0;
+ else
+ return i;
+ }
+ i += abs(l);
+ if (i>=plen) { // break condition (regular, not an error!)
+ i=plen-1;
+ }
+ p+=abs(l); // now p points to first byte after tag
+
+
+ // Closing tag found: does it match last opening tag?
+ if (l<0) xnstack_pop(s);
+
+ // Opening tag found: store it in last_tag!
+ if (l>0) {
+ xntag=xml_tag2int(t);
+ parent=xnstack_get_top(s); // get parent tag;
+ xnstack_push(s, xntag);
+ dlen = xml_get_data (p, d);
+
+ if (xntag==xml_field) { // Create new field
+ f=automops_add_field(amp);
+ } else
+ // Now copy the data 'd' into (the header & fields of) 'amp'
+ if (dlen>0) {
+ if (parent==xml_protocol) {
+ err = amp_add_pentry(amp, xntag, d);
+ } else
+ if (parent==xml_field) {
+ err = amp_add_fentry(amp, f, xntag, d);
+ }
+ if (err) {
+ if (!quiet) {
+ amperr2str(err, errmsg);
+ fprintf(stderr, "WARNING: Automops found '%s' at XML position %i\n", errmsg, i);
+ }
+ return i;
+ }
+ }
+ }
+ if (i==(plen-1)) return 0;
+
+ } while (l!=0);
+ return 0;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+// //
+////////////// ONLY XML NESTING STACK FUNCTIONS BELOW THIS LINE ///////////////
+//
+//
+
+void xnstack_init(struct xnstack *s)
+{
+ s->cursize=0;
+}
+
+// Returns top data element or -1 if stack empty
+// Does NOT remove data elements!
+int xnstack_get_top(struct xnstack *s)
+{
+ if (s->cursize==0) return -1;
+ return s->data[s->cursize-1];
+}
+
+// Push data onto stack
+// Returns -1 if max stack depth exceeded
+int xnstack_push(struct xnstack *s, int d)
+{
+ if (s->cursize<XN_MAX_STACK)
+ s->data[s->cursize++]=d;
+ else
+ return -1;
+ return 0;
+}
+
+
+// Returns top data element and ALSO REMOVES it from stack
+// Returns -1 if stack is empty
+int xnstack_pop(struct xnstack *s)
+{
+ int d;
+ d=xnstack_get_top(s);
+ if (d>=0) s->cursize--;
+ return d;
+}
+
+int xnstack_size(struct xnstack *s)
+{
+ return s->cursize;
+}
+
diff --git a/staging/rcv_rtp.c b/staging/rcv_rtp.c
new file mode 100644
index 0000000..336a6e0
--- /dev/null
+++ b/staging/rcv_rtp.c
@@ -0,0 +1,769 @@
+/*
+ * Mausezahn - A fast versatile traffic generator
+ * Copyright (C) 2008-2010 Herbert Haas
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
+ *
+*/
+
+
+///////////////////////////////////////////////////
+//
+// Table of contents:
+//
+// rcv_rtp_init()
+// rcv_rtp()
+// compare4B()
+// got_rtp_packet()
+// print_jitterbar()
+//
+
+///////////////////////////////////////////////////
+//
+// Documentation about RTP traffic analysis
+//
+// See http://wiki.wireshark.org/RTP_statistics
+//
+//
+
+#include "mz.h"
+#include "mops.h"
+
+// Initialize the rcv_rtp process: Read user parameters and initialize globals
+int rcv_rtp_init()
+{
+ char argval[MAX_PAYLOAD_SIZE];
+ char dummy[512];
+ int len;
+ u_int32_t port = 30000; // 4-byte variable to catch errors, see below
+
+ int ssrc_s = 0;
+
+ // Help text
+
+ if (getarg(tx.arg_string,"help", NULL)==1) {
+ fprintf(stderr,"\n"
+ MAUSEZAHN_VERSION
+ "\n"
+ "| RTP reception for jitter measurements.\n"
+ "|\n"
+ "| Parameters:\n"
+ "|\n"
+ "| bar ...... Display modes: By default 'bar' is used and shows the RFC 3550 jitter as\n"
+ "| ASCII-based waterfall diagram.\n"
+ "| txt ...... The 'txt' mode prints all measurement values numerically upon each\n"
+ "| measurement interval.\n"
+// "| curse ...... Shows all values and a diagram within an resizesable ncurses window.\n"
+ "|\n"
+ "| ssrc ....... Listen to the stream with the specified SSRC. You must specify this\n"
+ "| when there are concurrent streams, e. g. one in each direction.\n"
+ "|\n"
+ "| log ....... Write moving average also in a datafile (not only on terminal).\n"
+ "| logg ....... Like log but additionally write detailed real-time statistics in a data file\n"
+ "| path = <path> ....... Path to directory where datafiles can be stored (default: local directory).\n"
+ "| num = <10-%d> ...... number of packets to be received for averaging (default: %d).\n"
+ "| port = <0-65535> ....... Change if RTP packets are sent to a different port than 30000 (default).\n"
+ "|\n"
+ "| Note:\n"
+ "|\n"
+ "| Mausezahn can log actual realtime measurement data in data files (in the specified path or\n"
+ "| current directory) but always prints the moving average on the command line (this can be disabled\n"
+ "| using the 'quiet' option (-q)).\n"
+ "|\n"
+ "| The realtime data file(s) consist of two columns:\n"
+ "|\n"
+ "| 1. relative timestamp in usec\n"
+ "| 2. 'true' jitter in usec\n"
+ "|\n"
+ "| where the 'true' jitter is calculated using the (relative) timestamps inside the received\n"
+ "| packets t(i) and the (relative) timestamps T(i) observed locally when packets are received using\n"
+ "| the formula:\n"
+ "|\n"
+ "| jitter(i) = [T(i) - T(i-1)] - [t(i) - t(i-1)] + jitter(i-1) .\n"
+ "|\n"
+ "| This method has two advantages: (i) we do not need to synchronize the clocks of sender and\n"
+ "| receiver, and (ii) the TX-side jitter (mainly caused by the kernel-scheduler) is subtracted\n"
+ "| so that we primarily measure the jitter caused by the network.\n"
+ "| \n"
+ "| The data files consist of seven columns:\n"
+ "| \n"
+ "| 1. relative timestamp in seconds\n"
+ "| 2. minimum jitter\n"
+ "| 3. average jitter\n"
+ "| 4. minimum jitter\n"
+ "| 5. estimated jitter variance according RFC-3550\n"
+ "| 6. packet drop count (total)\n"
+ "| 7. packet disorder count (total)\n"
+ "| \n"
+ "| All measurement values are done in usec and refer to the current set of samples (see parameter 'num').\n"
+ "| Note that an RFC-conform jitter (smoothed mean deviation) is calculated and collected in column five.\n"
+ "| The drop value refers to the current measurement window, while the total drop and disorder values are\n"
+ "| calculated using some weird estimation functions; the goal was to provide a 'time-less' estimation\n"
+ "| while being able to automatically resynchronize to a re-started RTP measurement stream.\n"
+ "| \n"
+ "| EXAMPLE USAGE:\n"
+ "|\n"
+ "| At the TX-station enter:\n"
+ "|\n"
+ "| # mz eth0 -t rtp -B 10.3.3.42 (optionally change rate via -d option, payload size via pld command)\n"
+ "|\n"
+ "| At the RX-station (10.3.3.42) enter:\n"
+ "|\n"
+ "| # mz eth0 -T rtp \"log, path=/tmp/mz/\"\n"
+ "|\n"
+ "\n", TIME_COUNT_MAX, TIME_COUNT);
+ exit(0);
+ }
+
+
+ // check argstring for arguments
+
+ if (getarg(tx.arg_string,"bar", NULL)==1) {
+ rtp_dm = BAR;
+ }
+
+ if (getarg(tx.arg_string,"txt", NULL)==1) {
+ rtp_dm = TEXT;
+ }
+
+ if (getarg(tx.arg_string,"curses", NULL)==1) {
+ rtp_dm = BAR; //NCURSES;
+ fprintf(stderr, " XXX This Mausezahn version does not support ncurses windows.\n");
+ }
+
+ if (getarg(tx.arg_string,"width", argval)==1) {
+ if (rtp_dm != BAR) {
+ fprintf(stderr, " mz/rcv_rtp: The 'width' parameter requires the display mode 'bar'\n");
+ return -1;
+ }
+ bwidth = (int) str2int(argval); // [TODO] bwidth is currently not used
+ if (bwidth>RCV_RTP_MAX_BAR_WIDTH) {
+ fprintf(stderr, "The width must not exceed %i\n",
+ RCV_RTP_MAX_BAR_WIDTH);
+ return -1;
+ }
+ } else bwidth=80;
+
+ if (getarg(tx.arg_string,"ssrc", argval)==1) {
+ ssrc_s = str2hex(argval, mz_ssrc, 4);
+ if (ssrc_s<0) {
+ fprintf(stderr, " mz/rtp_rcv: invalid ssrc!\n");
+ return -1;
+ }
+ }
+
+ if (getarg(tx.arg_string,"log", NULL)==1) {
+ rtp_log = 1;
+ }
+
+ if (getarg(tx.arg_string,"logg", NULL)==1) {
+ rtp_log = 2;
+ }
+
+
+ if (getarg(tx.arg_string,"path", argval)==1) {
+ len = strlen(argval);
+ if (len>128) {
+ fprintf(stderr, " mz/Error: path must not exceed 128 characters!\n");
+ exit (-1);
+ }
+ if (argval[len-1]!='/') {
+ strncat(argval, "/",1); // ensure that all paths end with "/"
+ }
+ strncpy(path, argval, 128);
+ }
+
+
+ if (getarg(tx.arg_string,"num", argval)==1) {
+ gind_max = (u_int32_t) str2int(argval);
+ if (gind_max > TIME_COUNT_MAX) {
+ gind_max = TIME_COUNT_MAX;
+ fprintf(stderr, " mz/Warning: num range is 10..%d. Will reset to %d.\n",
+ TIME_COUNT_MAX, TIME_COUNT_MAX);
+ }
+ else if (gind_max < 10) {
+ gind_max = 10;
+ fprintf(stderr, " mz/Warning: num range is 10..%d. Will reset to 10.\n",
+ TIME_COUNT_MAX);
+ }
+ }
+
+
+ // initialize global filter string
+ strncpy (rtp_filter_str, "udp dst port 30000", 64);
+
+ if (getarg(tx.arg_string,"port", argval)==1) {
+ port = (u_int32_t) str2int(argval);
+ if (port>65535) {
+ port = 30000;
+ fprintf(stderr, " mz: Too large port number! Reset to default port (30000).\n");
+ }
+
+ sprintf(rtp_filter_str, "udp dst port %u", (unsigned int) port);
+ }
+
+ //
+ if (ssrc_s==0) str2hex("ca:fe:fe:ed", mz_ssrc, 4);
+
+ // open file
+ //
+ if (rtp_log) {
+ // get a new filename
+ timestamp_human(filename, "rtp_avg_");
+ strncpy(dummy, path, 128);
+ strncat(dummy, filename, 64);
+ if (verbose) fprintf(stderr, " mz: Will open %s\n", dummy);
+
+ fp = fopen (dummy, "w+");
+
+ if (fp == NULL) {
+ perror("fopen");
+ exit (-1);
+ }
+
+ gtotal=0; // counts written data blocks
+ fprintf(fp, "# Average jitter measurements made by Mausezahn " MAUSEZAHN_VERSION_SHORT ".\n");
+ fprintf(fp, "# Timestamp is in seconds, all other values in microseconds.\n");
+ fprintf(fp, "# Column values (from left to right):\n");
+ fprintf(fp, "# 1. Timestamp\n"
+ "# 2. min_jitter\n"
+ "# 3. avg_jitter\n"
+ "# 4. max_jitter\n"
+ "# 5. estimated jitter according RFC-3550\n"
+ "# 6. packet drop count (total)\n"
+ "# 7. packet disorder count (total)\n");
+
+
+ ///////////// also detailed log required /////////////
+ if (rtp_log==2) {
+ // get a new filename
+ timestamp_human(filename, "rtp_rt_");
+ strncpy(dummy, path, 128);
+ strncat(dummy, filename, 64);
+ if (verbose) fprintf(stderr, " mz: Will open %s\n", dummy);
+
+ fp2 = fopen (dummy, "w+");
+
+ if (fp2 == NULL) {
+ perror("fopen");
+ exit (-1);
+ }
+
+ fprintf(fp2, "# Jitter measurements by Mausezahn " MAUSEZAHN_VERSION_SHORT ".\n");
+ fprintf(fp2, "# Timestamp (usec) , true jitter (nsec)\n");
+ }
+
+ }
+
+ drop=0;
+ dis=0;
+ jitter_rfc=0;
+
+ return 0;
+}
+
+
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////////////////
+//
+// Defines the pcap handler and the callback function
+int rcv_rtp()
+{
+ char errbuf[PCAP_ERRBUF_SIZE];
+
+ pcap_t *p;
+
+ struct bpf_program filter;
+
+
+
+ p = pcap_open_live (tx.device,
+ MAXBYTES_TO_READ, // max num of bytes to read
+ 0, // 1 if promiscuous mode
+ PCAP_READ_TIMEOUT_MSEC, // read timeout in msec
+ errbuf);
+
+ if (p == NULL)
+ {
+ fprintf(stderr," mz/rcv_rtp: %s\n",errbuf);
+ exit(1);
+ }
+
+
+ if ( pcap_compile(p,
+ &filter, // the compiled version of the filter
+ rtp_filter_str, // text version of filter
+ 0, // 1 = optimize
+ 0) // netmask
+ == -1)
+ {
+ fprintf(stderr," mz/rcv_rtp: Error calling pcap_compile\n");
+ exit(1);
+ }
+
+
+
+ if ( pcap_setfilter(p, &filter) == -1)
+ {
+ fprintf(stderr," mz/rcv_rtp: Error setting filter\n");
+ pcap_geterr(p);
+ exit(1);
+ }
+
+ again:
+
+
+ pcap_loop (p,
+ 1, // number of packets to wait
+ got_rtp_packet, // name of callback function
+ NULL); // optional additional arguments for callback function
+
+
+ goto again;
+
+
+ // TODO: Currently we never reach this point!
+ fprintf(stderr, " mz: receiving of RTP finished.\n");
+ pcap_close(p);
+
+ return 0;
+}
+
+
+
+
+// Compares two 4-byte variables byte by byte
+// returns 0 if identical, 1 if different
+inline int compare4B (u_int8_t *ip1, u_int8_t *ip2)
+{
+ if (*ip1 != *ip2) return 1;
+ if (*(ip1+1) != *(ip2+1)) return 1;
+ if (*(ip1+2) != *(ip2+2)) return 1;
+ if (*(ip1+3) != *(ip2+3)) return 1;
+
+ return 0;
+}
+
+
+
+
+
+// Handler function to do something when RTP messages are received
+void got_rtp_packet(u_char *args,
+ const struct pcap_pkthdr *header, // statistics about the packet (see 'struct pcap_pkthdr')
+ const u_char *packet) // the bytestring sniffed
+{
+ const struct struct_ethernet *ethernet;
+ const struct struct_ip *ip;
+ const struct struct_udp *udp;
+ const struct struct_rtp *rtp;
+
+ int size_ethernet = sizeof(struct struct_ethernet);
+ int size_ip = sizeof(struct struct_ip);
+ int size_udp = sizeof(struct struct_udp);
+ // int size_rtp = sizeof(struct struct_rtp);
+ //
+ ethernet = (struct struct_ethernet*)(packet);
+ ip = (struct struct_ip*)(packet+size_ethernet);
+ udp = (struct struct_udp*)(packet+size_ethernet+size_ip);
+ rtp = (struct struct_rtp*)(packet+size_ethernet+size_ip+size_udp);
+
+ struct mz_timestamp
+ deltaTX,
+ deltaRX;
+
+ u_int32_t
+ i,
+ jitter_abs,
+ jitter_avg,
+ jitter_max,
+ jitter_min,
+ curtime=0;
+
+ int32_t ltemp;
+
+ u_int8_t *x,*y;
+
+ char dummy[256];
+ char ts_hms[10];
+ unsigned char *dum;
+ static u_int32_t drop_last=0, drop_prev=0;
+ int s1, s2;
+
+ // check if the RTP packet is really from a Mausezahn instance:
+ if (compare4B((u_int8_t*) &rtp->ssrc, mz_ssrc)==0) {
+ // we got a valid RTP packet from a Mausezahn instance
+ // Get current SQNR and store it in 'sqnr_cur' in host byte order
+ x = (u_int8_t*) &rtp->sqnr;
+ y = (u_int8_t*) &sqnr_cur;
+
+ *y = *(x+1);
+ y++;
+ *y = *x;
+
+ /////////////////////////////////////////////////////////////////////
+ // Packet drop and disorder detection:
+ if (sqnr0_flag) {
+ if (sqnr_next==sqnr_cur) { // correct SQNR received
+ sqnr_next++;
+ sqnr_last++;
+ } else if (sqnr_last>sqnr_cur) { // disordered sequence
+ dis++;
+ if (drop) drop--; // don't get below 0
+ else { // drop reached zero: resync (restarted RTP stream?)
+ sqnr_last = sqnr_cur;
+ sqnr_next = (++sqnr_last);
+ dis=0;
+ }
+ } else { // packet drop
+ drop += (sqnr_cur-sqnr_next);
+ sqnr_last = sqnr_cur;
+ sqnr_next = (++sqnr_last);
+ }
+ } else {
+ // initial synchronization with observed SQNR:
+ sqnr_last = sqnr_cur;
+ sqnr_next = (++sqnr_last);
+ sqnr0_flag++;
+ }
+ //
+ /////////////////////////////////////////////////////////////////////
+
+
+ // Get RX timestamp from pcap header
+ timeRX[gind].sec = header->ts.tv_sec;
+ timeRX[gind].nsec = header->ts.tv_usec *1000;
+
+ // Get TX timestamp from the packet
+ mops_hton4((u_int32_t*) &rtp->time_sec, (u_int8_t*) &timeTX[gind].sec);
+ mops_hton4((u_int32_t*) &rtp->time_nsec, (u_int8_t*) &timeTX[gind].nsec);
+
+// printf("%li %li\n", (long int) timeTX[gind].sec, (long int) timeTX[gind].nsec);
+
+ gind++;
+
+ ////////////////////////////////////////////////////////////////
+ if (gind == gind_max) { // array full, now calculate statistics
+ gind=0;
+ gtotal++;
+
+ jitter_avg = 0;
+ jitter_min = 0xffffffff;
+ jitter_max = 0;
+
+
+ ///////////////////////////////////////////////////////
+ // calculate deltas and jitters
+ for (i=2; i<gind_max; i++) { // omit the first 2 data
+ // entries because of
+ // artificial high TX-delta!
+ //
+ ///////////////////////////////////////////////
+ // calculate deltaTX and deltaRX
+ //
+ s1=timestamp_subtract (&timeTX[i], &timeTX[i-1], &deltaTX);
+ s2=timestamp_subtract (&timeRX[i], &timeRX[i-1], &deltaRX);
+ if (s1) fprintf(stderr, " *** ***\n");
+
+ // Then calculate the precise jitter by considering
+ // also TX-jitter: (pseudo)jitter = deltaRX - deltaTX,
+ // hence we have positive and negative jitter (delay
+ // deviations) jitter entries are in +/- nanoseconds
+ jitter[i] = (deltaRX.sec*1000000000L + deltaRX.nsec)
+ - (deltaTX.sec*1000000000L + deltaTX.nsec);
+ // Calculate RFC 3550 jitter estimation. According to
+ // that RFC the jitter should be measured in timestamp
+ // units; however currently Mausezahn uses nanoseconds.
+ // (If we want to solve this: G.711 timestamp units are
+ // 125 usec, so jitter/=125 would be sufficient, AFAIK)
+ ltemp = labs(jitter[i]) - jitter_rfc;
+ jitter_rfc += (ltemp>>4);
+ // Add previous pseudojitter to get the true jitter
+ // (See Documentation!)
+ jitter[i] += jitter[i-1];
+ //
+ ////////////////////////////////////////////////
+
+
+
+
+ ////////////////////////////////////////////////
+ // Determine avg, min, and max jitter within this time frame:
+ jitter_abs = labs(jitter[i]);
+ jitter_avg += jitter_abs;
+ if (jitter_abs < jitter_min) jitter_min = jitter_abs;
+ if (jitter_abs > jitter_max) jitter_max = jitter_abs;
+ //
+ ////////////////////////////////
+
+ /// PRINT IN FILE_2: Detailed jitter data ///
+ if (rtp_log==2) {
+ // Calculate relative timestamp for column 1 of the datafile
+ curtime = timeRX[i].sec*1000000+timeRX[i].nsec/1000;
+ if (time0_flag) {
+ curtime = curtime - time0;
+ } else { // this is only done once during the Mausezahn process
+ time0 = curtime;
+ time0_flag=1;
+ curtime = curtime - time0;
+ }
+ fprintf(fp2, "%lu, %li\n",
+ (long unsigned int) curtime,
+ (long int) jitter[i]);
+ fflush(fp2); // save everything immediately
+ // (CHECK if fsync() is additionally needed)
+ }
+ } // end for (i=2; i<gind_max; i++)
+ //
+ ////////////////////////////////////////////////////////
+
+
+ jitter_avg = jitter_avg / (gind_max-2); // average true jitter, always positive
+
+ if (drop>=drop_prev) { // because the total drop count may decrease(!) if disordered packets appear lately
+ drop_last = drop - drop_prev;
+ drop_prev=drop;
+ } else drop_last=0;
+
+ // PRINT ON CLI: statistics data
+ switch (rtp_dm) {
+ case TEXT:
+ dum = (unsigned char*) &ip->src;
+ fprintf(stdout,
+ "Got %u packets from host %u.%u.%u.%u: %lu lost (%lu absolute lost, %lu out of order)\n"
+ " Jitter_RFC (low pass filtered) = %li usec\n"
+ " Samples jitter (min/avg/max) = %lu/%lu/%lu usec\n",
+ gind_max,
+ *(dum),*(dum+1),*(dum+2),*(dum+3),
+ (long unsigned int) drop_last,
+ (long unsigned int) drop,
+ (long unsigned int) dis,
+ (long int) jitter_rfc/1000,
+ (long unsigned int) jitter_min/1000,
+ (long unsigned int) jitter_avg/1000,
+ (long unsigned int) jitter_max/1000);
+ break;
+
+ case BAR:
+ print_jitterbar(jitter_rfc/1000, drop_last);
+ break;
+
+ case NCURSES: // would be nice...?
+ break;
+
+ default:
+ break;
+ }
+
+ // Determine whether some packets got lost:
+ //
+ //
+ //
+ //
+
+
+
+ /// PRINT IN FILE_1: statistics only ///
+ if (rtp_log) {
+ ts_hms[0]=0x00;
+ timestamp_hms (ts_hms);
+ fprintf(fp,
+ "%s, %lu, %lu, %lu, %li, %u, %u\n",
+ ts_hms,
+ (long unsigned int) jitter_min/1000,
+ (long unsigned int) jitter_avg/1000,
+ (long unsigned int) jitter_max/1000,
+ (long int) jitter_rfc/1000,
+ drop,
+ dis);
+ fflush(fp);
+ }
+
+
+
+ // Open another file if current file reaches a limit
+ //
+ if ((rtp_log==2) && (gtotal>MAX_DATA_BLOCKS)) { // file big enough,
+ gtotal=0;
+ if (fclose(fp2) == EOF) {
+ perror("fclose");
+ exit(1);
+ }
+
+ if (verbose)
+ fprintf(stderr, " mz: %s written.\n",filename);
+
+ timestamp_human(filename, "rtp_"); // get a new filename
+ strncpy(dummy, path, 128);
+ strncat(dummy, filename, 64);
+
+ if (verbose) fprintf(stderr, " mz: Will open %s\n", dummy);
+
+ if ( (fp2 = fopen (dummy, "w+")) == NULL) {
+ if (errno != EAGAIN) {
+ perror("fopen");
+ exit (-1);
+ }
+ }
+ fprintf(fp2, "# Jitter measurements by Mausezahn "
+ MAUSEZAHN_VERSION_SHORT ".\n");
+ fprintf(fp2, "# Timestamp (usec) , true jitter (nsec)\n");
+ }
+ } // statistics end *********************************************************************
+ }
+}
+
+
+
+
+void print_jitterbar (long int j, u_int32_t d)
+{
+ // Determine actual data window by considering two events:
+ //
+ // 1) window move (j exceeds lower or upper limit)
+ // 2) window rescale (window moves happen too often or the variance
+ // of successive data points is too small)
+ //
+ // The most critical value is the chosen resolution (window range),
+ // especially the _initial_ resolution.
+
+ static long int range=0, min=0, max=0, minvar=0, j0=0, dj=0;
+ static int moved=0, varcount=0, barcount=0;
+ char str[128], bar[150],
+ str1[8], str2[8], str3[8], str4[8];
+ int event=0, anz;
+ long int tmp;
+
+ // Initialize vars (start with an opened window)
+ // Note that 'range' is actually half of the window
+ if (!range) {
+ range=j;
+ if (range<500) range=500;
+ max = j+range;
+ min = 0;
+ minvar=range/40;
+ event++;
+ } else {
+ dj = labs(j-j0); // no initialization: calculate jitter delta
+ }
+
+ // Move window when borders crossed:
+ if ((j<min) || (j>max)) {
+ max = j + range;
+ min = max-2*range;
+ if (min<0) {
+ min=0;
+ range=(max-min)/2;
+ fprintf(stdout, "\nNOTE: +- Rescaled window to %4.2f msec\n", (double) range/500);
+ }
+ moved++;
+ event++;
+ fprintf(stdout,"\n");
+// printf("move event: min=%li max=%li\n", min, max);
+ } else {
+ if (moved) moved--;
+// printf("normal event: min=%li max=%li\n", min, max);
+ }
+
+
+ // Increase range when window moved 5 times in a row
+ if (moved>2) {
+ range*=3;
+ if (range>10000000L) range=10000000L;
+ minvar=range/40;
+ if (minvar<1000) minvar=1000;
+ max=j+range;
+ min=j-range;
+ if (min<0) {
+ min=0;
+ range=(max-min)/2;
+ }
+ moved=0;
+ event++;
+// printf("scale up event: min=%li max=%li\n", min, max);
+ fprintf(stdout, "\nNOTE: ++ Rescaled window to %4.2f msec\n", (double) range/500);
+ }
+
+
+ // Decrease range when jitter deltas are smaller than minvar
+ // 5 times in a row
+ if (dj<minvar)
+ varcount++;
+ else
+ varcount=0;
+
+ if (varcount>5) {
+ range*=0.75;
+ if (range>j) range=j;
+ if (range<500) {
+ range=500;
+ }
+ minvar=range/40;
+ if (minvar<1000) minvar=1000;
+ max=j+range;
+ min=j-range;
+ if (min<0) {
+ min=0;
+ range=(max-min)/2;
+ }
+ fprintf(stdout, "\nNOTE: -- Rescaled window to %4.2f msec\n", (double) range/500);
+ varcount=0;
+ event++;
+// printf("scale down event: min=%li max=%li\n", min, max);
+ }
+
+ j0=j;
+
+ barcount++;
+ if (barcount==24) {
+ event=1;
+ barcount=0;
+ }
+
+ if (event) {
+ tmp=range*0.667;
+ sprintf(str1,"%4.2f", (double) min/1000);
+ sprintf(str2,"%4.2f", (double) (min+tmp)/1000);
+ sprintf(str3,"%4.2f", (double) (max-tmp)/1000);
+ sprintf(str4,"%4.2f", (double) max/1000);
+
+ fprintf(stdout,
+ "%-6s %-6s %-6s %-6s\n"
+ "|-------------------------|-------------------------|-------------------------|\n",
+ str1, str2, str3, str4);
+ barcount=0;
+ }
+
+ anz = 80*(j-min)/(2*range);
+ if (anz) {
+ memset((void*) str, '#', anz);
+ memset((void*) str+anz, ' ', 80-anz);
+ str[80]='\0';
+ }
+ else {
+ memset((void*) str, ' ', 80);
+ str[0]='#';
+ str[80]='\0';
+ }
+ if (d)
+ sprintf(bar, "%s%4.2f msec !%lu dropped!", str, (double) j/1000, (unsigned long int) d);
+ else
+ sprintf(bar, "%s%4.2f msec", str, (double) j/1000);
+
+ fprintf(stdout,"%s\n", bar);
+}
+
diff --git a/staging/rtp.c b/staging/rtp.c
new file mode 100644
index 0000000..6ce4458
--- /dev/null
+++ b/staging/rtp.c
@@ -0,0 +1,217 @@
+/*
+ * Mausezahn - A fast versatile traffic generator
+ * Copyright (C) 2008 Herbert Haas
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
+ *
+*/
+
+
+
+#include "mz.h"
+#include "cli.h"
+#include "mops.h"
+
+#define MZ_RTP_HELP \
+ "| RTP type: Send Real Time Protocol packets.\n" \
+ "|\n" \
+ "| This mode is solely intended to conduct delay, drop, and jitter measurements in\n" \
+ "| Voice (Video) over IP networks. You will typically initiate another Mausezahn\n" \
+ "| instance on the destination host, which will perform the measurements or even\n" \
+ "| 'bounce back' the packets for Round Trip Time (RTT) measurements.\n" \
+ "|\n" \
+ "| When the delay parameter is not specified, the default (inter-packet) delay is\n" \
+ "| set to 20 msec. You must specify the destination host using the -B option.\n" \
+ "| The default destination port is (UDP) 30000 but can be overridden (dp parameter).\n" \
+ "| You do not need to specify the count option (-c), because 'infinite' (0) is assumed.\n" \
+ "|\n" \
+ "| You can specify these additional GENERAL options:\n" \
+ "|\n" \
+ "| -c <count> ..... use this packet count value instead of infinity.\n" \
+ "| -d <delay> ..... use this delay value instead of the defaul. Per default\n" \
+ "| the units are microseconds but you can also use msec or sec\n" \
+ "|\n" \
+ "| You can specify these additional UDP/RTP-specific arguments:\n" \
+ "|\n" \
+ "| dp = <1-65535> ..... use this UDP destination port instead of 30,000.\n" \
+ "| sp = <1-65535> ..... use this UDP source port instead of random.\n" \
+ "| ssrc = XX:XX:XX:XX ... use this hex sequence as stream identifier\n" \
+ "| (=SSRC, required for multiple concurrent measurements)\n" \
+ "| codec ..... simulate G.711 codec (other will follow).\n" \
+ "| pld = <1..1000> ....... create specified payload size (default=160 bytes, which results\n" \
+ "| in a total datagram length of 180 bytes, considering the UDP and\n" \
+ "| RTP header lengths (8 and 12 bytes, respectively).\n" \
+ "|\n" \
+ "| Additional help: enter 'mz -T rtp help'\n" \
+ "|\n"
+
+
+
+int create_rtp_packet()
+{
+ u_int8_t byte1, byte2;
+ u_int16_t seqnr;
+ u_int8_t ssrc[4] = {0,0,0,0} ;
+ int ssrc_s = 0;
+ u_int8_t *ptr;
+ char argval[MAX_PAYLOAD_SIZE];
+ unsigned int rtp_payload_size=160;
+ struct mz_timestamp ts;
+
+ if ( (getarg(tx.arg_string,"help", NULL)==1) && (mode==RTP) ) {
+ if (mz_port)
+ {
+ cli_print(gcli, "%s", MZ_RTP_HELP);
+ return -1;
+ }
+ else
+ {
+
+ fprintf(stderr,"\n"
+ MAUSEZAHN_VERSION
+ "\n%s", MZ_RTP_HELP);
+ exit(0);
+ }
+ }
+
+
+ if (getarg(tx.arg_string,"pld", argval)==1) {
+ rtp_payload_size = (unsigned int) str2int(argval);
+ }
+
+ if (getarg(tx.arg_string,"codec", argval)==1) {
+ tx.delay = 20000;
+ }
+
+ if (getarg(tx.arg_string,"ssrc", argval)==1) {
+ ssrc_s = str2hex(argval, ssrc, 4);
+ if (ssrc_s<0) {
+ fprintf(stderr, " mz/rtp: invalid ssrc!\n");
+ return -1;
+ }
+ }
+
+ // TODO: Optional arguments for RTP
+
+
+ // Create header: //
+
+ // Byte 1
+ //
+ // +--+--+--+--+--+--+--+--+
+ // | ver | P| X| CSRC Count|
+ // +--+--+--+--+--+--+--+--+
+ //
+ // Default: ver=2, Padding=0, Extension_Header=1, CSRC_Count=0 => 10 0 1 0000 = 0x90
+
+ byte1 = 0x90;
+
+ // Byte 2
+ //
+ // +--+--+--+--+--+--+--+--+
+ // | M| Payload Type |
+ // +--+--+--+--+--+--+--+--+
+ //
+ // Marker=0, Payload Type=0 (or 8 alternatively)
+
+ byte2 = 0x00;
+
+ // Bytes 3,4
+ //
+ // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ // | Sequence Number |
+ // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+ seqnr = 0x0000;
+
+ // Bytes 5,6,7,8
+ //
+ // Timestamp /* done below */
+ //
+
+
+ // Bytes 9,10,11,12
+ //
+ // Synchronization Source Identifier
+ //
+
+ if (ssrc_s==0) str2hex("ca:fe:fe:ed", ssrc, 4);
+
+ // Bytes 13,14,15,16
+ //
+ // CSRC - Contributing Source Identifiers (optional, only used by mixers)
+ //
+ // csrc = 0x00000000;
+
+ // Bytes 17,18,19,20
+ //
+ // Header Extension (optional) NOT USED HERE!
+ //
+
+ // !!! Thus payload begins with index 16 in a C array !!!
+
+ // ------------ Now combine all fields: ----------------
+ tx.udp_payload[0] = byte1;
+ tx.udp_payload[1] = byte2;
+
+ ptr = (u_int8_t*) &seqnr;
+ tx.udp_payload[2] = *(ptr+1);
+ tx.udp_payload[3] = *ptr;
+
+ // TIMESTAMP: will be linearly increased, e.g. using 20msec G.711: 0, 160, 320, ...
+ tx.udp_payload[4] = 0x00;
+ tx.udp_payload[5] = 0x00;
+ tx.udp_payload[6] = 0x00;
+ tx.udp_payload[7] = 0x00;
+
+ tx.udp_payload[8] = ssrc[0];
+ tx.udp_payload[9] = ssrc[1];
+ tx.udp_payload[10] = ssrc[2];
+ tx.udp_payload[11] = ssrc[3];
+
+ /*
+ ptr = (u_int8_t*) &csrc;
+ tx.udp_payload[12] = *(ptr+3);
+ tx.udp_payload[13] = *(ptr+2);
+ tx.udp_payload[14] = *(ptr+1);
+ tx.udp_payload[15] = *ptr;
+ */
+
+ // Add the NEW Mausezahn extension header (see mops_ext_rtp.c)
+ tx.udp_payload[12] = 0xca; // identifier
+ tx.udp_payload[13] = 0xca;
+ tx.udp_payload[14] = 0x00;
+ tx.udp_payload[15] = 0x04; // length
+ getcurtime(&ts); // Now add TX timestamp:
+ mops_hton4 ((u_int32_t*) &ts.sec, &tx.udp_payload[16]);
+ mops_hton4 ((u_int32_t*) &ts.nsec, &tx.udp_payload[20]);
+ // NOTE: The remaining 8 bytes of this extension header are set to zero
+ // via the following code.
+
+ memset(&tx.udp_payload[24], 0x00, (rtp_payload_size-12)); // payload (considering our 8 byte timestamp)
+ tx.udp_payload_s = 12 + rtp_payload_size; // the latter ist the payload size
+
+ // ---------- now hand over to UDP -----------------
+
+ tx.dp = 30000;
+ tx.sp = 30000;
+
+ tx.udp_len = 8 + tx.udp_payload_s;
+
+ return 0;
+}
+
+
+
+
+
diff --git a/staging/send.c b/staging/send.c
new file mode 100644
index 0000000..5ad1a20
--- /dev/null
+++ b/staging/send.c
@@ -0,0 +1,264 @@
+/*
+ * Mausezahn - A fast versatile traffic generator
+ * Copyright (C) 2008 Herbert Haas
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
+ *
+*/
+
+
+
+
+
+// ***************************************************************************
+//
+// This sections contains:
+//
+// - complexity() ... calculates and reports how many frames will
+// be generated.
+// - send_frame() ... the general and mighty SENDING FUNCTION.
+//
+// ***************************************************************************
+
+#include "mz.h"
+#include "cli.h"
+
+
+// Calculates the number of frames to be sent.
+// Should be used as standard output except the
+// 'quiet' option (-q) has been specified.
+int complexity()
+{
+ unsigned long int
+ nr_sqnr = 1,
+ nr_dp = 1,
+ nr_sp = 1,
+ nr_da = 1,
+ nr_sa = 1;
+
+ u_int32_t
+ sn1,
+ sn2,
+ delta;
+
+ long double ref;
+
+ if (tx.count==0) goto infinity;
+
+ total_d = 1.0;
+
+ // How many sequence numbers?
+ if (tx.tcp_seq_delta)
+ {
+ sn1 = tx.tcp_seq_start;
+ sn2 = tx.tcp_seq_stop;
+ delta = tx.tcp_seq_delta;
+
+ if (sn1<sn2) // the easier case
+ {
+ nr_sqnr = (sn2-sn1)/delta;
+ }
+ else
+ {
+ nr_sqnr = (sn2 + (0xffffffff - sn1)) / delta;
+ }
+ //fprintf(stderr,"SQNR Range = %lu\n",nr_sqnr);
+ nr_sqnr +=1;
+ }
+
+ if (tx.dp_isrange)
+ {
+ nr_dp = tx.dp_stop - tx.dp_start + 1;
+ //fprintf(stderr,"DP Range = %lu\n",nr_dp);
+ }
+
+ if (tx.sp_isrange)
+ {
+ nr_sp = tx.sp_stop - tx.sp_start + 1;
+ //fprintf(stderr,"SP Range = %lu\n",nr_sp);
+ }
+
+ if (tx.ip_dst_isrange)
+ {
+ nr_da = tx.ip_dst_stop - tx.ip_dst_start + 1;
+ //fprintf(stderr,"DA Range = %lu\n",nr_da);
+ }
+
+ if (tx.ip_src_isrange)
+ {
+ nr_sa = tx.ip_src_stop - tx.ip_src_start + 1;
+ //fprintf(stderr,"SA Range = %lu\n",nr_sa);
+ }
+
+ total_d *= tx.count;
+ total_d *= nr_sqnr;
+ total_d *= nr_dp;
+ total_d *= nr_sp;
+ total_d *= nr_da;
+ total_d *= nr_sa;
+
+
+
+
+ ref=0xffffffff;
+
+ ref*=ref;
+
+ if (total_d>ref)
+ {
+ fprintf(stderr, "You must be crazy...\n");
+ }
+ else if (total_d>0xffffffff)
+ {
+ fprintf(stderr, "Do you REALLY know what you do?\n");
+ }
+ else if (total_d>0xffffff)
+ {
+ fprintf(stderr, "Do you know what you do?\n");
+ }
+
+ if (mz_port)
+ {
+ cli_print(gcli, "Mausezahn will send %.Lf frames...\r", total_d);
+ }
+ else
+ {
+ fprintf(stderr, "Mausezahn will send %.Lf frames... ", total_d);
+ fflush(stderr);
+ if (verbose) fprintf(stderr,"\n");
+ }
+
+
+
+ mz_start = clock();
+
+ infinity:
+
+
+ if (tx.count==0)
+ {
+ if (mz_port)
+ {
+ cli_print(gcli, "Mausezahn will send frames infinitly...\n");
+ }
+ else
+ {
+ fprintf(stderr, "Mausezahn will send frames infinitly...\n");
+ }
+ }
+
+
+ return 0;
+}
+
+
+
+///////////////////////////////////////////////////////////////////////
+//
+// Send complete frame (layers 2, 3, 4) multiple times if required
+//
+//
+int send_frame (libnet_t *l, libnet_ptag_t t3, libnet_ptag_t t4)
+{
+ int i=0, count;
+
+ int // local vars are faster ;-)
+ tcp_seq_delta,
+ dp_isrange,
+ sp_isrange,
+ ip_dst_isrange,
+ ip_src_isrange,
+ rtp_mode=0;
+
+
+ count = tx.count;
+ tcp_seq_delta = tx.tcp_seq_delta;
+ dp_isrange = tx.dp_isrange;
+ sp_isrange = tx.sp_isrange;
+ ip_dst_isrange = tx.ip_dst_isrange;
+ ip_src_isrange = tx.ip_src_isrange | tx.ip_src_rand;
+ if (mode == RTP) rtp_mode = 1;
+
+ if (count==0) goto AGAIN;
+
+ for (i=0; i<count; i++)
+ {
+
+ AGAIN:
+
+ if (verbose) (void) print_frame_details();
+ libnet_write(l);
+ if (mz_rand) tx.delay=(unsigned int) tx.delay*rand()/RAND_MAX;
+ if (tx.delay) SLEEP (tx.delay);
+
+ // No layer-2 modifications done here
+ // (see create_eth_frame which does L2 modifications additionally)
+
+
+ if (tcp_seq_delta)
+ {
+ if (update_TCP_SQNR(l, t4)==0) // end of range not yet reached
+ {
+ goto AGAIN;
+ }
+ }
+
+ if (dp_isrange)
+ {
+ if (update_DPORT(l, t4)==0) // end of range not yet reached
+ {
+ goto AGAIN;
+ }
+ }
+
+ if (sp_isrange)
+ {
+ if (update_SPORT(l, t4)==0) // end of range not yet reached
+ {
+ goto AGAIN;
+ }
+ }
+
+
+ if (ip_dst_isrange)
+ {
+ if (update_IP_DA(l, t3)==0) // end of range not yet reached
+ {
+ goto AGAIN;
+ }
+ }
+
+ if (ip_src_isrange) // also catches random SA (see above)
+ {
+ if (update_IP_SA(l, t3)==0) // end of range not yet reached
+ {
+ goto AGAIN;
+ }
+ }
+
+ if (rtp_mode) // update SQNR and Timestamps in RTP header and payload
+ {
+ update_RTP(l, t4);
+ }
+
+
+ if (!count) goto AGAIN;
+ }
+
+
+
+ libnet_destroy(l);
+
+ return 0;
+}
+
diff --git a/staging/send_eth.c b/staging/send_eth.c
new file mode 100644
index 0000000..ae811e8
--- /dev/null
+++ b/staging/send_eth.c
@@ -0,0 +1,491 @@
+/*
+ * Mausezahn - A fast versatile traffic generator
+ * Copyright (C) 2008 Herbert Haas
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
+ *
+*/
+
+
+
+
+// ***************************************************************************
+// This sections contains (as alternative to 'send_frame' in send.c)
+// a layer-2 based flexible sending function.
+//
+// Layer-2 modifications such as 802.1Q and MPLS is considered here!
+//
+// ***************************************************************************
+
+
+
+#include "mz.h"
+
+libnet_ptag_t create_eth_frame (libnet_t *l, libnet_ptag_t t3, libnet_ptag_t t4)
+{
+ libnet_t *L=NULL;
+ char errbuf[LIBNET_ERRBUF_SIZE];
+ libnet_ptag_t t=0, tmpls;
+ char argval[128];
+ u_int8_t et[2];
+ int et_len;
+
+ int i=0, j, mlen, mkomma, len, count, offset=0, found_colon=0;
+ char *left, *right;
+ char *f, mtag[64];
+ char verbose_mpls_string[128];
+
+ u_int8_t *packet;
+ u_int32_t packet_s;
+
+ char *saveptr, *ptrsubstring, substring[16], tmp[4*MAX_8021Q_TAGS];
+ u_int8_t CoS; // 0..7
+ u_int16_t vlan; // 12 bit value (0..4095)
+ u_int8_t dot1Q[4*MAX_8021Q_TAGS], *ptr;
+ u_int16_t dot1Q_eth_type=0x8100;
+ int bytecnt=0;
+
+ int isdot1Q, tcp_seq_delta, dp_isrange, sp_isrange, ip_dst_isrange, ip_src_isrange, eth_src_rand, rtp_mode=0;
+ unsigned int delay;
+
+
+
+
+
+
+ ////////////////////////////////////////////////////
+ // Prepare MPLS header if required
+ if (tx.mpls)
+ {
+ // first check how many labels have been specified:
+ mlen = strlen (tx.mpls_txt);
+ mkomma=0;
+
+ for (i=0; i<mlen; i++)
+ {
+ if (tx.mpls_txt[i]==',') mkomma++;
+ }
+
+ f = strtok_r (tx.mpls_txt, ",", &saveptr);
+
+ tx.mpls_bos=1;
+
+ do
+ {
+ strncpy(mtag, f, 64);
+ /*
+ if (mkomma==0)
+ {
+ tx.mpls_bos=0;
+ }
+ else
+ {
+ printf("BOS=1\n");
+ tx.mpls_bos=1;
+ }
+ */
+
+
+ if ( get_mpls_params(mtag) ) // error?
+ {
+ fprintf(stderr," mz/get_mpls_params: MPLS Parameters problem.\n");
+ exit (0);
+ }
+
+ tmpls = libnet_build_mpls(tx.mpls_label,
+ tx.mpls_exp,
+ tx.mpls_bos,
+ tx.mpls_ttl,
+ NULL,
+ 0,
+ l,
+ 0);
+
+ if (tmpls == -1)
+ {
+ fprintf(stderr, " mz/create_ip_packet: Can't build MPLS header: %s\n", libnet_geterror(l));
+ exit (0);
+ }
+
+ if (verbose)
+ {
+ sprintf(verbose_mpls_string,"[%u:%u:%u:%u]",
+ tx.mpls_label,
+ tx.mpls_exp,
+ tx.mpls_bos,
+ tx.mpls_ttl);
+ strcat(tx.mpls_verbose_string, verbose_mpls_string);
+ strcat(tx.mpls_verbose_string, " ");
+ }
+
+ tx.mpls_bos=0;
+ mkomma--;
+ }
+ while ( (f=strtok_r(NULL, ",", &saveptr)) != NULL);
+
+ }
+
+
+
+
+
+
+
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ // Evaluate Ethernet CLI options (-a and -b)
+ if (check_eth_mac_txt(ETH_DST)) // if true then problem (invalid user input?)
+ {
+ str2hex("ff:ff:ff:ff:ff:ff",tx.eth_dst, 6); // the default
+ }
+
+ // if not specified then own MAC will be used automatically
+ (void) check_eth_mac_txt(ETH_SRC);
+
+
+ // Get CLI arguments:
+ // If NOT set, default: 0x800 or ETHERTYPE_MPLS if MPLS is used (see init.c)
+ if (getarg(tx.arg_string,"ether_type", argval)==1)
+ {
+ et_len = str2hex (argval, et, 2);
+
+ if (et_len==1)
+ tx.eth_type = et[0];
+ else // 2 bytes specified
+ tx.eth_type = 256 * et[0] + et[1];
+
+ //tx.eth_type = (u_int16_t) str2int(argval);
+ }
+
+
+
+
+
+
+
+
+ /////////////////////////////////////////////////////////////////////////////////
+ // Ethernet with 802.1Q
+ //
+ // If multiple 802.1Q tags are specified then we need to build the whole
+ // frame manually because libnet only supports adding a single VLAN header.
+ // The easiest solution is to create the hex-string of the 802.1Q-chain as
+ // u_int8_t QinQ[] then add the IP packet as payload...
+ //
+ if (tx.dot1Q) // actually contains the number of VLAN tags
+ {
+
+ // we want our own context!
+ L = libnet_init(LIBNET_LINK_ADV, tx.device, errbuf);
+ if (L == NULL)
+ {
+ fprintf(stderr, "%s", errbuf);
+ exit(EXIT_FAILURE);
+ }
+
+ strncpy(tmp,tx.dot1Q_txt,(4*MAX_8021Q_TAGS));
+ ptrsubstring = strtok_r(tmp, ",.", &saveptr);
+ bytecnt=0;
+ do
+ {
+ // make a local copy
+ strncpy(substring, ptrsubstring, 16);
+ CoS=0; vlan=0;
+ // Get CoS and VLAN ID from partial string
+ len = strlen(substring);
+ found_colon=0;
+ for (i=0; i<len; i++)
+ {
+ if (substring[i]==':') found_colon=1;
+ }
+ if (found_colon) // Both CoS and VLAN specified
+ {
+ left = strtok (substring, ":");
+ right = strtok (NULL, ":");
+ CoS = (u_int8_t) str2int (left);
+ vlan = (u_int16_t) str2int (right);
+ }
+ else // Only VLAN specified
+ {
+ vlan = (u_int16_t) str2int (substring);
+ }
+
+ if (CoS > 7)
+ {
+ fprintf(stderr, " mz/create_eth_frame: CoS too high, adjusted to 7\n");
+ CoS = 7;
+ }
+
+ if (vlan > 4095)
+ {
+ fprintf(stderr, " mz/create_eth_frame: VLAN number too high, adjusted to 4095\n");
+ vlan = 4095;
+ }
+
+ // create 4 byte 802.1Q header:
+
+ dot1Q[bytecnt+0]=0x81;
+ dot1Q[bytecnt+1]=0x00;
+ ptr = (u_int8_t*) &vlan;
+ dot1Q[bytecnt+3]=*ptr;
+ ptr++;
+ *ptr = *ptr ^ (CoS<<5); // add CoS
+ dot1Q[bytecnt+2]=*ptr;
+ //check:
+ //printf("%02x %02x %02x %02x\n",dot1Q[bytecnt+0],dot1Q[bytecnt+1],dot1Q[bytecnt+2],dot1Q[bytecnt+3]);
+ bytecnt+=4; // next tag (note that bytecnt will finally hold the number of used bytes!)
+
+ } while ( (ptrsubstring = strtok_r(NULL, ",.", &saveptr)) !=NULL); //get all VLAN tags
+
+ // now create the whole packet:
+
+ dot1Q_eth_type = 0x8100; //these are also the first two bytes of dot1Q[]
+ bytecnt = bytecnt-2;
+
+ for (i=0;i<bytecnt;i++)
+ {
+ tx.eth_payload[i]=dot1Q[i+2];
+ }
+
+ // now add official EtherType for the payload (this has been determined some lines above)
+ ptr = (u_int8_t*) & tx.eth_type;
+ tx.eth_payload[i+1]= *ptr;
+ ptr++;
+ tx.eth_payload[i]= *ptr;
+ offset = i+2;
+
+ // -
+ // --
+ // ---
+ // ---- now all 802.1Q headers are genereated ----
+ // ---- and are placed already in tx.eth_payload ----
+ // ---- (and 'i' points to the next free byte) ----
+ // ---
+ // --
+ // -
+
+ // Finally get all bytes of upper layers (IP packet and payload)
+ if (libnet_adv_cull_packet(l, &packet, &packet_s) == -1)
+ {
+ fprintf(stderr, "%s", libnet_geterror(l));
+ }
+
+ // Copy the upper layer data to the eth_payload
+ for (j=0; j<packet_s; j++)
+ {
+ tx.eth_payload[j+offset]=packet[j];
+ }
+
+ // 'libnet_adv_cull_packet' performs an implicit malloc() and a corresponding call
+ // to libnet_adv_free_packet() should be made to free the memory packet occupies:
+ libnet_adv_free_packet(l, packet);
+
+ tx.eth_payload_s = j+offset;
+ tx.eth_type = dot1Q_eth_type;
+
+ t = libnet_build_ethernet (tx.eth_dst,
+ tx.eth_src,
+ tx.eth_type,
+ tx.eth_payload,
+ tx.eth_payload_s,
+ L,
+ 0);
+
+ if (t == -1)
+ {
+ fprintf(stderr, " mz/create_eth_frame: Can't build Ethernet header: %s\n",
+ libnet_geterror(l));
+ exit(EXIT_FAILURE);
+ }
+
+ // NOW the whole frame is ready to send!
+
+ }
+
+ else // normal Ethernet header without any 802.1Q-tag or MPLS-label
+
+ {
+
+ t = libnet_build_ethernet (tx.eth_dst,
+ tx.eth_src,
+ tx.eth_type,
+ NULL, // the payload
+ 0,
+ l,
+ 0);
+
+ if (t == -1)
+ {
+ fprintf(stderr, " mz/create_eth_frame: Can't build Ethernet header: %s\n",
+ libnet_geterror(l));
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ /////////////////////////////////////////////////////////////////////////////
+ //
+ // Now send everything - maybe lots of times with modifications.
+ //
+ //
+
+ // local vars are faster :-)
+ count = tx.count;
+ delay = tx.delay;
+ eth_src_rand = tx.eth_src_rand;
+ tcp_seq_delta = tx.tcp_seq_delta;
+ dp_isrange = tx.dp_isrange;
+ sp_isrange = tx.sp_isrange;
+ ip_dst_isrange = tx.ip_dst_isrange;
+ ip_src_isrange = tx.ip_src_isrange | tx.ip_src_rand; // either case should call update_SA()
+ isdot1Q = tx.dot1Q;
+ if (mode == RTP) rtp_mode = 1;
+
+ if (count==0) goto AGAIN;
+
+ for (i=0; i<count; i++)
+ {
+
+ AGAIN:
+
+ if (isdot1Q)
+ {
+ // Get all bytes of upper layers (IP packet and payload)
+ if (libnet_adv_cull_packet(l, &packet, &packet_s) == -1)
+ {
+ fprintf(stderr, "%s", libnet_geterror(l));
+ }
+
+ // Copy the upper layer data to the eth_payload
+ for (j=0; j<packet_s; j++)
+ {
+ tx.eth_payload[j+offset]=packet[j];
+ }
+
+ // 'libnet_adv_cull_packet' performs an implicit malloc() and a corresponding call
+ // to libnet_adv_free_packet() should be made to free the memory packet occupies:
+ libnet_adv_free_packet(l, packet);
+
+ if (eth_src_rand) update_Eth_SA(L, t);
+
+ t = libnet_build_ethernet (tx.eth_dst,
+ tx.eth_src,
+ tx.eth_type,
+ tx.eth_payload,
+ tx.eth_payload_s,
+ L,
+ t);
+ if (t == -1)
+ {
+ fprintf(stderr, " mz/create_eth_frame: Can't build Ethernet header: %s\n",
+ libnet_geterror(l));
+ exit(EXIT_FAILURE);
+ }
+ if (verbose) (void) print_frame_details();
+ libnet_write(L);
+ }
+ else // No QinQ and/or MPLS modifications => use normal 'l' context:
+ {
+ if (eth_src_rand) update_Eth_SA(l, t);
+ if (verbose) (void) print_frame_details();
+ libnet_write(l);
+ }
+
+
+// if (verbose) (void) print_frame_details();
+ if (delay) SLEEP (delay);
+
+
+ if (tcp_seq_delta)
+ {
+ if (update_TCP_SQNR(l, t4)==0) // end of range not yet reached
+ {
+ goto AGAIN;
+ }
+ }
+
+ if (dp_isrange)
+ {
+ if (update_DPORT(l, t4)==0) // end of range not yet reached
+ {
+ goto AGAIN;
+ }
+ }
+
+ if (sp_isrange)
+ {
+ if (update_SPORT(l, t4)==0) // end of range not yet reached
+ {
+ goto AGAIN;
+ }
+ }
+
+ if (ip_dst_isrange)
+ {
+ if (update_IP_DA(l, t3)==0) // end of range not yet reached
+ {
+ goto AGAIN;
+ }
+ }
+
+ if (ip_src_isrange)
+ {
+ if (update_IP_SA(l, t3)==0) // end of range not yet reached
+ {
+ goto AGAIN;
+ }
+ }
+
+
+ if (rtp_mode) // update SQNR and Timestamps in RTP header and payload
+ {
+ update_RTP(l, t4);
+ }
+
+
+ if (!count) goto AGAIN;
+ }
+
+
+ libnet_destroy(l);
+ if (isdot1Q)
+ libnet_destroy(L);
+
+
+ return t;
+}
+
+
+
+void print_dot1Q_help(void)
+{
+
+ fprintf(stderr,"\n"
+ MAUSEZAHN_VERSION
+ "\n"
+ "| 802.1Q header Syntax: -Q tag[,tag[,tag[,...]]]\n"
+ "| where each tag may consist of a CoS value using the syntax:\n"
+ "|\n"
+ "| <CoS>:<tag value>\n"
+ "|\n"
+ "| Examples:\n"
+ "|\n"
+ "| # mz -Q 100\n"
+ "| # mz -Q 5:100\n"
+ "| # mz -Q 5:100,200\n"
+ "| # mz -Q 5:100,7:200\n"
+ "| # mz -Q 100,200,300,5:400\n"
+ "\n\n");
+
+ exit(0);
+}
+
+
diff --git a/staging/syslog.c b/staging/syslog.c
new file mode 100644
index 0000000..c8fac9b
--- /dev/null
+++ b/staging/syslog.c
@@ -0,0 +1,248 @@
+/*
+ * Mausezahn - A fast versatile traffic generator
+ * Copyright (C) 2008,2009 Herbert Haas
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
+ *
+*/
+
+
+#include "mz.h"
+#include "cli.h"
+
+#define MZ_SYSLOG_HELP \
+ "| Syslog type: Send (traditional) Syslog packets via UDP.\n" \
+ "|\n" \
+ "| Parameters:\n" \
+ "|\n" \
+ "| severity, sev 0-7 .... Severity level from Emergency (0) to Debug (7)\n" \
+ "| facility, fac 0-23 .... Facility number\n" \
+ "|\n" \
+ "| time hh:mm:ss .... Local time, 24-hour format\n" \
+ "| month, mon Mmm .... Current month, 1-12\n" \
+ "| day dd .... Current day, 0-31\n" \
+ "|\n" \
+ "| host max 314 bytes .... Name or IP Address of sending host\n" \
+ "|\n" \
+ "| Defaults:\n" \
+ "|\n" \
+ "| Per default the severity \"Warning\" (4), the facility \"Security\" (4), and the\n" \
+ "| current time stamp is used. If no host is given, host is set to \"MZ\"\n" \
+ "|\n" \
+ "| You can define the Syslog message itself using the -P flag. For example:\n" \
+ "|\n" \
+ "| mz eth0 -t syslog sev=3 -P \"You have been mausezahned.\"\n" \
+ "|\n" \
+ "| By the way, mz (by intention) does not check if your timestamp is valid according\n" \
+ "| calendar rules. It is generally recommended to follow the Darwin Era Calendar ;-)\n" \
+ "|\n"
+
+
+
+// RFC 3164 states that a Syslog message consists of three parts: PRI, HEADER, and MSG.
+//
+// 1) PRI: contains facility(f) and severity(s), using the syntax "<N>" where N = f * 8 + s
+//
+// 2) HEADER: contains a timestamp and a sender-ID (name or IP), for example "May 25 23:42:42 Mausezahnhost"
+// Note that instead of leading zeroes a space must be used for the day e. g. "May 5".
+// However leading zeroes are required for hour, minutes, seconds, e. g. "01:05:09"
+//
+// 3) MSG: consists of TAG and CONTENT field. The TAG identifies the program or process and
+// must not exceed 32 characters. Typically the TAG and the CONTENT fields are delimited
+// via either a "[", or a colon (:) or a space. The CONTENT field is a simple text.
+//
+// EXAMPLE from RFC 3164:
+//
+// <34>Oct 11 22:14:15 mymachine su: 'su root' failed for lonvick on /dev/pts/8
+//
+// EXAMPLE from Cisco Router:
+//
+// *Mar 23 13:45:08.727: %ENVMON-3-FAN_FAILED: Fan 2 not rotating
+//
+
+
+int create_syslog_packet()
+{
+ unsigned int pri, sev, fac, day, curday, mon, curmon;
+ char lt[8], host[314];
+ char *Months[12] =
+ { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
+
+
+ time_t curtime;
+ struct tm curtime_broken;
+ char argval[MAX_PAYLOAD_SIZE];
+ int ca=0, aa;
+
+ aa=number_of_args(tx.arg_string);
+
+ if ( (getarg(tx.arg_string,"help", NULL)==1) && (mode==SYSLOG) )
+ {
+ ca++; // counts each argument
+ if (mz_port)
+ {
+ cli_print(gcli, "%s", MZ_SYSLOG_HELP);
+ return -1;
+ }
+ else
+ {
+ fprintf(stderr,"\n"
+ MAUSEZAHN_VERSION
+ "\n%s", MZ_SYSLOG_HELP);
+
+ exit(0);
+ }
+ }
+
+
+ if ( (getarg(tx.arg_string,"severity", argval)==1) ||
+ (getarg(tx.arg_string,"sev", argval)==1) )
+ {
+ ca++; // counts each argument
+ sev = (unsigned int) str2int(argval);
+ }
+ else
+ {
+ sev = 4;
+ }
+
+ if ( (getarg(tx.arg_string,"facility", argval)==1) ||
+ (getarg(tx.arg_string,"fac", argval)==1) )
+ {
+ ca++; // counts each argument
+ fac = (unsigned int) str2int(argval);
+ }
+ else
+ {
+ fac = 4;
+ }
+
+
+ time(&curtime);
+ localtime_r (&curtime, &curtime_broken);
+
+
+
+ if (getarg(tx.arg_string,"time", argval)==1)
+ {
+ ca++; // counts each argument
+ strncpy(lt,argval,8);
+ // TODO: check if specified timestamp has valid format, e. g. 15:03:22
+ }
+ else
+ {
+ timestamp_hms (lt);
+ }
+
+
+
+ curmon = curtime_broken.tm_mon; // Note that Jan = 0, ..., Dec = 11 !!!
+
+ if ( (getarg(tx.arg_string,"month", argval)==1) ||
+ (getarg(tx.arg_string,"mon", argval)==1) )
+ {
+ ca++; // counts each argument
+ mon = (unsigned int) str2int(argval);
+ if ( (mon<1) || (mon>12) )
+ {
+ fprintf(stderr, " mz/syslog: Invalid month; will use current month (%i)!\n", curmon+1);
+ mon = curmon;
+ }
+ }
+ else
+ {
+ mon = curmon;
+ }
+
+ curday = curtime_broken.tm_mday;
+
+ if (getarg(tx.arg_string,"day", argval)==1)
+ {
+ ca++; // counts each argument
+ day = (unsigned int) str2int(argval);
+ if ( (day<1) || (day>31) )
+ {
+ fprintf(stderr, " mz/syslog: Invalid day; will use current day(%i)!\n", curday);
+ day = curday;
+ }
+ }
+ else
+ {
+ day = curday;
+ }
+
+
+ if (getarg(tx.arg_string,"host", argval)==1)
+ {
+ ca++; // counts each argument
+ strncpy(host,argval,314); // 314 is just an arbitrary number ;-)
+ }
+ else
+ {
+ strcpy(host, "MZ42");
+ }
+
+
+ // CHECK SURPLUS ARGUMENTS
+ if (aa!=ca) {
+ fprintf(stderr, "WARNING: %i unmatched arguments within argument string!\n", aa-ca);
+ }
+
+
+ // Now put everything together:
+ //
+ // Again the EXAMPLE from RFC 3164:
+ //
+ // <34>Oct 11 22:14:15 mymachine su: 'su root' failed for lonvick on /dev/pts/8
+ //
+
+
+ pri = 8*fac+sev;
+
+ sprintf((char*) tx.udp_payload, "<%d>%s %2i %s %s ",
+ pri,
+ Months[mon],
+ day,
+ lt,
+ host);
+
+ if (tx.ascii) // ASCII PAYLOAD overrides hex payload
+ {
+ strncat((char *)tx.udp_payload, (char *)tx.ascii_payload, 2048);
+ tx.ascii=0; // avoid that 'create_udp_packet' overwrites this!
+ }
+ else
+ {
+ strcat((char *)tx.udp_payload, "%MZSYS-42-CRN: Main reactor exceeded critical temperature!");
+ }
+
+
+ tx.udp_payload_s = strlen((char *)tx.udp_payload);
+
+ tx.dp = 514;
+ tx.sp = 514;
+
+ tx.udp_len = 8 + tx.udp_payload_s;
+
+ if (verbose)
+ {
+ fprintf(stderr, "Syslog: %s\n", tx.udp_payload);
+ }
+
+
+ return 0;
+
+}
+
+
+
diff --git a/staging/time.c b/staging/time.c
new file mode 100644
index 0000000..4225b9e
--- /dev/null
+++ b/staging/time.c
@@ -0,0 +1,211 @@
+/*
+ * Mausezahn - A fast versatile traffic generator
+ * Copyright (C) 2008-2010 Herbert Haas
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
+ *
+*/
+
+
+#include "mz.h"
+
+
+// Check if current system supports the nanosecond timer functions.
+// Additionally, measure the precision.
+// This function should be called upon program start.
+//
+int check_timer()
+{
+ struct timespec res;
+ int r;
+
+// Check if the glibc is recent enough:
+#ifdef _POSIX_C_SOURCE
+
+ if (_POSIX_C_SOURCE >= 199309L) {
+ r = clock_getres(CLOCK_MONOTONIC, &res);
+ if (r!=0) perror(" mz/check_timer:");
+ if (verbose) {
+ fprintf(stderr, " This system supports a high resolution clock.\n");
+ fprintf(stderr, " The clock resolution is %li nanoseconds.\n",
+ res.tv_nsec);
+ }
+ }
+ else {
+ fprintf(stderr,
+ " WARNING: Your system does NOT support the newer high resolution clock\n"
+ " Please inform the author: herbert@perihel.at\n");
+ exit(1);
+ }
+#endif
+ return 0;
+}
+
+
+
+
+// This is the replacement for gettimeofday() which would result in 'jumps' if
+// the system clock is adjusted (e. g. via a NTP process) and finally the jitter
+// measurement would include wrong datapoints.
+//
+// Furthermore the function below utilizes the newer hi-res nanosecond timers.
+inline void getcurtime (struct mz_timestamp *t)
+{
+ struct timespec ct;
+ clock_gettime(CLOCK_MONOTONIC, &ct);
+ t->sec = ct.tv_sec;
+ t->nsec = ct.tv_nsec;
+}
+
+
+
+
+//////////////////////////////////////////////////////////////////////////////////////
+// Purpose: Calculate time deltas of two timestamps stored in struct timeval.
+//
+// Subtract the "struct timeval" values X and Y, storing the result in RESULT,
+// i. e. X-Y=RESULT.
+//
+// RETURN VALUES:
+//
+// Sign: 1 = negative, 0 = positive
+// Error: -1 due to a wrong timestamp (i. e. nsec > 999999999L)
+//
+inline int timestamp_subtract (struct mz_timestamp *x, struct mz_timestamp *y, struct mz_timestamp *result)
+{
+ int32_t ndiff;
+ int sign=0, carry=0;
+
+ // Check for wrong timestamps
+ if ((x->nsec>999999999L) || (y->nsec>999999999L)) return -1;
+
+ if (y->sec > x->sec) sign=1;
+ else if ((y->sec == x->sec) && (y->nsec > x->nsec)) sign=1;
+
+ ndiff = x->nsec - y->nsec;
+ if ((ndiff>0) && (sign)) carry=1;
+ if ((ndiff<0) && (sign)) ndiff = y->nsec - x->nsec;
+ if ((ndiff<0) && (!sign)) {
+ ndiff = 1000000000L + ndiff;
+ carry=1;
+ }
+
+ if (sign)
+ result->sec = y->sec - x->sec - carry;
+ else
+ result->sec = x->sec - y->sec - carry;
+
+ result->nsec = ndiff;
+ return sign;
+}
+
+
+// Add two variables of type struct mz_timestamp: x+y=result.
+//
+inline void timestamp_add (struct mz_timestamp *x, struct mz_timestamp *y, struct mz_timestamp *result)
+{
+ int carry=0;
+ u_int32_t c;
+
+ c = x->nsec + y->nsec;
+ if (c>999999999L) {
+ carry=1;
+ result->nsec =c-1000000000;
+ } else result->nsec =c;
+
+ result->sec = x->sec + y->sec + carry;
+}
+
+
+
+// Returns a human readable timestamp in the string result.
+// Optionally a prefix can be specified, for example if the
+// timestamp is part of a filename.
+//
+// Example:
+// char myTimeStamp[128];
+//
+// timestamp_human(myTimeStamp, NULL);
+//
+// => "20080718_155521"
+//
+// /* or with prefix */
+//
+// timestamp_human(myTimeStamp, "MZ_RTP_jitter_");
+//
+// => "MZ_RTP_jitter_20080718_155521"
+//
+int timestamp_human(char* result, const char* prefix)
+{
+ time_t curtime;
+ struct tm curtime_broken;
+ char curtime_str[32];
+
+ time(&curtime);
+ localtime_r (&curtime, &curtime_broken);
+
+ sprintf(curtime_str, "%4i%02i%02i-%02i%02i%02i",
+ curtime_broken.tm_year+1900,
+ curtime_broken.tm_mon+1,
+ curtime_broken.tm_mday,
+ curtime_broken.tm_hour,
+ curtime_broken.tm_min,
+ curtime_broken.tm_sec);
+
+ if (prefix==NULL)
+ {
+ strncpy(result, curtime_str, 32);
+ }
+ else
+ {
+ strncpy(result, prefix, 32);
+ strncat(result, curtime_str, 32);
+ }
+
+ return 0;
+}
+
+
+// Creates a human readable timestamp in the string result.
+// Optionally a prefix can be specified, for example if the
+// timestamp is part of a filename.
+//
+// Example:
+// char myTimeStamp[9];
+//
+// timestamp_hms (myTimeStamp);
+//
+// => "15:55:21"
+int timestamp_hms(char* result)
+{
+ time_t curtime;
+ struct tm curtime_broken;
+ char curtime_str[32];
+
+ time(&curtime);
+ localtime_r (&curtime, &curtime_broken);
+
+ sprintf(curtime_str, "%02i:%02i:%02i",
+ curtime_broken.tm_hour,
+ curtime_broken.tm_min,
+ curtime_broken.tm_sec);
+
+ strncpy(result, curtime_str, 9);
+
+ return 0;
+}
+
+
+
+
+
diff --git a/staging/tools.c b/staging/tools.c
new file mode 100644
index 0000000..96f0bb7
--- /dev/null
+++ b/staging/tools.c
@@ -0,0 +1,1344 @@
+/*
+ * Mausezahn - A fast versatile traffic generator
+ * Copyright (C) 2008-2010 Herbert Haas
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
+ *
+*/
+
+
+
+////////////////////////////////////////////////////////////////////////////////////////////
+//
+// Contains various tools to ease development of new modules:
+//
+// getarg ............. scans string for arguments and returns assigned value
+// str2int ............. Converts a string into unsigned long int in a safe way
+// str2lint ............ Same as str2int but returns an unsigned long long int
+// xstr2int ............ Same as str2int but expects hex digits
+// xstr2lint ........... Same as above but returns an unsigned long long int
+// get_ip_range_dst .... Parses string for an IP range and sets start/stop addresses
+// get_ip_range_src .... Same for source addresses
+// check_eth_mac_txt ... Scans tx.eth_dst|src_txt and sets tx.eth_dst|src appropriately
+// get_port_range ...... Parses string for a dst|src-port range and sets start/stop values
+// get_tcp_flags ....... Parses string for TCP arguments and sets tx.tcp_control
+// get_mpls_params ..... Parses string for MPLS parameters (label, exp, BOS, TTL)
+// exists .............. Parses a string for a single character and returns "1" if found
+// mz_strisbinary ...... Checks whether string consists only of 0 and 1, returns how many digits total
+// str2bin8 ............ Converts a string containing max 8 binary digits into a number
+// str2bin16 ........... Converts a string containing max 16 binary digits into a number
+// char2bits ........... Converts a char into a string containing ones and zeros
+// getfullpath_cfg ..... Creates a full filename with path to the desired config directory
+// getfullpath_log ..... Creates a full filename with path to the desired logging directory
+// mz_strncpy .......... A safer implementation of strncpy
+// number_of_args ...... Returns number of arguments of the Mausezahn argument string
+// mz_strisnum ......... Returns 1 if string only consists of decimal digits
+// mz_strishex ......... Returns 1 if string only consists of hexadecimal digits
+// mz_strcmp ........... Matches a string or a prefix of it with given min-length
+// Example usage: User CLI input
+// mz_tok .............. Decomposes a string into tokens and maps them to args
+// Example usage: IPv6-addresses, user input for MPLS-tags
+// delay_parse ......... Parses one or two strings for a delay specification and sets a struct timespec
+//
+////////////////////////////////////////////////////////////////////////////////////////////
+
+#include "mz.h"
+
+
+
+// Scan 'str' for an argument 'arg_name' and returns its value in arg_value
+// Return value: number of occurences of arg_name
+// Note that if arg_name occurs multiple times, the last found value is returned.
+// If last argument (arg_value) is set to NULL it will be ignored.
+// Example:
+// int i;
+// char ip[64];
+// i = getarg ("request, da=10.1.1.2, SYN", "da", ip);
+// ...will assign "10.1.1.2" to ip and the occurence i is set to 1.
+int getarg(char *str, char *arg_name, char *arg_value)
+{
+ char tmp[MAX_PAYLOAD_SIZE];
+ char *str1, *str2, *token, *subtoken;
+ char *saveptr1, *saveptr2;
+ int j, occurence=0;
+
+ strncpy(tmp,str,MAX_PAYLOAD_SIZE); // only operate on local strings
+
+ for (j = 1, str1 = tmp; ; j++, str1 = NULL)
+ {
+
+ token = strtok_r(str1, ",", &saveptr1);
+ if (token == NULL)
+ break;
+
+ str2 = token;
+ if ( (subtoken = strtok_r(str2, " =", &saveptr2))!=NULL)
+ {
+ if (strcasecmp(subtoken,arg_name)==0)
+ {
+ occurence+=1;
+ //printf("found %s\n",arg_name);
+ if ( (subtoken = strtok_r(NULL, " =", &saveptr2))!=NULL)
+ {
+ // argument has a value!
+ //printf("%s has value: [%s]\n",arg_name, subtoken);
+ if (arg_value!=NULL)
+ {
+ strcpy(arg_value,subtoken);
+ }
+ }
+ }
+ }
+ else
+ break;
+ }
+ return occurence;
+}
+
+
+// Convert str to (unsigned long) int
+// Return value: the unsigned long int
+unsigned long int str2int(char *str)
+{
+ unsigned long int i;
+
+ errno=0;
+
+ i = strtoul(str, (char **)NULL, 10);
+
+ if ((errno == ERANGE && (i == ULONG_MAX))
+ || (errno != 0 && i == 0))
+ {
+ perror("strtoul");
+ }
+
+ return i;
+}
+
+
+
+// Convert str to (unsigned long long) int
+// Return value: the unsigned long long int
+unsigned long long int str2lint(char *str)
+{
+ unsigned long long int i;
+
+ errno=0;
+
+ i = strtoull(str, (char **)NULL, 10);
+
+ if ((errno == ERANGE && (i == ULLONG_MAX))
+ || (errno != 0 && i == 0))
+ {
+ perror("strtoull");
+ }
+
+ return i;
+}
+
+
+// Convert hex-str to (unsigned long) int
+// Return value: the unsigned long int
+unsigned long int xstr2int(char *str)
+{
+ unsigned long int i;
+
+ errno=0;
+
+ i = strtoul(str, (char **)NULL, 16);
+
+ if ((errno == ERANGE && (i == ULONG_MAX))
+ || (errno != 0 && i == 0))
+ {
+
+ perror("strtoul");
+ }
+
+ return i;
+}
+
+
+// Convert hex-str to (unsigned long long) int
+// Return value: the unsigned long long int
+unsigned long long int xstr2lint(char *str)
+{
+ unsigned long long int i;
+
+ errno=0;
+
+ i = strtoull(str, (char **)NULL, 16);
+
+ if ((errno == ERANGE && (i == ULLONG_MAX))
+ || (errno != 0 && i == 0))
+ {
+ perror("strtoull");
+ }
+
+ return i;
+}
+
+
+
+
+// Parses string 'arg' for an IP range and finds start and stop IP addresses.
+// Return value: 0 upon success, 1 upon failure.
+//
+// NOTE: The results are written in the following variables:
+//
+// (u_int32_t) tx.ip_dst_start ... contains start value
+// (u_int32_t) tx.ip_dst_stop ... contains stop value
+// (u_int32_t) tx.ip_dst ... initialized with start value
+// int tx.ip_dst_isrange ... set to 1 if above values valid
+//
+// Possible range specifications:
+//
+// 1) 192.168.0.0-192.168.0.12
+// 2) 10.2.11.0-10.55.13.2
+// 3) 172.18.96.0/19
+//
+// That is:
+//
+// FIRST detect a range by scanning for the "-" OR "/" chars
+// THEN determine start and stop value and store them as normal unsigned integers
+//
+int get_ip_range_dst (char *arg)
+{
+
+ int
+ i, len,
+ found_slash=0, found_dash=0;
+
+ unsigned int q;
+ u_int32_t mask, invmask;
+
+ char *start_str, *stop_str;
+
+ len = strnlen(arg, 32);
+
+ if ( (len>31) || (len<9) ) // 255.255.255.200-255.255.255.255 (31 chars) OR 1.0.0.0/8 (9 chars)
+ return 1; // ERROR: no range
+
+ // Find "-" or "/"
+ for (i=0; i<len; i++)
+ {
+ if (arg[i]=='/') found_slash=1;
+ if (arg[i]=='-') found_dash=1;
+ }
+
+ if ((found_slash) && (found_dash))
+ exit (1); // ERROR: Wrong range string syntax (cannot use both "/" and "-" !!!
+
+ if (found_dash)
+ {
+ start_str = strtok (arg, "-");
+ stop_str = strtok (NULL, "-");
+
+ // These are the start and stop IP addresses of the range:
+ tx.ip_dst_start = str2ip32 (start_str);
+ tx.ip_dst_stop = str2ip32 (stop_str);
+ tx.ip_dst_h = tx.ip_dst_start;
+ tx.ip_dst = str2ip32_rev (start_str);
+
+ if (tx.ip_dst_start < tx.ip_dst_stop)
+ {
+ // Set range flag:
+ tx.ip_dst_isrange = 1;
+ return 0;
+ }
+ else
+ {
+ tx.ip_dst_isrange = 0;
+ return 1; // ERROR: stop value must be greater than start value !!!
+ }
+ }
+ else if (found_slash)
+ {
+ start_str = strtok (arg, "/");
+ stop_str = strtok (NULL, "/"); // Actually contains the prefix length, e. g. "24"
+
+ q = (unsigned int) str2int (stop_str);
+
+ mask = 0xffffffff;
+ mask <<= (32-q);
+ invmask = 0xffffffff - mask;
+
+ tx.ip_dst_start = (str2ip32 (start_str) & mask) +1; // the '+1' is to ensure that we do not start with the net-id
+ tx.ip_dst_stop = tx.ip_dst_start | invmask;
+ tx.ip_dst_h = tx.ip_dst_start;
+ tx.ip_dst = str2ip32_rev (start_str) | 0x01000000; // the '0x01000000' is to ensure that we do not start with the net-id
+ tx.ip_dst_isrange = 1;
+ return 0;
+ }
+
+
+ return 1; // ERROR: The specified argument string is not a range!
+
+}
+
+
+
+
+// Parses string 'arg' for an IP range and finds start and stop IP addresses.
+// Return value: 0 upon success, 1 upon failure.
+//
+// NOTE: The results are written in the following variables:
+//
+// (u_int32_t) tx.ip_src_start ... contains start value
+// (u_int32_t) tx.ip_src_stop ... contains stop value
+// (u_int32_t) tx.ip_src ... initialized with start value
+// int tx.ip_src_isrange ... set to 1 if above values valid
+//
+// Possible range specifications:
+//
+// 1) 192.168.0.0-192.168.0.12
+// 2) 10.2.11.0-10.55.13.2
+// 3) 172.18.96.0/19
+//
+// That is:
+//
+// FIRST detect a range by scanning for the "-" OR "/" chars
+// THEN determine start and stop value and store them as normal unsigned integers
+//
+int get_ip_range_src (char *arg)
+{
+
+ int
+ i, len,
+ found_slash=0, found_dash=0;
+
+ unsigned int q;
+ u_int32_t mask, invmask;
+
+ char *start_str, *stop_str;
+
+
+ len = strnlen(arg,32);
+
+ if ( (len>31) || (len<9) ) // 255.255.255.200-255.255.255.255 (31 chars) OR 1.0.0.0/8 (9 chars)
+ return 1; // ERROR: no range
+
+ // Find "-" or "/"
+ for (i=0; i<len; i++)
+ {
+ if (arg[i]=='/') found_slash=1;
+ if (arg[i]=='-') found_dash=1;
+ }
+
+ if ((found_slash) && (found_dash))
+ exit (1); // ERROR: Wrong range string syntax (cannot use both "/" and "-" !!!
+
+ if (found_dash)
+ {
+ start_str = strtok (arg, "-");
+ stop_str = strtok (NULL, "-");
+
+ // These are the start and stop IP addresses of the range:
+ tx.ip_src_start = str2ip32 (start_str);
+ tx.ip_src_stop = str2ip32 (stop_str);
+ tx.ip_src_h = tx.ip_src_start;
+ tx.ip_src = str2ip32_rev (start_str);
+
+ if (tx.ip_src_start < tx.ip_src_stop)
+ {
+ // Set range flag:
+ tx.ip_src_isrange = 1;
+ return 0;
+ }
+ else
+ {
+ tx.ip_src_isrange = 0;
+ return 1; // ERROR: stop value must be greater than start value !!!
+ }
+ }
+ else if (found_slash)
+ {
+ start_str = strtok (arg, "/");
+ stop_str = strtok (NULL, "/"); // Actually contains the prefix length, e. g. "24"
+
+ q = (unsigned int) str2int (stop_str);
+
+ mask = 0xffffffff;
+ mask <<= (32-q);
+ invmask = 0xffffffff - mask;
+
+ tx.ip_src_start = (str2ip32 (start_str) & mask) +1; // the '+1' is to ensure that we do not start with the net-id
+ tx.ip_src_stop = tx.ip_src_start | invmask;
+ tx.ip_src_h = tx.ip_src_start;
+ tx.ip_src = str2ip32_rev (start_str) | 0x01000000; // the '0x01000000' is to ensure that we do not start with the net-id
+ tx.ip_src_isrange = 1;
+ return 0;
+ }
+
+ return 1; // ERROR: The specified argument string is not a range!
+
+}
+
+
+// Scans tx.eth_dst_txt or tx.eth_src_txt and sets the corresponding
+// MAC addresses (tx.eth_dst or tx.eth_src) accordingly.
+// Argument: What string should be checked, ETH_SRC or ETH_DST.
+//
+// Return value:
+// 0 when a MAC address has been set or
+// 1 when not set (or wrongly set)
+//
+// Currently eth_src|dst_txt can be:
+// 'rand', 'own', 'bc'|'bcast', 'stp', 'pvst', 'cisco',
+// or a real mac address.
+//
+// TODO: implement other important MAC addresses
+int check_eth_mac_txt(int src_or_dst)
+{
+ char *eth_mac_txt;
+ u_int8_t *eth_mac;
+ int *eth_rand;
+ int i;
+
+ // Check argument
+ if (src_or_dst == ETH_SRC)
+ {
+ eth_mac_txt = tx.eth_src_txt;
+ eth_mac = tx.eth_src;
+ eth_rand = &tx.eth_src_rand;
+ }
+ else if (src_or_dst == ETH_DST)
+ {
+ eth_mac_txt = tx.eth_dst_txt;
+ eth_mac = tx.eth_dst;
+ eth_rand = &tx.eth_dst_rand;
+ }
+ else
+ {
+ return 1; // wrong argument
+ }
+
+
+ // Did the user really specify a dst-address?
+ if (strnlen(eth_mac_txt, 18)==0)
+ {
+ return 1; // No.
+ }
+
+
+ // Okay, lets check the commandline argument:
+ //
+ // Do you want a random MAC?
+ // TODO: Consider enforcement of unicast addresses
+ if (strncmp(eth_mac_txt, "rand", 4)==0)
+ {
+ eth_mac[0] = (u_int8_t) ( ((float) rand()/RAND_MAX)*256);
+ eth_mac[1] = (u_int8_t) ( ((float) rand()/RAND_MAX)*256);
+ eth_mac[2] = (u_int8_t) ( ((float) rand()/RAND_MAX)*256);
+ eth_mac[3] = (u_int8_t) ( ((float) rand()/RAND_MAX)*256);
+ eth_mac[4] = (u_int8_t) ( ((float) rand()/RAND_MAX)*256);
+ eth_mac[5] = (u_int8_t) ( ((float) rand()/RAND_MAX)*256);
+ *eth_rand = 1;
+ }
+ // Do you want your own interface MAC?
+ else if (strncmp(eth_mac_txt, "own", 3)==0)
+ {
+ for (i=0; i<6; i++)
+ {
+ eth_mac[i] = tx.eth_mac_own[i];
+ }
+ }
+ // Do you want a broadcast MAC?
+ else if (strncmp(eth_mac_txt, "bc", 2)==0) // NOTE that this also fetches "bcast"
+ {
+ str2hex_mac("FF:FF:FF:FF:FF:FF", eth_mac);
+ }
+ // Do you want the IEEE address 'all bridges' used for STP?
+ else if (strncmp(eth_mac_txt, "stp", 3)==0) //
+ {
+ str2hex_mac("01:80:C2:00:00:00", eth_mac); // IEEE for all bridges
+ }
+ // Do you want the Cisco address e. g. for CDP, VTP?
+ else if (strncmp(eth_mac_txt, "cisco", 5)==0)
+ {
+ str2hex_mac("01:00:0C:CC:CC:CC", eth_mac);
+ }
+ // Do you want the Cisco address e. g. for CDP, VTP?
+ else if (strncmp(eth_mac_txt, "pvst", 5)==0)
+ {
+ str2hex_mac("01:00:0C:CC:CC:CD", eth_mac);
+ }
+ // The string MUST contain a mac address
+ // TODO: CHECK whether the string has correct format for a mac address!
+ else
+ {
+ str2hex_mac(eth_mac_txt, eth_mac);
+ }
+
+ return 0;
+}
+
+
+
+
+
+// Scans argument for a port number or range and sets
+// the corresponding values in the tx struct:
+//
+// a) tx.sp_start, tx.sp_stop, tx.sp = tx.sp_start
+//
+// ** OR **
+//
+// b) tx.dp_start, tx.dp_stop, tx.dp = tx.dp_start
+//
+// Arguments:
+//
+// - 'sp_or_dp' is either SRC_PORT or DST_PORT
+// - 'arg' contains the port range as string such as 1-1024
+//
+// Return value: 0 on success, 1 upon failure
+//
+int get_port_range (int sp_or_dp, char *arg)
+{
+
+ int i, len, found_dash=0;
+
+ u_int32_t tmp1, tmp2;
+
+ u_int16_t
+ *port,
+ *start,
+ *stop;
+ int
+ *isrange;
+
+ char *start_str, *stop_str;
+
+
+ // Check which port to manage
+ if (sp_or_dp == DST_PORT)
+ {
+ port = &tx.dp;
+ start = &tx.dp_start;
+ stop = &tx.dp_stop;
+ isrange = &tx.dp_isrange;
+ }
+ else if (sp_or_dp == SRC_PORT)
+ {
+ port = &tx.sp;
+ start = &tx.sp_start;
+ stop = &tx.sp_stop;
+ isrange = &tx.sp_isrange;
+ }
+ else
+ {
+ return 1; // error
+ }
+
+
+ len = strnlen(arg,12);
+ if (len==0) return 1; // error
+
+ // Find "-"
+ for (i=0; i<len; i++)
+ {
+ if (arg[i]=='-') found_dash=1;
+ }
+
+ if (found_dash) // range specified
+ {
+ start_str = strtok (arg, "-");
+ stop_str = strtok (NULL, "-");
+
+ tmp1 = str2int (start_str);
+ if ( (tmp1<0)||(tmp1>65535))
+ {
+ fprintf(stderr," mz/get_port_range: Invalid port range!\n");
+ exit (-1);
+ }
+ *start = tmp1;
+
+ tmp2 = str2int (stop_str);
+ if ( (tmp2<0)||(tmp2>65535))
+ {
+ fprintf(stderr," mz/get_port_range: Invalid port range!\n");
+ exit (-1);
+ }
+ *stop = tmp2;
+
+ if (tmp1>tmp2) // swap start/stop values!
+ {
+ *start = tmp2;
+ *stop = tmp1;
+ }
+
+ *port = *start;
+ *isrange = 1;
+
+ return 0;
+ }
+ else // single port number
+ {
+ tmp1 = str2int (arg);
+ if ( (tmp1<0)||(tmp1>65535)) tmp1=0;
+ *port = tmp1;
+ *isrange = 0;
+ return 0;
+ }
+
+ return 1; // error
+}
+
+
+
+
+// Scans argument for TCP flags and sets
+// tx.tcp_control accordingly.
+//
+// Valid keywords are: fin, syn, rst, psh, ack, urg, ecn, cwr
+// Valid delimiters are: | or + or -
+// Return value: 0 on success, 1 upon failure
+//
+int get_tcp_flags (char* flags)
+{
+ char *f;
+
+ // From LSB to MSB: fin, syn, reset, push, ack, urg, ecn, cwr
+ // ecn...ECN-Echo, cwr...Congestion Window Reduced
+
+ if (strnlen(flags,40)==0) return 1; // error
+
+
+ f = strtok (flags, "|+-");
+ do
+ {
+ if (strncmp(f,"fin",3)==0)
+ {
+ tx.tcp_control = tx.tcp_control | 1;
+ }
+ else if (strncmp(f,"syn",3)==0)
+ {
+ tx.tcp_control = tx.tcp_control | 2;
+ }
+ else if (strncmp(f,"rst",3)==0)
+ {
+ tx.tcp_control = tx.tcp_control | 4;
+ }
+ else if (strncmp(f,"psh",3)==0)
+ {
+ tx.tcp_control = tx.tcp_control | 8;
+ }
+ else if (strncmp(f,"ack",3)==0)
+ {
+ tx.tcp_control = tx.tcp_control | 16;
+ }
+ else if (strncmp(f,"urg",3)==0)
+ {
+ tx.tcp_control = tx.tcp_control | 32;
+ }
+ else if (strncmp(f,"ecn",3)==0)
+ {
+ tx.tcp_control = tx.tcp_control | 64;
+ }
+ else if (strncmp(f,"cwr",3)==0)
+ {
+ tx.tcp_control = tx.tcp_control | 128;
+ }
+
+ } while ( (f=strtok(NULL, "|+-")) != NULL);
+
+ return 0;
+}
+
+
+
+// Scans string 'params' for MPLS parameters
+// and sets tx.mpls_* accordingly.
+//
+// CLI Syntax Examples:
+//
+// -M help .... shows syntax
+//
+// -M 800 .... label=800
+// -M 800:S .... label=800 and BOS flag set
+// -M 800:S:64 .... label=800, BOS, TTL=64
+// -M 800:64:S .... same
+// -M 64:77 .... label=64, TTL=77
+// -M 64:800 .... INVALID
+// -M 800:64 .... label=800, TTL=64
+// -M 800:3:S:64 .... additionally the experimental bits are set (all fields required!)
+//
+// Note: S = BOS(1), s = NOT-BOS(0)
+//
+// Valid delimiters: :-.,+
+// Return value: 0 on success, 1 upon failure
+int get_mpls_params(char *p)
+{
+
+ char *f1, *f2, *f3, *f4;
+ char params[256];
+
+ tx.mpls_exp = 0;
+ tx.mpls_ttl = 255;
+
+ strncpy(params, p, 256);
+
+ if (strncmp(params,"help",4)==0)
+ {
+ fprintf(stderr,"\n"
+ MAUSEZAHN_VERSION
+ "\n"
+ "| MPLS header Syntax: -M label[,label[,label[,...]]]\n"
+ "| where each header may consist of the following parameters:\n"
+ "|\n"
+ "| label ... the MPLS label (mandatory, 0..1048575)\n"
+ "| exp ..... experimental/CoS (default: 0, allowed values: 0..7)\n"
+ "| TTL ..... Time To Live (default: 255)\n"
+ "| BOS ..... marks bottom-of-stack; per default the last (most inner) header\n"
+ "| will have BOS=1. If desired you can set this flag for any header\n"
+ "| inbetween but this will lead to an invalid packet. Simply use\n"
+ "| 'S' to set BOS=1, or 's' to set BOS=0. Note that this flag MUST be\n"
+ "| the LAST argument.\n"
+ "|\n"
+ "| Examples:\n"
+ "|\n"
+ "| -M 800 .... label=800\n"
+ "| -M 800:6 .... label=800 and CoS=6\n"
+ "| -M 800:6:55 .... label=800, CoS=6, TTL=55\n"
+ "| -M 800:S .... label=800 and BOS=1\n"
+ "| -M 800:6:s .... label=800, CoS=6, and BOS=0\n"
+ "|\n"
+ "| multiple headers:\n"
+ "|\n"
+ "| -m 30,20:7,800:5:128 ... outer label=800 with CoS=5 and TTL=128,\n"
+ "| middle label=20 with CoS=7,\n"
+ "| inner label=30 (this one is closest to L3).\n"
+ "|\n"
+ "| Valid delimiters inside a header: : - . +\n"
+ "|\n"
+ "\n");
+ exit (0);
+ }
+ else
+ {
+
+ if ( (f1 = strtok (params, ":-.+")) == NULL )
+ {
+ return 1; // error!
+ }
+
+ tx.mpls_label = (u_int32_t) str2int (f1);
+ if (tx.mpls_label>1048575)
+ {
+ tx.mpls_label = 1048575; // 2^20
+ fprintf(stderr," Warning: MPLS label too big! Reduced to maximum allowed value.\n");
+ }
+ }
+
+
+ if ( (f2 = strtok (NULL, ":-.+")) != NULL ) // 2nd param set
+ {
+ if (strncmp(f2,"S",1)==0)
+ {
+ tx.mpls_bos = 1;
+ return 0;
+ }
+ else if (strncmp(f2,"s",1)==0)
+ {
+ tx.mpls_bos = 0;
+ return 0;
+ }
+ else
+ {
+ tx.mpls_exp = (u_int8_t) str2int (f2);
+ if (tx.mpls_exp > 7)
+ {
+ tx.mpls_exp = 7;
+ fprintf(stderr," Warning: MPLS CoS too big! Reduced to maximum allowed value.\n");
+ }
+ }
+
+
+ if ( (f3 = strtok (NULL, ":-.+")) != NULL ) // 3rd param set
+ {
+ if (strncmp(f3,"S",1)==0)
+ {
+ tx.mpls_bos = 1;
+ return 0;
+ }
+ else if (strncmp(f3,"s",1)==0)
+ {
+ tx.mpls_bos = 0;
+ return 0;
+ }
+ else
+ {
+ if ((u_int16_t) str2int (f3)>255)
+ {
+ fprintf(stderr," Warning: MPLS TTL too big! Reduced to maximum allowed value.\n");
+ tx.mpls_ttl = 255;
+ }
+ else
+ {
+ tx.mpls_ttl = (u_int8_t) str2int (f3);
+ }
+ }
+
+ if ( (f4 = strtok (NULL, ":-.+")) != NULL ) // 4th param set
+ {
+
+ if (strncmp(f3,"S",1)==0)
+ {
+ tx.mpls_bos = 1;
+ }
+ else if (strncmp(f3,"s",1)==0)
+ {
+ tx.mpls_bos = 0;
+ }
+
+ }
+
+ }
+ }
+
+
+ return 0;
+}
+
+
+// Parses str for occurence of character or sequence ch.
+// Returns number of occurences
+int exists(char* str, char* ch)
+{
+ int i,match;
+
+ size_t len_str, len_ch;
+
+ len_str = strlen(str);
+ len_ch = strlen(ch);
+ match=0;
+
+ for (i=0; i<len_str; i++)
+ {
+ if (strcmp(str++,ch)==0) match++;
+ }
+
+ return match;
+}
+
+
+
+// Checks if str consists only of 0 and 1
+//
+// RETURN VALUE:
+//
+// 0 if invalid chars found or str empty
+// n if str consists exactly of n binary digits
+int mz_strisbinary(char *str)
+{
+ int i, len, ret=0;
+
+ len = strlen(str);
+ if (len==0) return 0;
+
+ for (i=0; i<len; i++) {
+ if ((str[i]=='0') || (str[i]=='1')) {
+ ret++;
+ } else {
+ return 0;
+ }
+ }
+ return ret;
+}
+
+
+
+
+
+// Converts a string containing (max 8) binary digits into a number
+// RETURN VALUE:
+//
+// Either the number on success
+// Or -1 upon failure
+//
+int str2bin8 (char *str)
+{
+ int i, n, ret=0;
+
+ n=mz_strisbinary(str);
+
+ if ((!n) || (n>8)) return -1;
+
+ for (i=0; i<n; i++) if (str[i]=='1') ret |= ( 0x01 << (n-1-i) );
+ return ret;
+}
+
+
+
+
+// Converts a string containing (max 16) binary digits into a number
+// RETURN VALUE:
+//
+// Either the number on success
+// Or -1 upon failure
+//
+long int str2bin16 (char *str)
+{
+ int i, n;
+ long int ret=0;
+
+ n=mz_strisbinary(str);
+
+ if ((!n) || (n>16)) return -1;
+
+ for (i=0; i<n; i++) if (str[i]=='1') ret |= ( 0x01 << (n-1-i) ); // C is great ;-)
+ return ret;
+}
+
+
+
+// Converts a char into a string containing ones and zeros
+//
+// EXAMPLE:
+//
+// char c = 0x81; char str[16];
+// char2bits(c, str);
+// printf("%s\n",str); => "1 0 0 0 0 0 0 1"
+//
+int char2bits (char c, char *str)
+{
+ int i,j=1;
+ char tmp[]="0 0 0 0 0 0 0 0";
+
+ for (i=0; i<8; i++)
+ {
+ if (c&j) tmp[14-i*2]='1';
+ j=j*2;
+ }
+
+ strncpy(str, tmp, 15);
+ return 0;
+}
+
+
+// Takes filename and prepends valid configuration directory
+//
+// 1) prefer configurable mz_default_config_path[]
+// 2) otherwise use MZ_DEFAULT_CONFIG_PATH
+//
+// NOTE: 'filename' finally holds the full path
+// and must therefore be big enough
+//
+//
+// RETURN VALUE:
+// 0 upon success
+// 1 upon failure
+//
+int getfullpath_cfg (char *filename)
+{
+ int lenf, lenp;
+ char tmp[32];
+
+ lenf = strnlen(filename, 32);
+
+ // filename not given?
+ if ((lenf==0) || (lenf==32)) return 1;
+
+ strncpy(tmp, filename, 32);
+
+ // Prefer user-defined path if provided:
+ lenp = strnlen(mz_default_config_path,255);
+
+ if (lenp) {
+ if (strncmp(mz_default_config_path+lenp-1, "/",1))
+ strncat(mz_default_config_path, "/",1);
+ snprintf(filename, 255, "%s%s",mz_default_config_path,tmp);
+ }
+ else {
+ lenp = strlen(MZ_DEFAULT_CONFIG_PATH);
+ snprintf(filename, 255, "%s%s",MZ_DEFAULT_CONFIG_PATH,tmp);
+ }
+
+ if ((lenf+lenp)>255) return 1;
+
+ return 0;
+}
+
+
+
+// Takes filename and prepends valid logging directory
+//
+// 1) prefer configurable mz_default_log_path[]
+// 2) otherwise use MZ_DEFAULT_LOG_PATH
+//
+// NOTE: filename is overwritten and must be big enough to hold full path!
+//
+int getfullpath_log (char *filename)
+{
+ int lenf, lenp;
+ char tmp[32];
+
+ lenf = strnlen(filename, 32);
+
+ // filename not given?
+ if ((lenf==0) || (lenf==32)) return 1;
+
+ strncpy(tmp, filename, 32);
+
+ // Prefer user-defined path if provided:
+ lenp = strnlen(mz_default_log_path,255);
+ if (lenp) {
+ if (strncmp(mz_default_log_path+lenp-1, "/",1))
+ strncat(mz_default_log_path, "/",1);
+ snprintf(filename, 255, "%s%s",mz_default_log_path,tmp);
+ }
+ else {
+ lenp = strlen(MZ_DEFAULT_LOG_PATH);
+ snprintf(filename, 255, "%s%s",MZ_DEFAULT_LOG_PATH,tmp);
+ }
+
+ if ((lenf+lenp)>255) return 1;
+
+ return 0;
+}
+
+// Behaves much like strncpy but additionally ensures
+// that dest is always \0-terminated.
+//
+// USAGE NOTE: If you know exactly the length n of your string,
+// then you must provide n+1 to support the termination character.
+//
+// EXAMPLE: src="Hello", n=strlen(src)=5, and mz_strncpy(dest, src, n)
+// would result in dest={H,e,l,l,\0}.
+// Therefore the correct usage is:
+// mz_strncpy(dest, src, strlen(src)+1);
+// =============
+//
+// RETURN VALUE: pointer to dest
+char * mz_strncpy(char *dest, const char *src, size_t n)
+{
+ char *tmp;
+ tmp = strncpy(dest, src, n);
+ dest[n-1]='\0';
+ return tmp;
+}
+
+
+
+
+// Helper function to count the number of arguments
+// in the Mausezahn argument string (comma separated args)
+//
+// RETURN VALUE: Number of arguments
+//
+// TODO: Improve it. Use strtok.
+//
+int number_of_args (char *str)
+{
+ int len=0, i=0, commas=1;
+ if ((len=strnlen(str,MAX_PAYLOAD_SIZE))<2) return 0; // no valid argument
+ for (i=0; i<len; i++) if (str[i]==',') commas++;
+ if (str[len-1]==',') commas--; // comma at the end!
+ return commas;
+}
+
+
+
+// Checks if str consists only of digits 0..9
+//
+// RETURN VALUE:
+//
+// 0 if invalid chars found or str empty
+// n if str consists exactly of n digits
+int mz_strisnum(char *str)
+{
+ int i, len, ret=0;
+
+ len = strlen(str);
+ if (len==0) return 0;
+
+ for (i=0; i<len; i++) {
+ if (isdigit(str[i])) {
+ ret++;
+ } else {
+ return 0;
+ }
+ }
+ return ret;
+}
+
+
+// Checks if str consists only of hex digits 0..9 and a..f
+//
+// RETURN VALUE:
+//
+// 0 if invalid chars found or str empty
+// n if str consists exactly of n digits
+int mz_strishex(char *str)
+{
+ int i, len, ret=0;
+
+ len = strlen(str);
+ if (len==0) return 0;
+
+ for (i=0; i<len; i++) {
+ if (isxdigit(str[i])) {
+ ret++;
+ } else {
+ return 0;
+ }
+ }
+ return ret;
+}
+
+
+// Returns an 4-byte random number
+//
+u_int32_t mz_rand32 (void)
+{
+ static unsigned int r=0;
+ srand(r);
+ r=rand();
+ return (r<<16 | r);
+}
+
+
+
+
+
+
+// Compares user-provided string with a specified string.
+//
+// Return value:
+//
+// 0 if at least min characters match
+// 1 if at least one character of usr does NOT match the corresponding character in str.
+//
+// Note: Case-insensitive!
+// Goal: Should be more practical and secure than strcmp (and related)
+int mz_strcmp(char* usr_orig, char* str_orig, int min)
+{
+ int i, same=0, usrlen, max;
+ char usr[80], str[80];
+
+ usrlen = strlen(usr_orig);
+ max = strlen(str_orig);
+
+ strncpy(usr, usr_orig, 80);
+ strncpy(str, str_orig, 80);
+
+ // User provided not enough or too many chars
+ if ((usrlen<min) || (usrlen>max)) return 1;
+
+ // now check how many bytes really match
+ for (i=0; i<usrlen; i++) {
+ if (strncasecmp(&usr[i], &str[i], 1)==0) {
+ same++;
+ }
+ }
+
+ if (same<usrlen) return 1;
+
+ return 0;
+}
+
+
+
+
+
+// PURPOSE:
+//
+// Maps an arbitrary number of tokens from 'str' which are separated by
+// a character 'delim' into provided arguments.
+//
+// USAGE EXAMPLE:
+//
+// char str[]="Am:Dam:Des";
+// char t1[64], t2[64], t3[64], t4[64];
+//
+// mz_tok (str, ":", 4, t1, t2, t3, t4)
+//
+// => t1="Am", t2="Dam", t3="Des", t4=NULL
+//
+// NOTE:
+//
+// 1. If the delimiter symbol occurs twice without gap, it is interpreted
+// as 'fill-up' command. To avoid ambiguities this may only occur once.
+// See the IPv6 address format shortcuts as similar example.
+//
+// 2. If there are less tokens than allowed, the arguments are filled up
+// in order, while the remaining are casted to NULL:
+//
+// 3. str must be smaller than 4096 bytes!
+//
+// 4. To mitigate buffer overflow problems, the maximum token size is
+// currently limited to 64 bytes. Therefore it is recommended to
+// allocate 64 bytes for each argument.
+//
+// RETURN VALUE: Number of returned tokens or -1 upon error
+
+int mz_tok(char * str, char * delim, int anz, ...)
+{
+
+ va_list ap;
+ int i=0, n=0, len, llen, rlen, ltok=0, rtok=0;
+ char *d, *l, *r, *token, *saveptr, *arg;
+ char str2[4096], delim2[4]="", delim3[4]="";;
+
+ if (strlen(delim)!=1) return -1; // delim must contain a single character!
+ strncpy(str2, str, 4095); // protect the original str from strtok => operate on a copy only
+ len = strlen(str2);
+
+ // Check if some tokens are omitted (::)
+ strncpy(delim2, delim, 1); strncat(delim2, delim, 1); // create the double-delim
+ strncpy(delim3, delim2, 2); strncat(delim3, delim, 1); // create the double-delim
+ if (strstr(str2, delim3)!=NULL) return -1; // Error: ':::' occured!
+
+ if ( (d=strstr(str2, delim2))!=NULL ) { // delim2 ('::') found
+ // Check 3 cases: "::Sat:Sun", "Mon::Sat:Sun", and "Mon:Tue::"
+ if (strlen(d)>2) { // '::' is not at the end of str2
+ r=d+2; // r points to beginning of right string
+ if (strstr(r, delim2)!=NULL) return -1; // Error: '::' occurs more than once!
+ rtok++; // there is at least one token in the right string
+ rlen = strlen(r);
+ for(i=0;i<rlen;i++) if (strncmp(r++,delim,1)==0) rtok++;
+ }
+ else
+ rlen = 0;
+
+ if (rlen<(len-2)) { // '::' is not at the beginning of str2
+ l=d-1; // l points to end of left string
+ ltok++;
+ llen = len - rlen - 2;
+ for(i=0;i<llen;i++) if (strncmp(l--,delim,1)==0) ltok++;
+ }
+ //printf("ltok=%i, rtok=%i\n",ltok,rtok);
+ if ((ltok+rtok)>anz) return -1; // More tokens than arguments ('::' here leads to ambiguous mapping)
+ }
+ else
+ ltok=len+1; // makes subsequent algorithm to ignore exception handling
+
+
+
+ rtok=anz-rtok;
+ va_start(ap, anz);
+
+ token = strtok_r(str2, delim, &saveptr);
+ if (token==NULL) { va_end(ap); return n; }
+
+ for(i=0; i<anz; i++) {
+ arg = va_arg(ap, char *);
+ if ( (token==NULL) || // less tokens than arguments => assign NULL to the remaining arguments!
+ ((i>=ltok) && (i<rtok))) {
+ arg[0] = 0x00;
+ }
+ else { // we still have tokens...
+ n++;
+ strncpy(arg, token, 64);
+ token = strtok_r(NULL, delim, &saveptr);
+ }
+ }
+
+ va_end(ap);
+ return n;
+}
+
+
+
+
+
+
+//
+// PURPOSE: Simplify reading of user delay specifications.
+// Parse 'a' and 'b' and configure a struct timespec, i. e. seconds and nanoseconds.
+//
+// Typically 'a' contains only the value and 'b' the unit.
+// But if b==NULL then 'a' may also contain the unit such as "100msec"
+//
+// Allowed units are: nsec, usec, sec, min, hour
+//
+// NOTE: If no unit is given then assume msec as default unit
+//
+// RETURN VALUE: 0 upon success, 1 upon error (bad arguments)
+//
+int delay_parse (struct timespec *t, char *a, char *b)
+{
+ int i;
+ unsigned int sfactor=0, nfactor=1000000; // assume msec as default unit
+ unsigned long long delay, sdelay, ndelay;
+
+ if (b==NULL) { // only one argument, but may contain an unit (such as '314sec')
+ if (strstr(a, "msec")) {
+ nfactor=1000000;
+ }
+ else if (strstr(a, "usec")) {
+ nfactor=1000;
+ }
+ else if (strstr(a, "nsec")) {
+ nfactor=1;
+ }
+ else if (strstr(a, "sec")) { // NOTE: This must be the last check since 'sec' is included in previous strings
+ sfactor=1;
+ nfactor=0;
+ }
+ else if (strstr(a, "min")) {
+ sfactor=60;
+ nfactor=0;
+ }
+ else if (strstr(a, "hour")) {
+ sfactor=3600;
+ nfactor=0;
+ }
+ else { // Unit not found; check for non-digits!
+ // NOTE: we do not currently catch wrong strings that contain sec, usec, or msec.
+ //
+ for (i=0; i<strlen(a); i++) {
+ if (!isdigit(a[i])) return 1; // invalid unit
+ }
+ nfactor=1000000; // no unit given => assume msec
+ }
+ } else { // caller specified two arguments
+ if (mz_strcmp(b,"nsec", 1)==0)
+ nfactor=1;
+ else if (mz_strcmp(b,"usec", 1)==0)
+ nfactor=1000;
+ else if (mz_strcmp(b,"msec", 1)==0)
+ nfactor=1000000;
+ else if (mz_strcmp(b,"sec", 1)==0) {
+ sfactor=1;
+ nfactor=0;
+ }
+ else if (mz_strcmp(b,"min", 1)==0) {
+ sfactor=60;
+ nfactor=0;
+ }
+ else if (mz_strcmp(b,"hour", 1)==0) {
+ sfactor=3600;
+ nfactor=0;
+ }
+ else return 1; // Invalid unit
+ }
+
+ // Get user-defined actual value:
+ delay = strtoull(a, (char **)NULL, 10);
+ if ((errno==ERANGE) || (delay>999999999L)) { // see man 2 nanosleep
+ return 2; // Value too large! Supported range is from 0 to 999999999
+ }
+
+ sdelay = delay * sfactor;
+ ndelay = delay * nfactor;
+
+ if (ndelay>999999999L) {
+ sdelay = ndelay/1000000000L;
+ ndelay = ndelay - (sdelay*1000000000L);
+ }
+
+ t->tv_sec = sdelay;
+ t->tv_nsec = ndelay;
+ return 0;
+}
+
diff --git a/staging/tx_switch.c b/staging/tx_switch.c
new file mode 100644
index 0000000..b1a0d55
--- /dev/null
+++ b/staging/tx_switch.c
@@ -0,0 +1,178 @@
+/*
+ * Mausezahn - A fast versatile traffic generator
+ * Copyright (C) 2008-2010 Herbert Haas
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
+ *
+*/
+
+
+#include "mz.h"
+#include "cli.h"
+
+
+int tx_switch(struct cli_def *cli)
+{
+
+ // These handles are only used when creating L3 and above packets.
+ libnet_t *l; // the context
+ libnet_ptag_t t2=0, t3=0, t4=0; // handles to layers
+
+ double cpu_time_used;
+
+ switch (mode)
+ {
+ case BYTE_STREAM:
+ send_eth();
+ break;
+
+ case ARP:
+ if (send_arp()==-1) return 0;
+ break;
+
+ case BPDU:
+ if (send_bpdu()==-1) return 0;
+ break;
+
+ case CDP:
+ if (send_cdp()==-1) return 0;
+ break;
+
+ case IP: // From now on a new much more modular method is used:
+ l = get_link_context();
+ t3 = create_ip_packet(l); // t3 can be used for later header changes
+ if (!quiet) complexity();
+ if (tx.packet_mode==0) // Ethernet manipulation features does NOT use ARP to determine eth_dst
+ t2 = create_eth_frame(l, t3, t4); // t2 can be used for later header changes
+ else
+ send_frame (l, t3, t4); // NOTE: send_frame also destroys context finaly
+ break;
+
+ case ICMP:
+ tx.ip_proto = 1;
+ l = get_link_context();
+ t4 = create_icmp_packet(l); // t4 can be used for later header changes
+ if (t4==-1) return 0;
+ t3 = create_ip_packet(l); // t3 can be used for later header changes
+ if (!quiet) complexity();
+ if (tx.packet_mode==0) // Ethernet manipulation features does NOT use ARP to determine eth_dst
+ t2 = create_eth_frame(l, t3, t4); // t2 can be used for later header changes
+ else
+ send_frame (l, t3, t4); // NOTE: send_frame also destroys context finaly
+ break;
+
+ case UDP:
+ tx.ip_proto = 17;
+ l = get_link_context();
+ t4 = create_udp_packet(l); // t4 can be used for later header changes
+ if (t4==-1) return 0;
+ t3 = create_ip_packet(l); // t3 can be used for later header changes
+ if (!quiet) complexity();
+ if (tx.packet_mode==0) // Ethernet manipulation features does NOT use ARP to determine eth_dst
+ t2 = create_eth_frame(l, t3, t4); // t2 can be used for later header changes
+ else
+ send_frame (l, t3, t4); // NOTE: send_frame also destroys context finaly
+ break;
+
+ case TCP:
+ tx.ip_proto = 6;
+ l = get_link_context();
+ t4 = create_tcp_packet(l); // t4 can be used for later header changes
+ if (t4==-1) return 0;
+ t3 = create_ip_packet(l); // t3 can be used for later header changes
+ if (!quiet) complexity();
+ if (tx.packet_mode==0) // Ethernet manipulation features does NOT use ARP to determine eth_dst
+ t2 = create_eth_frame(l, t3, t4); // t2 can be used for later header changes
+ else
+ send_frame (l, t3, t4); // NOTE: send_frame also destroys context finaly
+ break;
+
+ case DNS:
+ tx.ip_proto = 17;
+ l = get_link_context();
+ if (create_dns_packet()==-1) return 0;
+ t4 = create_udp_packet(l); // t4 can be used for later header changes
+ t3 = create_ip_packet(l); // t3 can be used for later header changes
+ if (!quiet) complexity();
+ if (tx.packet_mode==0) // Ethernet manipulation features does NOT use ARP to determine eth_dst
+ t2 = create_eth_frame(l, t3, t4); // t2 can be used for later header changes
+ else
+ send_frame (l, t3, t4); // NOTE: send_frame also destroys context finaly
+ break;
+
+ case RTP:
+ tx.ip_proto = 17;
+ l = get_link_context();
+ if (create_rtp_packet()==-1) return 0;
+ cli_print(cli, "RTP mode! (count=%u, delay=%u usec)\n", tx.count, tx.delay);
+ t4 = create_udp_packet(l); // t4 can be used for later header changes
+ t3 = create_ip_packet(l); // t3 can be used for later header changes
+ if (!quiet) complexity();
+ if (tx.packet_mode==0) // Ethernet manipulation features does NOT use ARP to determine eth_dst
+ t2 = create_eth_frame(l, t3, t4); // t2 can be used for later header changes
+ else
+ send_frame (l, t3, t4); // NOTE: send_frame also destroys context finaly
+ break;
+
+ case RX_RTP: // Receive RTP packets
+ rcv_rtp_init();
+ rcv_rtp();
+ break;
+
+ case SYSLOG:
+ tx.ip_proto = 17;
+ l = get_link_context();
+ if (create_syslog_packet()==-1) return 0;
+ t4 = create_udp_packet(l); // t4 can be used for later header changes
+ t3 = create_ip_packet(l); // t3 can be used for later header changes
+ if (!quiet) complexity();
+
+ if (tx.packet_mode==0) // Ethernet manipulation features does NOT use ARP to determine eth_dst
+ t2 = create_eth_frame(l, t3, t4); // t2 can be used for later header changes
+ else
+ send_frame (l, t3, t4); // NOTE: send_frame also destroys context finaly
+ break;
+
+ case LLDP: // start with a new concept here
+ //l = get_link_context();
+ //(void) create_lldp_packet();
+ // // // printf("SIZE=%lu\n",sizeof(struct tx_struct));
+ break;
+
+
+ default:
+ cli_print(cli,"Unknown mode!\n");
+ return (1);
+ }
+
+
+ // ***** Re-init packet functions: *****
+ tx.ip_payload_s = 0;
+ tx.udp_len = 0;
+ tx.tcp_payload_s = 0;
+ tx.icmp_payload_s = 0;
+ tx.cdp_sum = 0;
+ mode = 0;
+ // **************************************
+
+
+ mz_stop = clock();
+ cpu_time_used = ((double) (mz_stop - mz_start)) / CLOCKS_PER_SEC;
+ if (cpu_time_used > 0)
+ {
+ total_d /= cpu_time_used;
+ cli_print(cli, "%.2f seconds (%.Lf packets per second)\n",cpu_time_used,total_d);
+ }
+
+ return 0;
+}