/* * Pcap.xs * * XS wrapper for LBL pcap(3) library. * * Copyright (C) 2005, 2006, 2007, 2008 Sebastien Aperghis-Tramoni with code by * Jean-Louis Morel. All rights reserved. * Copyright (C) 2003 Marco Carnut. All rights reserved. * Copyright (C) 1999 Tim Potter. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the same terms as Perl itself. * */ #ifdef __cplusplus extern "C" { #endif #ifdef _CYGWIN #include #endif #ifdef _WIN32 #include #endif #include "EXTERN.h" #include "perl.h" #include "XSUB.h" #define NEED_PL_signals 1 #define NEED_sv_2pv_nolen 1 #include "ppport.h" #include #ifdef _CYGWIN #include #endif #include "const-c.inc" #include "stubs.inc" #ifdef __cplusplus } #endif typedef struct bpf_program pcap_bpf_program_t; /* Wrapper for callback function */ SV *callback_fn; void callback_wrapper(u_char *user, const struct pcap_pkthdr *h, const u_char *pkt) { SV *packet = newSVpv((u_char *)pkt, h->caplen); HV *hdr = newHV(); SV *ref_hdr = newRV_inc((SV*)hdr); /* Fill the hash fields */ hv_store(hdr, "tv_sec", strlen("tv_sec"), newSViv(h->ts.tv_sec), 0); hv_store(hdr, "tv_usec", strlen("tv_usec"), newSViv(h->ts.tv_usec), 0); hv_store(hdr, "caplen", strlen("caplen"), newSVuv(h->caplen), 0); hv_store(hdr, "len", strlen("len"), newSVuv(h->len), 0); /* Push arguments onto stack */ dSP; PUSHMARK(sp); XPUSHs((SV*)user); XPUSHs(ref_hdr); XPUSHs(packet); PUTBACK; /* Call perl function */ call_sv (callback_fn, G_DISCARD); /* Decrement refcount to temp SVs */ SvREFCNT_dec(packet); SvREFCNT_dec(hdr); SvREFCNT_dec(ref_hdr); } MODULE = Net::Pcap PACKAGE = Net::Pcap PREFIX = pcap_ INCLUDE: const-xs.inc PROTOTYPES: DISABLE char * pcap_lookupdev(err) SV *err CODE: if (SvROK(err)) { char *errbuf = safemalloc(PCAP_ERRBUF_SIZE+1); SV *err_sv = SvRV(err); RETVAL = pcap_lookupdev(errbuf); #ifdef WPCAP { int length = lstrlenW((PWSTR)RETVAL) + 2; char *r = safemalloc(length); /* Conversion from Unicode to ANSI */ WideCharToMultiByte(CP_ACP, 0, (PWSTR)RETVAL, -1, r, length, NULL, NULL); lstrcpyA(RETVAL, r); safefree(r); } #endif /* WPCAP */ if (RETVAL == NULL) { sv_setpv(err_sv, errbuf); } else { err_sv = &PL_sv_undef; } safefree(errbuf); } else croak("arg1 not a hash ref"); OUTPUT: RETVAL err int pcap_lookupnet(device, net, mask, err) const char *device SV *net SV *mask SV *err CODE: if (SvROK(net) && SvROK(mask) && SvROK(err)) { char *errbuf = safemalloc(PCAP_ERRBUF_SIZE+1); bpf_u_int32 netp, maskp; SV *net_sv = SvRV(net); SV *mask_sv = SvRV(mask); SV *err_sv = SvRV(err); RETVAL = pcap_lookupnet(device, &netp, &maskp, errbuf); netp = ntohl(netp); maskp = ntohl(maskp); if (RETVAL != -1) { sv_setuv(net_sv, netp); sv_setuv(mask_sv, maskp); err_sv = &PL_sv_undef; } else { sv_setpv(err_sv, errbuf); } safefree(errbuf); } else { RETVAL = -1; if (!SvROK(net )) croak("arg2 not a reference"); if (!SvROK(mask)) croak("arg3 not a reference"); if (!SvROK(err )) croak("arg4 not a reference"); } OUTPUT: net mask err RETVAL void pcap_findalldevs_xs(devinfo, err) SV * devinfo SV * err PREINIT: char *errbuf = safemalloc(PCAP_ERRBUF_SIZE+1); PPCODE: if ( SvROK(err) && SvROK(devinfo) && (SvTYPE(SvRV(devinfo)) == SVt_PVHV) ) { int r; pcap_if_t *alldevs, *d; HV *hv; SV *err_sv = SvRV(err); hv = (HV *)SvRV(devinfo); r = pcap_findalldevs(&alldevs, errbuf); switch(r) { case 0: /* normal case */ for (d=alldevs; d; d=d->next) { XPUSHs(sv_2mortal(newSVpv(d->name, 0))); if (d->description) hv_store(hv, d->name, strlen(d->name), newSVpv(d->description, 0), 0); else if( (strcmp(d->name,"lo") == 0) || (strcmp(d->name,"lo0") == 0)) hv_store(hv, d->name, strlen(d->name), newSVpv("Loopback device", 0), 0); else hv_store(hv, d->name, strlen(d->name), newSVpv("No description available", 0), 0); } pcap_freealldevs(alldevs); err_sv = &PL_sv_undef; break; case 3: { /* function is not available */ char *dev = pcap_lookupdev(errbuf); if(dev == NULL) { sv_setpv(err_sv, errbuf); break; } XPUSHs(sv_2mortal(newSVpv(dev, 0))); if( (strcmp(dev,"lo") == 0) || (strcmp(dev,"lo0") == 0)) hv_store(hv, dev, strlen(dev), newSVpv("", 0), 0); else hv_store(hv, dev, strlen(dev), newSVpv("No description available", 0), 0); break; } case -1: /* error */ sv_setpv(err_sv, errbuf); break; } } else { if ( !SvROK(devinfo) || (SvTYPE(SvRV(devinfo)) != SVt_PVHV) ) croak("arg1 not a hash ref"); if ( !SvROK(err) ) croak("arg2 not a scalar ref"); } safefree(errbuf); pcap_t * pcap_open_live(device, snaplen, promisc, to_ms, err) const char *device int snaplen int promisc int to_ms SV *err; CODE: if (SvROK(err)) { char *errbuf = safemalloc(PCAP_ERRBUF_SIZE+1); SV *err_sv = SvRV(err); #ifdef _MSC_VER /* Net::Pcap hangs when to_ms == 0 under ActivePerl/MSVC */ if(to_ms == 0) to_ms = 1; #endif RETVAL = pcap_open_live(device, snaplen, promisc, to_ms, errbuf); if (RETVAL == NULL) { sv_setpv(err_sv, errbuf); } else { err_sv = &PL_sv_undef; } safefree(errbuf); } else croak("arg5 not a reference"); OUTPUT: err RETVAL pcap_t * pcap_open_dead(linktype, snaplen) int linktype int snaplen OUTPUT: RETVAL pcap_t * pcap_open_offline(fname, err) const char *fname SV *err CODE: if (SvROK(err)) { char *errbuf = safemalloc(PCAP_ERRBUF_SIZE+1); SV *err_sv = SvRV(err); RETVAL = pcap_open_offline(fname, errbuf); if (RETVAL == NULL) { sv_setpv(err_sv, errbuf); } else { err_sv = &PL_sv_undef; } safefree(errbuf); } else croak("arg2 not a reference"); OUTPUT: err RETVAL pcap_dumper_t * pcap_dump_open(p, fname) pcap_t *p const char *fname int pcap_setnonblock(p, nb, err) pcap_t *p int nb SV *err CODE: if (SvROK(err)) { char *errbuf = safemalloc(PCAP_ERRBUF_SIZE+1); SV *err_sv = SvRV(err); RETVAL = pcap_setnonblock(p, nb, errbuf); if (RETVAL == -1) { sv_setpv(err_sv, errbuf); } else { err_sv = &PL_sv_undef; } safefree(errbuf); } else croak("arg3 not a reference"); OUTPUT: err RETVAL int pcap_getnonblock(p, err) pcap_t *p SV *err CODE: if (SvROK(err)) { char *errbuf = safemalloc(PCAP_ERRBUF_SIZE+1); SV *err_sv = SvRV(err); RETVAL = pcap_getnonblock(p, errbuf); if (RETVAL == -1) { sv_setpv(err_sv, errbuf); } else { err_sv = &PL_sv_undef; } safefree(errbuf); } else croak("arg2 not a reference"); OUTPUT: err RETVAL int pcap_dispatch(p, cnt, callback, user) pcap_t *p int cnt SV *callback SV *user CODE: { U32 SAVE_signals; callback_fn = newSVsv(callback); user = newSVsv(user); *(pcap_geterr(p)) = '\0'; /* reset error string */ SAVE_signals = PL_signals; /* Allow the call to be interrupted by signals */ PL_signals |= PERL_SIGNALS_UNSAFE_FLAG; RETVAL = pcap_dispatch(p, cnt, callback_wrapper, (u_char *)user); PL_signals = SAVE_signals; SvREFCNT_dec(user); SvREFCNT_dec(callback_fn); } OUTPUT: RETVAL int pcap_loop(p, cnt, callback, user) pcap_t *p int cnt SV *callback SV *user CODE: { U32 SAVE_signals; callback_fn = newSVsv(callback); user = newSVsv(user); SAVE_signals = PL_signals; /* Allow the call to be interrupted by signals */ PL_signals |= PERL_SIGNALS_UNSAFE_FLAG; RETVAL = pcap_loop(p, cnt, callback_wrapper, (u_char *)user); PL_signals = SAVE_signals; SvREFCNT_dec(user); SvREFCNT_dec(callback_fn); } OUTPUT: RETVAL SV * pcap_next(p, pkt_header) pcap_t *p SV *pkt_header CODE: if (SvROK(pkt_header) && (SvTYPE(SvRV(pkt_header)) == SVt_PVHV)) { struct pcap_pkthdr real_h; const u_char *result; U32 SAVE_signals; HV *hv; memset(&real_h, '\0', sizeof(real_h)); SAVE_signals = PL_signals; /* Allow the call to be interrupted by signals */ PL_signals |= PERL_SIGNALS_UNSAFE_FLAG; result = pcap_next(p, &real_h); PL_signals = SAVE_signals; hv = (HV *)SvRV(pkt_header); if (result != NULL) { hv_store(hv, "tv_sec", strlen("tv_sec"), newSViv(real_h.ts.tv_sec), 0); hv_store(hv, "tv_usec", strlen("tv_usec"), newSViv(real_h.ts.tv_usec), 0); hv_store(hv, "caplen", strlen("caplen"), newSVuv(real_h.caplen), 0); hv_store(hv, "len", strlen("len"), newSVuv(real_h.len), 0); RETVAL = newSVpv((char *)result, real_h.caplen); } else RETVAL = &PL_sv_undef; } else croak("arg2 not a hash ref"); OUTPUT: pkt_header RETVAL int pcap_next_ex(p, pkt_header, pkt_data) pcap_t *p SV *pkt_header SV *pkt_data CODE: /* Check if pkt_header is a hashref and pkt_data a scalarref */ if (SvROK(pkt_header) && (SvTYPE(SvRV(pkt_header)) == SVt_PVHV) && SvROK(pkt_data)) { struct pcap_pkthdr *header; const u_char *data; U32 SAVE_signals; HV *hv; memset(&header, '\0', sizeof(header)); SAVE_signals = PL_signals; /* Allow the call to be interrupted by signals */ PL_signals |= PERL_SIGNALS_UNSAFE_FLAG; RETVAL = pcap_next_ex(p, &header, &data); PL_signals = SAVE_signals; hv = (HV *)SvRV(pkt_header); if (RETVAL == 1) { hv_store(hv, "tv_sec", strlen("tv_sec"), newSViv(header->ts.tv_sec), 0); hv_store(hv, "tv_usec", strlen("tv_usec"), newSViv(header->ts.tv_usec), 0); hv_store(hv, "caplen", strlen("caplen"), newSVuv(header->caplen), 0); hv_store(hv, "len", strlen("len"), newSVuv(header->len), 0); sv_setpvn((SV *)SvRV(pkt_data), data, header->caplen); } } else { RETVAL = -1; if (!SvROK(pkt_header) || (SvTYPE(SvRV(pkt_header)) != SVt_PVHV)) croak("arg2 not a hash ref"); if (!SvROK(pkt_data)) croak("arg3 not a scalar ref"); } OUTPUT: pkt_header pkt_data RETVAL void pcap_dump(p, pkt_header, sp) pcap_dumper_t *p SV *pkt_header SV *sp CODE: /* Check if pkt_header is a hashref */ if (SvROK(pkt_header) && (SvTYPE(SvRV(pkt_header)) == SVt_PVHV)) { struct pcap_pkthdr real_h; char *real_sp; HV *hv; SV **sv; memset(&real_h, '\0', sizeof(real_h)); /* Copy from hash to pcap_pkthdr */ hv = (HV *)SvRV(pkt_header); sv = hv_fetch(hv, "tv_sec", strlen("tv_sec"), 0); if (sv != NULL) { real_h.ts.tv_sec = SvIV(*sv); } sv = hv_fetch(hv, "tv_usec", strlen("tv_usec"), 0); if (sv != NULL) { real_h.ts.tv_usec = SvIV(*sv); } sv = hv_fetch(hv, "caplen", strlen("caplen"), 0); if (sv != NULL) { real_h.caplen = SvIV(*sv); } sv = hv_fetch(hv, "len", strlen("len"), 0); if (sv != NULL) { real_h.len = SvIV(*sv); } real_sp = SvPV(sp, PL_na); /* Call pcap_dump() */ pcap_dump((u_char *)p, &real_h, real_sp); } else croak("arg2 not a hash ref"); int pcap_compile(p, fp, str, optimize, mask) pcap_t *p SV *fp char *str int optimize bpf_u_int32 mask CODE: if (SvROK(fp)) { pcap_bpf_program_t *real_fp = safemalloc(sizeof(pcap_bpf_program_t)); *(pcap_geterr(p)) = '\0'; /* reset error string */ RETVAL = pcap_compile(p, real_fp, str, optimize, mask); sv_setref_pv(SvRV(fp), "pcap_bpf_program_tPtr", (void *)real_fp); } else croak("arg2 not a reference"); OUTPUT: fp RETVAL int pcap_compile_nopcap(snaplen, linktype, fp, str, optimize, mask) int snaplen int linktype SV *fp char *str int optimize bpf_u_int32 mask CODE: if (SvROK(fp)) { pcap_bpf_program_t *real_fp = safemalloc(sizeof(pcap_bpf_program_t)); RETVAL = pcap_compile_nopcap(snaplen, linktype, real_fp, str, optimize, mask); sv_setref_pv(SvRV(fp), "pcap_bpf_program_tPtr", (void *)real_fp); } else croak("arg3 not a reference"); OUTPUT: fp RETVAL int pcap_setfilter(p, fp) pcap_t *p pcap_bpf_program_t *fp void pcap_freecode(fp) pcap_bpf_program_t *fp void pcap_breakloop(p) pcap_t *p void pcap_close(p) pcap_t *p void pcap_dump_close(p) pcap_dumper_t *p FILE * pcap_dump_file(p) pcap_dumper_t *p int pcap_dump_flush(p) pcap_dumper_t *p int pcap_datalink(p) pcap_t *p int pcap_set_datalink(p, linktype) pcap_t *p int linktype int pcap_datalink_name_to_val(name) const char *name const char * pcap_datalink_val_to_name(linktype) int linktype const char * pcap_datalink_val_to_description(linktype) int linktype int pcap_snapshot(p) pcap_t *p int pcap_is_swapped(p) pcap_t *p int pcap_major_version(p) pcap_t *p int pcap_minor_version(p) pcap_t *p void pcap_perror(p, prefix) pcap_t *p char *prefix char * pcap_geterr(p) pcap_t *p char * pcap_strerror(error) int error const char * pcap_lib_version() FILE * pcap_file(p) pcap_t *p int pcap_fileno(p) pcap_t *p int pcap_get_selectable_fd(p) pcap_t *p int pcap_stats(p, ps) pcap_t *p; SV *ps; CODE: /* Call pcap_stats() function */ if (SvROK(ps) && (SvTYPE(SvRV(ps)) == SVt_PVHV)) { struct pcap_stat real_ps; HV *hv; *(pcap_geterr(p)) = '\0'; /* reset error string */ RETVAL = pcap_stats(p, &real_ps); /* Copy pcap_stats fields into hash */ hv = (HV *)SvRV(ps); hv_store(hv, "ps_recv", strlen("ps_recv"), newSVuv(real_ps.ps_recv), 0); hv_store(hv, "ps_drop", strlen("ps_drop"), newSVuv(real_ps.ps_drop), 0); hv_store(hv, "ps_ifdrop", strlen("ps_ifdrop"), newSVuv(real_ps.ps_ifdrop), 0); } else croak("arg2 not a hash ref"); OUTPUT: RETVAL int pcap_createsrcstr(source, type, host, port, name, err) SV * source int type char * host char * port char * name SV * err CODE: if (SvROK(source) && SvROK(err)) { char *errbuf = safemalloc(PCAP_ERRBUF_SIZE); char *sourcebuf = safemalloc(PCAP_BUF_SIZE); SV *err_sv = SvRV(err); SV *source_sv = SvRV(source); RETVAL = pcap_createsrcstr(sourcebuf, type, host, port, name, errbuf); if (RETVAL != -1) { sv_setpv(source_sv, sourcebuf); err_sv = &PL_sv_undef; } else { sv_setpv(err_sv, errbuf); } safefree(errbuf); safefree(sourcebuf); } else { RETVAL = -1; if (!SvROK(source)) croak("arg1 not a reference"); if (!SvROK(err)) croak("arg6 not a reference"); } OUTPUT: source err RETVAL int pcap_parsesrcstr(source, type, host, port, name, err) char * source SV * type SV * host SV * port SV * name SV * err CODE: if ( !SvROK(type) ) croak("arg2 not a reference"); if ( !SvROK(host) ) croak("arg3 not a reference"); if ( !SvROK(port) ) croak("arg4 not a reference"); if ( !SvROK(name) ) croak("arg5 not a reference"); if ( !SvROK(err) ) croak("arg6 not a reference"); else { int rtype; char *hostbuf = safemalloc(PCAP_BUF_SIZE); char *portbuf = safemalloc(PCAP_BUF_SIZE); char *namebuf = safemalloc(PCAP_BUF_SIZE); char *errbuf = safemalloc(PCAP_ERRBUF_SIZE); SV *type_sv = SvRV(type); SV *host_sv = SvRV(host); SV *port_sv = SvRV(port); SV *name_sv = SvRV(name); SV *err_sv = SvRV(err); RETVAL = pcap_parsesrcstr(source, &rtype, hostbuf, portbuf, namebuf, errbuf); if (RETVAL != -1) { sv_setiv(type_sv, rtype); sv_setpv(host_sv, hostbuf); sv_setpv(port_sv, portbuf); sv_setpv(name_sv, namebuf); err_sv = &PL_sv_undef; } else { sv_setpv(err_sv, errbuf); } safefree(hostbuf); safefree(portbuf); safefree(namebuf); safefree(errbuf); } OUTPUT: type host port name err RETVAL pcap_t * pcap_open(source, snaplen, flags, read_timeout, auth, err) char *source int snaplen int flags int read_timeout SV *auth SV *err CODE: if (!SvROK(err)) croak("arg6 not a reference"); if ( !SvOK(auth) || (SvOK(auth) && SvROK(auth) && (SvTYPE(SvRV(auth)) == SVt_PVHV)) ) { struct pcap_rmtauth real_auth; struct pcap_rmtauth * preal_auth; char *errbuf = safemalloc(PCAP_ERRBUF_SIZE); SV *err_sv = SvRV(err); if (!SvOK(auth)) { /* if auth (struct pcap_rmtauth) is undef */ preal_auth = NULL; } else { /* auth (struct pcap_rmtauth) is a hashref */ HV *hv; SV **sv; memset(&real_auth, '\0', sizeof(real_auth)); /* Copy from hash to pcap_rmtauth */ hv = (HV *)SvRV(auth); sv = hv_fetch(hv, "type", strlen("type"), 0); if (sv != NULL) real_auth.type = SvIV(*sv); sv = hv_fetch(hv, "username", strlen("username"), 0); if (sv != NULL) real_auth.username = SvPV(*sv, PL_na); sv = hv_fetch(hv, "password", strlen("password"), 0); if (sv != NULL) real_auth.password = SvPV(*sv, PL_na); preal_auth = &real_auth; } RETVAL = pcap_open(source, snaplen, flags, read_timeout, preal_auth, errbuf); if (RETVAL == NULL) { sv_setpv(err_sv, errbuf); } else { err_sv = &PL_sv_undef; } safefree(errbuf); } else croak("arg5 not a hash ref"); OUTPUT: RETVAL err int pcap_setuserbuffer(p, size) pcap_t *p int size int pcap_setbuff(p, dim) pcap_t *p int dim int pcap_setmode (p, mode) pcap_t *p int mode int pcap_setmintocopy(p, size) pcap_t *p int size void pcap_getevent(p) pcap_t *p PREINIT: unsigned int h; PPCODE: h = (unsigned int) pcap_getevent(p); ST(0) = sv_newmortal(); sv_setref_iv(ST(0), "Win32::Event", h); XSRETURN(1); int pcap_sendpacket(p, buf) pcap_t *p SV *buf CODE: RETVAL = pcap_sendpacket(p, SvPVX(buf), sv_len(buf)); OUTPUT: RETVAL pcap_send_queue * pcap_sendqueue_alloc(memsize) u_int memsize MODULE = Net::Pcap PACKAGE = pcap_send_queuePtr void DESTROY(queue) pcap_send_queue * queue CODE: pcap_sendqueue_destroy(queue); MODULE = Net::Pcap PACKAGE = Net::Pcap PREFIX = pcap_ int pcap_sendqueue_queue(queue, header, p) pcap_send_queue * queue SV *header SV *p CODE: /* Check that header is a hashref */ if (SvROK(header) && (SvTYPE(SvRV(header)) == SVt_PVHV)) { struct pcap_pkthdr real_h; char *real_p; HV *hv; SV **sv; memset(&real_h, '\0', sizeof(real_h)); /* Copy from hash to pcap_pkthdr */ hv = (HV *)SvRV(header); sv = hv_fetch(hv, "tv_sec", strlen("tv_sec"), 0); if (sv != NULL) { real_h.ts.tv_sec = SvIV(*sv); } sv = hv_fetch(hv, "tv_usec", strlen("tv_usec"), 0); if (sv != NULL) { real_h.ts.tv_usec = SvIV(*sv); } sv = hv_fetch(hv, "caplen", strlen("caplen"), 0); if (sv != NULL) { real_h.caplen = SvIV(*sv); } sv = hv_fetch(hv, "len", strlen("len"), 0); if (sv != NULL) { real_h.len = SvIV(*sv); } real_p = SvPV(p, PL_na); /* Call pcap_sendqueue_queue() */ RETVAL = pcap_sendqueue_queue(queue, &real_h, (unsigned char *) real_p); } else croak("arg2 not a hash ref"); OUTPUT: RETVAL u_int pcap_sendqueue_transmit(p, queue, sync) pcap_t *p pcap_send_queue * queue int sync