Merge from vendor branch GCC:
[dragonfly.git] / sys / contrib / ipfilter / netinet / ip_log.c
1 /*
2  * Copyright (C) 1997-2001 by Darren Reed.
3  *
4  * See the IPFILTER.LICENCE file for details on licencing.
5  *
6  * $Id: ip_log.c,v 2.5.2.1 2000/07/19 13:11:47 darrenr Exp $
7  * $FreeBSD: src/sys/contrib/ipfilter/netinet/ip_log.c,v 1.17.2.4 2003/03/01 03:55:54 darrenr Exp $
8  * $DragonFly: src/sys/contrib/ipfilter/netinet/ip_log.c,v 1.6 2004/02/12 22:35:47 joerg Exp $
9  */
10 #include <sys/param.h>
11 #if defined(KERNEL) && !defined(_KERNEL)
12 # define       _KERNEL
13 #endif
14 #if defined(__NetBSD__) && (NetBSD >= 199905) && !defined(IPFILTER_LKM) && \
15     defined(_KERNEL)
16 # include "opt_ipfilter_log.h"
17 #endif
18 #if  defined(__DragonFly__) || defined(__FreeBSD__)
19 # if defined(IPFILTER_LKM) || defined(_KERNEL)
20 #  if !defined(__FreeBSD_version) 
21 #   include <sys/osreldate.h>
22 #  endif
23 #  if !defined(IPFILTER_LKM)
24 #   if defined(__DragonFly__) || (defined(__FreeBSD_version) && (__FreeBSD_version >= 300000))
25 #    include "opt_ipfilter.h"
26 #   endif
27 #  endif
28 # else
29 #  ifdef KLD_MODULE
30 #   ifndef __FreeBSD_cc_version
31 #    include <osreldate.h>
32 #   else
33 #    if __FreeBSD_cc_version < 430000
34 #     include <osreldate.h>
35 #    endif
36 #   endif
37 #  endif
38 # endif
39 #endif
40 #ifdef  IPFILTER_LOG
41 # ifndef SOLARIS
42 #  define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4)))
43 # endif
44 # ifndef _KERNEL
45 #  include <stdio.h>
46 #  include <string.h>
47 #  include <stdlib.h>
48 #  include <ctype.h>
49 # endif
50 # include <sys/errno.h>
51 # include <sys/types.h>
52 # include <sys/file.h>
53 # if (defined(__DragonFly__) || __FreeBSD_version >= 220000) && defined(_KERNEL)
54 #  include <sys/fcntl.h>
55 #  include <sys/filio.h>
56 # else
57 #  include <sys/ioctl.h>
58 # endif
59 # include <sys/time.h>
60 # if defined(_KERNEL)
61 #  include <sys/systm.h>
62 # endif
63 # if !SOLARIS
64 #  if defined(__DragonFly__) || (NetBSD > 199609) || (OpenBSD > 199603) || (__FreeBSD_version >= 300000)
65 #   include <sys/dirent.h>
66 #  else
67 #   include <sys/dir.h>
68 #  endif
69 #  include <sys/mbuf.h>
70 # else
71 #  include <sys/filio.h>
72 #  include <sys/cred.h>
73 #  include <sys/kmem.h>
74 #  ifdef _KERNEL
75 #   include <sys/ddi.h>
76 #   include <sys/sunddi.h>
77 #   include <sys/ksynch.h>
78 #   include <sys/dditypes.h>
79 #   include <sys/cmn_err.h>
80 #  endif
81 # endif
82 # include <sys/protosw.h>
83 # include <sys/socket.h>
84
85 # include <net/if.h>
86 # ifdef sun
87 #  include <net/af.h>
88 # endif
89 # if defined(__DragonFly__) || __FreeBSD_version >= 300000
90 #  include <net/if_var.h>
91 # endif
92 # include <net/route.h>
93 # include <netinet/in.h>
94 # ifdef __sgi
95 #  define _KMEMUSER
96 #  include <sys/ddi.h>
97 #  ifdef IFF_DRVRLOCK /* IRIX6 */
98 #   include <sys/hashing.h>
99 #  endif
100 # endif
101 # if !(defined(__sgi) && !defined(IFF_DRVRLOCK)) /*IRIX<6*/
102 #  include <netinet/in_var.h>
103 # endif
104 # include <netinet/in_systm.h>
105 # include <netinet/ip.h>
106 # include <netinet/tcp.h>
107 # include <netinet/udp.h>
108 # include <netinet/ip_icmp.h>
109 # ifdef USE_INET6
110 #  include <netinet/icmp6.h>
111 # endif
112 # include <netinet/ip_var.h>
113 # ifndef _KERNEL
114 #  include <syslog.h>
115 # endif
116 # include "ip_compat.h"
117 # include <netinet/tcpip.h>
118 # include "ip_fil.h"
119 # if defined(__DragonFly__) || __FreeBSD_version >= 300000
120 #  include <sys/malloc.h>
121 # endif
122
123 # ifndef MIN
124 #  define       MIN(a,b)        (((a)<(b))?(a):(b))
125 # endif
126 # ifdef IPFILTER_LOGSIZE
127 #  undef IPLLOGSIZE
128 #  define IPLLOGSIZE IPFILTER_LOGSIZE
129 # endif
130
131
132 # if SOLARIS || defined(__sgi)
133 extern  kmutex_t        ipl_mutex;
134 #  if SOLARIS
135 extern  kcondvar_t      iplwait;
136 #  endif
137 # endif
138
139 iplog_t **iplh[IPL_LOGMAX+1], *iplt[IPL_LOGMAX+1], *ipll[IPL_LOGMAX+1];
140 size_t  iplused[IPL_LOGMAX+1];
141 static fr_info_t        iplcrc[IPL_LOGMAX+1];
142
143
144 /*
145  * Initialise log buffers & pointers.  Also iniialised the CRC to a local
146  * secret for use in calculating the "last log checksum".
147  */
148 void ipflog_init()
149 {
150         int     i;
151
152         for (i = IPL_LOGMAX; i >= 0; i--) {
153                 iplt[i] = NULL;
154                 ipll[i] = NULL;
155                 iplh[i] = &iplt[i];
156                 iplused[i] = 0;
157                 bzero((char *)&iplcrc[i], sizeof(iplcrc[i]));
158         }
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         size_t mlen, hlen;
178         size_t sizes[2];
179         void *ptrs[2];
180         int types[2];
181         u_char p;
182 # if SOLARIS && defined(_KERNEL)
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 (fin->fin_off == 0) {
193                 p = fin->fin_fi.fi_p;
194                 if (p == IPPROTO_TCP)
195                         hlen += MIN(sizeof(tcphdr_t), fin->fin_dlen);
196                 else if (p == IPPROTO_UDP)
197                         hlen += MIN(sizeof(udphdr_t), fin->fin_dlen);
198                 else if (p == IPPROTO_ICMP) {
199                         struct icmp *icmp;
200
201                         icmp = (struct icmp *)fin->fin_dp;
202          
203                         /*
204                          * For ICMP, if the packet is an error packet, also
205                          * include the information about the packet which
206                          * caused the error.
207                          */
208                         switch (icmp->icmp_type)
209                         {
210                         case ICMP_UNREACH :
211                         case ICMP_SOURCEQUENCH :
212                         case ICMP_REDIRECT :
213                         case ICMP_TIMXCEED :
214                         case ICMP_PARAMPROB :
215                                 hlen += MIN(sizeof(struct icmp) + 8,
216                                             fin->fin_dlen);
217                                 break;
218                         default :
219                                 hlen += MIN(sizeof(struct icmp),
220                                             fin->fin_dlen);
221                                 break;
222                         }
223                 }
224 #ifdef USE_INET6
225                 else if (p == IPPROTO_ICMPV6) {
226                         struct icmp6_hdr *icmp;
227
228                         icmp = (struct icmp6_hdr *)fin->fin_dp;
229          
230                         /*
231                          * For ICMPV6, if the packet is an error packet, also
232                          * include the information about the packet which
233                          * caused the error.
234                          */
235                         if (icmp->icmp6_type < 128) {
236                                 hlen += MIN(sizeof(struct icmp6_hdr) + 8,
237                                             fin->fin_dlen);
238                         } else {
239                                 hlen += MIN(sizeof(struct icmp6_hdr),
240                                             fin->fin_dlen);
241                         }
242                 }
243 #endif
244         }
245         /*
246          * Get the interface number and name to which this packet is
247          * currently associated.
248          */
249         bzero((char *)ipfl.fl_ifname, sizeof(ipfl.fl_ifname));
250 # if SOLARIS && defined(_KERNEL)
251         ipfl.fl_unit = (u_char)ifp->ill_ppa;
252         bcopy(ifp->ill_name, ipfl.fl_ifname,
253               MIN(ifp->ill_name_length, sizeof(ipfl.fl_ifname)));
254         mlen = (flags & FR_LOGBODY) ? MIN(msgdsize(m) - hlen, 128) : 0;
255 # else
256 #  if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199603)) || \
257         (defined(OpenBSD) && (OpenBSD >= 199603)) || \
258         (defined(__DragonFly__))
259         strncpy(ipfl.fl_ifname, ifp->if_xname, IFNAMSIZ);
260 #  else
261         ipfl.fl_unit = (u_char)ifp->if_unit;
262         strncpy(ipfl.fl_ifname, ifp->if_name, MIN(sizeof(ipfl.fl_ifname),
263                                                   sizeof(ifp->if_name)));
264 #  endif
265         mlen = (flags & FR_LOGBODY) ? MIN(fin->fin_plen - hlen, 128) : 0;
266 # endif
267         ipfl.fl_plen = (u_char)mlen;
268         ipfl.fl_hlen = (u_char)hlen;
269         ipfl.fl_rule = fin->fin_rule;
270         ipfl.fl_group = fin->fin_group;
271         if (fin->fin_fr != NULL)
272                 ipfl.fl_loglevel = fin->fin_fr->fr_loglevel;
273         else
274                 ipfl.fl_loglevel = 0xffff;
275         ipfl.fl_flags = flags;
276         ipfl.fl_dir = fin->fin_out;
277         ptrs[0] = (void *)&ipfl;
278         sizes[0] = sizeof(ipfl);
279         types[0] = 0;
280 # if SOLARIS && defined(_KERNEL)
281         /*
282          * Are we copied from the mblk or an aligned array ?
283          */
284         if (ip == (ip_t *)m->b_rptr) {
285                 ptrs[1] = m;
286                 sizes[1] = hlen + mlen;
287                 types[1] = 1;
288         } else {
289                 ptrs[1] = ip;
290                 sizes[1] = hlen + mlen;
291                 types[1] = 0;
292         }
293 # else
294         ptrs[1] = m;
295         sizes[1] = hlen + mlen;
296         types[1] = 1;
297 # endif
298         return ipllog(IPL_LOGIPF, fin, ptrs, sizes, types, 2);
299 }
300
301
302 /*
303  * ipllog
304  */
305 int ipllog(dev, fin, items, itemsz, types, cnt)
306 int dev;
307 fr_info_t *fin;
308 void **items;
309 size_t *itemsz;
310 int *types, cnt;
311 {
312         caddr_t buf, s;
313         iplog_t *ipl;
314         size_t len;
315         int i;
316  
317         /*
318          * Check to see if this log record has a CRC which matches the last
319          * record logged.  If it does, just up the count on the previous one
320          * rather than create a new one.
321          */
322         MUTEX_ENTER(&ipl_mutex);
323         if (fin != NULL) {
324                 if ((ipll[dev] != NULL) &&
325                     bcmp((char *)fin, (char *)&iplcrc[dev], FI_LCSIZE) == 0) {
326                         ipll[dev]->ipl_count++;
327                         MUTEX_EXIT(&ipl_mutex);
328                         return 1;
329                 }
330                 bcopy((char *)fin, (char *)&iplcrc[dev], FI_LCSIZE);
331         } else
332                 bzero((char *)&iplcrc[dev], FI_LCSIZE);
333         MUTEX_EXIT(&ipl_mutex);
334
335         /*
336          * Get the total amount of data to be logged.
337          */
338         for (i = 0, len = IPLOG_SIZE; i < cnt; i++)
339                 len += itemsz[i];
340
341         /*
342          * check that we have space to record this information and can
343          * allocate that much.
344          */
345         KMALLOCS(buf, caddr_t, len);
346         if (!buf)
347                 return 0;
348         MUTEX_ENTER(&ipl_mutex);
349         if ((iplused[dev] + len) > IPLLOGSIZE) {
350                 MUTEX_EXIT(&ipl_mutex);
351                 KFREES(buf, len);
352                 return 0;
353         }
354         iplused[dev] += len;
355         MUTEX_EXIT(&ipl_mutex);
356
357         /*
358          * advance the log pointer to the next empty record and deduct the
359          * amount of space we're going to use.
360          */
361         ipl = (iplog_t *)buf;
362         ipl->ipl_magic = IPL_MAGIC;
363         ipl->ipl_count = 1;
364         ipl->ipl_next = NULL;
365         ipl->ipl_dsize = len;
366 # ifdef _KERNEL
367 #  if SOLARIS || defined(sun)
368         uniqtime(&ipl->ipl_tv);
369 #  else
370 #   if defined(__DragonFly__) || BSD >= 199306 || defined(__FreeBSD__) || defined(__sgi)
371         microtime(&ipl->ipl_tv);
372 #   endif
373 #  endif
374 # else
375         ipl->ipl_sec = 0;
376         ipl->ipl_usec = 0;
377 # endif
378
379         /*
380          * Loop through all the items to be logged, copying each one to the
381          * buffer.  Use bcopy for normal data or the mb_t copyout routine.
382          */
383         for (i = 0, s = buf + IPLOG_SIZE; i < cnt; i++) {
384                 if (types[i] == 0)
385                         bcopy(items[i], s, itemsz[i]);
386                 else if (types[i] == 1) {
387 # if SOLARIS && defined(_KERNEL)
388                         copyout_mblk(items[i], 0, itemsz[i], s);
389 # else
390                         m_copydata(items[i], 0, itemsz[i], s);
391 # endif
392                 }
393                 s += itemsz[i];
394         }
395         MUTEX_ENTER(&ipl_mutex);
396         ipll[dev] = ipl;
397         *iplh[dev] = ipl;
398         iplh[dev] = &ipl->ipl_next;
399 # if SOLARIS && defined(_KERNEL)
400         cv_signal(&iplwait);
401         mutex_exit(&ipl_mutex);
402 # else
403         MUTEX_EXIT(&ipl_mutex);
404         WAKEUP(&iplh[dev]);
405 # endif
406         return 1;
407 }
408
409
410 int ipflog_read(unit, uio)
411 minor_t unit;
412 struct uio *uio;
413 {
414         size_t dlen, copied;
415         int error = 0;
416         iplog_t *ipl;
417 # if defined(_KERNEL) && !SOLARIS
418         int s;
419 # endif
420
421         /*
422          * Sanity checks.  Make sure the minor # is valid and we're copying
423          * a valid chunk of data.
424          */
425         if (IPL_LOGMAX < unit)
426                 return ENXIO;
427         if (!uio->uio_resid)
428                 return 0;
429         if (uio->uio_resid < IPLOG_SIZE)
430                 return EINVAL;
431  
432         /*
433          * Lock the log so we can snapshot the variables.  Wait for a signal
434          * if the log is empty.
435          */
436         SPL_NET(s);
437         MUTEX_ENTER(&ipl_mutex);
438
439         while (!iplused[unit] || !iplt[unit]) {
440 # if SOLARIS && defined(_KERNEL)
441                 if (!cv_wait_sig(&iplwait, &ipl_mutex)) {
442                         MUTEX_EXIT(&ipl_mutex);
443                         return EINTR;
444                 }
445 # else
446                 MUTEX_EXIT(&ipl_mutex);
447                 error = SLEEP(&iplh[unit], "ipl sleep");
448                 if (error) {
449                         SPL_X(s);
450                         return error;
451                 }
452                 MUTEX_ENTER(&ipl_mutex);
453 # endif /* SOLARIS */
454         }
455
456 # if defined(__DragonFly__) || BSD >= 199306 || defined(__FreeBSD__)
457         uio->uio_rw = UIO_READ;
458 # endif
459
460         for (copied = 0; (ipl = iplt[unit]); copied += dlen) {
461                 dlen = ipl->ipl_dsize;
462                 if (dlen > uio->uio_resid)
463                         break;
464                 /*
465                  * Don't hold the mutex over the uiomove call.
466                  */
467                 iplt[unit] = ipl->ipl_next;
468                 iplused[unit] -= dlen;
469                 MUTEX_EXIT(&ipl_mutex);
470                 error = UIOMOVE((caddr_t)ipl, dlen, UIO_READ, uio);
471                 MUTEX_ENTER(&ipl_mutex);
472                 if (error) {
473                         ipl->ipl_next = iplt[unit];
474                         iplt[unit] = ipl;
475                         iplused[unit] += dlen;
476                         break;
477                 }
478                 KFREES((caddr_t)ipl, dlen);
479         }
480         if (!iplt[unit]) {
481                 iplused[unit] = 0;
482                 iplh[unit] = &iplt[unit];
483                 ipll[unit] = NULL;
484         }
485
486         MUTEX_EXIT(&ipl_mutex);
487         SPL_X(s);
488         return error;
489 }
490
491
492 int ipflog_clear(unit)
493 minor_t unit;
494 {
495         iplog_t *ipl;
496         int used;
497
498         MUTEX_ENTER(&ipl_mutex);
499         while ((ipl = iplt[unit])) {
500                 iplt[unit] = ipl->ipl_next;
501                 KFREES((caddr_t)ipl, ipl->ipl_dsize);
502         }
503         iplh[unit] = &iplt[unit];
504         ipll[unit] = NULL;
505         used = iplused[unit];
506         iplused[unit] = 0;
507         bzero((char *)&iplcrc[unit], FI_LCSIZE);
508         MUTEX_EXIT(&ipl_mutex);
509         return used;
510 }
511 #endif /* IPFILTER_LOG */