From owner-freebsd-security Thu Dec 14 0:32:36 2000 From owner-freebsd-security@FreeBSD.ORG Thu Dec 14 00:32:28 2000 Return-Path: Delivered-To: freebsd-security@freebsd.org Received: from mailhost01.reflexnet.net (mailhost01.reflexnet.net [64.6.192.82]) by hub.freebsd.org (Postfix) with ESMTP id AD25837B400 for ; Thu, 14 Dec 2000 00:32:28 -0800 (PST) Received: from rfx-64-6-211-1.users.reflexcom.com ([64.6.211.149]) by mailhost01.reflexnet.net with Microsoft SMTPSVC(5.5.1877.197.19); Thu, 14 Dec 2000 00:30:44 -0800 Received: (from cjc@localhost) by rfx-64-6-211-1.users.reflexcom.com (8.11.0/8.11.0) id eBE8WJd35805 for freebsd-security@freebsd.org; Thu, 14 Dec 2000 00:32:19 -0800 (PST) (envelope-from cjc) Date: Thu, 14 Dec 2000 00:32:19 -0800 From: "Crist J. Clark" To: freebsd-security@freebsd.org Subject: Extended ipfw Logging Message-ID: <20001214003219.K96105@149.211.6.64.reflexcom.com> Reply-To: cjclark@alum.mit.edu Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="ZmUaFz6apKcXQszQ" X-Mailer: Mutt 1.0i Sender: cjc@rfx-64-6-211-1.users.reflexcom.com Sender: owner-freebsd-security@FreeBSD.ORG Precedence: bulk X-Loop: FreeBSD.org --ZmUaFz6apKcXQszQ Content-Type: text/plain; charset=us-ascii I posted this to the freebsd-ipfw list, but thought some of those in this group who do not follow that list might be interested too. INTRODUCTION I wanted to add some detail to the ipfw logging. Specificially, I wanted TCP flags. However, once I started coding, I decided why not toss just about every field of interest in. I have attached patches. WHAT THE PATCHES DO There are new fields for all packets. Data from the IP header, the IP ID, TTL, and extra fragmentation information is printed for all types of datagrams. TCP packets include additional information on sequence number, acknowledgement number, and flags. Here are examples. First, a TCP handshake, brief data exchange, and close (a telnet to the echo port), ipfw: 400 Accept TCP 192.168.64.254:2932 192.168.64.20:7 f=0x02 s=0x7feef91d a=0x00000000 i=0x48a9 t=0x40 in via ep0 DF ipfw: 400 Accept TCP 192.168.64.20:7 192.168.64.254:2932 f=0x12 s=0xeaa736a6 a=0x7feef91e i=0x0080 t=0x40 out via ep0 DF ipfw: 400 Accept TCP 192.168.64.254:2932 192.168.64.20:7 f=0x10 s=0x7feef91e a=0xeaa736a7 i=0x48aa t=0x40 in via ep0 DF ipfw: 400 Accept TCP 192.168.64.254:2932 192.168.64.20:7 f=0x18 s=0x7feef91e a=0xeaa736a7 i=0x48ca t=0x40 in via ep0 DF ipfw: 400 Accept TCP 192.168.64.20:7 192.168.64.254:2932 f=0x18 s=0xeaa736a7 a=0x7feef925 i=0x0083 t=0x40 out via ep0 DF ipfw: 400 Accept TCP 192.168.64.254:2932 192.168.64.20:7 f=0x10 s=0x7feef925 a=0xeaa736ae i=0x48cb t=0x40 in via ep0 DF ipfw: 400 Accept TCP 192.168.64.254:2932 192.168.64.20:7 f=0x11 s=0x7feef925 a=0xeaa736ae i=0x48ee t=0x40 in via ep0 DF ipfw: 400 Accept TCP 192.168.64.20:7 192.168.64.254:2932 f=0x10 s=0xeaa736ae a=0x7feef926 i=0x0086 t=0x40 out via ep0 DF ipfw: 400 Accept TCP 192.168.64.20:7 192.168.64.254:2932 f=0x11 s=0xeaa736ae a=0x7feef926 i=0x0087 t=0x40 out via ep0 DF ipfw: 400 Accept TCP 192.168.64.254:2932 192.168.64.20:7 f=0x10 s=0x7feef926 a=0xeaa736af i=0x48f0 t=0x40 in via ep0 DF Here is UDP (a timed update), ipfw: 400 Accept UDP 192.168.64.254:525 192.168.64.20:525 i=0x4bb8 t=0x40 in via ep0 ipfw: 400 Accept UDP 192.168.64.20:525 192.168.64.254:525 i=0x008b t=0x40 out via ep0 ipfw: 400 Accept UDP 192.168.64.254:525 192.168.64.255:525 i=0x4bb9 t=0x40 in via ep And finally, some fragmentation and ICMP (an oversized ping), ipfw: 400 Accept ICMP:8.0 192.168.64.254 192.168.64.20 i=0x5038 t=0xff in via ep0 Frag=0+ ipfw: 400 Accept ICMP 192.168.64.254 192.168.64.20 i=0x5038 t=0xff in via ep0 Frag=1480+ ipfw: 400 Accept ICMP 192.168.64.254 192.168.64.20 i=0x5038 t=0xff in via ep0 Frag=2960 ipfw: 400 Accept ICMP:0.0 192.168.64.20 192.168.64.254 i=0x0095 t=0xff out via ep0 There are more fields that could be done, but this is all I was interested in doing when coding. HOW TO INSTALL AND CONTROL Simply use patch(1) to apply the attached patches to your kernel source. The patches were made and tested on 5-CURRENT, but they will apply cleanly to 4-STABLE and I don't see why they would function any differently. To enable the patches in your kernel, add, options IPFIREWALL_EXTRA_VERBOSE To your kernel config. The patches use the net.inet.ip.fw.verbose sysctl knob, net.inet.ip.fw.verbose=0 # No logging net.inet.ip.fw.verbose=1 # Standard logging net.inet.ip.fw.verbose=2 # Enhanced logging logging So once compiled in, the changes can be switched on the fly. When the kernel is compiled with IPFIREWALL_EXTRA_VERBOSE, the verbose level of '2' is the default after reboot. SECURITY AND PERFORMANCE ISSUES I was questioned whether this might make a firewall box easier to DoS. I do not think there is any significant threat above that of a box with standard logging. If you have a look at the patches, there is not a whole lot of new code (although we are making snprintf(3) calls). If you already have logging running, I doubt the change in performance would be noticable. Another point someone brought up was whether this might overflow logs because you will not be getting 'last message repeated' lines from syslogd. Since the IP ID and other fields should be changing for every packet, you will not be seeing those. This might start to fill up logs more if you are having misconfiguration problems, but I do not think it makes the box easier to attack. It is trivial for an attacker to mix things up so that you will not get 'last message repeated' lines. Take something like a Smurf for example. You would be getting pounded from multiple source addresses. To summarize, if you want more information in your logs, these patches should give you more of what you want with little to no cost. If anyone has suggestions, bugs, criticism, or praise, send it along. Obviously, if it is something that you think others on the list might wish to discuss, CC the list. Otherwise, feel free to send mail directly to me. LOGGING AND CAPTURE DAEMON Another thing I was considering was the idea of making a more configurable logging utility and possibly a utility that will even capture packets. The magic of divert(4) sockets make it fairly straightforward to do these things in userland where you can add new abilities without worrying about bloating or breaking the kernel. This is similar to how some other firewall tools work. In addition to more configurable and expandable logging, I was considering the capability to capture raw packets. Now, I really do not think trying to build something like a fully loaded IDS from this is worthwhile when you have great tools like Snort available, but I think its usefulness for debugging a firewall would be reason enough and any actual security uses people find would be great. I have not really decided if I am going to do this. If I no one else is interested, I think I am best off just customizing my FreeBSD kernel code as needed or making a really basic (not necessarily user friendly or well documented) userland logger. Thanks. Have fun with the patches and please let me know if you are using them. -- Crist J. Clark cjclark@alum.mit.edu --ZmUaFz6apKcXQszQ Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="ip_fw.patch" --- ip_fw.c Sun Dec 10 19:13:17 2000 +++ /usr/src/sys/netinet/ip_fw.c Wed Dec 13 23:52:04 2000 @@ -67,7 +67,11 @@ static int fw_debug = 1; #ifdef IPFIREWALL_VERBOSE +#ifdef IPFIREWALL_EXTRA_VERBOSE +static int fw_verbose = 2; +#else static int fw_verbose = 1; +#endif #else static int fw_verbose = 0; #endif @@ -488,7 +492,7 @@ struct icmp *const icmp = (struct icmp *) ((u_int32_t *) ip + ip->ip_hl); u_int64_t count; char *action; - char action2[32], proto[47], name[18], fragment[17]; + char action2[32], proto[97], name[18], fragment[17]; int len; count = f ? f->fw_pcnt : ++counter; @@ -572,9 +576,18 @@ len += snprintf(SNPARGS(proto, len), " "); len += snprintf(SNPARGS(proto, len), "%s", inet_ntoa(ip->ip_dst)); - if ((ip->ip_off & IP_OFFMASK) == 0) - snprintf(SNPARGS(proto, len), ":%d", + if ((ip->ip_off & IP_OFFMASK) == 0) { + len += snprintf(SNPARGS(proto, len), ":%d", ntohs(tcp->th_dport)); +#ifdef IPFIREWALL_EXTRA_VERBOSE + if ( fw_verbose > 1 ) + len += snprintf(SNPARGS(proto, len), + " f=0x%02x s=0x%08x a=0x%08x", + tcp->th_flags, + ntohl(tcp->th_seq), + ntohl(tcp->th_ack)); +#endif + } break; case IPPROTO_UDP: len = snprintf(SNPARGS(proto, 0), "UDP %s", @@ -587,7 +600,7 @@ len += snprintf(SNPARGS(proto, len), "%s", inet_ntoa(ip->ip_dst)); if ((ip->ip_off & IP_OFFMASK) == 0) - snprintf(SNPARGS(proto, len), ":%d", + len += snprintf(SNPARGS(proto, len), ":%d", ntohs(udp->uh_dport)); break; case IPPROTO_ICMP: @@ -598,20 +611,46 @@ len = snprintf(SNPARGS(proto, 0), "ICMP "); len += snprintf(SNPARGS(proto, len), "%s", inet_ntoa(ip->ip_src)); - snprintf(SNPARGS(proto, len), " %s", inet_ntoa(ip->ip_dst)); + len += snprintf(SNPARGS(proto, len), " %s", inet_ntoa(ip->ip_dst)); break; default: len = snprintf(SNPARGS(proto, 0), "P:%d %s", ip->ip_p, inet_ntoa(ip->ip_src)); - snprintf(SNPARGS(proto, len), " %s", inet_ntoa(ip->ip_dst)); + len += snprintf(SNPARGS(proto, len), " %s", inet_ntoa(ip->ip_dst)); break; } - if ((ip->ip_off & IP_OFFMASK)) +#ifdef IPFIREWALL_EXTRA_VERBOSE + if ( fw_verbose > 1 ) { + snprintf(SNPARGS(proto, len), + " i=0x%04x t=0x%02x", + ntohs(ip->ip_id), + ip->ip_ttl); + if (ip->ip_off & IP_DF) + len = snprintf(SNPARGS(fragment, 0), " DF"); + else { + fragment[0] = '\0'; + len = 0; + } + if (ip->ip_off & (IP_OFFMASK | IP_MF)) + len += snprintf(SNPARGS(fragment, len), " Frag=%d", + (ip->ip_off & IP_OFFMASK)<<3); + if (ip->ip_off & IP_MF) + len += snprintf(SNPARGS(fragment, len), "+"); + } else { + if (ip->ip_off & (IP_OFFMASK | IP_MF)) + snprintf(SNPARGS(fragment, 0), " Fragment = %d", + ip->ip_off & IP_OFFMASK); + else + fragment[0] = '\0'; + } +#else + if (ip->ip_off & (IP_OFFMASK | IP_MF)) snprintf(SNPARGS(fragment, 0), " Fragment = %d", ip->ip_off & IP_OFFMASK); else fragment[0] = '\0'; +#endif if (oif) log(LOG_SECURITY | LOG_INFO, "%s %s %s out via %s%d%s\n", name, action, proto, oif->if_name, oif->if_unit, fragment); --ZmUaFz6apKcXQszQ Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="options.patch" --- options Sun Dec 10 18:25:56 2000 +++ /usr/src/sys/conf/options Sun Dec 10 01:45:19 2000 @@ -245,6 +245,7 @@ PFIL_HOOKS opt_pfil_hooks.h IPFIREWALL opt_ipfw.h IPFIREWALL_VERBOSE opt_ipfw.h +IPFIREWALL_EXTRA_VERBOSE opt_ipfw.h IPFIREWALL_VERBOSE_LIMIT opt_ipfw.h IPFIREWALL_DEFAULT_TO_ACCEPT opt_ipfw.h IPFIREWALL_FORWARD opt_ipfw.h --ZmUaFz6apKcXQszQ-- To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-security" in the body of the message