1 /* $FreeBSD$ */ 2 3 /* 4 * Copyright (C) 2012 by Darren Reed. 5 * 6 * See the IPFILTER.LICENCE file for details on licencing. 7 * 8 * $Id$ 9 */ 10 #include "ipf.h" 11 #include "ipt.h" 12 13 #if !defined(lint) 14 static const char rcsid[] = "@(#)$Id$"; 15 #endif 16 17 struct llc { 18 int lc_type; 19 int lc_sz; /* LLC header length */ 20 int lc_to; /* LLC Type offset */ 21 int lc_tl; /* LLC Type length */ 22 }; 23 24 /* 25 * While many of these maybe the same, some do have different header formats 26 * which make this useful. 27 */ 28 29 static struct llc llcs[] = { 30 { 0, 0, 0, 0 }, /* DLT_NULL */ 31 { 1, 14, 12, 2 }, /* DLT_Ethernet */ 32 { 10, 0, 0, 0 }, /* DLT_FDDI */ 33 { 12, 0, 0, 0 }, /* DLT_RAW */ 34 { -1, -1, -1, -1 } 35 }; 36 37 typedef struct { 38 u_int id; 39 u_short major; 40 u_short minor; 41 u_int timezone; 42 u_int sigfigs; 43 u_int snaplen; 44 u_int type; 45 } fileheader_t; 46 47 typedef struct { 48 u_32_t seconds; 49 u_32_t microseconds; 50 u_32_t caplen; 51 u_32_t wirelen; 52 } packetheader_t; 53 54 static int ipcap_open(char *); 55 static int ipcap_close(void); 56 static int ipcap_readip(mb_t *, char **, int *); 57 static int ipcap_read_rec(packetheader_t *); 58 static void iswap_hdr(fileheader_t *); 59 60 static int pfd = -1, swapped = 0; 61 static struct llc *llcp = NULL; 62 63 struct ipread pcap = { ipcap_open, ipcap_close, ipcap_readip, 0 }; 64 65 #define SWAPLONG(y) \ 66 ((((y)&0xff)<<24) | (((y)&0xff00)<<8) | (((y)&0xff0000)>>8) | (((y)>>24)&0xff)) 67 #define SWAPSHORT(y) \ 68 ( (((y)&0xff)<<8) | (((y)&0xff00)>>8) ) 69 70 static void 71 iswap_hdr(fileheader_t *p) 72 { 73 p->major = SWAPSHORT(p->major); 74 p->minor = SWAPSHORT(p->minor); 75 p->timezone = SWAPLONG(p->timezone); 76 p->sigfigs = SWAPLONG(p->sigfigs); 77 p->snaplen = SWAPLONG(p->snaplen); 78 p->type = SWAPLONG(p->type); 79 } 80 81 static int 82 ipcap_open(char *fname) 83 { 84 fileheader_t ph; 85 int fd, i; 86 87 if (pfd != -1) 88 return (pfd); 89 90 if (!strcmp(fname, "-")) 91 fd = 0; 92 else if ((fd = open(fname, O_RDONLY)) == -1) 93 return (-1); 94 95 if (read(fd, (char *)&ph, sizeof(ph)) != sizeof(ph)) 96 return (-2); 97 98 if (ph.id != 0xa1b2c3d4) { 99 if (SWAPLONG(ph.id) != 0xa1b2c3d4) { 100 (void) close(fd); 101 return (-2); 102 } 103 swapped = 1; 104 iswap_hdr(&ph); 105 } 106 107 for (i = 0; llcs[i].lc_type != -1; i++) 108 if (llcs[i].lc_type == ph.type) { 109 llcp = llcs + i; 110 break; 111 } 112 113 if (llcp == NULL) { 114 (void) close(fd); 115 return (-2); 116 } 117 118 pfd = fd; 119 printf("opened pcap file %s:\n", fname); 120 printf("\tid: %08x version: %d.%d type: %d snap %d\n", 121 ph.id, ph.major, ph.minor, ph.type, ph.snaplen); 122 123 return (fd); 124 } 125 126 127 static int 128 ipcap_close(void) 129 { 130 return (close(pfd)); 131 } 132 133 134 /* 135 * read in the header (and validate) which should be the first record 136 * in a pcap file. 137 */ 138 static int 139 ipcap_read_rec(packetheader_t *rec) 140 { 141 int n, p, i; 142 143 n = sizeof(*rec); 144 145 while (n > 0) { 146 i = read(pfd, (char *)rec, sizeof(*rec)); 147 if (i <= 0) 148 return (-2); 149 n -= i; 150 } 151 152 if (swapped) { 153 rec->caplen = SWAPLONG(rec->caplen); 154 rec->wirelen = SWAPLONG(rec->wirelen); 155 rec->seconds = SWAPLONG(rec->seconds); 156 rec->microseconds = SWAPLONG(rec->microseconds); 157 } 158 p = rec->caplen; 159 n = MIN(p, rec->wirelen); 160 if (!n || n < 0) 161 return (-3); 162 163 if (p < 0 || p > 65536) 164 return (-4); 165 return (p); 166 } 167 168 169 #ifdef notyet 170 /* 171 * read an entire pcap packet record. only the data part is copied into 172 * the available buffer, with the number of bytes copied returned. 173 */ 174 static int 175 ipcap_read(char *buf, int cnt) 176 { 177 packetheader_t rec; 178 static char *bufp = NULL; 179 int i, n; 180 181 if ((i = ipcap_read_rec(&rec)) <= 0) 182 return (i); 183 184 if (!bufp) 185 bufp = malloc(i); 186 else 187 bufp = realloc(bufp, i); 188 189 if (read(pfd, bufp, i) != i) 190 return (-2); 191 192 n = MIN(i, cnt); 193 bcopy(bufp, buf, n); 194 return (n); 195 } 196 #endif 197 198 199 /* 200 * return only an IP packet read into buf 201 */ 202 static int 203 ipcap_readip(mb_t *mb, char **ifn, int *dir) 204 { 205 static char *bufp = NULL; 206 packetheader_t rec; 207 struct llc *l; 208 char *s, ty[4]; 209 int i, j, n; 210 char *buf; 211 int cnt; 212 213 #if 0 214 ifn = ifn; /* gcc -Wextra */ 215 dir = dir; /* gcc -Wextra */ 216 #endif 217 buf = (char *)mb->mb_buf; 218 cnt = sizeof(mb->mb_buf); 219 l = llcp; 220 221 /* do { */ 222 if ((i = ipcap_read_rec(&rec)) <= 0) 223 return (i); 224 225 if (!bufp) 226 bufp = malloc(i); 227 else 228 bufp = realloc(bufp, i); 229 s = bufp; 230 231 for (j = i, n = 0; j > 0; ) { 232 n = read(pfd, s, j); 233 if (n <= 0) 234 return (-2); 235 j -= n; 236 s += n; 237 } 238 s = bufp; 239 240 i -= l->lc_sz; 241 s += l->lc_to; 242 bcopy(s, ty, l->lc_tl); 243 s += l->lc_tl; 244 /* } while (ty[0] != 0x8 && ty[1] != 0); */ 245 n = MIN(i, cnt); 246 bcopy(s, buf, n); 247 mb->mb_len = n; 248 return (n); 249 } 250