From martin@i.cz  Fri Jan  8 10:34:07 1999
Received: from kamna.i.cz (kamna.i.cz [193.85.255.30])
          by hub.freebsd.org (8.8.8/8.8.8) with SMTP id KAA03946
          for <FreeBSD-gnats-submit@freebsd.org>; Fri, 8 Jan 1999 10:34:05 -0800 (PST)
          (envelope-from martin@i.cz)
Received: (qmail 9973 invoked from network); 8 Jan 1999 18:33:33 -0000
Received: from woody.i.cz (@193.85.255.60)
  by kamna.i.cz with SMTP; 8 Jan 1999 18:33:33 -0000
Received: (from root@localhost) by woody.i.cz (8.8.8/8.7.3) id TAA23534; Fri, 8 Jan 1999 19:33:32 +0100 (MET)
Message-Id: <199901081833.TAA23534@woody.i.cz>
Date: Fri, 8 Jan 1999 19:33:32 +0100 (MET)
From: mm@i.cz
Reply-To: mm@i.cz
To: FreeBSD-gnats-submit@freebsd.org
Subject: logging enhancements for natd 
X-Send-Pr-Version: 3.2

>Number:         9394
>Category:       bin
>Synopsis:       enhancement to natd logging
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    brian
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Fri Jan  8 10:40:01 PST 1999
>Closed-Date:    Tue Mar 9 11:38:08 PST 1999
>Last-Modified:  Tue Mar  9 11:38:57 PST 1999
>Originator:     Martin Machacek
>Release:        FreeBSD 3.0-CURRENT i386
>Organization:
ICZ a.s.
>Environment:

FreeBSD 3.0-CURRENT as of 8.1.1999, FreeBSD 2.2.8-RELEASE
natd v 1.8 natd v 1.2.2.6

>Description:

Natd allows to deny (drop) incoming packets on the external interface if there
is no translation entry for them (i.e they do not belong to any outgoing
connection). However these packets are logged only if natd is run in verbose
mode and they are logged along with all permitted packets on stdout. I believe
that it is important to have trace of all denied packets in order to be able
to detect possible attacks or network configuration problems. I think that
running natd in verbose mode is not a viable solution since the volume of logged
data is unneccerarily high. I've implemented simple enhancement that allows to
log only denied incoming packets via syslog. The patch adds new option log_denied
(yes/no value) that enables or disables logging. Further the patch adds new
option log_facility (string value) that allows to specify syslog facility to
be used for all logging through syslog. Default facility is LOG_DAEMON. Denied
packets are being logged with level LOG_WARNING. The patch adds new function
to natd.c (SyslogPacket) that formats data from the ip structure of the packet
to be dropped and logs them using the syslog function. The patch also modifies
the PrintPacket function in order to be consistent with the new SyslogPacket
function. The modification adds logging of UDP source and destination ports,
ICMP types and subtypes and IP types other that TCP,UDP and ICMP.
I've also created corresponding patch to the manpage describing both new options.
I'm running patched natd on quite heavily loaded firewall running FreeBSD 2.2.8
for 2 days without any problems. The patch helped me already to discover several
configuration problems in external part of my network and also helped me to 
detect one (admittedly harmless) portscan attack against the firewall. WARNING:
I haven't tried to neither to compile (due to currently broken build environment
on my CURRENT machine) nor to run the patched natd on FreeBSD 3.0 i(due to lack
of spare time) but both patches apply cleanly.

>How-To-Repeat:

Run unpatched natd with deny_incoming enabled and try to e.g. potscan the 
firewall machine from outside. No dropped packet will be logged anywhre unless
natd is run in verbose mode.

>Fix:
	
Apply patches (see bellow) to natd.c and natd.8 (both patches should work both
for the 3.0 and 2.2 branch).

########## natd.c.patch ################

*** natd.c.orig	Thu Jan  7 13:19:26 1999
--- natd.c	Thu Jan  7 18:57:57 1999
***************
*** 21,26 ****
--- 21,28 ----
  #include <netinet/ip.h>
  #include <machine/in_cksum.h>
  #include <netinet/tcp.h>
+ #include <netinet/udp.h>
+ #include <netinet/ip_icmp.h>
  #include <sys/ioctl.h>
  #include <net/if.h>
  #include <net/route.h>
***************
*** 35,41 ****
--- 37,45 ----
  #include <stdio.h>
  #include <stdlib.h>
  #include <string.h>
+ #define SYSLOG_NAMES
  #include <syslog.h>
+ #undef SYSLOG_NAMES
  #include <unistd.h>
  
  #include "natd.h"
***************
*** 56,61 ****
--- 60,66 ----
  static void	HandleRoutingInfo (int fd);
  static void	Usage ();
  static void	PrintPacket (struct ip*);
+ static void	SyslogPacket (struct ip*, int priority, char *label);
  static void	SetAliasAddressFromIfName (char* ifName);
  static void	InitiateShutdown ();
  static void	Shutdown ();
***************
*** 95,100 ****
--- 100,107 ----
  static	struct sockaddr_in	packetAddr;
  static 	int			packetSock;
  static  int			dropIgnoredIncoming;
+ static  int			logDropped;
+ static	int			logFacility;
  
  int main (int argc, char** argv)
  {
***************
*** 127,138 ****
--- 134,154 ----
  	aliasAddr.s_addr	= INADDR_NONE;
  	aliasOverhead		= 12;
  	dynamicMode		= 0;
+ 	logDropped		= 0;
+ 	logFacility		= LOG_DAEMON;
  /*
   * Mark packet buffer empty.
   */
  	packetSock		= -1;
  
  	ParseArgs (argc, argv);
+ 
+ /*
+  * Open syslog channel
+  */
+ 
+ openlog("natd", LOG_CONS | LOG_PID, logFacility);
+ 
  /*
   * Check that valid aliasing address has been given.
   */
***************
*** 463,469 ****
  			break;
  
  		default:
! 			printf ("[?]    ");
  			break;
  		}
  /*
--- 479,485 ----
  			break;
  
  		default:
! 			printf ("[%d]    ", ip->ip_p);
  			break;
  		}
  /*
***************
*** 487,492 ****
--- 503,511 ----
  		    dropIgnoredIncoming) {
  
  			printf (" dropped.\n");
+ 			if ( logDropped ) {
+ 				SyslogPacket(ip, LOG_WARNING, "denied");
+ 			}
  			return;
  		}
  	}
***************
*** 594,613 ****
  static void PrintPacket (struct ip* ip)
  {
  	struct tcphdr*	tcphdr;
  
! 	if (ip->ip_p == IPPROTO_TCP)
! 		tcphdr = (struct tcphdr*) ((char*) ip + (ip->ip_hl << 2));
! 	else
! 		tcphdr = NULL;
! 
! 	printf ("%s", inet_ntoa (ip->ip_src));
! 	if (tcphdr)
! 		printf (":%d", ntohs (tcphdr->th_sport));
! 
! 	printf (" -> ");
! 	printf ("%s", inet_ntoa (ip->ip_dst));
! 	if (tcphdr)
! 		printf (":%d", ntohs (tcphdr->th_dport));
  }
  
  static void SetAliasAddressFromIfName (char* ifName)
--- 613,671 ----
  static void PrintPacket (struct ip* ip)
  {
  	struct tcphdr*	tcphdr;
+ 	struct udphdr*	udphdr;
+ 	struct icmp*	icmphdr;
+ 	char		src[20];
+ 	char		dst[20];
+ 
+ 	strncpy(src, inet_ntoa (ip->ip_src), sizeof(src) - 1);
+ 	strncpy(dst, inet_ntoa (ip->ip_dst), sizeof(dst) - 1);
+ 	switch (ip->ip_p) {
+ 		case IPPROTO_TCP:
+ 			tcphdr = (struct tcphdr*) ((char*) ip + (ip->ip_hl << 2));
+ 			printf("%s:%d -> %s:%d", src, ntohs (tcphdr->th_sport), dst, ntohs (tcphdr->th_dport));
+ 		break;
+ 		case IPPROTO_UDP:
+ 			udphdr = (struct udphdr*) ((char*) ip + (ip->ip_hl << 2));
+ 			printf("%s:%d -> %s:%d", src, ntohs (udphdr->uh_sport), dst, ntohs (udphdr->uh_dport));
+ 		break;
+ 		case IPPROTO_ICMP:
+ 			icmphdr = (struct icmp*) ((char*) ip + (ip->ip_hl << 2));
+ 			printf("%s -> %s %d(%d)", src, dst, ntohs (icmphdr->icmp_type), ntohs (icmphdr->icmp_code));
+ 		break;
+ 		default:
+ 			printf("%s -> %s ", src, dst);
+ 		break;
+ 	}
+ }
  
! static void SyslogPacket (struct ip* ip, int priority, char *label)
! {
! 	struct tcphdr*	tcphdr;
! 	struct udphdr*	udphdr;
! 	struct icmp*	icmphdr;
! 	char		src[20];
! 	char		dst[20];
! 
! 	strncpy(src, inet_ntoa (ip->ip_src), sizeof(src) - 1);
! 	strncpy(dst, inet_ntoa (ip->ip_dst), sizeof(dst) - 1);
! 	switch (ip->ip_p) {
! 		case IPPROTO_TCP:
! 			tcphdr = (struct tcphdr*) ((char*) ip + (ip->ip_hl << 2));
! 			syslog(priority, "%s [TCP] %s:%d -> %s:%d", label, src, ntohs (tcphdr->th_sport), dst, ntohs (tcphdr->th_dport));
! 		break;
! 		case IPPROTO_UDP:
! 			udphdr = (struct udphdr*) ((char*) ip + (ip->ip_hl << 2));
! 			syslog(priority, "%s [UDP] %s:%d -> %s:%d", label, src, ntohs (udphdr->uh_sport), dst, ntohs (udphdr->uh_dport));
! 		break;
! 		case IPPROTO_ICMP:
! 			icmphdr = (struct icmp*) ((char*) ip + (ip->ip_hl << 2));
! 			syslog(priority, "%s [ICMP] %s -> %s %d(%d)", label, src, dst, ntohs (icmphdr->icmp_type), ntohs (icmphdr->icmp_code));
! 		break;
! 		default:
! 			syslog(priority,"%s [%d] %s -> %s ", label, ip->ip_p, src, dst);
! 		break;
! 	}
  }
  
  static void SetAliasAddressFromIfName (char* ifName)
***************
*** 761,767 ****
  	RedirectPort,
  	RedirectAddress,
  	ConfigFile,
! 	DynamicMode
  };
  
  enum Param {
--- 819,827 ----
  	RedirectPort,
  	RedirectAddress,
  	ConfigFile,
! 	DynamicMode,
! 	LogDenied,
! 	LogFacility
  };
  
  enum Param {
***************
*** 922,928 ****
  		"file_name",
  		"read options from configuration file",
  		"config",
! 		"f" }
  };
  	
  static void ParseOption (char* option, char* parms, int cmdLine)
--- 982,1005 ----
  		"file_name",
  		"read options from configuration file",
  		"config",
! 		"f" },
! 
! 	{ LogDenied,
! 		0,
! 		YesNo,
! 	        "[yes|no]",
! 		"enable logging of denied incoming packets",
! 		"log_denied",
! 		NULL },
! 
! 	{ LogFacility,
! 		0,
! 		String,
! 	        "facility",
! 		"name of syslog facility to use for logging",
! 		"log_facility",
! 		NULL }
! 
  };
  	
  static void ParseOption (char* option, char* parms, int cmdLine)
***************
*** 937,942 ****
--- 1014,1020 ----
  	struct in_addr		addrValue;
  	int			max;
  	char*			end;
+ 	CODE* 			fac_record = NULL;
  /*
   * Find option from table.
   */
***************
*** 1069,1074 ****
--- 1147,1172 ----
  
  	case ConfigFile:
  		ReadConfigFile (strValue);
+ 		break;
+ 
+ 	case LogDenied:
+ 		logDropped = 1;
+ 		break;
+ 
+ 	case LogFacility:
+ 
+ 		fac_record = facilitynames;
+ 		while (fac_record->c_name != NULL) {
+ 			if(!strcmp(fac_record->c_name, strValue)) {
+ 				logFacility = fac_record->c_val;
+ 				break;
+ 			} else {
+ 				fac_record++;
+ 			}
+ 		}
+ 		if(fac_record->c_name == NULL) {
+ 			errx(1, "Unknown log facility name: %s", strValue);	
+ 		}
  		break;
  	}
  }


###### natd.8.patch ####################

*** natd.8.orig	Fri Jan  8 18:30:25 1999
--- natd.8	Fri Jan  8 18:42:53 1999
***************
*** 22,30 ****
--- 22,32 ----
  .Nm
  .Op Fl log
  .Op Fl deny_incoming
+ .Op Fl log_denied
  .Op Fl use_sockets
  .Op Fl same_ports
  .Op Fl verbose
+ .Op Fl log_facility Ar facility_name
  .Op Fl unregistered_only
  .Op Fl permanent_link
  .Op Fl dynamic
***************
*** 74,79 ****
--- 76,89 ----
  .It Fl deny_incoming | d
  Reject packets destined for the current IP number that have no entry
  in the internal translation table.
+ 
+ .It Fl log_denied
+ Log denied incoming packets via syslog (see also log_facility)
+ 
+ .It Fl log_facility Ar facility_name
+ Use specified log facility when logging information via syslog.
+ Facility names are as in
+ .Xr syslog.conf 5
  
  .It Fl use_sockets | s
  Allocate a

>Release-Note:
>Audit-Trail:

From: Brian Somers <brian@Awfulhak.org>
To: mm@i.cz
Cc: FreeBSD-gnats-submit@FreeBSD.ORG, Ari Suutari <ari@suutari.iki.fi>
Subject: Re: bin/9394: logging enhancements for natd 
Date: Sat, 09 Jan 1999 18:34:02 +0000

 > 
 > >Number:         9394
 
 I've forwarded these patches to the natd author for his comments.
 -- 
 Brian <brian@Awfulhak.org> <brian@FreeBSD.org> <brian@OpenBSD.org>
       <http://www.Awfulhak.org>
 Don't _EVER_ lose your sense of humour !
 
 
Responsible-Changed-From-To: freebsd-bugs->brian 
Responsible-Changed-By: brian 
Responsible-Changed-When: Sat Jan 9 18:36:17 PST 1999 
Responsible-Changed-Why:  
I've sent this for comment to Ari (the natd author) 
. 
State-Changed-From-To: open->closed 
State-Changed-By: brian 
State-Changed-When: Tue Mar 9 11:38:08 PST 1999 
State-Changed-Why:  
natd in -current now has these increased logging capabilities. 
>Unformatted:
