Subject: Re: Problem with ipmon(8)
To: Matthias Scheler <tron@zhadum.de>
From: Greg A. Woods <woods@weird.com>
List: tech-net
Date: 07/04/2001 17:36:35
[ On Wednesday, July 4, 2001 at 21:46:22 (+0200), Manuel Bouyer wrote: ]
> Subject: Re: Problem with ipmon(8)
>
> On Tue, Jul 03, 2001 at 09:01:19PM +0000, Matthias Scheler wrote:
> > 	Hello,
> > 
> > I start "ipmon" with the default flags "-sn" at system startup time to
> > watch the packet filter on my NetBSD NAT gateway. After a few hours
> > "ipmon" simply dies. Does anybody else these this problem?
> 
> which NetBSD version ? On 1.5 I've never seen this.
> Does it dump core ?

He's not using '-D', which means if he hits ^C on the console then ipmon
will die.  Matthias you have to use '-D' when starting ipmon.  It should
be the default, but it's not (perhaps because it was designed initially
to run under a SysV-style init with /etc/inittab).

I meant to follow up on this thread too....

Long long ago I fixed my copy of ipmon.c to call daemon(0,0) instead of
trying to do its own variant.

I also fixed it so that it wouldn't close stderr so as to facilitate the
times when it tries to write to STDERR if OPT_SYSLOG is set (so that I
could see any errors that it did complain about!).

You'll find these fixes among the attached diffs....  (which also
include other fixes and a little gift:  ICMP code->ASCII translation :-)

I seem to remember that before I made these changes ipmon would
occasionally die on me too, even with -D.

-- 
							Greg A. Woods

+1 416 218-0098      VE3TCP      <gwoods@acm.org>     <woods@robohack.ca>
Planix, Inc. <woods@planix.com>;   Secrets of the Weird <woods@weird.com>


Index: ipmon.c
===================================================================
RCS file: /cvs/NetBSD/src/dist/ipf/ipmon.c,v
retrieving revision 1.1.1.4
diff -c -c -r1.1.1.4 ipmon.c
*** ipmon.c	2001/06/12 21:03:00	1.1.1.4
--- ipmon.c	2001/07/04 21:28:11
***************
*** 123,128 ****
--- 123,129 ----
  static	void	dumphex __P((FILE *, u_char *, int));
  static	int	read_log __P((int, int *, char *, int));
  static	void	write_pid __P((char *));
+ static	char	*icmpname __P((u_int, u_int));
  
  char	*hostname __P((int, int, u_32_t *));
  char	*portname __P((int, char *, u_int));
***************
*** 135,142 ****
  static	char	**protocols = NULL;
  static	char	**udp_ports = NULL;
  static	char	**tcp_ports = NULL;
  
- 
  #define	OPT_SYSLOG	0x001
  #define	OPT_RESOLVE	0x002
  #define	OPT_HEXBODY	0x004
--- 136,143 ----
  static	char	**protocols = NULL;
  static	char	**udp_ports = NULL;
  static	char	**tcp_ports = NULL;
+ static  char	*argv0 = "ipmon";
  
  #define	OPT_SYSLOG	0x001
  #define	OPT_RESOLVE	0x002
  #define	OPT_HEXBODY	0x004
***************
*** 267,272 ****
--- 268,275 ----
  int	res, v;
  u_32_t	*ip;
  {
+ # define MAX_INETA	16
+ 	static char hname[MAXHOSTNAMELEN + MAX_INETA + 3];
  #ifdef	USE_INET6
  	static char hostbuf[MAXHOSTNAMELEN+1];
  #endif
***************
*** 280,287 ****
  		hp = gethostbyaddr((char *)ip, sizeof(ip), AF_INET);
  		if (!hp)
  			return inet_ntoa(ipa);
! 		return hp->h_name;
! 
  	}
  #ifdef	USE_INET6
  	(void) inet_ntop(AF_INET6, ip, hostbuf, sizeof(hostbuf) - 1);
--- 283,290 ----
  		hp = gethostbyaddr((char *)ip, sizeof(ip), AF_INET);
  		if (!hp)
  			return inet_ntoa(ipa);
! 		sprintf(hname, "%.*s[%s]", MAXHOSTNAMELEN, hp->h_name, inet_ntoa(ipa));
! 		return hname;
  	}
  #ifdef	USE_INET6
  	(void) inet_ntop(AF_INET6, ip, hostbuf, sizeof(hostbuf) - 1);
***************
*** 317,322 ****
--- 320,449 ----
  }
  
  
+ char	*icmpname(type, code)
+ u_int	type;
+ u_int	code;
+ {
+ 	static char	name[80];	/* > sizeof("UNREACH_ADMIN_PROHIBIT/NNNN") */
+ 	char		codeval[8];	/* > sizeof("/NN") */
+ 
+ 	if (code)
+ 		sprintf(codeval, "/%d", code);
+ 	else
+ 		codeval[0] = '\0';
+ 	switch (type) {
+ 	case ICMP_ECHOREPLY:				/* 0 */
+ 		sprintf(name, "echoreply%s", codeval);
+ 		break;
+ 	case ICMP_UNREACH:				/* 3 */
+ 		switch (code) {
+ 		case ICMP_UNREACH_NET:				/* 0 */
+ 			return("unreach/net");
+ 		case ICMP_UNREACH_HOST:				/* 1 */
+ 			return("unreach/host");
+ 		case ICMP_UNREACH_PROTOCOL:			/* 2 */
+ 			return("unreach/protocol");
+ 		case ICMP_UNREACH_PORT:				/* 3 */
+ 			return("unreach/port");
+ 		case ICMP_UNREACH_NEEDFRAG:			/* 4 */
+ 			return("unreach/needfrag");
+ 		case ICMP_UNREACH_SRCFAIL:			/* 5 */
+ 			return("unreach/srcfail");
+ 		case ICMP_UNREACH_NET_UNKNOWN:			/* 6 */
+ 			return("unreach/net_unknown");
+ 		case ICMP_UNREACH_HOST_UNKNOWN:			/* 7 */
+ 			return("unreach/host_unknown");
+ 		case ICMP_UNREACH_ISOLATED:			/* 8 */
+ 			return("unreach/isolated");
+ 		case ICMP_UNREACH_NET_PROHIB:			/* 9 */
+ 			return("unreach/net_prohib");
+ 		case ICMP_UNREACH_HOST_PROHIB:			/* 10 */
+ 			return("unreach/host_prohib");
+ 		case ICMP_UNREACH_TOSNET:			/* 11 */
+ 			return("unreach/tosnet");
+ 		case ICMP_UNREACH_TOSHOST:			/* 12 */
+ 			return("unreach/toshost");
+ 		case ICMP_UNREACH_ADMIN_PROHIBIT:		/* 13 */
+ 			return("unreach/admin_prohibit");
+ 		default:
+ 			sprintf(name, "unreach/%d", code);
+ 			break;
+ 		}
+ 		break;
+ 	case ICMP_SOURCEQUENCH:				/* 4 */
+ 		sprintf(name, "sourcequench%s", codeval);
+ 		break;
+ 	case ICMP_REDIRECT:				/* 5 */
+ 		switch (code) {
+ 		case ICMP_REDIRECT_NET:				/* 0 */
+ 			return("redirect/net");
+ 		case ICMP_REDIRECT_HOST:			/* 1 */
+ 			return("redirect/host");
+ 		case ICMP_REDIRECT_TOSNET:			/* 2 */
+ 			return("redirect/tosnet");
+ 		case ICMP_REDIRECT_TOSHOST:			/* 3 */
+ 			return("redirect/toshost");
+ 		default:
+ 			sprintf(name, "redirect/%d", code);
+ 			break;
+ 		}
+ 		break;
+ 	case ICMP_ECHO:					/* 8 */
+ 		sprintf(name, "echo%s", codeval);
+ 		break;
+ 	case ICMP_ROUTERADVERT:				/* 9 */
+ 		sprintf(name, "routeradvert%s", codeval);
+ 		break;
+ 	case ICMP_ROUTERSOLICIT:			/* 10 */
+ 		sprintf(name, "routersolicit%s", codeval);
+ 		break;
+ 	case ICMP_TIMXCEED:				/* 11 */
+ 		switch (code) {
+ 		case ICMP_TIMXCEED_INTRANS:			/* 0 */
+ 			return("timxceed/intrans");
+ 		case ICMP_TIMXCEED_REASS:			/* 1 */
+ 			return("timxceed/reass");
+ 		default:
+ 			sprintf(name, "timxceed/%d", code);
+ 			break;
+ 		}
+ 		break;
+ 	case ICMP_PARAMPROB:				/* 12 */
+ 		switch (code) {
+ 		case ICMP_PARAMPROB_OPTABSENT:			/* 1 */
+ 			return("paramprob/optabsent");
+ 		default:
+ 			sprintf(name, "paramprob/%d", code);
+ 			break;
+ 		}
+ 		break;
+ 	case ICMP_TSTAMP:				/* 13 */
+ 		sprintf(name, "tstamp%s", codeval);
+ 		break;
+ 	case ICMP_TSTAMPREPLY:				/* 14 */
+ 		sprintf(name, "tstampreply%s", codeval);
+ 		break;
+ 	case ICMP_IREQ:					/* 15 */
+ 		sprintf(name, "ireq%s", codeval);
+ 		break;
+ 	case ICMP_IREQREPLY:				/* 16 */
+ 		sprintf(name, "ireqreply%s", codeval);
+ 		break;
+ 	case ICMP_MASKREQ:				/* 17 */
+ 		sprintf(name, "maskreq%s", codeval);
+ 		break;
+ 	case ICMP_MASKREPLY:				/* 18 */
+ 		sprintf(name, "maskreply%s", codeval);
+ 		break;
+ 	default:
+ 		sprintf(name, "%d/%d", type, code);
+ 		break;
+ 	}
+ 
+ 	return name;
+ }
+ 
+ 
  static	void	dumphex(log, buf, len)
  FILE	*log;
  u_char	*buf;
***************
*** 741,749 ****
  		ic = (struct icmp *)((char *)ip + hl);
  		(void) sprintf(t, "%s -> ", hostname(res, v, s));
  		t += strlen(t);
! 		(void) sprintf(t, "%s PR icmp len %hu %hu icmp %d/%d",
  			hostname(res, v, d), hl, plen,
! 			ic->icmp_type, ic->icmp_code);
  		if (ic->icmp_type == ICMP_UNREACH ||
  		    ic->icmp_type == ICMP_SOURCEQUENCH ||
  		    ic->icmp_type == ICMP_PARAMPROB ||
--- 868,876 ----
  		ic = (struct icmp *)((char *)ip + hl);
  		(void) sprintf(t, "%s -> ", hostname(res, v, s));
  		t += strlen(t);
! 		(void) sprintf(t, "%s PR icmp len %hu %hu icmp %s",
  			hostname(res, v, d), hl, plen,
! 			icmpname((u_int) ic->icmp_type, (u_int) ic->icmp_code));
  		if (ic->icmp_type == ICMP_UNREACH ||
  		    ic->icmp_type == ICMP_SOURCEQUENCH ||
  		    ic->icmp_type == ICMP_PARAMPROB ||
***************
*** 881,887 ****
  
  	if ((fd = open(file, O_RDWR)) == -1) {
  		(void) fprintf(stderr, "%s: open: %s\n", file,STRERROR(errno));
! 		exit(-1);
  	}
  
  	if (ioctl(fd, SIOCIPFFB, &flushed) == 0) {
--- 1008,1014 ----
  
  	if ((fd = open(file, O_RDWR)) == -1) {
  		(void) fprintf(stderr, "%s: open: %s\n", file,STRERROR(errno));
! 		exit(1);
  	}
  
  	if (ioctl(fd, SIOCIPFFB, &flushed) == 0) {
***************
*** 944,950 ****
  	int	fd[3], doread, n, i;
  	int	tr, nr, regular[3], c;
  	int	fdt[3], devices = 0, make_daemon = 0;
! 	char	buf[512], *iplfile[3], *s;
  	extern	int	optind;
  	extern	char	*optarg;
  
--- 1071,1077 ----
  	int	fd[3], doread, n, i;
  	int	tr, nr, regular[3], c;
  	int	fdt[3], devices = 0, make_daemon = 0;
! 	char	buf[512], *iplfile[3];
  	extern	int	optind;
  	extern	char	*optarg;
  
***************
*** 954,959 ****
--- 1081,1088 ----
  	iplfile[1] = IPNAT_NAME;
  	iplfile[2] = IPSTATE_NAME;
  
+ 	argv0 = (argv0 = strrchr(argv[0], '/')) ? argv0 + 1 : argv[0];
+ 
  	while ((c = getopt(argc, argv, "?abDf:FhnN:o:O:pP:sS:tvxX")) != -1)
  		switch (c)
  		{
***************
*** 1004,1017 ****
  			pidfile = optarg;
  			break;
  		case 's' :
! 			s = strrchr(argv[0], '/');
! 			if (s == NULL)
! 				s = argv[0];
! 			else
! 				s++;
! 			openlog(s, LOG_NDELAY|LOG_PID, LOGFAC);
! 			s = NULL;
  			opts |= OPT_SYSLOG;
  			break;
  		case 'S' :
  			opts |= OPT_STATE;
--- 1133,1141 ----
  			pidfile = optarg;
  			break;
  		case 's' :
! 			openlog(argv0, LOG_NDELAY|LOG_PID, LOGFAC);
  			opts |= OPT_SYSLOG;
+ 			log = NULL;		/* don't log to stdout any more! */
  			break;
  		case 'S' :
  			opts |= OPT_STATE;
***************
*** 1033,1039 ****
  		default :
  		case 'h' :
  		case '?' :
! 			usage(argv[0]);
  		}
  
  	init_tabs();
--- 1157,1163 ----
  		default :
  		case 'h' :
  		case '?' :
! 			usage(argv0);
  		}
  
  	init_tabs();
***************
*** 1054,1066 ****
  				(void) fprintf(stderr,
  					       "%s: open: %s\n", iplfile[i],
  					       STRERROR(errno));
! 				exit(-1);
  			}
- 
  			if (fstat(fd[i], &sb) == -1) {
  				(void) fprintf(stderr, "%d: fstat: %s\n",fd[i],
  					       STRERROR(errno));
! 				exit(-1);
  			}
  			if (!(regular[i] = !S_ISCHR(sb.st_mode)))
  				devices++;
--- 1178,1191 ----
  				(void) fprintf(stderr,
  					       "%s: open: %s\n", iplfile[i],
  					       STRERROR(errno));
! 				exit(1);
! 				/* NOTREACHED */
  			}
  			if (fstat(fd[i], &sb) == -1) {
  				(void) fprintf(stderr, "%d: fstat: %s\n",fd[i],
  					       STRERROR(errno));
! 				exit(1);
! 				/* NOTREACHED */
  			}
  			if (!(regular[i] = !S_ISCHR(sb.st_mode)))
  				devices++;
***************
*** 1071,1095 ****
  		logfile = argv[optind];
  		log = logfile ? fopen(logfile, "a") : stdout;
  		if (log == NULL) {
- 			
  			(void) fprintf(stderr, "%s: fopen: %s\n", argv[optind],
  				STRERROR(errno));
! 			exit(-1);
  		}
  		setvbuf(log, NULL, _IONBF, 0);
  	} else
  		log = NULL;
  
  	if (make_daemon && ((log != stdout) || (opts & OPT_SYSLOG))) {
! 		if (fork() > 0)
  			exit(0);
! 		write_pid(pidfile);
  		close(0);
  		close(1);
! 		close(2);
! 		setsid();
! 	} else
! 		write_pid(pidfile);
  
  	signal(SIGHUP, handlehup);
  
--- 1196,1231 ----
  		logfile = argv[optind];
  		log = logfile ? fopen(logfile, "a") : stdout;
  		if (log == NULL) {
  			(void) fprintf(stderr, "%s: fopen: %s\n", argv[optind],
  				STRERROR(errno));
! 			exit(1);
! 			/* NOTREACHED */
  		}
  		setvbuf(log, NULL, _IONBF, 0);
  	} else
  		log = NULL;
  
  	if (make_daemon && ((log != stdout) || (opts & OPT_SYSLOG))) {
! #if BSD
! 		daemon(0, !(opts & OPT_SYSLOG));
! #else
! 		int pid;
! 		if ((pid = fork()) > 0)
  			exit(0);
! 		if (pid < 0) {
! 			(void) fprintf(stderr, "%s: fork() failed: %s\n", argv0,
! 				       STRERROR(errno));
! 			exit(1);
! 			/* NOTREACHED */
! 		}
! 		setsid();
! 		if (!(opts & OPT_SYSLOG))
! 			close(2);
! #endif /* !BSD */
  		close(0);
  		close(1);
! 	}
! 	write_pid(pidfile);
  
  	signal(SIGHUP, handlehup);
  
***************
*** 1102,1109 ****
  				continue;
  			if (!regular[i]) {
  				if (ioctl(fd[i], FIONREAD, &tr) == -1) {
! 					perror("ioctl(FIONREAD)");
! 					exit(-1);
  				}
  			} else {
  				tr = (lseek(fd[i], 0, SEEK_CUR) < sb.st_size);
--- 1238,1249 ----
  				continue;
  			if (!regular[i]) {
  				if (ioctl(fd[i], FIONREAD, &tr) == -1) {
! 					if (opts & OPT_SYSLOG)
! 						syslog(LOG_CRIT, "ioctl(FIONREAD): %m");
! 					else
! 						perror("ioctl(FIONREAD)");
! 					exit(1);
! 					/* NOTREACHED */
  				}
  			} else {
  				tr = (lseek(fd[i], 0, SEEK_CUR) < sb.st_size);
***************
*** 1128,1141 ****
  			{
  			case -1 :
  				if (opts & OPT_SYSLOG)
! 					syslog(LOG_ERR, "read: %m\n");
  				else
  					perror("read");
  				doread = 0;
  				break;
  			case 1 :
  				if (opts & OPT_SYSLOG)
! 					syslog(LOG_ERR, "aborting logging\n");
  				else
  					fprintf(log, "aborting logging\n");
  				doread = 0;
--- 1268,1281 ----
  			{
  			case -1 :
  				if (opts & OPT_SYSLOG)
! 					syslog(LOG_CRIT, "read: %m\n");
  				else
  					perror("read");
  				doread = 0;
  				break;
  			case 1 :
  				if (opts & OPT_SYSLOG)
! 					syslog(LOG_CRIT, "aborting logging\n");
  				else
  					fprintf(log, "aborting logging\n");
  				doread = 0;