diff options
Diffstat (limited to 'contrib/libpcap/pcap.c')
-rw-r--r-- | contrib/libpcap/pcap.c | 280 |
1 files changed, 166 insertions, 114 deletions
diff --git a/contrib/libpcap/pcap.c b/contrib/libpcap/pcap.c index c763093..324752f 100644 --- a/contrib/libpcap/pcap.c +++ b/contrib/libpcap/pcap.c @@ -33,7 +33,7 @@ #ifndef lint static const char rcsid[] _U_ = - "@(#) $Header: /tcpdump/master/libpcap/pcap.c,v 1.112.2.12 2008-09-22 20:16:01 guy Exp $ (LBL)"; + "@(#) $Header: /tcpdump/master/libpcap/pcap.c,v 1.128 2008-12-23 20:13:29 guy Exp $ (LBL)"; #endif #ifdef HAVE_CONFIG_H @@ -43,6 +43,14 @@ static const char rcsid[] _U_ = #ifdef WIN32 #include <pcap-stdinc.h> #else /* WIN32 */ +#if HAVE_INTTYPES_H +#include <inttypes.h> +#elif HAVE_STDINT_H +#include <stdint.h> +#endif +#ifdef HAVE_SYS_BITYPES_H +#include <sys/bitypes.h> +#endif #include <sys/types.h> #include <sys/mman.h> #endif /* WIN32 */ @@ -97,6 +105,119 @@ pcap_cant_set_rfmon(pcap_t *p _U_) return (0); } +/* + * Default one-shot callback; overridden for capture types where the + * packet data cannot be guaranteed to be available after the callback + * returns, so that a copy must be made. + */ +static void +pcap_oneshot(u_char *user, const struct pcap_pkthdr *h, const u_char *pkt) +{ + struct oneshot_userdata *sp = (struct oneshot_userdata *)user; + + *sp->hdr = *h; + *sp->pkt = pkt; +} + +const u_char * +pcap_next(pcap_t *p, struct pcap_pkthdr *h) +{ + struct oneshot_userdata s; + const u_char *pkt; + + s.hdr = h; + s.pkt = &pkt; + s.pd = p; + if (pcap_dispatch(p, 1, p->oneshot_callback, (u_char *)&s) <= 0) + return (0); + return (pkt); +} + +int +pcap_next_ex(pcap_t *p, struct pcap_pkthdr **pkt_header, + const u_char **pkt_data) +{ + struct oneshot_userdata s; + + s.hdr = &p->pcap_header; + s.pkt = pkt_data; + s.pd = p; + + /* Saves a pointer to the packet headers */ + *pkt_header= &p->pcap_header; + + if (p->sf.rfile != NULL) { + int status; + + /* We are on an offline capture */ + status = pcap_offline_read(p, 1, pcap_oneshot, (u_char *)&s); + + /* + * Return codes for pcap_offline_read() are: + * - 0: EOF + * - -1: error + * - >1: OK + * The first one ('0') conflicts with the return code of + * 0 from pcap_read() meaning "no packets arrived before + * the timeout expired", so we map it to -2 so you can + * distinguish between an EOF from a savefile and a + * "no packets arrived before the timeout expired, try + * again" from a live capture. + */ + if (status == 0) + return (-2); + else + return (status); + } + + /* + * Return codes for pcap_read() are: + * - 0: timeout + * - -1: error + * - -2: loop was broken out of with pcap_breakloop() + * - >1: OK + * The first one ('0') conflicts with the return code of 0 from + * pcap_offline_read() meaning "end of file". + */ + return (p->read_op(p, 1, pcap_oneshot, (u_char *)&s)); +} + +static void +initialize_ops(pcap_t *p) +{ + /* + * Set operation pointers for operations that only work on + * an activated pcap_t to point to a routine that returns + * a "this isn't activated" error. + */ + p->read_op = (read_op_t)pcap_not_initialized; + p->inject_op = (inject_op_t)pcap_not_initialized; + p->setfilter_op = (setfilter_op_t)pcap_not_initialized; + p->setdirection_op = (setdirection_op_t)pcap_not_initialized; + p->set_datalink_op = (set_datalink_op_t)pcap_not_initialized; + p->getnonblock_op = (getnonblock_op_t)pcap_not_initialized; + p->setnonblock_op = (setnonblock_op_t)pcap_not_initialized; + p->stats_op = (stats_op_t)pcap_not_initialized; +#ifdef WIN32 + p->setbuff_op = (setbuff_op_t)pcap_not_initialized; + p->setmode_op = (setmode_op_t)pcap_not_initialized; + p->setmintocopy_op = (setmintocopy_op_t)pcap_not_initialized; +#endif + + /* + * Default cleanup operation - implementations can override + * this, but should call pcap_cleanup_live_common() after + * doing their own additional cleanup. + */ + p->cleanup_op = pcap_cleanup_live_common; + + /* + * In most cases, the standard one-short callback can + * be used for pcap_next()/pcap_next_ex(). + */ + p->oneshot_callback = pcap_oneshot; +} + pcap_t * pcap_create_common(const char *source, char *ebuf) { @@ -111,6 +232,8 @@ pcap_create_common(const char *source, char *ebuf) memset(p, 0, sizeof(*p)); #ifndef WIN32 p->fd = -1; /* not opened yet */ + p->selectable_fd = -1; + p->send_fd = -1; #endif p->opt.source = strdup(source); @@ -123,30 +246,13 @@ pcap_create_common(const char *source, char *ebuf) /* * Default to "can't set rfmon mode"; if it's supported by - * a platform, it can set the op to its routine to check - * whether a particular device supports it. + * a platform, the create routine that called us can set + * the op to its routine to check whether a particular + * device supports it. */ p->can_set_rfmon_op = pcap_cant_set_rfmon; - /* - * Some operations can be performed only on activated pcap_t's; - * have those operations handled by a "not supported" handler - * until the pcap_t is activated. - */ - p->read_op = (read_op_t)pcap_not_initialized; - p->inject_op = (inject_op_t)pcap_not_initialized; - p->setfilter_op = (setfilter_op_t)pcap_not_initialized; - p->setdirection_op = (setdirection_op_t)pcap_not_initialized; - p->set_datalink_op = (set_datalink_op_t)pcap_not_initialized; - p->getnonblock_op = (getnonblock_op_t)pcap_not_initialized; - p->setnonblock_op = (setnonblock_op_t)pcap_not_initialized; - p->stats_op = (stats_op_t)pcap_not_initialized; -#ifdef WIN32 - p->setbuff_op = (setbuff_op_t)pcap_not_initialized; - p->setmode_op = (setmode_op_t)pcap_not_initialized; - p->setmintocopy_op = (setmintocopy_op_t)pcap_not_initialized; -#endif - p->cleanup_op = pcap_cleanup_live_common; + initialize_ops(p); /* put in some defaults*/ pcap_set_timeout(p, 0); @@ -220,6 +326,24 @@ pcap_activate(pcap_t *p) status = p->activate_op(p); if (status >= 0) p->activated = 1; + else { + if (p->errbuf[0] == '\0') { + /* + * No error message supplied by the activate routine; + * for the benefit of programs that don't specially + * handle errors other than PCAP_ERROR, return the + * error message corresponding to the status. + */ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s", + pcap_statustostr(status)); + } + + /* + * Undo any operation pointer setting, etc. done by + * the activate operation. + */ + initialize_ops(p); + } return (status); } @@ -257,9 +381,13 @@ pcap_open_live(const char *source, int snaplen, int promisc, int to_ms, char *er goto fail; return (p); fail: - if (status == PCAP_ERROR || status == PCAP_ERROR_NO_SUCH_DEVICE || + if (status == PCAP_ERROR) + snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s", source, + p->errbuf); + else if (status == PCAP_ERROR_NO_SUCH_DEVICE || status == PCAP_ERROR_PERM_DENIED) - strlcpy(errbuf, p->errbuf, PCAP_ERRBUF_SIZE); + snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s (%s)", source, + pcap_statustostr(status), p->errbuf); else snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s", source, pcap_statustostr(status)); @@ -313,95 +441,6 @@ pcap_loop(pcap_t *p, int cnt, pcap_handler callback, u_char *user) } } -struct singleton { - struct pcap_pkthdr *hdr; - const u_char *pkt; -}; - - -static void -pcap_oneshot(u_char *userData, const struct pcap_pkthdr *h, const u_char *pkt) -{ - struct singleton *sp = (struct singleton *)userData; - *sp->hdr = *h; - sp->pkt = pkt; -} - -const u_char * -pcap_next(pcap_t *p, struct pcap_pkthdr *h) -{ - struct singleton s; - - s.hdr = h; - if (pcap_dispatch(p, 1, pcap_oneshot, (u_char*)&s) <= 0) - return (0); - return (s.pkt); -} - -struct pkt_for_fakecallback { - struct pcap_pkthdr *hdr; - const u_char **pkt; -}; - -static void -pcap_fakecallback(u_char *userData, const struct pcap_pkthdr *h, - const u_char *pkt) -{ - struct pkt_for_fakecallback *sp = (struct pkt_for_fakecallback *)userData; - - *sp->hdr = *h; - *sp->pkt = pkt; -} - -int -pcap_next_ex(pcap_t *p, struct pcap_pkthdr **pkt_header, - const u_char **pkt_data) -{ - struct pkt_for_fakecallback s; - - s.hdr = &p->pcap_header; - s.pkt = pkt_data; - - /* Saves a pointer to the packet headers */ - *pkt_header= &p->pcap_header; - - if (p->sf.rfile != NULL) { - int status; - - /* We are on an offline capture */ - status = pcap_offline_read(p, 1, pcap_fakecallback, - (u_char *)&s); - - /* - * Return codes for pcap_offline_read() are: - * - 0: EOF - * - -1: error - * - >1: OK - * The first one ('0') conflicts with the return code of - * 0 from pcap_read() meaning "no packets arrived before - * the timeout expired", so we map it to -2 so you can - * distinguish between an EOF from a savefile and a - * "no packets arrived before the timeout expired, try - * again" from a live capture. - */ - if (status == 0) - return (-2); - else - return (status); - } - - /* - * Return codes for pcap_read() are: - * - 0: timeout - * - -1: error - * - -2: loop was broken out of with pcap_breakloop() - * - >1: OK - * The first one ('0') conflicts with the return code of 0 from - * pcap_offline_read() meaning "end of file". - */ - return (p->read_op(p, 1, pcap_fakecallback, (u_char *)&s)); -} - /* * Force the loop in "pcap_read()" or "pcap_read_offline()" to terminate. */ @@ -624,6 +663,17 @@ static struct dlt_choice dlt_choices[] = { DLT_CHOICE(DLT_BLUETOOTH_HCI_H4_WITH_PHDR, "Bluetooth HCI UART transport layer plus pseudo-header"), DLT_CHOICE(DLT_AX25_KISS, "AX.25 with KISS header"), DLT_CHOICE(DLT_IEEE802_15_4_NONASK_PHY, "IEEE 802.15.4 with non-ASK PHY data"), + DLT_CHOICE(DLT_MPLS, "MPLS with label as link-layer header"), + DLT_CHOICE(DLT_USB_LINUX_MMAPPED, "USB with padded Linux header"), + DLT_CHOICE(DLT_DECT, "DECT"), + DLT_CHOICE(DLT_AOS, "AOS Space Data Link protocol"), + DLT_CHOICE(DLT_WIHART, "Wireless HART"), + DLT_CHOICE(DLT_FC_2, "Fibre Channel FC-2"), + DLT_CHOICE(DLT_FC_2_WITH_FRAME_DELIMS, "Fibre Channel FC-2 with frame delimiters"), + DLT_CHOICE(DLT_IPNET, "Solaris ipnet"), + DLT_CHOICE(DLT_CAN_SOCKETCAN, "CAN-bus with SocketCAN headers"), + DLT_CHOICE(DLT_IPV4, "Raw IPv4"), + DLT_CHOICE(DLT_IPV6, "Raw IPv6"), DLT_CHOICE_SENTINEL }; @@ -1169,6 +1219,8 @@ pcap_cleanup_live_common(pcap_t *p) close(p->fd); p->fd = -1; } + p->selectable_fd = -1; + p->send_fd = -1; #endif } @@ -1266,7 +1318,7 @@ pcap_offline_filter(struct bpf_program *fp, const struct pcap_pkthdr *h, #ifdef HAVE_VERSION_H #include "version.h" #else -static const char pcap_version_string[] = "libpcap version 0.9[.x]"; +static const char pcap_version_string[] = "libpcap version 1.x.y"; #endif #ifdef WIN32 |