pax_global_header 0000666 0000000 0000000 00000000064 11201406511 0014501 g ustar 00root root 0000000 0000000 52 comment=c105b8147ca0ff70268165633a2a9473cc7d3679
pcaputils-0.8/ 0000775 0000000 0000000 00000000000 11201406511 0013354 5 ustar 00root root 0000000 0000000 pcaputils-0.8/.gitignore 0000664 0000000 0000000 00000000104 11201406511 0015337 0 ustar 00root root 0000000 0000000 *.d
*.o
src/pcapdump
src/pcapip
src/pcappick
src/pcapuc
util/util.a
pcaputils-0.8/Makefile 0000664 0000000 0000000 00000001644 11201406511 0015021 0 ustar 00root root 0000000 0000000 ### 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.mk 0000664 0000000 0000000 00000000657 11201406511 0015007 0 ustar 00root root 0000000 0000000 # 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/ 0000775 0000000 0000000 00000000000 11201406511 0014121 5 ustar 00root root 0000000 0000000 pcaputils-0.8/doc/LICENSE 0000664 0000000 0000000 00000002045 11201406511 0015127 0 ustar 00root root 0000000 0000000 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.
pcaputils-0.8/doc/Makefile 0000664 0000000 0000000 00000000221 11201406511 0015554 0 ustar 00root root 0000000 0000000 MAN = 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.docbook 0000664 0000000 0000000 00000010215 11201406511 0017273 0 ustar 00root root 0000000 0000000
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.docbook 0000664 0000000 0000000 00000002223 11201406511 0016736 0 ustar 00root root 0000000 0000000
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.docbook 0000664 0000000 0000000 00000002710 11201406511 0017115 0 ustar 00root root 0000000 0000000
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.docbook 0000664 0000000 0000000 00000002233 11201406511 0017255 0 ustar 00root root 0000000 0000000
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.docbook 0000664 0000000 0000000 00000003715 11201406511 0016744 0 ustar 00root root 0000000 0000000
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/ 0000775 0000000 0000000 00000000000 11201406511 0014143 5 ustar 00root root 0000000 0000000 pcaputils-0.8/src/Rules.mk 0000664 0000000 0000000 00000002101 11201406511 0015560 0 ustar 00root root 0000000 0000000 # 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.c 0000664 0000000 0000000 00000026126 11201406511 0016127 0 ustar 00root root 0000000 0000000 /*
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.c 0000664 0000000 0000000 00000007370 11201406511 0015572 0 ustar 00root root 0000000 0000000 /*
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.c 0000664 0000000 0000000 00000005367 11201406511 0016114 0 ustar 00root root 0000000 0000000 /*
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.c 0000664 0000000 0000000 00000013310 11201406511 0015560 0 ustar 00root root 0000000 0000000 /*
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/ 0000775 0000000 0000000 00000000000 11201406511 0014331 5 ustar 00root root 0000000 0000000 pcaputils-0.8/util/Rules.mk 0000664 0000000 0000000 00000001221 11201406511 0015750 0 ustar 00root root 0000000 0000000 # 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.c 0000664 0000000 0000000 00000003207 11201406511 0015442 0 ustar 00root root 0000000 0000000 #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.h 0000664 0000000 0000000 00000000677 11201406511 0015457 0 ustar 00root root 0000000 0000000 #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.c 0000664 0000000 0000000 00000022247 11201406511 0015766 0 ustar 00root root 0000000 0000000 /*
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.h 0000664 0000000 0000000 00000003214 11201406511 0015764 0 ustar 00root root 0000000 0000000 #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.c 0000664 0000000 0000000 00000003035 11201406511 0016300 0 ustar 00root root 0000000 0000000 #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.h 0000664 0000000 0000000 00000000323 11201406511 0016302 0 ustar 00root root 0000000 0000000 #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.c 0000664 0000000 0000000 00000004157 11201406511 0015747 0 ustar 00root root 0000000 0000000 /*
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.h 0000664 0000000 0000000 00000000427 11201406511 0015750 0 ustar 00root root 0000000 0000000 #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.c 0000664 0000000 0000000 00000003673 11201406511 0015425 0 ustar 00root root 0000000 0000000 /*
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.h 0000664 0000000 0000000 00000000577 11201406511 0015432 0 ustar 00root root 0000000 0000000 #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.c 0000664 0000000 0000000 00000006745 11201406511 0015277 0 ustar 00root root 0000000 0000000 /*
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.h 0000664 0000000 0000000 00000013147 11201406511 0015276 0 ustar 00root root 0000000 0000000 #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.c 0000664 0000000 0000000 00000025362 11201406511 0016137 0 ustar 00root root 0000000 0000000 /*
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.h 0000664 0000000 0000000 00000006635 11201406511 0016146 0 ustar 00root root 0000000 0000000 /*
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.c 0000664 0000000 0000000 00000002517 11201406511 0015435 0 ustar 00root root 0000000 0000000 #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.h 0000664 0000000 0000000 00000000614 11201406511 0015436 0 ustar 00root root 0000000 0000000 #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.c 0000664 0000000 0000000 00000011036 11201406511 0015435 0 ustar 00root root 0000000 0000000 /*
* 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.h 0000664 0000000 0000000 00000006436 11201406511 0015452 0 ustar 00root root 0000000 0000000 #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.c 0000664 0000000 0000000 00000003601 11201406511 0015263 0 ustar 00root root 0000000 0000000 /*
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.h 0000664 0000000 0000000 00000000230 11201406511 0015263 0 ustar 00root root 0000000 0000000 #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.c 0000664 0000000 0000000 00000013735 11201406511 0016141 0 ustar 00root root 0000000 0000000 #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