diff options
author | Andreas Fankhauser hiddenalpha.ch | 2023-09-08 15:39:54 +0200 |
---|---|---|
committer | Andreas Fankhauser hiddenalpha.ch | 2023-09-08 15:39:54 +0200 |
commit | 7ebf105a444aba301476ae34677075b25f14523f (patch) | |
tree | 6f0fa2d3c8b902a9f76c49c05c3dc44b83253eea | |
parent | 850ecbddaf846c2bc19920ab9c37377b63418fc1 (diff) | |
download | UnspecifiedGarbage-7ebf105a444aba301476ae34677075b25f14523f.zip UnspecifiedGarbage-7ebf105a444aba301476ae34677075b25f14523f.tar.gz |
(pcap) Add simplified copy of Pcapit from CeeMiscLib.
-rw-r--r-- | configure | 11 | ||||
-rw-r--r-- | src/main/c/PcapOne/PcapOne.c | 302 |
2 files changed, 313 insertions, 0 deletions
@@ -66,6 +66,16 @@ printTarget_Asn1Digger () { } +printTarget_PcapOne () { + printf '\n' + printf 'build/bin/pcap-one$(BINEXT):\n' + printf 'build/bin/pcap-one$(BINEXT): src/main/c/PcapOne/PcapOne.c\n' + printf ' @echo " LN $@"\n' + printf ' @$(MKDIR_P) build/bin\n' + printf ' @$(CC) -o $@ $(CFLAGS) $^ $(INCDIRS)\n' +} + + main () { ( printMakefileHdr @@ -73,6 +83,7 @@ main () { printTarget_link printTarget_PemCodec printTarget_Asn1Digger + printTarget_PcapOne ) > "${MF:?}" } diff --git a/src/main/c/PcapOne/PcapOne.c b/src/main/c/PcapOne/PcapOne.c new file mode 100644 index 0000000..634d01c --- /dev/null +++ b/src/main/c/PcapOne/PcapOne.c @@ -0,0 +1,302 @@ +/* TODO fix this bullshit */ +typedef unsigned u_int; +typedef unsigned short u_short; +typedef unsigned char u_char; +#include <pcap/pcap.h> +/* endOf TODO */ + + +/* System */ +#include <assert.h> +#include <stdlib.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> + +static char const*const DEV_STDIN = "/dev/stdin"; + +#define FLG_isHelp (1<<0) +#define FLG_isTcpPsh (1<<3) +#define FLG_isTcpRst (1<<4) +#define FLG_isTcpSyn (1<<5) +#define FLG_isTcpFin (1<<6) +#define FLG_isHttpReq (1<<7) +#define FLG_isLlLinux (1<<12) +#define FLG_INIT (0) + +typedef struct PcapOne PcapOne; + + +struct PcapOne { + uint_least16_t flg; + char *dumpFilePath; + char *pcapErrbuf; + pcap_t *pcap; + unsigned long frameNr; + struct/*most recent frame*/{ + int_fast32_t llProto; + int llHdrEnd; + }; + struct/*most recent packet*/{ + int_fast16_t netProto; + int netBodyLen; + int netHdrEnd; + int_fast32_t netTotLen; + uint_least32_t ipSrcAddr, ipDstAddr; + }; + struct/*most recent segment*/{ + int trspBodyLen; + int_fast32_t trspSrcPort, trspDstPort; + int trspHdrEnd; + }; + struct/*most recent http requst*/{ + const char *httpReqHeadline; + int httpReqHeadline_len; + int httpReq_off; /* pkg offset from begin of most recent request */ + }; +}; + + +/*BEG func fwd decl*/ +static void parse_ll_LINUX_SLL( PcapOne*, const struct pcap_pkthdr*, const u_char* ); +static void parse_net_IPv4( PcapOne*, const struct pcap_pkthdr*, const u_char* ); +static void parse_trsp_TCP( PcapOne*, const struct pcap_pkthdr*, const u_char* ); +static void parse_appl_HTTP_req( PcapOne*, const struct pcap_pkthdr*, const u_char* ); +static void printParsingResults( PcapOne* ); +/*END func fwd decl*/ + +static void printHelp(){ + #define STRQUOT_21a9ffbe344c0792ed88688d6c676359(s) #s + #define STRQUOT(s) STRQUOT_21a9ffbe344c0792ed88688d6c676359(s) + const char *basename = "/"__FILE__ + sizeof("/"__FILE__); + for(; basename[-1] != '/'; --basename ); + printf("%s%s%s", " \n" + " ", basename, " " STRQUOT(PROJECT_VERSION) "\n" + " \n" + " Options:\n" + " \n" + " --pcap-stdin\n" + " Like --pcap but reading from stdin.\n" + " \n" + " --pcap <path>\n" + " Pcap file to operate on. Compressed files are NOT supported.\n" + " \n"); + #undef STRQUOT_21a9ffbe344c0792ed88688d6c676359 + #undef STRQUOT +} + + +static int parseArgs( PcapOne*app, int argc, char**argv ){ + app->flg = FLG_INIT; + app->dumpFilePath = NULL; + for( int iA = 1 ; iA < argc ; ++iA ){ + const char *arg = argv[iA]; + if(0){ + }else if( !strcmp(arg,"--help") ){ + app->flg |= FLG_isHelp; return 0; + }else if( !strcmp(arg,"--pcap") ){ + arg = argv[++iA]; + if( arg == NULL ){ fprintf(stderr, "EINVAL --pcap needs value\n"); return -1; } + app->dumpFilePath = arg; + }else if( !strcmp(arg,"--pcap-stdin") ){ + app->dumpFilePath = DEV_STDIN; + }else{ + fprintf(stderr, "EINVAL: %s\n", arg); return -1; + } + } + if( app->dumpFilePath == NULL ){ + fprintf(stderr, "EINVAL Arg missing: --pcap <path>\n"); return -1; } + return 0; +} + + +static void onPcapPkg( u_char*user, const struct pcap_pkthdr*hdr, const u_char*buf ){ + int err; + PcapOne *const app = (void*)user; + + /* prepare for this new packet */ + app->frameNr += 1; + app->flg &= ~(FLG_isTcpPsh | FLG_isTcpRst | FLG_isTcpSyn | FLG_isTcpFin | FLG_isHttpReq); + + /* data-link layer */ + switch( pcap_datalink(app->pcap) ){ + case 0x71: parse_ll_LINUX_SLL(app, hdr, buf); break; + default: assert(!fprintf(stderr,"pcap_datalink() -> 0x%02X\n", pcap_datalink(app->pcap))); + } + + /* network layer */ + switch( app->llProto ){ + case 0x0800: parse_net_IPv4(app, hdr, buf); break; + default: printf("???, proto=0x%04X, network-layer\n", app->llProto); return; + } + + /* transport layer */ + switch( app->netProto ){ + case 0x06: parse_trsp_TCP(app, hdr, buf); break; + default: printf("???, proto=0x%02X, transport-layer\n", app->netProto); return; + } + + assert(app->trspBodyLen >= 0); + + /* application layer, towards server */ + switch( app->trspDstPort ){ + case 80: parse_appl_HTTP_req(app, hdr, buf); break; + case 7012: parse_appl_HTTP_req(app, hdr, buf); break; + case 8080: parse_appl_HTTP_req(app, hdr, buf); break; + } + + printParsingResults(app); +} + + +static void parse_ll_LINUX_SLL( PcapOne*app, const struct pcap_pkthdr*hdr, const u_char*buf ){ + assert(hdr->caplen >= 15); + app->llProto = buf[14]<<8 | buf[15]; + app->llHdrEnd = 16; +} + + +static void parse_net_IPv4( PcapOne*app, const struct pcap_pkthdr*hdr, const u_char*buf ){ + assert(hdr->caplen >= app->llHdrEnd+19 && "TODO_775afde7f19010220e9df8d5e2924c3e"); + int_fast8_t netHdrLen = (buf[app->llHdrEnd+0] & 0x0F) * 4; + app->netTotLen = buf[app->llHdrEnd+2] << 8 | buf[app->llHdrEnd+3]; + app->netProto = buf[app->llHdrEnd+9]; + app->ipSrcAddr = 0 + | ((uint_least32_t)buf[app->llHdrEnd+12]) << 24 + | ((uint_least32_t)buf[app->llHdrEnd+13]) << 16 + | buf[app->llHdrEnd+14] << 8 + | buf[app->llHdrEnd+15] ; + app->ipDstAddr = 0 + | ((uint_least32_t)buf[app->llHdrEnd+16]) << 24 + | ((uint_least32_t)buf[app->llHdrEnd+17]) << 16 + | buf[app->llHdrEnd+18] << 8 + | buf[app->llHdrEnd+19] ; + app->netHdrEnd = app->llHdrEnd + netHdrLen; + app->netBodyLen = app->netTotLen - netHdrLen; +} + + +static void parse_trsp_TCP( PcapOne*app, const struct pcap_pkthdr*hdr, const u_char*buf ){ + assert(hdr->caplen >= app->netHdrEnd+12 && "TODO_058d5f41043d383e1ba2c492d0db4b6a"); + app->trspSrcPort = buf[app->netHdrEnd+0] << 8 | buf[app->netHdrEnd+1]; + app->trspDstPort = buf[app->netHdrEnd+2] << 8 | buf[app->netHdrEnd+3]; + int tcpHdrLen = (buf[app->netHdrEnd+12] >> 4) * 4; + app->trspHdrEnd = app->netHdrEnd + tcpHdrLen; + app->trspBodyLen = app->netBodyLen - tcpHdrLen; +} + + +static void parse_appl_HTTP_req( PcapOne*app, const struct pcap_pkthdr*hdr, const u_char*buf ){ + app->flg |= FLG_isHttpReq; + app->httpReqHeadline = buf + app->trspHdrEnd; + app->httpReqHeadline_len = 0; + for(;; ++app->httpReqHeadline_len ){ + if( (app->trspHdrEnd + app->httpReqHeadline_len) > hdr->caplen ) break; + if( app->httpReqHeadline[app->httpReqHeadline_len] == '\r' ) break; + if( app->httpReqHeadline[app->httpReqHeadline_len] == '\n' ) break; + } + /* TODO improve, as now its like a guess only */ + int isNewRequest = 0 + | !memcmp(buf + app->trspHdrEnd, "GET ", 4) + | !memcmp(buf + app->trspHdrEnd, "PUT ", 4) + | !memcmp(buf + app->trspHdrEnd, "POST ", 5) + | !memcmp(buf + app->trspHdrEnd, "DELETE ", 7) + ; + if( isNewRequest ){ + app->httpReq_off = 0; + }else{ + app->httpReq_off = 42; /*TODO make more accurate*/ + } +} + + +static void printParsingResults( PcapOne*app ){ + int err; + + int isHttpRequest = (app->flg & FLG_isHttpReq); + int isHttpReqBegin = isHttpRequest && app->httpReq_off == 0; + + if( isHttpRequest && isHttpReqBegin ){ + /* find http method */ + const char *method = app->httpReqHeadline; + int method_len = 0; + for(;; ++method_len ){ + if( method_len > app->httpReqHeadline_len ) break; + if( method[method_len] == ' ' ) break; + } + /* find http uri */ + const char *uri = method + method_len + 1; + int uri_len = 0; + for(;; ++uri_len ){ + if( method_len + uri_len > app->httpReqHeadline_len ) break; + if( uri[uri_len] == ' ' ) break; + } + /* print it as a quick-n-dirty CSV record */ + printf("r;HTTP req;%.*s;%.*s\n", method_len, method, uri_len, uri); + } +} + + +static int run( PcapOne*app ){ + int err; + err = pcap_init(PCAP_CHAR_ENC_UTF_8, app->pcapErrbuf); + if( err == PCAP_ERROR ){ + fprintf(stderr, "libpcap: %s\n", app->pcapErrbuf); err = -1; goto endFn; } + app->pcap = pcap_open_offline( + (app->dumpFilePath == DEV_STDIN) ? "-" : app->dumpFilePath, + app->pcapErrbuf); + if( app->pcap == NULL ){ + fprintf(stderr, "libpcap: %s\n", app->pcapErrbuf); err = -1; goto endFn; } + for(;;){ + err = pcap_dispatch(app->pcap, -1, onPcapPkg, (void*)app); + switch( err ){ + case PCAP_ERROR: + fprintf(stderr, "pcap_dispatch(): %s\n", pcap_geterr(app->pcap)); + err = -1; goto endFn; + case PCAP_ERROR_BREAK: + case PCAP_ERROR_NOT_ACTIVATED: + fprintf(stderr, "pcap_dispatch() -> %d\n", err); + err = -1; goto endFn; + } + if( err > 0 ){ + fprintf(stderr, "Processed %d packages in this turn.\n", err); + continue; + } + break; + } + err = 0; +endFn: + if( app->pcap != NULL ){ pcap_close(app->pcap); app->pcap = NULL; } + return err; +} + + +int main( int argc, char**argv ){ + int err; + static char errbuf[PCAP_ERRBUF_SIZE]; + errbuf[0] = '\0'; + PcapOne app = { + .flg = FLG_INIT, + .pcapErrbuf = errbuf, + .pcap = NULL, + .frameNr = 0, + .trspBodyLen = 0, + }; + #define app (&app) + + err = parseArgs(app, argc, argv); + if( err ){ goto endFn; } + + if( app->flg & FLG_isHelp ){ + printHelp(); goto endFn; } + + err = run(app); + +endFn: + if( err < 0 ) err = -err; + if( err > 0x7F ) err = 1; + return err; + #undef app +} + + |