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