📄 pcap-linux.c
字号:
handle->dlt_count = 2; } /* FALLTHROUGH */ case ARPHRD_METRICOM: case ARPHRD_LOOPBACK: handle->linktype = DLT_EN10MB; handle->offset = 2; break; case ARPHRD_EETHER: handle->linktype = DLT_EN3MB; break; case ARPHRD_AX25: handle->linktype = DLT_AX25; break; case ARPHRD_PRONET: handle->linktype = DLT_PRONET; break; case ARPHRD_CHAOS: handle->linktype = DLT_CHAOS; break;#ifndef ARPHRD_IEEE802_TR#define ARPHRD_IEEE802_TR 800 /* From Linux 2.4 */#endif case ARPHRD_IEEE802_TR: case ARPHRD_IEEE802: handle->linktype = DLT_IEEE802; handle->offset = 2; break; case ARPHRD_ARCNET: handle->linktype = DLT_ARCNET_LINUX; break;#ifndef ARPHRD_FDDI /* From Linux 2.2.13 */#define ARPHRD_FDDI 774#endif case ARPHRD_FDDI: handle->linktype = DLT_FDDI; handle->offset = 3; break;#ifndef ARPHRD_ATM /* FIXME: How to #include this? */#define ARPHRD_ATM 19#endif case ARPHRD_ATM: /* * The Classical IP implementation in ATM for Linux * supports both what RFC 1483 calls "LLC Encapsulation", * in which each packet has an LLC header, possibly * with a SNAP header as well, prepended to it, and * what RFC 1483 calls "VC Based Multiplexing", in which * different virtual circuits carry different network * layer protocols, and no header is prepended to packets. * * They both have an ARPHRD_ type of ARPHRD_ATM, so * you can't use the ARPHRD_ type to find out whether * captured packets will have an LLC header, and, * while there's a socket ioctl to *set* the encapsulation * type, there's no ioctl to *get* the encapsulation type. * * This means that * * programs that dissect Linux Classical IP frames * would have to check for an LLC header and, * depending on whether they see one or not, dissect * the frame as LLC-encapsulated or as raw IP (I * don't know whether there's any traffic other than * IP that would show up on the socket, or whether * there's any support for IPv6 in the Linux * Classical IP code); * * filter expressions would have to compile into * code that checks for an LLC header and does * the right thing. * * Both of those are a nuisance - and, at least on systems * that support PF_PACKET sockets, we don't have to put * up with those nuisances; instead, we can just capture * in cooked mode. That's what we'll do, if we can. * Otherwise, we'll just fail. */ if (cooked_ok) handle->linktype = DLT_LINUX_SLL; else handle->linktype = -1; break;#ifndef ARPHRD_IEEE80211 /* From Linux 2.4.6 */#define ARPHRD_IEEE80211 801#endif case ARPHRD_IEEE80211: handle->linktype = DLT_IEEE802_11; break;#ifndef ARPHRD_IEEE80211_PRISM /* From Linux 2.4.18 */#define ARPHRD_IEEE80211_PRISM 802#endif case ARPHRD_IEEE80211_PRISM: handle->linktype = DLT_PRISM_HEADER; break;#ifndef ARPHRD_IEEE80211_RADIOTAP /* new */#define ARPHRD_IEEE80211_RADIOTAP 803#endif case ARPHRD_IEEE80211_RADIOTAP: handle->linktype = DLT_IEEE802_11_RADIO; break; case ARPHRD_PPP: /* * Some PPP code in the kernel supplies no link-layer * header whatsoever to PF_PACKET sockets; other PPP * code supplies PPP link-layer headers ("syncppp.c"); * some PPP code might supply random link-layer * headers (PPP over ISDN - there's code in Ethereal, * for example, to cope with PPP-over-ISDN captures * with which the Ethereal developers have had to cope, * heuristically trying to determine which of the * oddball link-layer headers particular packets have). * * As such, we just punt, and run all PPP interfaces * in cooked mode, if we can; otherwise, we just treat * it as DLT_RAW, for now - if somebody needs to capture, * on a 2.0[.x] kernel, on PPP devices that supply a * link-layer header, they'll have to add code here to * map to the appropriate DLT_ type (possibly adding a * new DLT_ type, if necessary). */ if (cooked_ok) handle->linktype = DLT_LINUX_SLL; else { /* * XXX - handle ISDN types here? We can't fall * back on cooked sockets, so we'd have to * figure out from the device name what type of * link-layer encapsulation it's using, and map * that to an appropriate DLT_ value, meaning * we'd map "isdnN" devices to DLT_RAW (they * supply raw IP packets with no link-layer * header) and "isdY" devices to a new DLT_I4L_IP * type that has only an Ethernet packet type as * a link-layer header. * * But sometimes we seem to get random crap * in the link-layer header when capturing on * ISDN devices.... */ handle->linktype = DLT_RAW; } break;#ifndef ARPHRD_CISCO#define ARPHRD_CISCO 513 /* previously ARPHRD_HDLC */#endif case ARPHRD_CISCO: handle->linktype = DLT_C_HDLC; break; /* Not sure if this is correct for all tunnels, but it * works for CIPE */ case ARPHRD_TUNNEL:#ifndef ARPHRD_SIT#define ARPHRD_SIT 776 /* From Linux 2.2.13 */#endif case ARPHRD_SIT: case ARPHRD_CSLIP: case ARPHRD_SLIP6: case ARPHRD_CSLIP6: case ARPHRD_ADAPT: case ARPHRD_SLIP:#ifndef ARPHRD_RAWHDLC#define ARPHRD_RAWHDLC 518#endif case ARPHRD_RAWHDLC:#ifndef ARPHRD_DLCI#define ARPHRD_DLCI 15#endif case ARPHRD_DLCI: /* * XXX - should some of those be mapped to DLT_LINUX_SLL * instead? Should we just map all of them to DLT_LINUX_SLL? */ handle->linktype = DLT_RAW; break;#ifndef ARPHRD_FRAD#define ARPHRD_FRAD 770#endif case ARPHRD_FRAD: handle->linktype = DLT_FRELAY; break; case ARPHRD_LOCALTLK: handle->linktype = DLT_LTALK; break;#ifndef ARPHRD_FCPP#define ARPHRD_FCPP 784#endif case ARPHRD_FCPP:#ifndef ARPHRD_FCAL#define ARPHRD_FCAL 785#endif case ARPHRD_FCAL:#ifndef ARPHRD_FCPL#define ARPHRD_FCPL 786#endif case ARPHRD_FCPL:#ifndef ARPHRD_FCFABRIC#define ARPHRD_FCFABRIC 787#endif case ARPHRD_FCFABRIC: /* * We assume that those all mean RFC 2625 IP-over- * Fibre Channel, with the RFC 2625 header at * the beginning of the packet. */ handle->linktype = DLT_IP_OVER_FC; break;#ifndef ARPHRD_IRDA#define ARPHRD_IRDA 783#endif case ARPHRD_IRDA: /* Don't expect IP packet out of this interfaces... */ handle->linktype = DLT_LINUX_IRDA; /* We need to save packet direction for IrDA decoding, * so let's use "Linux-cooked" mode. Jean II */ //handle->md.cooked = 1; break; default: handle->linktype = -1; break; }}/* ===== Functions to interface to the newer kernels ================== *//* * Try to open a packet socket using the new kernel interface. * Returns 0 on failure. * FIXME: 0 uses to mean success (Sebastian) */static intlive_open_new(pcap_t *handle, const char *device, int promisc, int to_ms, char *ebuf){#ifdef HAVE_PF_PACKET_SOCKETS int sock_fd = -1, arptype; int err; int fatal_err = 0; struct packet_mreq mr; /* One shot loop used for error handling - bail out with break */ do { /* * Open a socket with protocol family packet. If a device is * given we try to open it in raw mode otherwise we use * the cooked interface. */ sock_fd = device ? socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)) : socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_ALL)); if (sock_fd == -1) { snprintf(ebuf, PCAP_ERRBUF_SIZE, "socket: %s", pcap_strerror(errno) ); break; } /* It seems the kernel supports the new interface. */ handle->md.sock_packet = 0; /* * Get the interface index of the loopback device. * If the attempt fails, don't fail, just set the * "md.lo_ifindex" to -1. * * XXX - can there be more than one device that loops * packets back, i.e. devices other than "lo"? If so, * we'd need to find them all, and have an array of * indices for them, and check all of them in * "pcap_read_packet()". */ handle->md.lo_ifindex = iface_get_id(sock_fd, "lo", ebuf); /* * Default value for offset to align link-layer payload * on a 4-byte boundary. */ handle->offset = 0; /* * What kind of frames do we have to deal with? Fall back * to cooked mode if we have an unknown interface type. */ if (device) { /* Assume for now we don't need cooked mode. */ handle->md.cooked = 0; arptype = iface_get_arptype(sock_fd, device, ebuf); if (arptype == -1) { fatal_err = 1; break; } map_arphrd_to_dlt(handle, arptype, 1); if (handle->linktype == -1 || handle->linktype == DLT_LINUX_SLL || handle->linktype == DLT_LINUX_IRDA || (handle->linktype == DLT_EN10MB && (strncmp("isdn", device, 4) == 0 || strncmp("isdY", device, 4) == 0))) { /* * Unknown interface type (-1), or a * device we explicitly chose to run * in cooked mode (e.g., PPP devices), * or an ISDN device (whose link-layer * type we can only determine by using * APIs that may be different on different * kernels) - reopen in cooked mode. */ if (close(sock_fd) == -1) { snprintf(ebuf, PCAP_ERRBUF_SIZE, "close: %s", pcap_strerror(errno)); break; } sock_fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_ALL)); if (sock_fd == -1) { snprintf(ebuf, PCAP_ERRBUF_SIZE, "socket: %s", pcap_strerror(errno)); break; } handle->md.cooked = 1; /* * Get rid of any link-layer type list * we allocated - this only supports cooked * capture. */ if (handle->dlt_list != NULL) { free(handle->dlt_list); handle->dlt_list = NULL; handle->dlt_count = 0; } if (handle->linktype == -1) { /* * Warn that we're falling back on * cooked mode; we may want to * update "map_arphrd_to_dlt()" * to handle the new type. */ snprintf(ebuf, PCAP_ERRBUF_SIZE, "arptype %d not " "supported by libpcap - " "falling back to cooked " "socket", arptype); } /* IrDA capture is not a real "cooked" capture, * it's IrLAP frames, not IP packets. */ if (handle->linktype != DLT_LINUX_IRDA) handle->linktype = DLT_LINUX_SLL; } handle->md.ifindex = iface_get_id(sock_fd, device, ebuf); if (handle->md.ifindex == -1) break; if ((err = iface_bind(sock_fd, handle->md.ifindex, ebuf)) < 0) { if (err == -2) fatal_err = 1; break; } } else { /* * This is cooked mode. */ handle->md.cooked = 1; handle->linktype = DLT_LINUX_SLL; /* * We're not bound to a device. * XXX - true? Or true only if we're using * the "any" device? * For now, we're using this as an indication * that we can't transmit; stop doing that only * if we figure out how to transmit in cooked * mode. */ handle->md.ifindex = -1; } /* * Select promiscuous mode on if "promisc" is set. * * Do not turn allmulti mode on if we don't select * promiscuous mode - on some devices (e.g., Orinoco * wireless interfaces), allmulti mode isn't supported * and the driver implements it by turning promiscuous * mode on, and that screws up the operation of the * card as a normal networking interface, and on no * other platform I know of does starting a non- * promiscuous capture affect which multicast packets * are received by the interface. */ /* * Hmm, how can we set promiscuous mode on all interfaces? * I am not sure if that is possible at all. */ if (device && promisc) { memset(&mr, 0, sizeof(mr)); mr.mr_ifindex = handle->md.ifindex; mr.mr_type = PACKET_MR_PROMISC; if (setsockopt(sock_fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mr, sizeof(mr)) == -1) { snprintf(ebuf, PCAP_ERRBUF_SIZE, "setsockopt: %s", pcap_strerror(errno)); break; } } /* Save the socket FD in the pcap structure */ handle->fd = sock_fd; return 1; } while(0); if (sock_fd != -1) close(sock_fd); if (fatal_err) { /* * Get rid of any link-layer type list we allocated. */ if (handle->dlt_list != NULL) free(handle->dlt_list); return -2; } else return 0;#else strncpy(ebuf, "New packet capturing interface not supported by build " "environment", PCAP_ERRBUF_SIZE); return 0;#endif}#ifdef HAVE_PF_PACKET_SOCKETS/* * Return the index of the given device name. Fill ebuf and return * -1 on failure. */static intiface_get_id(int fd, const char *device, char *ebuf){ struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); if (ioctl(fd, SIOCGIFINDEX, &ifr) == -1) { snprintf(ebuf, PCAP_ERRBUF_SIZE, "ioctl: %s", pcap_strerror(errno)); return -1; } return ifr.ifr_ifindex;}/* * Bind the socket associated with FD to the given device. */static intiface_bind(int fd, int ifindex, char *ebuf){ struct sockaddr_ll sll; int err; socklen_t errlen = sizeof(err); memset(&sll, 0, sizeof(sll)); sll.sll_family = AF_PACKET; sll.sll_ifindex = ifindex; sll.sll_protocol = htons(ETH_P_ALL); if (bind(fd, (struct sockaddr *) &sll, sizeof(sll)) == -1) { snprintf(ebuf, PCAP_ERRBUF_SIZE, "bind: %s", pcap_strerror(errno)); return -1; } /* Any pending errors, e.g., network is down? */ if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &errlen) == -1) { snprintf(ebuf, PCAP_ERRBUF_SIZE, "getsockopt: %s", pcap_strerror(errno)); return -2; } if (err > 0) { snprintf(ebuf, PCAP_ERRBUF_SIZE, "bind: %s", pcap_strerror(err)); return -2; } return 0;}#endif/* ===== Functions to interface to the older kernels ================== *//* * With older kernels promiscuous mode is kind of interesting because we * have to reset the interface before exiting. The problem can't really * be solved without some daemon taking care of managing usage counts. * If we put the interface into promiscuous mode, we set a flag indicating * that we must take it out of that mode when the interface is closed, * and, when closing the interface, if that flag is set we take it out * of promiscuous mode. *//*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -