Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tcpedit - add dlt plugin sllv2 #841

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/tcpedit/plugins/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
30 changes: 30 additions & 0 deletions src/tcpedit/plugins/dlt_linuxsll2/Makefile.am
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# $Id:$
# START OF: dlt_linuxsll2
# Note, if you add any files to your plugin, you will need to edit dlt_<plugin>/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
1 change: 1 addition & 0 deletions src/tcpedit/plugins/dlt_linuxsll2/README
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
https://www.tcpdump.org/linktypes/LINKTYPE_LINUX_SLL2.html
311 changes: 311 additions & 0 deletions src/tcpedit/plugins/dlt_linuxsll2/linuxsll2.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,311 @@
/* $Id$ */

/*
* Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
* Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - 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 <http://www.gnu.org/licenses/>.
*/

#include "linuxsll2.h"
#include "../ethernet.h"
#include "dlt_utils.h"
#include "tcpedit.h"
#include "tcpedit_stub.h"
#include <stdlib.h>
#include <string.h>

static char dlt_name[] = "linuxsll2";

Check warning on line 29 in src/tcpedit/plugins/dlt_linuxsll2/linuxsll2.c

View workflow job for this annotation

GitHub Actions / cpp-linter

src/tcpedit/plugins/dlt_linuxsll2/linuxsll2.c:29:13 [cppcoreguidelines-avoid-non-const-global-variables]

variable 'dlt_name' is non-const and globally accessible, consider making it const
static char _U_ dlt_prefix[] = "linuxsll2";

Check warning on line 30 in src/tcpedit/plugins/dlt_linuxsll2/linuxsll2.c

View workflow job for this annotation

GitHub Actions / cpp-linter

src/tcpedit/plugins/dlt_linuxsll2/linuxsll2.c:30:13 [bugprone-reserved-identifier]

declaration uses identifier '_U_', which is a reserved identifier

Check warning on line 30 in src/tcpedit/plugins/dlt_linuxsll2/linuxsll2.c

View workflow job for this annotation

GitHub Actions / cpp-linter

src/tcpedit/plugins/dlt_linuxsll2/linuxsll2.c:30:13 [cppcoreguidelines-avoid-non-const-global-variables]

variable '_U_' is non-const and globally accessible, consider making it const
static uint16_t dlt_value = DLT_LINUX_SLL2;

Check warning on line 31 in src/tcpedit/plugins/dlt_linuxsll2/linuxsll2.c

View workflow job for this annotation

GitHub Actions / cpp-linter

src/tcpedit/plugins/dlt_linuxsll2/linuxsll2.c:31:17 [cppcoreguidelines-avoid-non-const-global-variables]

variable 'dlt_value' is non-const and globally accessible, consider making it const

/*
* 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;

Check warning on line 173 in src/tcpedit/plugins/dlt_linuxsll2/linuxsll2.c

View workflow job for this annotation

GitHub Actions / cpp-linter

src/tcpedit/plugins/dlt_linuxsll2/linuxsll2.c:173:9 [cppcoreguidelines-init-variables]

variable 'type' is not initialized
linux_sll2_header_t *linux_sll2;

Check warning on line 174 in src/tcpedit/plugins/dlt_linuxsll2/linuxsll2.c

View workflow job for this annotation

GitHub Actions / cpp-linter

src/tcpedit/plugins/dlt_linuxsll2/linuxsll2.c:174:26 [cppcoreguidelines-init-variables]

variable 'linux_sll2' is not initialized
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 */

Check warning on line 186 in src/tcpedit/plugins/dlt_linuxsll2/linuxsll2.c

View workflow job for this annotation

GitHub Actions / cpp-linter

src/tcpedit/plugins/dlt_linuxsll2/linuxsll2.c:186:5 [bugprone-branch-clone]

if with identical then and else branches
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)

Check warning on line 201 in src/tcpedit/plugins/dlt_linuxsll2/linuxsll2.c

View workflow job for this annotation

GitHub Actions / cpp-linter

src/tcpedit/plugins/dlt_linuxsll2/linuxsll2.c:201:57 [bugprone-easily-swappable-parameters]

2 adjacent parameters of 'dlt_linuxsll2_encode' of similar type ('int') are easily swapped by mistake
{
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;

Check warning on line 216 in src/tcpedit/plugins/dlt_linuxsll2/linuxsll2.c

View workflow job for this annotation

GitHub Actions / cpp-linter

src/tcpedit/plugins/dlt_linuxsll2/linuxsll2.c:216:26 [cppcoreguidelines-init-variables]

variable 'linux_sll2' is not initialized
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;

Check warning on line 234 in src/tcpedit/plugins/dlt_linuxsll2/linuxsll2.c

View workflow job for this annotation

GitHub Actions / cpp-linter

src/tcpedit/plugins/dlt_linuxsll2/linuxsll2.c:234:9 [cppcoreguidelines-init-variables]

variable 'l2len' is not initialized
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;
}
Loading
Loading