From d0009856814c13d13770db5aadd7b2fabf947776 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Mon, 13 May 2013 13:53:27 +0200 Subject: 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 Signed-off-by: Tobias Klauser --- staging/mops.c | 769 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 769 insertions(+) create mode 100644 staging/mops.c (limited to 'staging/mops.c') 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; jcounter[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; i0) && (!(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; ieth_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; +} + + -- cgit v1.2.3-54-g00ecf