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