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