]> git.saurik.com Git - apple/xnu.git/blob - bsd/netinet/ip_log.c
xnu-124.13.tar.gz
[apple/xnu.git] / bsd / netinet / ip_log.c
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 */