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