📄 pcap-linux.c
字号:
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; /* ARPHRD_LAPD is unofficial and randomly allocated, if reallocation * is needed, please report it to <daniele@orlandi.com> */#ifndef ARPHRD_LAPD#define ARPHRD_LAPD 8445#endif case ARPHRD_LAPD: /* Don't expect IP packet out of this interfaces... */ handle->linktype = DLT_LINUX_LAPD; 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_LINUX_LAPD || (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_LAPD) 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, "SIOCGIFINDEX: %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. *//* * List of pcaps for which we turned promiscuous mode on by hand. * If there are any such pcaps, we arrange to call "pcap_close_all()" * when we exit, and have it close all of them to turn promiscuous mode * off. */static struct pcap *pcaps_to_close;/* * TRUE if we've already called "atexit()" to cause "pcap_close_all()" to * be called on exit. */static int did_atexit;static void pcap_close_all(void){ struct pcap *handle; while ((handle = pcaps_to_close) != NULL) pcap_close(handle);}static void pcap_close_linux( pcap_t *handle ){ struct pcap *p, *prevp; struct ifreq ifr; if (handle->md.clear_promisc) { /* * We put the interface into promiscuous mode; take * it out of promiscuous mode. * * XXX - if somebody else wants it in promiscuous mode, * this code cannot know that, so it'll take it out * of promiscuous mode. That's not fixable in 2.0[.x] * kernels. */ memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, handle->md.device, sizeof(ifr.ifr_name)); if (ioctl(handle->fd, SIOCGIFFLAGS, &ifr) == -1) { fprintf(stderr, "Can't restore interface flags (SIOCGIFFLAGS failed: %s).\n" "Please adjust manually.\n" "Hint: This can't happen with Linux >= 2.2.0.\n", strerror(errno)); } else { if (ifr.ifr_flags & IFF_PROMISC) { /* * Promiscuous mode is currently on; turn it * off. */ ifr.ifr_flags &= ~IFF_PROMISC; if (ioctl(handle->fd, SIOCSIFFLAGS, &ifr) == -1) { fprintf(stderr, "Can't restore interface flags (SIOCSIFFLAGS failed: %s).\n" "Please adjust manually.\n" "Hint: This can't happen with Linux >= 2.2.0.\n", strerror(errno)); } } } /* * Take this pcap out of the list of pcaps for which we * have to take the interface out of promiscuous mode. */ for (p = pcaps_to_close, prevp = NULL; p != NULL; prevp = p, p = p->md.next) { if (p == handle) { /* * Found it. Remove it from the list. */ if (prevp == NULL) { /* * It was at the head of the list. */ pcaps_to_close = p->md.next; } else { /* * It was in the middle of the list. */ prevp->md.next = p->md.next; } break; } } } if (handle->md.device != NULL) free(handle->md.device); handle->md.device = NULL; pcap_close_common(handle);}/* * Try to open a packet socket using the old kernel interface. * Returns 0 on failure. * FIXME: 0 uses to mean success (Sebastian) */static intlive_open_old(pcap_t *handle, const char *device, int promisc, int to_ms, char *ebuf){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -