1145519Sdarrenr/* $FreeBSD$ */ 2145510Sdarrenr 3145510Sdarrenr/* 4255332Scy * Copyright (C) 2012 by Darren Reed. 5145510Sdarrenr * 6145510Sdarrenr * See the IPFILTER.LICENCE file for details on licencing. 7145510Sdarrenr * 8255332Scy * $Id$ 9145510Sdarrenr */ 10145510Sdarrenr#include "ipf.h" 11145510Sdarrenr#include "ipt.h" 12145510Sdarrenr 13145510Sdarrenr#if !defined(lint) 14255332Scystatic const char rcsid[] = "@(#)$Id$"; 15145510Sdarrenr#endif 16145510Sdarrenr 17145510Sdarrenrstruct llc { 18145510Sdarrenr int lc_type; 19145510Sdarrenr int lc_sz; /* LLC header length */ 20145510Sdarrenr int lc_to; /* LLC Type offset */ 21145510Sdarrenr int lc_tl; /* LLC Type length */ 22145510Sdarrenr}; 23145510Sdarrenr 24145510Sdarrenr/* 25145510Sdarrenr * While many of these maybe the same, some do have different header formats 26145510Sdarrenr * which make this useful. 27145510Sdarrenr */ 28145510Sdarrenr 29145510Sdarrenrstatic struct llc llcs[] = { 30255332Scy { 0, 0, 0, 0 }, /* DLT_NULL */ 31255332Scy { 1, 14, 12, 2 }, /* DLT_Ethernet */ 32255332Scy { 10, 0, 0, 0 }, /* DLT_FDDI */ 33255332Scy { 12, 0, 0, 0 }, /* DLT_RAW */ 34145510Sdarrenr { -1, -1, -1, -1 } 35145510Sdarrenr}; 36145510Sdarrenr 37255332Scytypedef struct { 38255332Scy u_int id; 39255332Scy u_short major; 40255332Scy u_short minor; 41255332Scy u_int timezone; 42255332Scy u_int sigfigs; 43255332Scy u_int snaplen; 44255332Scy u_int type; 45255332Scy} fileheader_t; 46145510Sdarrenr 47255332Scytypedef struct { 48255332Scy u_32_t seconds; 49255332Scy u_32_t microseconds; 50255332Scy u_32_t caplen; 51255332Scy u_32_t wirelen; 52255332Scy} packetheader_t; 53255332Scy 54255332Scystatic int ipcap_open __P((char *)); 55255332Scystatic int ipcap_close __P((void)); 56255332Scystatic int ipcap_readip __P((mb_t *, char **, int *)); 57255332Scystatic int ipcap_read_rec __P((packetheader_t *)); 58255332Scystatic void iswap_hdr __P((fileheader_t *)); 59255332Scy 60145510Sdarrenrstatic int pfd = -1, swapped = 0; 61145510Sdarrenrstatic struct llc *llcp = NULL; 62145510Sdarrenr 63255332Scystruct ipread pcap = { ipcap_open, ipcap_close, ipcap_readip, 0 }; 64145510Sdarrenr 65145510Sdarrenr#define SWAPLONG(y) \ 66145510Sdarrenr ((((y)&0xff)<<24) | (((y)&0xff00)<<8) | (((y)&0xff0000)>>8) | (((y)>>24)&0xff)) 67145510Sdarrenr#define SWAPSHORT(y) \ 68145510Sdarrenr ( (((y)&0xff)<<8) | (((y)&0xff00)>>8) ) 69145510Sdarrenr 70255332Scystatic void iswap_hdr(p) 71255332Scy fileheader_t *p; 72145510Sdarrenr{ 73255332Scy p->major = SWAPSHORT(p->major); 74255332Scy p->minor = SWAPSHORT(p->minor); 75255332Scy p->timezone = SWAPLONG(p->timezone); 76255332Scy p->sigfigs = SWAPLONG(p->sigfigs); 77255332Scy p->snaplen = SWAPLONG(p->snaplen); 78255332Scy p->type = SWAPLONG(p->type); 79145510Sdarrenr} 80145510Sdarrenr 81255332Scystatic int ipcap_open(fname) 82255332Scy char *fname; 83145510Sdarrenr{ 84255332Scy fileheader_t ph; 85145510Sdarrenr int fd, i; 86145510Sdarrenr 87145510Sdarrenr if (pfd != -1) 88145510Sdarrenr return pfd; 89145510Sdarrenr 90145510Sdarrenr if (!strcmp(fname, "-")) 91145510Sdarrenr fd = 0; 92145510Sdarrenr else if ((fd = open(fname, O_RDONLY)) == -1) 93145510Sdarrenr return -1; 94145510Sdarrenr 95145510Sdarrenr if (read(fd, (char *)&ph, sizeof(ph)) != sizeof(ph)) 96145510Sdarrenr return -2; 97145510Sdarrenr 98255332Scy if (ph.id != 0xa1b2c3d4) { 99255332Scy if (SWAPLONG(ph.id) != 0xa1b2c3d4) { 100145510Sdarrenr (void) close(fd); 101145510Sdarrenr return -2; 102145510Sdarrenr } 103145510Sdarrenr swapped = 1; 104255332Scy iswap_hdr(&ph); 105145510Sdarrenr } 106145510Sdarrenr 107145510Sdarrenr for (i = 0; llcs[i].lc_type != -1; i++) 108255332Scy if (llcs[i].lc_type == ph.type) { 109145510Sdarrenr llcp = llcs + i; 110145510Sdarrenr break; 111145510Sdarrenr } 112145510Sdarrenr 113145510Sdarrenr if (llcp == NULL) { 114145510Sdarrenr (void) close(fd); 115145510Sdarrenr return -2; 116145510Sdarrenr } 117145510Sdarrenr 118145510Sdarrenr pfd = fd; 119145510Sdarrenr printf("opened pcap file %s:\n", fname); 120145510Sdarrenr printf("\tid: %08x version: %d.%d type: %d snap %d\n", 121255332Scy ph.id, ph.major, ph.minor, ph.type, ph.snaplen); 122145510Sdarrenr 123145510Sdarrenr return fd; 124145510Sdarrenr} 125145510Sdarrenr 126145510Sdarrenr 127255332Scystatic int ipcap_close() 128145510Sdarrenr{ 129145510Sdarrenr return close(pfd); 130145510Sdarrenr} 131145510Sdarrenr 132145510Sdarrenr 133145510Sdarrenr/* 134145510Sdarrenr * read in the header (and validate) which should be the first record 135145510Sdarrenr * in a pcap file. 136145510Sdarrenr */ 137255332Scystatic int ipcap_read_rec(rec) 138255332Scy packetheader_t *rec; 139145510Sdarrenr{ 140153881Sguido int n, p, i; 141153881Sguido char *s; 142145510Sdarrenr 143153881Sguido s = (char *)rec; 144153881Sguido n = sizeof(*rec); 145145510Sdarrenr 146153881Sguido while (n > 0) { 147153881Sguido i = read(pfd, (char *)rec, sizeof(*rec)); 148153881Sguido if (i <= 0) 149153881Sguido return -2; 150153881Sguido s += i; 151153881Sguido n -= i; 152153881Sguido } 153153881Sguido 154145510Sdarrenr if (swapped) { 155255332Scy rec->caplen = SWAPLONG(rec->caplen); 156255332Scy rec->wirelen = SWAPLONG(rec->wirelen); 157255332Scy rec->seconds = SWAPLONG(rec->seconds); 158255332Scy rec->microseconds = SWAPLONG(rec->microseconds); 159145510Sdarrenr } 160255332Scy p = rec->caplen; 161255332Scy n = MIN(p, rec->wirelen); 162145510Sdarrenr if (!n || n < 0) 163145510Sdarrenr return -3; 164145510Sdarrenr 165153881Sguido if (p < 0 || p > 65536) 166153881Sguido return -4; 167145510Sdarrenr return p; 168145510Sdarrenr} 169145510Sdarrenr 170145510Sdarrenr 171145510Sdarrenr#ifdef notyet 172145510Sdarrenr/* 173145510Sdarrenr * read an entire pcap packet record. only the data part is copied into 174145510Sdarrenr * the available buffer, with the number of bytes copied returned. 175145510Sdarrenr */ 176255332Scystatic int ipcap_read(buf, cnt) 177255332Scy char *buf; 178255332Scy int cnt; 179145510Sdarrenr{ 180255332Scy packetheader_t rec; 181145510Sdarrenr static char *bufp = NULL; 182145510Sdarrenr int i, n; 183145510Sdarrenr 184255332Scy if ((i = ipcap_read_rec(&rec)) <= 0) 185145510Sdarrenr return i; 186145510Sdarrenr 187145510Sdarrenr if (!bufp) 188145510Sdarrenr bufp = malloc(i); 189145510Sdarrenr else 190145510Sdarrenr bufp = realloc(bufp, i); 191145510Sdarrenr 192145510Sdarrenr if (read(pfd, bufp, i) != i) 193145510Sdarrenr return -2; 194145510Sdarrenr 195145510Sdarrenr n = MIN(i, cnt); 196145510Sdarrenr bcopy(bufp, buf, n); 197145510Sdarrenr return n; 198145510Sdarrenr} 199145510Sdarrenr#endif 200145510Sdarrenr 201145510Sdarrenr 202145510Sdarrenr/* 203145510Sdarrenr * return only an IP packet read into buf 204145510Sdarrenr */ 205255332Scystatic int ipcap_readip(mb, ifn, dir) 206255332Scy mb_t *mb; 207255332Scy char **ifn; 208255332Scy int *dir; 209145510Sdarrenr{ 210145510Sdarrenr static char *bufp = NULL; 211255332Scy packetheader_t rec; 212145510Sdarrenr struct llc *l; 213145510Sdarrenr char *s, ty[4]; 214153881Sguido int i, j, n; 215255332Scy char *buf; 216255332Scy int cnt; 217145510Sdarrenr 218255332Scy#if 0 219255332Scy ifn = ifn; /* gcc -Wextra */ 220255332Scy dir = dir; /* gcc -Wextra */ 221255332Scy#endif 222255332Scy buf = (char *)mb->mb_buf; 223255332Scy cnt = sizeof(mb->mb_buf); 224145510Sdarrenr l = llcp; 225145510Sdarrenr 226145510Sdarrenr /* do { */ 227255332Scy if ((i = ipcap_read_rec(&rec)) <= 0) 228145510Sdarrenr return i; 229145510Sdarrenr 230145510Sdarrenr if (!bufp) 231145510Sdarrenr bufp = malloc(i); 232145510Sdarrenr else 233145510Sdarrenr bufp = realloc(bufp, i); 234145510Sdarrenr s = bufp; 235145510Sdarrenr 236153881Sguido for (j = i, n = 0; j > 0; ) { 237153881Sguido n = read(pfd, s, j); 238153881Sguido if (n <= 0) 239153881Sguido return -2; 240153881Sguido j -= n; 241153881Sguido s += n; 242153881Sguido } 243153881Sguido s = bufp; 244145510Sdarrenr 245145510Sdarrenr i -= l->lc_sz; 246145510Sdarrenr s += l->lc_to; 247145510Sdarrenr bcopy(s, ty, l->lc_tl); 248145510Sdarrenr s += l->lc_tl; 249145510Sdarrenr /* } while (ty[0] != 0x8 && ty[1] != 0); */ 250145510Sdarrenr n = MIN(i, cnt); 251145510Sdarrenr bcopy(s, buf, n); 252255332Scy mb->mb_len = n; 253145510Sdarrenr return n; 254145510Sdarrenr} 255