From 4def4c766c2516ed91eb6ed2d29b2de9cd0df66b Mon Sep 17 00:00:00 2001 From: Fred Date: Sun, 3 Sep 2023 14:02:46 -0700 Subject: [PATCH] Feature #727 - Linux SLL version 2 updates PR #728 cleanup and completion of SLL v2 implementation --- configure.ac | 9 ++ docs/CHANGELOG | 1 + docs/CREDIT | 3 + lib/sll.h | 110 +++++++++++------- src/common/dlt_names.c | 22 ++++ src/common/dlt_names.h | 4 + src/common/fakepcap.h | 4 + src/common/get.c | 10 +- src/defines.h.in | 1 + src/tcpedit/dlt.c | 15 ++- src/tcpedit/plugins/dlt_linuxsll2/linuxsll2.c | 31 ++--- src/tcpedit/plugins/dlt_linuxsll2/linuxsll2.h | 6 +- .../plugins/dlt_linuxsll2/linuxsll2_types.h | 2 +- src/tcpprep.c | 1 + src/tcprewrite_opts.def | 2 + 15 files changed, 154 insertions(+), 67 deletions(-) diff --git a/configure.ac b/configure.ac index b410e541f..cdc1a9d33 100644 --- a/configure.ac +++ b/configure.ac @@ -1525,6 +1525,15 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include "$LPCAPINC"]], [[ int foo; ],[AC_MSG_RESULT(no) ]) +AC_MSG_CHECKING(for DLT_LINUX_SLL2 in libpcap) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include "$LPCAPINC"]], [[ int foo; + foo = DLT_LINUX_SLL2 + ]])],[ AC_DEFINE([HAVE_DLT_LINUX_SLL2], [1], + [Does pcap.h include a header with DLT_LINUX_SLL2?]) + AC_MSG_RESULT(yes) + ],[AC_MSG_RESULT(no) + ]) + AC_MSG_CHECKING(for DLT_C_HDLC in libpcap) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include "$LPCAPINC"]], [[ int foo; foo = DLT_C_HDLC ]])],[ AC_DEFINE([HAVE_DLT_C_HDLC], [1], diff --git a/docs/CHANGELOG b/docs/CHANGELOG index 571c48464..f2d997fe3 100644 --- a/docs/CHANGELOG +++ b/docs/CHANGELOG @@ -1,4 +1,5 @@ 09/03/2023 Version 4.5.0-beta1 + - create DLT_LINUX_SLL2 plugin (#727) 06/04/2023 Version 4.4.4 - overflow check fix for parse_mpls (#795) diff --git a/docs/CREDIT b/docs/CREDIT index 467e076cb..38e200f69 100644 --- a/docs/CREDIT +++ b/docs/CREDIT @@ -113,3 +113,6 @@ Florian Weimer David Guti - prevent L2 flooding of ipv6 unicast packets for tcpreplay-edit + +Bastian Triller + - Linux SLL2 diff --git a/lib/sll.h b/lib/sll.h index 4f278792f..149665460 100644 --- a/lib/sll.h +++ b/lib/sll.h @@ -1,10 +1,10 @@ /*- * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 - * The Regents of the University of California. All rights reserved. + * The Regents of the University of California. All rights reserved. * * This code is derived from the Stanford/CMU enet packet filter, * (net/enet.c) distributed as part of 4.3BSD, and code contributed - * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence + * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence * Berkeley Laboratory. * * Redistribution and use in source and binary forms, with or without @@ -42,30 +42,30 @@ * For captures on Linux cooked sockets, we construct a fake header * that includes: * - * a 2-byte "packet type" which is one of: + * a 2-byte "packet type" which is one of: * - * LINUX_SLL_HOST packet was sent to us - * LINUX_SLL_BROADCAST packet was broadcast - * LINUX_SLL_MULTICAST packet was multicast - * LINUX_SLL_OTHERHOST packet was sent to somebody else - * LINUX_SLL_OUTGOING packet was sent *by* us; + * LINUX_SLL_HOST packet was sent to us + * LINUX_SLL_BROADCAST packet was broadcast + * LINUX_SLL_MULTICAST packet was multicast + * LINUX_SLL_OTHERHOST packet was sent to somebody else + * LINUX_SLL_OUTGOING packet was sent *by* us; * - * a 2-byte Ethernet protocol field; + * a 2-byte Ethernet protocol field; * - * a 2-byte link-layer type; + * a 2-byte link-layer type; * - * a 2-byte link-layer address length; + * a 2-byte link-layer address length; * - * an 8-byte source link-layer address, whose actual length is - * specified by the previous value. + * an 8-byte source link-layer address, whose actual length is + * specified by the previous value. * * All fields except for the link-layer address are in network byte order. * * DO NOT change the layout of this structure, or change any of the * LINUX_SLL_ values below. If you must change the link-layer header * for a "cooked" Linux capture, introduce a new DLT_ type (ask - * "tcpdump-workers@tcpdump.org" for one, so that you don't give it a - * value that collides with a value already being used), and use the + * "tcpdump-workers@lists.tcpdump.org" for one, so that you don't give it + * a value that collides with a value already being used), and use the * new header in captures of that type, so that programs that can * handle DLT_LINUX_SLL captures will continue to handle them correctly * without any change, and so that capture files with different headers @@ -77,54 +77,76 @@ #ifndef _SLL_H_ #define _SLL_H_ +#include + /* * A DLT_LINUX_SLL fake link-layer header. */ -#define SLL_HDR_LEN 16 /* total header length */ -#define SLL_ADDRLEN 8 /* length of address field */ +#define SLL_HDR_LEN 16 /* total header length */ +#define SLL_ADDRLEN 8 /* length of address field */ struct sll_header { - u_int16_t sll_pkttype; /* packet type */ - u_int16_t sll_hatype; /* link-layer address type */ - u_int16_t sll_halen; /* link-layer address length */ + u_int16_t sll_pkttype; /* packet type */ + u_int16_t sll_hatype; /* link-layer address type */ + u_int16_t sll_halen; /* link-layer address length */ u_int8_t sll_addr[SLL_ADDRLEN]; /* link-layer address */ - u_int16_t sll_protocol; /* protocol */ + u_int16_t sll_protocol; /* protocol */ +}; + +/* + * A DLT_LINUX_SLL2 fake link-layer header. + */ +#define SLL2_HDR_LEN 20 /* total header length */ + +struct sll2_header { + u_int16_t sll2_protocol; /* protocol */ + u_int16_t sll2_reserved_mbz; /* reserved - must be zero */ + u_int32_t sll2_if_index; /* 1-based interface index */ + u_int16_t sll2_hatype; /* link-layer address type */ + u_int8_t sll2_pkttype; /* packet type */ + u_int8_t sll2_halen; /* link-layer address length */ + u_int8_t sll2_addr[SLL_ADDRLEN]; /* link-layer address */ }; /* - * The LINUX_SLL_ values for "sll_pkttype"; these correspond to the - * PACKET_ values on Linux, but are defined here so that they're - * available even on systems other than Linux, and so that they - * don't change even if the PACKET_ values change. + * The LINUX_SLL_ values for "sll_pkttype" and LINUX_SLL2_ values for + * "sll2_pkttype"; these correspond to the PACKET_ values on Linux, + * which are defined by a header under include/uapi in the current + * kernel source, and are thus not going to change on Linux. We + * define them here so that they're available even on systems other + * than Linux. */ -#define LINUX_SLL_HOST 0 -#define LINUX_SLL_BROADCAST 1 -#define LINUX_SLL_MULTICAST 2 -#define LINUX_SLL_OTHERHOST 3 -#define LINUX_SLL_OUTGOING 4 +#define LINUX_SLL_HOST 0 +#define LINUX_SLL_BROADCAST 1 +#define LINUX_SLL_MULTICAST 2 +#define LINUX_SLL_OTHERHOST 3 +#define LINUX_SLL_OUTGOING 4 /* - * The LINUX_SLL_ values for "sll_protocol"; these correspond to the - * ETH_P_ values on Linux, but are defined here so that they're - * available even on systems other than Linux. We assume, for now, - * that the ETH_P_ values won't change in Linux; if they do, then: + * The LINUX_SLL_ values for "sll_protocol" and LINUX_SLL2_ values for + * "sll2_protocol"; these correspond to the ETH_P_ values on Linux, but + * are defined here so that they're available even on systems other than + * Linux. We assume, for now, that the ETH_P_ values won't change in + * Linux; if they do, then: * - * if we don't translate them in "pcap-linux.c", capture files - * won't necessarily be readable if captured on a system that - * defines ETH_P_ values that don't match these values; + * if we don't translate them in "pcap-linux.c", capture files + * won't necessarily be readable if captured on a system that + * defines ETH_P_ values that don't match these values; * - * if we do translate them in "pcap-linux.c", that makes life - * unpleasant for the BPF code generator, as the values you test - * for in the kernel aren't the values that you test for when - * reading a capture file, so the fixup code run on BPF programs - * handed to the kernel ends up having to do more work. + * if we do translate them in "pcap-linux.c", that makes life + * unpleasant for the BPF code generator, as the values you test + * for in the kernel aren't the values that you test for when + * reading a capture file, so the fixup code run on BPF programs + * handed to the kernel ends up having to do more work. * * Add other values here as necessary, for handling packet types that * might show up on non-Ethernet, non-802.x networks. (Not all the ones * in the Linux "if_ether.h" will, I suspect, actually show up in * captures.) */ -#define LINUX_SLL_P_802_3 0x0001 /* Novell 802.3 frames without 802.2 LLC header */ -#define LINUX_SLL_P_802_2 0x0004 /* 802.2 frames (not D/I/X Ethernet) */ +#define LINUX_SLL_P_802_3 0x0001 /* Novell 802.3 frames without 802.2 LLC header */ +#define LINUX_SLL_P_802_2 0x0004 /* 802.2 frames (not D/I/X Ethernet) */ +#define LINUX_SLL_P_CAN 0x000C /* CAN frames, with SocketCAN pseudo-headers */ +#define LINUX_SLL_P_CANFD 0x000D /* CAN FD frames, with SocketCAN pseudo-headers */ #endif diff --git a/src/common/dlt_names.c b/src/common/dlt_names.c index de694f207..d0b60ecfe 100644 --- a/src/common/dlt_names.c +++ b/src/common/dlt_names.c @@ -506,6 +506,28 @@ char *dlt2name[] = { "Unknown", "Unknown", "Unknown", + "Unknown", + "Unknown", + "Unknown", + "Unknown", + "Unknown", + "Unknown", + "Unknown", + "Unknown", + "Unknown", + "Unknown", + "Unknown", + "Unknown", + "Unknown", + "Unknown", + "Unknown", + "Unknown", + "Unknown", + "Unknown", + "Unknown", + "Unknown", + "Unknown", + "DLT_LINUX_SLL2", NULL }; diff --git a/src/common/dlt_names.h b/src/common/dlt_names.h index dfd437949..3f3534a3c 100644 --- a/src/common/dlt_names.h +++ b/src/common/dlt_names.h @@ -186,6 +186,10 @@ extern const char *dlt2name[]; #define DLT_LINUX_SLL 113 #endif +#ifndef DLT_LINUX_SLL2 +#define DLT_LINUX_SLL2 276 +#endif + #ifndef DLT_LTALK #define DLT_LTALK 114 #endif diff --git a/src/common/fakepcap.h b/src/common/fakepcap.h index fd0efd905..cc269d4d8 100644 --- a/src/common/fakepcap.h +++ b/src/common/fakepcap.h @@ -29,6 +29,10 @@ #define DLT_LINUX_SLL 113 #endif +#ifndef HAVE_DLT_LINUX_SLL2 +#define DLT_LINUX_SLL2 276 +#endif + #ifndef HAVE_DLT_C_HDLC #define DLT_C_HDLC 104 #endif diff --git a/src/common/get.c b/src/common/get.c index 2d911160f..e77f358a2 100644 --- a/src/common/get.c +++ b/src/common/get.c @@ -357,10 +357,18 @@ get_l2len_protocol(const u_char *pktdata, if (datalen < SLL_HDR_LEN) return -1; + *l2len = SLL_HDR_LEN; sll_hdr_t *sll_hdr = (sll_hdr_t *)pktdata; - *l2len = sizeof(*sll_hdr); *protocol = ntohs(sll_hdr->sll_protocol); break; + case DLT_LINUX_SLL2: + if (datalen < SLL2_HDR_LEN) + return -1; + + *l2len = SLL2_HDR_LEN; + sll2_hdr_t *sll2_hdr = (sll2_hdr_t *)pktdata; + *protocol = ntohs(sll2_hdr->sll2_protocol); + break; default: errx(-1, "Unable to process unsupported DLT type: %s (0x%x)", diff --git a/src/defines.h.in b/src/defines.h.in index 6b651398a..364b215ba 100644 --- a/src/defines.h.in +++ b/src/defines.h.in @@ -101,6 +101,7 @@ typedef struct tcpr_icmpv6_hdr icmpv6_hdr_t; typedef struct tcpr_ethernet_hdr eth_hdr_t; typedef struct tcpr_802_1q_hdr vlan_hdr_t; typedef struct sll_header sll_hdr_t; +typedef struct sll2_header sll2_hdr_t; typedef struct tcpr_arp_hdr arp_hdr_t; typedef struct tcpr_dnsv4_hdr dnsv4_hdr_t; diff --git a/src/tcpedit/dlt.c b/src/tcpedit/dlt.c index 56d64b1f3..a1d26380a 100644 --- a/src/tcpedit/dlt.c +++ b/src/tcpedit/dlt.c @@ -21,6 +21,7 @@ #include "dlt.h" #include "config.h" #include "tcpedit.h" +#include #include /** @@ -49,13 +50,13 @@ dlt2layer2len(tcpedit_t *tcpedit, int dlt) case DLT_EN10MB: len = 12; break; - /* - case DLT_VLAN: - len = 14; - break; - */ + case DLT_LINUX_SLL: - len = 16; + len = SLL_HDR_LEN; + break; + + case DLT_LINUX_SLL2: + len = SLL2_HDR_LEN; break; case DLT_PPP_SERIAL: @@ -103,6 +104,7 @@ dltrequires(tcpedit_t *tcpedit, int dlt) break; case DLT_LINUX_SLL: + case DLT_LINUX_SLL2: /* we have proto & SRC address */ req = TCPEDIT_DLT_DST; break; @@ -136,6 +138,7 @@ dlt2mtu(tcpedit_t *tcpedit, int dlt) break; case DLT_LINUX_SLL: + case DLT_LINUX_SLL2: mtu = 16436; break; diff --git a/src/tcpedit/plugins/dlt_linuxsll2/linuxsll2.c b/src/tcpedit/plugins/dlt_linuxsll2/linuxsll2.c index 828cb0416..2c5812166 100644 --- a/src/tcpedit/plugins/dlt_linuxsll2/linuxsll2.c +++ b/src/tcpedit/plugins/dlt_linuxsll2/linuxsll2.c @@ -59,7 +59,7 @@ dlt_linuxsll2_register(tcpeditdlt_t *ctx) plugin->requires += 0; - /* what is our DLT value? */ + /* 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 */ @@ -85,7 +85,6 @@ dlt_linuxsll2_register(tcpeditdlt_t *ctx) 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, @@ -104,8 +103,15 @@ dlt_linuxsll2_init(tcpeditdlt_t *ctx) } /* allocate memory for our decode extra data */ - ctx->decoded_extra_size = sizeof(linuxsll2_extra_t); - ctx->decoded_extra = safe_malloc(ctx->decoded_extra_size); + 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); @@ -130,13 +136,14 @@ dlt_linuxsll2_cleanup(tcpeditdlt_t *ctx) return TCPEDIT_ERROR; } - /* FIXME: make this function do something if necessary */ if (ctx->decoded_extra != NULL) { safe_free(ctx->decoded_extra); ctx->decoded_extra = NULL; ctx->decoded_extra_size = 0; } + safe_free(plugin->name); + plugin->name = NULL; if (plugin->config != NULL) { safe_free(plugin->config); plugin->config = NULL; @@ -255,18 +262,18 @@ dlt_linuxsll2_get_layer3(tcpeditdlt_t *ctx, u_char *packet, const int pktlen) * like SPARC */ u_char * -dlt_linuxsll2_merge_layer3(tcpeditdlt_t *ctx, u_char *packet, const int pktlen, u_char *l3data) +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(l3data); + 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, l3data, l2len); + return tcpedit_dlt_l3data_merge(ctx, packet, pktlen, ipv4_data ?: ipv6_data, l2len); } /* @@ -301,17 +308,13 @@ dlt_linuxsll2_get_mac(tcpeditdlt_t *ctx, tcpeditdlt_mac_type_t mac, const u_char switch(mac) { case SRC_MAC: memcpy(ctx->srcmac, &packet[6], 8); /* linuxssl defines the src mac field to be 8 bytes, not 6 */ - return(ctx->srcmac); - break; - + return ctx->srcmac; case DST_MAC: - return(NULL); break; - default: errx(-1, "Invalid tcpeditdlt_mac_type_t: %d", mac); } - return(NULL); + return NULL; } tcpeditdlt_l2addr_type_t diff --git a/src/tcpedit/plugins/dlt_linuxsll2/linuxsll2.h b/src/tcpedit/plugins/dlt_linuxsll2/linuxsll2.h index 7c3b7add5..0a76988bd 100644 --- a/src/tcpedit/plugins/dlt_linuxsll2/linuxsll2.h +++ b/src/tcpedit/plugins/dlt_linuxsll2/linuxsll2.h @@ -37,7 +37,11 @@ int dlt_linuxsll2_decode(tcpeditdlt_t *ctx, const u_char *packet, const int pktl 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, const int pktlen); u_char *dlt_linuxsll2_get_layer3(tcpeditdlt_t *ctx, u_char *packet, const int pktlen); -u_char *dlt_linuxsll2_merge_layer3(tcpeditdlt_t *ctx, u_char *packet, const int pktlen, u_char *l3data); +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, const int pktlen); u_char *dlt_linuxsll2_get_mac(tcpeditdlt_t *ctx, tcpeditdlt_mac_type_t mac, const u_char *packet, const int pktlen); diff --git a/src/tcpedit/plugins/dlt_linuxsll2/linuxsll2_types.h b/src/tcpedit/plugins/dlt_linuxsll2/linuxsll2_types.h index 066143297..d44a2cbb9 100644 --- a/src/tcpedit/plugins/dlt_linuxsll2/linuxsll2_types.h +++ b/src/tcpedit/plugins/dlt_linuxsll2/linuxsll2_types.h @@ -55,7 +55,7 @@ typedef struct { typedef struct { u_int16_t proto; /* Ethernet protocol type */ u_int16_t mbz; /* reserved */ - u_int32_t iindex; /* iface index */ + u_int32_t if_index; /* iface index */ u_int16_t type; /* linux ARPHRD_* values for link-layer device type. See: * http://www.gelato.unsw.edu.au/lxr/source/include/linux/if_arp.h */ diff --git a/src/tcpprep.c b/src/tcpprep.c index d17014c0b..52fdc8aa3 100644 --- a/src/tcpprep.c +++ b/src/tcpprep.c @@ -108,6 +108,7 @@ main(int argc, char *argv[]) switch (pcap_datalink(options->pcap)) { case DLT_EN10MB: case DLT_LINUX_SLL: + case DLT_LINUX_SLL2: case DLT_RAW: case DLT_C_HDLC: case DLT_JUNIPER_ETHER: diff --git a/src/tcprewrite_opts.def b/src/tcprewrite_opts.def index 42f341796..a3f400776 100644 --- a/src/tcprewrite_opts.def +++ b/src/tcprewrite_opts.def @@ -63,6 +63,8 @@ tcprewrite currently supports reading the following DLT types: @item @var{DLT_LINUX_SLL} aka Linux Cooked Socket @item +@var{DLT_LINUX_SLL2} aka Linux Cooked Socket v2 +@item @var{DLT_RAW} aka RAW IP @item @var{DLT_NULL} aka BSD Loopback