FreeBSD/Linux Kernel Cross Reference
sys/netinet/ip_log.c
1 /*
2 * Copyright (C) 1997 by Darren Reed.
3 *
4 * Redistribution and use in source and binary forms are permitted
5 * provided that this notice is preserved and due credit is given
6 * to the original author and the contributors.
7 *
8 * $FreeBSD$
9 */
10 #include "opt_ipfilter.h"
11
12 #ifdef IPFILTER_LOG
13 # ifndef SOLARIS
14 # define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4)))
15 # endif
16
17 # if defined(KERNEL) && !defined(_KERNEL)
18 # define _KERNEL
19 # endif
20 # ifdef __FreeBSD__
21 # if defined(_KERNEL) && !defined(IPFILTER_LKM)
22 # define __FreeBSD_version 300000 /* this will do as a hack */
23 # else
24 # include <osreldate.h>
25 # endif
26 # endif
27 # ifndef _KERNEL
28 # include <stdio.h>
29 # include <string.h>
30 # include <stdlib.h>
31 # include <ctype.h>
32 # endif
33 # include <sys/errno.h>
34 # include <sys/types.h>
35 # include <sys/param.h>
36 # include <sys/file.h>
37 # if __FreeBSD_version >= 220000 && defined(_KERNEL)
38 # include <sys/fcntl.h>
39 # include <sys/filio.h>
40 # else
41 # include <sys/ioctl.h>
42 # endif
43 # include <sys/time.h>
44 # if defined(_KERNEL) && !defined(linux)
45 # include <sys/systm.h>
46 # endif
47 # include <sys/uio.h>
48 # if !SOLARIS
49 # if (NetBSD > 199609) || (OpenBSD > 199603) || defined(__FreeBSD__)
50 # include <sys/dirent.h>
51 # else
52 # include <sys/dir.h>
53 # endif
54 # ifndef linux
55 # include <sys/mbuf.h>
56 # endif
57 # else
58 # include <sys/filio.h>
59 # include <sys/cred.h>
60 # include <sys/ddi.h>
61 # include <sys/sunddi.h>
62 # include <sys/ksynch.h>
63 # include <sys/kmem.h>
64 # include <sys/mkdev.h>
65 # include <sys/dditypes.h>
66 # include <sys/cmn_err.h>
67 # endif
68 # ifndef linux
69 # include <sys/protosw.h>
70 # endif
71 # include <sys/socket.h>
72
73 # include <net/if.h>
74 # ifdef sun
75 # include <net/af.h>
76 # endif
77 # if __FreeBSD_version >= 300000
78 # include <sys/malloc.h>
79 # include <machine/random.h>
80 # endif
81 # include <net/route.h>
82 # include <netinet/in.h>
83 # ifdef __sgi
84 # include <sys/ddi.h>
85 # ifdef IFF_DRVRLOCK /* IRIX6 */
86 # include <sys/hashing.h>
87 # endif
88 # endif
89 # if !defined(linux) && !(defined(__sgi) && !defined(IFF_DRVRLOCK)) /*IRIX<6*/
90 # include <netinet/in_var.h>
91 # endif
92 # include <netinet/in_systm.h>
93 # include <netinet/ip.h>
94 # include <netinet/tcp.h>
95 # include <netinet/udp.h>
96 # include <netinet/ip_icmp.h>
97 # ifndef linux
98 # include <netinet/ip_var.h>
99 # endif
100 # ifndef _KERNEL
101 # include <syslog.h>
102 # endif
103 # include "netinet/ip_compat.h"
104 # include <netinet/tcpip.h>
105 # include "netinet/ip_fil.h"
106 # include "netinet/ip_proxy.h"
107 # include "netinet/ip_nat.h"
108 # include "netinet/ip_frag.h"
109 # include "netinet/ip_state.h"
110 # include "netinet/ip_auth.h"
111 # ifndef MIN
112 # define MIN(a,b) (((a)<(b))?(a):(b))
113 # endif
114
115
116 # if SOLARIS || defined(__sgi)
117 extern kmutex_t ipl_mutex;
118 # if SOLARIS
119 extern kcondvar_t iplwait;
120 # endif
121 # endif
122
123 iplog_t **iplh[IPL_LOGMAX+1], *iplt[IPL_LOGMAX+1];
124 int iplused[IPL_LOGMAX+1];
125 static u_long iplcrc[IPL_LOGMAX+1];
126 static u_long iplcrcinit;
127 #ifdef linux
128 static struct wait_queue *iplwait[IPL_LOGMAX+1];
129 #endif
130
131
132 /*
133 * Initialise log buffers & pointers. Also iniialised the CRC to a local
134 * secret for use in calculating the "last log checksum".
135 */
136 void ipflog_init()
137 {
138 int i;
139
140 for (i = IPL_LOGMAX; i >= 0; i--) {
141 iplt[i] = NULL;
142 iplh[i] = &iplt[i];
143 iplused[i] = 0;
144 }
145 # if defined(__FreeBSD__) && __FreeBSD_version >= 300000
146 read_random(&iplcrcinit, sizeof iplcrcinit);
147 # else
148 {
149 struct timeval tv;
150
151 #if BSD >= 199306 || defined(__FreeBSD__) || defined(__sgi)
152 microtime(&tv);
153 # else
154 uniqtime(&tv);
155 # endif
156 iplcrcinit = tv.tv_sec ^ (tv.tv_usec << 8) ^ tv.tv_usec;
157 }
158 # endif
159 }
160
161
162 /*
163 * ipflog
164 * Create a log record for a packet given that it has been triggered by a
165 * rule (or the default setting). Calculate the transport protocol header
166 * size using predetermined size of a couple of popular protocols and thus
167 * how much data to copy into the log, including part of the data body if
168 * requested.
169 */
170 int ipflog(flags, ip, fin, m)
171 u_int flags;
172 ip_t *ip;
173 fr_info_t *fin;
174 mb_t *m;
175 {
176 ipflog_t ipfl;
177 register int mlen, hlen;
178 u_long crc;
179 size_t sizes[2];
180 void *ptrs[2];
181 int types[2];
182 # if SOLARIS
183 ill_t *ifp = fin->fin_ifp;
184 # else
185 struct ifnet *ifp = fin->fin_ifp;
186 # endif
187
188 /*
189 * calculate header size.
190 */
191 hlen = fin->fin_hlen;
192 if (ip->ip_p == IPPROTO_TCP)
193 hlen += MIN(sizeof(tcphdr_t), fin->fin_dlen);
194 else if (ip->ip_p == IPPROTO_UDP)
195 hlen += MIN(sizeof(udphdr_t), fin->fin_dlen);
196 else if (ip->ip_p == IPPROTO_ICMP) {
197 struct icmp *icmp = (struct icmp *)((char *)ip + hlen);
198
199 /*
200 * For ICMP, if the packet is an error packet, also include
201 * the information about the packet which caused the error.
202 */
203 switch (icmp->icmp_type)
204 {
205 case ICMP_UNREACH :
206 case ICMP_SOURCEQUENCH :
207 case ICMP_REDIRECT :
208 case ICMP_TIMXCEED :
209 case ICMP_PARAMPROB :
210 hlen += MIN(sizeof(struct icmp) + 8, fin->fin_dlen);
211 break;
212 default :
213 hlen += MIN(sizeof(struct icmp), fin->fin_dlen);
214 break;
215 }
216 }
217 /*
218 * Get the interface number and name to which this packet is
219 * currently associated.
220 */
221 # if SOLARIS
222 ipfl.fl_unit = (u_char)ifp->ill_ppa;
223 bcopy(ifp->ill_name, ipfl.fl_ifname, MIN(ifp->ill_name_length, 4));
224 mlen = (flags & FR_LOGBODY) ? MIN(msgdsize(m) - hlen, 128) : 0;
225 # else
226 # if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199603)) || \
227 (defined(OpenBSD) && (OpenBSD >= 199603))
228 strncpy(ipfl.fl_ifname, ifp->if_xname, IFNAMSIZ);
229 # else
230 # ifndef linux
231 ipfl.fl_unit = (u_char)ifp->if_unit;
232 # endif
233 if ((ipfl.fl_ifname[0] = ifp->if_name[0]))
234 if ((ipfl.fl_ifname[1] = ifp->if_name[1]))
235 if ((ipfl.fl_ifname[2] = ifp->if_name[2]))
236 ipfl.fl_ifname[3] = ifp->if_name[3];
237 # endif
238 mlen = (flags & FR_LOGBODY) ? MIN(ip->ip_len - hlen, 128) : 0;
239 # endif
240 ipfl.fl_plen = (u_char)mlen;
241 ipfl.fl_hlen = (u_char)hlen;
242 ipfl.fl_rule = fin->fin_rule;
243 ipfl.fl_group = fin->fin_group;
244 ipfl.fl_flags = flags;
245 ptrs[0] = (void *)&ipfl;
246 sizes[0] = sizeof(ipfl);
247 types[0] = 0;
248 #if SOLARIS
249 /*
250 * Are we copied from the mblk or an aligned array ?
251 */
252 if (ip == (ip_t *)m->b_rptr) {
253 ptrs[1] = m;
254 sizes[1] = hlen + mlen;
255 types[1] = 1;
256 } else {
257 ptrs[1] = ip;
258 sizes[1] = hlen + mlen;
259 types[1] = 0;
260 }
261 #else
262 ptrs[1] = m;
263 sizes[1] = hlen + mlen;
264 types[1] = 1;
265 #endif
266 crc = (ipf_cksum((u_short *)fin, FI_CSIZE) << 8) + iplcrcinit;
267 return ipllog(IPL_LOGIPF, crc, ptrs, sizes, types, 2);
268 }
269
270
271 /*
272 * ipllog
273 */
274 int ipllog(dev, crc, items, itemsz, types, cnt)
275 int dev;
276 u_long crc;
277 void **items;
278 size_t *itemsz;
279 int *types, cnt;
280 {
281 iplog_t *ipl;
282 caddr_t buf, s;
283 int len, i;
284
285 /*
286 * Check to see if this log record has a CRC which matches the last
287 * record logged. If it does, just up the count on the previous one
288 * rather than create a new one.
289 */
290 if (crc) {
291 MUTEX_ENTER(&ipl_mutex);
292 if ((iplcrc[dev] == crc) && *iplh[dev]) {
293 (*iplh[dev])->ipl_count++;
294 MUTEX_EXIT(&ipl_mutex);
295 return 1;
296 }
297 iplcrc[dev] = crc;
298 MUTEX_EXIT(&ipl_mutex);
299 }
300
301 /*
302 * Get the total amount of data to be logged.
303 */
304 for (i = 0, len = sizeof(iplog_t); i < cnt; i++)
305 len += itemsz[i];
306
307 /*
308 * check that we have space to record this information and can
309 * allocate that much.
310 */
311 KMALLOC(buf, caddr_t, len);
312 if (!buf)
313 return 0;
314 MUTEX_ENTER(&ipl_mutex);
315 if ((iplused[dev] + len) > IPLLOGSIZE) {
316 MUTEX_EXIT(&ipl_mutex);
317 KFREES(buf, len);
318 return 0;
319 }
320 iplused[dev] += len;
321 MUTEX_EXIT(&ipl_mutex);
322
323 /*
324 * advance the log pointer to the next empty record and deduct the
325 * amount of space we're going to use.
326 */
327 ipl = (iplog_t *)buf;
328 ipl->ipl_magic = IPL_MAGIC;
329 ipl->ipl_count = 1;
330 ipl->ipl_next = NULL;
331 ipl->ipl_dsize = len;
332 # if SOLARIS || defined(sun) || defined(linux)
333 uniqtime((struct timeval *)&ipl->ipl_sec);
334 # else
335 # if BSD >= 199306 || defined(__FreeBSD__) || defined(__sgi)
336 microtime((struct timeval *)&ipl->ipl_sec);
337 # endif
338 # endif
339
340 /*
341 * Loop through all the items to be logged, copying each one to the
342 * buffer. Use bcopy for normal data or the mb_t copyout routine.
343 */
344 for (i = 0, s = buf + sizeof(*ipl); i < cnt; i++) {
345 if (types[i] == 0)
346 bcopy(items[i], s, itemsz[i]);
347 else if (types[i] == 1) {
348 # if SOLARIS
349 copyout_mblk(items[i], 0, itemsz[i], s);
350 # else
351 m_copydata(items[i], 0, itemsz[i], s);
352 # endif
353 }
354 s += itemsz[i];
355 }
356 MUTEX_ENTER(&ipl_mutex);
357 *iplh[dev] = ipl;
358 iplh[dev] = &ipl->ipl_next;
359 # if SOLARIS
360 cv_signal(&iplwait);
361 mutex_exit(&ipl_mutex);
362 # else
363 MUTEX_EXIT(&ipl_mutex);
364 # ifdef linux
365 wake_up_interruptible(&iplwait[dev]);
366 # else
367 wakeup(&iplh[dev]);
368 # endif
369 # endif
370 return 1;
371 }
372
373
374 int ipflog_read(unit, uio)
375 int unit;
376 struct uio *uio;
377 {
378 iplog_t *ipl;
379 int error = 0, dlen, copied;
380 # if defined(_KERNEL) && !SOLARIS
381 int s;
382 # endif
383
384 /*
385 * Sanity checks. Make sure the minor # is valid and we're copying
386 * a valid chunk of data.
387 */
388 if ((IPL_LOGMAX < unit) || (unit < 0))
389 return ENXIO;
390 if (!uio->uio_resid)
391 return 0;
392 if ((uio->uio_resid < sizeof(iplog_t)) ||
393 (uio->uio_resid > IPLLOGSIZE))
394 return EINVAL;
395
396 /*
397 * Lock the log so we can snapshot the variables. Wait for a signal
398 * if the log is empty.
399 */
400 SPL_NET(s);
401 MUTEX_ENTER(&ipl_mutex);
402
403 while (!iplused[unit] || !iplt[unit]) {
404 # if SOLARIS && defined(_KERNEL)
405 if (!cv_wait_sig(&iplwait, &ipl_mutex)) {
406 MUTEX_EXIT(&ipl_mutex);
407 return EINTR;
408 }
409 # else
410 # ifdef linux
411 interruptible_sleep_on(&iplwait[unit]);
412 if (current->signal & ~current->blocked)
413 return -EINTR;
414 # else
415 MUTEX_EXIT(&ipl_mutex);
416 SPL_X(s);
417 error = SLEEP(&iplh[unit], "ipl sleep");
418 if (error)
419 return error;
420 SPL_NET(s);
421 MUTEX_ENTER(&ipl_mutex);
422 # endif /* linux */
423 # endif /* SOLARIS */
424 }
425
426 # if BSD >= 199306 || defined(__FreeBSD__)
427 uio->uio_rw = UIO_READ;
428 # endif
429
430 for (copied = 0; (ipl = iplt[unit]); copied += dlen) {
431 dlen = ipl->ipl_dsize;
432 if (dlen + sizeof(iplog_t) > uio->uio_resid)
433 break;
434 /*
435 * Don't hold the mutex over the uiomove call.
436 */
437 iplt[unit] = ipl->ipl_next;
438 MUTEX_EXIT(&ipl_mutex);
439 SPL_X(s);
440 error = UIOMOVE((caddr_t)ipl, ipl->ipl_dsize, UIO_READ, uio);
441 KFREES((caddr_t)ipl, ipl->ipl_dsize);
442 if (error)
443 break;
444 SPL_NET(s);
445 MUTEX_ENTER(&ipl_mutex);
446 iplused[unit] -= dlen;
447 }
448 if (!ipl) {
449 iplused[unit] = 0;
450 iplh[unit] = &iplt[unit];
451 }
452
453 if (!error) {
454 MUTEX_EXIT(&ipl_mutex);
455 SPL_X(s);
456 }
457 #ifdef linux
458 if (!error)
459 return copied;
460 return -error;
461 #else
462 return error;
463 #endif
464 }
465
466
467 int ipflog_clear(unit)
468 int unit;
469 {
470 iplog_t *ipl;
471 int used;
472
473 while ((ipl = iplt[unit])) {
474 iplt[unit] = ipl->ipl_next;
475 KFREES((caddr_t)ipl, ipl->ipl_dsize);
476 }
477 iplh[unit] = &iplt[unit];
478 used = iplused[unit];
479 iplused[unit] = 0;
480 iplcrc[unit] = 0;
481 return used;
482 }
483 #endif /* IPFILTER_LOG */
Cache object: aff61141f8550df6116c4e0a6faf0fc9
|