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
iswap_hdr(fileheader_t * p)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
ipcap_open(char * fname)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
ipcap_close(void)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
ipcap_read_rec(packetheader_t * rec)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
ipcap_read(char * buf,int cnt)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
ipcap_readip(mb_t * mb,char ** ifn,int * dir)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