diff options
author | Mario Rugiero <mario.rugiero@helpsystems.com> | 2019-10-07 16:37:04 -0300 |
---|---|---|
committer | Mario Rugiero <mario.rugiero@helpsystems.com> | 2019-10-07 16:37:04 -0300 |
commit | f4a26d7d25ac19e547c2f5b6ca4fa60355fb3654 (patch) | |
tree | 287e1133b33b0eb48856df355e2136b2fa37419c /pcap-linux.c | |
parent | 711885e9bf0e31eac2b1717f67ac862224fc42a7 (diff) |
Linux: remove support for SOCK_PACKET.
Diffstat (limited to 'pcap-linux.c')
-rw-r--r-- | pcap-linux.c | 652 |
1 files changed, 71 insertions, 581 deletions
diff --git a/pcap-linux.c b/pcap-linux.c index 9a5d98d5..4c43301a 100644 --- a/pcap-linux.c +++ b/pcap-linux.c @@ -67,48 +67,6 @@ * SUCH DAMAGE. */ -/* - * Known problems with 2.0[.x] kernels: - * - * - The loopback device gives every packet twice; on 2.2[.x] kernels, - * if we use PF_PACKET, we can filter out the transmitted version - * of the packet by using data in the "sockaddr_ll" returned by - * "recvfrom()", but, on 2.0[.x] kernels, we have to use - * PF_INET/SOCK_PACKET, which means "recvfrom()" supplies a - * "sockaddr_pkt" which doesn't give us enough information to let - * us do that. - * - * - We have to set the interface's IFF_PROMISC flag ourselves, if - * we're to run in promiscuous mode, which means we have to turn - * it off ourselves when we're done; the kernel doesn't keep track - * of how many sockets are listening promiscuously, which means - * it won't get turned off automatically when no sockets are - * listening promiscuously. We catch "pcap_close()" and, for - * interfaces we put into promiscuous mode, take them out of - * promiscuous mode - which isn't necessarily the right thing to - * do, if another socket also requested promiscuous mode between - * the time when we opened the socket and the time when we close - * the socket. - * - * - MSG_TRUNC isn't supported, so you can't specify that "recvfrom()" - * return the amount of data that you could have read, rather than - * the amount that was returned, so we can't just allocate a buffer - * whose size is the snapshot length and pass the snapshot length - * as the byte count, and also pass MSG_TRUNC, so that the return - * value tells us how long the packet was on the wire. - * - * This means that, if we want to get the actual size of the packet, - * so we can return it in the "len" field of the packet header, - * we have to read the entire packet, not just the part that fits - * within the snapshot length, and thus waste CPU time copying data - * from the kernel that our caller won't see. - * - * We have to get the actual size, and supply it in "len", because - * otherwise, the IP dissector in tcpdump, for example, will complain - * about "truncated-ip", as the packet will appear to have been - * shorter, on the wire, than the IP header said it should have been. - */ - #define _GNU_SOURCE @@ -146,69 +104,23 @@ #include "diag-control.h" -/* - * If PF_PACKET is defined, we can use {SOCK_RAW,SOCK_DGRAM}/PF_PACKET - * sockets rather than SOCK_PACKET sockets. - * - * To use them, we include <linux/if_packet.h> rather than - * <netpacket/packet.h>; we do so because - * - * some Linux distributions (e.g., Slackware 4.0) have 2.2 or - * later kernels and libc5, and don't provide a <netpacket/packet.h> - * file; - * - * not all versions of glibc2 have a <netpacket/packet.h> file - * that defines stuff needed for some of the 2.4-or-later-kernel - * features, so if the system has a 2.4 or later kernel, we - * still can't use those features. - * - * We're already including a number of other <linux/XXX.h> headers, and - * this code is Linux-specific (no other OS has PF_PACKET sockets as - * a raw packet capture mechanism), so it's not as if you gain any - * useful portability by using <netpacket/packet.h> - * - * XXX - should we just include <linux/if_packet.h> even if PF_PACKET - * isn't defined? It only defines one data structure in 2.0.x, so - * it shouldn't cause any problems. - */ -#ifdef PF_PACKET -# include <linux/if_packet.h> - - /* - * On at least some Linux distributions (for example, Red Hat 5.2), - * there's no <netpacket/packet.h> file, but PF_PACKET is defined if - * you include <sys/socket.h>, but <linux/if_packet.h> doesn't define - * any of the PF_PACKET stuff such as "struct sockaddr_ll" or any of - * the PACKET_xxx stuff. - * - * So we check whether PACKET_HOST is defined, and assume that we have - * PF_PACKET sockets only if it is defined. - */ -# ifdef PACKET_HOST -# define HAVE_PF_PACKET_SOCKETS -# ifdef PACKET_AUXDATA -# define HAVE_PACKET_AUXDATA -# endif /* PACKET_AUXDATA */ -# endif /* PACKET_HOST */ - - - /* check for memory mapped access avaibility. We assume every needed - * struct is defined if the macro TPACKET_HDRLEN is defined, because it - * uses many ring related structs and macros */ -# ifdef PCAP_SUPPORT_PACKET_RING -# ifdef TPACKET_HDRLEN -# define HAVE_PACKET_RING -# ifdef TPACKET3_HDRLEN -# define HAVE_TPACKET3 -# endif /* TPACKET3_HDRLEN */ -# ifdef TPACKET2_HDRLEN -# define HAVE_TPACKET2 -# else /* TPACKET2_HDRLEN */ -# define TPACKET_V1 0 /* Old kernel with only V1, so no TPACKET_Vn defined */ -# endif /* TPACKET2_HDRLEN */ -# endif /* TPACKET_HDRLEN */ -# endif /* PCAP_SUPPORT_PACKET_RING */ -#endif /* PF_PACKET */ + +/* check for memory mapped access avaibility. We assume every needed + * struct is defined if the macro TPACKET_HDRLEN is defined, because it + * uses many ring related structs and macros */ +#ifdef PCAP_SUPPORT_PACKET_RING +#ifdef TPACKET_HDRLEN +# define HAVE_PACKET_RING +# ifdef TPACKET3_HDRLEN +# define HAVE_TPACKET3 +# endif /* TPACKET3_HDRLEN */ +# ifdef TPACKET2_HDRLEN +# define HAVE_TPACKET2 +# else /* TPACKET2_HDRLEN */ +# define TPACKET_V1 0 /* Old kernel with only V1, so no TPACKET_Vn defined */ +# endif /* TPACKET2_HDRLEN */ +#endif /* TPACKET_HDRLEN */ +#endif /* PCAP_SUPPORT_PACKET_RING */ #ifdef SO_ATTACH_FILTER #include <linux/types.h> @@ -311,7 +223,6 @@ struct pcap_linux { int blocks_to_filter_in_userland; int must_do_on_close; /* stuff we must do when we close */ int timeout; /* timeout for buffering */ - int sock_packet; /* using Linux 2.0 compatible interface */ int cooked; /* using SOCK_DGRAM rather than SOCK_RAW */ int ifindex; /* interface index of device we're bound to */ int lo_ifindex; /* interface index of the loopback device */ @@ -347,13 +258,10 @@ static int get_if_flags(const char *, bpf_u_int32 *, char *); static int is_wifi(int, const char *); static void map_arphrd_to_dlt(pcap_t *, int, int, const char *, int); static int pcap_activate_linux(pcap_t *); -static int activate_old(pcap_t *, int); -#ifdef HAVE_PF_PACKET_SOCKETS -static int activate_new(pcap_t *, int); +static int activate_sock(pcap_t *, int); #ifdef HAVE_PACKET_RING static int activate_mmap(pcap_t *, int *); #endif -#endif /* HAVE_PF_PACKET_SOCKETS */ static int pcap_can_set_rfmon_linux(pcap_t *); static int pcap_read_linux(pcap_t *, int, pcap_handler, u_char *); static int pcap_read_packet(pcap_t *, pcap_handler, u_char *); @@ -469,19 +377,15 @@ static void pcap_oneshot_mmap(u_char *user, const struct pcap_pkthdr *h, /* * Wrap some ioctl calls */ -#ifdef HAVE_PF_PACKET_SOCKETS static int iface_get_id(int fd, const char *device, char *ebuf); -#endif /* HAVE_PF_PACKET_SOCKETS */ static int iface_get_mtu(int fd, const char *device, char *ebuf); static int iface_get_arptype(int fd, const char *device, char *ebuf); -#ifdef HAVE_PF_PACKET_SOCKETS static int iface_bind(int fd, int ifindex, char *ebuf, int protocol); #ifdef IW_MODE_MONITOR static int has_wext(int sock_fd, const char *device, char *ebuf); #endif /* IW_MODE_MONITOR */ static int enter_rfmon_mode(pcap_t *handle, int sock_fd, const char *device); -#endif /* HAVE_PF_PACKET_SOCKETS */ #if defined(HAVE_LINUX_NET_TSTAMP_H) && defined(PACKET_TIMESTAMP) static int iface_ethtool_get_ts_info(const char *device, pcap_t *handle, char *ebuf); @@ -1478,20 +1382,6 @@ static void pcap_breakloop_linux(pcap_t *handle) } #endif -#ifdef HAVE_PF_PACKET_SOCKETS -/* - * We need a special error return to indicate that PF_PACKET sockets - * aren't supported; that's not a fatal error, it's just an indication - * that we have a pre-2.2 kernel, and must fall back on PF_INET/SOCK_PACKET - * sockets. - * - * We assume, for now, that we won't have so many PCAP_ERROR_ values that - * -128 will be used, and use that as the error (it fits into a byte, - * so comparison against it should be doable without too big an immediate - * value - yeah, I know, premature optimization is the root of all evil...). - */ -#define PCAP_ERROR_NO_PF_PACKET_SOCKETS -128 - /* * Open a PF_PACKET socket. */ @@ -1511,24 +1401,6 @@ open_pf_packet_socket(pcap_t *handle, int cooked) socket(PF_PACKET, SOCK_RAW, protocol); if (sock_fd == -1) { - if (errno == EINVAL || errno == EAFNOSUPPORT) { - /* - * PF_PACKET sockets aren't supported. - * - * If this is the first attempt to open a PF_PACKET - * socket, our caller will just want to try a - * PF_INET/SOCK_PACKET socket; in other cases, we - * already succeeded opening a PF_PACKET socket, - * but are just switching to cooked from raw, in - * which case this is a fatal error (and "can't - * happen", because the kernel isn't going to - * spontaneously drop its support for PF_PACKET - * sockets). - */ - snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, - "PF_PACKET sockets not supported (this \"can't happen\"!"); - return PCAP_ERROR_NO_PF_PACKET_SOCKETS; - } if (errno == EPERM || errno == EACCES) { /* * You don't have permission to open the @@ -1547,7 +1419,6 @@ open_pf_packet_socket(pcap_t *handle, int cooked) } return sock_fd; } -#endif /* * Get a handle for a live capture from the given device. You can @@ -1645,49 +1516,18 @@ pcap_activate_linux(pcap_t *handle) if (handle->opt.promisc) handlep->sysfs_dropped = linux_if_drops(handlep->device); -#ifdef HAVE_PF_PACKET_SOCKETS /* - * Current Linux kernels use the protocol family PF_PACKET to - * allow direct access to all packets on the network while - * older kernels had a special socket type SOCK_PACKET to - * implement this feature. - * While this old implementation is kind of obsolete we need - * to be compatible with older kernels for a while so we are - * trying both methods with the newer method preferred. - * - * Try to activate with a PF_PACKET socket. If the "any" device - * was specified, we open a SOCK_DGRAM socket for the cooked - * interface, otherwise we first try a SOCK_RAW socket for - * the raw interface. + * If the "any" device is specified, try to open a SOCK_DGRAM. + * Otherwise, open a SOCK_RAW. */ - ret = activate_new(handle, is_any_device); + ret = activate_sock(handle, is_any_device); if (ret < 0) { - if (ret != PCAP_ERROR_NO_PF_PACKET_SOCKETS) { - /* - * Fatal error; the return value is the error code, - * and handle->errbuf has been set to an appropriate - * error message. - */ - return ret; - } - /* - * We don't support PF_PACKET/SOCK_whatever - * sockets; try the old mechanism. + * Fatal error; the return value is the error code, + * and handle->errbuf has been set to an appropriate + * error message. */ - ret = activate_old(handle, is_any_device); - if (ret != 0) { - /* - * Both methods to open the packet socket - * failed. - * - * Tidy up and report our failure - * (handle->errbuf is expected to be set - * by the functions above). - */ - status = ret; - goto fail; - } + return ret; } else { #ifdef HAVE_PACKET_RING /* @@ -1729,24 +1569,6 @@ pcap_activate_linux(pcap_t *handle) } #endif /* HAVE_PACKET_RING */ } -#else /* HAVE_PF_PACKET_SOCKETS */ - /* - * We don't support PF_PACKET/SOCK_whatever sockets, so we must - * try the old mechanism. - */ - ret = activate_old(handle, is_any_device); - if (ret != 0) { - /* - * That failed. - * - * Tidy up and report our failure - * (handle->errbuf is expected to be set - * by the functions above). - */ - status = ret; - goto fail; - } -#endif /* HAVE_PF_PACKET_SOCKETS */ /* * We set up the socket, but not with memory-mapped access. @@ -1873,11 +1695,7 @@ pcap_read_packet(pcap_t *handle, pcap_handler callback, u_char *userdata) struct pcap_linux *handlep = handle->priv; u_char *bp; int offset; -#ifdef HAVE_PF_PACKET_SOCKETS struct sockaddr_ll from; -#else - struct sockaddr from; -#endif #if defined(HAVE_PACKET_AUXDATA) && defined(HAVE_STRUCT_TPACKET_AUXDATA_TP_VLAN_TCI) struct iovec iov; struct msghdr msg; @@ -1894,7 +1712,6 @@ pcap_read_packet(pcap_t *handle, pcap_handler callback, u_char *userdata) struct pcap_pkthdr pcap_header; struct bpf_aux_data aux_data; -#ifdef HAVE_PF_PACKET_SOCKETS /* * If this is a cooked device, leave extra room for a * fake packet header. @@ -1906,13 +1723,6 @@ pcap_read_packet(pcap_t *handle, pcap_handler callback, u_char *userdata) offset = SLL_HDR_LEN; } else offset = 0; -#else - /* - * This system doesn't have PF_PACKET sockets, so it doesn't - * support cooked devices. - */ - offset = 0; -#endif /* * Receive a single packet from the kernel. @@ -1996,36 +1806,26 @@ pcap_read_packet(pcap_t *handle, pcap_handler callback, u_char *userdata) } } -#ifdef HAVE_PF_PACKET_SOCKETS - if (!handlep->sock_packet) { - /* - * Unfortunately, there is a window between socket() and - * bind() where the kernel may queue packets from any - * interface. If we're bound to a particular interface, - * discard packets not from that interface. - * - * (If socket filters are supported, we could do the - * same thing we do when changing the filter; however, - * that won't handle packet sockets without socket - * filter support, and it's a bit more complicated. - * It would save some instructions per packet, however.) - */ - if (handlep->ifindex != -1 && - from.sll_ifindex != handlep->ifindex) - return 0; + /* + * Unfortunately, there is a window between socket() and + * bind() where the kernel may queue packets from any + * interface. If we're bound to a particular interface, + * discard packets not from that interface. + * + * (If socket filters are supported, we could do the + * same thing we do when changing the filter; however, + * that won't handle packet sockets without socket + * filter support, and it's a bit more complicated. + * It would save some instructions per packet, however.) + */ + if (handlep->ifindex != -1 && + from.sll_ifindex != handlep->ifindex) + return 0; - /* - * Do checks based on packet direction. - * We can only do this if we're using PF_PACKET; the - * address returned for SOCK_PACKET is a "sockaddr_pkt" - * which lacks the relevant packet type information. - */ - if (!linux_check_direction(handle, &from)) - return 0; - } -#endif + /* Do checks based on packet direction. */ + if (!linux_check_direction(handle, &from)) + return 0; -#ifdef HAVE_PF_PACKET_SOCKETS /* * If this is a cooked device, fill in the fake packet header. */ @@ -2134,7 +1934,6 @@ pcap_read_packet(pcap_t *handle, pcap_handler callback, u_char *userdata) } } #endif /* defined(HAVE_PACKET_AUXDATA) && defined(HAVE_STRUCT_TPACKET_AUXDATA_TP_VLAN_TCI) */ -#endif /* HAVE_PF_PACKET_SOCKETS */ /* * XXX: According to the kernel source we should get the real @@ -2262,34 +2061,29 @@ pcap_inject_linux(pcap_t *handle, const void *buf, int size) struct pcap_linux *handlep = handle->priv; int ret; -#ifdef HAVE_PF_PACKET_SOCKETS - if (!handlep->sock_packet) { - /* PF_PACKET socket */ - if (handlep->ifindex == -1) { - /* - * We don't support sending on the "any" device. - */ - pcap_strlcpy(handle->errbuf, - "Sending packets isn't supported on the \"any\" device", - PCAP_ERRBUF_SIZE); - return (-1); - } + if (handlep->ifindex == -1) { + /* + * We don't support sending on the "any" device. + */ + pcap_strlcpy(handle->errbuf, + "Sending packets isn't supported on the \"any\" device", + PCAP_ERRBUF_SIZE); + return (-1); + } - if (handlep->cooked) { - /* - * We don't support sending on cooked-mode sockets. - * - * XXX - how do you send on a bound cooked-mode - * socket? - * Is a "sendto()" required there? - */ - pcap_strlcpy(handle->errbuf, - "Sending packets isn't supported in cooked mode", - PCAP_ERRBUF_SIZE); - return (-1); - } + if (handlep->cooked) { + /* + * We don't support sending on cooked-mode sockets. + * + * XXX - how do you send on a bound cooked-mode + * socket? + * Is a "sendto()" required there? + */ + pcap_strlcpy(handle->errbuf, + "Sending packets isn't supported in cooked mode", + PCAP_ERRBUF_SIZE); + return (-1); } -#endif ret = (int)send(handle->fd, buf, size, 0); if (ret == -1) { @@ -3187,21 +2981,10 @@ pcap_setfilter_linux(pcap_t *handle, struct bpf_program *filter) static int pcap_setdirection_linux(pcap_t *handle, pcap_direction_t d) { -#ifdef HAVE_PF_PACKET_SOCKETS struct pcap_linux *handlep = handle->priv; - if (!handlep->sock_packet) { - handle->direction = d; - return 0; - } -#endif - /* - * We're not using PF_PACKET sockets, so we can't determine - * the direction of the packet. - */ - snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, - "Setting direction is not supported on SOCK_PACKET sockets"); - return -1; + handle->direction = d; + return 0; } static int @@ -3305,7 +3088,7 @@ static void map_arphrd_to_dlt(pcap_t *handle, int sock_fd, int arptype, * XXX - are there any other sorts of "fake Ethernet" that * have ARPHRD_ETHER but that shouldn't offer DLT_DOCSIS as * a Cisco CMTS won't put traffic onto it or get traffic - * bridged onto it? ISDN is handled in "activate_new()", + * bridged onto it? ISDN is handled in "activate_sock()", * as we fall back on cooked mode there, and we use * is_wifi() to check for 802.11 devices; are there any * others? @@ -3661,7 +3444,7 @@ static void map_arphrd_to_dlt(pcap_t *handle, int sock_fd, int arptype, /* We need to save packet direction for IrDA decoding, * so let's use "Linux-cooked" mode. Jean II * - * XXX - this is handled in activate_new(). */ + * XXX - this is handled in activate_sock(). */ /* handlep->cooked = 1; */ break; @@ -3703,7 +3486,7 @@ static void map_arphrd_to_dlt(pcap_t *handle, int sock_fd, int arptype, * pick up the netlink protocol type such as NETLINK_ROUTE, * NETLINK_GENERIC, NETLINK_FIB_LOOKUP, etc. * - * XXX - this is handled in activate_new(). + * XXX - this is handled in activate_sock(). */ /* handlep->cooked = 1; */ break; @@ -3721,9 +3504,6 @@ static void map_arphrd_to_dlt(pcap_t *handle, int sock_fd, int arptype, } } -#ifdef HAVE_PF_PACKET_SOCKETS -/* ===== Functions to interface to the newer kernels ================== */ - #ifdef PACKET_RESERVE static void set_dlt_list_cooked(pcap_t *handle, int sock_fd) @@ -3768,7 +3548,7 @@ set_dlt_list_cooked(pcap_t *handle _U_, int sock_fd _U_) * Returns 0 on success and a PCAP_ERROR_ value on failure. */ static int -activate_new(pcap_t *handle, int is_any_device) +activate_sock(pcap_t *handle, int is_any_device) { struct pcap_linux *handlep = handle->priv; const char *device = handle->opt.device; @@ -3792,9 +3572,6 @@ activate_new(pcap_t *handle, int is_any_device) return sock_fd; } - /* It seems the kernel supports the new interface. */ - handlep->sock_packet = 0; - /* * Get the interface index of the loopback device. * If the attempt fails, don't fail, just set the @@ -3888,21 +3665,6 @@ activate_new(pcap_t *handle, int is_any_device) } sock_fd = open_pf_packet_socket(handle, 1); if (sock_fd < 0) { - if (sock_fd == PCAP_ERROR_NO_PF_PACKET_SOCKETS) { - /* - * We don't support PF_PACKET/SOCK_whatever - * sockets. This should never happen, - * because we don't support cooked mode - * without those sockets, so we - * shouldn't get called if we're - * running on a kernel old enough - * not to support them. - * - * The error message has already been - * filled in appropriately. - */ - sock_fd = PCAP_ERROR; - } /* * Fatal error; the return value is the * error code, and handle->errbuf has @@ -4050,14 +3812,6 @@ activate_new(pcap_t *handle, int is_any_device) #endif /* HAVE_PACKET_AUXDATA */ /* - * This is a 2.2[.x] or later kernel (we know that - * because we're not using a SOCK_PACKET socket - - * PF_PACKET is supported only in 2.2 and later - * kernels). - * - * We can safely pass "recvfrom()" a byte count - * based on the snapshot length. - * * If we're in cooked mode, make the snapshot length * large enough to hold a "cooked mode" header plus * 1 byte of packet data (so we don't pass a byte @@ -4201,7 +3955,7 @@ activate_mmap(pcap_t *handle, int *status) * warnings or to a PCAP_WARNING_ value if there is a warning. * * Override some defaults and inherit the other fields from - * activate_new. + * activate_sock. * handle->offset is used to get the current position into the rx ring. * handle->cc is used to store the ring size. */ @@ -6971,8 +6725,6 @@ iface_get_offload(pcap_t *handle _U_) #endif /* HAVE_PACKET_RING */ -#endif /* HAVE_PF_PACKET_SOCKETS */ - static struct dsa_proto { const char *name; bpf_u_int32 linktype; @@ -7055,268 +6807,6 @@ iface_dsa_get_proto_info(const char *device, pcap_t *handle) return PCAP_ERROR; } -/* ===== Functions to interface to the older kernels ================== */ - -/* - * Try to open a packet socket using the old kernel interface. - * Returns 0 on success and a PCAP_ERROR_ value on an error. - */ -static int -activate_old(pcap_t *handle, int is_any_device) -{ - struct pcap_linux *handlep = handle->priv; - int err; - int arptype; - struct ifreq ifr; - const char *device = handle->opt.device; - struct utsname utsname; - int mtu; - - /* - * PF_INET/SOCK_PACKET sockets must be bound to a device, so we - * can't support the "any" device. - */ - if (is_any_device) { - pcap_strlcpy(handle->errbuf, "pcap_activate: The \"any\" device isn't supported on 2.0[.x]-kernel systems", - PCAP_ERRBUF_SIZE); - return PCAP_ERROR; - } - - /* Open the socket */ - handle->fd = socket(PF_INET, SOCK_PACKET, htons(ETH_P_ALL)); - if (handle->fd == -1) { - err = errno; - pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, - err, "socket"); - if (err == EPERM || err == EACCES) { - /* - * You don't have permission to open the - * socket. - */ - return PCAP_ERROR_PERM_DENIED; - } else { - /* - * Other error. - */ - return PCAP_ERROR; - } - } - - /* It worked - we are using the old interface */ - handlep->sock_packet = 1; - - /* ...which means we get the link-layer header. */ - handlep->cooked = 0; - - /* Bind to the given device */ - if (iface_bind_old(handle->fd, device, handle->errbuf) == -1) { - close(handle->fd); - return PCAP_ERROR; - } - - /* - * Try to get the link-layer type. - */ - arptype = iface_get_arptype(handle->fd, device, handle->errbuf); - if (arptype < 0) { - close(handle->fd); - return arptype; - } - - /* - * Try to find the DLT_ type corresponding to that - * link-layer type. - */ - map_arphrd_to_dlt(handle, handle->fd, arptype, device, 0); - if (handle->linktype == -1) { - snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, - "unknown arptype %d", arptype); - return PCAP_ERROR; - } - - /* Go to promisc mode if requested */ - - if (handle->opt.promisc) { - memset(&ifr, 0, sizeof(ifr)); - pcap_strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); - if (ioctl(handle->fd, SIOCGIFFLAGS, &ifr) == -1) { - pcap_fmt_errmsg_for_errno(handle->errbuf, - PCAP_ERRBUF_SIZE, errno, "SIOCGIFFLAGS"); - close(handle->fd); - return PCAP_ERROR; - } - if ((ifr.ifr_flags & IFF_PROMISC) == 0) { - /* - * Promiscuous mode isn't currently on, - * so turn it on, and remember that - * we should turn it off when the - * pcap_t is closed. - */ - - /* - * If we haven't already done so, arrange - * to have "pcap_close_all()" called when - * we exit. - */ - if (!pcap_do_addexit(handle)) { - /* - * "atexit()" failed; don't put - * the interface in promiscuous - * mode, just give up. - */ - close(handle->fd); - return PCAP_ERROR; - } - - ifr.ifr_flags |= IFF_PROMISC; - if (ioctl(handle->fd, SIOCSIFFLAGS, &ifr) == -1) { - pcap_fmt_errmsg_for_errno(handle->errbuf, - PCAP_ERRBUF_SIZE, errno, "SIOCSIFFLAGS"); - return PCAP_ERROR; - } - handlep->must_do_on_close |= MUST_CLEAR_PROMISC; - - /* - * Add this to the list of pcaps - * to close when we exit. - */ - pcap_add_to_pcaps_to_close(handle); - } - } - - /* - * Compute the buffer size. - * - * We're using SOCK_PACKET, so this might be a 2.0[.x] - * kernel, and might require special handling - check. - */ - if (uname(&utsname) < 0 || - strncmp(utsname.release, "2.0", 3) == 0) { - /* - * Either we couldn't find out what kernel release - * this is, or it's a 2.0[.x] kernel. - * - * In the 2.0[.x] kernel, a "recvfrom()" on - * a SOCK_PACKET socket, with MSG_TRUNC set, will - * return the number of bytes read, so if we pass - * a length based on the snapshot length, it'll - * return the number of bytes from the packet - * copied to userland, not the actual length - * of the packet. - * - * This means that, for example, the IP dissector - * in tcpdump will get handed a packet length less - * than the length in the IP header, and will - * complain about "truncated-ip". - * - * So we don't bother trying to copy from the - * kernel only the bytes in which we're interested, - * but instead copy them all, just as the older - * versions of libpcap for Linux did. - * - * The buffer therefore needs to be big enough to - * hold the largest packet we can get from this - * device. Unfortunately, we can't get the MRU - * of the network; we can only get the MTU. The - * MTU may be too small, in which case a packet larger - * than the buffer size will be truncated *and* we - * won't get the actual packet size. - * - * However, if the snapshot length is larger than - * the buffer size based on the MTU, we use the - * snapshot length as the buffer size, instead; - * this means that with a sufficiently large snapshot - * length we won't artificially truncate packets - * to the MTU-based size. - * - * This mess just one of many problems with packet - * capture on 2.0[.x] kernels; you really want a - * 2.2[.x] or later kernel if you want packet capture - * to work well. - */ - mtu = iface_get_mtu(handle->fd, device, handle->errbuf); - if (mtu == -1) { - close(handle->fd); - return PCAP_ERROR; - } - handle->bufsize = MAX_LINKHEADER_SIZE + mtu; - if (handle->bufsize < (u_int)handle->snapshot) - handle->bufsize = (u_int)handle->snapshot; - } else { - /* - * This is a 2.2[.x] or later kernel. - * - * We can safely pass "recvfrom()" a byte count - * based on the snapshot length. - * - * XXX - this "should not happen", as 2.2[.x] - * kernels all have PF_PACKET sockets, and there's - * no configuration option to disable them without - * disabling SOCK_PACKET sockets, because - * SOCK_PACKET sockets are implemented in the same - * source file, net/packet/af_packet.c. There *is* - * an option to disable SOCK_PACKET sockets so that - * you only have PF_PACKET sockets, and the kernel - * will log warning messages for code that uses - * "obsolete (PF_INET,SOCK_PACKET)". - */ - handle->bufsize = (u_int)handle->snapshot; - } - - /* - * Default value for offset to align link-layer payload - * on a 4-byte boundary. - */ - handle->offset = 0; - - /* - * SOCK_PACKET sockets don't supply information from - * stripped VLAN tags. - */ - handlep->vlan_offset = -1; /* unknown */ - - return 0; -} - -/* - * Bind the socket associated with FD to the given device using the - * interface of the old kernels. - */ -static int -iface_bind_old(int fd, const char *device, char *ebuf) -{ - struct sockaddr saddr; - int err; - socklen_t errlen = sizeof(err); - - memset(&saddr, 0, sizeof(saddr)); - pcap_strlcpy(saddr.sa_data, device, sizeof(saddr.sa_data)); - if (bind(fd, &saddr, sizeof(saddr)) == -1) { - pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, - errno, "bind"); - return -1; - } - - /* Any pending errors, e.g., network is down? */ - - if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &errlen) == -1) { - pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, - errno, "getsockopt (SO_ERROR)"); - return -1; - } - - if (err > 0) { - pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, - err, "bind"); - return -1; - } - - return 0; -} - - -/* ===== System calls available on all supported kernels ============== */ - /* * Query the kernel for the MTU of the given interface. */ |