diff options
Diffstat (limited to 'testprogs')
-rw-r--r-- | testprogs/.gitignore | 13 | ||||
-rw-r--r-- | testprogs/BPF/1.txt | 2 | ||||
-rw-r--r-- | testprogs/BPF/2.txt | 2 | ||||
-rw-r--r-- | testprogs/BPF/3.txt | 1 | ||||
-rw-r--r-- | testprogs/BPF/4.txt | 2 | ||||
-rw-r--r-- | testprogs/BPF/5.txt | 1 | ||||
-rw-r--r-- | testprogs/BPF/6.txt | 1 | ||||
-rw-r--r-- | testprogs/BPF/7.txt | 1 | ||||
-rw-r--r-- | testprogs/CMakeLists.txt | 38 | ||||
-rw-r--r-- | testprogs/Makefile.in | 144 | ||||
-rw-r--r-- | testprogs/can_set_rfmon_test.c | 96 | ||||
-rw-r--r-- | testprogs/capturetest.c | 299 | ||||
-rw-r--r-- | testprogs/filtertest.c | 341 | ||||
-rw-r--r-- | testprogs/findalldevstest.c | 272 | ||||
-rw-r--r-- | testprogs/opentest.c | 236 | ||||
-rw-r--r-- | testprogs/pcap_compile_test.c | 11 | ||||
-rw-r--r-- | testprogs/reactivatetest.c | 88 | ||||
-rw-r--r-- | testprogs/selpolltest.c | 443 | ||||
-rw-r--r-- | testprogs/threadsignaltest.c | 393 | ||||
-rw-r--r-- | testprogs/unix.h | 58 | ||||
-rw-r--r-- | testprogs/valgrindtest.c | 427 | ||||
-rwxr-xr-x | testprogs/visopts.py | 309 |
22 files changed, 3178 insertions, 0 deletions
diff --git a/testprogs/.gitignore b/testprogs/.gitignore new file mode 100644 index 00000000..b9178b4e --- /dev/null +++ b/testprogs/.gitignore @@ -0,0 +1,13 @@ +Makefile +*~ +*.dSYM +*.o +valgrindtest +capturetest +can_set_rfmon_test +filtertest +findalldevstest +opentest +reactivatetest +selpolltest +threadsignaltest diff --git a/testprogs/BPF/1.txt b/testprogs/BPF/1.txt new file mode 100644 index 00000000..66086952 --- /dev/null +++ b/testprogs/BPF/1.txt @@ -0,0 +1,2 @@ +# common block merging, same block elimination, result propogation +host 192.168.1.1 diff --git a/testprogs/BPF/2.txt b/testprogs/BPF/2.txt new file mode 100644 index 00000000..e9bc1165 --- /dev/null +++ b/testprogs/BPF/2.txt @@ -0,0 +1,2 @@ +# common block merging +port 80 diff --git a/testprogs/BPF/3.txt b/testprogs/BPF/3.txt new file mode 100644 index 00000000..6c08d3d0 --- /dev/null +++ b/testprogs/BPF/3.txt @@ -0,0 +1 @@ +tcp[tcpflags]&tcp-syn != 0 or tcp[tcpflags]&tcp-fin != 0 or tcp[tcpflags]&tcp-rst != 0 diff --git a/testprogs/BPF/4.txt b/testprogs/BPF/4.txt new file mode 100644 index 00000000..3fd2e663 --- /dev/null +++ b/testprogs/BPF/4.txt @@ -0,0 +1,2 @@ +# or pullup +ether[12:2] = 0x800 or ether[12:2] = 0x8100 or ether[0] & 0x80 != 0 or ether[12:2] = 0x9100 diff --git a/testprogs/BPF/5.txt b/testprogs/BPF/5.txt new file mode 100644 index 00000000..23fc0ca5 --- /dev/null +++ b/testprogs/BPF/5.txt @@ -0,0 +1 @@ +vlan 186 and ip diff --git a/testprogs/BPF/6.txt b/testprogs/BPF/6.txt new file mode 100644 index 00000000..694c185b --- /dev/null +++ b/testprogs/BPF/6.txt @@ -0,0 +1 @@ +ip and ((icmp and dst host 1.1.1.1 and not host 2.2.2.2) or (host 1.1.1.1 and src host 3.3.3.3)) diff --git a/testprogs/BPF/7.txt b/testprogs/BPF/7.txt new file mode 100644 index 00000000..33978a4e --- /dev/null +++ b/testprogs/BPF/7.txt @@ -0,0 +1 @@ +not vlan and tcp port 80 diff --git a/testprogs/CMakeLists.txt b/testprogs/CMakeLists.txt new file mode 100644 index 00000000..fda14dc7 --- /dev/null +++ b/testprogs/CMakeLists.txt @@ -0,0 +1,38 @@ +if(MSVC) + file(GLOB PROJECT_SOURCE_LIST_WIN32_C ${pcap_SOURCE_DIR}/missing/getopt.c) + include_directories(${pcap_SOURCE_DIR}/missing) +endif(MSVC) + +add_custom_target(testprogs) + +macro(add_test_executable _executable) + add_executable(${_executable} EXCLUDE_FROM_ALL + ${_executable}.c ${PROJECT_SOURCE_LIST_WIN32_C}) + set_target_properties(${_executable} PROPERTIES + COMPILE_OPTIONS "${C_ADDITIONAL_FLAGS}") + if(WIN32) + target_link_libraries(${_executable} + ${ARGN} ${LIBRARY_NAME} ${PCAP_LINK_LIBRARIES}) + else(WIN32) + target_link_libraries(${_executable} + ${ARGN} ${LIBRARY_NAME}_static ${PCAP_LINK_LIBRARIES}) + endif(WIN32) + add_dependencies(testprogs ${_executable}) +endmacro() + +add_test_executable(can_set_rfmon_test) +add_test_executable(capturetest) +add_test_executable(filtertest) +add_test_executable(findalldevstest) +add_test_executable(opentest) +add_test_executable(reactivatetest) + +if(NOT WIN32) + add_test_executable(selpolltest) +endif() + +add_test_executable(threadsignaltest ${CMAKE_THREAD_LIBS_INIT}) + +if(NOT WIN32) + add_test_executable(valgrindtest) +endif() diff --git a/testprogs/Makefile.in b/testprogs/Makefile.in new file mode 100644 index 00000000..ec0a4720 --- /dev/null +++ b/testprogs/Makefile.in @@ -0,0 +1,144 @@ +# Copyright (c) 1993, 1994, 1995, 1996 +# 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. + +# +# Various configurable paths (remember to edit Makefile.in, not Makefile) +# + +# Top level hierarchy +prefix = @prefix@ +exec_prefix = @exec_prefix@ +datarootdir = @datarootdir@ +# Pathname of directory to install the configure program +bindir = @bindir@ +# Pathname of directory to install the rpcapd daemon +sbindir = @sbindir@ +# Pathname of directory to install the include files +includedir = @includedir@ +# Pathname of directory to install the library +libdir = @libdir@ +# Pathname of directory to install the man pages +mandir = @mandir@ + +# VPATH +srcdir = @srcdir@ +VPATH = @srcdir@ + +# +# You shouldn't need to edit anything below. +# + +LD = /usr/bin/ld +CC = @CC@ +AR = @AR@ +LN_S = @LN_S@ +MKDEP = @MKDEP@ +CCOPT = @V_CCOPT@ +INCLS = -I. -I.. -I@srcdir@ -I@srcdir@/.. @V_INCLS@ +DEFS = @DEFS@ @V_DEFS@ +ADDLOBJS = @ADDLOBJS@ +ADDLARCHIVEOBJS = @ADDLARCHIVEOBJS@ +LIBS = @LIBS@ +PTHREAD_LIBS = @PTHREAD_LIBS@ +CROSSFLAGS= +CFLAGS = @CFLAGS@ ${CROSSFLAGS} +LDFLAGS = @LDFLAGS@ ${CROSSFLAGS} +DYEXT = @DYEXT@ +V_RPATH_OPT = @V_RPATH_OPT@ +DEPENDENCY_CFLAG = @DEPENDENCY_CFLAG@ +EXTRA_NETWORK_LIBS=@EXTRA_NETWORK_LIBS@ + +# Standard CFLAGS for building test programs +FULL_CFLAGS = $(CCOPT) $(INCLS) $(DEFS) $(CFLAGS) + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ + +# Explicitly define compilation rule since SunOS 4's make doesn't like gcc. +# Also, gcc does not remove the .o before forking 'as', which can be a +# problem if you don't own the file but can write to the directory. +.c.o: + @rm -f $@ + $(CC) $(FULL_CFLAGS) -c $(srcdir)/$*.c + +SRC = @VALGRINDTEST_SRC@ \ + capturetest.c \ + can_set_rfmon_test.c \ + filtertest.c \ + findalldevstest.c \ + opentest.c \ + reactivatetest.c \ + selpolltest.c \ + threadsignaltest.c + +TESTS = $(SRC:.c=) + +TAGFILES = \ + $(SRC) $(HDR) + +CLEANFILES = $(OBJ) $(TESTS) + +all: $(TESTS) + +capturetest: $(srcdir)/capturetest.c ../libpcap.a + $(CC) $(FULL_CFLAGS) -I. -L. -o capturetest $(srcdir)/capturetest.c ../libpcap.a $(LIBS) + +can_set_rfmon_test: $(srcdir)/can_set_rfmon_test.c ../libpcap.a + $(CC) $(FULL_CFLAGS) -I. -L. -o can_set_rfmon_test $(srcdir)/can_set_rfmon_test.c ../libpcap.a $(LIBS) + +filtertest: $(srcdir)/filtertest.c ../libpcap.a + $(CC) $(FULL_CFLAGS) -I. -L. -o filtertest $(srcdir)/filtertest.c ../libpcap.a $(EXTRA_NETWORK_LIBS) $(LIBS) + +findalldevstest: $(srcdir)/findalldevstest.c ../libpcap.a + $(CC) $(FULL_CFLAGS) -I. -L. -o findalldevstest $(srcdir)/findalldevstest.c ../libpcap.a $(EXTRA_NETWORK_LIBS) $(LIBS) + +opentest: $(srcdir)/opentest.c ../libpcap.a + $(CC) $(FULL_CFLAGS) -I. -L. -o opentest $(srcdir)/opentest.c ../libpcap.a $(LIBS) + +reactivatetest: $(srcdir)/reactivatetest.c ../libpcap.a + $(CC) $(FULL_CFLAGS) -I. -L. -o reactivatetest $(srcdir)/reactivatetest.c ../libpcap.a $(LIBS) + +selpolltest: $(srcdir)/selpolltest.c ../libpcap.a + $(CC) $(FULL_CFLAGS) -I. -L. -o selpolltest $(srcdir)/selpolltest.c ../libpcap.a $(LIBS) + +threadsignaltest: $(srcdir)/threadsignaltest.c ../libpcap.a + $(CC) $(FULL_CFLAGS) -I. -L. -o threadsignaltest $(srcdir)/threadsignaltest.c ../libpcap.a $(LIBS) $(PTHREAD_LIBS) + +valgrindtest: $(srcdir)/valgrindtest.c ../libpcap.a + $(CC) $(FULL_CFLAGS) -I. -L. -o valgrindtest $(srcdir)/valgrindtest.c ../libpcap.a $(LIBS) + +clean: + rm -f $(CLEANFILES) + rm -rf *.dSYM + +distclean: clean + rm -f Makefile config.cache config.log config.status \ + config.h stamp-h stamp-h.in + rm -rf autom4te.cache + +install: + +uninstall: + +tags: $(TAGFILES) + ctags -wtd $(TAGFILES) + +depend: + ../$(MKDEP) -c "$(CC)" -m "$(DEPENDENCY_CFLAG)" $(CFLAGS) $(DEFS) $(INCLS) $(SRC) diff --git a/testprogs/can_set_rfmon_test.c b/testprogs/can_set_rfmon_test.c new file mode 100644 index 00000000..ea4f0c40 --- /dev/null +++ b/testprogs/can_set_rfmon_test.c @@ -0,0 +1,96 @@ +/* + * 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. + */ + +#include "varattrs.h" + +#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"; +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> + +#include <pcap.h> + +#include "pcap/funcattrs.h" + +static const char *program_name; + +/* Forwards */ +static void error(const char *, ...); + +int +main(int argc, char **argv) +{ + const char *cp; + pcap_t *pd; + char ebuf[PCAP_ERRBUF_SIZE]; + int status; + + if ((cp = strrchr(argv[0], '/')) != NULL) + program_name = cp + 1; + else + program_name = argv[0]; + + if (argc != 2) { + fprintf(stderr, "Usage: %s <device>\n", program_name); + return 2; + } + + pd = pcap_create(argv[1], ebuf); + if (pd == NULL) + error("%s", ebuf); + status = pcap_can_set_rfmon(pd); + if (status < 0) { + if (status == PCAP_ERROR) + error("%s: pcap_can_set_rfmon failed: %s", argv[1], + pcap_geterr(pd)); + else + error("%s: pcap_can_set_rfmon failed: %s", argv[1], + pcap_statustostr(status)); + return 1; + } + printf("%s: Monitor mode %s be set\n", argv[1], status ? "can" : "cannot"); + return 0; +} + +/* 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 */ +} diff --git a/testprogs/capturetest.c b/testprogs/capturetest.c new file mode 100644 index 00000000..573239f2 --- /dev/null +++ b/testprogs/capturetest.c @@ -0,0 +1,299 @@ +/* + * 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. + */ + +#include "varattrs.h" + +#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"; +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include <limits.h> +#ifdef _WIN32 + #include "getopt.h" +#else + #include <unistd.h> +#endif +#include <errno.h> +#include <sys/types.h> + +#include <pcap.h> + +#include "pcap/funcattrs.h" + +#ifdef _WIN32 + #include "portability.h" +#endif + +static char *program_name; + +/* Forwards */ +static void countme(u_char *, const struct pcap_pkthdr *, const u_char *); +static void PCAP_NORETURN usage(void); +static void PCAP_NORETURN error(const char *, ...) PCAP_PRINTFLIKE(1, 2); +static void warning(const char *, ...) PCAP_PRINTFLIKE(1, 2); +static char *copy_argv(char **); + +static pcap_t *pd; + +int +main(int argc, char **argv) +{ + register int op; + register char *cp, *cmdbuf, *device; + long longarg; + char *p; + int timeout = 1000; + int immediate = 0; + int nonblock = 0; + pcap_if_t *devlist; + bpf_u_int32 localnet, netmask; + 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:mnt:")) != -1) { + switch (op) { + + case 'i': + device = optarg; + break; + + case 'm': + immediate = 1; + break; + + case 'n': + nonblock = 1; + break; + + case 't': + longarg = strtol(optarg, &p, 10); + if (p == optarg || *p != '\0') { + error("Timeout value \"%s\" is not a number", + optarg); + /* NOTREACHED */ + } + if (longarg < 0) { + error("Timeout value %ld is negative", longarg); + /* NOTREACHED */ + } + if (longarg > INT_MAX) { + error("Timeout value %ld is too large (> %d)", + longarg, INT_MAX); + /* NOTREACHED */ + } + timeout = (int)longarg; + break; + + default: + usage(); + /* NOTREACHED */ + } + } + + if (device == NULL) { + if (pcap_findalldevs(&devlist, ebuf) == -1) + error("%s", ebuf); + if (devlist == NULL) + error("no interfaces available for capture"); + device = strdup(devlist->name); + pcap_freealldevs(devlist); + } + *ebuf = '\0'; + pd = pcap_create(device, ebuf); + if (pd == NULL) + error("%s", ebuf); + status = pcap_set_snaplen(pd, 65535); + if (status != 0) + error("%s: pcap_set_snaplen failed: %s", + device, pcap_statustostr(status)); + if (immediate) { + status = pcap_set_immediate_mode(pd, 1); + if (status != 0) + error("%s: pcap_set_immediate_mode failed: %s", + device, pcap_statustostr(status)); + } + status = pcap_set_timeout(pd, timeout); + if (status != 0) + error("%s: pcap_set_timeout 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)); + } + 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, nonblock, 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); + pcap_freecode(&fcode); + free(cmdbuf); + 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 [ -mn ] [ -i interface ] [ -t timeout] [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/testprogs/filtertest.c b/testprogs/filtertest.c new file mode 100644 index 00000000..380cb73e --- /dev/null +++ b/testprogs/filtertest.c @@ -0,0 +1,341 @@ +/* + * 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. + */ + +#include "varattrs.h" + +#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"; +#endif + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <pcap.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#ifdef _WIN32 + #include "getopt.h" + #include "unix.h" +#else + #include <unistd.h> +#endif +#include <fcntl.h> +#include <errno.h> +#ifdef _WIN32 + #include <winsock2.h> + #include <ws2tcpip.h> +#else + #include <sys/socket.h> + #include <arpa/inet.h> +#endif +#include <sys/types.h> +#include <sys/stat.h> + +#include "pcap/funcattrs.h" + +static char *program_name; + +/* Forwards */ +static void PCAP_NORETURN usage(void); +static void PCAP_NORETURN error(const char *, ...) PCAP_PRINTFLIKE(1, 2); +static void warn(const char *, ...) PCAP_PRINTFLIKE(1, 2); + +#ifdef BDEBUG +int dflag; +#endif + +/* + * 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 */ +} + +/* VARARGS */ +static void +warn(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; +} + +int +main(int argc, char **argv) +{ + char *cp; + int op; +#ifndef BDEBUG + int dflag; +#endif + char *infile; + int Oflag; + long snaplen; + char *p; + int dlt; + int have_fcode = 0; + bpf_u_int32 netmask = PCAP_NETMASK_UNKNOWN; + char *cmdbuf; + pcap_t *pd; + struct bpf_program fcode; + +#ifdef _WIN32 + if (pcap_wsockinit() != 0) + return 1; +#endif /* _WIN32 */ + +#ifndef BDEBUG + dflag = 1; +#else + /* if optimizer debugging is enabled, output DOT graph + * `dflag=4' is equivalent to -dddd to follow -d/-dd/-ddd + * convention in tcpdump command line + */ + dflag = 4; +#endif + 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': { + bpf_u_int32 addr; + + switch (inet_pton(AF_INET, optarg, &addr)) { + + case 0: + error("invalid netmask %s", optarg); + break; + + case -1: + error("invalid netmask %s: %s", optarg, + pcap_strerror(errno)); + break; + + case 1: + netmask = addr; + break; + } + 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) { + dlt = (int)strtol(argv[optind], &p, 10); + if (p == argv[optind] || *p != '\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)); + + have_fcode = 1; + if (!bpf_validate(fcode.bf_insns, fcode.bf_len)) + warn("Filter doesn't pass validation"); + +#ifdef BDEBUG + if (cmdbuf != NULL) { + // replace line feed with space + for (cp = cmdbuf; *cp != '\0'; ++cp) { + if (*cp == '\r' || *cp == '\n') { + *cp = ' '; + } + } + // only show machine code if BDEBUG defined, since dflag > 3 + printf("machine codes for filter: %s\n", cmdbuf); + } else + printf("machine codes for empty filter:\n"); +#endif + + bpf_dump(&fcode, dflag); + free(cmdbuf); + if (have_fcode) + pcap_freecode (&fcode); + 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/testprogs/findalldevstest.c b/testprogs/findalldevstest.c new file mode 100644 index 00000000..6a221f25 --- /dev/null +++ b/testprogs/findalldevstest.c @@ -0,0 +1,272 @@ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#ifdef _WIN32 + #include <winsock2.h> + #include <ws2tcpip.h> + #include <windows.h> +#else + #include <sys/socket.h> + #include <netinet/in.h> + #include <arpa/inet.h> + #include <netdb.h> + #include <unistd.h> +#endif + +#include <pcap.h> + +#include "pcap/funcattrs.h" + +static int ifprint(pcap_if_t *d); +static char *iptos(bpf_u_int32 in); + +#ifdef _WIN32 +#include "portability.h" + +/* + * Generate a string for a Win32-specific error (i.e. an error generated when + * calling a Win32 API). + * For errors occurred during standard C calls, we still use pcap_strerror() + */ +#define ERRBUF_SIZE 1024 +static const char * +win32_strerror(DWORD error) +{ + static char errbuf[ERRBUF_SIZE+1]; + size_t errlen; + + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, 0, errbuf, + ERRBUF_SIZE, NULL); + + /* + * "FormatMessage()" "helpfully" sticks CR/LF at the end of the + * message. Get rid of it. + */ + errlen = strlen(errbuf); + if (errlen >= 2) { + errbuf[errlen - 1] = '\0'; + errbuf[errlen - 2] = '\0'; + errlen -= 2; + } + return errbuf; +} + +static char * +getpass(const char *prompt) +{ + HANDLE console_handle = GetStdHandle(STD_INPUT_HANDLE); + DWORD console_mode, save_console_mode; + static char password[128+1]; + char *p; + + fprintf(stderr, "%s", prompt); + + /* + * Turn off echoing. + */ + if (!GetConsoleMode(console_handle, &console_mode)) { + fprintf(stderr, "Can't get console mode: %s\n", + win32_strerror(GetLastError())); + exit(1); + } + save_console_mode = console_mode; + console_mode &= ~ENABLE_ECHO_INPUT; + if (!SetConsoleMode(console_handle, console_mode)) { + fprintf(stderr, "Can't set console mode: %s\n", + win32_strerror(GetLastError())); + exit(1); + } + if (fgets(password, sizeof password, stdin) == NULL) { + fprintf(stderr, "\n"); + SetConsoleMode(console_handle, save_console_mode); + exit(1); + } + fprintf(stderr, "\n"); + SetConsoleMode(console_handle, save_console_mode); + p = strchr(password, '\n'); + if (p != NULL) + *p = '\0'; + return password; +} +#endif + +int main(int argc, char **argv) +{ + pcap_if_t *alldevs; + pcap_if_t *d; + bpf_u_int32 net, mask; + int exit_status = 0; + char errbuf[PCAP_ERRBUF_SIZE+1]; +#ifdef ENABLE_REMOTE + struct pcap_rmtauth auth; + char username[128+1]; + char *p; + char *password; +#endif + +#ifdef ENABLE_REMOTE + if (argc >= 2) + { + if (pcap_findalldevs_ex(argv[1], NULL, &alldevs, errbuf) == -1) + { + /* + * OK, try it with a user name and password. + */ + fprintf(stderr, "User name: "); + if (fgets(username, sizeof username, stdin) == NULL) + exit(1); + p = strchr(username, '\n'); + if (p != NULL) + *p = '\0'; + password = getpass("Password: "); + auth.type = RPCAP_RMTAUTH_PWD; + auth.username = username; + auth.password = password; + if (pcap_findalldevs_ex(argv[1], &auth, &alldevs, errbuf) == -1) + { + fprintf(stderr,"Error in pcap_findalldevs: %s\n",errbuf); + exit(1); + } + } + } + else +#endif + { + if (pcap_findalldevs(&alldevs, errbuf) == -1) + { + fprintf(stderr,"Error in pcap_findalldevs: %s\n",errbuf); + exit(1); + } + } + for(d=alldevs;d;d=d->next) + { + if (!ifprint(d)) + exit_status = 2; + } + + if (alldevs != NULL) + { + if (pcap_lookupnet(alldevs->name, &net, &mask, errbuf) < 0) + { + fprintf(stderr,"Error in pcap_lookupnet: %s\n",errbuf); + exit_status = 2; + } + else + { + printf("Preferred device is on network: %s/%s\n",iptos(net), iptos(mask)); + } + } + + pcap_freealldevs(alldevs); + exit(exit_status); +} + +static int ifprint(pcap_if_t *d) +{ + pcap_addr_t *a; + char ipv4_buf[INET_ADDRSTRLEN]; + char ipv6_buf[INET6_ADDRSTRLEN]; + const char *sep; + int status = 1; /* success */ + + printf("%s\n",d->name); + if (d->description) + printf("\tDescription: %s\n",d->description); + printf("\tFlags: "); + sep = ""; + if (d->flags & PCAP_IF_UP) { + printf("%sUP", sep); + sep = ", "; + } + if (d->flags & PCAP_IF_RUNNING) { + printf("%sRUNNING", sep); + sep = ", "; + } + if (d->flags & PCAP_IF_LOOPBACK) { + printf("%sLOOPBACK", sep); + sep = ", "; + } + printf("\n"); + + for(a=d->addresses;a;a=a->next) { + if (a->addr != NULL) + switch(a->addr->sa_family) { + case AF_INET: + printf("\tAddress Family: AF_INET\n"); + if (a->addr) + printf("\t\tAddress: %s\n", + inet_ntop(AF_INET, + &((struct sockaddr_in *)(a->addr))->sin_addr, + ipv4_buf, sizeof ipv4_buf)); + if (a->netmask) + printf("\t\tNetmask: %s\n", + inet_ntop(AF_INET, + &((struct sockaddr_in *)(a->netmask))->sin_addr, + ipv4_buf, sizeof ipv4_buf)); + if (a->broadaddr) + printf("\t\tBroadcast Address: %s\n", + inet_ntop(AF_INET, + &((struct sockaddr_in *)(a->broadaddr))->sin_addr, + ipv4_buf, sizeof ipv4_buf)); + if (a->dstaddr) + printf("\t\tDestination Address: %s\n", + inet_ntop(AF_INET, + &((struct sockaddr_in *)(a->dstaddr))->sin_addr, + ipv4_buf, sizeof ipv4_buf)); + 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, + ipv6_buf, sizeof ipv6_buf)); + if (a->netmask) + printf("\t\tNetmask: %s\n", + inet_ntop(AF_INET6, + ((struct sockaddr_in6 *)(a->netmask))->sin6_addr.s6_addr, + ipv6_buf, sizeof ipv6_buf)); + if (a->broadaddr) + printf("\t\tBroadcast Address: %s\n", + inet_ntop(AF_INET6, + ((struct sockaddr_in6 *)(a->broadaddr))->sin6_addr.s6_addr, + ipv6_buf, sizeof ipv6_buf)); + if (a->dstaddr) + printf("\t\tDestination Address: %s\n", + inet_ntop(AF_INET6, + ((struct sockaddr_in6 *)(a->dstaddr))->sin6_addr.s6_addr, + ipv6_buf, sizeof ipv6_buf)); + break; +#endif + default: + printf("\tAddress Family: Unknown (%d)\n", a->addr->sa_family); + break; + } + else + { + fprintf(stderr, "\tWarning: a->addr is NULL, skipping this address.\n"); + status = 0; + } + } + printf("\n"); + return status; +} + +/* 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/testprogs/opentest.c b/testprogs/opentest.c new file mode 100644 index 00000000..bad38eb0 --- /dev/null +++ b/testprogs/opentest.c @@ -0,0 +1,236 @@ +/* + * 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. + */ + +#include "varattrs.h" + +#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"; +#endif + +#include <pcap.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#ifdef _WIN32 + #include "getopt.h" +#else + #include <unistd.h> +#endif +#include <errno.h> + +#include "pcap/funcattrs.h" + +#ifdef _WIN32 + #include "portability.h" +#endif + +#define MAXIMUM_SNAPLEN 65535 + +static char *program_name; + +/* Forwards */ +static void PCAP_NORETURN usage(void); +static void PCAP_NORETURN error(const char *, ...) PCAP_PRINTFLIKE(1, 2); +static void warning(const char *, ...) PCAP_PRINTFLIKE(1, 2); + +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_if_t *devlist; + 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 (device == NULL) { + if (pcap_findalldevs(&devlist, ebuf) == -1) + error("%s", ebuf); + if (devlist == NULL) + error("no interfaces available for capture"); + device = strdup(devlist->name); + pcap_freealldevs(devlist); + } + if (useactivate) { + pd = pcap_create(device, ebuf); + if (pd == NULL) + error("%s: pcap_create failed: %s", device, 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 + printf("%s opened successfully\n", device); + } else { + *ebuf = '\0'; + pd = pcap_open_live(device, 65535, 0, 1000, ebuf); + if (pd == NULL) + error("%s", ebuf); + else if (*ebuf) + warning("%s", ebuf); + else + printf("%s opened successfully\n", device); + } + 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/testprogs/pcap_compile_test.c b/testprogs/pcap_compile_test.c new file mode 100644 index 00000000..924ec732 --- /dev/null +++ b/testprogs/pcap_compile_test.c @@ -0,0 +1,11 @@ + pcap = pcap_open_dead(link, snaplen); + /* todo: hook together argv to a single string */ + prog = argv[0]; + if (pcap_compile(pcap, &p, prog, optimize, 0) < 0) { + fprintf(stderr, pcap_geterr(pcap)); + exit(1); + } + bpf_dump(&p, option); + pcap_freecode(&p); + pcap_close(pcap); + diff --git a/testprogs/reactivatetest.c b/testprogs/reactivatetest.c new file mode 100644 index 00000000..42b2c3b8 --- /dev/null +++ b/testprogs/reactivatetest.c @@ -0,0 +1,88 @@ +/* + * 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. + */ + +#include "varattrs.h" + +#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"; +#endif + +#include <pcap.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> + +#include "pcap/funcattrs.h" + +/* 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/testprogs/selpolltest.c b/testprogs/selpolltest.c new file mode 100644 index 00000000..5d47b3d5 --- /dev/null +++ b/testprogs/selpolltest.c @@ -0,0 +1,443 @@ +/* + * 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. + */ + +#include "varattrs.h" + +#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"; +#endif + +/* + * Tests how select() and poll() behave on the selectable file descriptor + * for a pcap_t. + * + * This would be significantly different on Windows, as it'd test + * how WaitForMultipleObjects() would work on the event handle for a + * pcap_t. + */ +#include <pcap.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include <unistd.h> +#include <errno.h> +#include <sys/types.h> +#ifdef HAVE_SYS_SELECT_H +#include <sys/select.h> +#else +#include <sys/time.h> /* older UN*Xes */ +#endif +#include <poll.h> + +#include "pcap/funcattrs.h" + +char *program_name; + +/* Forwards */ +static void countme(u_char *, const struct pcap_pkthdr *, const u_char *); +static void PCAP_NORETURN usage(void); +static void PCAP_NORETURN error(const char *, ...) PCAP_PRINTFLIKE(1, 2); +static void warning(const char *, ...) PCAP_PRINTFLIKE(1, 2); +static char *copy_argv(char **); + +static pcap_t *pd; + +int +main(int argc, char **argv) +{ + register int op; + bpf_u_int32 localnet, netmask; + register char *cp, *cmdbuf, *device; + int doselect, dopoll, dotimeout, dononblock; + char *mechanism; + struct bpf_program fcode; + char ebuf[PCAP_ERRBUF_SIZE]; + pcap_if_t *devlist; + int selectable_fd; + struct timeval *required_timeout; + int status; + int packet_count; + + device = NULL; + doselect = 0; + dopoll = 0; + mechanism = NULL; + 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; + mechanism = "select() and pcap_dispatch()"; + break; + + case 'p': + dopoll = 1; + mechanism = "poll() and pcap_dispatch()"; + 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) { + if (pcap_findalldevs(&devlist, ebuf) == -1) + error("%s", ebuf); + if (devlist == NULL) + error("no interfaces available for capture"); + device = strdup(devlist->name); + pcap_freealldevs(devlist); + } + *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 (doselect || dopoll) { + /* + * We need either an FD on which to do select()/poll() + * or, if there isn't one, a timeout to use in select()/ + * poll(). + */ + selectable_fd = pcap_get_selectable_fd(pd); + if (selectable_fd == -1) { + printf("Listening on %s, using %s, with a timeout\n", + device, mechanism); + required_timeout = pcap_get_required_select_timeout(pd); + if (required_timeout == NULL) + error("select()/poll() isn't supported on %s, even with a timeout", + device); + + /* + * As we won't be notified by select() or poll() + * that a read can be done, we'll have to periodically + * try reading from the device every time the required + * timeout expires, and we don't want those attempts + * to block if nothing has arrived in that interval, + * so we want to force non-blocking mode. + */ + dononblock = 1; + } else { + printf("Listening on %s, using %s\n", device, + mechanism); + required_timeout = NULL; + } + } else + printf("Listening on %s, using pcap_dispatch()\n", device); + + if (dononblock) { + if (pcap_setnonblock(pd, 1, ebuf) == -1) + error("pcap_setnonblock failed: %s", ebuf); + } + if (doselect) { + for (;;) { + fd_set setread, setexcept; + struct timeval seltimeout; + + FD_ZERO(&setread); + if (selectable_fd != -1) { + FD_SET(selectable_fd, &setread); + FD_ZERO(&setexcept); + FD_SET(selectable_fd, &setexcept); + } + if (dotimeout) { + seltimeout.tv_sec = 0; + if (required_timeout != NULL && + required_timeout->tv_usec < 1000) + seltimeout.tv_usec = required_timeout->tv_usec; + else + seltimeout.tv_usec = 1000; + status = select(selectable_fd + 1, &setread, + NULL, &setexcept, &seltimeout); + } else if (required_timeout != NULL) { + seltimeout = *required_timeout; + status = select(selectable_fd + 1, &setread, + NULL, &setexcept, &seltimeout); + } else { + status = select((selectable_fd == -1) ? + 0 : selectable_fd + 1, &setread, + NULL, &setexcept, NULL); + } + if (status == -1) { + printf("Select returns error (%s)\n", + strerror(errno)); + } else { + if (selectable_fd == -1) { + if (status != 0) + printf("Select returned a descriptor\n"); + } 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; + /* + * Don't report this if we're using a + * required timeout and we got no packets, + * because that could be a very short timeout, + * and we don't want to spam the user with + * a ton of "no packets" reports. + */ + if (status != 0 || packet_count != 0 || + required_timeout != NULL) { + 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 if (required_timeout != NULL && + required_timeout->tv_usec >= 1000) + polltimeout = required_timeout->tv_usec/1000; + else + polltimeout = -1; + status = poll(&fd, (selectable_fd == -1) ? 0 : 1, polltimeout); + if (status == -1) { + printf("Poll returns error (%s)\n", + strerror(errno)); + } else { + if (selectable_fd == -1) { + if (status != 0) + printf("Poll returned a descriptor\n"); + } 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; + /* + * Don't report this if we're using a + * required timeout and we got no packets, + * because that could be a very short timeout, + * and we don't want to spam the user with + * a ton of "no packets" reports. + */ + if (status != 0 || packet_count != 0 || + required_timeout != NULL) { + 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/testprogs/threadsignaltest.c b/testprogs/threadsignaltest.c new file mode 100644 index 00000000..bd46f936 --- /dev/null +++ b/testprogs/threadsignaltest.c @@ -0,0 +1,393 @@ +/* + * 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. + */ + +#include "varattrs.h" + +#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"; +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include <limits.h> +#ifdef _WIN32 + #include <winsock2.h> + #include <windows.h> + + #define THREAD_HANDLE HANDLE + #define THREAD_FUNC_ARG_TYPE LPVOID + #define THREAD_FUNC_RETURN_TYPE DWORD __stdcall + + #include "getopt.h" +#else + #include <pthread.h> + #include <signal.h> + #include <unistd.h> + + #define THREAD_HANDLE pthread_t + #define THREAD_FUNC_ARG_TYPE void * + #define THREAD_FUNC_RETURN_TYPE void * +#endif +#include <errno.h> +#include <sys/types.h> + +#include <pcap.h> + +#include "pcap/funcattrs.h" + +#ifdef _WIN32 + #include "portability.h" +#endif + +static char *program_name; + +/* Forwards */ +static void countme(u_char *, const struct pcap_pkthdr *, const u_char *); +static void PCAP_NORETURN usage(void); +static void PCAP_NORETURN error(const char *, ...) PCAP_PRINTFLIKE(1, 2); +static void warning(const char *, ...) PCAP_PRINTFLIKE(1, 2); +static char *copy_argv(char **); + +static pcap_t *pd; + +#ifdef _WIN32 +/* + * Generate a string for a Win32-specific error (i.e. an error generated when + * calling a Win32 API). + * For errors occurred during standard C calls, we still use pcap_strerror() + */ +#define ERRBUF_SIZE 1024 +static const char * +win32_strerror(DWORD error) +{ + static char errbuf[ERRBUF_SIZE+1]; + size_t errlen; + + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, 0, errbuf, + ERRBUF_SIZE, NULL); + + /* + * "FormatMessage()" "helpfully" sticks CR/LF at the end of the + * message. Get rid of it. + */ + errlen = strlen(errbuf); + if (errlen >= 2) { + errbuf[errlen - 1] = '\0'; + errbuf[errlen - 2] = '\0'; + errlen -= 2; + } + return errbuf; +} +#else +static void +catch_sigusr1(int sig _U_) +{ + printf("Got SIGUSR1\n"); +} +#endif + +static void +sleep_secs(int secs) +{ +#ifdef _WIN32 + Sleep(secs*1000); +#else + unsigned secs_remaining; + + if (secs <= 0) + return; + secs_remaining = secs; + while (secs_remaining != 0) + secs_remaining = sleep(secs_remaining); +#endif +} + +static THREAD_FUNC_RETURN_TYPE +capture_thread_func(THREAD_FUNC_ARG_TYPE arg) +{ + char *device = arg; + int packet_count; + int status; +#ifndef _WIN32 + struct sigaction action; + sigset_t mask; +#endif + +#ifndef _WIN32 + sigemptyset(&mask); + action.sa_handler = catch_sigusr1; + action.sa_mask = mask; + action.sa_flags = 0; + if (sigaction(SIGUSR1, &action, NULL) == -1) + error("Can't catch SIGUSR1: %s", strerror(errno)); +#endif + + 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); + } else + printf("No packets seen by pcap_dispatch\n"); + } + 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'); + printf("Loop got broken\n"); + } + (void)fflush(stdout); + if (status == -1) { + /* + * Error. Report it. + */ + (void)fprintf(stderr, "%s: pcap_loop: %s\n", + program_name, pcap_geterr(pd)); + } + return 0; +} + +int +main(int argc, char **argv) +{ + register int op; + register char *cp, *cmdbuf, *device; + int immediate = 0; + pcap_if_t *devlist; + bpf_u_int32 localnet, netmask; + struct bpf_program fcode; + char ebuf[PCAP_ERRBUF_SIZE]; + int status; + THREAD_HANDLE capture_thread; +#ifndef _WIN32 + void *retval; +#endif + + 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) { + if (pcap_findalldevs(&devlist, ebuf) == -1) + error("%s", ebuf); + if (devlist == NULL) + error("no interfaces available for capture"); + device = strdup(devlist->name); + pcap_freealldevs(devlist); + } + *ebuf = '\0'; + pd = pcap_create(device, ebuf); + if (pd == NULL) + error("%s", ebuf); + status = pcap_set_snaplen(pd, 65535); + if (status != 0) + error("%s: pcap_set_snaplen failed: %s", + device, pcap_statustostr(status)); + if (immediate) { + status = pcap_set_immediate_mode(pd, 1); + if (status != 0) + error("%s: pcap_set_immediate_mode failed: %s", + device, pcap_statustostr(status)); + } + status = pcap_set_timeout(pd, 5*60*1000); + if (status != 0) + error("%s: pcap_set_timeout 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)); + } + 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)); + +#ifdef _WIN32 + capture_thread = CreateThread(NULL, 0, capture_thread_func, device, + 0, NULL); + if (capture_thread == NULL) + error("Can't create capture thread: %s", + win32_strerror(GetLastError())); +#else + status = pthread_create(&capture_thread, NULL, capture_thread_func, + device); + if (status != 0) + error("Can't create capture thread: %s", strerror(status)); +#endif + sleep_secs(60); + pcap_breakloop(pd); +#ifdef _WIN32 + printf("Setting event\n"); + if (!SetEvent(pcap_getevent(pd))) + error("Can't set event for pcap_t: %s", + win32_strerror(GetLastError())); + if (WaitForSingleObject(capture_thread, INFINITE) == WAIT_FAILED) + error("Wait for thread termination failed: %s", + win32_strerror(GetLastError())); + CloseHandle(capture_thread); +#else + printf("Sending SIGUSR1\n"); + status = pthread_kill(capture_thread, SIGUSR1); + if (status != 0) + warning("Can't interrupt capture thread: %s", strerror(status)); + status = pthread_join(capture_thread, &retval); + if (status != 0) + error("Wait for thread termination failed: %s", + strerror(status)); +#endif + + pcap_close(pd); + pcap_freecode(&fcode); + 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 [ -m ] [ -i interface ] [ -t timeout] [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/testprogs/unix.h b/testprogs/unix.h new file mode 100644 index 00000000..68ef4cb9 --- /dev/null +++ b/testprogs/unix.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 1994, 1995, 1996 + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + */ + +#ifndef unix_h +#define unix_h + +/* + * Definitions to make MSVC C runtime library structures and functions + * look like the UNIX structures and functions they are intended to + * resemble. + */ +#ifdef _MSC_VER + #define stat _stat + #define fstat _fstat + + #define open _open + #define O_RDONLY _O_RDONLY + #define O_WRONLY _O_WRONLY + #define O_RDWR _O_RDWR + #define O_BINARY _O_BINARY + #define O_CREAT _O_CREAT + #define O_TRUNC _O_TRUNC + #define read _read + #define write _write + #define close _close +#endif + +#endif diff --git a/testprogs/valgrindtest.c b/testprogs/valgrindtest.c new file mode 100644 index 00000000..c2e3d790 --- /dev/null +++ b/testprogs/valgrindtest.c @@ -0,0 +1,427 @@ +/* + * 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. + */ + +#include "varattrs.h" + +/* + * This doesn't actually test libpcap itself; it tests whether + * valgrind properly handles the APIs libpcap uses. If it doesn't, + * we end up getting patches submitted to "fix" references that + * valgrind claims are being made to uninitialized data, when, in + * fact, the OS isn't making any such references - or we get + * valgrind *not* detecting *actual* incorrect references. + * + * Both BPF and Linux socket filters aren't handled correctly + * by some versions of valgrind. See valgrind bug 318203 for + * Linux: + * + * https://bugs.kde.org/show_bug.cgi?id=318203 + * + * and valgrind bug 312989 for macOS: + * + * https://bugs.kde.org/show_bug.cgi?id=312989 + * + * The fixes for both of those are checked into the official valgrind + * repository. + * + * The unofficial FreeBSD port has similar issues to the official macOS + * port, for similar reasons. + */ +#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"; +#endif + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <arpa/inet.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include "pcap/funcattrs.h" + +#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(_AIX) || defined(sun) +/* OS with BPF - use BPF */ +#define USE_BPF +#elif defined(linux) +/* Linux - use socket filters */ +#define USE_SOCKET_FILTERS +#else +#error "Unknown platform or platform that doesn't support Valgrind" +#endif + +#if defined(USE_BPF) + +#include <sys/ioctl.h> +#include <net/bpf.h> + +/* + * Make "pcap.h" not include "pcap/bpf.h"; we are going to include the + * native OS version, as we're going to be doing our own ioctls to + * make sure that, in the uninitialized-data tests, the filters aren't + * checked by libpcap before being handed to BPF. + */ +#define PCAP_DONT_INCLUDE_PCAP_BPF_H + +#elif defined(USE_SOCKET_FILTERS) + +#include <sys/socket.h> +#include <linux/types.h> +#include <linux/filter.h> + +#endif + +#include <pcap.h> + +static char *program_name; + +/* Forwards */ +static void PCAP_NORETURN usage(void); +static void PCAP_NORETURN error(const char *, ...) PCAP_PRINTFLIKE(1, 2); +static void warning(const char *, ...) PCAP_PRINTFLIKE(1, 2); + +/* + * 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 */ +} + +/* 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; +} + +#define INSN_COUNT 17 + +int +main(int argc, char **argv) +{ + char *cp, *device; + int op; + int dorfmon, useactivate; + char ebuf[PCAP_ERRBUF_SIZE]; + char *infile; + char *cmdbuf; + pcap_if_t *devlist; + pcap_t *pd; + int status = 0; + int pcap_fd; +#if defined(USE_BPF) + struct bpf_program bad_fcode; + struct bpf_insn uninitialized[INSN_COUNT]; +#elif defined(USE_SOCKET_FILTERS) + struct sock_fprog bad_fcode; + struct sock_filter uninitialized[INSN_COUNT]; +#endif + struct bpf_program fcode; + + device = NULL; + dorfmon = 0; + useactivate = 0; + infile = NULL; + + if ((cp = strrchr(argv[0], '/')) != NULL) + program_name = cp + 1; + else + program_name = argv[0]; + + opterr = 0; + while ((op = getopt(argc, argv, "aF:i:I")) != -1) { + switch (op) { + + case 'a': + useactivate = 1; + break; + + case 'F': + infile = optarg; + break; + + case 'i': + device = optarg; + break; + + case 'I': + dorfmon = 1; + useactivate = 1; /* required for rfmon */ + break; + + default: + usage(); + /* NOTREACHED */ + } + } + + if (device == NULL) { + /* + * No interface specified; get whatever pcap_lookupdev() + * finds. + */ + if (pcap_findalldevs(&devlist, ebuf) == -1) + error("%s", ebuf); + if (devlist == NULL) + error("no interfaces available for capture"); + device = strdup(devlist->name); + pcap_freealldevs(devlist); + } + + if (infile != NULL) { + /* + * Filter specified with "-F" and a file containing + * a filter. + */ + cmdbuf = read_infile(infile); + } else { + if (optind < argc) { + /* + * Filter specified with arguments on the + * command line. + */ + cmdbuf = copy_argv(&argv[optind+1]); + } else { + /* + * No filter specified; use an empty string, which + * compiles to an "accept all" filter. + */ + cmdbuf = ""; + } + } + + if (useactivate) { + pd = pcap_create(device, ebuf); + if (pd == NULL) + error("%s: pcap_create() failed: %s", device, ebuf); + status = pcap_set_snaplen(pd, 65535); + if (status != 0) + error("%s: pcap_set_snaplen failed: %s", + device, pcap_statustostr(status)); + 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)); + 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, 1, 1000, ebuf); + if (pd == NULL) + error("%s", ebuf); + else if (*ebuf) + warning("%s", ebuf); + } + + pcap_fd = pcap_fileno(pd); + + /* + * Try setting a filter with an uninitialized bpf_program + * structure. This should cause valgrind to report a + * problem. + * + * We don't check for errors, because it could get an + * error due to a bad pointer or count. + */ +#if defined(USE_BPF) + ioctl(pcap_fd, BIOCSETF, &bad_fcode); +#elif defined(USE_SOCKET_FILTERS) + setsockopt(pcap_fd, SOL_SOCKET, SO_ATTACH_FILTER, &bad_fcode, + sizeof(bad_fcode)); +#endif + + /* + * Try setting a filter with an initialized bpf_program + * structure that points to an uninitialized program. + * That should also cause valgrind to report a problem. + * + * We don't check for errors, because it could get an + * error due to a bad pointer or count. + */ +#if defined(USE_BPF) + bad_fcode.bf_len = INSN_COUNT; + bad_fcode.bf_insns = uninitialized; + ioctl(pcap_fd, BIOCSETF, &bad_fcode); +#elif defined(USE_SOCKET_FILTERS) + bad_fcode.len = INSN_COUNT; + bad_fcode.filter = uninitialized; + setsockopt(pcap_fd, SOL_SOCKET, SO_ATTACH_FILTER, &bad_fcode, + sizeof(bad_fcode)); +#endif + + /* + * Now compile a filter and set the filter with that. + * That should *not* cause valgrind to report a + * problem. + */ + if (pcap_compile(pd, &fcode, cmdbuf, 1, 0) < 0) + error("can't compile filter: %s", pcap_geterr(pd)); + if (pcap_setfilter(pd, &fcode) < 0) + error("can't set filter: %s", pcap_geterr(pd)); + + pcap_close(pd); + exit(status < 0 ? 1 : 0); +} + +static void +usage(void) +{ + (void)fprintf(stderr, "%s, with %s\n", program_name, + pcap_lib_version()); + (void)fprintf(stderr, + "Usage: %s [-aI] [ -F file ] [ -I interface ] [ expression ]\n", + program_name); + exit(1); +} diff --git a/testprogs/visopts.py b/testprogs/visopts.py new file mode 100755 index 00000000..ab4f396d --- /dev/null +++ b/testprogs/visopts.py @@ -0,0 +1,309 @@ +#!/usr/bin/env python + +""" +This program parse the output from pcap_compile() to visualize the CFG after +each optimize phase. + +Usage guide: +1. Enable optimizier debugging code when configure libpcap, + and build libpcap & filtertest + ./configure --enable-optimizer-dbg + make + make filtertest +2. Run filtertest to compile BPF expression, save to output a.txt + ./filtertest EN10MB host 192.168.1.1 > a.txt +3. Send a.txt to this program's standard input + cat a.txt | tests/visopts.py +4. Step 2&3 can be merged: + ./filtertest EN10MB host 192.168.1.1 | tests/visopts.py +5. The standard output is something like this: + generated files under directory: /tmp/visopts-W9ekBw + the directory will be removed when this programs finished. + open this link: http://localhost:39062/expr1.html +6. Using open link at the 3rd line `http://localhost:39062/expr1.html' + +Note: +1. CFG graph is translated to SVG document, expr1.html embeded them as external + document. If you open expr1.html as local file using file:// protocol, some + browsers will deny such requests so the web pages will not shown properly. + For chrome, you can run it using following command to avoid this: + chromium --disable-web-security + That's why this program start a localhost http server. +2. expr1.html use jquery from http://ajax.googleapis.com, so you need internet + access to show the web page. +""" + +import sys, os +import string +import subprocess +import json + +html_template = string.Template(""" +<html> + <head> + <title>BPF compiler optimization phases for $expr </title> + <style type="text/css"> + .hc { + /* half width container */ + display: inline-block; + float: left; + width: 50%; + } + </style> + + <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"/></script> + <!--script type="text/javascript" src="./jquery.min.js"/></script--> + <script type="text/javascript"> + var expr = '$expr'; + var exprid = 1; + var gcount = $gcount; + var logs = JSON.parse('$logs'); + logs[gcount] = ""; + + var leftsvg = null; + var rightsvg = null; + + function gurl(index) { + index += 1; + if (index < 10) + s = "00" + index; + else if (index < 100) + s = "0" + index; + else + s = "" + index; + return "./expr" + exprid + "_g" + s + ".svg" + } + + function annotate_svgs() { + if (!leftsvg || !rightsvg) return; + + $$.each([$$(leftsvg), $$(rightsvg)], function() { + $$(this).find("[id|='block'][opacity]").each(function() { + $$(this).removeAttr('opacity'); + }); + }); + + $$(leftsvg).find("[id|='block']").each(function() { + var has = $$(rightsvg).find("#" + this.id).length != 0; + if (!has) $$(this).attr("opacity", "0.4"); + else { + $$(this).click(function() { + var target = $$(rightsvg).find("#" + this.id); + var offset = $$("#rightsvgc").offset().top + target.position().top; + window.scrollTo(0, offset); + target.focus(); + }); + } + }); + $$(rightsvg).find("[id|='block']").each(function() { + var has = $$(leftsvg).find("#" + this.id).length != 0; + if (!has) $$(this).attr("opacity", "0.4"); + else { + $$(this).click(function() { + var target = $$(leftsvg).find("#" + this.id); + var offset = $$("#leftsvgc").offset().top + target.position().top; + window.scrollTo(0, offset); + target.focus(); + }); + } + }); + } + + function init_svgroot(svg) { + svg.setAttribute("width", "100%"); + svg.setAttribute("height", "100%"); + } + function wait_leftsvg() { + if (leftsvg) return; + var doc = document.getElementById("leftsvgc").getSVGDocument(); + if (doc == null) { + setTimeout(wait_leftsvg, 500); + return; + } + leftsvg = doc.documentElement; + //console.log(leftsvg); + // initialize it + init_svgroot(leftsvg); + annotate_svgs(); + } + function wait_rightsvg() { + if (rightsvg) return; + var doc = document.getElementById("rightsvgc").getSVGDocument(); + if (doc == null) { + setTimeout(wait_rightsvg, 500); + return; + } + rightsvg = doc.documentElement; + //console.log(rightsvg); + // initialize it + init_svgroot(rightsvg); + annotate_svgs(); + } + function load_left(index) { + var url = gurl(index); + var frag = "<embed id='leftsvgc' type='image/svg+xml' pluginspage='http://www.adobe.com/svg/viewer/install/' src='" + url + "'/>"; + $$("#lsvg").html(frag); + $$("#lcomment").html(logs[index]); + $$("#lsvglink").attr("href", url); + leftsvg = null; + wait_leftsvg(); + } + function load_right(index) { + var url = gurl(index); + var frag = "<embed id='rightsvgc' type='image/svg+xml' pluginspage='http://www.adobe.com/svg/viewer/install/' src='" + url + "'/>"; + $$("#rsvg").html(frag); + $$("#rcomment").html(logs[index]); + $$("#rsvglink").attr("href", url); + rightsvg = null; + wait_rightsvg(); + } + + $$(document).ready(function() { + for (var i = 0; i < gcount; i++) { + var opt = "<option value='" + i + "'>loop" + i + " -- " + logs[i] + "</option>"; + $$("#lselect").append(opt); + $$("#rselect").append(opt); + } + var on_selected = function() { + var index = parseInt($$(this).children("option:selected").val()); + if (this.id == "lselect") + load_left(index); + else + load_right(index); + } + $$("#lselect").change(on_selected); + $$("#rselect").change(on_selected); + + $$("#backward").click(function() { + var index = parseInt($$("#lselect option:selected").val()); + if (index <= 0) return; + $$("#lselect").val(index - 1).change(); + $$("#rselect").val(index).change(); + }); + $$("#forward").click(function() { + var index = parseInt($$("#rselect option:selected").val()); + if (index >= gcount - 1) return; + $$("#lselect").val(index).change(); + $$("#rselect").val(index + 1).change(); + }); + + if (gcount >= 1) $$("#lselect").val(0).change(); + if (gcount >= 2) $$("#rselect").val(1).change(); + }); + </script> + </head> + <body style="width: 96%"> + <div> + <h1>$expr</h1> + <div style="text-align: center;"> + <button id="backward" type="button"><<</button> + + <button id="forward" type="button">>></button> + </div> + </div> + <br/> + <div style="clear: both;"> + <div class="hc lc"> + <select id="lselect"></select> + <a id="lsvglink" target="_blank">open this svg in browser</a> + <p id="lcomment"></p> + </div> + <div class="hc rc"> + <select id="rselect"></select> + <a id="rsvglink" target="_blank">open this svg in browser</a> + <p id="rcomment"></p> + </div> + </div> + <br/> + <div style="clear: both;"> + <div id="lsvg" class="hc lc"></div> + <div id="rsvg" class="hc rc"></div> + </div> + </body> +</html> +""") + +def write_html(expr, gcount, logs): + logs = map(lambda s: s.strip().replace("\n", "<br/>"), logs) + + global html_template + html = html_template.safe_substitute(expr=expr.encode("string-escape"), gcount=gcount, logs=json.dumps(logs).encode("string-escape")) + with file("expr1.html", "wt") as f: + f.write(html) + +def render_on_html(infile): + expr = None + gid = 1 + log = "" + dot = "" + indot = 0 + logs = [] + + for line in infile: + if line.startswith("machine codes for filter:"): + expr = line[len("machine codes for filter:"):].strip() + break + elif line.startswith("digraph BPF {"): + indot = 1 + dot = line + elif indot: + dot += line + if line.startswith("}"): + indot = 2 + else: + log += line + + if indot == 2: + p = subprocess.Popen(['dot', '-Tsvg'], stdin=subprocess.PIPE, stdout=subprocess.PIPE) + svg = p.communicate(dot)[0] + with file("expr1_g%03d.svg" % (gid), "wt") as f: + f.write(svg) + + logs.append(log) + gid += 1 + log = "" + dot = "" + indot = 0 + + if indot != 0: + #unterminated dot graph for expression + return False + if expr is None: + # BPF parser encounter error(s) + return False + write_html(expr, gid - 1, logs) + return True + +def run_httpd(): + import SimpleHTTPServer + import SocketServer + + class MySocketServer(SocketServer.TCPServer): + allow_reuse_address = True + Handler = SimpleHTTPServer.SimpleHTTPRequestHandler + httpd = MySocketServer(("localhost", 0), Handler) + print "open this link: http://localhost:%d/expr1.html" % (httpd.server_address[1]) + try: + httpd.serve_forever() + except KeyboardInterrupt as e: + pass + +def main(): + import tempfile + import atexit + import shutil + os.chdir(tempfile.mkdtemp(prefix="visopts-")) + atexit.register(shutil.rmtree, os.getcwd()) + print "generated files under directory: %s" % os.getcwd() + print " the directory will be removed when this programs finished." + + if not render_on_html(sys.stdin): + return 1 + run_httpd() + return 0 + +if __name__ == "__main__": + if '-h' in sys.argv or '--help' in sys.argv: + print __doc__ + exit(0) + exit(main()) |