From 2bcc60885d8dc61d49608cf9125a2432607631b1 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Wed, 3 Jul 2013 16:44:23 +0200 Subject: pcap: support for various linktypes Add a device_type() method to get the assigned dev->type from the kernel, and add support for automatic selection of the correct pcap file header's linktype. This needs to be integrated into the core code though. Signed-off-by: Daniel Borkmann --- dev.c | 24 +++++++++++++ dev.h | 1 + pcap_io.h | 117 +++++++++++++++++++++++++++++++++++++++++++++++++++++++------- 3 files changed, 129 insertions(+), 13 deletions(-) diff --git a/dev.c b/dev.c index 3e2e7af..f109a61 100644 --- a/dev.c +++ b/dev.c @@ -34,6 +34,30 @@ int device_ifindex(const char *ifname) return index; } +int device_type(const char *ifname) +{ + int ret, sock, type; + struct ifreq ifr; + + if (!strncmp("any", ifname, strlen("any"))) + return 0; + + sock = af_socket(AF_INET); + + memset(&ifr, 0, sizeof(ifr)); + strlcpy(ifr.ifr_name, ifname, IFNAMSIZ); + + ret = ioctl(sock, SIOCGIFHWADDR, &ifr); + if (unlikely(ret)) + panic("Cannot get iftype from device!\n"); + + /* dev->type */ + type = ifr.ifr_hwaddr.sa_family; + close(sock); + + return type; +} + static int __device_address6(const char *ifname, struct sockaddr_storage *ss) { int ret, family, found = -EINVAL; diff --git a/dev.h b/dev.h index cebcee4..87751c6 100644 --- a/dev.h +++ b/dev.h @@ -7,6 +7,7 @@ extern int device_mtu(const char *ifname); extern int device_address(const char *ifname, int af, struct sockaddr_storage *ss); extern int device_ifindex(const char *ifname); +extern int device_type(const char *ifname); extern short device_get_flags(const char *ifname); extern void device_set_flags(const char *ifname, const short flags); extern int device_up_and_running(char *ifname); diff --git a/pcap_io.h b/pcap_io.h index 5488788..18ce8ea 100644 --- a/pcap_io.h +++ b/pcap_io.h @@ -17,6 +17,7 @@ #include "built_in.h" #include "die.h" +#include "dev.h" #include "ioops.h" #define TCPDUMP_MAGIC 0xa1b2c3d4 @@ -33,9 +34,28 @@ #define PCAP_TSOURCE_SYS_HARDWARE 2 #define PCAP_TSOURCE_RAW_HARDWARE 3 -#define LINKTYPE_EN10MB 1 /* Ethernet (10Mb) */ -#define LINKTYPE_IEEE802_11 105 /* IEEE 802.11 wireless */ -#define LINKTYPE_NETLINK 253 /* Netlink messages */ +#define LINKTYPE_NULL 0 +#define LINKTYPE_EN10MB 1 +#define LINKTYPE_EN3MB 2 +#define LINKTYPE_AX25 3 +#define LINKTYPE_PRONET 4 +#define LINKTYPE_CHAOS 5 +#define LINKTYPE_IEEE802 6 +#define LINKTYPE_SLIP 8 +#define LINKTYPE_PPP 9 +#define LINKTYPE_FDDI 10 +#define LINKTYPE_ATM_CLIP 19 +#define LINKTYPE_C_HDLC 104 +#define LINKTYPE_IEEE802_11 105 +#define LINKTYPE_FRELAY 107 +#define LINKTYPE_ECONET 115 +#define LINKTYPE_ARCNET_LINUX 129 +#define LINKTYPE_LINUX_IRDA 144 +#define LINKTYPE_CAN20B 190 +#define LINKTYPE_IEEE802_15_4_LINUX 191 +#define LINKTYPE_INFINIBAND 247 +#define LINKTYPE_NETLINK 253 +#define LINKTYPE_MAX 254 struct pcap_filehdr { uint32_t magic; @@ -149,6 +169,51 @@ static inline uint16_t tp_to_pcap_tsource(uint32_t status) return 0; } +static inline int pcap_devtype_to_linktype(const char *ifname) +{ + int type = device_type(ifname); + + case (type) { + case ARPHRD_TUNNEL: + case ARPHRD_TUNNEL6: + case ARPHRD_LOOPBACK: + case ARPHRD_SIT: + case ARPHRD_IPDDP: + case ARPHRD_IPGRE: + case ARPHRD_IP6GRE: + case ARPHRD_ETHER: return LINKTYPE_EN10MB; + case ARPHRD_IEEE80211_PRISM: + case ARPHRD_IEEE80211_RADIOTAP: + case ARPHRD_IEEE80211: return LINKTYPE_IEEE802_11; + case ARPHRD_NETLINK: return LINKTYPE_NETLINK; + case ARPHRD_EETHER: return LINKTYPE_EN3MB; + case ARPHRD_AX25: return LINKTYPE_AX25; + case ARPHRD_CHAOS: return LINKTYPE_CHAOS; + case ARPHRD_PRONET: return LINKTYPE_PRONET; + case ARPHRD_IEEE802_TR: + case ARPHRD_IEEE802: return LINKTYPE_IEEE802; + case ARPHRD_INFINIBAND: return LINKTYPE_INFINIBAND; + case ARPHRD_ATM: return LINKTYPE_ATM_CLIP; + case ARPHRD_DLCI: return LINKTYPE_FRELAY; + case ARPHRD_ARCNET: return LINKTYPE_ARCNET_LINUX; + case ARPHRD_CSLIP: + case ARPHRD_CSLIP6: + case ARPHRD_SLIP6: + case ARPHRD_SLIP: return LINKTYPE_SLIP; + case ARPHRD_PPP: return LINKTYPE_PPP; + case ARPHRD_CAN: return LINKTYPE_CAN20B; + case ARPHRD_ECONET: return LINKTYPE_ECONET; + case ARPHRD_HDLC: + case ARPHRD_RAWHDLC: + case ARPHRD_CISCO: return LINKTYPE_C_HDLC; + case ARPHRD_FDDI: return LINKTYPE_FDDI; + case ARPHRD_IEEE802154_MONITOR: + case ARPHRD_IEEE802154: return LINKTYPE_IEEE802_15_4_LINUX; + case ARPHRD_IRDA: return LINKTYPE_LINUX_IRDA; + default: return LINKTYPE_NULL; + } +} + static inline void pcap_check_magic(uint32_t magic) { switch (magic) { @@ -567,22 +632,48 @@ static inline void pcap_prepare_header(struct pcap_filehdr *hdr, uint32_t magic, hdr->linktype = swapped ? ___constant_swab32(linktype) : linktype; } +static const bool pcap_supported_linktypes[LINKTYPE_MAX] __maybe_unused = { + [LINKTYPE_NULL] = true, + [LINKTYPE_EN10MB] = true, + [LINKTYPE_EN3MB] = true, + [LINKTYPE_AX25] = true, + [LINKTYPE_PRONET] = true, + [LINKTYPE_CHAOS] = true, + [LINKTYPE_IEEE802] = true, + [LINKTYPE_SLIP] = true, + [LINKTYPE_PPP] = true, + [LINKTYPE_FDDI] = true, + [LINKTYPE_ATM_CLIP] = true, + [LINKTYPE_C_HDLC] = true, + [LINKTYPE_IEEE802_11] = true, + [LINKTYPE_FRELAY] = true, + [LINKTYPE_ECONET] = true, + [LINKTYPE_ARCNET_LINUX] = true, + [LINKTYPE_LINUX_IRDA] = true, + [LINKTYPE_CAN20B] = true, + [LINKTYPE_IEEE802_15_4_LINUX] = true, + [LINKTYPE_INFINIBAND] = true, + [LINKTYPE_NETLINK] = true, +}; + static inline void pcap_validate_header(const struct pcap_filehdr *hdr) { + bool good = false; + uint32_t linktype_swab = bswap_32(hdr->linktype); pcap_check_magic(hdr->magic); - switch (hdr->linktype) { - case LINKTYPE_EN10MB: - case LINKTYPE_IEEE802_11: - case LINKTYPE_NETLINK: - case ___constant_swab32(LINKTYPE_EN10MB): - case ___constant_swab32(LINKTYPE_IEEE802_11): - case ___constant_swab32(LINKTYPE_NETLINK): - break; - default: - panic("This file has not a valid pcap header\n"); + if (hdr->linktype < LINKTYPE_MAX) { + if (!pcap_supported_linktypes[hdr->linktype]) + good = true; + } + + if (linktype_swab < LINKTYPE_MAX) { + if (!pcap_supported_linktypes[linktype_swab]) + good = true; } + if (!good) + panic("This file has an unsupported pcap header!\n"); if (unlikely(hdr->version_major != PCAP_VERSION_MAJOR) && ___constant_swab16(hdr->version_major) != PCAP_VERSION_MAJOR) panic("This file has not a valid pcap header\n"); -- cgit v1.2.3-54-g00ecf