diff options
author | green <green@FreeBSD.org> | 1999-08-01 16:57:24 +0000 |
---|---|---|
committer | green <green@FreeBSD.org> | 1999-08-01 16:57:24 +0000 |
commit | d848a791d143dcd43bbfd4243df4fe61c62fac41 (patch) | |
tree | 02d5b553f5f87af777c6d66d6b2b25611e79109b | |
parent | 7263583ccb568e6d5e6e6d32d6e126a50ea4229d (diff) | |
download | FreeBSD-src-d848a791d143dcd43bbfd4243df4fe61c62fac41.zip FreeBSD-src-d848a791d143dcd43bbfd4243df4fe61c62fac41.tar.gz |
Make ipfw's logging more dynamic. Now, log will use the default limit
_or_ you may specify "log logamount number" to set logging specifically
the rule.
In addition, "ipfw resetlog" has been added, which will reset the
logging counters on any/all rule(s). ipfw resetlog does not affect
the packet/byte counters (as ipfw reset does), and is the only "set"
command that can be run at securelevel >= 3.
This should address complaints about not being able to set logging
amounts, not being able to restart logging at a high securelevel,
and not being able to just reset logging without resetting all of the
counters in a rule.
-rw-r--r-- | sbin/ipfw/ipfw.8 | 33 | ||||
-rw-r--r-- | sbin/ipfw/ipfw.c | 75 | ||||
-rw-r--r-- | sys/netinet/in.h | 3 | ||||
-rw-r--r-- | sys/netinet/ip_fw.c | 89 | ||||
-rw-r--r-- | sys/netinet/ip_fw.h | 4 | ||||
-rw-r--r-- | sys/netinet/raw_ip.c | 3 |
6 files changed, 184 insertions, 23 deletions
diff --git a/sbin/ipfw/ipfw.8 b/sbin/ipfw/ipfw.8 index ba3da16..e3933d5 100644 --- a/sbin/ipfw/ipfw.8 +++ b/sbin/ipfw/ipfw.8 @@ -1,5 +1,5 @@ .\" -.\" $Id: ipfw.8,v 1.53 1999/06/15 12:56:38 ru Exp $ +.\" $Id: ipfw.8,v 1.54 1999/06/19 18:43:18 green Exp $ .\" .Dd July 20, 1996 .Dt IPFW 8 @@ -30,6 +30,12 @@ flush zero .Op Ar number ... .Nm ipfw +.Oo +.Fl q +.Oc +resetlog +.Op Ar number ... +.Nm ipfw delete .Ar number ... .Nm ipfw @@ -49,7 +55,7 @@ show add .Op Ar number .Ar action -.Op log +.Op log Op Ar logamount Ar number .Ar proto from .Ar src @@ -227,6 +233,10 @@ The show command is equivalent to The zero operation zeroes the counters associated with rule number .Ar number . .Pp +The resetlog operation resets the logging counters associated with +rule number +.Ar number . +.Pp The flush operation removes all rules. .Pp Any command beginning with a @@ -265,7 +275,7 @@ Don't ask for confirmation for commands that can cause problems if misused .Ar Note , if there is no tty associated with the process, this is implied. .It Fl q -While adding, zeroing or flushing, be quiet about actions (implies +While adding, zeroing, resetlogging or flushing, be quiet about actions (implies .Fl f Ns ). This is useful for adjusting rules by executing multiple .Nm @@ -411,15 +421,22 @@ then when a packet matches a rule with the keyword a message will be printed on the console. If the kernel was compiled with the .Dv IPFIREWALL_VERBOSE_LIMIT -option, then logging will cease after the number of packets -specified by the option are received for that particular -chain entry. Logging may then be re-enabled by clearing -the packet counter for that entry. +option, then by default logging will cease after the number +of packets specified by the option are received for that +particular chain entry. However, if +.Ar logamount Ar number +is used, that +.Ar number +will be the default logging limit rather than +.Dv IPFIREWALL_VERBOSE_LIMIT . +Logging may then be re-enabled by clearing the logging counter +or the packet counter for that entry. .Pp Console logging and the log limit are adjustable dynamically through the .Xr sysctl 8 -interface. +interface in the MIB base of +.Dv net.inet.ip.fw . .Pp .Ar proto : .Bl -hang -offset flag -width 1234567890123456 diff --git a/sbin/ipfw/ipfw.c b/sbin/ipfw/ipfw.c index 78d5474..1ff1ed7 100644 --- a/sbin/ipfw/ipfw.c +++ b/sbin/ipfw/ipfw.c @@ -20,13 +20,14 @@ #ifndef lint static const char rcsid[] = - "$Id: ipfw.c,v 1.70 1999/06/11 09:43:53 ru Exp $"; + "$Id: ipfw.c,v 1.71 1999/06/19 18:43:15 green Exp $"; #endif /* not lint */ #include <sys/types.h> #include <sys/socket.h> #include <sys/sockio.h> +#include <sys/sysctl.h> #include <sys/time.h> #include <sys/wait.h> @@ -247,8 +248,11 @@ show_ipfw(struct ip_fw *chain, int pcwidth, int bcwidth) errx(EX_OSERR, "impossible"); } - if (chain->fw_flg & IP_FW_F_PRN) + if (chain->fw_flg & IP_FW_F_PRN) { printf(" log"); + if (chain->fw_logamount) + printf(" logamount %d", chain->fw_logamount); + } pe = getprotobynumber(chain->fw_prot); if (pe) @@ -599,12 +603,13 @@ show_usage(const char *fmt, ...) " [pipe] list [number ...]\n" " [pipe] show [number ...]\n" " zero [number ...]\n" +" resetlog [number ...]\n" " pipe number config [pipeconfig]\n" " rule: action proto src dst extras...\n" " action:\n" " {allow|permit|accept|pass|deny|drop|reject|unreach code|\n" " reset|count|skipto num|divert port|tee port|fwd ip|\n" -" pipe num} [log]\n" +" pipe num} [log [logamount count]]\n" " proto: {ip|tcp|udp|icmp|<number>}\n" " src: from [not] {any|ip[{/bits|:mask}]} [{port|port-port},[port],...]\n" " dst: to [not] {any|ip[{/bits|:mask}]} [{port|port-port},[port],...]\n" @@ -1164,6 +1169,18 @@ add(ac,av) if (ac && !strncmp(*av,"log",strlen(*av))) { rule.fw_flg |= IP_FW_F_PRN; av++; ac--; } + if (ac && !strncmp(*av,"logamount",strlen(*av))) { + if (!(rule.fw_flg & IP_FW_F_PRN)) + show_usage("``logamount'' not valid without ``log''"); + ac--; av++; + if (!ac) + show_usage("``logamount'' requires argument"); + rule.fw_logamount = atoi(*av); + if (rule.fw_logamount <= 0) + show_usage("``logamount'' argument must be greater " + "than 0"); + ac--; av++; + } /* protocol */ if (ac == 0) @@ -1385,6 +1402,17 @@ badviacombo: if (rule.fw_nports) show_usage("can't mix 'frag' and port specifications"); } + if (rule.fw_flg & IP_FW_F_PRN) { + if (!rule.fw_logamount) { + size_t len = sizeof(int); + + if (sysctlbyname("net.inet.ip.fw.verbose_limit", + &rule.fw_logamount, &len, NULL, 0) == -1) + errx(1, "sysctlbyname(\"%s\")", + "net.inet.ip.fw.verbose_limit"); + } + rule.fw_loghighest = rule.fw_logamount; + } if (!do_quiet) show_ipfw(&rule, 10, 10); @@ -1432,6 +1460,45 @@ zero (ac, av) } } +static void +resetlog (ac, av) + int ac; + char **av; +{ + av++; ac--; + + if (!ac) { + /* clear all entries */ + if (setsockopt(s,IPPROTO_IP,IP_FW_RESETLOG,NULL,0)<0) + err(EX_UNAVAILABLE, "setsockopt(%s)", "IP_FW_RESETLOG"); + if (!do_quiet) + printf("Logging counts reset.\n"); + } else { + struct ip_fw rule; + int failed = EX_OK; + + memset(&rule, 0, sizeof rule); + while (ac) { + /* Rule number */ + if (isdigit(**av)) { + rule.fw_number = atoi(*av); av++; ac--; + if (setsockopt(s, IPPROTO_IP, + IP_FW_RESETLOG, &rule, sizeof rule)) { + warn("rule %u: setsockopt(%s)", rule.fw_number, + "IP_FW_RESETLOG"); + failed = EX_UNAVAILABLE; + } + else if (!do_quiet) + printf("Entry %d logging count reset\n", + rule.fw_number); + } else + show_usage("invalid rule number ``%s''", *av); + } + if (failed != EX_OK) + exit(failed); + } +} + static int ipfw_main(ac,av) int ac; @@ -1527,6 +1594,8 @@ ipfw_main(ac,av) } } else if (!strncmp(*av, "zero", strlen(*av))) { zero(ac,av); + } else if (!strncmp(*av, "resetlog", strlen(*av))) { + resetlog(ac,av); } else if (!strncmp(*av, "print", strlen(*av))) { list(--ac,++av); } else if (!strncmp(*av, "list", strlen(*av))) { diff --git a/sys/netinet/in.h b/sys/netinet/in.h index 1eebb9a..1838def 100644 --- a/sys/netinet/in.h +++ b/sys/netinet/in.h @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * @(#)in.h 8.3 (Berkeley) 1/3/94 - * $Id: in.h,v 1.41 1999/05/04 16:20:29 luigi Exp $ + * $Id: in.h,v 1.42 1999/05/08 14:28:52 peter Exp $ */ #ifndef _NETINET_IN_H_ @@ -322,6 +322,7 @@ struct ip_opts { #define IP_FW_FLUSH 52 /* flush firewall rule chain */ #define IP_FW_ZERO 53 /* clear single/all firewall counter(s) */ #define IP_FW_GET 54 /* get entire firewall rule chain */ +#define IP_FW_RESETLOG 55 /* reset logging counters */ #define IP_DUMMYNET_CONFIGURE 60 /* add/configure a dummynet pipe */ #define IP_DUMMYNET_DEL 61 /* delete a dummynet pipe from chain */ diff --git a/sys/netinet/ip_fw.c b/sys/netinet/ip_fw.c index a9e8288..5543bdf 100644 --- a/sys/netinet/ip_fw.c +++ b/sys/netinet/ip_fw.c @@ -12,7 +12,7 @@ * * This software is provided ``AS IS'' without any warranties of any kind. * - * $Id: ip_fw.c,v 1.114 1999/06/19 18:43:28 green Exp $ + * $Id: ip_fw.c,v 1.115 1999/07/28 22:27:27 green Exp $ */ /* @@ -106,6 +106,7 @@ SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, verbose_limit, CTLFLAG_RW, static int add_entry __P((struct ip_fw_head *chainptr, struct ip_fw *frwl)); static int del_entry __P((struct ip_fw_head *chainptr, u_short number)); static int zero_entry __P((struct ip_fw *)); +static int resetlog_entry __P((struct ip_fw *)); static int check_ipfw_struct __P((struct ip_fw *m)); static __inline int iface_match __P((struct ifnet *ifp, union ip_fw_if *ifu, @@ -306,10 +307,11 @@ ipfw_report(struct ip_fw *f, struct ip *ip, struct tcphdr *const tcp = (struct tcphdr *) ((u_int32_t *) ip+ ip->ip_hl); struct udphdr *const udp = (struct udphdr *) ((u_int32_t *) ip+ ip->ip_hl); struct icmp *const icmp = (struct icmp *) ((u_int32_t *) ip + ip->ip_hl); - int count; + u_int64_t count; count = f ? f->fw_pcnt : ++counter; - if (fw_verbose_limit != 0 && count > fw_verbose_limit) + if ((f == NULL && fw_verbose_limit != 0 && count > fw_verbose_limit) || + (f && f->fw_logamount != 0 && count > f->fw_loghighest)) return; /* Print command name */ @@ -409,9 +411,11 @@ ipfw_report(struct ip_fw *f, struct ip *ip, if ((ip->ip_off & IP_OFFMASK)) printf(" Fragment = %d",ip->ip_off & IP_OFFMASK); printf("\n"); - if (fw_verbose_limit != 0 && count == fw_verbose_limit) - printf("ipfw: limit reached on rule #%d\n", - f ? f->fw_number : -1); + if ((f ? f->fw_logamount != 0 : 1) && + count == (f ? f->fw_loghighest : fw_verbose_limit)) + printf("ipfw: limit %d reached on rule #%d\n", + f ? f->fw_logamount : fw_verbose_limit, + f ? f->fw_number : -1); } } @@ -1069,6 +1073,7 @@ zero_entry(struct ip_fw *frwl) s = splnet(); for (fcp = LIST_FIRST(&ip_fw_chain); fcp; fcp = LIST_NEXT(fcp, chain)) { fcp->rule->fw_bcnt = fcp->rule->fw_pcnt = 0; + fcp->rule->fw_loghighest = fcp->rule->fw_logamount; fcp->rule->timestamp = 0; } splx(s); @@ -1086,6 +1091,8 @@ zero_entry(struct ip_fw *frwl) s = splnet(); while (fcp && frwl->fw_number == fcp->rule->fw_number) { fcp->rule->fw_bcnt = fcp->rule->fw_pcnt = 0; + fcp->rule->fw_loghighest = + fcp->rule->fw_logamount; fcp->rule->timestamp = 0; fcp = LIST_NEXT(fcp, chain); } @@ -1108,6 +1115,55 @@ zero_entry(struct ip_fw *frwl) } static int +resetlog_entry(struct ip_fw *frwl) +{ + struct ip_fw_chain *fcp; + int s, cleared; + + if (frwl == 0) { + s = splnet(); + for (fcp = LIST_FIRST(&ip_fw_chain); fcp; fcp = LIST_NEXT(fcp, chain)) + fcp->rule->fw_loghighest = fcp->rule->fw_pcnt + + fcp->rule->fw_logamount; + splx(s); + } + else { + cleared = 0; + + /* + * It's possible to insert multiple chain entries with the + * same number, so we don't stop after finding the first + * match if zeroing a specific entry. + */ + for (fcp = LIST_FIRST(&ip_fw_chain); fcp; fcp = LIST_NEXT(fcp, chain)) + if (frwl->fw_number == fcp->rule->fw_number) { + s = splnet(); + while (fcp && frwl->fw_number == fcp->rule->fw_number) { + fcp->rule->fw_loghighest = + fcp->rule->fw_pcnt + + fcp->rule->fw_logamount; + fcp = LIST_NEXT(fcp, chain); + } + splx(s); + cleared = 1; + break; + } + if (!cleared) /* we didn't find any matching rules */ + return (EINVAL); + } + + if (fw_verbose) { + if (frwl) + printf("ipfw: Entry %d logging count reset.\n", + frwl->fw_number); + else + printf("ipfw: All logging counts cleared.\n"); + } + + return (0); +} + +static int check_ipfw_struct(struct ip_fw *frwl) { /* Check for invalid flag bits */ @@ -1241,8 +1297,12 @@ ip_fw_ctl(struct sockopt *sopt) struct ip_fw_chain *fcp; struct ip_fw frwl; - /* Disallow sets in really-really secure mode. */ - if (sopt->sopt_dir == SOPT_SET && securelevel >= 3) + /* + * Disallow sets in really-really secure mode, but still allow + * the logging counters to be reset. + */ + if (sopt->sopt_dir == SOPT_SET && securelevel >= 3 && + sopt->sopt_name != IP_FW_RESETLOG) return (EPERM); error = 0; @@ -1320,6 +1380,17 @@ ip_fw_ctl(struct sockopt *sopt) } break; + case IP_FW_RESETLOG: + if (sopt->sopt_val != 0) { + error = sooptcopyin(sopt, &frwl, sizeof frwl, + sizeof frwl); + if (error || (error = resetlog_entry(&frwl))) + break; + } else { + error = resetlog_entry(0); + } + break; + default: printf("ip_fw_ctl invalid option %d\n", sopt->sopt_name); error = EINVAL ; @@ -1373,7 +1444,7 @@ ip_fw_init(void) if (fw_verbose_limit == 0) printf("unlimited logging\n"); else - printf("logging limited to %d packets/entry\n", + printf("logging limited to %d packets/entry by default\n", fw_verbose_limit); #endif } diff --git a/sys/netinet/ip_fw.h b/sys/netinet/ip_fw.h index d858040..958eb67 100644 --- a/sys/netinet/ip_fw.h +++ b/sys/netinet/ip_fw.h @@ -11,7 +11,7 @@ * * This software is provided ``AS IS'' without any warranties of any kind. * - * $Id: ip_fw.h,v 1.38 1999/06/19 18:43:30 green Exp $ + * $Id: ip_fw.h,v 1.39 1999/07/28 22:22:57 green Exp $ */ #ifndef _IP_FW_H @@ -85,6 +85,8 @@ struct ip_fw { void *next_rule_ptr ; /* next rule in case of match */ uid_t fw_uid; /* uid to match */ gid_t fw_gid; /* gid to match */ + int fw_logamount; /* amount to log */ + u_int64_t fw_loghighest; /* highest number packet to log */ }; #define IP_FW_GETNSRCP(rule) ((rule)->fw_nports & 0x0f) diff --git a/sys/netinet/raw_ip.c b/sys/netinet/raw_ip.c index f94cc09..d8117dd 100644 --- a/sys/netinet/raw_ip.c +++ b/sys/netinet/raw_ip.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * @(#)raw_ip.c 8.7 (Berkeley) 5/15/95 - * $Id: raw_ip.c,v 1.58 1999/04/27 11:17:36 phk Exp $ + * $Id: raw_ip.c,v 1.59 1999/05/03 23:57:30 billf Exp $ */ #include <sys/param.h> @@ -293,6 +293,7 @@ rip_ctloutput(so, sopt) case IP_FW_DEL: case IP_FW_FLUSH: case IP_FW_ZERO: + case IP_FW_RESETLOG: if (ip_fw_ctl_ptr == 0) error = ENOPROTOOPT; else |