pax_global_header00006660000000000000000000000064112014065110014501gustar00rootroot0000000000000052 comment=c105b8147ca0ff70268165633a2a9473cc7d3679 pcaputils-0.8/000077500000000000000000000000001120140651100133545ustar00rootroot00000000000000pcaputils-0.8/.gitignore000066400000000000000000000001041120140651100153370ustar00rootroot00000000000000*.d *.o src/pcapdump src/pcapip src/pcappick src/pcapuc util/util.a pcaputils-0.8/Makefile000066400000000000000000000016441120140651100150210ustar00rootroot00000000000000### Build flags for all targets CFLAGS ?= -O2 -ggdb -Wall CF_ALL = $(CFLAGS) -Wextra -std=gnu99 -I. LF_ALL = -rdynamic -Wl,--as-needed -Wl,-z,defs ### Build tools CC = gcc COMP = $(CC) $(CF_ALL) $(CF_TGT) -o $@ -c $< LINK = $(CC) $(LF_ALL) $(LF_TGT) -o $@ $^ $(LL_TGT) $(LL_ALL) COMPLINK = $(CC) $(CF_ALL) $(CF_TGT) $(LF_ALL) $(LF_TGT) -o $@ $< $(LL_TGT) $(LL_ALL) ARCH = $(AR) rcs $@ $^ MAKEDEP = @set -e; rm -f $@; $(CC) $(CF_ALL) $(CFG_TGT) -MM $(CPPFLAGS) $< > $@.$$$$; \ sed 's,.*:,$(patsubst %.d,%.o,$@) $@ : ,g' < $@.$$$$ > $@; \ rm -f $@.$$$$ DEBCHANGELOG = @sed -i \ -e 's/@@PKGNAME@@/$(PKGNAME)/' \ -e 's/@@PKGVER@@/$(PKGVER)/' \ -e 's/@@DEBFULLNAME@@/$(DEBFULLNAME)/' \ -e 's/@@DEBEMAIL@@/$(DEBEMAIL)/' \ -e 's/@@DATE@@/$(shell date -R)/' \ $(EXPORT)/debian/changelog ### Standard parts include Rules.mk pcaputils-0.8/Rules.mk000066400000000000000000000006571120140651100150070ustar00rootroot00000000000000# Standard stuff .SUFFIXES: .SUFFIXES: .c .o .d all: targets # Subdirectories dir := util include $(dir)/Rules.mk dir := src include $(dir)/Rules.mk # General directory independent rules %.o: %.c $(COMP) %: %.o $(LINK) %: %.c $(COMPLINK) %.d: %.c $(MAKEDEP) .PHONY: targets targets: bin lib .PHONY: bin bin: $(TGT_BIN) .PHONY: lib lib: $(TGT_LIB) .PHONY: clean clean: rm -f $(CLEAN) .SECONDARY: $(CLEAN) pcaputils-0.8/doc/000077500000000000000000000000001120140651100141215ustar00rootroot00000000000000pcaputils-0.8/doc/LICENSE000066400000000000000000000020451120140651100151270ustar00rootroot00000000000000Copyright (C) 2007 Robert S. Edmonds Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. pcaputils-0.8/doc/Makefile000066400000000000000000000002211120140651100155540ustar00rootroot00000000000000MAN = pcapdump.1 pcapip.1 pcappick.1 pcapuc.1 all: $(MAN) clean: rm -f $(MAN) %.1: %.docbook docbook2x-man --xinclude $< .PHONY: all clean pcaputils-0.8/doc/pcapdump.docbook000066400000000000000000000102151120140651100172730ustar00rootroot00000000000000 pcapdump 1 pcapdump dedicated packet capture utility pcapdump OPTIONS DESCRIPTION pcapdump captures packets from a network interface and writes them to a dumpfile. The filename argument given to will be formated by strftime(3). PROGRAM OPTIONS owner Set the output file's owning user to owner. group Set the output file's owning group to group. mode Set the output file's mode to mode, specified in octal. secs Dump file rotation interval in seconds. count Exit after capturing count packets. secs Exit after capturing during this amount of seconds. Only capture link, network, and transport headers; do not capture application-layer data. sample value Sample the packet stream by only dumping 1 in every sample value packets. Together with -S, sample the packets randomly, not systematically. pidfile Daemonize the process and write its PID to pidfile. config file File to read configuration variables from. Instead of passing configuration through the command line, a file can be used to specify values for the , , , , , , , , and options (not all need to be specified; defaults will be used otherwise). See /usr/share/doc/pcaputils/examples/pcapdump/eth0 for an example. pcaputils-0.8/doc/pcapip.docbook000066400000000000000000000022231120140651100167360ustar00rootroot00000000000000 pcapip 1 pcapip filter a pcap for IP addresses pcapip OPTIONS DESCRIPTION pcapip filters an input pcap file based on a file containing IP addresses to be matched. PROGRAM OPTIONS file File containing list of IP addresses, one per line. pcaputils-0.8/doc/pcapnet.docbook000066400000000000000000000027101120140651100171150ustar00rootroot00000000000000 PCAPNET OPTIONS interface Input interface to read packets from. pcap file Dump file to read packets from. pcap file Dump file to write filtered packets to. expression BPF expression which selects packets to be filtered. snaplen Capture snaplen bytes of data from each packet. Disable promiscuous mode sniffing. pcaputils-0.8/doc/pcappick.docbook000066400000000000000000000022331120140651100172550ustar00rootroot00000000000000 pcappick 1 pcappick pick specific frames out of a pcap file by number pcappick OPTIONS DESCRIPTION pcappick reads an input pcap file and picks a specific frame to output. PROGRAM OPTIONS number Frame number to pick. pcaputils-0.8/doc/pcapuc.docbook000066400000000000000000000037151120140651100167440ustar00rootroot00000000000000 pcapuc 1 pcapuc filter a pcap for IP addresses pcapuc OPTIONS DESCRIPTION pcapuc parses an input pcap file and prints unique IP addresses and the number of packets each IP address appeared in. Optionally, pcapuc can limit its output to addresses that only appear in the source address field of the IP header, addresses that only appear in the destination address field, or sets of IP addresses that appear in the source and destination address fields. PROGRAM OPTIONS count source IP addresses only count destination IP addresses only count pairs of IP addresses output only the number of unique IP addresses or IP address pairs pcaputils-0.8/src/000077500000000000000000000000001120140651100141435ustar00rootroot00000000000000pcaputils-0.8/src/Rules.mk000066400000000000000000000021011120140651100155600ustar00rootroot00000000000000# Standard things sp := $(sp).x dirstack_$(sp) := $(d) d := $(dir) # Local variables PKGNAME := pcaputils PKGVER := 0.7 CF_$(d) := -I$(d) LL_$(d) := util/util.a OBJS_$(d) := \ $(d)/pcapdump.o \ $(d)/pcapip.o \ $(d)/pcappick.o \ $(d)/pcapuc.o DEPS_$(d) := $(OBJS_$(d):%.o=%.d) TGTS_$(d) := \ $(d)/pcapdump \ $(d)/pcapip \ $(d)/pcappick \ $(d)/pcapuc TGT_BIN := $(TGT_BIN) $(TGTS_$(d)) CLEAN := $(CLEAN) $(TGTS_$(d)) $(OBJS_$(d)) $(DEPS_$(d)) # Local rules $(OBJS_$(d)): CF_TGT := $(CF_$(d)) $(d)/pcapdump: LL_TGT := -lpcap $(d)/pcapdump: $(d)/pcapdump.o $(LL_$(d)) $(LINK) $(d)/pcapip: LL_TGT := -lpcap -lJudy $(d)/pcapip: $(d)/pcapip.o $(LL_$(d)) $(LINK) $(d)/pcappick: LL_TGT := -lpcap $(d)/pcappick: $(d)/pcappick.o $(LL_$(d)) $(LINK) $(d)/pcapuc: LL_TGT := -lpcap -lJudy $(d)/pcapuc: $(d)/pcapuc.o $(LL_$(d)) $(LINK) .PHONY: export EXPORT = ../build/$(PKGNAME)-$(PKGVER) export: rm -rf $(EXPORT) svn export . $(EXPORT) svn export util $(EXPORT)/util # Standard things -include $(DEPS_$(d)) d := $(dirstack_$(sp)) sp := $(basename $(sp)) pcaputils-0.8/src/pcapdump.c000066400000000000000000000261261120140651100161270ustar00rootroot00000000000000/* pcapdump.c - dump and filter pcaps Copyright (C) 2007 Robert S. Edmonds Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define FNAME_MAXLEN 512 /* globals */ static char *program_name = "pcapdump"; static cfgopt_t cfg[] = { pcapcfg_device, pcapcfg_readfile, pcapcfg_bpf, pcapcfg_snaplen, pcapcfg_promisc, { 'u', "owner", CONFIG_STR, {}, "root", "output file owning user" }, { 'g', "group", CONFIG_STR, {}, "root", "output file owning group" }, { 'm', "mode", CONFIG_OCT, {}, "0600", "output file mode" }, { 't', "interval", CONFIG_DEC, {}, "86400", "output file rotation interval" }, { 'T', "duration", CONFIG_DEC, {}, NULL, "capture duration in seconds" }, { 'c', "count", CONFIG_DEC, {}, NULL, "packet count limit" }, { 'H', "headersonly", CONFIG_BOOL,{}, "0", "dump headers only" }, { 'S', "sample", CONFIG_DEC, {}, "0", "sample value" }, { 'R', "random", CONFIG_BOOL,{}, "0", "random sampling of packets" }, { 'w', "filefmt", CONFIG_STR, {}, NULL, "output file format" }, { 'P', "pidfile", CONFIG_STR, {}, NULL, "pid file" }, cfgopt_cfgfile, cfgopt_end }; static pcap_args_t pa; static bool check_interval = false; static bool headers_only = false; static bool reload_config = false; static bool stop_running = false; static char *pcapdump_filefmt; static int pcapdump_interval; static int64_t count_bytes; static int64_t count_packets; static int64_t pcapdump_packetlimit = -1; static int64_t pcapdump_duration = -1; static int64_t total_count_bytes; static int64_t total_count_dropped; static int64_t total_count_packets; static time_t time_lastdump; static time_t time_start; static bool pcapdump_sample_random = false; static int pcapdump_sample; static int pcapdump_sample_value; /* forward declarations */ static bool has_config_changed(void); static bool should_sample(void); static inline bool is_new_interval(time_t t); static void check_interval_and_reset(void); static void close_and_exit(void); static void daemonize(void); static void load_config(void); static void parse_args(int argc, char **argv); static void print_end_stats(void); static void process_packet(u_char *, const struct pcap_pkthdr *, const u_char *); static void reset_config(void); static void reset_dump(void); static void setup_signals(void); static void sigalarm_handler(int x __unused); static void sighup_handler(int x __unused); static void sigterm_handler(int x __unused); static void update_and_print_stats(void); static void usage(const char *msg); /* functions */ int main(int argc, char **argv){ struct timeval tv; gettimeofday(&tv, NULL); time_start = tv.tv_sec; setlinebuf(stderr); parse_args(argc, argv); daemonize(); reset_config(); setup_signals(); reset_dump(); for(;;){ pcapnet_packet_loop(&pa, process_packet); if(stop_running){ close_and_exit(); }else if(check_interval){ check_interval_and_reset(); }else if(reload_config){ reset_config(); reload_config = false; } else break; } return EXIT_SUCCESS; } static void daemonize(void){ cfgopt_t *cur = cfgopt_get(cfg, "pidfile"); if(cur && cur->val.str) util_daemonize(program_name, cur->val.str); } static void reset_config(void){ if(!pa.handle){ /* initial call to reset_config */ load_config(); pcapnet_init(&pa); cfgopt_print(cfg); }else{ /* called from signal handler */ if(has_config_changed()){ load_config(); pcapnet_reinit_device(&pa); } reset_dump(); } } static void load_config(void){ FREE(pa.dev); FREE(pa.bpf_string); FREE(pcapdump_filefmt); pa.dev = cfgopt_get_str_dup(cfg, "device"); pa.bpf_string = cfgopt_get_str_dup(cfg, "bpf"); pcapdump_filefmt = cfgopt_get_str_dup(cfg, "filefmt"); pa.promisc = cfgopt_get_bool(cfg, "promisc"); pa.snaplen = cfgopt_get_num(cfg, "snaplen"); pcapdump_interval = cfgopt_get_num(cfg, "interval"); pcapdump_packetlimit = cfgopt_get_num(cfg, "count"); pcapdump_duration = cfgopt_get_num(cfg, "duration"); } static bool has_config_changed(void){ char *configfile = cfgopt_get_str(cfg, "configfile"); if(configfile){ if(!cfgopt_load(cfg, configfile)) ERROR("configuration error, exiting"); } if( cfgopt_get_num(cfg, "interval") != pcapdump_interval || cfgopt_get_num(cfg, "duration") != pcapdump_duration || cfgopt_get_bool(cfg, "promisc") != pa.promisc || cfgopt_get_num(cfg, "snaplen") != pa.snaplen || strcmp(pa.bpf_string, cfgopt_get_str(cfg, "bpf")) != 0 || strcmp(pa.dev, cfgopt_get_str(cfg, "device")) != 0 || strcmp(pcapdump_filefmt,cfgopt_get_str(cfg, "filefmt")) != 0 ){ return true; }else{ return false; } } static void close_and_exit(void){ print_end_stats(); pcapnet_close(&pa); exit(EXIT_SUCCESS); } static void process_packet(u_char *user __unused, const struct pcap_pkthdr *hdr, const u_char *pkt){ if( pcapdump_packetlimit > 0 && total_count_packets + count_packets >= pcapdump_packetlimit ){ DEBUG("packet limit reached"); close_and_exit(); } if( pcapdump_duration > 0 && hdr->ts.tv_sec > (time_start + pcapdump_duration) ){ DEBUG("duration exceeded"); close_and_exit(); } if(is_new_interval(hdr->ts.tv_sec)) reset_dump(); if(pcapdump_sample > 0 && !should_sample()) return; if(unlikely(!headers_only)){ pcap_dump((u_char *) pa.dumper, hdr, pkt); ++count_packets; count_bytes += hdr->len; }else{ size_t len = hdr->caplen; const u_char *app = pcapnet_start_app_layer(pa.datalink, pkt, &len); u32 applen = app - pkt; if(app && applen <= (u32) pa.snaplen){ struct pcap_pkthdr newhdr = { .ts = hdr->ts, .caplen = applen, .len = hdr->len, }; pcap_dump((u_char *) pa.dumper, &newhdr, pkt); ++count_packets; count_bytes += applen; } } return; } static bool should_sample(void){ /* See RFC 5475 for a description of sampling techniques. Comments * in this function use the RFC terminology. */ if(!pcapdump_sample_random) { /* Systematic count-based sampling, section 5.1 */ if(--pcapdump_sample_value == 0){ pcapdump_sample_value = pcapdump_sample; return true; }else{ return false; } }else{ /* Uniform probabilistic sampling, section 5.2.2.1 */ if(rng_randint(0, pcapdump_sample - 1) == 0){ return true; }else{ return false; } } } static inline bool is_new_interval(time_t t){ if( (pcapdump_interval > 0) && (((t % pcapdump_interval == 0) && (t != time_lastdump)) || (t - time_lastdump > pcapdump_interval)) ) return true; else return false; } static void check_interval_and_reset(void){ check_interval = false; struct timeval tv; gettimeofday(&tv, NULL); if(is_new_interval(tv.tv_sec) && !reload_config) reset_dump(); if(pa.dev) alarm(1); } static void reset_dump(void){ if(pa.dumper) pcapnet_close_dump(&pa); char *fname; CALLOC(fname, FNAME_MAXLEN); struct timeval tv; gettimeofday(&tv, NULL); struct tm *the_time = gmtime(&tv.tv_sec); strftime(fname, FNAME_MAXLEN, pcapdump_filefmt, the_time); update_and_print_stats(); if(pcapdump_interval > 0) time_lastdump = tv.tv_sec - (tv.tv_sec % pcapdump_interval); int fd = creat_mog( fname, cfgopt_get_num(cfg, "mode"), cfgopt_get_str(cfg, "owner"), cfgopt_get_str(cfg, "group") ); pcapnet_init_dumpfd(&pa, fd); DEBUG("opened %s", fname); } static void update_and_print_stats(void){ char *rate; struct pcap_stat stat; unsigned count_dropped; rate = human_readable_rate(count_packets, count_bytes, pcapdump_interval); if(pcap_stats(pa.handle, &stat) == 0){ total_count_dropped += (count_dropped = stat.ps_drop); if(time_lastdump > 0 && pcapdump_interval > 0) DEBUG("%" PRIi64 " packets dumped (%u dropped) at %s", count_packets, count_dropped, rate ); } FREE(rate); total_count_packets += count_packets; total_count_bytes += count_bytes; count_packets = 0; count_bytes = 0; } static void print_end_stats(void){ char *rate; struct pcap_stat stat; struct timeval tv; gettimeofday(&tv, NULL); total_count_packets += count_packets; total_count_bytes += count_bytes; count_packets = 0; count_bytes = 0; rate = human_readable_rate(total_count_packets, total_count_bytes, tv.tv_sec - time_start); if(pcap_stats(pa.handle, &stat) == 0){ total_count_dropped += stat.ps_drop; if(time_lastdump > 0 && pcapdump_interval > 0) DEBUG("%" PRIi64 " total packets dumped (%" PRIi64 " dropped) at %s", total_count_packets, total_count_dropped, rate ); } FREE(rate); } static void setup_signals(void){ signal(SIGHUP, sighup_handler); siginterrupt(SIGHUP, 1); pcapnet_setup_signals(sigterm_handler); if(pa.dev && pcapdump_interval > 0){ signal(SIGALRM, sigalarm_handler); siginterrupt(SIGALRM, 1); alarm(1); } } static void sigalarm_handler(int x __unused){ check_interval = true; pcapnet_break_loop(&pa); } static void sighup_handler(int x __unused){ reload_config = true; pcapnet_break_loop(&pa); } static void sigterm_handler(int x __unused){ stop_running = true; pcapnet_break_loop(&pa); } static void parse_args(int argc, char **argv){ cfgopt_t *cur; cfgopt_parse_args(cfg, argc, argv); pcapnet_load_cfg(&pa, cfg); if(!pcapnet_are_packets_available(&pa)) usage("need to specify a packet capture source"); if(!cfgopt_is_present(cfg, "filefmt")) usage("need to specify output file format"); if((cur = cfgopt_get(cfg, "configfile")) && cur->val.str && cur->val.str[0] != '/') usage("use fully qualified config file path"); headers_only = cfgopt_get_bool(cfg, "headersonly"); pcapdump_sample = pcapdump_sample_value = cfgopt_get_num(cfg, "sample"); pcapdump_sample_random = cfgopt_get_bool(cfg, "random"); if(pcapdump_sample_random && (pcapdump_sample <= 0)) usage("random sampling requires a random value"); if(pcapdump_sample_random) rng_seed(false); } static void usage(const char *msg){ fprintf(stderr, "Error: %s\n\n", msg); fprintf(stderr, "Usage: %s \n", program_name); cfgopt_usage(cfg); exit(EXIT_FAILURE); } pcaputils-0.8/src/pcapip.c000066400000000000000000000073701120140651100155720ustar00rootroot00000000000000/* pcapip.c - pcap IP filter Copyright (C) 2007 Robert S. Edmonds Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include /* globals */ static char *program_name = "pcapip"; static cfgopt_t cfg[] = { pcapcfg_device, pcapcfg_bpf, pcapcfg_readfile, pcapcfg_writefile, pcapcfg_snaplen, pcapcfg_promisc, { 'l', "list", CONFIG_STR, {}, NULL, "file containing list of IP addresses" }, cfgopt_end }; static pcap_args_t pa; static void *pool = NULL; /* forward declarations */ static void parse_args(int argc, char **argv); static void process_packet(u_char *, const struct pcap_pkthdr *, const u_char *); static void read_ipfile(char *fname); static void sighandler(int x __unused); static void usage(const char *msg); /* functions */ int main(int argc, char **argv){ parse_args(argc, argv); read_ipfile(cfgopt_get_str(cfg, "list")); pcapnet_init(&pa); pcapnet_setup_signals(sighandler); pcapnet_packet_loop(&pa, process_packet); pcapnet_close(&pa); return EXIT_SUCCESS; } static void sighandler(int x __unused){ pcapnet_break_loop(&pa); } static void process_packet(u_char *user __unused, const struct pcap_pkthdr *hdr, const u_char *pkt){ int etype; size_t len = hdr->caplen; struct iphdr *ip_hdr = (struct iphdr *) pcapnet_start_network_header(pa.datalink, pkt, &etype, &len); if(ip_hdr == NULL) return; if(etype == ETHERTYPE_IP){ if(JudyLGet(pool, my_ntohl(ip_hdr->saddr), PJE0)){ pcap_dump((u_char *) pa.dumper, hdr, pkt); }else if(JudyLGet(pool, my_ntohl(ip_hdr->daddr), PJE0)){ pcap_dump((u_char *) pa.dumper, hdr, pkt); } } } static void read_ipfile(char *fname){ char *line = NULL; size_t len = 0; FILE *fp = fopen(fname, "r"); if(fp == NULL){ ERROR("unable to open file '%s'", fname); } while(getline(&line, &len, fp) != -1){ ipaddr_t addr; scan_ip4(line, (char *) &addr); addr = my_ntohl(addr); Word_t *val = (Word_t *)JudyLGet(pool, addr, PJE0); if(val == NULL){ val = (Word_t *)JudyLIns(&pool, addr, PJE0); } } FREE(line); } static void parse_args(int argc, char **argv){ cfgopt_parse_args(cfg, argc, argv); pcapnet_load_cfg(&pa, cfg); if(!pcapnet_are_packets_available(&pa)) usage("need to specify a packet capture source"); if(!cfgopt_is_present(cfg, "writefile")) usage("need to specify output file"); if(!cfgopt_is_present(cfg, "list")) usage("need to specify an IP list file"); } static void usage(const char *msg){ fprintf(stderr, "Error: %s\n\n", msg); fprintf(stderr, "Usage: %s \n", program_name); cfgopt_usage(cfg); exit(EXIT_FAILURE); } pcaputils-0.8/src/pcappick.c000066400000000000000000000053671120140651100161140ustar00rootroot00000000000000/* pcappick.c - pick a pcap frame Copyright (C) 2007 Robert S. Edmonds Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include /* globals */ static char *program_name = "pcappick"; static cfgopt_t cfg[] = { pcapcfg_device, pcapcfg_readfile, pcapcfg_writefile, pcapcfg_bpf, pcapcfg_snaplen, pcapcfg_promisc, { 'c', "count", CONFIG_DEC, {}, NULL, "frame number to pick" }, cfgopt_end }; static pcap_args_t pa; static uint64_t count_packet = 0; static uint64_t count_target = 0; /* forward declarations */ static void parse_args(int argc, char **argv); static void process_packet(u_char *, const struct pcap_pkthdr *, const u_char *); static void usage(const char *msg); /* functions */ int main(int argc, char **argv){ parse_args(argc, argv); pcapnet_init(&pa); pcapnet_packet_loop(&pa, process_packet); pcapnet_close(&pa); return EXIT_FAILURE; } static void process_packet(u_char *user __unused, const struct pcap_pkthdr *hdr, const u_char *pkt){ ++count_packet; if(count_packet == count_target){ pcap_dump((u_char *) pa.dumper, hdr, pkt); pcapnet_close(&pa); exit(EXIT_SUCCESS); } } static void parse_args(int argc, char **argv){ cfgopt_parse_args(cfg, argc, argv); pcapnet_load_cfg(&pa, cfg); if(!pcapnet_are_packets_available(&pa)) usage("need to specify a packet capture source"); if(!cfgopt_is_present(cfg, "count")) usage("need a frame number"); count_target = cfgopt_get_num(cfg, "count"); } static void usage(const char *msg){ fprintf(stderr, "Error: %s\n\n", msg); fprintf(stderr, "Usage: %s \n", program_name); cfgopt_usage(cfg); exit(EXIT_FAILURE); } pcaputils-0.8/src/pcapuc.c000066400000000000000000000133101120140651100155600ustar00rootroot00000000000000/* pcapuc.c - pcap IP address unique count Copyright (C) 2007 Robert S. Edmonds Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include /* globals */ static char *program_name = "pcapuc"; static bool count_src_only = false; static bool count_dst_only = false; static bool count_pairs_only = false; static bool count_summary_only = false; static cfgopt_t cfg[] = { pcapcfg_device, pcapcfg_readfile, pcapcfg_bpf, pcapcfg_promisc, { 'S', "countsrc", CONFIG_BOOL, { .boolean = &count_src_only }, "0", "count src addresses only" }, { 'D', "countdst", CONFIG_BOOL, { .boolean = &count_dst_only }, "0", "count dst addresses only" }, { 'P', "countpairs", CONFIG_BOOL, { .boolean = &count_pairs_only }, "0", "count (src, dst) sets only" }, { 'C', "countsum", CONFIG_BOOL, { .boolean = &count_summary_only },"0", "only output the summary count" }, cfgopt_end }; static pcap_args_t pa; static void *pool = NULL; /* forward declarations */ static void parse_args(int argc, char **argv); static void print_uniq(void); static void process_packet(u_char *, const struct pcap_pkthdr *, const u_char *); static void sighandler(int x __unused); static void usage(const char *msg); int main(int argc, char **argv){ parse_args(argc, argv); pcapnet_init(&pa); pcapnet_setup_signals(sighandler); pcapnet_packet_loop(&pa, process_packet); pcapnet_close(&pa); print_uniq(); return EXIT_SUCCESS; } static void process_packet(u_char *user __unused, const struct pcap_pkthdr *hdr, const u_char *pkt){ int etype; size_t len = hdr->caplen; struct iphdr *ip_hdr = (struct iphdr *) pcapnet_start_network_header(pa.datalink, pkt, &etype, &len); if(ip_hdr == NULL) return; if(etype == ETHERTYPE_IP){ if(count_src_only){ ipaddr_t addr = my_ntohl(ip_hdr->saddr); Word_t *val = (Word_t *) JudyLGet(pool, addr, PJE0); if(val == NULL){ val = (Word_t *) JudyLIns(&pool, addr, PJE0); *val = 1; }else{ *val += 1; } }else if(count_dst_only){ ipaddr_t addr = my_ntohl(ip_hdr->daddr); Word_t *val = (Word_t *) JudyLGet(pool, addr, PJE0); if(val == NULL){ val = (Word_t *) JudyLIns(&pool, addr, PJE0); *val = 1; }else{ *val += 1; } }else if(count_pairs_only){ ipaddr_t ip[2] = { my_ntohl(ip_hdr->saddr), my_ntohl(ip_hdr->daddr) }; if(ip[0] > ip[1]) SWAP(ip[0], ip[1]); void **val_ip0 = (void **) JudyLGet(pool, ip[0], PJE0); if(val_ip0 == NULL){ val_ip0 = (void **) JudyLIns(&pool, ip[0], PJE0); *val_ip0 = NULL; } Word_t *val_ip1 = (Word_t *) JudyLGet(*val_ip0, ip[1], PJE0); if(val_ip1 == NULL){ val_ip1 = (Word_t *) JudyLIns(val_ip0, ip[1], PJE0); *val_ip1 = 1; }else{ *val_ip1 += 1; } } } } static void print_uniq(void){ if(count_src_only || count_dst_only){ Word_t ip = 0; Word_t *val; if(count_summary_only){ uint64_t count = JudyLCount(pool, 0, -1, PJE0); printf("%" PRIu64 "\n", count); }else{ while((val = (Word_t *) JudyLNext(pool, &ip, PJE0)) != NULL){ char sip[INET_ADDRSTRLEN]; ipaddr_t ip_copy = my_htonl(ip); fmt_ip4(sip, (char *) &ip_copy); printf("%s\t%ld\n", sip, (long) *val); } } }else if(count_pairs_only){ Word_t ip[2] = { 0, 0 }; Word_t **val_ip0; Word_t *val_ip1; if(count_summary_only){ uint64_t count = 0; while((val_ip0 = (Word_t **) JudyLNext(pool, &ip[0], PJE0)) != NULL){ count += JudyLCount(*val_ip0, 0, -1, PJE0); } printf("%" PRIu64 "\n", count); }else{ uint64_t count = 0; while((val_ip0 = (Word_t **) JudyLNext(pool, &ip[0], PJE0)) != NULL){ while((val_ip1 = (Word_t *) JudyLNext(*val_ip0, &ip[1], PJE0)) != NULL){ ++count; char sip0[INET_ADDRSTRLEN]; char sip1[INET_ADDRSTRLEN]; ipaddr_t ip0 = my_htonl(ip[0]); ipaddr_t ip1 = my_htonl(ip[1]); fmt_ip4(sip0, (char *) &ip0); fmt_ip4(sip1, (char *) &ip1); printf("%s\t%s\t%ld\n", sip0, sip1, (long) *val_ip1); } ip[1] = 0; } } } } static void sighandler(int x __unused){ pcapnet_break_loop(&pa); } static void parse_args(int argc, char **argv){ cfgopt_parse_args(cfg, argc, argv); pcapnet_load_cfg(&pa, cfg); if(!pcapnet_are_packets_available(&pa)) usage("need to specify a packet capture source"); int c = count_src_only + count_dst_only + count_pairs_only; if(c > 1) usage("mutually exclusive options selecetd"); else if(c == 0) usage("select a counting mode"); } static void usage(const char *msg){ fprintf(stderr, "Error: %s\n\n", msg); fprintf(stderr, "Usage: %s \n", program_name); cfgopt_usage(cfg); exit(EXIT_FAILURE); } pcaputils-0.8/util/000077500000000000000000000000001120140651100143315ustar00rootroot00000000000000pcaputils-0.8/util/Rules.mk000066400000000000000000000012211120140651100157500ustar00rootroot00000000000000# Standard things sp := $(sp).x dirstack_$(sp) := $(d) d := $(dir) # Local variables OBJS_$(d) := \ $(d)/byte.o \ $(d)/cfgopt.o \ $(d)/checksum.o \ $(d)/file.o \ $(d)/daemon.o \ $(d)/net.o \ $(d)/pcapnet.o \ $(d)/rate.o \ $(d)/ring.o \ $(d)/rng.o \ $(d)/scanfmt.o \ $(d)/server.o \ $(d)/socket.o \ $(d)/uint.o \ $(d)/util.o DEPS_$(d) := $(OBJS_$(d):%.o=%.d) TGTS_$(d) := $(d)/util.a TGT_LIB := $(TGT_LIB) $(TGTS_$(d)) CLEAN := $(CLEAN) $(TGTS_$(d)) $(OBJS_$(d)) $(DEPS_$(d)) # Local rules $(d)/util.a: $(OBJS_$(d)) $(ARCH) # Standard things -include $(DEPS_$(d)) d := $(dirstack_$(sp)) sp := $(basename $(sp)) pcaputils-0.8/util/byte.c000066400000000000000000000032071120140651100154420ustar00rootroot00000000000000#include "byte.h" /* derived from public domain djbdns code */ unsigned int byte_chr(const char* s,unsigned int n,int c) { char ch; const char *t; ch = (char) c; t = s; for (;;) { if (!n) break; if (*t == ch) break; ++t; --n; if (!n) break; if (*t == ch) break; ++t; --n; if (!n) break; if (*t == ch) break; ++t; --n; if (!n) break; if (*t == ch) break; ++t; --n; } return t - s; } void byte_copy(void* To, unsigned int n, const void* From) { char *to=To; const char *from=From; for (;;) { if (!n) return; *to++ = *from++; --n; if (!n) return; *to++ = *from++; --n; if (!n) return; *to++ = *from++; --n; if (!n) return; *to++ = *from++; --n; } } void byte_copyr(void* To,unsigned int n, const void* From) { char *to=(char*)To+n; const char *from=(char*)From+n; for (;;) { if (!n) return; *--to = *--from; --n; if (!n) return; *--to = *--from; --n; if (!n) return; *--to = *--from; --n; if (!n) return; *--to = *--from; --n; } } int byte_diff(const void* S,unsigned int n, const void* T) { const char *s=S; const char *t=T; for (;;) { if (!n) return 0; if (*s != *t) break; ++s; ++t; --n; if (!n) return 0; if (*s != *t) break; ++s; ++t; --n; if (!n) return 0; if (*s != *t) break; ++s; ++t; --n; if (!n) return 0; if (*s != *t) break; ++s; ++t; --n; } return ((int)(unsigned int)(unsigned char) *s) - ((int)(unsigned int)(unsigned char) *t); } void byte_zero(void* S,unsigned int n) { char* s=S; for (;;) { if (!n) break; *s++ = 0; --n; if (!n) break; *s++ = 0; --n; if (!n) break; *s++ = 0; --n; if (!n) break; *s++ = 0; --n; } } pcaputils-0.8/util/byte.h000066400000000000000000000006771120140651100154570ustar00rootroot00000000000000#ifndef RSEUTIL_BYTE_H #define RSEUTIL_BYTE_H int byte_diff(const void *, unsigned int, const void *); unsigned int byte_chr(const char *s, unsigned int n, int c); unsigned int byte_rchr(const char *s, unsigned int n, int c); void byte_copy(void *to, unsigned int n, const void *from); void byte_copyr(void *to, unsigned int n, const void *from); void byte_zero(void *, unsigned int); #define byte_equal(s,n,t) (!byte_diff((s),(n),(t))) #endif pcaputils-0.8/util/cfgopt.c000066400000000000000000000222471120140651100157660ustar00rootroot00000000000000/* cfgopt.c - unified config file / command line option parsing Copyright (C) 2008 Robert S. Edmonds Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #define _GNU_SOURCE #include #include #include #include "cfgopt.h" #include "scanfmt.h" #include "util.h" /* declarations */ static void cfgopt_load_value(cfgopt_t *cfg, char *value); /* functions */ bool cfgopt_load(cfgopt_t *cfg, char *fname){ FILE *fp; size_t len; char *line = NULL; bool success = true; if(!cfg || !fname) return false; if(!(fp = fopen(fname, "r"))) ERROR("fopen() failed: %s", strerror(errno)); while(getline(&line, &len, fp) != -1){ char *tok_key; char *tok_val; tok_key = strtok(line, "=\"\t\n"); if(!tok_key) continue; tok_val = strtok(NULL, "\"\t\n"); if(!tok_val){ DEBUG("null value for key='%s'", tok_key); continue; } cfgopt_t *cur = cfgopt_get(cfg, tok_key); if(!cur){ DEBUG("unknown configuration key '%s'", tok_key); success = false; continue; }else{ cfgopt_load_value(cur, tok_val); } FREE(line); } for(; cfg->type != CONFIG_END ; ++cfg) if(!cfg->val.str) cfgopt_load_value(cfg, cfg->default_value); FREE(line); fclose(fp); return success; } static void cfgopt_load_value(cfgopt_t *cfg, char *value){ if(!value) return; switch(cfg->type){ case CONFIG_STR: { cfg->val.str = strdup(value); break; } case CONFIG_DEC: case CONFIG_OCT: { int base = cfg->type == CONFIG_DEC ? 0 : 8; if(!cfg->val.num) NEW0(cfg->val.num); *cfg->val.num = strtoul(value, NULL, base); break; } case CONFIG_BOOL: { if(!cfg->val.boolean) NEW0(cfg->val.boolean); *cfg->val.boolean = (bool) strtoul(value, NULL, 0); break; } case CONFIG_IP: { char *ip; MALLOC(ip, 4); if(scan_ip4(value, ip) == 0) ERROR("invalid IPv4 literal: %s", value); cfg->val.ip = ip; break; } case CONFIG_IP6: { char *ip6; MALLOC(ip6, 16); if(scan_ip6(value, ip6) == 0) ERROR("invalid IPv6 literal: %s", value); cfg->val.ip6 = ip6; break; } case CONFIG_MAC: { char *mac; MALLOC(mac, 6); if(scan_mac(value, mac) != 6) ERROR("invalid MAC literal: %s", value); cfg->val.mac = mac; break; } case CONFIG_NONOPT: { if(!cfg->val.nonopt){ cfg->val.nonopt = strdup(value); }else{ size_t new_size = 2 + strlen(cfg->val.nonopt) + strlen(value); REALLOC(cfg->val.nonopt, new_size); strcat(cfg->val.nonopt, " "); strcat(cfg->val.nonopt, value); } break; } default: ERROR("invalid configuration type %d", (int) cfg->type); } } cfgopt_t *cfgopt_get(cfgopt_t *cfg, char *key){ for(; cfg->type != CONFIG_END ; ++cfg){ if(strcasecmp(cfg->key, key) == 0) return cfg; } return NULL; } char *cfgopt_get_str(cfgopt_t *cfg, char *key){ for(; cfg->type != CONFIG_END ; ++cfg){ if(strcasecmp(cfg->key, key) == 0){ if(cfg->type != CONFIG_STR) ERROR("key='%s' is not a CONFIG_STR", key); return cfg->val.str; } } return NULL; } char *cfgopt_get_str_dup(cfgopt_t *cfg, char *key){ for(; cfg->type != CONFIG_END ; ++cfg){ if(strcasecmp(cfg->key, key) == 0){ if(cfg->type != CONFIG_STR) ERROR("key='%s' is not a CONFIG_STR", key); if(cfg->val.str) return strdup(cfg->val.str); } } return NULL; } long cfgopt_get_num(cfgopt_t *cfg, char *key){ for(; cfg->type != CONFIG_END ; ++cfg){ if(strcasecmp(cfg->key, key) == 0){ if(cfg->type != CONFIG_DEC && cfg->type != CONFIG_OCT) ERROR("key='%s' is not a CONFIG_DEC or CONFIG_OCT", key); if(cfg->val.num) return *cfg->val.num; } } return 0; } bool cfgopt_get_bool(cfgopt_t *cfg, char *key){ for(; cfg->type != CONFIG_END ; ++cfg){ if(strcasecmp(cfg->key, key) == 0){ if(cfg->type != CONFIG_BOOL) ERROR("key='%s' is not a CONFIG_BOOL", key); if(cfg->val.boolean) return *cfg->val.boolean; } } return false; } char *cfgopt_get_ip(cfgopt_t *cfg, char *key){ for(; cfg->type != CONFIG_END ; ++cfg){ if(strcasecmp(cfg->key, key) == 0){ if(cfg->type != CONFIG_IP) ERROR("key='%s' is not a CONFIG_IP", key); if(cfg->val.ip) return cfg->val.ip; } } return NULL; } char *cfgopt_get_ip6(cfgopt_t *cfg, char *key){ for(; cfg->type != CONFIG_END ; ++cfg){ if(strcasecmp(cfg->key, key) == 0){ if(cfg->type != CONFIG_IP6) ERROR("key='%s' is not a CONFIG_IP6", key); return cfg->val.ip; } } return NULL; } char *cfgopt_get_mac(cfgopt_t *cfg, char *key){ for(; cfg->type != CONFIG_END ; ++cfg){ if(strcasecmp(cfg->key, key) == 0){ if(cfg->type != CONFIG_MAC) ERROR("key='%s' is not a CONFIG_MAC", key); return cfg->val.mac; } } return NULL; } char *cfgopt_get_nonopt(cfgopt_t *cfg){ for(; cfg->type != CONFIG_END ; ++cfg){ if(cfg->type == CONFIG_NONOPT) return cfg->val.nonopt; } return NULL; } void cfgopt_free(cfgopt_t *cfg){ for(; cfg->type != CONFIG_END ; ++cfg){ FREE(cfg->val.str); } } bool cfgopt_is_present(cfgopt_t *cfg, char *key){ for(; cfg->type != CONFIG_END ; ++cfg){ if((strcasecmp(cfg->key, key) == 0) && cfg->val.str) return true; } return false; } void cfgopt_print(cfgopt_t *cfg){ for(; cfg->type != CONFIG_END ; ++cfg){ switch(cfg->type){ case CONFIG_STR: if(cfg->val.str) DEBUG("key='%s', val='%s'", cfg->key, cfg->val.str); break; case CONFIG_BOOL: if(cfg->val.boolean) DEBUG("key='%s', val=%s", cfg->key, *cfg->val.boolean ? "true" : "false"); break; case CONFIG_DEC: if(cfg->val.num) DEBUG("key='%s', val=%ld", cfg->key, *cfg->val.num); break; case CONFIG_OCT: if(cfg->val.num) DEBUG("key='%s', val=%lo", cfg->key, *cfg->val.num); break; case CONFIG_IP: { char sip[FMT_IP4]; fmt_ip4(sip, cfg->val.ip); DEBUG("key='%s', val=%s", cfg->key, sip); break; } case CONFIG_IP6: { char sip[FMT_IP6]; fmt_ip6(sip, cfg->val.ip); DEBUG("key='%s', val=%s", cfg->key, sip); break; } case CONFIG_MAC: { char smac[FMT_MAC]; fmt_mac(smac, cfg->val.mac); DEBUG("key='%s', val=%s", cfg->key, smac); break; } case CONFIG_NONOPT: if(cfg->val.nonopt) DEBUG("nonopt='%s'", cfg->val.nonopt); break; default: break; } } } void cfgopt_usage(cfgopt_t *cfg){ for(; cfg->type != CONFIG_END ; ++cfg){ switch(cfg->type){ case CONFIG_STR: case CONFIG_DEC: case CONFIG_OCT: case CONFIG_IP: case CONFIG_IP6: case CONFIG_MAC: fprintf(stderr, "\t[ -%c <%s> %s %s%s%s]\n", cfg->cmd, cfg->key, cfg->help, cfg->default_value == NULL ? "" : "(default: ", cfg->default_value == NULL ? "" : cfg->default_value, cfg->default_value == NULL ? "" : ") " ); break; case CONFIG_BOOL: fprintf(stderr, "\t[ -%c %s %s%s%s]\n", cfg->cmd, cfg->help, cfg->default_value == NULL ? "" : "(default: ", cfg->default_value == NULL ? "" : cfg->default_value, cfg->default_value == NULL ? "" : ") " ); break; default: break; } } } void cfgopt_parse_args(cfgopt_t *cfg, int argc, char **argv){ int c; char *options; cfgopt_t *cur; CALLOC(options, 2 * cfgopt_len(cfg)); for(cur = cfg ; cur->type != CONFIG_END ; ++cur){ switch(cur->type){ case CONFIG_STR: case CONFIG_DEC: case CONFIG_OCT: case CONFIG_IP: case CONFIG_IP6: case CONFIG_MAC: strcat(options, &cur->cmd); strcat(options, ":"); break; case CONFIG_BOOL: strcat(options, &cur->cmd); break; default: break; } } for(cur = cfg ; cur->type != CONFIG_END ; ++cur) if(cur->type != CONFIG_NONOPT) cfgopt_load_value(cur, cur->default_value); while((c = getopt(argc, argv, options)) != EOF){ for(cur = cfg ; cur->type != CONFIG_END ; ++cur){ if(c == cur->cmd){ if(cur->type == CONFIG_BOOL){ if(cur->default_value && cur->default_value[0] == '0') cfgopt_load_value(cur, "1"); else if(cur->default_value && cur->default_value[0] == '1') cfgopt_load_value(cur, "0"); else cfgopt_load_value(cur, "1"); }else{ cfgopt_load_value(cur, optarg); } } } } for(cur = cfg ; cur->type != CONFIG_END; ++cur) if(cur->type == CONFIG_NONOPT) while(argv[optind] != '\0') cfgopt_load_value(cur, argv[optind++]); if((cur = cfgopt_get(cfg, "configfile")) && cur->val.str && !cfgopt_load(cfg, cur->val.str)) ERROR("configuration error, exiting"); FREE(options); } size_t cfgopt_len(cfgopt_t *cfg){ size_t len = 0; for(; cfg->type != CONFIG_END ; ++cfg) ++len; return len; } pcaputils-0.8/util/cfgopt.h000066400000000000000000000032141120140651100157640ustar00rootroot00000000000000#ifndef CFGOPT_H #define CFGOPT_H #include #include "util.h" /* declarations */ enum CFGOPT_TYPE { CONFIG_STR, CONFIG_DEC, CONFIG_OCT, CONFIG_BOOL, CONFIG_IP, CONFIG_IP6, CONFIG_MAC, CONFIG_NONOPT, CONFIG_END }; typedef struct cfgopt { char cmd; char *key; enum CFGOPT_TYPE type; union { char *str; long *num; bool *boolean; char *ip; char *ip6; char *mac; char *nonopt; } val; char *default_value; char *help; } cfgopt_t; #define cfgopt_cfgfile { 'C', "configfile", CONFIG_STR, {}, NULL, "config file" } #define cfgopt_help { 'h', "help", CONFIG_BOOL, {}, "0", "show help" } #define cfgopt_verbose { 'V', "verbose", CONFIG_BOOL, { .boolean = &util_flag_verbose }, "0", "verbose output" } #define cfgopt_nonopt { '\0', "", CONFIG_NONOPT, {}, "", "" } #define cfgopt_end { '\0', "", CONFIG_END, {}, "", "" } /* functions */ extern bool cfgopt_load(cfgopt_t *, char *fname); extern size_t cfgopt_len(cfgopt_t *); extern void cfgopt_free(cfgopt_t *); extern void cfgopt_parse_args(cfgopt_t *, int argc, char **argv); extern void cfgopt_print(cfgopt_t *); extern void cfgopt_usage(cfgopt_t *); extern bool cfgopt_get_bool(cfgopt_t *, char *key); extern bool cfgopt_is_present(cfgopt_t *, char *key); extern cfgopt_t *cfgopt_get(cfgopt_t *, char *key); extern char *cfgopt_get_ip(cfgopt_t *, char *key); extern char *cfgopt_get_ip6(cfgopt_t *, char *key); extern char *cfgopt_get_mac(cfgopt_t *, char *key); extern char *cfgopt_get_nonopt(cfgopt_t *); extern char *cfgopt_get_str(cfgopt_t *, char *key); extern char *cfgopt_get_str_dup(cfgopt_t *, char *key); extern long cfgopt_get_num(cfgopt_t *, char *key); #endif pcaputils-0.8/util/checksum.c000066400000000000000000000030351120140651100163000ustar00rootroot00000000000000#include "checksum.h" #include "net.h" #include "uint.h" #include "util.h" /* * This is a version of ip_compute_csum() optimized for IP headers, * which always checksum on 4 octet boundaries. * * By Jorge Cwik , adapted for linux by * Arnt Gulbrandsen. */ /** * ip_fast_csum - Compute the IPv4 header checksum efficiently. * iph: ipv4 header * ihl: length of header / 4 */ #if defined(__i386__) || defined(__amd64__) __inline u16 checksum_ip(const void *iph, unsigned ihl) { unsigned sum; asm( " movl (%1), %0\n" " subl $4, %2\n" " jbe 2f\n" " addl 4(%1), %0\n" " adcl 8(%1), %0\n" " adcl 12(%1), %0\n" "1: adcl 16(%1), %0\n" " lea 4(%1), %1\n" " decl %2\n" " jne 1b\n" " adcl $0, %0\n" " movl %0, %2\n" " shrl $16, %0\n" " addw %w2, %w0\n" " adcl $0, %0\n" " notl %0\n" "2:" /* Since the input registers which are loaded with iph and ihl are modified, we must also specify them as outputs, or gcc will assume they contain their original values. */ : "=r" (sum), "=r" (iph), "=r" (ihl) : "1" (iph), "2" (ihl) : "memory"); return (u16) sum; } #else __inline u16 checksum_ip(const void *iph, unsigned ihl) { return checksum_net(iph, 4 * ihl); } #endif __inline u16 checksum_net(const void *p, unsigned len) { unsigned sum = 0; u16 *ip = (u16 *) p; while(len > 1){ sum += *ip++; len -= 2; } while(sum >> 16) sum = (sum & 0xffff) + (sum >> 16); #if __BYTE_ORDER == __LITTLE_ENDIAN return (u16) (~sum); #else return bswap16((u16) (~sum)); #endif } pcaputils-0.8/util/checksum.h000066400000000000000000000003231120140651100163020ustar00rootroot00000000000000#ifndef CHECKSUM_H #define CHECKSUM_H #include "uint.h" #include "util.h" extern __inline u16 checksum_ip(const void *iph, unsigned ihl); extern __inline u16 checksum_net(const void *p, unsigned len); #endif pcaputils-0.8/util/daemon.c000066400000000000000000000041571120140651100157470ustar00rootroot00000000000000/* daemon.c - functions for daemonizing Copyright (C) 2008 Robert S. Edmonds Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include #include "daemon.h" #include "scanfmt.h" #include "util.h" void pidfile_create(const char *pidfile){ FILE *fp; pid_t pid; if(!pidfile) return; pid = getpid(); if(!(fp = fopen(pidfile, "w"))) ERROR("unable to open pidfile %s for writing: %s", pidfile, strerror(errno)); fprintf(fp, "%d\n", pid); fclose(fp); } void util_daemonize(char *program_name, char *pidfile){ if(daemon(0, 0) != 0) ERROR("%s", strerror(errno)); pidfile_create(pidfile); openlog(program_name, LOG_PID, LOG_DAEMON); util_flag_daemonized = true; } void envuidgid(void){ char *envuid; char *envgid; unsigned long uid; unsigned long gid; if((envgid = getenv("GID"))){ scan_ulong(envgid, &gid); if(-1 == setgid((gid_t) gid)) ERROR("unable to setgid(%s): %s", envgid, strerror(errno)); } if((envuid = getenv("UID"))){ scan_ulong(envuid, &uid); if(-1 == setuid((uid_t) uid)) ERROR("unable to setuid(%s): %s", envuid, strerror(errno)); } } pcaputils-0.8/util/daemon.h000066400000000000000000000004271120140651100157500ustar00rootroot00000000000000#ifndef RSEUTIL_PIDFILE_H #define RSEUTIL_PIDFILE_H #define daemon_pidfile { 'P', "pidfile", CONFIG_STR, {}, NULL, "pid file" } extern void envuidgid(void); extern void pidfile_create(const char *pidfile); extern void util_daemonize(char *program_name, char *pidfile); #endif pcaputils-0.8/util/file.c000066400000000000000000000036731120140651100154250ustar00rootroot00000000000000/* file.c - abstractions for file manipulation Copyright (C) 2008 Robert S. Edmonds Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include #include #include #include int creat_mog(const char *pathname, mode_t mode, const char *owner, const char *group){ uid_t uid; gid_t gid; int fd; struct group *gr; struct passwd *pw; pw = getpwnam(owner); gr = getgrnam(group); if(pw) uid = pw->pw_uid; else uid = geteuid(); if(gr) gid = gr->gr_gid; else gid = getegid(); if((fd = creat(pathname, mode)) == -1) ERROR("creat() failed: %s", strerror(errno)); if(geteuid() == 0) if(fchown(fd, uid, gid) != 0) ERROR("fchown() failed: %s", strerror(errno)); return fd; } int Open(const char *pathname, int flags){ int fd = open(pathname, flags); if(fd == -1) ERROR("unable to open(%s, %d): %s", pathname, flags, strerror(errno)); return fd; } pcaputils-0.8/util/file.h000066400000000000000000000005771120140651100154320ustar00rootroot00000000000000#ifndef RSEUTIL_FILE_H #define RSEUTIL_FILE_H #include #include #include #define Chdir(dir) do{ \ if(chdir(dir) != 0) ERROR("unable to chdir(%s): %s", dir, strerror(errno)); \ }while(0) extern int creat_mog(const char *pathname, mode_t mode, const char *owner, const char *group); extern int Open(const char *pathname, int flags); #endif pcaputils-0.8/util/net.c000066400000000000000000000067451120140651100152770ustar00rootroot00000000000000/* net.c - functions useful for programs which interact with the network Copyright (C) 2008 Robert S. Edmonds Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include #include #include #include "byte.h" #include "net.h" #include "scanfmt.h" #include "uint.h" #include "util.h" /* functions */ u32 bswap32(u32 x){ return ((x << 24) & 0xff000000 ) | ((x << 8) & 0x00ff0000 ) | ((x >> 8) & 0x0000ff00 ) | ((x >> 24) & 0x000000ff ); } u16 bswap16(u16 x){ return (u16) ((x & 0xff) << 8 | (x & 0xff00) >> 8); } ipaddr_range_t sips_to_range(char *sip0, char *sip1){ ipaddr_range_t ipr; scan_ip4(sip0, ipr.ip0); scan_ip4(sip1, ipr.ip1); return ipr; } char *human_readable_rate(u64 packets, u64 bytes, unsigned interval){ char prefix_packets[] = "\0\0"; char prefix_bytes[] = "\0\0"; char *str; CALLOC(str, 64); double div_packets = ((double) packets) / interval; double div_bytes = ((double) bytes) / interval; if(div_packets >= 1E9){ prefix_packets[0] = 'G'; div_packets /= 1E9; }else if(div_packets >= 1E6){ prefix_packets[0] = 'M'; div_packets /= 1E6; }else if(div_packets >= 1E3){ prefix_packets[0] = 'K'; div_packets /= 1E3; } if(div_bytes >= 1E9){ prefix_bytes[0] = 'G'; div_bytes /= 1E9; }else if(div_bytes >= 1E6){ prefix_bytes[0] = 'M'; div_bytes /= 1E6; }else if(div_bytes >= 1E3){ prefix_bytes[0] = 'K'; div_bytes /= 1E3; } snprintf(str, 64, "%.2f %spps, %.2f %sBps", div_packets, prefix_packets, div_bytes, prefix_bytes); return str; } u16 random_unprivileged_port(void){ long r = random(); r &= 0xffff; r |= 0x400; return (u16) r; } bool gai4(const char *hostname, char ip[4]){ struct addrinfo hints = { .ai_family = AF_INET, .ai_socktype = 0, .ai_protocol = 0 }; struct addrinfo *res; if(0 == getaddrinfo(hostname, NULL, &hints, &res)){ byte_copy(ip, 4, (char *) &((struct sockaddr_in *) res->ai_addr)->sin_addr.s_addr); freeaddrinfo(res); return true; }else{ DEBUG("getaddrinfo() returned: %s", strerror(errno)); } return false; } bool gai6(const char *hostname, char ip[16]){ struct addrinfo hints = { .ai_family = AF_INET6, .ai_socktype = 0, .ai_protocol = 0 }; struct addrinfo *res; if(0 == getaddrinfo(hostname, NULL, &hints, &res)){ byte_copy(ip, 16, (char *) &((struct sockaddr_in6 *) res->ai_addr)->sin6_addr); freeaddrinfo(res); return true; }else{ DEBUG("getaddrinfo() returned: %s", strerror(errno)); } return false; } pcaputils-0.8/util/net.h000066400000000000000000000131471120140651100152760ustar00rootroot00000000000000#ifndef RSEUTIL_NET_H #define RSEUTIL_NET_H #include #include #include "uint.h" #include "util.h" /* macros */ #define INET_ADDRSTRLEN 16 #define IP_MIN_HLEN 20 #define UDP_HLEN 8 #define ICMP_HLEN 4 #define ETH_ALEN 6 #define ETH_HLEN 14 #define ETHERTYPE_IP 0x0800 #define ETHERTYPE_IPV6 0x86dd #define ETHERTYPE_ARP 0x0806 #define ETHERTYPE_VLAN 0x8100 #define IP_RF 0x8000 #define IP_DF 0x4000 #define IP_MF 0x2000 #if !defined(IPPROTO_ICMP) #define IPPROTO_ICMP 1 #endif #if !defined(IPPROTO_IPIP) #define IPPROTO_IPIP 4 #endif #if !defined(IPPROTO_TCP) #define IPPROTO_TCP 6 #endif #if !defined(IPPROTO_UDP) #define IPPROTO_UDP 17 #endif #if !defined(IPPROTO_IPV6) #define IPPROTO_IPV6 41 #endif #if !defined(IPPROTO_ICMPV6) #define IPPROTO_ICMPV6 58 #endif #if !defined(INET6_ADDRSTRLEN) #define INET6_ADDRSTRLEN 46 #endif #define TCP_FIN 0x01 #define TCP_SYN 0x02 #define TCP_RST 0x04 #define TCP_PSH 0x08 #define TCP_ACK 0x10 #define TCP_URG 0x20 #define TCPFLAGS_STRLEN sizeof("FSRPAU") #if __BYTE_ORDER == __LITTLE_ENDIAN #define my_ntohs(x) bswap16(x) #define my_htons(x) bswap16(x) #define my_ntohl(x) bswap32(x) #define my_htonl(x) bswap32(x) #else #define my_ntohs(x) (x) #define my_htons(x) (x) #define my_ntohl(x) (x) #define my_htonl(x) (x) #endif #define NIPQUAD(addr) \ ((unsigned char *)&addr)[0], \ ((unsigned char *)&addr)[1], \ ((unsigned char *)&addr)[2], \ ((unsigned char *)&addr)[3] /* declarations */ struct ethhdr { char dst[ETH_ALEN]; char src[ETH_ALEN]; u16 type; } __attribute__ ((__packed__)); struct arphdr { u16 fmt_hw; /* hardware address format */ u16 fmt_proto; /* protocol address format */ u8 len_hw; /* length of hardware address */ u8 len_proto; /* length of protocol address */ u16 opcode; char sender_hw[ETH_ALEN]; char sender_ip[4]; char target_hw[ETH_ALEN]; char target_ip[4]; } __attribute__ ((__packed__)); #define ARPOP_REQUEST 1 #define ARPOP_REPLY 2 #define ARPHRD_ETHER 1 struct iphdr { #if __BYTE_ORDER == __LITTLE_ENDIAN unsigned int ihl:4; unsigned int version:4; #elif __BYTE_ORDER == __BIG_ENDIAN unsigned int version:4; unsigned int ihl:4; #endif u8 tos; u16 tot_len; u16 id; u16 frag_off; u8 ttl; u8 protocol; u16 check; u32 saddr; u32 daddr; } __attribute__ ((__packed__)); struct ip6hdr { union { struct ip6_hdrctl { u32 ip6_un1_flow; /* 20 bits of flow-ID */ u16 ip6_un1_plen; /* payload length */ u8 ip6_un1_nxt; /* next header */ u8 ip6_un1_hlim; /* hop limit */ } ip6_un1; u8 ip6_un2_vfc; /* 4 bits version, top 4 bits class */ } ip6_ctlun; char src[16]; char dst[16]; } __attribute__ ((__packed__)); #define ip6_vfc ip6_ctlun.ip6_un2_vfc #define ip6_flow ip6_ctlun.ip6_un1.ip6_un1_flow #define ip6_plen ip6_ctlun.ip6_un1.ip6_un1_plen #define ip6_nxt ip6_ctlun.ip6_un1.ip6_un1_nxt #define ip6_hlim ip6_ctlun.ip6_un1.ip6_un1_hlim #define ip6_hops ip6_ctlun.ip6_un1.ip6_un1_hlim struct icmphdr { u8 type; u8 code; u16 check; union { struct { u16 id; u16 seq; } echo; u32 gateway; struct { u16 unused; u16 mtu; } frag; /* pmtud */ } un; } __attribute__ ((__packed__)); #define ICMP_ECHOREPLY 0 #define ICMP_ECHO 8 struct tcphdr { u16 source; u16 dest; u32 seq; u32 ack_seq; #if __BYTE_ORDER == __LITTLE_ENDIAN u16 res1:4; u16 doff:4; #elif __BYTE_ORDER == __BIG_ENDIAN u16 doff:4; u16 res1:4; #endif u8 flags; u16 window; u16 check; u16 urg_ptr; } __attribute__ ((__packed__)); struct pseudo_tcphdr { u32 saddr; u32 daddr; #if __BYTE_ORDER == __LITTLE_ENDIAN u8 proto; u8 zero; #elif __BYTE_ORDER == __BIG_ENDIAN u8 zero; u8 proto; #endif u16 tot_len; } __attribute__ ((__packed__)); struct udphdr { u16 source; u16 dest; u16 len; u16 check; } __attribute__ ((__packed__)); struct dnshdr { unsigned id :16; /* query identification number */ #if BYTE_ORDER == BIG_ENDIAN /* fields in third byte */ unsigned qr: 1; /* response flag */ unsigned opcode: 4; /* purpose of message */ unsigned aa: 1; /* authoritive answer */ unsigned tc: 1; /* truncated message */ unsigned rd: 1; /* recursion desired */ /* fields in fourth byte */ unsigned ra: 1; /* recursion available */ unsigned unused :1; /* unused bits (MBZ as of 4.9.3a3) */ unsigned ad: 1; /* authentic data from named */ unsigned cd: 1; /* checking disabled by resolver */ unsigned rcode :4; /* response code */ #endif #if BYTE_ORDER == LITTLE_ENDIAN /* fields in third byte */ unsigned rd :1; /* recursion desired */ unsigned tc :1; /* truncated message */ unsigned aa :1; /* authoritive answer */ unsigned opcode :4; /* purpose of message */ unsigned qr :1; /* response flag */ /* fields in fourth byte */ unsigned rcode :4; /* response code */ unsigned cd: 1; /* checking disabled by resolver */ unsigned ad: 1; /* authentic data from named */ unsigned unused :1; /* unused bits (MBZ as of 4.9.3a3) */ unsigned ra :1; /* recursion available */ #endif /* remaining bytes */ unsigned qdcount :16; /* number of question entries */ unsigned ancount :16; /* number of answer entries */ unsigned nscount :16; /* number of authority entries */ unsigned arcount :16; /* number of resource entries */ } __attribute__ ((__packed__)); typedef u32 ipaddr_t; typedef u16 port_t; typedef struct ipaddr_range { char ip0[4]; char ip1[4]; } ipaddr_range_t; bool gai4(const char *hostname, char ip[4]); bool gai6(const char *hostname, char ip[16]); char *human_readable_rate(u64 packets, u64 bytes, unsigned interval); ipaddr_range_t sips_to_range(char *sip0, char *sip1); u16 random_unprivileged_port(void); u16 bswap16(u16 x); u32 bswap32(u32 x); #endif pcaputils-0.8/util/pcapnet.c000066400000000000000000000253621120140651100161370ustar00rootroot00000000000000/* pcapnet.c - libpcap abstraction layer Copyright (C) 2007 Robert S. Edmonds Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include #include #include #include #include "cfgopt.h" #include "net.h" #include "pcapnet.h" #include "util.h" /* functions */ void pcapnet_load_cfg(pcap_args_t *pa, cfgopt_t *cfg){ cfgopt_t *cur; char *str; if(!pa || !cfg) ERROR("pa or cfg null"); if((str = cfgopt_get_str(cfg, "device")) && str && str[0] != '\0') pa->dev = strdup(str); if((str = cfgopt_get_str(cfg, "inject")) && str && str[0] != '\0') pa->dev_out = strdup(str); if((str = cfgopt_get_str(cfg, "readfile")) && str && str[0] != '\0') pa->fname = strdup(str); if((str = cfgopt_get_str(cfg, "writefile")) && str && str[0] != '\0') pa->fname_out = strdup(str); if((str = cfgopt_get_str(cfg, "bpf")) && str && str[0] != '\0') pa->bpf_string = strdup(str); if((cur = cfgopt_get(cfg, "snaplen")) && cur->val.num) pa->snaplen = *cur->val.num; if((cur = cfgopt_get(cfg, "promisc")) && cur->val.boolean) pa->promisc = *cur->val.boolean; } bool pcapnet_are_packets_available(pcap_args_t *pa){ if(!pa->fname && !pa->dev) return false; return true; } const u_char *pcapnet_start_network_header( int datalink, const u_char *orig_pkt, int *etype, /* modified */ size_t *len /* modified */ ){ const u_char *pkt = orig_pkt; switch(datalink){ case DLT_NULL: { if(*len < 4) return NULL; *len -= 4; pkt += 4; uint32_t x = *(const uint32_t *) pkt; if (x == PF_INET) *etype = ETHERTYPE_IP; else if(x == PF_INET6) *etype = ETHERTYPE_IPV6; break; } case DLT_LOOP: { if(*len < 4) return NULL; *len -= 4; pkt += 4; uint32_t x = my_ntohl(*(const uint32_t *) pkt); if (x == PF_INET) *etype = ETHERTYPE_IP; else if(x == PF_INET6) *etype = ETHERTYPE_IPV6; break; } case DLT_EN10MB: { if(*len < ETH_HLEN) return NULL; const struct ethhdr *ether = (const struct ethhdr *) pkt; *etype = my_ntohs(ether->type); *len -= ETH_HLEN; pkt += ETH_HLEN; if(*etype == ETHERTYPE_VLAN){ if(*len < 4) return NULL; *len -= 4; *etype = my_ntohs(*(const uint16_t *)(pkt + 2)); pkt += 4; } break; } case DLT_RAW: { if(*len < sizeof(struct iphdr)) return NULL; const struct iphdr *ip = (const struct iphdr *) pkt; if(ip->ihl == 4U){ *etype = ETHERTYPE_IP; }else if(ip->ihl == 6U){ *etype = ETHERTYPE_IPV6; }else{ return NULL; } break; } #ifdef DLT_LINUX_SLL case DLT_LINUX_SLL: { if(*len < 16) return NULL; *etype = my_ntohs(*(const uint16_t *)(pkt + 14)); *len -= 16; pkt += 16; break; } #endif } return pkt; } const u_char *pcapnet_start_transport_header( int datalink, const u_char *orig_pkt, size_t *len /* modified */, u8 *proto /* modified */ ){ int etype = 0; size_t net_len = *len; const u_char *pkt = pcapnet_start_network_header(datalink, orig_pkt, &etype, &net_len); if(!pkt) return NULL; switch(etype){ struct iphdr *ip; struct ip6hdr *ip6; case ETHERTYPE_IP: ip = (void *) pkt; if(*len < sizeof(struct iphdr) || *len < (4U * ip->ihl)) return NULL; *len -= 4 * ip->ihl; pkt += 4 * ip->ihl; *proto = ip->protocol; break; case ETHERTYPE_IPV6: ip6 = (void *) pkt; if(*len < sizeof(struct ip6hdr)) return NULL; *len -= sizeof(struct ip6hdr); pkt += sizeof(struct ip6hdr); *proto = ip6->ip6_nxt; break; default: return NULL; } switch(*proto){ case IPPROTO_TCP: if(*len < sizeof(struct tcphdr)) return NULL; case IPPROTO_UDP: if(*len < sizeof(struct udphdr)) return NULL; case IPPROTO_ICMPV6: case IPPROTO_ICMP: if(*len < ICMP_HLEN) return NULL; } return pkt; } const u_char *pcapnet_start_app_layer( int datalink, const u_char *orig_pkt, size_t *len /* modified */ ){ u8 proto; int etype = 0; size_t net_len = *len; const u_char *pkt = pcapnet_start_network_header(datalink, orig_pkt, &etype, &net_len); if(!pkt) return NULL; switch(etype){ struct iphdr *ip; struct ip6hdr *ip6; ip_header: case ETHERTYPE_IP: ip = (void *) pkt; if(*len < (unsigned) IP_MIN_HLEN || *len < (4U * ip->ihl)) return NULL; *len -= 4 * ip->ihl; pkt += 4 * ip->ihl; proto = ip->protocol; break; ipv6_header: case ETHERTYPE_IPV6: ip6 = (void *) pkt; if(*len < sizeof(struct ip6hdr)) return NULL; *len -= sizeof(struct ip6hdr); pkt += sizeof(struct ip6hdr); proto = ip6->ip6_nxt; break; default: return NULL; } switch(proto){ case IPPROTO_TCP: { struct tcphdr *tcp = (void *) pkt; if(*len < sizeof(struct tcphdr)) break; *len -= sizeof(struct tcphdr); pkt += sizeof(struct tcphdr); size_t option_octets = 4 * tcp->doff - sizeof(struct tcphdr); if(*len < option_octets) break; *len -= option_octets; pkt += option_octets; break; } case IPPROTO_UDP: if(*len < UDP_HLEN) break; *len -= UDP_HLEN; pkt += UDP_HLEN; break; case IPPROTO_ICMPV6: case IPPROTO_ICMP: if(*len < ICMP_HLEN) break; *len -= ICMP_HLEN; pkt += ICMP_HLEN; break; case IPPROTO_IPV6: goto ipv6_header; case IPPROTO_IPIP: goto ip_header; } return pkt; } void pcapnet_check_datalink_type(int dlt){ switch(dlt) { case DLT_NULL: case DLT_LOOP: case DLT_EN10MB: case DLT_RAW: #ifdef DLT_LINUX_SLL case DLT_LINUX_SLL: #endif break; default: ERROR("datalink type %s not supported", pcap_datalink_val_to_name(dlt)); } } void pcapnet_init(pcap_args_t *pa){ if(pa->dev && pa->fname) ERROR("cannot read packets from device and file simultaneously"); if(!(pa->dev || pa->fname)) ERROR("need a packet capture source"); if(pa->snaplen < 0 || pa->snaplen > 65536){ pa->snaplen = 1518; } if(pa->dev){ DEBUG("opening capture interface %s%s%s%s", pa->dev, pa->bpf_string ? " with filter '" : "", pa->bpf_string ? pa->bpf_string : "", pa->bpf_string ? "'" : "" ); pcapnet_init_device(&pa->handle, pa->dev, pa->snaplen, pa->to_ms, pa->promisc); pcapnet_init_bpf(pa); } if(pa->dev_out){ DEBUG("opening injection interface %s", pa->dev_out); if(pa->dev && strcmp(pa->dev, pa->dev_out) == 0){ pa->handle_out = pa->handle; }else{ pcapnet_init_device(&pa->handle_out, pa->dev_out, 1, 0, true); } } if(pa->fname){ pcapnet_init_file(&pa->handle, pa->fname); pcapnet_init_bpf(pa); DEBUG("reading from pcap file %s link-type %s%s%s%s", pa->fname, pcap_datalink_val_to_name(pcap_datalink(pa->handle)), pa->bpf_string ? " with filter '" : "", pa->bpf_string ? pa->bpf_string : "", pa->bpf_string ? "'" : "" ); } if(pa->fname_out){ pcapnet_init_dump(pa, pa->fname_out); } if(pa->handle){ pa->datalink = pcap_datalink(pa->handle); pcapnet_check_datalink_type(pa->datalink); } if(pa->handle_out){ pa->datalink_out = pcap_datalink(pa->handle_out); } } void pcapnet_reinit_device(pcap_args_t *pa){ if(pa->handle) pcap_close(pa->handle); pcapnet_init_device(&pa->handle, pa->dev, pa->snaplen, pa->to_ms, pa->promisc); pcapnet_init_bpf(pa); } void pcapnet_init_bpf(pcap_args_t *pa){ struct bpf_program pcap_filter; if(pa->bpf_string != NULL){ HENDEL_PCAPERR(pa->handle, pcap_compile(pa->handle, &pcap_filter, pa->bpf_string, 1, 0)); HENDEL_PCAPERR(pa->handle, pcap_setfilter(pa->handle, &pcap_filter)); pcap_freecode(&pcap_filter); } } void pcapnet_init_device(pcap_t **pcap, char *dev, int snaplen, int to_ms, bool promisc){ char pcap_errbuf[PCAP_ERRBUF_SIZE]; if(NULL == (*pcap = pcap_open_live(dev, snaplen, promisc, to_ms, pcap_errbuf))) ERROR("pcap_open_live failed: %s", pcap_errbuf); } void pcapnet_init_dump(pcap_args_t *pa, char *fname){ if(!fname) ERROR("filename is nil"); if(!pa->dumper){ if(!(pa->dumper = pcap_dump_open(pa->handle, fname))){ ERROR("pcap_dump_open: %s", pcap_geterr(pa->handle)); } }else{ ERROR("pcap dumper already initialized"); } } void pcapnet_init_dumpfd(pcap_args_t *pa, int fd){ if(!pa->dumper){ FILE *fp = fdopen(fd, "w"); if(!fp) ERROR("fdopen: %s", strerror(errno)); if(!(pa->dumper = pcap_dump_fopen(pa->handle, fp))){ ERROR("pcap_dump_fopen: %s", pcap_geterr(pa->handle)); } }else{ ERROR("pcap dumper already initialized"); } } void pcapnet_init_file(pcap_t **pcap, char *fname){ FILE *fp; char errbuf[PCAP_ERRBUF_SIZE]; if(strcmp(fname, "-") == 0) fp = fdopen(0, "r"); else fp = fopen(fname, "r"); if(fp == NULL) ERROR("f(d)open failed: %s", strerror(errno)); if(NULL == (*pcap = pcap_fopen_offline(fp, errbuf))) ERROR("pcap_fopen_offline failed: %s", errbuf); } void pcapnet_close(pcap_args_t *pa){ pcapnet_close_dump(pa); if(pa->handle_out){ pcap_close(pa->handle_out); pa->handle_out = NULL; } if(pa->handle){ pcap_close(pa->handle); pa->handle = NULL; } FREE(pa->dev); FREE(pa->dev_out); FREE(pa->fname); FREE(pa->fname_out); } void pcapnet_close_dump(pcap_args_t *pa){ if(pa->dumper){ if(pa->fname_out) DEBUG("closing pcap file %s", pa->fname_out); pcap_dump_flush(pa->dumper); pcap_dump_close(pa->dumper); pa->dumper = NULL; } } void pcapnet_packet_loop(pcap_args_t *pa, pcap_handler cb){ if(!pa || !(pa->handle)) ERROR("pcap handle not initialized"); pcap_loop(pa->handle, -1, cb, (void *)pa); } void pcapnet_break_loop(pcap_args_t *pa){ if(!pa || !(pa->handle)) ERROR("pcap handle not initialized"); pcap_breakloop(pa->handle); } void pcapnet_setup_signals(void (*sighandler)(int)){ signal(SIGINT, sighandler); signal(SIGTERM, sighandler); siginterrupt(SIGINT, 1); siginterrupt(SIGTERM, 1); } void pcapnet_print_pkt(const struct pcap_pkthdr *hdr, const u_char *pkt){ int c = 0; for(unsigned i = 0 ; i < hdr->caplen ; ++i, ++c){ if(c == 25){ c = 0; fprintf(stderr, "\n"); } fprintf(stderr, "%2.x ", pkt[i]); } } pcaputils-0.8/util/pcapnet.h000066400000000000000000000066351120140651100161460ustar00rootroot00000000000000/* Copyright (C) 2007 Robert S. Edmonds Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef PCAPNET_H #define PCAPNET_H #include #include #include #include #include #include #include #include "cfgopt.h" #include "uint.h" #include "util.h" /* macros */ #define HENDEL_PCAPERR(pcaphandle, pcapexprn) do{ \ int rc = pcapexprn; \ if(rc == -1){ \ DEBUG("pcap error [" #pcapexprn "]: %s", pcap_geterr(pcaphandle)); \ exit(EXIT_FAILURE); \ } \ }while(0) /* declarations */ #define pcapcfg_device { 'i', "device", CONFIG_STR, {}, NULL, "input interface" } #define pcapcfg_inject { 'o', "inject", CONFIG_STR, {}, NULL, "output interface" } #define pcapcfg_readfile { 'r', "readfile", CONFIG_STR, {}, NULL, "input file" } #define pcapcfg_writefile { 'w', "writefile", CONFIG_STR, {}, NULL, "output file" } #define pcapcfg_bpf { 'f', "bpf", CONFIG_STR, {}, NULL, "bpf filter" } #define pcapcfg_snaplen { 's', "snaplen", CONFIG_DEC, {}, "1518", "capture length" } #define pcapcfg_promisc { 'p', "promisc", CONFIG_BOOL, {}, "1", "disable promiscuous mode" } typedef struct pcap_args { bool promisc; char *bpf_string; char *dev; char *dev_out; char *fname; char *fname_out; int datalink; int datalink_out; int dumpfd; int snaplen; int to_ms; pcap_dumper_t *dumper; pcap_t *handle; pcap_t *handle_out; } pcap_args_t; const u_char *pcapnet_start_network_header(int datalink, const u_char *pkt, int *etype, size_t *len); const u_char *pcapnet_start_transport_header(int datalink, const u_char *pkt, size_t *len, u8 *proto); const u_char *pcapnet_start_app_layer(int datalink, const u_char *pkt, size_t *len); bool pcapnet_are_packets_available(pcap_args_t *); void pcapnet_break_loop(pcap_args_t *); void pcapnet_check_datalink_type(int dlt); void pcapnet_close(pcap_args_t *); void pcapnet_close_dump(pcap_args_t *); void pcapnet_init(pcap_args_t *); void pcapnet_init_bpf(pcap_args_t *); void pcapnet_init_device(pcap_t **, char *dev, int snaplen, int to_ms, bool promisc); void pcapnet_init_dump(pcap_args_t *, char *fname); void pcapnet_init_dumpfd(pcap_args_t *, int fd); void pcapnet_init_file(pcap_t **, char *fname); void pcapnet_load_cfg(pcap_args_t *, cfgopt_t *); void pcapnet_packet_loop(pcap_args_t *, pcap_handler cb); void pcapnet_print_pkt(const struct pcap_pkthdr *, const u_char *); void pcapnet_reinit_device(pcap_args_t *); void pcapnet_setup_signals(void (*sighandler)(int)); #endif pcaputils-0.8/util/rate.c000066400000000000000000000025171120140651100154350ustar00rootroot00000000000000#include #include #include #include #include rate_t *rate_new(int call_rate){ rate_t *r; NEW0(r); r->call_rate = call_rate; r->gtod_rate = call_rate / 10; r->sleep_rate = call_rate / 100; r->ts.tv_sec = 0; r->ts.tv_nsec = 4E6; if(r->gtod_rate == 0) r->gtod_rate = 1; if(r->sleep_rate == 0) r->sleep_rate = 1; gettimeofday(&r->tv[0], NULL); return r; } void rate_free(rate_t **r){ FREE(*r); } void rate_call(rate_t *r, void (fn)(void *), void *data){ (r->call_no)++; (r->call_no_last)++; if(unlikely(r->call_no % r->sleep_rate == 0)){ nanosleep(&r->ts, NULL); } if(unlikely(r->call_no % r->gtod_rate == 0)){ gettimeofday(&r->tv[1], NULL); double d0 = r->tv[0].tv_sec + r->tv[0].tv_usec / 1E6; double d1 = r->tv[1].tv_sec + r->tv[1].tv_usec / 1E6; r->cur_rate = ((int) (r->call_no_last / (d1 - d0))); if(abs(r->cur_rate - r->call_rate) > 10){ if(r->cur_rate - r->call_rate > 0){ if(r->sleep_rate > 1){ int d = r->sleep_rate / 10; r->sleep_rate -= (d > 1 ? d : 1); VERBOSE("sleep_rate=%d", r->sleep_rate); } }else if (r->sleep_rate < 1E6){ int d = r->sleep_rate / 10; r->sleep_rate += (d > 1 ? d : 1); VERBOSE("sleep_rate=%d", r->sleep_rate); } } r->call_no_last = 0; r->tv[0] = r->tv[1]; } if(fn) fn(data); } pcaputils-0.8/util/rate.h000066400000000000000000000006141120140651100154360ustar00rootroot00000000000000#ifndef RATE_H #define RATE_H #include #include #include typedef struct rate { unsigned call_no; int call_no_last; int call_rate; int gtod_rate; int sleep_rate; int cur_rate; struct timeval tv[2]; struct timespec ts; } rate_t; rate_t *rate_new(int call_rate); void rate_free(rate_t **); void rate_call(rate_t *, void (fn)(void *), void *data); #endif pcaputils-0.8/util/ring.c000066400000000000000000000110361120140651100154350ustar00rootroot00000000000000/* * Portable Audio I/O Library * Ring Buffer utility. * * Author: Phil Burk, http://www.softsynth.com * modified for SMP safety on Mac OS X by Bjorn Roche * modified for SMP safety on Linux by Leland Lucius * also, allowed for const where possible * * Note that this is safe only for a single-thread reader and a * single-thread writer. * * Copyright (c) 1999-2000 Ross Bencina and Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* derived from http://www.portaudio.com/trac/browser/portaudio/branches/v19-devel/src/common/pa_ringbuffer.c */ #include #include #include #include #include "ring.h" #include "util.h" ring_t *ring_new(size_t sz){ ring_t *rbuf = NULL; if( ((sz - 1) & sz) == 0){ NEW0(rbuf); MALLOC(rbuf->buffer, sz); rbuf->buffer_size = sz; ring_flush(rbuf); rbuf->big_mask = (2 * sz) - 1; rbuf->small_mask = sz - 1; }else{ ERROR("sz=%zd is not a power of 2", sz); } return rbuf; } size_t ring_read_bytes_avail(ring_t *rbuf){ ring_rmb(); return ( (rbuf->write_idx - rbuf->read_idx) & rbuf->big_mask ); } size_t ring_write_bytes_avail(ring_t *rbuf){ return rbuf->buffer_size - ring_read_bytes_avail(rbuf); } void ring_flush(ring_t *rbuf){ rbuf->write_idx = rbuf->read_idx = 0; } size_t ring_get_write_regions(ring_t *rbuf, size_t sz, void **dataPtr1, size_t *sizePtr1, void **dataPtr2, size_t *sizePtr2){ size_t index; size_t available = ring_write_bytes_avail(rbuf); if(sz > available) sz = available; index = rbuf->write_idx & rbuf->small_mask; if((index + sz) > rbuf->buffer_size) { size_t first_half = rbuf->buffer_size - index; *dataPtr1 = &rbuf->buffer[index]; *sizePtr1 = first_half; *dataPtr2 = &rbuf->buffer[0]; *sizePtr2 = sz - first_half; } else { *dataPtr1 = &rbuf->buffer[index]; *sizePtr1 = sz; *dataPtr2 = NULL; *sizePtr2 = 0; } return sz; } size_t ring_advance_write_idx(ring_t *rbuf, size_t sz){ ring_wmb(); return rbuf->write_idx = (rbuf->write_idx + sz) & rbuf->big_mask; } size_t ring_get_read_regions(ring_t *rbuf, size_t sz, void **dataPtr1, size_t *sizePtr1, void **dataPtr2, size_t *sizePtr2){ size_t index; size_t available = ring_read_bytes_avail(rbuf); if(sz > available) sz = available; index = rbuf->read_idx & rbuf->small_mask; if((index + sz) > rbuf->buffer_size) { size_t first_half = rbuf->buffer_size - index; *dataPtr1 = &rbuf->buffer[index]; *sizePtr1 = first_half; *dataPtr2 = &rbuf->buffer[0]; *sizePtr2 = sz - first_half; } else { *dataPtr1 = &rbuf->buffer[index]; *sizePtr1 = sz; *dataPtr2 = NULL; *sizePtr2 = 0; } return sz; } size_t ring_advance_read_idx(ring_t *rbuf, size_t sz){ ring_wmb(); return rbuf->read_idx = (rbuf->read_idx + sz) & rbuf->big_mask; } size_t ring_write(ring_t *rbuf, const void *data, size_t sz){ size_t size1, size2, num_written; void *data1, *data2; num_written = ring_get_write_regions(rbuf, sz, &data1, &size1, &data2, &size2); if(size2 > 0) { memcpy(data1, data, size1); data = ((char *) data) + size1; memcpy(data2, data, size2); } else { memcpy(data1, data, size1); } ring_advance_write_idx(rbuf, num_written); return num_written; } size_t ring_read(ring_t *rbuf, void *data, size_t sz){ size_t size1, size2, num_read; void *data1, *data2; num_read = ring_get_read_regions(rbuf, sz, &data1, &size1, &data2, &size2); if(size2 > 0) { memcpy(data, data1, size1); data = ((char *)data) + size1; memcpy(data, data2, size2); } else { memcpy(data, data1, size1); } ring_advance_read_idx(rbuf, num_read); return num_read; } pcaputils-0.8/util/ring.h000066400000000000000000000064361120140651100154520ustar00rootroot00000000000000#ifndef PA_RINGBUFFER_H #define PA_RINGBUFFER_H /* * Portable Audio I/O Library * Ring Buffer utility. * * Author: Phil Burk, http://www.softsynth.com * modified for SMP safety on OS X by Bjorn Roche. * also allowed for const where possible. * * Note that this is safe only for a single-thread reader * and a single-thread writer. * * This program is distributed with the PortAudio Portable Audio Library. * For more information see: http://www.portaudio.com * Copyright (c) 1999-2000 Ross Bencina and Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* derived from http://www.portaudio.com/trac/browser/portaudio/branches/v19-devel/src/common/pa_ringbuffer.h */ #include #if defined(__GNUC__) # if defined(__PPC__) # define ring_fmb() asm volatile("sync":::"memory") # define ring_rmb() asm volatile("sync":::"memory") # define ring_wmb() asm volatile("sync":::"memory") # elif defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) || defined(__x86_64__) # define ring_fmb() asm volatile("mfence":::"memory") # define ring_rmb() asm volatile("lfence":::"memory") # define ring_wmb() asm volatile("sfence":::"memory") # elif (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) # define ring_fmb() __sync_synchronize() # define ring_rmb() __sync_synchronize() # define ring_wmb() __sync_synchronize() # else # define ring_fmb() # define ring_rmb() # define ring_wmb() # endif #endif typedef struct ring { size_t buffer_size; size_t write_idx; size_t read_idx; size_t big_mask; size_t small_mask; char *buffer; } ring_t; ring_t *ring_new(size_t sz); size_t ring_advance_read_idx(ring_t *rbuf, size_t sz); size_t ring_advance_write_idx(ring_t *rbuf, size_t sz); size_t ring_get_read_regions(ring_t *rbuf, size_t sz, void **dataPtr1, size_t *sizePtr1, void **dataPtr2, size_t *sizePtr2); size_t ring_get_write_regions(ring_t *rbuf, size_t sz, void **dataPtr1, size_t *sizePtr1, void **dataPtr2, size_t *sizePtr2); size_t ring_read(ring_t *rbuf, void *data, size_t sz); size_t ring_read_bytes_avail(ring_t *rbuf); size_t ring_write(ring_t *rbuf, const void *data, size_t sz); size_t ring_write_bytes_avail(ring_t *rbuf); void ring_flush(ring_t *rbuf); #endif pcaputils-0.8/util/rng.c000066400000000000000000000036011120140651100152630ustar00rootroot00000000000000/* rng.c - randomization functions Copyright (C) 2008 Robert S. Edmonds Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include #include "rng.h" #include "util.h" void rng_seed(bool secure){ char *dev; int fd; unsigned seed; if(secure) dev = "/dev/random"; else dev = "/dev/urandom"; if((fd = open(dev, O_RDONLY)) != -1){ if(read(fd, &seed, sizeof(seed)) != sizeof(seed)) ERROR("unable to read %u bytes from %s", (unsigned) sizeof(seed), dev); }else{ ERROR("unable to open %s for reading: %s", dev, strerror(errno)); } srandom(seed); close(fd); } int rng_randint(int min, int max){ return (int) (((double) (max - min + 1)) * (rand() / (RAND_MAX + ((double) min)))); } pcaputils-0.8/util/rng.h000066400000000000000000000002301120140651100152630ustar00rootroot00000000000000#ifndef RSEUTIL_RNG_H #define RSEUTIL_RNG_H #include extern void rng_seed(bool secure); extern int rng_randint(int min, int max); #endif pcaputils-0.8/util/scanfmt.c000066400000000000000000000137351120140651100161410ustar00rootroot00000000000000#include #include "socket.h" #include "scanfmt.h" unsigned fmt_mac(char *s, const char mac[6]){ unsigned i; unsigned len = 0; i = fmt_xlong(s, (unsigned long) (unsigned char) mac[0]); len += i; if(s) s += i; if(s) *s++ = ':'; ++len; i = fmt_xlong(s, (unsigned long) (unsigned char) mac[1]); len += i; if(s) s += i; if(s) *s++ = ':'; ++len; i = fmt_xlong(s, (unsigned long) (unsigned char) mac[2]); len += i; if(s) s += i; if(s) *s++ = ':'; ++len; i = fmt_xlong(s, (unsigned long) (unsigned char) mac[3]); len += i; if(s) s += i; if(s) *s++ = ':'; ++len; i = fmt_xlong(s, (unsigned long) (unsigned char) mac[4]); len += i; if(s) s += i; if(s) *s++ = ':'; ++len; i = fmt_xlong(s, (unsigned long) (unsigned char) mac[5]); len += i; if(s) s += i; *s = '\0'; return len; } unsigned scan_mac(const char *s, char mac[6]){ const char *tmp = s; unsigned len = 0; unsigned pos = 0; while(isxdigit(*tmp)){ mac[pos] = ((char) scan_fromhex(*tmp)) << 4 | ((char) scan_fromhex(*(tmp + 1))); ++pos; ++len; tmp += 2; if(*tmp == ':' || *tmp == '-' || *tmp == '.') ++tmp; } return len; } /* derived from public domain djbdns code */ unsigned fmt_ulong(char *s, unsigned long u) { unsigned len; unsigned long q; len = 1; q = u; while (q > 9) { ++len; q /= 10; } if (s) { s += len; do { *--s = '0' + (u % 10); u /= 10; } while(u); /* handles u == 0 */ } return len; } unsigned scan_ulong(const char *s, unsigned long *u) { unsigned pos = 0; unsigned long result = 0; unsigned long c; while ((c = (unsigned long) (unsigned char) (s[pos] - '0')) < 10) { result = result * 10 + c; ++pos; } *u = result; return pos; } unsigned fmt_xlong(char *s, unsigned long u) { unsigned len; unsigned long q; char c; len = 1; q = u; while (q > 15) { ++len; q /= 16; } if (s) { s += len; do { c = '0' + (u & 15); if (c > '0' + 9) c += 'a' - '0' - 10; *--s = c; u /= 16; } while(u); } return len; } unsigned scan_xlong(const char *src, unsigned long *dest) { const char *tmp=src; unsigned long l=0; unsigned char c; while ((c = (char) scan_fromhex(*tmp))<16) { l=(l<<4)+c; ++tmp; } *dest=l; return tmp-src; } int scan_fromhex(unsigned char c) { c-='0'; if (c<=9) return c; c&=~0x20; c-='A'-'0'; if (c<6) return c+10; return -1; } unsigned fmt_ip4(char *s,const char ip[4]) { unsigned i; unsigned len = 0; i = fmt_ulong(s,(unsigned long) (unsigned char) ip[0]); len += i; if (s) s += i; if (s) *s++ = '.'; ++len; i = fmt_ulong(s,(unsigned long) (unsigned char) ip[1]); len += i; if (s) s += i; if (s) *s++ = '.'; ++len; i = fmt_ulong(s,(unsigned long) (unsigned char) ip[2]); len += i; if (s) s += i; if (s) *s++ = '.'; ++len; i = fmt_ulong(s,(unsigned long) (unsigned char) ip[3]); len += i; if (s) s += i; *s = '\0'; return len; } unsigned scan_ip4(const char *s, char ip[4]) { unsigned i; unsigned len; unsigned long u; len = 0; i = scan_ulong(s,&u); if (!i) return 0; ip[0] = u; s += i; len += i; if (*s != '.') return 0; ++s; ++len; i = scan_ulong(s,&u); if (!i) return 0; ip[1] = u; s += i; len += i; if (*s != '.') return 0; ++s; ++len; i = scan_ulong(s,&u); if (!i) return 0; ip[2] = u; s += i; len += i; if (*s != '.') return 0; ++s; ++len; i = scan_ulong(s,&u); if (!i) return 0; ip[3] = u; s += i; len += i; return len; } /* functions from libowfat */ /* Copyright (c) 2001 Felix von Leitner. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License Version 2 as published by the Free Software Foundation. */ unsigned fmt_ip6(char *s, const char ip[16]) { unsigned long len,temp, k, pos0=0,len0=0, pos1=0, compr=0; for (k=0; k<16; k+=2) { if (ip[k]==0 && ip[k+1]==0) { if (!compr) { compr=1; pos1=k; } if (k==14) { k=16; goto last; } } else if (compr) { last: if ((temp=k-pos1) > len0) { len0=temp; pos0=pos1; } compr=0; } } for (len=0,k=0; k<16; k+=2) { if (k==12 && ip6_isv4mapped(ip)) { len += fmt_ip4(s,ip+12); break; } if (pos0==k && len0) { if (k==0) { ++len; if (s) *s++ = ':'; } ++len; if (s) *s++ = ':'; k += len0-2; continue; } temp = ((unsigned long) (unsigned char) ip[k] << 8) + (unsigned long) (unsigned char) ip[k+1]; temp = fmt_xlong(s,temp); len += temp; if (s) s += temp; if (k<14) { ++len; if (s) *s++ = ':'; } } *s = '\0'; return len; } unsigned scan_ip6(const char *s, char ip[16]) { unsigned i; unsigned len=0; unsigned long u; char suffix[16]; unsigned prefixlen=0; unsigned suffixlen=0; if ((i=scan_ip4(s,ip+12))) { for (len=0; len<12; ++len) ip[len]=V4mappedprefix[len]; return i; } for (i=0; i<16; i++) ip[i]=0; for (;;) { if (*s == ':') { ++len; ++s; if (*s == ':') { /* Found "::", skip to part 2 */ ++len; ++s; break; } } i = scan_xlong(s,&u); if (!i) return 0; if (prefixlen==12 && s[i]=='.') { /* the last 4 bytes may be written as IPv4 address */ i=scan_ip4(s,ip+12); if (i) return i+len; else return 0; } ip[prefixlen++] = (u >> 8); ip[prefixlen++] = (u & 255); s += i; len += i; if (prefixlen==16) return len; } /* part 2, after "::" */ for (;;) { if (*s == ':') { if (suffixlen==0) break; s++; len++; } else if (suffixlen) break; i = scan_xlong(s,&u); if (!i) { if (suffixlen) --len; break; } if (suffixlen+prefixlen<=12 && s[i]=='.') { int j=scan_ip4(s,suffix+suffixlen); if (j) { suffixlen+=4; len+=j; break; } else prefixlen=12-suffixlen; /* make end-of-loop test true */ } suffix[suffixlen++] = (u >> 8); suffix[suffixlen++] = (u & 255); s += i; len += i; if (prefixlen+suffixlen==16) break; } for (i=0; i= 0){ if(socket_bind6_reuse(fd, ip6, port, 0) == -1){ close(fd); fd = socket_tcp(); if(fd >= 0){ if(-1 == socket_bind4_reuse(fd, ip, port)) ERROR("unable to create server socket: %s", strerror(errno)); else{ fmt_ip4(sip, ip); DEBUG("bound TCP socket on %s:%hu", sip, port); } }else{ ERROR("unable to create TCP socket: %s", strerror(errno)); } }else{ fmt_ip6(sip, ip6); DEBUG("bound TCP socket on [%s]:%hu", sip, port); } if(socket_listen(fd, backlog) == -1) ERROR("listen() failed: %s", strerror(errno)); }else{ ERROR("unable to create TCP socket: %s", strerror(errno)); } return fd; } int setup_udp_server_socket(const char ip[4], const char ip6[16], u16 port){ char sip[FMT_IP6]; int fd; fd = socket_udp6(); if(fd >= 0){ if(socket_bind6(fd, ip6, port, 0) == -1){ close(fd); fd = socket_udp(); if(socket_bind4(fd, ip, port) == -1){ ERROR("unable to create server socket: %s", strerror(errno)); }else{ fmt_ip4(sip, ip); DEBUG("bound UDP socket on %s:%hu", sip, port); } }else{ fmt_ip6(sip, ip6); DEBUG("bound UDP socket on [%s]:%hu", sip, port); } }else{ ERROR("unable to create UDP socket: %s", strerror(errno)); } return fd; } pcaputils-0.8/util/server.h000066400000000000000000000004271120140651100160130ustar00rootroot00000000000000#ifndef RSEUTIL_SERVER_H #define RSEUTIL_SERVER_H #include "socket.h" #include "uint.h" extern int setup_tcp_server_socket(const char ip[4], const char ip6[16], u16 port, int backlog); extern int setup_udp_server_socket(const char ip[4], const char ip6[16], u16 port); #endif pcaputils-0.8/util/socket.c000066400000000000000000000107411120140651100157700ustar00rootroot00000000000000#include #include #include #include #include #include #include "byte.h" #include "socket.h" #include "uint.h" /* from libowfat */ /* Copyright (c) 2001 Felix von Leitner. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License Version 2 as published by the Free Software Foundation. */ const char V4any[4]={0,0,0,0}; const char V4loopback[4]={127,0,0,1}; const char V4mappedprefix[12]={0,0,0,0,0,0,0,0,0,0,0xff,0xff}; const char V6loopback[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}; const char V6any[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; int socket_tcp6(void){ int s; s = socket(PF_INET6, SOCK_STREAM, 0); if(s == -1 && errno == EINVAL) s = socket(PF_INET, SOCK_STREAM, 0); return s; } int socket_tcp(void){ int s; s = socket(PF_INET, SOCK_STREAM, 0); if (s == -1) return -1; return s; } int socket_bind6(int s, const char ip[16], u16 port, u32 scope_id){ struct sockaddr_in6 sa; byte_zero(&sa, sizeof sa); sa.sin6_family = AF_INET6; u16_pack_big((char *) &sa.sin6_port, port); /* implicit: sa.sin6_flowinfo = 0; */ byte_copy((char *) &sa.sin6_addr, 16, ip); sa.sin6_scope_id = scope_id; return bind(s, (struct sockaddr *) &sa, sizeof sa); } int socket_bind6_reuse(int s, const char ip[16], u16 port, u32 scope_id){ int opt = 1; setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof opt); return socket_bind6(s, ip, port, scope_id); } int socket_listen(int s, unsigned backlog){ return listen(s, backlog); } int socket_accept6(int s, char ip[16], u16 *port, u32 *scope_id){ struct sockaddr_in6 sa; unsigned dummy = sizeof sa; int fd; fd = accept(s, (struct sockaddr *) &sa, &dummy); if(fd == -1) return -1; if(sa.sin6_family == AF_INET) { struct sockaddr_in *sa4 = (struct sockaddr_in *) &sa; byte_copy(ip, 12, V4mappedprefix); byte_copy(ip + 12, 4, (char *) &sa4->sin_addr); u16_unpack_big((char *) &sa4->sin_port, port); return fd; } byte_copy(ip, 16, (char *) &sa.sin6_addr); u16_unpack_big((char *) &sa.sin6_port, port); if(scope_id) *scope_id = sa.sin6_scope_id; return fd; } int socket_recv6(int s, char *buf, unsigned len, char ip[16], u16 *port, u32 *scope_id){ struct sockaddr_in6 sa; unsigned int dummy = sizeof sa; int r; byte_zero(&sa, dummy); r = recvfrom(s, buf, len, 0, (struct sockaddr *) &sa, &dummy); if(r == -1) return -1; byte_copy(ip, 16, (char *) &sa.sin6_addr); u16_unpack_big((char *) &sa.sin6_port, port); if(scope_id) *scope_id = sa.sin6_scope_id; return r; } int socket_bind4(int s, const char ip[4], u16 port){ struct sockaddr_in sa; byte_zero(&sa, sizeof sa); sa.sin_family = AF_INET; u16_pack_big((char *) &sa.sin_port,port); byte_copy((char *) &sa.sin_addr, 4, ip); return bind(s, (struct sockaddr *) &sa, sizeof sa); } int socket_bind4_reuse(int s, const char ip[4], u16 port){ int opt = 1; setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof opt); return socket_bind4(s, ip, port); } int socket_connect4(int s, const char ip[4], u16 port){ struct sockaddr_in sa; byte_zero(&sa, sizeof sa); sa.sin_family = AF_INET; u16_pack_big((char *) &sa.sin_port, port); byte_copy((char *) &sa.sin_addr, 4, ip); return connect(s, (struct sockaddr *) &sa, sizeof sa); } int socket_connect6(int s, const char ip[16], u16 port, u32 scope_id){ struct sockaddr_in6 sa; byte_zero(&sa, sizeof sa); sa.sin6_family = PF_INET6; u16_pack_big((char *) &sa.sin6_port, port); sa.sin6_flowinfo = 0; sa.sin6_scope_id = scope_id; byte_copy((char *) &sa.sin6_addr, 16, ip); return connect(s, (struct sockaddr *) &sa, sizeof sa); } int socket_udp6(void){ int s; s = socket(PF_INET6, SOCK_DGRAM, 0); if(s == -1){ if(errno == EINVAL) s = socket(PF_INET, SOCK_DGRAM, 0); } return s; } int socket_udp(void){ return socket(PF_INET, SOCK_DGRAM, 0); } int socket_send4(int s, const char *buf, int len, const char ip[4], u16 port){ struct sockaddr_in sa; byte_zero(&sa, sizeof(sa)); sa.sin_family = AF_INET; u16_pack_big((char *) &sa.sin_port, port); byte_copy((char *) &sa.sin_addr, 4, ip); return sendto(s, buf, len, 0, (struct sockaddr *) &sa, sizeof(sa)); } int socket_recv4(int s, char *buf, int len, char ip[4], u16 *port){ struct sockaddr_in sa; socklen_t dummy = sizeof(sa); int r; r = recvfrom(s, buf, len, 0, (struct sockaddr *) &sa, &dummy); if(r == -1) return -1; byte_copy(ip, 4, (char *) &sa.sin_addr); u16_unpack_big((char *) &sa.sin_port, port); return r; } pcaputils-0.8/util/socket.h000066400000000000000000000025211120140651100157720ustar00rootroot00000000000000#ifndef RSEUTIL_SOCKET_H #define RSEUTIL_SOCKET_H #include #include #include "byte.h" #include "uint.h" extern const char V4any[4]; extern const char V4loopback[4]; extern const char V4mappedprefix[12]; extern const char V6loopback[16]; extern const char V6any[16]; #define ip6_isv4mapped(ip) (byte_equal(ip,12,V4mappedprefix)) extern int socket_accept6(int s, char *ip, u16 *port, u32 *scope_id); extern int socket_bind4(int s, const char *ip, u16); extern int socket_bind4_reuse(int s, const char *ip, u16); extern int socket_bind6(int s, const char *ip, u16 port, u32 scope_id); extern int socket_bind6_reuse(int s, const char *ip, u16 port, u32 scope_id); extern int socket_connect4(int s, const char *ip, u16 port); extern int socket_connect6(int s, const char *ip, u16 port, u32 scope_id); extern int socket_listen(int s, unsigned backlog); extern int socket_recv4(int s, char *buf, int len, char ip[4], u16 *port); extern int socket_recv6(int s, char *buf, unsigned len, char *ip, u16 *port, u32 *scope_id); extern int socket_send4(int s, const char *buf, int len, const char ip[4], u16 port); extern int socket_send6(int s, const char *buf, unsigned len, const char *ip, u16 port, u32 scope_id); extern int socket_tcp(void); extern int socket_tcp6(void); extern int socket_udp(void); extern int socket_udp6(void); #endif pcaputils-0.8/util/uint.c000066400000000000000000000026411120140651100154570ustar00rootroot00000000000000#include "uint.h" /* derived from public domain djbdns code */ void u16_pack(char s[2], u16 u) { s[0] = (char) (u & 255); s[1] = (char) (u >> 8); } void u16_pack_big(char s[2], u16 u) { s[1] = (char) (u & 255); s[0] = (char) (u >> 8); } void u16_unpack(const char s[2], u16 *u) { u16 result; result = (unsigned char) s[1]; result <<= 8; result += (unsigned char) s[0]; *u = result; } void u16_unpack_big(const char s[2], u16 *u) { u16 result; result = (unsigned char) s[0]; result <<= 8; result += (unsigned char) s[1]; *u = result; } void u32_pack(char s[4], u32 u) { s[0] = (char) (u & 255); u >>= 8; s[1] = (char) (u & 255); u >>= 8; s[2] = (char) (u & 255); s[3] = (char) (u >> 8); } void u32_pack_big(char s[4], u32 u) { s[3] = (char) (u & 255); u >>= 8; s[2] = (char) (u & 255); u >>= 8; s[1] = (char) (u & 255); s[0] = (char) (u >> 8); } void u32_unpack(const char s[4], u32 *u) { u32 result; result = (unsigned char) s[3]; result <<= 8; result += (unsigned char) s[2]; result <<= 8; result += (unsigned char) s[1]; result <<= 8; result += (unsigned char) s[0]; *u = result; } void u32_unpack_big(const char s[4], u32 *u) { u32 result; result = (unsigned char) s[0]; result <<= 8; result += (unsigned char) s[1]; result <<= 8; result += (unsigned char) s[2]; result <<= 8; result += (unsigned char) s[3]; *u = result; } pcaputils-0.8/util/uint.h000066400000000000000000000011351120140651100154610ustar00rootroot00000000000000#ifndef RSEUTIL_UINT_H #define RSEUTIL_UINT_H #include #include typedef int8_t i8; typedef int16_t i16; typedef int32_t i32; typedef int64_t i64; typedef uint8_t u8; typedef uint16_t u16; typedef uint32_t u32; typedef uint64_t u64; extern void u16_pack(char *, u16); extern void u16_pack_big(char *, u16); extern void u16_unpack(const char *, u16 *); extern void u16_unpack_big(const char *, u16 *); extern void u32_pack(char *, u32); extern void u32_pack_big(char *, u32); extern void u32_unpack(const char *, u32 *); extern void u32_unpack_big(const char *, u32 *); #endif pcaputils-0.8/util/util.c000066400000000000000000000007041120140651100154530ustar00rootroot00000000000000#include #include #include #include #include #include bool util_flag_daemonized; bool util_flag_verbose; void util_print_backtrace(int x __unused){ #define NFRAMES 32 int nptrs; void *buf[NFRAMES]; fprintf(stderr, "what? alarms?! good lord, we're under electronic attack!\n"); nptrs = backtrace(buf, NFRAMES); backtrace_symbols_fd(buf, nptrs, STDERR_FILENO); abort(); } pcaputils-0.8/util/util.h000066400000000000000000000046451120140651100154700ustar00rootroot00000000000000#ifndef RSEUTIL_UTIL_H #define RSEUTIL_UTIL_H #include #include #include #include #include #include extern bool util_flag_daemonized; extern bool util_flag_verbose; /* macros */ #define DEBUG(format, ...) do{ \ if(util_flag_daemonized) syslog(LOG_DAEMON | LOG_DEBUG, "%s] " format, __func__, ## __VA_ARGS__); \ else fprintf(stderr, "%s] " format "\n", __func__, ## __VA_ARGS__); \ }while(0) #define ERROR(format, ...) do{ \ DEBUG("Error: " format, ## __VA_ARGS__); \ exit(EXIT_FAILURE); \ }while(0) #define VERBOSE(format, ...) do{ \ if(util_flag_verbose) DEBUG(format, ## __VA_ARGS__); \ }while(0) #define MALLOC(target, size) do{ \ target = malloc(size); \ if(target == NULL){ \ DEBUG("malloc() failed, aborting"); \ abort(); \ } \ }while(0) #define CALLOC(target, size) do{ \ target = calloc(1, size); \ if(target == NULL){ \ DEBUG("calloc() failed, aborting"); \ abort(); \ } \ }while(0) #define REALLOC(target, size) do { \ target = realloc(target, size); \ if(target == NULL){ \ DEBUG("realloc() failed, aborting"); \ abort(); \ } \ }while(0) #define NEW(target) do{ \ target = malloc(sizeof(*target)); \ if(target == NULL){ \ DEBUG("malloc() failed, aborting"); \ abort(); \ } \ }while(0) #define NEW0(target) do{ \ target = calloc(1, sizeof(*target)); \ if(target == NULL){ \ DEBUG("malloc() failed, aborting"); \ abort(); \ } \ }while(0) #define FREE(target) do{ \ if(target){ \ free(target); \ target = NULL; \ } \ }while(0) #define Chdir(dir) do{ \ if(chdir(dir) != 0) ERROR("unable to chdir(%s): %s", dir, strerror(errno)); \ }while(0) #define Chroot(dir) do{ \ if(chroot(dir) != 0) ERROR("unable to chroot(%s): %s", dir, strerror(errno)); \ }while(0) #define ZERO(target) memset(&target, 0, sizeof(target)); /* General-purpose swap macro from http://www.spinellis.gr/blog/20060130/index.html */ #define SWAP(a, b) do{\ char c[sizeof(a)]; \ memcpy((void *)&c, (void *)&a, sizeof(c)); \ memcpy((void *)&a, (void *)&b, sizeof(a)); \ memcpy((void *)&b, (void *)&c, sizeof(b)); \ }while(0) #define likely(x) __builtin_expect((x), 1) #define unlikely(x) __builtin_expect((x), 0) #if __GNUC__ >= 3 # define __unused __attribute__((unused)) #else # define __unused #endif #if __GNUC_GNU_INLINE__ # define __inline inline __attribute__((gnu_inline)) #else # define __inline inline #endif void util_print_backtrace(int); #endif