ext/pcap/Pcap.c in ruby-pcap-0.7.9 vs ext/pcap/Pcap.c in ruby-pcap-0.8.0

- old
+ new

@@ -5,11 +5,10 @@ * * Copyright (C) 1998-2000 Masaki Fukushima */ #include "ruby_pcap.h" -#include "rubysig.h" #include <sys/time.h> #include <sys/types.h> #include <unistd.h> #define DEFAULT_DATALINK DLT_EN10MB @@ -316,40 +315,116 @@ const u_char *data; { rb_yield(new_packet(data, pkthdr, cap->dl_type)); } +#define DST_ADDR(data) INT2FIX(ntohl(*((unsigned int *) (data + 30)))) +#define SRC_ADDR(data) INT2FIX(ntohl(*((unsigned int *) (data + 26)))) + +static void +dst_ipv4_addr_handler(cap, pkthdr, data) + struct capture_object *cap; + const struct pcap_pkthdr *pkthdr; + const u_char *data; +{ + rb_yield(DST_ADDR(data)); +} + +static void +src_ipv4_addr_handler(cap, pkthdr, data) + struct capture_object *cap; + const struct pcap_pkthdr *pkthdr; + const u_char *data; +{ + rb_yield(SRC_ADDR(data)); +} + +#define SRCV6_ADDR(data) rb_integer_unpack((u_char *) (data + 22), 16, 1, 0, INTEGER_PACK_BIG_ENDIAN) +#define DSTV6_ADDR(data) rb_integer_unpack((u_char *) (data + 38), 16, 1, 0, INTEGER_PACK_BIG_ENDIAN) + +static void +dst_ipv6_addr_handler(cap, pkthdr, data) + struct capture_object *cap; + const struct pcap_pkthdr *pkthdr; + const u_char *data; +{ + rb_yield(DSTV6_ADDR(data)); +} + +static void +src_ipv6_addr_handler(cap, pkthdr, data) + struct capture_object *cap; + const struct pcap_pkthdr *pkthdr; + const u_char *data; +{ + rb_yield(SRCV6_ADDR(data)); +} + +void parse_opts(VALUE v_opts, void **default_handler) +{ + if (NIL_P(v_opts)) { + DEBUG_PRINT("using default capture handler"); + *default_handler = &handler; + } else { + // raise error if second argument is not a symbol + Check_Type(v_opts, T_SYMBOL); + // only :source, :destination are supported + if (SYM2ID(v_opts) == rb_intern("source")) { + DEBUG_PRINT("yeilding only source ipv4 addresses"); + *default_handler = &src_ipv4_addr_handler; + } else if (SYM2ID(v_opts) == rb_intern("destination")) { + DEBUG_PRINT("yeilding only destination ipv4 addresses"); + *default_handler = &dst_ipv4_addr_handler; + } else if (SYM2ID(v_opts) == rb_intern("destinationv6")) { + DEBUG_PRINT("yeilding only destination ipv6 addresses"); + *default_handler = &dst_ipv6_addr_handler; + } else if (SYM2ID(v_opts) == rb_intern("sourcev6")) { + DEBUG_PRINT("yeilding only source ipv6 addresses"); + *default_handler = &src_ipv6_addr_handler; + } else { + // unkonw keyword passed, use default capture handler + DEBUG_PRINT("unknown option, using default capture handler"); + *default_handler = &handler; + } + } +} + static VALUE capture_dispatch(argc, argv, self) int argc; VALUE *argv; VALUE self; { - VALUE v_cnt; - int cnt; + VALUE v_cnt, v_opts; + int ret = 0, cnt = 0; + unsigned int cap_cnt = 0; struct capture_object *cap; - int ret; + void *default_handler; DEBUG_PRINT("capture_dispatch"); GetCapture(self, cap); /* scan arg */ - if (rb_scan_args(argc, argv, "01", &v_cnt) >= 1) { - FIXNUM_P(v_cnt); - cnt = FIX2INT(v_cnt); + rb_scan_args(argc, argv, "02", &v_cnt, &v_opts); + if (NIL_P(v_cnt)) { + cnt = -1; } else { - cnt = -1; + FIXNUM_P(v_cnt); + cnt = FIX2INT(v_cnt); } - - MAYBE_TRAP_BEG; - ret = pcap_dispatch(cap->pcap, cnt, handler, (u_char *)cap); - MAYBE_TRAP_END; - if (ret == -1) { + parse_opts(v_opts, &default_handler); + // call dispatch with 10,000 and break if we have reached desired amount + // if dispatch is called with -1/0 sometimes it dispatches millions of packets + for (cap_cnt = 0; cap_cnt < cnt; cap_cnt += ret ) { + MAYBE_TRAP_BEG; + ret = pcap_dispatch(cap->pcap, 10000, default_handler, (u_char *)cap); + MAYBE_TRAP_END; + if (ret < 0) { rb_raise(ePcapError, "dispatch: %s", pcap_geterr(cap->pcap)); + } } - - return INT2FIX(ret); + return UINT2NUM(cap_cnt); } static VALUE capture_fh(argc, argv, self) int argc; @@ -371,29 +446,31 @@ capture_loop(argc, argv, self) int argc; VALUE *argv; VALUE self; { - VALUE v_cnt; + VALUE v_cnt, v_opts; int cnt; struct capture_object *cap; int ret; + void *default_handler; DEBUG_PRINT("capture_loop"); GetCapture(self, cap); /* scan arg */ - if (rb_scan_args(argc, argv, "01", &v_cnt) >= 1) { - FIXNUM_P(v_cnt); - cnt = FIX2INT(v_cnt); + rb_scan_args(argc, argv, "02", &v_cnt, &v_opts); + if (NIL_P(v_cnt)) { + cnt = -1; } else { - cnt = -1; + FIXNUM_P(v_cnt); + cnt = FIX2INT(v_cnt); } - + parse_opts(v_opts, &default_handler); if (pcap_file(cap->pcap) != NULL) { MAYBE_TRAP_BEG; - ret = pcap_loop(cap->pcap, cnt, handler, (u_char *)cap); + ret = pcap_loop(cap->pcap, cnt, default_handler, (u_char *)cap); MAYBE_TRAP_END; } else { int fd = pcap_fileno(cap->pcap); fd_set rset; @@ -407,11 +484,11 @@ FD_SET(fd, &rset); if (select(fd+1, &rset, NULL, NULL, &tm) == 0) { rb_thread_wait_fd(fd); } MAYBE_TRAP_BEG; - ret = pcap_dispatch(cap->pcap, 1, handler, (u_char *)cap); + ret = pcap_dispatch(cap->pcap, 1, default_handler, (u_char *)cap); MAYBE_TRAP_END; } while (ret == 0); if (ret <= 0) break; @@ -538,10 +615,34 @@ rb_raise(ePcapError, "pcap_inject expected to write %d but actually wrote %d", bufsiz, r); } return Qnil; } +// configure capture direction: IN/OUT packets +static VALUE +capture_direction(self, direction) + VALUE direction; + VALUE self; +{ + struct capture_object *cap; + // default value is in and out packets + int v_direction = PCAP_D_INOUT; + + DEBUG_PRINT("capture_direction"); + GetCapture(self, cap); + Check_Type(direction, T_SYMBOL); + // set desired direction: :in,:out or both + if (SYM2ID(direction) == rb_intern("in")) { + DEBUG_PRINT("setting capture direction IN"); + v_direction = PCAP_D_IN; + } else if (SYM2ID(direction) == rb_intern("out")) { + DEBUG_PRINT("setting capture direction OUT"); + v_direction = PCAP_D_OUT; + } + return INT2NUM(pcap_setdirection(cap->pcap, v_direction)); +} + /* * Dumper object */ struct dumper_object { @@ -903,9 +1004,10 @@ rb_define_method(cCapture, "datalink", capture_datalink, 0); rb_define_method(cCapture, "snapshot", capture_snapshot, 0); rb_define_method(cCapture, "snaplen", capture_snapshot, 0); rb_define_method(cCapture, "stats", capture_stats, 0); rb_define_method(cCapture, "inject", capture_inject, 1); + rb_define_method(cCapture, "direction", capture_direction, 1); /* define class Dumper */ cDumper = rb_define_class_under(mPcap, "Dumper", rb_cObject); rb_define_singleton_method(cDumper, "open", dumper_open, 2); rb_define_method(cDumper, "close", dumper_close, 0);