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