📄 pcap.i
字号:
/* -*- Mode: C; -*- *//******************************************************************************* ** Copyright 2005 University of Cambridge Computer Laboratory. ** ** This file is part of Nprobe. ** ** Nprobe is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2 of the License, or ** (at your option) any later version. ** ** Nprobe is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with Nprobe; if not, write to the Free Software ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ** *******************************************************************************/%module pcap%{#include "http_errdefs.h"#include "pcap.h"#include "pcap-int.h"#include <arpa/inet.h>#include <netinet/ether.h>%}%{struct py_pcap { struct pcap *pd; struct pcap_pkthdr header; char ebuf[PCAP_ERRBUF_SIZE]; unsigned char *userdata; pcap_handler printer; struct bpf_program fcode; bpf_u_int32 netmask; int stdin;};static char msg[2*PCAP_ERRBUF_SIZE];/* * These functions are called on error to set up python exceptions * - NOTE Zero return denotes error, successful returns may be objects * (pointers thereto actually) so non-zero must denote success. */int py_pcap_ioerror(char *msg1, char *msg2) { sprintf(msg, "py_pcap ioerror: %s - %s", msg1, msg2); PyErr_SetString(PyExc_IOError, msg); return 0; }int py_pcap_typeerror(char *msg1, char *msg2) { //fprintf(stderr, "py_pcap_typeerror called %s - %s\n", msg1, msg2); sprintf(msg, "py_pcap typeerror: %s - %s", msg1, msg2); PyErr_SetString(PyExc_TypeError, msg); return 0; }int py_pcap_eoferror(char *msg1, char *msg2) { //fprintf(stderr, "py_pcap_eoferror called %s - %s\n", msg1, msg2); sprintf(msg, "py_pcap eoferror: %s - %s", msg1, msg2); PyErr_SetString(PyExc_EOFError, msg); return 0; }int py_pcap_addrerror(char *msg1, char *msg2) { //fprintf(stderr, "py_pcap_addrerror called %s - %s\n", msg1, msg2); sprintf(msg, "py_pcap addrerror: %s - %s", msg1, msg2); PyErr_SetString(PyExc_TypeError, msg); return 0; }%}struct py_pcap { struct pcap *pd; struct pcap_pkthdr header; char ebuf[PCAP_ERRBUF_SIZE]; unsigned char *userdata; pcap_handler printer; struct bpf_program fcode; bpf_u_int32 netmask; int stdin; };%typemap(python, in) char * ethaddr{ if(!PyString_Check($source)) { PyErr_SetString(PyExc_TypeError, "not a string"); return NULL; } $target = PyString_AsString($source); }%typemap(python, out) struct ether_addr *{ $target = PyString_FromStringAndSize((char *)$source, 6);}%inline %{typedef int Status; typedef unsigned char * ethaddr; char *ntoa(int addr) { struct in_addr in; in.s_addr=addr; return inet_ntoa(in); }int aton(char *host) { struct in_addr adr; if (inet_aton(host, &adr) == 0) return py_pcap_addrerror("inet_aton() Can't convert address", ""); return adr.s_addr; } int _ntohs(int port) { return (int)ntohs((short)(port & 0xff)); }char *_ether_ntoa(char *ethaddr) { struct ether_addr *addr = (struct ether_addr *)ethaddr; static char buf[sizeof("00.00.00.00.00.00")]; ether_ntoa_r(addr, buf); return buf; } struct ether_addr *_ether_aton(const char *addr) { static struct ether_addr ad; ether_aton_r(addr, &ad); return &ad; } void FCLOSE(FILE *f) { printf("closing\n"); fflush(f); fclose(f); } char *nprobe_errstring(int err) { return http_err_string(err); } %}/* * Want methods that return python objects to do so without further wrapping * */%typemap(python, out) PyObject *{ $target=(PyObject *)_result;}/* * For methods either successful or generating errors we want to have either no * return value or raise an exception. These methods initially return a type * Status (int). Note that because objects may be returned an initial success * return is non-zero - Status returns must reverse the usual convention of * 0 = success, !=0 = failure (see the py_pcap_*error functions above which * set up exceptions and return 0 for failure). Our return wrapping therefore * returns either the python None object (the convention for void function * returns) for success, or the NULL value in case of failure. */%typemap(python, out) Status{ if (!$source) /* FAIL exception set up by py_pcap_*error function */ $target = (PyObject *)$source; else /* SUCCESS */ $target = Py_None; Py_XINCREF(Py_None);}/* * For methods returning a * FILE convert to a python file object - zero * return equates to an exception. We need to intercept input arguments _arg1 * (file name) and _arg2 (mode) in order to provide them as arguments to the * PyFile_FromFile() function. We similarly need to determine the function to * be called to close the file */%typemap(python, out) FILE *{ if (!$source) /* FAILED - pass it on */ { $target = (PyObject *)$source; } else /* SUCCESS - create file object */ { int (*close)(FILE *); if (_arg1[0] == '-' && _arg1[1] == '\0') close = NULL; else close = fclose; $target = PyFile_FromFile($source, _arg1, "w", close); } }/* * Convert python file object arguments to FILE * */%typemap(python, in) FILE *{ if (!PyFile_Check($source)) { PyErr_SetString(PyExc_TypeError, "Need a file!"); return NULL; } $target = PyFile_AsFile($source);}/* * Convert python tuple representing a timestamp to struct timeval * */%typemap(python, in) struct timeval * (struct timeval tmp){ if (!PyArg_ParseTuple($source, "ll", &tmp.tv_sec, &tmp.tv_usec)) { PyErr_SetString(PyExc_TypeError, "Cant convert timeval"); return NULL; } printf("val %d %d\n", tmp.tv_sec, tmp.tv_usec); $target = &tmp;} %addmethods py_pcap {/* Constructor */py_pcap(){ struct py_pcap *ap; if ((ap = (struct py_pcap *)malloc(sizeof(struct py_pcap))) == NULL) { fprintf(stderr, "pymod pcap: init malloc error\n"); exit(1); } ap->pd = NULL; ap->printer = NULL; ap->userdata = NULL; ap->stdin = 0; return ap;}/*Destructor */~py_pcap() { if (self->pd) pcap_close(self->pd); free(self);} Status open_offline(const char *fnm) { self->pd = pcap_open_offline(fnm, self->ebuf); if (self->pd == NULL) { //printf("open_offline fail - errno %d, msg %s\n", errno, self->ebuf); if (errno == 0) sprintf(self->ebuf, "empty tcpdump file or malformed header %s\n", fnm); return py_pcap_typeerror("open_offline", self->ebuf); } if (fnm[0] == '-' && fnm[1] == '\0') self->stdin = 1; self->netmask = 0; return 1; }int datalink(){ return self->pd->linktype;}int snaplen(){ return self->pd->snapshot;}PyObject * ftell(void){ long off; if ((off = ftell(self->pd->sf.rfile)) == -1) return (PyObject *)py_pcap_typeerror("ftell()", strerror(errno)); else return Py_BuildValue("i", off);}Status fseek(long off){ if (fseek(self->pd->sf.rfile, off, SEEK_SET) != 0) return py_pcap_typeerror("fseek()", ""); else return 1;}Status dump_open(const char *fnm){ if (self->pd == NULL) { return py_pcap_typeerror("dump_open()", "pcap not open"); } else { pcap_dumper_t *p = pcap_dump_open(self->pd, fnm); if (p == NULL) return py_pcap_ioerror("dump_open()", pcap_geterr(self->pd)); self->printer = pcap_dump; self->userdata = (u_char *)p; return 1; }}/* * Like dump_open but returns a file to which we can dump packets by calling * alt_dump() */FILE * alt_dump_open(const char *fname){ FILE *f; int sf_write_header(FILE *fp, int linktype, int thiszone, int snaplen); if (self->pd == NULL) return (FILE *)py_pcap_typeerror("alt_dump_open()", "pcap not open"); if (fname[0] == '-' && fname[1] == '\0') { f = stdout; } else { f = fopen(fname, "w"); if (f == NULL) return (FILE *)py_pcap_ioerror("alt_dump_open() - open", pcap_strerror(errno)); } if (sf_write_header(f, self->pd->linktype, self->pd->tzoff, self->pd->snapshot) != 0) return (FILE *)py_pcap_ioerror("alt_dump_open() - sf_write_hdr()", pcap_strerror(errno)); return f; }/* * Just checks set-up and calls pcap loop */Status loop(int cnt) { if (self->pd == NULL) { return py_pcap_typeerror("loop()", "pcap not open"); } else if (self->printer == NULL) { return py_pcap_typeerror("loop()", "no printer specified"); } else { if (pcap_loop(self->pd, cnt, self->printer, self->userdata) < 0) return py_pcap_typeerror("loop()", pcap_geterr(self->pd)); } return 1; }/* * Rolls two pcap funs into one to parse filter expression and set filter */Status set_filter(char *cmdbuf) { if (self->pd == NULL) { return py_pcap_typeerror("set_filter()", "pcap not open"); } if (pcap_compile(self->pd, &self->fcode, cmdbuf, 1, self->netmask) < 0) return py_pcap_typeerror("pcap_compile()", pcap_geterr(self->pd)); if (pcap_setfilter(self->pd, &self->fcode) < 0) return py_pcap_typeerror("set_filter()", pcap_geterr(self->pd)); return 1; }Status py_pcap_compile(char *cmdbuf) { if (self->pd == NULL) { return py_pcap_typeerror("py_pcap_compile()", "pcap not open"); } if (pcap_compile(self->pd, &self->fcode, cmdbuf, 1, self->netmask) < 0) return py_pcap_typeerror("pcap_compile()", pcap_geterr(self->pd)); return 1; }/* * Single packet read based on pcap_next - returns tuple of pkt length, * contents, and (float) time stamp */PyObject * next_fts() { const unsigned char *buf; if (self->pd) { buf = pcap_next(self->pd, &self->header); if (buf) return Py_BuildValue("is#f", self->header.len, buf, self->header.caplen, self->header.ts.tv_sec*1.0+self->header.ts.tv_usec*1.0/1e6); else return (PyObject *)py_pcap_eoferror("next()", "EOF"); } else { return (PyObject *)py_pcap_typeerror("next()", "pcap not open"); }}/* * As next_fts() but t.s. is tuple of (ts.tv_sec, ts.tv_usec) */PyObject * next_tts() { const unsigned char *buf; if (self->pd) { buf = pcap_next(self->pd, &self->header); if (buf) return Py_BuildValue("is#(ii)", self->header.len, buf, self->header.caplen, self->header.ts.tv_sec, self->header.ts.tv_usec); else return (PyObject *)py_pcap_eoferror("next()", "EOF"); } else { return (PyObject *)py_pcap_typeerror("next()", "pcap not open"); } }/* * As next_fts() but returned tuple includes file offset of packet record */PyObject * next_o_fts() { const unsigned char *buf; if (self->pd) { long off; if (self->stdin) off = 0; else if ((off = ftell(self->pd->sf.rfile)) == -1) return (PyObject *)py_pcap_typeerror("ftell()", ""); buf = pcap_next(self->pd, &self->header); if (buf) return Py_BuildValue("iis#f", off, self->header.len, buf, self->header.caplen, self->header.ts.tv_sec*1.0+self->header.ts.tv_usec*1.0/1e6); else return (PyObject *)py_pcap_eoferror("next()", "EOF"); } else { return (PyObject *)py_pcap_typeerror("next()", "pcap not open"); }}/* * As next_tts() but returned tuple includes file offset of packet record */PyObject * next_o_tts() { const unsigned char *buf; if (self->pd) { long off; if (self->stdin) off = 0; else if ((off = ftell(self->pd->sf.rfile)) == -1) return (PyObject *)py_pcap_typeerror("ftell()", ""); buf = pcap_next(self->pd, &self->header); if (buf) return Py_BuildValue("iis#(ii)", off, self->header.len, buf, self->header.caplen, self->header.ts.tv_sec, self->header.ts.tv_usec); else return (PyObject *)py_pcap_eoferror("next()", "EOF"); } else { return (PyObject *)py_pcap_typeerror("next()", "pcap not open"); } }/* * Dump a single packet read by next() to file opened with dump_open() */Status dump(){ const struct pcap_pkthdr *h = &self->header; //fprintf(stderr, "dump dumping %d\n", h->caplen); if (!self->userdata) return py_pcap_ioerror("dump()", "Dump not initialised"); if (fwrite((char *)h, sizeof(*h), 1, (FILE *)self->userdata) != 1) return py_pcap_ioerror("dump()", "hdr write IOError"); if (fwrite((char *)self->pd->buffer, h->caplen, 1, (FILE *)self->userdata) != 1) return py_pcap_ioerror("dump()", "pkt write IOError"); //fprintf(stderr, "dump OK\n"); return 1;}/* * Dump single packet to any file opened with alt_dump_open() */Status alt_dump(FILE *file){ const struct pcap_pkthdr *h = &self->header; //fprintf(stderr, "alt_dump dumping %d\n", h->caplen); if (fwrite((char *)h, sizeof(*h), 1, file) != 1) return py_pcap_ioerror("dump()", "hdr write IOError"); if (fwrite((char *)self->pd->buffer, h->caplen, 1, file) != 1) return py_pcap_ioerror("dump()", "pkt write IOError"); return 1;}Status dump_close(){ if (self->userdata) pcap_dump_close((pcap_dumper_t *)self->userdata); return 1;}/* * Present packet read with next() to packet filter */int filter(){ const struct pcap_pkthdr *h = &self->header; return bpf_filter(self->fcode.bf_insns, self->pd->buffer, h->len, h->caplen); }void set_ts(struct timeval *tv){ self->header.ts.tv_sec = tv->tv_sec; self->header.ts.tv_usec = tv->tv_usec;}}; /* End addmethods py_pcap */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -