From 5a0615f5c40ce036a7e13cfffe00927f845ad563 Mon Sep 17 00:00:00 2001 From: "George V. Neville-Neil" Date: Tue, 31 Jan 2012 18:24:25 +0000 Subject: Add, remove and move files for the 1.2.1 import of libpcap Submitted by: wxs --- filtertest.c | 266 --------------------- findalldevstest.c | 131 ----------- opentest.c | 216 ----------------- pcap-netfilter-linux.c | 468 +++++++++++++++++++++++++++++++++++++ pcap-netfilter-linux.h | 35 +++ pcap-tstamp.manmisc.in | 132 +++++++++++ pcap_free_datalinks.3pcap | 0 pcap_freealldevs.3pcap | 0 pcap_list_tstamp_types.3pcap.in | 70 ++++++ pcap_set_tstamp_type.3pcap.in | 65 ++++++ pcap_tstamp_type_name_to_val.3pcap | 45 ++++ pcap_tstamp_type_val_to_name.3pcap | 45 ++++ selpolltest.c | 350 --------------------------- test/filtertest.c | 266 +++++++++++++++++++++ test/findalldevstest.c | 131 +++++++++++ test/nonblocktest.c | 226 ++++++++++++++++++ test/opentest.c | 216 +++++++++++++++++ test/reactivatetest.c | 84 +++++++ test/selpolltest.c | 350 +++++++++++++++++++++++++++ 19 files changed, 2133 insertions(+), 963 deletions(-) delete mode 100644 filtertest.c delete mode 100644 findalldevstest.c delete mode 100644 opentest.c create mode 100644 pcap-netfilter-linux.c create mode 100644 pcap-netfilter-linux.h create mode 100644 pcap-tstamp.manmisc.in delete mode 100644 pcap_free_datalinks.3pcap delete mode 100644 pcap_freealldevs.3pcap create mode 100644 pcap_list_tstamp_types.3pcap.in create mode 100644 pcap_set_tstamp_type.3pcap.in create mode 100644 pcap_tstamp_type_name_to_val.3pcap create mode 100644 pcap_tstamp_type_val_to_name.3pcap delete mode 100644 selpolltest.c create mode 100644 test/filtertest.c create mode 100644 test/findalldevstest.c create mode 100644 test/nonblocktest.c create mode 100644 test/opentest.c create mode 100644 test/reactivatetest.c create mode 100644 test/selpolltest.c diff --git a/filtertest.c b/filtertest.c deleted file mode 100644 index a56d1e49e923..000000000000 --- a/filtertest.c +++ /dev/null @@ -1,266 +0,0 @@ -/* - * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that: (1) source code distributions - * retain the above copyright notice and this paragraph in its entirety, (2) - * distributions including binary code include the above copyright notice and - * this paragraph in its entirety in the documentation or other materials - * provided with the distribution, and (3) all advertising materials mentioning - * features or use of this software display the following acknowledgement: - * ``This product includes software developed by the University of California, - * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of - * the University nor the names of its contributors may be used to endorse - * or promote products derived from this software without specific prior - * written permission. - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. - */ - -#ifndef lint -static const char copyright[] _U_ = - "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000\n\ -The Regents of the University of California. All rights reserved.\n"; -static const char rcsid[] _U_ = - "@(#) $Header: /tcpdump/master/libpcap/filtertest.c,v 1.2 2005-08-08 17:50:13 guy Exp $ (LBL)"; -#endif - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifndef HAVE___ATTRIBUTE__ -#define __attribute__(x) -#endif - -static char *program_name; - -/* Forwards */ -static void usage(void) __attribute__((noreturn)); -static void error(const char *, ...) - __attribute__((noreturn, format (printf, 1, 2))); - -extern int optind; -extern int opterr; -extern char *optarg; - -/* - * On Windows, we need to open the file in binary mode, so that - * we get all the bytes specified by the size we get from "fstat()". - * On UNIX, that's not necessary. O_BINARY is defined on Windows; - * we define it as 0 if it's not defined, so it does nothing. - */ -#ifndef O_BINARY -#define O_BINARY 0 -#endif - -static char * -read_infile(char *fname) -{ - register int i, fd, cc; - register char *cp; - struct stat buf; - - fd = open(fname, O_RDONLY|O_BINARY); - if (fd < 0) - error("can't open %s: %s", fname, pcap_strerror(errno)); - - if (fstat(fd, &buf) < 0) - error("can't stat %s: %s", fname, pcap_strerror(errno)); - - cp = malloc((u_int)buf.st_size + 1); - if (cp == NULL) - error("malloc(%d) for %s: %s", (u_int)buf.st_size + 1, - fname, pcap_strerror(errno)); - cc = read(fd, cp, (u_int)buf.st_size); - if (cc < 0) - error("read %s: %s", fname, pcap_strerror(errno)); - if (cc != buf.st_size) - error("short read %s (%d != %d)", fname, cc, (int)buf.st_size); - - close(fd); - /* replace "# comment" with spaces */ - for (i = 0; i < cc; i++) { - if (cp[i] == '#') - while (i < cc && cp[i] != '\n') - cp[i++] = ' '; - } - cp[cc] = '\0'; - return (cp); -} - -/* VARARGS */ -static void -error(const char *fmt, ...) -{ - va_list ap; - - (void)fprintf(stderr, "%s: ", program_name); - va_start(ap, fmt); - (void)vfprintf(stderr, fmt, ap); - va_end(ap); - if (*fmt) { - fmt += strlen(fmt); - if (fmt[-1] != '\n') - (void)fputc('\n', stderr); - } - exit(1); - /* NOTREACHED */ -} - -/* - * Copy arg vector into a new buffer, concatenating arguments with spaces. - */ -static char * -copy_argv(register char **argv) -{ - register char **p; - register u_int len = 0; - char *buf; - char *src, *dst; - - p = argv; - if (*p == 0) - return 0; - - while (*p) - len += strlen(*p++) + 1; - - buf = (char *)malloc(len); - if (buf == NULL) - error("copy_argv: malloc"); - - p = argv; - dst = buf; - while ((src = *p++) != NULL) { - while ((*dst++ = *src++) != '\0') - ; - dst[-1] = ' '; - } - dst[-1] = '\0'; - - return buf; -} - -int -main(int argc, char **argv) -{ - char *cp; - int op; - int dflag; - char *infile; - int Oflag; - long snaplen; - int dlt; - bpf_u_int32 netmask = PCAP_NETMASK_UNKNOWN; - char *cmdbuf; - pcap_t *pd; - struct bpf_program fcode; - -#ifdef WIN32 - if(wsockinit() != 0) return 1; -#endif /* WIN32 */ - - dflag = 1; - infile = NULL; - Oflag = 1; - snaplen = 68; - - if ((cp = strrchr(argv[0], '/')) != NULL) - program_name = cp + 1; - else - program_name = argv[0]; - - opterr = 0; - while ((op = getopt(argc, argv, "dF:m:Os:")) != -1) { - switch (op) { - - case 'd': - ++dflag; - break; - - case 'F': - infile = optarg; - break; - - case 'O': - Oflag = 0; - break; - - case 'm': { - in_addr_t addr; - - addr = inet_addr(optarg); - if (addr == INADDR_NONE) - error("invalid netmask %s", optarg); - netmask = addr; - break; - } - - case 's': { - char *end; - - snaplen = strtol(optarg, &end, 0); - if (optarg == end || *end != '\0' - || snaplen < 0 || snaplen > 65535) - error("invalid snaplen %s", optarg); - else if (snaplen == 0) - snaplen = 65535; - break; - } - - default: - usage(); - /* NOTREACHED */ - } - } - - if (optind >= argc) { - usage(); - /* NOTREACHED */ - } - - dlt = pcap_datalink_name_to_val(argv[optind]); - if (dlt < 0) - error("invalid data link type %s", argv[optind]); - - if (infile) - cmdbuf = read_infile(infile); - else - cmdbuf = copy_argv(&argv[optind+1]); - - pd = pcap_open_dead(dlt, snaplen); - if (pd == NULL) - error("Can't open fake pcap_t"); - - if (pcap_compile(pd, &fcode, cmdbuf, Oflag, netmask) < 0) - error("%s", pcap_geterr(pd)); - bpf_dump(&fcode, dflag); - pcap_close(pd); - exit(0); -} - -static void -usage(void) -{ - (void)fprintf(stderr, "%s, with %s\n", program_name, - pcap_lib_version()); - (void)fprintf(stderr, - "Usage: %s [-dO] [ -F file ] [ -m netmask] [ -s snaplen ] dlt [ expression ]\n", - program_name); - exit(1); -} diff --git a/findalldevstest.c b/findalldevstest.c deleted file mode 100644 index ec7c95015c9e..000000000000 --- a/findalldevstest.c +++ /dev/null @@ -1,131 +0,0 @@ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include - -#include - -static void ifprint(pcap_if_t *d); -static char *iptos(bpf_u_int32 in); - -int main(int argc, char **argv) -{ - pcap_if_t *alldevs; - pcap_if_t *d; - char *s; - bpf_u_int32 net, mask; - - char errbuf[PCAP_ERRBUF_SIZE+1]; - if (pcap_findalldevs(&alldevs, errbuf) == -1) - { - fprintf(stderr,"Error in pcap_findalldevs: %s\n",errbuf); - exit(1); - } - for(d=alldevs;d;d=d->next) - { - ifprint(d); - } - - if ( (s = pcap_lookupdev(errbuf)) == NULL) - { - fprintf(stderr,"Error in pcap_lookupdev: %s\n",errbuf); - } - else - { - printf("Preferred device name: %s\n",s); - } - - if (pcap_lookupnet(s, &net, &mask, errbuf) < 0) - { - fprintf(stderr,"Error in pcap_lookupnet: %s\n",errbuf); - } - else - { - printf("Preferred device is on network: %s/%s\n",iptos(net), iptos(mask)); - } - - exit(0); -} - -static void ifprint(pcap_if_t *d) -{ - pcap_addr_t *a; -#ifdef INET6 - char ntop_buf[INET6_ADDRSTRLEN]; -#endif - - printf("%s\n",d->name); - if (d->description) - printf("\tDescription: %s\n",d->description); - printf("\tLoopback: %s\n",(d->flags & PCAP_IF_LOOPBACK)?"yes":"no"); - - for(a=d->addresses;a;a=a->next) { - switch(a->addr->sa_family) - { - case AF_INET: - printf("\tAddress Family: AF_INET\n"); - if (a->addr) - printf("\t\tAddress: %s\n", - inet_ntoa(((struct sockaddr_in *)(a->addr))->sin_addr)); - if (a->netmask) - printf("\t\tNetmask: %s\n", - inet_ntoa(((struct sockaddr_in *)(a->netmask))->sin_addr)); - if (a->broadaddr) - printf("\t\tBroadcast Address: %s\n", - inet_ntoa(((struct sockaddr_in *)(a->broadaddr))->sin_addr)); - if (a->dstaddr) - printf("\t\tDestination Address: %s\n", - inet_ntoa(((struct sockaddr_in *)(a->dstaddr))->sin_addr)); - break; -#ifdef INET6 - case AF_INET6: - printf("\tAddress Family: AF_INET6\n"); - if (a->addr) - printf("\t\tAddress: %s\n", - inet_ntop(AF_INET6, - ((struct sockaddr_in6 *)(a->addr))->sin6_addr.s6_addr, - ntop_buf, sizeof ntop_buf)); - if (a->netmask) - printf("\t\tNetmask: %s\n", - inet_ntop(AF_INET6, - ((struct sockaddr_in6 *)(a->netmask))->sin6_addr.s6_addr, - ntop_buf, sizeof ntop_buf)); - if (a->broadaddr) - printf("\t\tBroadcast Address: %s\n", - inet_ntop(AF_INET6, - ((struct sockaddr_in6 *)(a->broadaddr))->sin6_addr.s6_addr, - ntop_buf, sizeof ntop_buf)); - if (a->dstaddr) - printf("\t\tDestination Address: %s\n", - inet_ntop(AF_INET6, - ((struct sockaddr_in6 *)(a->dstaddr))->sin6_addr.s6_addr, - ntop_buf, sizeof ntop_buf)); - break; -#endif - default: - printf("\tAddress Family: Unknown (%d)\n", a->addr->sa_family); - break; - } - } - printf("\n"); -} - -/* From tcptraceroute */ -#define IPTOSBUFFERS 12 -static char *iptos(bpf_u_int32 in) -{ - static char output[IPTOSBUFFERS][3*4+3+1]; - static short which; - u_char *p; - - p = (u_char *)∈ - which = (which + 1 == IPTOSBUFFERS ? 0 : which + 1); - sprintf(output[which], "%d.%d.%d.%d", p[0], p[1], p[2], p[3]); - return output[which]; -} diff --git a/opentest.c b/opentest.c deleted file mode 100644 index 0c91531018db..000000000000 --- a/opentest.c +++ /dev/null @@ -1,216 +0,0 @@ -/* - * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that: (1) source code distributions - * retain the above copyright notice and this paragraph in its entirety, (2) - * distributions including binary code include the above copyright notice and - * this paragraph in its entirety in the documentation or other materials - * provided with the distribution, and (3) all advertising materials mentioning - * features or use of this software display the following acknowledgement: - * ``This product includes software developed by the University of California, - * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of - * the University nor the names of its contributors may be used to endorse - * or promote products derived from this software without specific prior - * written permission. - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. - */ - -#ifndef lint -static const char copyright[] = - "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000\n\ -The Regents of the University of California. All rights reserved.\n"; -#endif - -#include -#include -#include -#include -#include -#include -#include - -#define MAXIMUM_SNAPLEN 65535 - -static char *program_name; - -/* Forwards */ -static void usage(void) __attribute__((noreturn)); -static void error(const char *, ...); -static void warning(const char *, ...); - -extern int optind; -extern int opterr; -extern char *optarg; - -int -main(int argc, char **argv) -{ - register int op; - register char *cp, *device; - int dorfmon, dopromisc, snaplen, useactivate, bufsize; - char ebuf[PCAP_ERRBUF_SIZE]; - pcap_t *pd; - int status = 0; - - device = NULL; - dorfmon = 0; - dopromisc = 0; - snaplen = MAXIMUM_SNAPLEN; - bufsize = 0; - useactivate = 0; - if ((cp = strrchr(argv[0], '/')) != NULL) - program_name = cp + 1; - else - program_name = argv[0]; - - opterr = 0; - while ((op = getopt(argc, argv, "i:Ips:aB:")) != -1) { - switch (op) { - - case 'i': - device = optarg; - break; - - case 'I': - dorfmon = 1; - useactivate = 1; /* required for rfmon */ - break; - - case 'p': - dopromisc = 1; - break; - - case 's': { - char *end; - - snaplen = strtol(optarg, &end, 0); - if (optarg == end || *end != '\0' - || snaplen < 0 || snaplen > MAXIMUM_SNAPLEN) - error("invalid snaplen %s", optarg); - else if (snaplen == 0) - snaplen = MAXIMUM_SNAPLEN; - break; - } - - case 'B': - bufsize = atoi(optarg)*1024; - if (bufsize <= 0) - error("invalid packet buffer size %s", optarg); - useactivate = 1; /* required for bufsize */ - break; - - case 'a': - useactivate = 1; - break; - - default: - usage(); - /* NOTREACHED */ - } - } - - if (useactivate) { - pd = pcap_create(device, ebuf); - if (pd == NULL) - error("%s", ebuf); - status = pcap_set_snaplen(pd, snaplen); - if (status != 0) - error("%s: pcap_set_snaplen failed: %s", - device, pcap_statustostr(status)); - if (dopromisc) { - status = pcap_set_promisc(pd, 1); - if (status != 0) - error("%s: pcap_set_promisc failed: %s", - device, pcap_statustostr(status)); - } - if (dorfmon) { - status = pcap_set_rfmon(pd, 1); - if (status != 0) - error("%s: pcap_set_rfmon failed: %s", - device, pcap_statustostr(status)); - } - status = pcap_set_timeout(pd, 1000); - if (status != 0) - error("%s: pcap_set_timeout failed: %s", - device, pcap_statustostr(status)); - if (bufsize != 0) { - status = pcap_set_buffer_size(pd, bufsize); - if (status != 0) - error("%s: pcap_set_buffer_size failed: %s", - device, pcap_statustostr(status)); - } - status = pcap_activate(pd); - if (status < 0) { - /* - * pcap_activate() failed. - */ - error("%s: %s\n(%s)", device, - pcap_statustostr(status), pcap_geterr(pd)); - } else if (status > 0) { - /* - * pcap_activate() succeeded, but it's warning us - * of a problem it had. - */ - warning("%s: %s\n(%s)", device, - pcap_statustostr(status), pcap_geterr(pd)); - } - } else { - *ebuf = '\0'; - pd = pcap_open_live(device, 65535, 0, 1000, ebuf); - if (pd == NULL) - error("%s", ebuf); - else if (*ebuf) - warning("%s", ebuf); - } - pcap_close(pd); - exit(status < 0 ? 1 : 0); -} - -static void -usage(void) -{ - (void)fprintf(stderr, - "Usage: %s [ -Ipa ] [ -i interface ] [ -s snaplen ] [ -B bufsize ]\n", - program_name); - exit(1); -} - -/* VARARGS */ -static void -error(const char *fmt, ...) -{ - va_list ap; - - (void)fprintf(stderr, "%s: ", program_name); - va_start(ap, fmt); - (void)vfprintf(stderr, fmt, ap); - va_end(ap); - if (*fmt) { - fmt += strlen(fmt); - if (fmt[-1] != '\n') - (void)fputc('\n', stderr); - } - exit(1); - /* NOTREACHED */ -} - -/* VARARGS */ -static void -warning(const char *fmt, ...) -{ - va_list ap; - - (void)fprintf(stderr, "%s: WARNING: ", program_name); - va_start(ap, fmt); - (void)vfprintf(stderr, fmt, ap); - va_end(ap); - if (*fmt) { - fmt += strlen(fmt); - if (fmt[-1] != '\n') - (void)fputc('\n', stderr); - } -} diff --git a/pcap-netfilter-linux.c b/pcap-netfilter-linux.c new file mode 100644 index 000000000000..225e49f904e2 --- /dev/null +++ b/pcap-netfilter-linux.c @@ -0,0 +1,468 @@ +/* + * Copyright (c) 2011 Jakub Zawadzki + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "pcap-int.h" + +#ifdef NEED_STRERROR_H +#include "strerror.h" +#endif + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include "pcap-netfilter-linux.h" + +#define HDR_LENGTH (NLMSG_LENGTH(NLMSG_ALIGN(sizeof(struct nfgenmsg)))) + +#define NFLOG_IFACE "nflog" + +static int +nflog_read_linux(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user) +{ + const unsigned char *buf; + int count = 0; + int len; + + /* ignore interrupt system call error */ + do { + len = recv(handle->fd, handle->buffer, handle->bufsize, 0); + if (handle->break_loop) { + handle->break_loop = 0; + return -2; + } + } while ((len == -1) && (errno == EINTR)); + + if (len < 0) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't receive packet %d:%s", errno, pcap_strerror(errno)); + return -1; + } + + buf = handle->buffer; + while (len >= NLMSG_SPACE(0)) { + const struct nlmsghdr *nlh = (const struct nlmsghdr *) buf; + u_int32_t msg_len; + + if (nlh->nlmsg_len < sizeof(struct nlmsghdr) || len < nlh->nlmsg_len) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Message truncated: (got: %d) (nlmsg_len: %u)", len, nlh->nlmsg_len); + return -1; + } + + if (NFNL_SUBSYS_ID(nlh->nlmsg_type) == NFNL_SUBSYS_ULOG && + NFNL_MSG_TYPE(nlh->nlmsg_type) == NFULNL_MSG_PACKET) + { + const unsigned char *payload = NULL; + struct pcap_pkthdr pkth; + + if (handle->linktype != DLT_NFLOG) { + const struct nfattr *payload_attr = NULL; + + if (nlh->nlmsg_len < HDR_LENGTH) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Malformed message: (nlmsg_len: %u)", nlh->nlmsg_len); + return -1; + } + + if (nlh->nlmsg_len > HDR_LENGTH) { + struct nfattr *attr = NFM_NFA(NLMSG_DATA(nlh)); + int attr_len = nlh->nlmsg_len - NLMSG_ALIGN(HDR_LENGTH); + + while (NFA_OK(attr, attr_len)) { + switch (NFA_TYPE(attr)) { + case NFULA_PAYLOAD: + payload_attr = attr; + break; + } + attr = NFA_NEXT(attr, attr_len); + } + } + + if (payload_attr) { + payload = NFA_DATA(payload_attr); + pkth.len = pkth.caplen = NFA_PAYLOAD(payload_attr); + } + + } else { + payload = NLMSG_DATA(nlh); + pkth.caplen = pkth.len = nlh->nlmsg_len-NLMSG_ALIGN(sizeof(struct nlmsghdr)); + } + + if (payload) { + /* pkth.caplen = min (payload_len, handle->snapshot); */ + + gettimeofday(&pkth.ts, NULL); + if (handle->fcode.bf_insns == NULL || + bpf_filter(handle->fcode.bf_insns, payload, pkth.len, pkth.caplen)) + { + handle->md.packets_read++; + callback(user, &pkth, payload); + count++; + } + } + } + + msg_len = NLMSG_ALIGN(nlh->nlmsg_len); + if (msg_len > len) + msg_len = len; + + len -= msg_len; + buf += msg_len; + } + return count; +} + +static int +netfilter_set_datalink(pcap_t *handle, int dlt) +{ + handle->linktype = dlt; + return 0; +} + +static int +netfilter_stats_linux(pcap_t *handle, struct pcap_stat *stats) +{ + stats->ps_recv = handle->md.packets_read; + stats->ps_drop = 0; + stats->ps_ifdrop = 0; + return 0; +} + +static int +netfilter_inject_linux(pcap_t *handle, const void *buf, size_t size) +{ + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "inject not supported on netfilter devices"); + return (-1); +} + +struct my_nfattr { + u_int16_t nfa_len; + u_int16_t nfa_type; + void *data; +}; + +static int +nflog_send_config_msg(const pcap_t *handle, u_int8_t family, u_int16_t res_id, const struct my_nfattr *mynfa) +{ + char buf[1024] __attribute__ ((aligned)); + + struct nlmsghdr *nlh = (struct nlmsghdr *) buf; + struct nfgenmsg *nfg = (struct nfgenmsg *) (buf + sizeof(struct nlmsghdr)); + + struct sockaddr_nl snl; + static unsigned int seq_id; + + if (!seq_id) + seq_id = time(NULL); + ++seq_id; + + nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct nfgenmsg)); + nlh->nlmsg_type = (NFNL_SUBSYS_ULOG << 8) | NFULNL_MSG_CONFIG; + nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; + nlh->nlmsg_pid = 0; /* to kernel */ + nlh->nlmsg_seq = seq_id; + + nfg->nfgen_family = family; + nfg->version = NFNETLINK_V0; + nfg->res_id = htons(res_id); + + if (mynfa) { + struct nfattr *nfa = (struct nfattr *) (buf + NLMSG_ALIGN(nlh->nlmsg_len)); + + nfa->nfa_type = mynfa->nfa_type; + nfa->nfa_len = NFA_LENGTH(mynfa->nfa_len); + memcpy(NFA_DATA(nfa), mynfa->data, mynfa->nfa_len); + nlh->nlmsg_len = NLMSG_ALIGN(nlh->nlmsg_len) + NFA_ALIGN(nfa->nfa_len); + } + + memset(&snl, 0, sizeof(snl)); + snl.nl_family = AF_NETLINK; + + if (sendto(handle->fd, nlh, nlh->nlmsg_len, 0, (struct sockaddr *) &snl, sizeof(snl)) == -1) + return -1; + + /* waiting for reply loop */ + do { + socklen_t addrlen = sizeof(snl); + int len; + + /* ignore interrupt system call error */ + do { + len = recvfrom(handle->fd, buf, sizeof(buf), 0, (struct sockaddr *) &snl, &addrlen); + } while ((len == -1) && (errno == EINTR)); + + if (len <= 0) + return len; + + if (addrlen != sizeof(snl) || snl.nl_family != AF_NETLINK) { + errno = EINVAL; + return -1; + } + + nlh = (struct nlmsghdr *) buf; + if (snl.nl_pid != 0 || seq_id != nlh->nlmsg_seq) /* if not from kernel or wrong sequence skip */ + continue; + + while (len >= NLMSG_SPACE(0) && NLMSG_OK(nlh, len)) { + if (nlh->nlmsg_type == NLMSG_ERROR || (nlh->nlmsg_type == NLMSG_DONE && nlh->nlmsg_flags & NLM_F_MULTI)) { + if (nlh->nlmsg_len < NLMSG_ALIGN(sizeof(struct nlmsgerr))) { + errno = EBADMSG; + return -1; + } + errno = -(*((int *)NLMSG_DATA(nlh))); + return (errno == 0) ? 0 : -1; + } + nlh = NLMSG_NEXT(nlh, len); + } + } while (1); + + return -1; /* never here */ +} + +static int +nflog_send_config_cmd(const pcap_t *handle, u_int16_t group_id, u_int8_t cmd, u_int8_t family) +{ + struct nfulnl_msg_config_cmd msg; + struct my_nfattr nfa; + + msg.command = cmd; + + nfa.data = &msg; + nfa.nfa_type = NFULA_CFG_CMD; + nfa.nfa_len = sizeof(msg); + + return nflog_send_config_msg(handle, family, group_id, &nfa); +} + +static int +nflog_send_config_mode(const pcap_t *handle, u_int16_t group_id, u_int8_t copy_mode, u_int32_t copy_range) +{ + struct nfulnl_msg_config_mode msg; + struct my_nfattr nfa; + + msg.copy_range = htonl(copy_range); + msg.copy_mode = copy_mode; + + nfa.data = &msg; + nfa.nfa_type = NFULA_CFG_MODE; + nfa.nfa_len = sizeof(msg); + + return nflog_send_config_msg(handle, AF_UNSPEC, group_id, &nfa); +} + +static int +nflog_activate(pcap_t* handle) +{ + const char *dev = handle->opt.source; + unsigned short groups[32]; + int group_count = 0; + int i; + + if (strncmp(dev, NFLOG_IFACE, strlen(NFLOG_IFACE)) == 0) { + dev += strlen(NFLOG_IFACE); + + /* nflog:30,33,42 looks nice, allow it */ + if (*dev == ':') + dev++; + + while (*dev) { + long int group_id; + char *end_dev; + + if (group_count == 32) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Maximum 32 netfilter groups! dev: %s", + handle->opt.source); + return PCAP_ERROR; + } + + group_id = strtol(dev, &end_dev, 0); + if (end_dev != dev) { + if (group_id < 0 || group_id > 65535) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Netfilter group range from 0 to 65535 (got %ld)", + group_id); + return PCAP_ERROR; + } + + groups[group_count++] = (unsigned short) group_id; + dev = end_dev; + } + if (*dev != ',') + break; + dev++; + } + } + + if (*dev) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Can't get netfilter group(s) index from %s", + handle->opt.source); + return PCAP_ERROR; + } + + /* if no groups, add default: 0 */ + if (!group_count) { + groups[0] = 0; + group_count = 1; + } + + /* Initialize some components of the pcap structure. */ + handle->bufsize = 128 + handle->snapshot; + handle->offset = 0; + handle->linktype = DLT_NFLOG; + handle->read_op = nflog_read_linux; + handle->inject_op = netfilter_inject_linux; + handle->setfilter_op = install_bpf_program; /* no kernel filtering */ + handle->setdirection_op = NULL; + handle->set_datalink_op = NULL; + handle->set_datalink_op = netfilter_set_datalink; + handle->getnonblock_op = pcap_getnonblock_fd; + handle->setnonblock_op = pcap_setnonblock_fd; + handle->stats_op = netfilter_stats_linux; + + /* Create netlink socket */ + handle->fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_NETFILTER); + if (handle->fd < 0) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't create raw socket %d:%s", errno, pcap_strerror(errno)); + return PCAP_ERROR; + } + + handle->dlt_list = (u_int *) malloc(sizeof(u_int) * 2); + if (handle->dlt_list != NULL) { + handle->dlt_list[0] = DLT_NFLOG; + handle->dlt_list[1] = DLT_IPV4; + handle->dlt_count = 2; + } + + handle->buffer = malloc(handle->bufsize); + if (!handle->buffer) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't allocate dump buffer: %s", pcap_strerror(errno)); + goto close_fail; + } + + if (nflog_send_config_cmd(handle, 0, NFULNL_CFG_CMD_PF_UNBIND, AF_INET) < 0) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "NFULNL_CFG_CMD_PF_UNBIND: %s", pcap_strerror(errno)); + goto close_fail; + } + + if (nflog_send_config_cmd(handle, 0, NFULNL_CFG_CMD_PF_BIND, AF_INET) < 0) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "NFULNL_CFG_CMD_PF_BIND: %s", pcap_strerror(errno)); + goto close_fail; + } + + /* Bind socket to the nflog groups */ + for (i = 0; i < group_count; i++) { + if (nflog_send_config_cmd(handle, groups[i], NFULNL_CFG_CMD_BIND, AF_UNSPEC) < 0) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't listen on group group index: %s", pcap_strerror(errno)); + goto close_fail; + } + + if (nflog_send_config_mode(handle, groups[i], NFULNL_COPY_PACKET, handle->snapshot) < 0) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "NFULNL_COPY_PACKET: %s", pcap_strerror(errno)); + goto close_fail; + } + } + + if (handle->opt.rfmon) { + /* + * Monitor mode doesn't apply to netfilter devices. + */ + pcap_cleanup_live_common(handle); + return PCAP_ERROR_RFMON_NOTSUP; + } + + if (handle->opt.buffer_size != 0) { + /* + * Set the socket buffer size to the specified value. + */ + if (setsockopt(handle->fd, SOL_SOCKET, SO_RCVBUF, &handle->opt.buffer_size, sizeof(handle->opt.buffer_size)) == -1) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "SO_RCVBUF: %s", pcap_strerror(errno)); + goto close_fail; + } + } + + handle->selectable_fd = handle->fd; + return 0; + +close_fail: + pcap_cleanup_live_common(handle); + return PCAP_ERROR; +} + +pcap_t * +nflog_create(const char *device, char *ebuf) +{ + pcap_t *p; + + p = pcap_create_common(device, ebuf); + if (p == NULL) + return (NULL); + + p->activate_op = nflog_activate; + return (p); +} + +int +netfilter_platform_finddevs(pcap_if_t **alldevsp, char *err_str) +{ + pcap_if_t *found_dev = *alldevsp; + int sock; + + sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_NETFILTER); + if (sock < 0) { + /* if netlink is not supported this this is not fatal */ + if (errno == EAFNOSUPPORT) + return 0; + snprintf(err_str, PCAP_ERRBUF_SIZE, "Can't open netlink socket %d:%s", + errno, pcap_strerror(errno)); + return -1; + } + close(sock); + + if (pcap_add_if(&found_dev, NFLOG_IFACE, 0, "Linux netfilter log (NFLOG) interface", err_str) < 0) + return -1; + return 0; +} + diff --git a/pcap-netfilter-linux.h b/pcap-netfilter-linux.h new file mode 100644 index 000000000000..dd76b8a4350c --- /dev/null +++ b/pcap-netfilter-linux.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2011 Jakub Zawadzki + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Prototypes for netlink-related functions + */ +int netfilter_platform_finddevs(pcap_if_t **alldevsp, char *err_str); +pcap_t *nflog_create(const char *device, char *ebuf); diff --git a/pcap-tstamp.manmisc.in b/pcap-tstamp.manmisc.in new file mode 100644 index 000000000000..2cd32c621362 --- /dev/null +++ b/pcap-tstamp.manmisc.in @@ -0,0 +1,132 @@ +.\" +.\" Copyright (c) 1987, 1988, 1989, 1990, 1991, 1992, 1994, 1995, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP-TSTAMP @MAN_MISC_INFO@ "22 August 2010" +.SH NAME +pcap-tstamp \- packet time stamps in libpcap +.SH DESCRIPTION +When capturing traffic, each packet is given a time stamp representing, +for incoming packets, the arrival time of the packet and, for outgoing +packets, the transmission time of the packet. This time is an +approximation of the arrival or transmission time. If it is supplied by +the operating system running on the host on which the capture is being +done, there are several reasons why it might not precisely represent the +arrival or transmission time: +.IP +if the time stamp is applied to the packet when the networking stack +receives the packet, the networking stack might not see the packet until +an interrupt is delivered for the packet or a timer event causes the +networking device driver to poll for packets, and the time stamp might +not be applied until the packet has had some processing done by other +code in the networking stack, so there might be a significant delay +between the time when the last bit of the packet is received by the +capture device and when the networking stack time-stamps the packet; +.IP +the timer used to generate the time stamps might have low resolution, +for example, it might be a timer updated once per host operating system +timer tick, with the host operating system timer ticking once every few +milliseconds; +.IP +a high-resolution timer might use a counter that runs at a rate +dependent on the processor clock speed, and that clock speed might be +adjusted upwards or downwards over time and the timer might not be able +to compensate for all those adjustments; +.IP +the host operating system's clock might be adjusted over time to match a +time standard to which the host is being synchronized, which might be +done by temporarily slowing down or speeding up the clock or by making a +single adjustment; +.IP +different CPU cores on a multi-core or multi-processor system might be +running at different speeds, or might not have time counters all +synchronized, so packets time-stamped by different cores might not have +consistent time stamps. +.LP +In addition, packets time-stamped by different cores might be +time-stamped in one order and added to the queue of packets for libpcap +to read in another order, so time stamps might not be monotonically +increasing. +.LP +Some capture devices on some platforms can provide time stamps for +packets; those time stamps are usually high-resolution time stamps, and +are usually applied to the packet when the first or last bit of the +packet arrives, and are thus more accurate than time stamps provided by +the host operating system. Those time stamps might not, however, be +synchronized with the host operating system's clock, so that, for +example, the time stamp of a packet might not correspond to the time +stamp of an event on the host triggered by the arrival of that packet. +.LP +Depending on the capture device and the software on the host, libpcap +might allow different types of time stamp to be used. The +.BR pcap_list_tstamp_types (3PCAP) +routine provides, for a packet capture handle created by +.BR pcap_create (3PCAP) +but not yet activated by +.BR pcap_activate (3PCAP), +a list of time stamp types supported by the capture device for that +handle. +The list might be empty, in which case no choice of time stamp type is +offered for that capture device. If the list is not empty, the +.BR pcap_set_tstamp_type (3PCAP) +routine can be used after a +.B pcap_create() +call and before a +.B pcap_activate() +call to specify the type of time stamp to be used on the device. +The time stamp types are listed here; the first value is the #define to +use in code, the second value is the value returned by +.B pcap_tstamp_type_val_to_name() +and accepted by +.BR pcap_tstamp_name_to_val() . +.RS 5 +.TP 5 +.BR PCAP_TSTAMP_HOST " - " host +Time stamp provided by the host on which the capture is being done. The +precision of this time stamp is unspecified; it might or might not be +synchronized with the host operating system's clock. +.TP 5 +.BR PCAP_TSTAMP_HOST_LOWPREC " - " host_lowprec +Time stamp provided by the host on which the capture is being done. +This is a low-precision time stamp, synchronized with the host operating +system's clock. +.TP 5 +.BR PCAP_TSTAMP_HOST_HIPREC " - " host_hiprec +Time stamp provided by the host on which the capture is being done. +This is a high-precision time stamp; it might or might not be +synchronized with the host operating system's clock. It might be more +expensive to fetch than +.BR PCAP_TSTAMP_HOST_LOWPREC . +.TP 5 +.BR PCAP_TSTAMP_ADAPTER " - " adapter +Time stamp provided by the network adapter on which the capture is being +done. This is a high-precision time stamp, synchronized with the host +operating system's clock. +.TP 5 +.BR PCAP_TSTAMP_ADAPTER_UNSYNCED " - " adapter_unsynced +Time stamp provided by the network adapter on which the capture is being +done. This is a high-precision time stamp; it is not synchronized with +the host operating system's clock. +.RE +.SH SEE ALSO +pcap_set_tstamp_type(3PCAP), +pcap_list_tstamp_types(3PCAP), +pcap_tstamp_type_val_to_name(3PCAP), +pcap_tstamp_name_to_val(3PCAP) diff --git a/pcap_free_datalinks.3pcap b/pcap_free_datalinks.3pcap deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/pcap_freealldevs.3pcap b/pcap_freealldevs.3pcap deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/pcap_list_tstamp_types.3pcap.in b/pcap_list_tstamp_types.3pcap.in new file mode 100644 index 000000000000..66d3d6679310 --- /dev/null +++ b/pcap_list_tstamp_types.3pcap.in @@ -0,0 +1,70 @@ +.\" +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_LIST_TSTAMP_TYPES 3PCAP "21 August 2010" +.SH NAME +pcap_list_tstamp_types, pcap_free_tstamp_types \- get a list of time +stamp types supported by a capture device, and free that list +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +int pcap_list_tstamp_types(pcap_t *p, int **tstamp_typesp); +void pcap_free_tstamp_types(int *tstamp_types); +.ft +.fi +.SH DESCRIPTION +.B pcap_list_tstamp_types() +is used to get a list of the supported time stamp types of the interface +associated with the pcap descriptor. +.B pcap_list_tstamp_types() +allocates an array to hold the list and sets +.I *tstamp_typesp +to point to the array. +See +.BR pcap-tstamp (@MAN_MISC_INFO@) +for a list of all the time stamp types. +.PP +The caller is responsible for freeing the array with +.BR pcap_free_tstamp_types() , +which frees the list pointed to by +.IR tstamp_types . +.SH RETURN VALUE +.B pcap_list_tstamp_types() +returns the number of time stamp types in the array on success and +.B PCAP_ERROR +on failure. +A return value of zero means that you cannot specify a time stamp type; +you are limited to the capture device's default time stamp type. +If +.B PCAP_ERROR +is returned, +.B pcap_geterr() +or +.B pcap_perror() +may be called with +.I p +as an argument to fetch or display the error text. +.SH SEE ALSO +pcap(3PCAP), pcap_geterr(3PCAP), pcap_tstamp_type_val_to_name(3PCAP), +pcap-tstamp(@MAN_MISC_INFO@) diff --git a/pcap_set_tstamp_type.3pcap.in b/pcap_set_tstamp_type.3pcap.in new file mode 100644 index 000000000000..261c315200c0 --- /dev/null +++ b/pcap_set_tstamp_type.3pcap.in @@ -0,0 +1,65 @@ +.\" +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_SET_TSTAMP_TYPE 3PCAP "21 August 2010" +.SH NAME +pcap_set_tstamp_type \- set the time stamp type to be used by a +capture device +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +int pcap_set_tstamp_type(pcap_t *p, int tstamp_type); +.ft +.fi +.SH DESCRIPTION +.B pcap_set_tstamp_type() +sets the the type of time stamp desired for packets captured on the pcap +descriptor to the type specified by +.IR tstamp_type . +It must be called on a pcap descriptor created by +.B pcap_create() +that has not yet been activated by +.BR pcap_activate() . +.B pcap_list_tstamp_types() +will give a list of the time stamp types supported by a given capture +device. +See +.BR pcap-tstamp (@MAN_MISC_INFO@) +for a list of all the time stamp types. +.SH RETURN VALUE +.B pcap_set_tstamp_type() +returns 0 on success if the specified time stamp type is expected to be +supported by the capture device, +.B PCAP_WARNING_TSTAMP_TYPE_NOTSUP +on success if the specified time stamp type is not supported by the +capture device, +.B PCAP_ERROR_ACTIVATED +if called on a capture handle that has been activated, and +.B PCAP_ERROR_CANTSET_TSTAMP_TYPE +if the capture device doesn't support setting the time stamp type. +.SH SEE ALSO +pcap(3PCAP), +pcap_list_tstamp_types(3PCAP), +pcap_tstamp_type_name_to_val(3PCAP), +pcap-tstamp(@MAN_MISC_INFO@) diff --git a/pcap_tstamp_type_name_to_val.3pcap b/pcap_tstamp_type_name_to_val.3pcap new file mode 100644 index 000000000000..8fcc4d75c00f --- /dev/null +++ b/pcap_tstamp_type_name_to_val.3pcap @@ -0,0 +1,45 @@ +.\" +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_TSTAMP_TYPE_NAME_TO_VAL 3PCAP "21 August 2010" +.SH NAME +pcap_tstamp_type_name_to_val \- get the time stamp type value +corresponding to a time stamp type name +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +int pcap_tstamp_type_name_to_val(const char *name); +.ft +.fi +.SH DESCRIPTION +.B pcap_tstamp_type_name_to_val() +translates a time stamp type name to the corresponding time stamp type +value. The translation is case-insensitive. +.SH RETURN VALUE +.B pcap_tstamp_type_name_to_val() +returns 0 on success and +.B PCAP_ERROR +on failure. +.SH SEE ALSO +pcap(3PCAP), pcap_tstamp_type_val_to_name(3PCAP) diff --git a/pcap_tstamp_type_val_to_name.3pcap b/pcap_tstamp_type_val_to_name.3pcap new file mode 100644 index 000000000000..5d8d75405c17 --- /dev/null +++ b/pcap_tstamp_type_val_to_name.3pcap @@ -0,0 +1,45 @@ +.\" +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_TSTAMP_TYPE_VAL_TO_NAME 3PCAP "21 August 2010" +.SH NAME +pcap_tstamp_type_val_to_name, pcap_tstamp_type_val_to_description \- get +a name or description for a time stamp type value +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +const char *pcap_tstamp_type_val_to_name(int tstamp_type); +const char *pcap_tstamp_type_val_to_description(int tstamp_type); +.ft +.fi +.SH DESCRIPTION +.B pcap_tstamp_type_val_to_name() +translates a time stamp type value to the corresponding time stamp type +name. NULL is returned on failure. +.PP +.B pcap_tstamp_type_val_to_description() +translates a time stamp type value to a short description of that time +stamp type. NULL is returned on failure. +.SH SEE ALSO +pcap(3PCAP), pcap_tstamp_type_name_to_val(3PCAP) diff --git a/selpolltest.c b/selpolltest.c deleted file mode 100644 index d94fb567fb20..000000000000 --- a/selpolltest.c +++ /dev/null @@ -1,350 +0,0 @@ -/* - * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that: (1) source code distributions - * retain the above copyright notice and this paragraph in its entirety, (2) - * distributions including binary code include the above copyright notice and - * this paragraph in its entirety in the documentation or other materials - * provided with the distribution, and (3) all advertising materials mentioning - * features or use of this software display the following acknowledgement: - * ``This product includes software developed by the University of California, - * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of - * the University nor the names of its contributors may be used to endorse - * or promote products derived from this software without specific prior - * written permission. - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. - */ - -#ifndef lint -static const char copyright[] = - "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000\n\ -The Regents of the University of California. All rights reserved.\n"; -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -char *program_name; - -/* Forwards */ -static void countme(u_char *, const struct pcap_pkthdr *, const u_char *); -static void usage(void) __attribute__((noreturn)); -static void error(const char *, ...); -static void warning(const char *, ...); -static char *copy_argv(char **); - -static pcap_t *pd; - -extern int optind; -extern int opterr; -extern char *optarg; - -int -main(int argc, char **argv) -{ - register int op; - bpf_u_int32 localnet, netmask; - register char *cp, *cmdbuf, *device; - int doselect, dopoll, dotimeout, dononblock; - struct bpf_program fcode; - char ebuf[PCAP_ERRBUF_SIZE]; - int selectable_fd; - int status; - int packet_count; - - device = NULL; - doselect = 0; - dopoll = 0; - dotimeout = 0; - dononblock = 0; - if ((cp = strrchr(argv[0], '/')) != NULL) - program_name = cp + 1; - else - program_name = argv[0]; - - opterr = 0; - while ((op = getopt(argc, argv, "i:sptn")) != -1) { - switch (op) { - - case 'i': - device = optarg; - break; - - case 's': - doselect = 1; - break; - - case 'p': - dopoll = 1; - break; - - case 't': - dotimeout = 1; - break; - - case 'n': - dononblock = 1; - break; - - default: - usage(); - /* NOTREACHED */ - } - } - - if (doselect && dopoll) { - fprintf(stderr, "selpolltest: choose select (-s) or poll (-p), but not both\n"); - return 1; - } - if (dotimeout && !doselect && !dopoll) { - fprintf(stderr, "selpolltest: timeout (-t) requires select (-s) or poll (-p)\n"); - return 1; - } - if (device == NULL) { - device = pcap_lookupdev(ebuf); - if (device == NULL) - error("%s", ebuf); - } - *ebuf = '\0'; - pd = pcap_open_live(device, 65535, 0, 1000, ebuf); - if (pd == NULL) - error("%s", ebuf); - else if (*ebuf) - warning("%s", ebuf); - if (pcap_lookupnet(device, &localnet, &netmask, ebuf) < 0) { - localnet = 0; - netmask = 0; - warning("%s", ebuf); - } - cmdbuf = copy_argv(&argv[optind]); - - if (pcap_compile(pd, &fcode, cmdbuf, 1, netmask) < 0) - error("%s", pcap_geterr(pd)); - - if (pcap_setfilter(pd, &fcode) < 0) - error("%s", pcap_geterr(pd)); - if (pcap_get_selectable_fd(pd) == -1) - error("pcap_get_selectable_fd() fails"); - if (dononblock) { - if (pcap_setnonblock(pd, 1, ebuf) == -1) - error("pcap_setnonblock failed: %s", ebuf); - } - selectable_fd = pcap_get_selectable_fd(pd); - printf("Listening on %s\n", device); - if (doselect) { - for (;;) { - fd_set setread, setexcept; - struct timeval seltimeout; - - FD_ZERO(&setread); - FD_SET(selectable_fd, &setread); - FD_ZERO(&setexcept); - FD_SET(selectable_fd, &setexcept); - if (dotimeout) { - seltimeout.tv_sec = 0; - seltimeout.tv_usec = 1000; - status = select(selectable_fd + 1, &setread, - NULL, &setexcept, &seltimeout); - } else { - status = select(selectable_fd + 1, &setread, - NULL, &setexcept, NULL); - } - if (status == -1) { - printf("Select returns error (%s)\n", - strerror(errno)); - } else { - if (status == 0) - printf("Select timed out: "); - else - printf("Select returned a descriptor: "); - if (FD_ISSET(selectable_fd, &setread)) - printf("readable, "); - else - printf("not readable, "); - if (FD_ISSET(selectable_fd, &setexcept)) - printf("exceptional condition\n"); - else - printf("no exceptional condition\n"); - packet_count = 0; - status = pcap_dispatch(pd, -1, countme, - (u_char *)&packet_count); - if (status < 0) - break; - printf("%d packets seen, %d packets counted after select returns\n", - status, packet_count); - } - } - } else if (dopoll) { - for (;;) { - struct pollfd fd; - int polltimeout; - - fd.fd = selectable_fd; - fd.events = POLLIN; - if (dotimeout) - polltimeout = 1; - else - polltimeout = -1; - status = poll(&fd, 1, polltimeout); - if (status == -1) { - printf("Poll returns error (%s)\n", - strerror(errno)); - } else { - if (status == 0) - printf("Poll timed out\n"); - else { - printf("Poll returned a descriptor: "); - if (fd.revents & POLLIN) - printf("readable, "); - else - printf("not readable, "); - if (fd.revents & POLLERR) - printf("exceptional condition, "); - else - printf("no exceptional condition, "); - if (fd.revents & POLLHUP) - printf("disconnect, "); - else - printf("no disconnect, "); - if (fd.revents & POLLNVAL) - printf("invalid\n"); - else - printf("not invalid\n"); - } - packet_count = 0; - status = pcap_dispatch(pd, -1, countme, - (u_char *)&packet_count); - if (status < 0) - break; - printf("%d packets seen, %d packets counted after poll returns\n", - status, packet_count); - } - } - } else { - for (;;) { - packet_count = 0; - status = pcap_dispatch(pd, -1, countme, - (u_char *)&packet_count); - if (status < 0) - break; - printf("%d packets seen, %d packets counted after pcap_dispatch returns\n", - status, packet_count); - } - } - if (status == -2) { - /* - * We got interrupted, so perhaps we didn't - * manage to finish a line we were printing. - * Print an extra newline, just in case. - */ - putchar('\n'); - } - (void)fflush(stdout); - if (status == -1) { - /* - * Error. Report it. - */ - (void)fprintf(stderr, "%s: pcap_loop: %s\n", - program_name, pcap_geterr(pd)); - } - pcap_close(pd); - exit(status == -1 ? 1 : 0); -} - -static void -countme(u_char *user, const struct pcap_pkthdr *h, const u_char *sp) -{ - int *counterp = (int *)user; - - (*counterp)++; -} - -static void -usage(void) -{ - (void)fprintf(stderr, "Usage: %s [ -sptn ] [ -i interface ] [expression]\n", - program_name); - exit(1); -} - -/* VARARGS */ -static void -error(const char *fmt, ...) -{ - va_list ap; - - (void)fprintf(stderr, "%s: ", program_name); - va_start(ap, fmt); - (void)vfprintf(stderr, fmt, ap); - va_end(ap); - if (*fmt) { - fmt += strlen(fmt); - if (fmt[-1] != '\n') - (void)fputc('\n', stderr); - } - exit(1); - /* NOTREACHED */ -} - -/* VARARGS */ -static void -warning(const char *fmt, ...) -{ - va_list ap; - - (void)fprintf(stderr, "%s: WARNING: ", program_name); - va_start(ap, fmt); - (void)vfprintf(stderr, fmt, ap); - va_end(ap); - if (*fmt) { - fmt += strlen(fmt); - if (fmt[-1] != '\n') - (void)fputc('\n', stderr); - } -} - -/* - * Copy arg vector into a new buffer, concatenating arguments with spaces. - */ -static char * -copy_argv(register char **argv) -{ - register char **p; - register u_int len = 0; - char *buf; - char *src, *dst; - - p = argv; - if (*p == 0) - return 0; - - while (*p) - len += strlen(*p++) + 1; - - buf = (char *)malloc(len); - if (buf == NULL) - error("copy_argv: malloc"); - - p = argv; - dst = buf; - while ((src = *p++) != NULL) { - while ((*dst++ = *src++) != '\0') - ; - dst[-1] = ' '; - } - dst[-1] = '\0'; - - return buf; -} diff --git a/test/filtertest.c b/test/filtertest.c new file mode 100644 index 000000000000..a56d1e49e923 --- /dev/null +++ b/test/filtertest.c @@ -0,0 +1,266 @@ +/* + * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef lint +static const char copyright[] _U_ = + "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000\n\ +The Regents of the University of California. All rights reserved.\n"; +static const char rcsid[] _U_ = + "@(#) $Header: /tcpdump/master/libpcap/filtertest.c,v 1.2 2005-08-08 17:50:13 guy Exp $ (LBL)"; +#endif + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef HAVE___ATTRIBUTE__ +#define __attribute__(x) +#endif + +static char *program_name; + +/* Forwards */ +static void usage(void) __attribute__((noreturn)); +static void error(const char *, ...) + __attribute__((noreturn, format (printf, 1, 2))); + +extern int optind; +extern int opterr; +extern char *optarg; + +/* + * On Windows, we need to open the file in binary mode, so that + * we get all the bytes specified by the size we get from "fstat()". + * On UNIX, that's not necessary. O_BINARY is defined on Windows; + * we define it as 0 if it's not defined, so it does nothing. + */ +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +static char * +read_infile(char *fname) +{ + register int i, fd, cc; + register char *cp; + struct stat buf; + + fd = open(fname, O_RDONLY|O_BINARY); + if (fd < 0) + error("can't open %s: %s", fname, pcap_strerror(errno)); + + if (fstat(fd, &buf) < 0) + error("can't stat %s: %s", fname, pcap_strerror(errno)); + + cp = malloc((u_int)buf.st_size + 1); + if (cp == NULL) + error("malloc(%d) for %s: %s", (u_int)buf.st_size + 1, + fname, pcap_strerror(errno)); + cc = read(fd, cp, (u_int)buf.st_size); + if (cc < 0) + error("read %s: %s", fname, pcap_strerror(errno)); + if (cc != buf.st_size) + error("short read %s (%d != %d)", fname, cc, (int)buf.st_size); + + close(fd); + /* replace "# comment" with spaces */ + for (i = 0; i < cc; i++) { + if (cp[i] == '#') + while (i < cc && cp[i] != '\n') + cp[i++] = ' '; + } + cp[cc] = '\0'; + return (cp); +} + +/* VARARGS */ +static void +error(const char *fmt, ...) +{ + va_list ap; + + (void)fprintf(stderr, "%s: ", program_name); + va_start(ap, fmt); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + if (*fmt) { + fmt += strlen(fmt); + if (fmt[-1] != '\n') + (void)fputc('\n', stderr); + } + exit(1); + /* NOTREACHED */ +} + +/* + * Copy arg vector into a new buffer, concatenating arguments with spaces. + */ +static char * +copy_argv(register char **argv) +{ + register char **p; + register u_int len = 0; + char *buf; + char *src, *dst; + + p = argv; + if (*p == 0) + return 0; + + while (*p) + len += strlen(*p++) + 1; + + buf = (char *)malloc(len); + if (buf == NULL) + error("copy_argv: malloc"); + + p = argv; + dst = buf; + while ((src = *p++) != NULL) { + while ((*dst++ = *src++) != '\0') + ; + dst[-1] = ' '; + } + dst[-1] = '\0'; + + return buf; +} + +int +main(int argc, char **argv) +{ + char *cp; + int op; + int dflag; + char *infile; + int Oflag; + long snaplen; + int dlt; + bpf_u_int32 netmask = PCAP_NETMASK_UNKNOWN; + char *cmdbuf; + pcap_t *pd; + struct bpf_program fcode; + +#ifdef WIN32 + if(wsockinit() != 0) return 1; +#endif /* WIN32 */ + + dflag = 1; + infile = NULL; + Oflag = 1; + snaplen = 68; + + if ((cp = strrchr(argv[0], '/')) != NULL) + program_name = cp + 1; + else + program_name = argv[0]; + + opterr = 0; + while ((op = getopt(argc, argv, "dF:m:Os:")) != -1) { + switch (op) { + + case 'd': + ++dflag; + break; + + case 'F': + infile = optarg; + break; + + case 'O': + Oflag = 0; + break; + + case 'm': { + in_addr_t addr; + + addr = inet_addr(optarg); + if (addr == INADDR_NONE) + error("invalid netmask %s", optarg); + netmask = addr; + break; + } + + case 's': { + char *end; + + snaplen = strtol(optarg, &end, 0); + if (optarg == end || *end != '\0' + || snaplen < 0 || snaplen > 65535) + error("invalid snaplen %s", optarg); + else if (snaplen == 0) + snaplen = 65535; + break; + } + + default: + usage(); + /* NOTREACHED */ + } + } + + if (optind >= argc) { + usage(); + /* NOTREACHED */ + } + + dlt = pcap_datalink_name_to_val(argv[optind]); + if (dlt < 0) + error("invalid data link type %s", argv[optind]); + + if (infile) + cmdbuf = read_infile(infile); + else + cmdbuf = copy_argv(&argv[optind+1]); + + pd = pcap_open_dead(dlt, snaplen); + if (pd == NULL) + error("Can't open fake pcap_t"); + + if (pcap_compile(pd, &fcode, cmdbuf, Oflag, netmask) < 0) + error("%s", pcap_geterr(pd)); + bpf_dump(&fcode, dflag); + pcap_close(pd); + exit(0); +} + +static void +usage(void) +{ + (void)fprintf(stderr, "%s, with %s\n", program_name, + pcap_lib_version()); + (void)fprintf(stderr, + "Usage: %s [-dO] [ -F file ] [ -m netmask] [ -s snaplen ] dlt [ expression ]\n", + program_name); + exit(1); +} diff --git a/test/findalldevstest.c b/test/findalldevstest.c new file mode 100644 index 000000000000..ec7c95015c9e --- /dev/null +++ b/test/findalldevstest.c @@ -0,0 +1,131 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include + +#include + +static void ifprint(pcap_if_t *d); +static char *iptos(bpf_u_int32 in); + +int main(int argc, char **argv) +{ + pcap_if_t *alldevs; + pcap_if_t *d; + char *s; + bpf_u_int32 net, mask; + + char errbuf[PCAP_ERRBUF_SIZE+1]; + if (pcap_findalldevs(&alldevs, errbuf) == -1) + { + fprintf(stderr,"Error in pcap_findalldevs: %s\n",errbuf); + exit(1); + } + for(d=alldevs;d;d=d->next) + { + ifprint(d); + } + + if ( (s = pcap_lookupdev(errbuf)) == NULL) + { + fprintf(stderr,"Error in pcap_lookupdev: %s\n",errbuf); + } + else + { + printf("Preferred device name: %s\n",s); + } + + if (pcap_lookupnet(s, &net, &mask, errbuf) < 0) + { + fprintf(stderr,"Error in pcap_lookupnet: %s\n",errbuf); + } + else + { + printf("Preferred device is on network: %s/%s\n",iptos(net), iptos(mask)); + } + + exit(0); +} + +static void ifprint(pcap_if_t *d) +{ + pcap_addr_t *a; +#ifdef INET6 + char ntop_buf[INET6_ADDRSTRLEN]; +#endif + + printf("%s\n",d->name); + if (d->description) + printf("\tDescription: %s\n",d->description); + printf("\tLoopback: %s\n",(d->flags & PCAP_IF_LOOPBACK)?"yes":"no"); + + for(a=d->addresses;a;a=a->next) { + switch(a->addr->sa_family) + { + case AF_INET: + printf("\tAddress Family: AF_INET\n"); + if (a->addr) + printf("\t\tAddress: %s\n", + inet_ntoa(((struct sockaddr_in *)(a->addr))->sin_addr)); + if (a->netmask) + printf("\t\tNetmask: %s\n", + inet_ntoa(((struct sockaddr_in *)(a->netmask))->sin_addr)); + if (a->broadaddr) + printf("\t\tBroadcast Address: %s\n", + inet_ntoa(((struct sockaddr_in *)(a->broadaddr))->sin_addr)); + if (a->dstaddr) + printf("\t\tDestination Address: %s\n", + inet_ntoa(((struct sockaddr_in *)(a->dstaddr))->sin_addr)); + break; +#ifdef INET6 + case AF_INET6: + printf("\tAddress Family: AF_INET6\n"); + if (a->addr) + printf("\t\tAddress: %s\n", + inet_ntop(AF_INET6, + ((struct sockaddr_in6 *)(a->addr))->sin6_addr.s6_addr, + ntop_buf, sizeof ntop_buf)); + if (a->netmask) + printf("\t\tNetmask: %s\n", + inet_ntop(AF_INET6, + ((struct sockaddr_in6 *)(a->netmask))->sin6_addr.s6_addr, + ntop_buf, sizeof ntop_buf)); + if (a->broadaddr) + printf("\t\tBroadcast Address: %s\n", + inet_ntop(AF_INET6, + ((struct sockaddr_in6 *)(a->broadaddr))->sin6_addr.s6_addr, + ntop_buf, sizeof ntop_buf)); + if (a->dstaddr) + printf("\t\tDestination Address: %s\n", + inet_ntop(AF_INET6, + ((struct sockaddr_in6 *)(a->dstaddr))->sin6_addr.s6_addr, + ntop_buf, sizeof ntop_buf)); + break; +#endif + default: + printf("\tAddress Family: Unknown (%d)\n", a->addr->sa_family); + break; + } + } + printf("\n"); +} + +/* From tcptraceroute */ +#define IPTOSBUFFERS 12 +static char *iptos(bpf_u_int32 in) +{ + static char output[IPTOSBUFFERS][3*4+3+1]; + static short which; + u_char *p; + + p = (u_char *)∈ + which = (which + 1 == IPTOSBUFFERS ? 0 : which + 1); + sprintf(output[which], "%d.%d.%d.%d", p[0], p[1], p[2], p[3]); + return output[which]; +} diff --git a/test/nonblocktest.c b/test/nonblocktest.c new file mode 100644 index 000000000000..70a6bfdaa1bc --- /dev/null +++ b/test/nonblocktest.c @@ -0,0 +1,226 @@ +/* + * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef lint +static const char copyright[] = + "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000\n\ +The Regents of the University of California. All rights reserved.\n"; +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +char *program_name; + +/* Forwards */ +static void countme(u_char *, const struct pcap_pkthdr *, const u_char *); +static void usage(void) __attribute__((noreturn)); +static void error(const char *, ...); +static void warning(const char *, ...); +static char *copy_argv(char **); + +static pcap_t *pd; + +extern int optind; +extern int opterr; +extern char *optarg; + +int +main(int argc, char **argv) +{ + register int op; + bpf_u_int32 localnet, netmask; + register char *cp, *cmdbuf, *device; + struct bpf_program fcode; + char ebuf[PCAP_ERRBUF_SIZE]; + int status; + int packet_count; + + device = NULL; + if ((cp = strrchr(argv[0], '/')) != NULL) + program_name = cp + 1; + else + program_name = argv[0]; + + opterr = 0; + while ((op = getopt(argc, argv, "i:")) != -1) { + switch (op) { + + case 'i': + device = optarg; + break; + + default: + usage(); + /* NOTREACHED */ + } + } + + if (device == NULL) { + device = pcap_lookupdev(ebuf); + if (device == NULL) + error("%s", ebuf); + } + *ebuf = '\0'; + pd = pcap_open_live(device, 65535, 0, 1000, ebuf); + if (pd == NULL) + error("%s", ebuf); + else if (*ebuf) + warning("%s", ebuf); + if (pcap_lookupnet(device, &localnet, &netmask, ebuf) < 0) { + localnet = 0; + netmask = 0; + warning("%s", ebuf); + } + cmdbuf = copy_argv(&argv[optind]); + + if (pcap_compile(pd, &fcode, cmdbuf, 1, netmask) < 0) + error("%s", pcap_geterr(pd)); + + if (pcap_setfilter(pd, &fcode) < 0) + error("%s", pcap_geterr(pd)); + if (pcap_setnonblock(pd, 1, ebuf) == -1) + error("pcap_setnonblock failed: %s", ebuf); + printf("Listening on %s\n", device); + for (;;) { + packet_count = 0; + status = pcap_dispatch(pd, -1, countme, + (u_char *)&packet_count); + if (status < 0) + break; + if (status != 0) { + printf("%d packets seen, %d packets counted after pcap_dispatch returns\n", + status, packet_count); + } + } + if (status == -2) { + /* + * We got interrupted, so perhaps we didn't + * manage to finish a line we were printing. + * Print an extra newline, just in case. + */ + putchar('\n'); + } + (void)fflush(stdout); + if (status == -1) { + /* + * Error. Report it. + */ + (void)fprintf(stderr, "%s: pcap_loop: %s\n", + program_name, pcap_geterr(pd)); + } + pcap_close(pd); + exit(status == -1 ? 1 : 0); +} + +static void +countme(u_char *user, const struct pcap_pkthdr *h, const u_char *sp) +{ + int *counterp = (int *)user; + + (*counterp)++; +} + +static void +usage(void) +{ + (void)fprintf(stderr, "Usage: %s [ -sptn ] [ -i interface ] [expression]\n", + program_name); + exit(1); +} + +/* VARARGS */ +static void +error(const char *fmt, ...) +{ + va_list ap; + + (void)fprintf(stderr, "%s: ", program_name); + va_start(ap, fmt); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + if (*fmt) { + fmt += strlen(fmt); + if (fmt[-1] != '\n') + (void)fputc('\n', stderr); + } + exit(1); + /* NOTREACHED */ +} + +/* VARARGS */ +static void +warning(const char *fmt, ...) +{ + va_list ap; + + (void)fprintf(stderr, "%s: WARNING: ", program_name); + va_start(ap, fmt); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + if (*fmt) { + fmt += strlen(fmt); + if (fmt[-1] != '\n') + (void)fputc('\n', stderr); + } +} + +/* + * Copy arg vector into a new buffer, concatenating arguments with spaces. + */ +static char * +copy_argv(register char **argv) +{ + register char **p; + register u_int len = 0; + char *buf; + char *src, *dst; + + p = argv; + if (*p == 0) + return 0; + + while (*p) + len += strlen(*p++) + 1; + + buf = (char *)malloc(len); + if (buf == NULL) + error("copy_argv: malloc"); + + p = argv; + dst = buf; + while ((src = *p++) != NULL) { + while ((*dst++ = *src++) != '\0') + ; + dst[-1] = ' '; + } + dst[-1] = '\0'; + + return buf; +} diff --git a/test/opentest.c b/test/opentest.c new file mode 100644 index 000000000000..0c91531018db --- /dev/null +++ b/test/opentest.c @@ -0,0 +1,216 @@ +/* + * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef lint +static const char copyright[] = + "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000\n\ +The Regents of the University of California. All rights reserved.\n"; +#endif + +#include +#include +#include +#include +#include +#include +#include + +#define MAXIMUM_SNAPLEN 65535 + +static char *program_name; + +/* Forwards */ +static void usage(void) __attribute__((noreturn)); +static void error(const char *, ...); +static void warning(const char *, ...); + +extern int optind; +extern int opterr; +extern char *optarg; + +int +main(int argc, char **argv) +{ + register int op; + register char *cp, *device; + int dorfmon, dopromisc, snaplen, useactivate, bufsize; + char ebuf[PCAP_ERRBUF_SIZE]; + pcap_t *pd; + int status = 0; + + device = NULL; + dorfmon = 0; + dopromisc = 0; + snaplen = MAXIMUM_SNAPLEN; + bufsize = 0; + useactivate = 0; + if ((cp = strrchr(argv[0], '/')) != NULL) + program_name = cp + 1; + else + program_name = argv[0]; + + opterr = 0; + while ((op = getopt(argc, argv, "i:Ips:aB:")) != -1) { + switch (op) { + + case 'i': + device = optarg; + break; + + case 'I': + dorfmon = 1; + useactivate = 1; /* required for rfmon */ + break; + + case 'p': + dopromisc = 1; + break; + + case 's': { + char *end; + + snaplen = strtol(optarg, &end, 0); + if (optarg == end || *end != '\0' + || snaplen < 0 || snaplen > MAXIMUM_SNAPLEN) + error("invalid snaplen %s", optarg); + else if (snaplen == 0) + snaplen = MAXIMUM_SNAPLEN; + break; + } + + case 'B': + bufsize = atoi(optarg)*1024; + if (bufsize <= 0) + error("invalid packet buffer size %s", optarg); + useactivate = 1; /* required for bufsize */ + break; + + case 'a': + useactivate = 1; + break; + + default: + usage(); + /* NOTREACHED */ + } + } + + if (useactivate) { + pd = pcap_create(device, ebuf); + if (pd == NULL) + error("%s", ebuf); + status = pcap_set_snaplen(pd, snaplen); + if (status != 0) + error("%s: pcap_set_snaplen failed: %s", + device, pcap_statustostr(status)); + if (dopromisc) { + status = pcap_set_promisc(pd, 1); + if (status != 0) + error("%s: pcap_set_promisc failed: %s", + device, pcap_statustostr(status)); + } + if (dorfmon) { + status = pcap_set_rfmon(pd, 1); + if (status != 0) + error("%s: pcap_set_rfmon failed: %s", + device, pcap_statustostr(status)); + } + status = pcap_set_timeout(pd, 1000); + if (status != 0) + error("%s: pcap_set_timeout failed: %s", + device, pcap_statustostr(status)); + if (bufsize != 0) { + status = pcap_set_buffer_size(pd, bufsize); + if (status != 0) + error("%s: pcap_set_buffer_size failed: %s", + device, pcap_statustostr(status)); + } + status = pcap_activate(pd); + if (status < 0) { + /* + * pcap_activate() failed. + */ + error("%s: %s\n(%s)", device, + pcap_statustostr(status), pcap_geterr(pd)); + } else if (status > 0) { + /* + * pcap_activate() succeeded, but it's warning us + * of a problem it had. + */ + warning("%s: %s\n(%s)", device, + pcap_statustostr(status), pcap_geterr(pd)); + } + } else { + *ebuf = '\0'; + pd = pcap_open_live(device, 65535, 0, 1000, ebuf); + if (pd == NULL) + error("%s", ebuf); + else if (*ebuf) + warning("%s", ebuf); + } + pcap_close(pd); + exit(status < 0 ? 1 : 0); +} + +static void +usage(void) +{ + (void)fprintf(stderr, + "Usage: %s [ -Ipa ] [ -i interface ] [ -s snaplen ] [ -B bufsize ]\n", + program_name); + exit(1); +} + +/* VARARGS */ +static void +error(const char *fmt, ...) +{ + va_list ap; + + (void)fprintf(stderr, "%s: ", program_name); + va_start(ap, fmt); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + if (*fmt) { + fmt += strlen(fmt); + if (fmt[-1] != '\n') + (void)fputc('\n', stderr); + } + exit(1); + /* NOTREACHED */ +} + +/* VARARGS */ +static void +warning(const char *fmt, ...) +{ + va_list ap; + + (void)fprintf(stderr, "%s: WARNING: ", program_name); + va_start(ap, fmt); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + if (*fmt) { + fmt += strlen(fmt); + if (fmt[-1] != '\n') + (void)fputc('\n', stderr); + } +} diff --git a/test/reactivatetest.c b/test/reactivatetest.c new file mode 100644 index 000000000000..9031a64a619e --- /dev/null +++ b/test/reactivatetest.c @@ -0,0 +1,84 @@ +/* + * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef lint +static const char copyright[] = + "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000\n\ +The Regents of the University of California. All rights reserved.\n"; +#endif + +#include +#include +#include +#include +#include + +/* Forwards */ +static void error(const char *, ...); + +int +main(void) +{ + char ebuf[PCAP_ERRBUF_SIZE]; + pcap_t *pd; + int status = 0; + + pd = pcap_open_live("lo0", 65535, 0, 1000, ebuf); + if (pd == NULL) { + pd = pcap_open_live("lo", 65535, 0, 1000, ebuf); + if (pd == NULL) { + error("Neither lo0 nor lo could be opened: %s", + ebuf); + return 2; + } + } + status = pcap_activate(pd); + if (status != PCAP_ERROR_ACTIVATED) { + if (status == 0) + error("pcap_activate() of opened pcap_t succeeded"); + else if (status == PCAP_ERROR) + error("pcap_activate() of opened pcap_t failed with %s, not PCAP_ERROR_ACTIVATED", + pcap_geterr(pd)); + else + error("pcap_activate() of opened pcap_t failed with %s, not PCAP_ERROR_ACTIVATED", + pcap_statustostr(status)); + } + return 0; +} + +/* VARARGS */ +static void +error(const char *fmt, ...) +{ + va_list ap; + + (void)fprintf(stderr, "reactivatetest: "); + va_start(ap, fmt); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + if (*fmt) { + fmt += strlen(fmt); + if (fmt[-1] != '\n') + (void)fputc('\n', stderr); + } + exit(1); + /* NOTREACHED */ +} diff --git a/test/selpolltest.c b/test/selpolltest.c new file mode 100644 index 000000000000..d94fb567fb20 --- /dev/null +++ b/test/selpolltest.c @@ -0,0 +1,350 @@ +/* + * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef lint +static const char copyright[] = + "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000\n\ +The Regents of the University of California. All rights reserved.\n"; +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +char *program_name; + +/* Forwards */ +static void countme(u_char *, const struct pcap_pkthdr *, const u_char *); +static void usage(void) __attribute__((noreturn)); +static void error(const char *, ...); +static void warning(const char *, ...); +static char *copy_argv(char **); + +static pcap_t *pd; + +extern int optind; +extern int opterr; +extern char *optarg; + +int +main(int argc, char **argv) +{ + register int op; + bpf_u_int32 localnet, netmask; + register char *cp, *cmdbuf, *device; + int doselect, dopoll, dotimeout, dononblock; + struct bpf_program fcode; + char ebuf[PCAP_ERRBUF_SIZE]; + int selectable_fd; + int status; + int packet_count; + + device = NULL; + doselect = 0; + dopoll = 0; + dotimeout = 0; + dononblock = 0; + if ((cp = strrchr(argv[0], '/')) != NULL) + program_name = cp + 1; + else + program_name = argv[0]; + + opterr = 0; + while ((op = getopt(argc, argv, "i:sptn")) != -1) { + switch (op) { + + case 'i': + device = optarg; + break; + + case 's': + doselect = 1; + break; + + case 'p': + dopoll = 1; + break; + + case 't': + dotimeout = 1; + break; + + case 'n': + dononblock = 1; + break; + + default: + usage(); + /* NOTREACHED */ + } + } + + if (doselect && dopoll) { + fprintf(stderr, "selpolltest: choose select (-s) or poll (-p), but not both\n"); + return 1; + } + if (dotimeout && !doselect && !dopoll) { + fprintf(stderr, "selpolltest: timeout (-t) requires select (-s) or poll (-p)\n"); + return 1; + } + if (device == NULL) { + device = pcap_lookupdev(ebuf); + if (device == NULL) + error("%s", ebuf); + } + *ebuf = '\0'; + pd = pcap_open_live(device, 65535, 0, 1000, ebuf); + if (pd == NULL) + error("%s", ebuf); + else if (*ebuf) + warning("%s", ebuf); + if (pcap_lookupnet(device, &localnet, &netmask, ebuf) < 0) { + localnet = 0; + netmask = 0; + warning("%s", ebuf); + } + cmdbuf = copy_argv(&argv[optind]); + + if (pcap_compile(pd, &fcode, cmdbuf, 1, netmask) < 0) + error("%s", pcap_geterr(pd)); + + if (pcap_setfilter(pd, &fcode) < 0) + error("%s", pcap_geterr(pd)); + if (pcap_get_selectable_fd(pd) == -1) + error("pcap_get_selectable_fd() fails"); + if (dononblock) { + if (pcap_setnonblock(pd, 1, ebuf) == -1) + error("pcap_setnonblock failed: %s", ebuf); + } + selectable_fd = pcap_get_selectable_fd(pd); + printf("Listening on %s\n", device); + if (doselect) { + for (;;) { + fd_set setread, setexcept; + struct timeval seltimeout; + + FD_ZERO(&setread); + FD_SET(selectable_fd, &setread); + FD_ZERO(&setexcept); + FD_SET(selectable_fd, &setexcept); + if (dotimeout) { + seltimeout.tv_sec = 0; + seltimeout.tv_usec = 1000; + status = select(selectable_fd + 1, &setread, + NULL, &setexcept, &seltimeout); + } else { + status = select(selectable_fd + 1, &setread, + NULL, &setexcept, NULL); + } + if (status == -1) { + printf("Select returns error (%s)\n", + strerror(errno)); + } else { + if (status == 0) + printf("Select timed out: "); + else + printf("Select returned a descriptor: "); + if (FD_ISSET(selectable_fd, &setread)) + printf("readable, "); + else + printf("not readable, "); + if (FD_ISSET(selectable_fd, &setexcept)) + printf("exceptional condition\n"); + else + printf("no exceptional condition\n"); + packet_count = 0; + status = pcap_dispatch(pd, -1, countme, + (u_char *)&packet_count); + if (status < 0) + break; + printf("%d packets seen, %d packets counted after select returns\n", + status, packet_count); + } + } + } else if (dopoll) { + for (;;) { + struct pollfd fd; + int polltimeout; + + fd.fd = selectable_fd; + fd.events = POLLIN; + if (dotimeout) + polltimeout = 1; + else + polltimeout = -1; + status = poll(&fd, 1, polltimeout); + if (status == -1) { + printf("Poll returns error (%s)\n", + strerror(errno)); + } else { + if (status == 0) + printf("Poll timed out\n"); + else { + printf("Poll returned a descriptor: "); + if (fd.revents & POLLIN) + printf("readable, "); + else + printf("not readable, "); + if (fd.revents & POLLERR) + printf("exceptional condition, "); + else + printf("no exceptional condition, "); + if (fd.revents & POLLHUP) + printf("disconnect, "); + else + printf("no disconnect, "); + if (fd.revents & POLLNVAL) + printf("invalid\n"); + else + printf("not invalid\n"); + } + packet_count = 0; + status = pcap_dispatch(pd, -1, countme, + (u_char *)&packet_count); + if (status < 0) + break; + printf("%d packets seen, %d packets counted after poll returns\n", + status, packet_count); + } + } + } else { + for (;;) { + packet_count = 0; + status = pcap_dispatch(pd, -1, countme, + (u_char *)&packet_count); + if (status < 0) + break; + printf("%d packets seen, %d packets counted after pcap_dispatch returns\n", + status, packet_count); + } + } + if (status == -2) { + /* + * We got interrupted, so perhaps we didn't + * manage to finish a line we were printing. + * Print an extra newline, just in case. + */ + putchar('\n'); + } + (void)fflush(stdout); + if (status == -1) { + /* + * Error. Report it. + */ + (void)fprintf(stderr, "%s: pcap_loop: %s\n", + program_name, pcap_geterr(pd)); + } + pcap_close(pd); + exit(status == -1 ? 1 : 0); +} + +static void +countme(u_char *user, const struct pcap_pkthdr *h, const u_char *sp) +{ + int *counterp = (int *)user; + + (*counterp)++; +} + +static void +usage(void) +{ + (void)fprintf(stderr, "Usage: %s [ -sptn ] [ -i interface ] [expression]\n", + program_name); + exit(1); +} + +/* VARARGS */ +static void +error(const char *fmt, ...) +{ + va_list ap; + + (void)fprintf(stderr, "%s: ", program_name); + va_start(ap, fmt); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + if (*fmt) { + fmt += strlen(fmt); + if (fmt[-1] != '\n') + (void)fputc('\n', stderr); + } + exit(1); + /* NOTREACHED */ +} + +/* VARARGS */ +static void +warning(const char *fmt, ...) +{ + va_list ap; + + (void)fprintf(stderr, "%s: WARNING: ", program_name); + va_start(ap, fmt); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + if (*fmt) { + fmt += strlen(fmt); + if (fmt[-1] != '\n') + (void)fputc('\n', stderr); + } +} + +/* + * Copy arg vector into a new buffer, concatenating arguments with spaces. + */ +static char * +copy_argv(register char **argv) +{ + register char **p; + register u_int len = 0; + char *buf; + char *src, *dst; + + p = argv; + if (*p == 0) + return 0; + + while (*p) + len += strlen(*p++) + 1; + + buf = (char *)malloc(len); + if (buf == NULL) + error("copy_argv: malloc"); + + p = argv; + dst = buf; + while ((src = *p++) != NULL) { + while ((*dst++ = *src++) != '\0') + ; + dst[-1] = ' '; + } + dst[-1] = '\0'; + + return buf; +} -- cgit v1.2.3