diff --git a/src/tcpedit/plugins/Makefile.am b/src/tcpedit/plugins/Makefile.am index c99e2741..9b6dd40c 100644 --- a/src/tcpedit/plugins/Makefile.am +++ b/src/tcpedit/plugins/Makefile.am @@ -42,6 +42,7 @@ include %reldir%/dlt_raw/Makefile.am include %reldir%/dlt_null/Makefile.am include %reldir%/dlt_loop/Makefile.am include %reldir%/dlt_linuxsll/Makefile.am +include %reldir%/dlt_linuxsll2/Makefile.am include %reldir%/dlt_ieee80211/Makefile.am include %reldir%/dlt_radiotap/Makefile.am include %reldir%/dlt_jnpr_ether/Makefile.am diff --git a/src/tcpedit/plugins/dlt_linuxsll2/Makefile.am b/src/tcpedit/plugins/dlt_linuxsll2/Makefile.am new file mode 100644 index 00000000..6ec1fbbc --- /dev/null +++ b/src/tcpedit/plugins/dlt_linuxsll2/Makefile.am @@ -0,0 +1,30 @@ +# $Id:$ +# START OF: dlt_linuxsll2 +# Note, if you add any files to your plugin, you will need to edit dlt_/Makefile.am +# add your .c files to libtcpedit_a_SOURCES +# add your .h files to noinst_HEADERS +# add any other files (like documentation, notes, etc) to EXTRA_DIST +# add your dependency information (see comment below) + +libtcpedit_a_SOURCES += %reldir%/linuxsll2.c + +noinst_HEADERS += \ + %reldir%/linuxsll2.h \ + %reldir%/linuxsll2_types.h + +EXTRA_DIST += %reldir%/linuxsll2_opts.def + +# dependencies for your plugin source code. Edit as necessary +linuxsll2.c: \ + $(TCPEDIT_PLUGINS_DEPS) \ + %reldir%/../../tcpedit_api.h \ + %reldir%/linuxsll2.h \ + %reldir%/linuxsll2_types.h + +# You probably don't want to touch anything below this line until the end of the plugin + +DLT_STUB_DEPS += %reldir%/linuxsll2_opts.def + +MOSTLYCLEANFILES += *~ + +# END OF: dlt_linuxsll2 diff --git a/src/tcpedit/plugins/dlt_linuxsll2/README b/src/tcpedit/plugins/dlt_linuxsll2/README new file mode 100644 index 00000000..78e888e1 --- /dev/null +++ b/src/tcpedit/plugins/dlt_linuxsll2/README @@ -0,0 +1 @@ +https://www.tcpdump.org/linktypes/LINKTYPE_LINUX_SLL2.html diff --git a/src/tcpedit/plugins/dlt_linuxsll2/linuxsll2.c b/src/tcpedit/plugins/dlt_linuxsll2/linuxsll2.c new file mode 100644 index 00000000..b10d6ec0 --- /dev/null +++ b/src/tcpedit/plugins/dlt_linuxsll2/linuxsll2.c @@ -0,0 +1,311 @@ +/* $Id$ */ + +/* + * Copyright (c) 2001-2010 Aaron Turner + * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * + * The Tcpreplay Suite of tools is free software: you can redistribute it + * and/or modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or with the authors permission any later version. + * + * The Tcpreplay Suite 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 the Tcpreplay Suite. If not, see . + */ + +#include "linuxsll2.h" +#include "../ethernet.h" +#include "dlt_utils.h" +#include "tcpedit.h" +#include "tcpedit_stub.h" +#include +#include + +static char dlt_name[] = "linuxsll2"; +static char _U_ dlt_prefix[] = "linuxsll2"; +static uint16_t dlt_value = DLT_LINUX_SLL2; + +/* + * Function to register ourselves. This function is always called, regardless + * of what DLT types are being used, so it shouldn't be allocating extra buffers + * or anything like that (use the dlt_linuxsll2_init() function below for that). + * Tasks: + * - Create a new plugin struct + * - Fill out the provides/requires bit masks. Note: Only specify which fields are + * actually in the header. + * - Add the plugin to the context's plugin chain + * Returns: TCPEDIT_ERROR | TCPEDIT_OK | TCPEDIT_WARN + */ +int +dlt_linuxsll2_register(tcpeditdlt_t *ctx) +{ + tcpeditdlt_plugin_t *plugin; + assert(ctx); + + /* create a new plugin structure */ + plugin = tcpedit_dlt_newplugin(); + + /* FIXME: set what we provide & require */ + plugin->provides += PLUGIN_MASK_PROTO + PLUGIN_MASK_SRCADDR; + plugin-> + requires + += 0; + + /* what is our DLT value? */ + plugin->dlt = dlt_value; + + /* set the prefix name of our plugin. This is also used as the prefix for our options */ + plugin->name = safe_strdup(dlt_prefix); + + /* + * Point to our functions, note, you need a function for EVERY method. + * Even if it is only an empty stub returning success. + */ + plugin->plugin_init = dlt_linuxsll2_init; + plugin->plugin_cleanup = dlt_linuxsll2_cleanup; + plugin->plugin_parse_opts = dlt_linuxsll2_parse_opts; + plugin->plugin_decode = dlt_linuxsll2_decode; + plugin->plugin_encode = dlt_linuxsll2_encode; + plugin->plugin_proto = dlt_linuxsll2_proto; + plugin->plugin_l2addr_type = dlt_linuxsll2_l2addr_type; + plugin->plugin_l2len = dlt_linuxsll2_l2len; + plugin->plugin_get_layer3 = dlt_linuxsll2_get_layer3; + plugin->plugin_merge_layer3 = dlt_linuxsll2_merge_layer3; + plugin->plugin_get_mac = dlt_linuxsll2_get_mac; + + /* add it to the available plugin list */ + return tcpedit_dlt_addplugin(ctx, plugin); +} + +/* + * Initializer function. This function is called only once, if and only if + * this plugin will be utilized. Remember, if you need to keep track of any state, + * store it in your plugin->config, not a global! + * Returns: TCPEDIT_ERROR | TCPEDIT_OK | TCPEDIT_WARN + */ +int +dlt_linuxsll2_init(tcpeditdlt_t *ctx) +{ + tcpeditdlt_plugin_t *plugin; + assert(ctx); + + if ((plugin = tcpedit_dlt_getplugin(ctx, dlt_value)) == NULL) { + tcpedit_seterr(ctx->tcpedit, "Unable to initialize unregistered plugin %s", dlt_name); + return TCPEDIT_ERROR; + } + + /* allocate memory for our decode extra data */ + if (ctx->decoded_extra_size > 0) { + if (ctx->decoded_extra_size < sizeof(linuxsll2_extra_t)) { + ctx->decoded_extra_size = sizeof(linuxsll2_extra_t); + ctx->decoded_extra = safe_realloc(ctx->decoded_extra, ctx->decoded_extra_size); + } + } else { + ctx->decoded_extra_size = sizeof(linuxsll2_extra_t); + ctx->decoded_extra = safe_malloc(ctx->decoded_extra_size); + } + + /* allocate memory for our config data */ + plugin->config_size = sizeof(linuxsll2_config_t); + plugin->config = safe_malloc(plugin->config_size); + + return TCPEDIT_OK; /* success */ +} + +/* + * Since this is used in a library, we should manually clean up after ourselves + * Unless you allocated some memory in dlt_linuxsll2_init(), this is just an stub. + * Returns: TCPEDIT_ERROR | TCPEDIT_OK | TCPEDIT_WARN + */ +int +dlt_linuxsll2_cleanup(tcpeditdlt_t *ctx) +{ + tcpeditdlt_plugin_t *plugin; + assert(ctx); + + if ((plugin = tcpedit_dlt_getplugin(ctx, dlt_value)) == NULL) { + tcpedit_seterr(ctx->tcpedit, "Unable to cleanup unregistered plugin %s", dlt_name); + return TCPEDIT_ERROR; + } + + safe_free(plugin->name); + plugin->name = NULL; + safe_free(plugin->config); + plugin->config = NULL; + plugin->config_size = 0; + + return TCPEDIT_OK; /* success */ +} + +/* + * This is where you should define all your AutoGen AutoOpts option parsing. + * Any user specified option should have it's bit turned on in the 'provides' + * bit mask. + * Returns: TCPEDIT_ERROR | TCPEDIT_OK | TCPEDIT_WARN + */ +int +dlt_linuxsll2_parse_opts(tcpeditdlt_t *ctx) +{ + assert(ctx); + + /* nothing to parse */ + return TCPEDIT_OK; /* success */ +} + +/* + * Function to decode the layer 2 header in the packet. + * You need to fill out: + * - ctx->l2len + * - ctx->srcaddr + * - ctx->dstaddr + * - ctx->proto + * - ctx->decoded_extra + * Returns: TCPEDIT_ERROR | TCPEDIT_OK | TCPEDIT_WARN + */ +int +dlt_linuxsll2_decode(tcpeditdlt_t *ctx, const u_char *packet, int pktlen) +{ + int type; + linux_sll2_header_t *linux_sll2; + assert(ctx); + assert(packet); + + if (pktlen < (int)sizeof(linux_sll2_header_t)) + return TCPEDIT_ERROR; + + linux_sll2 = (linux_sll2_header_t *)packet; + ctx->proto = linux_sll2->proto; + ctx->l2len = sizeof(linux_sll2_header_t); + + type = ntohs(linux_sll2->type); + if (type == ARPHRD_ETHER || type == ARPHRD_LOOPBACK) { /* ethernet or loopback */ + memcpy(&(ctx->srcaddr), linux_sll2->address, ETHER_ADDR_LEN); + } else { + tcpedit_seterr(ctx->tcpedit, "%s", "DLT_LINUX_SLL2 pcap's must contain only ethernet or loopback packets"); + return TCPEDIT_ERROR; + } + + return TCPEDIT_OK; /* success */ +} + +/* + * Function to encode the layer 2 header back into the packet. + * Returns: total packet len or TCPEDIT_ERROR + */ +int +dlt_linuxsll2_encode(tcpeditdlt_t *ctx, u_char *packet, _U_ int pktlen, _U_ tcpr_dir_t dir) +{ + assert(ctx); + assert(packet); + + tcpedit_seterr(ctx->tcpedit, "%s", "DLT_LINUX_SLL2 plugin does not support packet encoding"); + return TCPEDIT_ERROR; +} + +/* + * Function returns the Layer 3 protocol type of the given packet, or TCPEDIT_ERROR on error + */ +int +dlt_linuxsll2_proto(tcpeditdlt_t *ctx, const u_char *packet, int pktlen) +{ + linux_sll2_header_t *linux_sll2; + assert(ctx); + assert(packet); + + if (pktlen < (int)sizeof(linux_sll2_header_t)) + return TCPEDIT_ERROR; + + linux_sll2 = (linux_sll2_header_t *)packet; + + return linux_sll2->proto; +} + +/* + * Function returns a pointer to the layer 3 protocol header or NULL on error + */ +u_char * +dlt_linuxsll2_get_layer3(tcpeditdlt_t *ctx, u_char *packet, int pktlen) +{ + int l2len; + assert(ctx); + assert(packet); + + l2len = dlt_linuxsll2_l2len(ctx, packet, pktlen); + if (l2len == -1 || pktlen < l2len) + return NULL; + + return tcpedit_dlt_l3data_copy(ctx, packet, pktlen, l2len); +} + +/* + * function merges the packet (containing L2 and old L3) with the l3data buffer + * containing the new l3 data. Note, if L2 % 4 == 0, then they're pointing to the + * same buffer, otherwise there was a memcpy involved on strictly aligned architectures + * like SPARC + */ +u_char * +dlt_linuxsll2_merge_layer3(tcpeditdlt_t *ctx, u_char *packet, int pktlen, u_char *ipv4_data, u_char *ipv6_data) +{ + int l2len; + assert(ctx); + assert(packet); + assert(ipv4_data || ipv6_data); + + l2len = dlt_linuxsll2_l2len(ctx, packet, pktlen); + if (l2len == -1 || pktlen < l2len) + return NULL; + + return tcpedit_dlt_l3data_merge(ctx, packet, pktlen, ipv4_data ?: ipv6_data, l2len); +} + +/* + * return the length of the L2 header of the current packet + */ +int +dlt_linuxsll2_l2len(tcpeditdlt_t *ctx, const u_char *packet, int pktlen) +{ + assert(ctx); + assert(packet); + + if (pktlen < (int)sizeof(linux_sll2_header_t)) + return -1; + + return sizeof(linux_sll2_header_t); +} + +/* + * return a static pointer to the source/destination MAC address + * return NULL on error/address doesn't exist + */ +u_char * +dlt_linuxsll2_get_mac(tcpeditdlt_t *ctx, tcpeditdlt_mac_type_t mac, const u_char *packet, int pktlen) +{ + assert(ctx); + assert(packet); + + if (pktlen < 14) + return NULL; + + /* FIXME: return a ptr to the source or dest mac address. */ + switch (mac) { + case SRC_MAC: + memcpy(ctx->srcmac, &packet[6], 8); /* linuxssl2 defines the src mac field to be 8 bytes, not 6 */ + return (ctx->srcmac); + case DST_MAC: + return (NULL); + default: + errx(-1, "Invalid tcpeditdlt_mac_type_t: %d", mac); + } +} + +tcpeditdlt_l2addr_type_t +dlt_linuxsll2_l2addr_type(void) +{ + /* we only support ethernet packets */ + return ETHERNET; +} diff --git a/src/tcpedit/plugins/dlt_linuxsll2/linuxsll2.h b/src/tcpedit/plugins/dlt_linuxsll2/linuxsll2.h new file mode 100644 index 00000000..05a6e776 --- /dev/null +++ b/src/tcpedit/plugins/dlt_linuxsll2/linuxsll2.h @@ -0,0 +1,50 @@ +/* $Id$ */ + +/* + * Copyright (c) 2001-2010 Aaron Turner + * Copyright (c) 2013-2022 Fred Klassen - AppNeta + * + * The Tcpreplay Suite of tools is free software: you can redistribute it + * and/or modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or with the authors permission any later version. + * + * The Tcpreplay Suite 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 the Tcpreplay Suite. If not, see . + */ + +#pragma once + +#include "plugins_types.h" +#include "linuxsll2_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +int dlt_linuxsll2_register(tcpeditdlt_t *ctx); +int dlt_linuxsll2_init(tcpeditdlt_t *ctx); +int dlt_linuxsll2_cleanup(tcpeditdlt_t *ctx); +int dlt_linuxsll2_parse_opts(tcpeditdlt_t *ctx); +int dlt_linuxsll2_decode(tcpeditdlt_t *ctx, const u_char *packet, int pktlen); +int dlt_linuxsll2_encode(tcpeditdlt_t *ctx, u_char *packet, int pktlen, tcpr_dir_t dir); +int dlt_linuxsll2_proto(tcpeditdlt_t *ctx, const u_char *packet, int pktlen); +u_char *dlt_linuxsll2_get_layer3(tcpeditdlt_t *ctx, u_char *packet, int pktlen); +u_char *dlt_linuxsll2_merge_layer3(tcpeditdlt_t *ctx, + u_char *packet, + int pktlen, + u_char *ipv4_data, + u_char *ipv6_data); +tcpeditdlt_l2addr_type_t dlt_linuxsll2_l2addr_type(void); +int dlt_linuxsll2_l2len(tcpeditdlt_t *ctx, const u_char *packet, int pktlen); +u_char *dlt_linuxsll2_get_mac(tcpeditdlt_t *ctx, tcpeditdlt_mac_type_t mac, const u_char *packet, int pktlen); + +#ifdef __cplusplus +} +#endif diff --git a/src/tcpedit/plugins/dlt_linuxsll2/linuxsll2_opts.def b/src/tcpedit/plugins/dlt_linuxsll2/linuxsll2_opts.def new file mode 100644 index 00000000..ee0a9155 --- /dev/null +++ b/src/tcpedit/plugins/dlt_linuxsll2/linuxsll2_opts.def @@ -0,0 +1 @@ +/* no options for DLT_LINUX_SLL */ diff --git a/src/tcpedit/plugins/dlt_linuxsll2/linuxsll2_types.h b/src/tcpedit/plugins/dlt_linuxsll2/linuxsll2_types.h new file mode 100644 index 00000000..7351791a --- /dev/null +++ b/src/tcpedit/plugins/dlt_linuxsll2/linuxsll2_types.h @@ -0,0 +1,66 @@ +/* $Id$ */ + +/* + * Copyright (c) 2001-2010 Aaron Turner + * + * The Tcpreplay Suite of tools is free software: you can redistribute it + * and/or modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or with the authors permission any later version. + * + * The Tcpreplay Suite 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 the Tcpreplay Suite. If not, see . + */ + +#pragma once + +#include "plugins_types.h" +#include "tcpedit_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * structure to hold any data parsed from the packet by the decoder. + * Example: Ethernet VLAN tag info + */ +typedef struct { + u_char packet[MAXPACKET]; +} linuxsll2_extra_t; + +/* + * FIXME: structure to hold any data in the tcpeditdlt_plugin_t->config + * Things like: + * - Parsed user options + * - State between packets + * - Note, you should only use this for the encoder function, decoder functions should place + * "extra" data parsed from the packet in the tcpeditdlt_t->decoded_extra buffer since that + * is available to any encoder plugin. + */ +typedef struct { + /* dummy entry for SunPro compiler which doesn't like empty structs */ + int dummy; +} linuxsll2_config_t; + +/* https://www.tcpdump.org/linktypes/LINKTYPE_LINUX_SLL2.html */ +typedef struct { + u_int16_t proto; + u_int16_t reserved; + u_int32_t iface_idx; + u_int16_t type; + u_int8_t pkt_type; + +#define ARPHRD_ETHER 1 + u_int8_t length; + u_char address[8]; +} __attribute__((packed)) linux_sll2_header_t; + +#ifdef __cplusplus +} +#endif diff --git a/src/tcpedit/plugins/dlt_plugins.c b/src/tcpedit/plugins/dlt_plugins.c index 51585378..70885309 100644 --- a/src/tcpedit/plugins/dlt_plugins.c +++ b/src/tcpedit/plugins/dlt_plugins.c @@ -33,6 +33,7 @@ #include "dlt_ieee80211/ieee80211.h" #include "dlt_jnpr_ether/jnpr_ether.h" #include "dlt_linuxsll/linuxsll.h" +#include "dlt_linuxsll2/linuxsll2.h" #include "dlt_loop/loop.h" #include "dlt_null/null.h" #include "dlt_pppserial/pppserial.h" @@ -57,6 +58,7 @@ tcpedit_dlt_register(tcpeditdlt_t *ctx) retcode += dlt_null_register(ctx); retcode += dlt_loop_register(ctx); retcode += dlt_linuxsll_register(ctx); + retcode += dlt_linuxsll2_register(ctx); retcode += dlt_ieee80211_register(ctx); retcode += dlt_radiotap_register(ctx); retcode += dlt_jnpr_ether_register(ctx); diff --git a/src/tcpedit/plugins/dlt_stub.def b/src/tcpedit/plugins/dlt_stub.def index 1c948898..10af36f0 100644 --- a/src/tcpedit/plugins/dlt_stub.def +++ b/src/tcpedit/plugins/dlt_stub.def @@ -8,6 +8,7 @@ #include dlt_null/null_opts.def #include dlt_loop/loop_opts.def #include dlt_linuxsll/linuxsll_opts.def +#include dlt_linuxsll2/linuxsll2_opts.def #include dlt_ieee80211/ieee80211_opts.def #include dlt_radiotap/radiotap_opts.def #include dlt_jnpr_ether/jnpr_ether_opts.def