--- Makefile.in.orig	Tue Jul 20 19:28:20 2004
+++ Makefile.in	Thu Nov  2 13:35:27 2006
@@ -47,7 +47,7 @@
 
 NETMOND_C = netmond.c netstate.c event.c session.c mib.c snmp.c router.c \
 	trap.c ping.c tcp.c udp.c dns.c radius.c tacacs.c md5.c util.c \
-	variables.c save.c regex.c malloc.c reconfig.c
+	variables.c save.c regex.c malloc.c reconfig.c pipe.c
 NETMOND_Y = calc.y parseconf.y
 NETMOND_L = scanconf.l
 NETMOND_G = version.c
--- dns.c.orig	Mon Aug 25 18:19:04 2003
+++ dns.c	Thu Nov  2 13:35:27 2006
@@ -149,6 +149,8 @@
 {
 	SESSION *sd = method->sd;
 	int reqid;
+	struct sockaddr_in *from;
+	char ipaddr[20];
 
 	/* sanity check */
 	if (!sd) return;
@@ -161,6 +163,14 @@
 		return;
 	}
 
+	/* bind  socket to local source address */
+
+	from = (struct sockaddr_in *)&sd->me;
+	if ( from->sin_addr.s_addr != INADDR_ANY ) {		
+	    if( bind(sd->sock, &sd->me, sizeof(struct sockaddr) ) == -1 ) 
+		report(LOG_WARNING, "dns_start : bind failed for %s: %s",
+		    	intoa(ipaddr,from->sin_addr), strerror(*(__error())) );
+	}
 	/* turn on non-blocking I/O */
 	if (set_socket_async(sd->sock, TRUE) < 0) {
 		dns_reply(errno, sd, 0);
@@ -288,7 +298,7 @@
 	METHOD *method;
 {
 	SESSION template;
-	struct sockaddr_in *to;
+	struct sockaddr_in *to, *from;
 
 	dprintf(("dns_init(%s/%s)\n", target->name, method->name));
 
@@ -303,6 +313,10 @@
 	to->sin_family = AF_INET;
 	to->sin_port = htons(method->rport);
 	to->sin_addr = method->address ? method->ip_addr : target->ip_addr;
+	from = (struct sockaddr_in *)&template.me;
+	bzero((char *)from, sizeof(struct sockaddr_in));
+	from->sin_family = AF_INET;
+	from->sin_addr = target->ip_srcaddr;
 	template.timeout = method->timeout * 1000000L; /* make microseconds */
 	template.retries = method->retries;
 	template.send = dns_send;
@@ -332,6 +346,7 @@
 	IPPROTO_UDP,	/* network protocol */
 	NAMESERVER_PORT, /* server port */
 	0, 0,		/* timeout and retries undefined yet */
+        NULL,NULL,       /* when variables unused */
 	{ 0, 0 },	/* no parameters used */
 
 	/* Non-initialized data */
--- event.c.orig	Thu Feb 27 17:42:32 2003
+++ event.c	Tue Nov 14 17:40:52 2006
@@ -288,7 +288,7 @@
 #ifdef	HAVE_PTHREAD
 	pthread_mutex_lock(&localtime_lock);
 #endif
-	tm = localtime(&tvp->tv_sec);
+	tm = localtime((time_t *)&tvp->tv_sec);
 	defect = tm->tm_sec + 60 * tm->tm_min + 3600 * tm->tm_hour + off;
 #ifdef	HAVE_PTHREAD
 	pthread_mutex_unlock(&localtime_lock);
--- netmon.h.orig	Tue Aug 26 10:00:38 2003
+++ netmon.h	Thu Dec 28 13:31:06 2006
@@ -14,6 +14,9 @@
 #include <sys/socket.h>
 #include <sys/time.h>
 #include <netinet/in.h>
+#include <pwd.h>
+#include <grp.h>
+#include <time.h>
 #ifdef	DEBUG_MEMORY
 #include <assert.h>
 #endif
@@ -77,7 +80,10 @@
 #endif
 
 #define	NETMON			"netmon"
-#define	DEFAULT_CONFIG		"/etc/netmon.conf"
+#define	DEFAULT_CONFIG		"/usr/local/etc/netmond.conf"
+#define USERNAME		"netmon"
+#define GROUPNAME		"netmon"
+#define PIDFILE_PATH		"/var/run"
 #define	DEFAULT_WATCHDOG	600	/* 10 min */
 
 #define	POLLING_MIN		30	/* 30 sec */
@@ -88,9 +94,13 @@
 typedef	struct timeval TIMEVAL;
 typedef	unsigned long oid;
 
+#define	STATE_UNKNOWN	0
 #define	STATE_UP	1
 #define	STATE_DOWN	2
+#define	STATE_DEGRADED	3
+#define	STATE_WARNING	4
 #define	BGP_ESTABLISHED	6
+#define	ENV_NORMAL	1
 #define	ENV_NOTPRESENT	5
 
 #define	OBJ_STATE	0
@@ -111,6 +121,9 @@
 #define	TYPE_ENVFAN		9
 #define	TYPE_ENVPS		10
 
+#define WHEN_PROTO		10099
+#define PIPE_PROTO		10098
+
 struct object_ent;
 struct method_ent;
 
@@ -250,6 +263,7 @@
 
 	int state;		/* current operational status (UP/DOWN/...) */
 	int prev_state;		/* previous operational status */
+	int ignore_state;       /* if =1, ignore this interface while parent object state evaluating */
 	TIMEVAL last_request;	/* last time interface requested */
 	TIMEVAL prev_request;	/* previous time interface requested */
 	TIMEVAL last_reply;	/* last time interface reply */
@@ -294,6 +308,7 @@
 	int asn;		/* AS number */
 	char *descr;		/* AS description */
 	char *datadir;		/* directory where store data */
+	int ignore_state;       /* if =1, ignore this AS while parent object state evaluating */
 	SAVE *save_list;	/* list of save methods */
 	GROUP_REF *ns_acl;	/* netstate client access list */
 
@@ -325,6 +340,7 @@
 	int type;		/* type of gauge: TYPE_ENVTEMP, etc */
 	char *descr;		/* env mon description */
 	char *datadir;		/* directory where store data */
+	int ignore_state;       /* if =1, ignore this ENV while parent object state evaluating */
 	SAVE *save_list;	/* list of save methods */
 	GROUP_REF *ns_acl;	/* netstate client access list */
 
@@ -385,13 +401,14 @@
 	struct method_ent *method;	/* session method */
 	int sock;		/* socket file descriptor */
 	struct sockaddr peer;	/* address of peer */
+	struct sockaddr me;	/* my source address  */
 	long timeout;		/* number of microseconds until first timeout */
 	int retries;		/* number of retries before timeout */
 	int (*connect) __P((struct session_ent *));
 	int (*send) __P((struct session_ent *, REQUEST *));
 	int (*recv) __P((struct session_ent *));
 	void (*read) __P((int, struct session_ent *, int));
-
+	pid_t	pid;
 	/* returned values */
 	int data_int;		/* data length or chat-script matchs */
 	char *data_ptr;		/* pointer to resulting data if any */
@@ -428,6 +445,8 @@
 	u_short	rport;		/* remote port number, 0=unused */
 	int timeout;		/* number of seconds until first timeout */
 	int retries;		/* number of retries before timeout */
+	char *when;	        /* condition string */
+	char *when_fmt;         /* message when condition is true */
 	union {
 		struct ping_param {
 			short send;	/* ICMP echo request packets to send */
@@ -530,7 +549,9 @@
 	char *descr;		/* object description */
 	char *datadir;		/* directory where store data */
 	char *address;		/* domain name or dotted IP address */
+	char *srcaddress;	/* domain name or dotted source IP address */
 	struct in_addr ip_addr;	/* ip address of peer */
+	struct in_addr ip_srcaddr; /* source ip address */
 	int polling;		/* polling period in seconds */
 	int saving;		/* saving period in seconds */
 	int sync;		/* polling counter to synchronize saving */
@@ -544,6 +565,10 @@
 
 	int state;		/* current operational status (UP/DOWN/...) */
 	int prev_state;		/* previous operational status */
+	int ignore_state;       /* if =1, ignore this obj while parent object state evaluating */
+	int mths_ok;		/* count of Ok finished methods */
+	int mths_fail;		/* count of Failed methods */
+	int smths_fail;		/* count of Failed services methods */
 	TIMEVAL last_request;	/* last time method requested */
 	TIMEVAL prev_request;	/* previous time method requested */
 	TIMEVAL last_reply;	/* last time method reply */
@@ -574,17 +599,29 @@
 
 typedef	struct config_ent {
 	char *rootdir;		/* default work directory */
+	char *chrootdir;	/* chroot directory for EXEC children */
+	char *username;		/* username for EXEC children */	
+	uid_t	uid;		/* UID for EXEC children */	
+	char *groupname;	/* groupname for EXEC children */	
+	gid_t	gid;		/* GID for EXEC children */	
 	char *timefmt;		/* strftime format of currtime for logging */
+	char *srcaddress;	/* my default source domain name or dotted IP address */
+	struct in_addr ip_srcaddr; /* my default sorce ip address  */
 	int polling;		/* default polling interval in seconds */
 	int saving;		/* default saving interval in seconds */
 	int timeout;		/* default timeout in seconds */
 	int retries;		/* default number of retries */
+	int compatibility_flag;	/*  */
 
 	int enable_traps;	/* enable SNMP traps */
 	int source_traps;	/* match src-addr and agent-addr of traps */
+	char *trap_address;	/* Trap bind address */
+	struct in_addr trap_ip_addr;	/*  */	
 
 	/* netstate server */
 	int ns_port;		/* server port number */
+	char *ns_address;	/* NetState bind address */
+	struct in_addr ns_ip_addr;	/*  */	
 	int ns_timo;		/* client timeout in seconds */
 	GROUP_REF *ns_acl;	/* netstate client access list */
 
@@ -616,6 +653,7 @@
 extern int netstate_sock;
 extern int Cflag;
 extern int syslog_initialized;
+extern int compatibility_flag;
 
 /*
  * Function prototypes
@@ -733,6 +771,19 @@
 void tcp_start __P((METHOD *));
 void tcp_stop __P((METHOD *));
 int match_expect __P((SESSION *, CHATSCRIPT *, char *));
+int tcp_connect __P((SESSION *));
+int tcp_send __P((SESSION *,REQUEST *));
+int tcp_recv __P((SESSION *));
+void tcp_close __P((int, SESSION *, int));
+
+/* pipe.c */
+int pipe_init __P((OBJECT *, METHOD *));
+void pipe_start __P((METHOD *));
+void pipe_stop __P((METHOD *));
+
+int when_init __P((OBJECT *, METHOD *));
+void when_start __P((METHOD *));
+void when_stop __P((METHOD *));
 
 /* udp.c */
 int udp_init __P((OBJECT *, METHOD *));
--- netmond.c.orig	Tue Jul 20 17:57:19 2004
+++ netmond.c	Thu Dec 28 13:31:06 2006
@@ -62,6 +62,8 @@
 pid_t mypid;			/* my self PID */
 int syslog_initialized;		/* syslog ready to use */
 int syslog_facility;		/* current syslog facility */
+int compatibility_flag = 1;	/* version backward compatibility flag.
+                                   default - work like previous version  */
 
 #ifdef	HAVE_PTHREAD
 pthread_t main_thr;
@@ -79,7 +81,6 @@
 static int reconfig_pending;
 static int watchdog_timeout;
 static int watchdog_pending;
-
 static struct sighandler_ent {
 	int sig;
 	int flags;
@@ -254,8 +255,7 @@
 	/*
 	 * Make pid file.
 	 */
-	(void)strcpy(buf, program_name);
-	(void)strcat(buf, ".pid");
+	snprintf(buf, sizeof(buf), "%s/%s.pid", PIDFILE_PATH, program_name);
 	if ((fp = fopen(buf, "w")) != NULL) {
 		fprintf(fp, "%d\n", (int)mypid);
 		fclose(fp);
@@ -380,7 +380,8 @@
 #ifdef	HAVE_PTHREAD
 					reconfig_pending = 0;
 #else
-					reconfig_pending = -1;
+				//	reconfig_pending = -1;
+					reconfig_pending = 0;
 #endif
 				}
 			}
@@ -626,73 +627,159 @@
 	TIMEVAL tv;
 	VARIABLE *var;
 	OBJECT *service;
+	INTERFACE *interface;
+	BGP_AS	*bgp;
+	BGP_PEER *bgp_peer;
+	ENV_MON	*env;
+	ENV_GAUGE *gauge;
+	char *buf;
+	ssize_t buf_len; 
 
 	/* current timestamp */
 	gettimeofday(&tv, NULL);
-
 	/* save method diagnostic */
-	if (method && diag && (var = get_var(object->var_list, method->name)) != NULL)
-		str2var(var, diag);
-
-	if (!method || !ok) {
-		/*
-		 * Method list aborted or Start Trap received.
-		 */
-
-		/* update object operational status */
-		object->prev_state = object->state;
+	if (method && diag && (var = get_var(object->var_list, method->name)) != NULL) {
+	    str2var(var, diag);
+	    /* save method return value */
+	    buf_len = strlen(method->name)+4;
+	    buf = malloc(buf_len);
+	    if ( buf ) {
+		snprintf(buf,buf_len,"%s.ok",method->name);	    
+		if ((var = get_var(object->var_list, buf)) != NULL)
+		    set_var(var, INTEGER, &ok, sizeof(ok));
+		free(buf);    
+	    } else {
+		report(LOG_ERR, "method_finished(%s!):.ok malloc: %m", object->name,method->name);			
+	    }
+	}
+	if ( compatibility_flag ) {
+	    if (!method || !ok) {
 		object->state = STATE_DOWN;
-
 		if (object->state != object->prev_state)
 			object->last_change = tv;
-
 #ifdef	DEBUG
 		if (object->prev_state != STATE_DOWN)
 			dprintf(("object \"%s\" change state to DOWN\n", object->name));
 #endif
-
 		/* stop anything here */
 		object_stop(object);
-
 		for (service = object->service; service; service = service->next)
 			object_stop(service);
 
 		set_none_state(object);
-
 		save_object_state(object);
-
 		/* stop data saving on the object */
 		remove_event(save_object_data, object);
-
 		/* keep touching the object if required */
 		if (object->polling > 0) {
 			tv.tv_sec += object->polling / 2;
 			add_event(&tv, start_method_list, object);
 		}
 		return;
-	}
-
-	if (method->next) {
-		/*
-		 * Advance to next object method.
-		 */
-
+	    }	
+	    if (method->next) {
+		method = method->next;
+		(*method->start)(method);
+	    	return;
+	    }
+    	    object->prev_reply = object->last_reply;
+	    object->last_reply = tv; /* last reply timestamp */
+    	
+	    /* update object operational status */
+	    object->prev_state = object->state;
+	    object->state = STATE_UP;	    
+
+	} else {
+	    if (!method || !ok) {
+		object->mths_fail++;
+	    }  else {
+	    	object->mths_ok++;
+	    }
+	    if (method && method->next) {
+		/*  Advance to next object method.  */		 
 		method = method->next;
 		(*method->start)(method);
 		return;
-	}
+	    }
+	    /* Method list done. */
+	    object->prev_reply = object->last_reply;
+	    object->last_reply = tv; /* last reply timestamp */
+	
+	    /* update object operational status */
+	    object->prev_state = object->state;
+	    if ( object->mths_ok == 0 ) {
+		object->state = STATE_DOWN;
 
-	/*
-	 * Method list done.
-	 */
+		if (object->state != object->prev_state)
+			object->last_change = tv;
+#ifdef	DEBUG
+		if (object->prev_state != STATE_DOWN)
+			dprintf(("object \"%s\" change state to DOWN\n", object->name));
+#endif
+		/* stop anything here */
+		object_stop(object);
 
-	object->prev_reply = object->last_reply;
-	object->last_reply = tv; /* last reply timestamp */
+		for (service = object->service; service; service = service->next)
+			object_stop(service);
 
-	/* update object operational status */
-	object->prev_state = object->state;
-	object->state = STATE_UP;
+		set_none_state(object);
+
+		save_object_state(object);
+
+		/* stop data saving on the object */
+		remove_event(save_object_data, object);
 
+		/* keep touching the object if required */
+		if (object->polling > 0) {
+			tv.tv_sec += object->polling / 2;
+			add_event(&tv, start_method_list, object);
+		}
+		return;
+	    } else {
+		if ( object->mths_fail ) {
+		    object->state = STATE_DEGRADED;
+		} else {
+		    object->state = STATE_UP;
+		    for (service = object->service; service; service = service->next) {		
+			if (!service->ignore_state && service->state != STATE_UP) {
+			    object->state = STATE_WARNING;		
+			    break;
+			}
+		    }
+		    for (interface = object->interface; interface; interface = interface->next) {
+			if (!interface->ignore_state && interface->state != STATE_UP) {
+			    object->state = STATE_WARNING;		
+			    break;
+			}
+		    }
+		    for ( bgp = object->bgp; bgp; bgp = bgp->next) {    
+			if (bgp->ignore_state ) continue;
+			for ( bgp_peer = bgp->peer; bgp_peer; bgp_peer=bgp_peer->next) {
+			    if ( bgp_peer->state != BGP_ESTABLISHED){
+				object->state = STATE_WARNING;		
+				break;
+			    }
+			}
+			if (object->state == STATE_WARNING)
+			    break;		    
+		    }	    
+		    for (env = object->env; env; env = env->next) {
+			if (env->ignore_state ) continue;
+			for( gauge = env->gauge; gauge; gauge=gauge->next) {
+			    if (gauge->state != ENV_NORMAL && gauge->state != ENV_NOTPRESENT ) {
+				object->state = STATE_WARNING;		
+				break;
+			    }
+			}	
+			if (object->state == STATE_WARNING)
+				break;		    
+		    }	
+		}
+	    }
+	    object->mths_ok = 0;
+	    object->mths_fail = 0;
+	    object->smths_fail = 0;
+	}
 	if (object->state != object->prev_state)
 		object->last_change = tv;
 
@@ -827,10 +914,25 @@
 		/* child would be terminated by signals */
 		sigprocmask(SIG_SETMASK, NULL, &sigmask);
 		sigprocmask(SIG_UNBLOCK, &sigmask, NULL);
-
+		close(netstate_sock);
+		
 		/* make session leader to be able killpg() latter */
 		setsid();
 
+		if ( cf->chrootdir) {
+		    if ( chroot( cf->chrootdir ) < 0 ) {
+			report(LOG_ERR, "chroot %s: %s", cf->chrootdir,strerror(*(__error())) );
+			_exit(127);
+		    }
+		}
+		if ( setgid(cf->gid) < 0 ) {
+		    report(LOG_ERR, "setgid %s[%d]: %s", cf->groupname, cf->gid, strerror(*(__error())) );
+		    _exit(127);
+		}			
+		if ( (cf->uid != 0) & (setuid(cf->uid) < 0) ) {
+		    report(LOG_ERR, "setuid %s[%d]: %s", cf->username, cf->uid, strerror(*(__error())) );
+		    _exit(127);
+		}		
 		execve(file, av, environ);
 		report(LOG_ERR, "execve %s: %m", file);
 		_exit(127);
@@ -928,8 +1030,7 @@
 #endif
 	{
 		char pidfile[100];
-		(void)strcpy(pidfile, program_name);
-		(void)strcat(pidfile, ".pid");
+		snprintf(pidfile, sizeof(pidfile), "%s/%s.pid", PIDFILE_PATH, program_name);
 		(void)unlink(pidfile);
 		report(LOG_CRIT, "aborted by signal %d", sig);
 	} else	report(LOG_INFO, "interrupted by signal %d", sig);
--- netstate.c.orig	Tue Aug 26 10:54:09 2003
+++ netstate.c	Thu Nov  2 13:35:27 2006
@@ -128,7 +128,7 @@
 		memset(&sin, 0, sizeof(sin));
 		sin.sin_family = AF_INET;
 		sin.sin_port = htons(cf->ns_port);
-		sin.sin_addr.s_addr = INADDR_ANY;
+		sin.sin_addr = cf->ns_ip_addr;
 		if (bind(netstate_sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
 			report(LOG_ERR, "bind port %d: %m", ntohs(sin.sin_port));
 			close(netstate_sock);
@@ -405,6 +405,14 @@
 	_exit(1);
 }
 #endif
+int 
+iskoi8(unsigned char ch)
+{
+    if ( ch == 163 ) return 1;
+    if ( ch == 179 ) return 1;
+    if ( ch >= 192 ) return 1;
+    return 0;    
+}
 
 void *
 netstate_serve(arg)
@@ -505,9 +513,9 @@
 			set_timer(0, interrupt);
 #endif
 		if (!cp) break;
-		while (isprint(*cp)) cp++;
+		while ( iskoi8(*cp) || isprint(*cp) ) cp++;
 		*cp = '\0';
-
+	    
 		next = input;
 		if ((cp = my_strsep(&next, " ")) == NULL) {
 			bad_input++;
--- parseconf.y.orig	Tue Aug 26 10:53:30 2003
+++ parseconf.y	Thu Dec 28 13:31:06 2006
@@ -13,6 +13,7 @@
 #endif
 
 #include <sys/types.h>
+#include <sys/limits.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <stdio.h>
@@ -117,6 +118,7 @@
 	first_save = NULL;
 
 	global_var_list = 0;
+	config.compatibility_flag = 1;
 }
 
 static char *
@@ -197,11 +199,37 @@
 	BGP_AS *bgp;
 	ENV_MON *env;
 	char *cp, buf[1024];
+	struct	passwd *pwentry;
+	struct	group  *grentry;
 
 	if (!config.rootdir) {
 		report(LOG_ERR, "%s: rootdir unspecified", config_file);
 		return NULL;
 	}
+	compatibility_flag = config.compatibility_flag;
+	if (!config.srcaddress)
+    		bzero(&config.ip_srcaddr, sizeof(struct in_addr));
+	if (!config.ns_address)
+    		bzero(&config.ns_ip_addr, sizeof(struct in_addr));
+	if (!config.trap_address)
+    		bzero(&config.trap_ip_addr, sizeof(struct in_addr));
+		
+	if(!config.username) {
+	    config.username = strdup(USERNAME);
+	    if ((pwentry = getpwnam(USERNAME)) == (struct passwd *) NULL) {
+		report(LOG_ERR, "Bad default username: %s.",config.username);
+		return NULL;
+	    }
+	    config.uid = pwentry->pw_uid;
+	}
+	if(!config.groupname) {
+	    config.groupname = strdup(GROUPNAME);
+	    if ((grentry = getgrnam(GROUPNAME)) == (struct group *) NULL) {
+		report(LOG_ERR, "Bad default groupname: %s.",config.groupname);
+		return NULL;
+	    }
+	    config.gid = (gid_t)grentry->gr_gid;
+	}
 	if (config.polling) {
 		if (!config.timeout)
 			config.timeout = TIMEOUT_DEFAULT;
@@ -273,6 +301,7 @@
 
 		for (service = target->service; service; service = service->next) {
 			service->ip_addr = target->ip_addr;
+			service->ip_srcaddr = target->ip_srcaddr;
 			service->parent = target;
 
 			(void)strcpy(cp, "/");
@@ -329,6 +358,8 @@
 	METHOD *method;
 	CHATSCRIPT *cs;
 	REFERENCE *ref;
+	char *buf;
+	ssize_t buf_len;
 
 	/* sanity check */
 	if (!chain || !item) {
@@ -362,6 +393,16 @@
 			yyerror("Out of memory");
 			return 0;
 		}
+		buf_len =  strlen(method->name)+4 ;
+		buf = malloc( buf_len );
+		if (buf) 
+		    snprintf(buf,buf_len,"%s.ok",method->name);
+		if (!buf || !add_var(&curr->var_list, buf)) {
+			yyerror("Out of memory");
+			return 0;
+		}
+		free(buf);
+		
 		/* bind variable references */
 		for (cs = method->chatscript; cs; cs = cs->next) {
 			for (ref = cs->var_ref; ref; ref = ref->next) {
@@ -854,7 +895,7 @@
 	}
 	/* check for duplicates */
 	for (curr = *chain; curr; curr = curr->next) {
-		if (!strcasecmp(curr->name, item->name)) {
+		if ( chain == &first_save && !strcasecmp(curr->name, item->name)) {
 			yyerror("save name \"%s\" duplicated", item->name);
 			return 0;
 		}
@@ -901,7 +942,9 @@
 	char *argument;
 {
 	METHOD *new;
-
+        char arg_list[1024], *av[MAX_ARGS+2];
+	int ac = 0;
+		
 	if ((new = (METHOD *)malloc(sizeof(METHOD))) == NULL) {
 		yyerror("Out of memory");
 		return NULL;
@@ -915,10 +958,24 @@
 		yyerror("Out of memory");
 		return 0;
 	}
-	if (argument)
+	if (argument) {
 		new->argument = argument;
-	else if (new->argument)
+                (void)strncpy(arg_list, argument, sizeof(arg_list));
+		arg_list[sizeof(arg_list)-1] = '\0';
+	} else if (new->argument) {
 		new->argument = strdup(new->argument);
+                (void)strncpy(arg_list, new->argument, sizeof(arg_list));
+		arg_list[sizeof(arg_list)-1] = '\0';	
+	} else  arg_list[0] = '\0';
+        av[ac++] = new->name;
+        ac += make_argv(arg_list, (char ***)&av[ac], MAX_ARGS);
+	av[ac] = NULL;
+
+        if (new->when && (new->when = insert_args(new->when, av, ac)) == NULL)
+	        return NULL;
+	if (new->when_fmt && (new->when_fmt = insert_args(new->when_fmt, av, ac)) == NULL)
+                return NULL;
+	
 	if (new->chatscript) {
 		new->chatscript = dup_chatscript(new->name, new->argument, new->chatscript);
 		if (!new->chatscript) return NULL;
@@ -1342,11 +1399,15 @@
 
 /* Lexical analyzer return values */
 %token TOKEN_ROOTDIR
+%token TOKEN_CHROOTDIR
+%token TOKEN_USERNAME
+%token TOKEN_GROUPNAME
 %token TOKEN_TIMEFMT
 %token TOKEN_POLLING
 %token TOKEN_SAVING
 %token TOKEN_TIMEOUT
 %token TOKEN_RETRIES
+%token TOKEN_OMULSTATES
 
 %token TOKEN_GROUP
 %token TOKEN_PERMIT
@@ -1354,6 +1415,7 @@
 
 %token TOKEN_NETSTATE
 %token TOKEN_PORT
+%token TOKEN_BINDADDRESS
 
 %token TOKEN_SAVE
 %token TOKEN_FILE
@@ -1365,6 +1427,7 @@
 
 %token TOKEN_OBJECT
 %token TOKEN_ADDRESS
+%token TOKEN_SRCADDRESS
 %token TOKEN_DESCRIPTION
 %token TOKEN_SERVICE
 %token TOKEN_INTERFACE
@@ -1398,11 +1461,13 @@
 %token TOKEN_V2
 
 %token TOKEN_TRAP
+%token TOKEN_TRAPBINDADDRESS
 %token TOKEN_SOURCECHECK
 %token TOKEN_COMMUNITY
 %token TOKEN_ENTERPRISE
 %token TOKEN_SPECIFIC
 %token TRAP_GENERIC
+%token TOKEN_IGNORESTATE
 
 %token <number> TOKEN_NUMBER
 %token <string> TOKEN_STRING
@@ -1410,7 +1475,7 @@
 %token <string> VAR_OID
 
 %type <number> optional_number
-%type <string> optional_string quoted_string legal_string multiline_string
+%type <string> optional_string quoted_string legal_string multiline_string optional_multiline_string
 %type <save> get_save
 %type <method> get_method
 %type <trap> get_trap
@@ -1442,6 +1507,60 @@
 				YYABORT;
 			}
 		}
+	|	TOKEN_CHROOTDIR quoted_string
+		{
+			if (config.chrootdir) {
+				yyerror("ChRootDir statement duplicated");
+				YYABORT;
+			}
+			config.chrootdir = $2;
+		}
+	|	TOKEN_USERNAME quoted_string
+		{
+			struct passwd *pwentry;
+			
+			if (config.username) {
+				yyerror("UserName statement duplicated");
+				YYABORT;
+			}
+    			if ((pwentry = getpwnam($2)) == (struct passwd *)NULL) {
+				yyerror("UserName %s unknown.", $2);
+				YYABORT;			    
+			}			
+			config.uid = pwentry->pw_uid;
+			config.username = $2;			
+		}
+
+	|	TOKEN_GROUPNAME quoted_string
+		{
+			struct group *grentry;
+			
+			if (config.groupname) {
+				yyerror("GroupName statement duplicated");
+				YYABORT;
+			}
+    			if ((grentry = getgrnam($2)) == (struct group *)NULL) {
+				yyerror("GroupName %s unknown.", $2);
+				YYABORT;			    
+			}			
+			config.gid = grentry->gr_gid;
+			config.groupname = $2;			
+		}
+
+	|	TOKEN_SRCADDRESS quoted_string
+		{
+			struct in_addr ip_srcaddr;
+
+			if (config.srcaddress) {
+				yyerror("config source address duplicated");
+				YYABORT;
+			}
+			if (!gethostaddr(&ip_srcaddr, $2)) {
+				YYABORT;
+			}
+			config.srcaddress = $2;
+			memcpy(&config.ip_srcaddr, &ip_srcaddr, sizeof(struct in_addr));
+		}	
 	|	TOKEN_TIMEFMT quoted_string
 		{
 			if (config.timefmt) {
@@ -1485,6 +1604,10 @@
 			}
 			config.retries = $2;
 		}
+	|	TOKEN_OMULSTATES
+		{
+			config.compatibility_flag = 0;
+		}	    
 	|	TOKEN_NETSTATE '{' netstate_config '}'
 		{
 			if (!config.ns_port) {
@@ -1531,6 +1654,17 @@
 		{
 			config.source_traps = 1;
 		}
+	|	TOKEN_TRAPBINDADDRESS quoted_string
+		{
+			if (config.trap_address) {
+				yyerror("bindaddress duplicated");
+				YYABORT;
+			}
+    			if (!gethostaddr(&config.trap_ip_addr, $2)) {
+				YYABORT;
+			}
+			config.trap_address = $2;
+		}
 	|	TOKEN_TRAP legal_string '{' trap_config '}'
 		{
 			trap.name = $2;
@@ -1556,6 +1690,13 @@
 				yyerror("object address unspecified");
 				YYABORT;
 			}
+			if (!object.srcaddress) {
+				if (!config.srcaddress) {
+    				    bzero(&object.ip_srcaddr, sizeof(struct in_addr));
+				} else {
+				    memcpy(&object.ip_srcaddr, &config.ip_srcaddr, sizeof(struct in_addr));
+				}
+			}
 /*			if ((object.interface || object.ifgroup ||
 			     object.bgp || object.env) &&
 			    !find_method(object.method_list, "ROUTER")) {
@@ -1637,6 +1778,17 @@
 				YYABORT;
 			}
 		}
+	|	TOKEN_BINDADDRESS quoted_string
+		{
+			if (config.ns_address) {
+				yyerror("bindaddress duplicated");
+				YYABORT;
+			}
+			if (!gethostaddr(&config.ns_ip_addr, $2)) {
+				YYABORT;
+			}
+			config.ns_address = $2;
+		}
 	|	TOKEN_PERMIT quoted_string
 		{
 			/* for backward compatibility */
@@ -1701,7 +1853,7 @@
 			}
 			save.state = $2;
 		}
-	|	TOKEN_WHEN multiline_string TOKEN_NUMBER optional_string
+	|	TOKEN_WHEN multiline_string TOKEN_NUMBER optional_multiline_string
 		{
 			if (save.when) {
 				yyerror("save when condition duplicated");
@@ -1763,6 +1915,19 @@
 			method.start = echo_start;
 			method.stop = echo_stop;
 		}
+	|	TOKEN_PIPE quoted_string
+		{
+			if (method.protocol) {
+				yyerror("method protocol duplicated");
+				YYABORT;
+			}
+			method.protocol = PIPE_PROTO;
+			method.when = $2;
+			method.init = pipe_init;
+			method.start = pipe_start;
+			method.stop = tcp_stop;
+			method.retries = 1;		
+		}
 	|	TOKEN_PORT TOKEN_NUMBER
 		{
 			if (method.protocol &&
@@ -1808,12 +1973,30 @@
 				}
 			}
 		}
+	|	TOKEN_WHEN multiline_string TOKEN_NUMBER  optional_multiline_string
+		{
+			method.protocol = WHEN_PROTO;
+			if (method.when) {
+				yyerror("Method 'when condition' duplicated");
+				YYABORT;
+			}
+			method.init = when_init;
+			method.start = when_start;
+			method.stop = when_stop;
+			method.when = $2;
+			method.timeout = $3;
+			method.when_fmt = $4;
+		}
 	|	TOKEN_TIMEOUT TOKEN_NUMBER
 		{
 			if (method.timeout) {
 				yyerror("timeout statement duplicated");
 				YYABORT;
 			}
+			if (method.protocol == WHEN_PROTO) {
+				yyerror("timeout was defined in WHEN statement");
+				YYABORT;			
+			}
 			if ($2 < 1 || $2 > POLLING_MIN) {
 				yyerror("invalid timeout value (min 1 max %d sec.)",
 					POLLING_MIN);
@@ -1827,6 +2010,10 @@
 				yyerror("retries statement duplicated");
 				YYABORT;
 			}
+			if (method.protocol == PIPE_PROTO) {
+				yyerror("no retries possible in PIPE method");
+				YYABORT;			
+			}
 			if ($2 < 1 || $2 > POLLING_MIN) {
 				yyerror("invalid retries number (min 1 max %d)",
 					POLLING_MIN);
@@ -1838,7 +2025,8 @@
 		{
 			if (method.protocol &&
 			    method.protocol != IPPROTO_TCP &&
-			    method.protocol != IPPROTO_UDP) {
+			    method.protocol != IPPROTO_UDP &&
+			    method.protocol != PIPE_PROTO) {
 				yyerror("no suitable method protocol");
 				YYABORT;
 			}
@@ -2095,6 +2283,18 @@
 			}
 			object.address = $2;
 		}
+	|	TOKEN_SRCADDRESS quoted_string
+		{
+			if (object.srcaddress) {
+				yyerror("object source address duplicated");
+				YYABORT;
+			}
+			if (!gethostaddr(&object.ip_srcaddr, $2)) {
+				YYABORT;
+			}
+			object.srcaddress = $2;
+		}
+		
 	|	TOKEN_POLLING TOKEN_NUMBER
 		{
 			if (object.polling) {
@@ -2241,7 +2441,7 @@
 		}
 	|	TOKEN_INTERFACE TOKEN_NUMBER
 		{
-			if ($2 < 1 || $2 > 65535) {
+			if ($2 < 1 || $2 > INT_MAX) {
 				yyerror("interface index out of range");
 				YYABORT;
 			}
@@ -2252,7 +2452,7 @@
 		}
 	|	TOKEN_INTERFACE TOKEN_NUMBER '{' interface_config '}'
 		{
-			if ($2 < 1 || $2 > 65535) {
+			if ($2 < 1 || $2 > INT_MAX ) {
 				yyerror("interface index out of range");
 				YYABORT;
 			}
@@ -2473,6 +2673,10 @@
 				YYABORT;
 			}
 		}
+	|	TOKEN_IGNORESTATE
+		{
+			subobject.ignore_state = 1;
+		}
 	;
 
 interface_config:	/* empty */
@@ -2530,6 +2734,10 @@
 				YYABORT;
 			}
 		}
+	|	TOKEN_IGNORESTATE
+		{
+			interface.ignore_state = 1;
+		}
 	;
 
 bgp_config:	/* empty */
@@ -2580,6 +2788,10 @@
 			}
 			free($2);
 		}
+	|	TOKEN_IGNORESTATE
+		{
+			bgp_as.ignore_state = 1;
+		}
 	;
 
 env_config:	/* empty */
@@ -2629,6 +2841,10 @@
 				YYABORT;
 			}
 		}
+	|	TOKEN_IGNORESTATE
+		{
+			env_mon.ignore_state = 1;
+		}
 	;
 
 get_save:	legal_string optional_string
@@ -2918,6 +3134,12 @@
 			$$ = NULL;
 		}
 	|	quoted_string
+	;
+optional_multiline_string:
+		{
+			$$ = NULL;
+		}
+	|	multiline_string
 	;
 
 %%
--- ping.c.orig	Fri Aug 22 11:07:53 2003
+++ ping.c	Thu Dec 28 13:31:06 2006
@@ -352,7 +352,8 @@
 	dprintf(("check_netpath(%s)\n", target->name));
 
 	for (nexthop = target->nexthop; nexthop; nexthop = nexthop->next) {
-		if ((nexthop->target && nexthop->target->state != STATE_UP) ||
+		if ((nexthop->target && nexthop->target->state == STATE_UNKNOWN) ||
+		    (nexthop->target && nexthop->target->state == STATE_DOWN) ||
 		    (nexthop->interface && nexthop->interface->state != STATE_UP))
 			return 0;
 	}
@@ -368,6 +369,7 @@
 	u_char buf[MAX_PACKETSZ];
 	struct ip *ip;
 	struct icmp *icmp;
+	struct sockaddr_in *from = (struct sockaddr_in *)&sd->me;
 	struct sockaddr_in *to = (struct sockaddr_in *)&sd->peer;
 	int header_len = sizeof(struct ip);
 	int total_len = method->rport ? method->rport : MIN_PACKETSZ;
@@ -400,7 +402,7 @@
 #endif
 	ip->ip_ttl = IPDEFTTL;
 	ip->ip_p = IPPROTO_ICMP;
-	/* ip->ip_src <-- filled by kernel (hopefulness) */
+	ip->ip_src = from->sin_addr; /* replaced by kernel if=INADDR_ANY (hopefulness) */
 	ip->ip_dst = to->sin_addr;
 
 	if (rr_opt) { /* IP Option: Record Route */
@@ -423,6 +425,7 @@
 	memcpy(icmp->icmp_data, &sd->buf, sizeof(TIMEVAL *));
 
 	icmp->icmp_cksum = in_cksum((u_short *)icmp, total_len - header_len);
+
 #ifdef	NO_ICMP_ERRORS
 	total_len = send(sd->sock, (char *)buf, total_len, 0);
 #else
@@ -600,6 +603,8 @@
 {
 	SESSION *sd = method->sd;
 	int tmpval;
+	char	ipaddr[20];
+	struct	sockaddr_in	*from;
 
 	/* sanity check */
 	if (!sd) return;
@@ -616,6 +621,13 @@
 		echo_reply(errno, sd, 0);
 		return;
 	}
+	/* bind RAW socket to local source address */
+	from = (struct sockaddr_in *)&sd->me;
+	if ( from->sin_addr.s_addr != INADDR_ANY ) {		
+	    if( bind(sd->sock, &sd->me, sizeof(struct sockaddr) ) == -1 ) 
+		report(LOG_WARNING, "echo_start : bind failed for %s: %s",
+		    	intoa(ipaddr,from->sin_addr), strerror(*(__error())) );
+	}
 #ifdef	SO_BSDCOMPAT
 	/* The following option is only necessary on Linux machines because
 	 * they have the unusual behavior of returning some ICMP errors to
@@ -701,7 +713,12 @@
 				if (sd->pkt_recv > 1) msec /= (double)sd->pkt_recv;
 				sprintf(buf, "%g", msec);
 				diag = buf;
-			} else	diag = "0.000";
+			    if ( msec >= 10 ) {
+				sprintf(buf, "%d", (int)msec);
+			    } else {
+				sprintf(buf, "%g", msec);
+			    }
+			} else	diag = "0.0";
 		} else {
 			op = -1;
 			diag = icmp_error(sd->data_int);
@@ -740,8 +757,9 @@
 	METHOD *method;
 {
 	SESSION template;
-	struct sockaddr_in *to;
+	struct sockaddr_in *to, *from;
 	char varname[100];
+	char ipaddr[20];
 
 	dprintf(("echo_init(%s/%s)\n", target->name, method->name));
 
@@ -758,6 +776,9 @@
 	to = (struct sockaddr_in *)&template.peer;
 	to->sin_family = AF_INET;
 	to->sin_addr = method->address ? method->ip_addr : target->ip_addr;
+	from = (struct sockaddr_in *)&template.me;
+	from->sin_family = AF_INET;
+	from->sin_addr = target->ip_srcaddr;
 	template.timeout = method->timeout * 1000000L; /* make microseconds */
 	template.retries = method->retries;
 	template.send = echo_send;
@@ -798,6 +819,7 @@
 	IPPROTO_ICMP,	/* network protocol */
 	0,		/* no packet size for built-in method */
 	0, 0,		/* timeout and retries undefined yet */
+	NULL,NULL,	/* when variables unused */
 	{ 1, 1 },	/* send/expect packet counter */
 
 	/* Non-initialized data */
--- /dev/null	2014-03-07 15:59:00.000000000 +0200
+++ pipe.c	2014-01-24 02:14:07.000000000 +0200
@@ -0,0 +1,273 @@
+/*
+ *	Copyright (c) 1999-2002 Rinet Corp., Novosibirsk, Russia
+ *      partial (c) vfom@narod.ru 
+ *
+ * Redistribution and use in source forms, with and without modification,
+ * are permitted provided that this entire comment appears intact.
+ *
+ * THIS SOURCE CODE IS PROVIDED ``AS IS'' WITHOUT ANY WARRANTIES OF ANY KIND.
+ */
+
+#ifdef	HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <errno.h>
+#ifdef	HAVE_DMALLOC_H
+#include <dmalloc.h>
+#else
+#include "malloc.h"
+#endif
+#include "assert.h"
+
+#include "netmon.h"
+#include "regex.h"
+
+extern int errno;
+extern CONFIG *cf;                     /* current configuration */
+
+static int pipe_execfile __P ((char *, char *,pid_t *, OBJECT *));
+
+void
+pipe_start(method)
+	METHOD *method;
+{
+	SESSION *sd = method->sd;
+	OBJECT *target = sd->owner;
+	int tmpval;
+
+	/* sanity check */
+	if (!sd) return;
+
+	tcp_stop(method); /* stop the method if still running */
+	if ((method->sd)->pid > 0) { kill((method->sd)->pid, SIGTERM); }
+	sd->pid = -1;
+
+	/* open stream socket near before TCP session */
+	if ((sd->sock = pipe_execfile(method->when, method->argument, &(sd->pid), target)) < 0) {
+		tcp_close(errno, sd, 0);
+		return;
+	}
+
+	/* turn on non-blocking I/O before connecting */
+	if (set_socket_async(sd->sock, TRUE) < 0) {
+		tcp_close(errno, sd, 0);
+		if ((method->sd)->pid > 0) { kill((method->sd)->pid, SIGTERM); }
+		return;
+	}
+
+	/* timeout and retries for connection */
+	sd->timeout = method->timeout * 1000000L; /* make miscroseconds */
+	sd->retries = method->retries;
+	sd->connect = tcp_connect;	/* `awaiting' connection */
+	
+	if ((tmpval = session_start(sd, NULL)) != 0) {
+		dprintf(("pipe_start(%s/%s): reqid=%d\n",
+			 sd->owner->name, method->name, tmpval));
+//report(LOG_INFO, "pipe_start(%s/%s): reqid=%d\n",
+//			 sd->owner->name, method->name, tmpval);
+	}
+}
+
+int
+pipe_init(target, method)
+	OBJECT *target;
+	METHOD *method;
+{
+	SESSION template;
+
+	dprintf(("pipe_init(%s/%s)\n", target->name, method->name));
+//	report(LOG_INFO,"pipe_init(%s/%s)\n", target->name, method->name);
+
+	if (method->sd)
+		session_free(method->sd);
+
+	memset(&template, 0, sizeof(template));
+	template.owner = target;
+	template.method = method;
+	template.sock = -1;	/* not yet opened */
+	template.pid = -1;	
+	template.timeout = method->timeout * 1000000L; /* make microseconds */
+	template.retries = method->retries;
+	template.connect = tcp_connect;
+	template.send = tcp_send;
+	template.recv = tcp_recv;
+	template.read = tcp_close;
+
+	if ((method->sd = session_create(&template)) == NULL) {
+		errno = ENOMEM;
+		return -1;
+	}
+
+	return 0;
+}
+
+#define	MAX_ARGS	50
+int
+pipe_execfile(file, args, p_pid, target)
+	char *file, *args;
+	pid_t *p_pid;
+	OBJECT *target;
+{
+	sigset_t sigmask;
+	int ac = 0, fildes[2];
+	char *av[MAX_ARGS+2];
+	extern char **environ;
+	pid_t	pid;
+
+	dprintf(("pipe_execfile: %s %s\n", file, args ? args : "null"));
+//	report(LOG_INFO,"pipe_execfile: %s %s\n", file, args ? args : "null");
+
+	if (socketpair(PF_LOCAL, SOCK_STREAM, 0, fildes) < 0) {
+		report(LOG_ERR, "socketpair: %m");
+		return(-1);
+	}
+
+	if (*file != '/') {
+		av[ac++] = "sh";
+		av[ac++] = "-c";
+		av[ac++] = file;
+#ifdef	_PATH_BSHELL
+		file = _PATH_BSHELL;
+#else
+		file = "/bin/sh";
+#endif
+	} else	av[ac++] = strippath(file);
+
+	ac += make_argv(args, (char ***) &av[ac], MAX_ARGS);
+	av[ac] = NULL;
+
+	switch (pid=vfork()) {
+	case -1:
+		report(LOG_ERR, "fork: %m");
+		close(fildes[0]);
+		close(fildes[1]);
+		return(-1);
+	case 0:		/* child */
+		if (fcntl(fildes[0], F_SETFD, 0) < 0) {
+    		    report(LOG_ERR," fcntl (F_SETFD, 0): %m");
+	    	    _exit(127);
+		}
+		if (fildes[0] != 0) {
+			dup2(fildes[0], 0);
+			close(fildes[0]);
+		}
+		dup2(0, 1);
+		dup2(0, 2);
+
+		/* child would be terminated by signals */
+		sigprocmask(SIG_SETMASK, NULL, &sigmask);
+		sigprocmask(SIG_UNBLOCK, &sigmask, NULL);
+		close(netstate_sock);
+
+		/* make session leader to be able killpg() latter */
+		setsid();
+
+		if ( cf->chrootdir) {
+		    if ( chroot( cf->chrootdir ) < 0 ) {
+			report(LOG_ERR, "chroot %s: %s", cf->chrootdir,strerror(*(__error())) );
+			_exit(127);
+		    }
+		}
+		if ( setgid(cf->gid) < 0 ) {
+		    report(LOG_ERR, "setgid %s[%d]: %s", cf->groupname, cf->gid, strerror(*(__error())) );
+		    _exit(127);
+		}			
+		if ( (cf->uid != 0) & (setuid(cf->uid) < 0) ) {
+		    report(LOG_ERR, "setuid %s[%d]: %s", cf->username, cf->uid, strerror(*(__error())) );
+		    _exit(127);
+		}		
+		
+    		setenv ("OBJECT_NAME",target->name,1 );
+    		setenv ("OBJECT_ADDRESS",target->address,1 );
+		if (target->srcaddress) 
+		    setenv ("OBJECT_SRC_ADDRESS",target->srcaddress,1 );
+		if (target->datadir) 
+		    setenv ("OBJECT_DATADIR",target->datadir,1 );
+		execve(file, av, environ);
+		report(LOG_ERR, "execve %s: %m", file);
+		_exit(127);
+	}
+	/* parent */
+	if ( p_pid != NULL ) { *p_pid = pid; };
+	close(fildes[0]);
+	return(fildes[1]);
+}
+
+void
+when_stop(method)
+	METHOD *method;
+{
+//	session_stop(method->sd, 1);
+}
+
+void
+when_start(method)
+	METHOD *method;
+{
+	SESSION *sd = method->sd;
+	OBJECT *target = sd->owner;
+	TIMEVAL tv_now;
+	
+	char *diag, buf[4096];
+	int tmpval, matched;
+
+	/* sanity check */
+	if (!sd) return;
+	
+	sd->sock=-1;
+
+	/* calculate condition */
+	insert_variables(buf, sizeof(buf), method->when, TYPE_OBJECT, target);
+	matched = (calculate(buf) ? 1 : 0);
+//	report(LOG_WARNING, "when_start EVAL: '%s' %d %s %d",buf,matched,target->name,sd->tv_sum.tv_sec);
+	diag = "OK" ;
+	if ( matched ) {
+	    gettimeofday(&tv_now,NULL);
+	    if ( (u_int64_t)sd->tv_sum.tv_sec != 0 ) {
+		if ( ( (u_int64_t)(tv_now.tv_sec) - (u_int64_t)(sd->tv_sum.tv_sec) ) > method->timeout ) {
+		    insert_variables(buf, sizeof(buf), method->when_fmt, TYPE_OBJECT, target);
+		    diag = buf;		
+		}	    	    
+	    } else {
+		sd->tv_sum.tv_sec = tv_now.tv_sec;
+		matched = 0;
+	    }
+	} else {
+	    sd->tv_sum.tv_sec=0;
+	}
+//	report(LOG_WARNING, "when_start DIAG: '%s' %d %d",diag,matched,sd->tv_sum.tv_sec);
+
+	dump_var_list(target->var_list);
+	method_finished(target, method, diag, !matched);
+}
+
+int
+when_init(target, method)
+	OBJECT *target;
+	METHOD *method;
+{
+	SESSION template;
+	dprintf(("when_init(%s/%s)\n", target->name, method->name));
+
+	if (method->sd)
+		session_free(method->sd);
+
+	memset(&template, 0, sizeof(template));
+	template.owner = target;
+	template.method = method;
+	template.sock = -1; /* never used socket */
+	if ((method->sd = session_create(&template)) == NULL) {
+		errno = ENOMEM;
+		return -1;
+	}
+	return 0;
+}
--- radius.c.orig	Mon Aug 25 18:20:03 2003
+++ radius.c	Mon Nov 13 16:58:49 2006
@@ -33,7 +33,7 @@
  * RADIUS specification according to RFC2138.
  */
 
-#define	RADIUSSERVER_PORT	1645	/* 1812 suggested */
+#define	RADIUSSERVER_PORT	1812	/* 1812 suggested */
 #define	HEADER_LEN		20
 #define	MIN_PACKETSZ		HEADER_LEN
 #define	MAX_PACKETSZ		4096
@@ -208,6 +208,8 @@
 {
 	SESSION *sd = method->sd;
 	int reqid;
+	struct sockaddr_in *from;
+	char ipaddr[20];
 
 	/* sanity check */
 	if (!sd) return;
@@ -220,6 +222,13 @@
 		return;
 	}
 
+	/* bind  socket to local source address */
+	from = (struct sockaddr_in *)&sd->me;
+	if ( from->sin_addr.s_addr != INADDR_ANY ) {		
+	    if( bind(sd->sock, &sd->me, sizeof(struct sockaddr) ) == -1 ) 
+		report(LOG_WARNING, "radius_start : bind failed for %s: %s",
+		    intoa(ipaddr,from->sin_addr), strerror(*(__error())) );
+	}	
 	/* turn on non-blocking I/O */
 	if (set_socket_async(sd->sock, TRUE) < 0) {
 		radius_reply(errno, sd, 0);
@@ -311,7 +320,7 @@
 	METHOD *method;
 {
 	SESSION template;
-	struct sockaddr_in *to;
+	struct sockaddr_in *to, *from;
 
 	dprintf(("radius_init(%s/%s)\n", target->name, method->name));
 
@@ -326,6 +335,10 @@
 	to->sin_family = AF_INET;
 	to->sin_port = htons(method->rport);
 	to->sin_addr = method->address ? method->ip_addr : target->ip_addr;
+	from = (struct sockaddr_in *)&template.me;
+	bzero((char *)from, sizeof(struct sockaddr_in));
+	from->sin_family = AF_INET;
+	from->sin_addr = target->ip_srcaddr;
 	template.timeout = method->timeout * 1000000L; /* make microseconds */
 	template.retries = method->retries;
 	template.send = radius_send;
@@ -355,6 +368,7 @@
 	IPPROTO_UDP,	/* network protocol */
 	RADIUSSERVER_PORT, /* server port */
 	0, 0,		/* timeout and retries undefined yet */
+        NULL,NULL,       /* when variables unused */
 	{ 0, 0 },	/* no parameters used */
 
 	/* Non-initialized data */
--- reconfig.c.orig	Tue Aug 26 10:54:37 2003
+++ reconfig.c	Thu Dec 28 13:31:06 2006
@@ -175,6 +175,7 @@
 
 	rescan = (old->bandwidth != new->bandwidth); /* to force rescan */
 	old->bandwidth = new->bandwidth;
+	old->ignore_state = new->ignore_state;
 
 	splice_var_list(&old->var_list, &new->var_list);
 
@@ -260,6 +261,7 @@
 
 	/* setup new list of peers */
 	old->handconf = new->handconf;
+	old->ignore_state = new->ignore_state;
 	free_bgp_peers(old, 1);
 	old->peer = new->peer;
 	new->peer = NULL;
@@ -340,6 +342,7 @@
 
 	/* setup new list of peers */
 	old->handconf = new->handconf;
+	old->ignore_state = new->ignore_state;
 	free_env_gauges(old, 1);
 	old->gauge = new->gauge;
 	new->gauge = NULL;
@@ -395,7 +398,7 @@
 	OBJECT *parent;
 	OBJECT *old, *new;
 {
-	void *ip_addr;
+	void *ip_addr, *ip_srcaddr;
 	OBJECT *service;
 
 	object_stop(old);
@@ -403,9 +406,13 @@
 	ptrswap(&old->descr, &new->descr);
 	ptrswap(&old->datadir, &new->datadir);
 	ptrswap(&old->address, &new->address);
-	if (parent)
+	if (parent) {
 		ip_addr = &parent->ip_addr;
-	else	ip_addr = &new->ip_addr;
+		ip_srcaddr = &parent->ip_srcaddr;
+	} else {	
+	    ip_addr = &new->ip_addr;
+	    ip_srcaddr = &new->ip_srcaddr;
+	}
 	old->parent = parent;
 
 	if (memcmp(&old->ip_addr, ip_addr, sizeof(old->ip_addr))) {
@@ -418,6 +425,8 @@
 			memset(old->snmpdata, 0, sizeof(SNMP_DATA));
 		}
 	}
+	if (memcmp(&old->ip_srcaddr, ip_srcaddr, sizeof(old->ip_srcaddr))) 
+		memcpy(&old->ip_srcaddr, ip_srcaddr, sizeof(old->ip_srcaddr));
 
 	old->polling = new->polling;
 	old->saving = new->saving;
@@ -450,6 +459,8 @@
 	service = splice_object_list(old, &old->service, &new->service);
 	for (; service; service = service->next) {
 		service->ip_addr = old->ip_addr;
+		service->ip_srcaddr = old->ip_srcaddr;
+		service->ignore_state = old->ignore_state;
 		service->parent = old;
 		object_init(service);
 	}
@@ -516,21 +527,42 @@
 	}
 	if (cf_new->rootdir) free(cf_new->rootdir);
 
+	ptrswap(&cf->chrootdir, &cf_new->chrootdir);
+	if (cf_new->chrootdir) free(cf_new->chrootdir);
+
+	ptrswap(&cf->username, &cf_new->username);
+	if (cf_new->username) free(cf_new->username);
+	cf->uid = cf_new->uid;
+
+	ptrswap(&cf->groupname, &cf_new->groupname);
+	if (cf_new->groupname) free(cf_new->groupname);
+	cf->gid = cf_new->gid;
+
 	ptrswap(&cf->timefmt, &cf_new->timefmt);
 	if (cf_new->timefmt) free(cf_new->timefmt);
 
+	ptrswap(&cf->srcaddress, &cf_new->srcaddress);
+	if (cf_new->srcaddress) free(cf_new->srcaddress);
+	memcpy( &cf->ip_srcaddr, &cf_new->ip_srcaddr, sizeof(struct in_addr));
 	cf->polling = cf_new->polling;
 	cf->saving = cf_new->saving;
 	cf->timeout = cf_new->timeout;
 	cf->retries = cf_new->retries;
+	compatibility_flag = cf->compatibility_flag = cf_new->compatibility_flag;
 
-	if (cf->enable_traps != cf_new->enable_traps) {
+	if ((cf->enable_traps != cf_new->enable_traps) || memcmp(&cf->trap_ip_addr, &cf_new->trap_ip_addr, sizeof(struct in_addr)) ) {
+		ptrswap(&cf->trap_address, &cf_new->trap_address);
+		if (cf_new->trap_address) free(cf_new->trap_address);
+		memcpy( &cf->trap_ip_addr, &cf_new->trap_ip_addr, sizeof(struct in_addr));
 		cf->enable_traps = cf_new->enable_traps;
 		trap_init(cf->enable_traps > 0);
 	}
 	cf->source_traps = cf_new->source_traps;
 
-	if (cf->ns_port != cf_new->ns_port) {
+	if ((cf->ns_port != cf_new->ns_port) || memcmp(&cf->ns_ip_addr, &cf_new->ns_ip_addr, sizeof(struct in_addr))) {
+		ptrswap(&cf->ns_address, &cf_new->ns_address);
+		if (cf_new->ns_address) free(cf_new->ns_address);
+		memcpy( &cf->ns_ip_addr, &cf_new->ns_ip_addr, sizeof(struct in_addr));
 		cf->ns_port = cf_new->ns_port;
 		netstate_init(cf->ns_port);
 	}
@@ -576,6 +608,12 @@
 	free_object_list(cf_cur->target);
 
 	if (cf_cur->rootdir) free(cf_cur->rootdir);
+	if (cf_cur->chrootdir) free(cf_cur->chrootdir);
+	if (cf_cur->username) free(cf_cur->username);
+	if (cf_cur->groupname) free(cf_cur->groupname);
+	if (cf_cur->srcaddress) free(cf_cur->srcaddress);
+	if (cf_cur->ns_address) free(cf_cur->ns_address);
+	if (cf_cur->trap_address) free(cf_cur->trap_address);
 	if (cf_cur->timefmt) free(cf_cur->timefmt);
 
 	trap_init(cf_cur->enable_traps > 0);
@@ -649,6 +687,7 @@
 		if (obj->descr) free(obj->descr);
 		if (obj->datadir) free(obj->datadir);
 		if (obj->address) free(obj->address);
+		if (obj->srcaddress) free(obj->srcaddress);
 		free_trap_list(obj->trap_list);
 		free_var_list(obj->var_list);
 		free_save_list(obj->save_list);
--- regex.c.orig	Mon Feb 24 14:52:12 2003
+++ regex.c	Thu Nov  2 13:35:27 2006
@@ -554,12 +554,12 @@
  * the bitset form, since we may wish to extend it
  * in the future for other character classifications. 
  *
- *	TRUE for 0-9 A-Z a-z _
+ *	TRUE for 0-9 A-Z a-z _ а-я А-Я
  */
 static char chrtyp[MAXCHR] = {
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  
 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 
@@ -569,10 +569,23 @@
 	1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 0, 0, 0, 0, 0
+	1, 1, 1, 0, 0, 0, 0, 0, 0, 0,	// 120-129
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,   // 130-139
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,   // 140-149
+	0, 0, 0, 1, 0, 0, 0, 0, 0, 0,   // 160-169     163=ё
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 1,   // 170-179     179=Ё
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,   // 180-189
+	0, 0, 1, 1, 1, 1, 1, 1, 1, 1,   // 190-199
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1,   // 200-209
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1,   // 210-219
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1,   // 220-229
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1,   // 230-239
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1,   // 240-249
+	1, 1, 1, 1, 1, 1                // 250-255
 	};
 
-#define inascii(x)	(0177&(x))
+//#define inascii(x)	(0177&(x))
+#define inascii(x)	(0255&(x))
 #define iswordc(x) 	chrtyp[inascii(x)]
 #define isinset(x, y) 	((x)[((y)&BLKIND)>>3] & (1<<((y)&BITIND)))
 
@@ -583,7 +596,7 @@
 
 #define ANYSKIP	2 	/* CLO ANY END ...	   */
 #define CHRSKIP	3	/* CLO CHR chr END ...	   */
-#define CCLSKIP 18	/* CLO CCL 16bytes END ... */
+#define CCLSKIP BITBLK+2       /* CLO CCL 32bytes END ... */
 
 static char *
 pmatch(prog, lp, ap)
--- regex.h.orig	Mon Feb 24 14:39:49 2003
+++ regex.h	Thu Nov  2 13:38:39 2006
@@ -21,12 +21,12 @@
  */
 #define MAXDFA  1024
 #define MAXTAG  10
-#define MAXCHR	128
+#define MAXCHR	256
 #define CHRBIT	8
 #define BITBLK	MAXCHR/CHRBIT
 #define BLKIND	0170
 #define BITIND	07
-#define ASCIIB	0177
+#define ASCIIB	0255
 
 typedef /*unsigned*/ char CHAR;
 
--- router.c.orig	Mon Aug 25 16:07:07 2003
+++ router.c	Thu Dec 28 13:31:06 2006
@@ -309,6 +309,7 @@
 	for (group_ref = proto->ns_acl; group_ref; group_ref = group_ref->next)
 		add_group_ref_copy(&iface->ns_acl, group_ref);
 
+	iface->ignore_state = proto->ignore_state;
         if (last)
                 last->next = iface;
         else    object->interface = iface;
@@ -2214,6 +2215,8 @@
 	METHOD *method;
 {
 	SESSION *sd = method->sd;
+	struct sockaddr_in *from;
+	char ipaddr[20];
 
 	/* sanity check */
 	if (!sd) {
@@ -2229,7 +2232,13 @@
 		router_reply(errno, sd, 0);
 		return;
 	}
-
+	/* bind socket to local source address */
+	from = (struct sockaddr_in *)&sd->me;
+	if ( from->sin_addr.s_addr != INADDR_ANY ) {		
+	    if( bind(sd->sock, &sd->me, sizeof(struct sockaddr) ) == -1 ) 
+		report(LOG_WARNING, "router_start : bind failed for %s: %s",
+		    	intoa(ipaddr,from->sin_addr), strerror(*(__error())) );
+	}
 	/* turn on non-blocking I/O */
 	if (set_socket_async(sd->sock, TRUE) < 0) {
 		router_reply(errno, sd, 0);
@@ -2306,7 +2315,7 @@
 	METHOD *method;
 {
 	SESSION template;
-	struct sockaddr_in *to;
+	struct sockaddr_in *to, *from;
 
 	dprintf(("router_init(%s/%s)\n", target->name, method->name));
 
@@ -2321,6 +2330,10 @@
 	to->sin_family = AF_INET;
 	to->sin_port = htons(method->rport);
 	to->sin_addr = method->address ? method->ip_addr : target->ip_addr;
+	from = (struct sockaddr_in *)&template.me;
+	bzero((char *)from, sizeof (struct sockaddr_in));
+	from->sin_family = AF_INET;
+	from->sin_addr = target->ip_srcaddr;
 	template.timeout = method->timeout * 1000000L; /* make microseconds */
 	template.retries = method->retries;
 	template.send = snmp_send;
@@ -2359,6 +2372,7 @@
 	IPPROTO_UDP,	/* network protocol */
 	SNMPSERVER_PORT,/* server port */
 	0, 0,		/* timeout and retries undefined yet */
+        NULL,NULL,       /* when variables unused */
 	{ SNMP_VERSION_1, /* version number */
 	  BATCH_DEFAULT },/* batch value */
 
--- scanconf.l.orig	Thu Sep 18 09:59:48 2003
+++ scanconf.l	Thu Dec 28 13:31:06 2006
@@ -88,11 +88,15 @@
 
 /* token names */
 ROOTDIR		[Rr]oot[Dd]ir
+CHROOTDIR	[Cc]h[Rr]oot[Dd]ir
+USERNAME	[Uu]ser[Nn]ame
+GROUPNAME	[Gg]roup[Nn]ame
 TIMEFMT		[Tt]ime[Ff]mt
 POLLING		[Pp]olling
 SAVING		[Ss]aving
 TIMEOUT		[Tt]imeout
 RETRIES		[Rr]etries
+OMULSTATES	[Oo]bject[Mm]ultiple[Ss]tates
 
 GROUP		[Gg]roup
 PERMIT		[Pp]ermit
@@ -111,6 +115,8 @@
 
 OBJECT		[Oo]bject
 ADDRESS		[Aa]ddress
+SRCADDRESS	[Ss]rc[Aa]ddress
+BINDADDRESS	[Bb]ind[Aa]ddress
 DESCRIPTION	[Dd]escription|[Cc]omment
 SERVICE		[Ss]ervice
 INTERFACE	[Ii]nterface
@@ -144,11 +150,13 @@
 V2		[Vv]2
 
 TRAP		[Tt]rap
+TRAPBINDADDRESS	[Tt]rap[Bb]ind[Aa]ddress
 SOURCECHECK	[Ss]ource[Cc]heck
 COMMUNITY	[Cc]ommunity
 ENTERPRISE	[Ee]nterprise
 SPECIFIC	[Ss]pecific
 GENERIC		GENERIC|[Gg]eneric
+IGNORESTATE     [Ii]gnore[Ss]tate
 
 LETTER		[a-zA-Z]
 DIGIT		[0-9]
@@ -186,6 +194,12 @@
 
 {ROOTDIR}	{	return TOKEN_ROOTDIR;	}
 
+{USERNAME}	{	return TOKEN_USERNAME;	}
+
+{GROUPNAME}	{	return TOKEN_GROUPNAME;	}
+
+{CHROOTDIR}	{	return TOKEN_CHROOTDIR;	}
+
 {TIMEFMT}	{	return TOKEN_TIMEFMT;	}
 
 {POLLING}	{	return TOKEN_POLLING;	}
@@ -196,6 +210,8 @@
 
 {RETRIES}	{	return TOKEN_RETRIES;	}
 
+{OMULSTATES}	{	return TOKEN_OMULSTATES; }
+
 {GROUP}		{	return TOKEN_GROUP;	}
 
 {PERMIT}	{	return TOKEN_PERMIT;	}
@@ -224,6 +240,10 @@
 
 {ADDRESS}	{	return TOKEN_ADDRESS;	}
 
+{SRCADDRESS}	{	return TOKEN_SRCADDRESS; }
+
+{BINDADDRESS}	{	return TOKEN_BINDADDRESS; }
+
 {DESCRIPTION}	{	return TOKEN_DESCRIPTION; }
 
 {SERVICE}	{	return TOKEN_SERVICE;	}
@@ -286,6 +306,8 @@
 
 {TRAP}		{	return TOKEN_TRAP;	}
 
+{TRAPBINDADDRESS}	{	return TOKEN_TRAPBINDADDRESS;	}
+
 {SOURCECHECK}	{	return TOKEN_SOURCECHECK; }
 
 {COMMUNITY}	{	return TOKEN_COMMUNITY;	}
@@ -295,6 +317,8 @@
 {SPECIFIC}	{	return TOKEN_SPECIFIC;	}
 
 {GENERIC}	{	return TRAP_GENERIC;	}
+
+{IGNORESTATE}	{	return TOKEN_IGNORESTATE; }
 
 \${LETTER}({LETTER}|{DIGIT}|_)+(\.{DIGIT}+)*	{
 			yylval.string = &yytext[1];
--- session.c.orig	Sat Aug  2 11:26:38 2003
+++ session.c	Thu Nov  2 13:35:27 2006
@@ -59,6 +59,7 @@
 	curr_session->method = template->method;
 	curr_session->sock = template->sock;
 	curr_session->peer = template->peer;
+	curr_session->me = template->me;
 	curr_session->timeout = template->timeout;
 	curr_session->retries = template->retries;
 	curr_session->connect = template->connect;
@@ -302,7 +303,6 @@
 	int active = 0, pending = 0;
 
 	timerclear(&earliest);
-
 	/*
 	 * For each request outstanding, add it's socket to the readfds,
 	 * and if it is the earliest timeout to expire, mark it as lowest.
@@ -352,7 +352,6 @@
 	int reqid;
 {
 	REQUEST *sr;
-
 	if (reqid == 0) /* for single request per session (like tcp or icmp) */
 		return sd->request;
 
@@ -443,7 +442,6 @@
 	int reqid;
 
 	gettimeofday(&now, NULL);
-
 	/*
 	 * For each request outstanding, check to see if it has expired.
 	 */
--- snmp.c.orig	Tue Jul 20 17:51:25 2004
+++ snmp.c	Thu Nov  2 13:35:27 2006
@@ -1214,6 +1214,8 @@
 {
 	SESSION *sd = method->sd;
 	int reqid;
+	struct sockaddr_in *from;
+	char ipaddr[20];
 
 	/* sanity check */
 	if (!sd) return;
@@ -1225,7 +1227,13 @@
 		snmp_reply(errno, sd, 0);
 		return;
 	}
-
+	/* bind datagram socket to local source address */
+	from = (struct sockaddr_in *)&sd->me;
+	if ( from->sin_addr.s_addr != INADDR_ANY ) {		
+	    if( bind(sd->sock, &sd->me, sizeof(struct sockaddr) ) == -1 ) 
+		report(LOG_WARNING, "snmp_start : bind failed for %s: %s",
+		    	intoa(ipaddr,from->sin_addr), strerror(*(__error())) );
+	}
 	/* turn on non-blocking I/O */
 	if (set_socket_async(sd->sock, TRUE) < 0) {
 		snmp_reply(errno, sd, 0);
@@ -1290,7 +1298,7 @@
 	METHOD *method;
 {
 	SESSION template;
-	struct sockaddr_in *to;
+	struct sockaddr_in *to, *from;
 
 	dprintf(("snmp_init(%s/%s)\n", target->name, method->name));
 
@@ -1305,6 +1313,10 @@
 	to->sin_family = AF_INET;
 	to->sin_port = htons(method->rport);
 	to->sin_addr = method->address ? method->ip_addr : target->ip_addr;
+	from = (struct sockaddr_in *)&template.me;
+	bzero((char *)from, sizeof(struct sockaddr_in ));
+	from->sin_family = AF_INET;
+	from->sin_addr = target->ip_srcaddr;
 	template.timeout = method->timeout * 1000000L; /* make microseconds */
 	template.retries = method->retries;
 	template.send = snmp_send;
@@ -1334,6 +1346,7 @@
 	IPPROTO_UDP,	/* network protocol */
 	SNMPSERVER_PORT,/* server port */
 	0, 0,		/* timeout and retries undefined yet */
+        NULL,NULL,       /* when variables unused */
 	{ SNMP_VERSION_1,/* version number */
 	  0 },		 /* no parameter used */
 
--- tacacs.c.orig	Mon Aug 25 18:20:41 2003
+++ tacacs.c	Thu Nov  2 13:35:27 2006
@@ -302,6 +302,8 @@
 {
 	SESSION *sd = method->sd;
 	int reqid;
+	struct sockaddr_in *from;
+	char ipaddr[20];
 
 	/* sanity check */
 	if (!sd) return;
@@ -314,6 +316,13 @@
 		return;
 	}
 
+	/* bind  socket to local source address */ 
+	from = (struct sockaddr_in *)&sd->me;
+	if ( from->sin_addr.s_addr != INADDR_ANY ) {		
+	    if( bind(sd->sock, &sd->me, sizeof(struct sockaddr) ) == -1 ) 
+	        report(LOG_WARNING, "tacacs_start : bind failed for %s: %s",
+		    	intoa(ipaddr,from->sin_addr), strerror(*(__error())) );
+	}	
 	/* turn on non-blocking I/O before connecting */
 	if (set_socket_async(sd->sock, TRUE) < 0) {
 		tacacs_reply(errno, sd, 0);
@@ -415,7 +424,7 @@
 	METHOD *method;
 {
 	SESSION template;
-	struct sockaddr_in *to;
+	struct sockaddr_in *to, *from;
 
 	dprintf(("tacacs_init(%s/%s)\n", target->name, method->name));
 
@@ -430,6 +439,10 @@
 	to->sin_family = AF_INET;
 	to->sin_port = htons(method->rport);
 	to->sin_addr = method->address ? method->ip_addr : target->ip_addr;
+	from = (struct sockaddr_in *)&template.me;
+	bzero((char *)from, sizeof(struct sockaddr_in));
+	from->sin_family = AF_INET;
+	from->sin_addr = target->ip_srcaddr;
 	template.timeout = method->timeout * 1000000L; /* make microseconds */
 	template.retries = method->retries;
 	template.connect = tacacs_connect;
@@ -460,6 +473,7 @@
 	IPPROTO_TCP,	/* network protocol */
 	TACACSSERVER_PORT, /* server port */
 	0, 0,		/* timeout and retries undefined yet */
+        NULL,NULL,       /* when variables unused */
 	{ 0, 0 },	/* no parameters used */
 
 	/* Non-initialized data */
--- tcp.c.orig	Wed Sep 17 12:55:52 2003
+++ tcp.c	Thu Nov  2 13:35:27 2006
@@ -16,6 +16,7 @@
 #include <netinet/in.h>
 #include <stdio.h>
 #include <string.h>
+#include <signal.h>
 #include <unistd.h>
 #include <syslog.h>
 #include <errno.h>
@@ -30,12 +31,10 @@
 
 extern int errno;
 
-static void tcp_close __P((int, SESSION *, int));
-
 /*
  * Check to see if an TCP connection established at this session.
  */
-static int
+int
 tcp_connect(sd)
 	SESSION *sd;
 {
@@ -89,7 +88,7 @@
 /*
  * Send the data through TCP session.
  */
-static int
+int
 tcp_send(sd, request)
 	SESSION *sd;
 	REQUEST *request;
@@ -191,7 +190,7 @@
 /*
  * Receive data through TCP session.
  */
-static int
+int
 tcp_recv(sd)
 	SESSION *sd;
 {
@@ -319,6 +318,8 @@
 {
 	SESSION *sd = method->sd;
 	int tmpval;
+	struct sockaddr_in *from;
+	char ipaddr[20];
 
 	/* sanity check */
 	if (!sd) return;
@@ -330,17 +331,13 @@
 		tcp_close(errno, sd, 0);
 		return;
 	}
-
+	from = (struct sockaddr_in *)&sd->me;
 	/* allocate local port if required */
 	if (method->lport_min) {
-		struct sockaddr_in sin;
-
-		sin.sin_family = AF_INET;
-		sin.sin_addr.s_addr = htonl(INADDR_ANY);
 		tmpval = method->lport_min;
 		do {
-			sin.sin_port = htons((u_short)tmpval);
-			if (!bind(sd->sock, (struct sockaddr *)&sin, sizeof(sin))) {
+			from->sin_port = htons((u_short)tmpval);
+			if (!bind(sd->sock, &sd->me, sizeof(struct sockaddr))) {
 				tmpval = 0;
 				break;
 			}
@@ -354,6 +351,13 @@
 			tcp_close(EAGAIN, sd, 0);
 			return;
 		}
+	} else {
+	    /* bind  socket to local source address */
+	    if ( from->sin_addr.s_addr != INADDR_ANY ) {		
+		if( bind(sd->sock, &sd->me, sizeof(struct sockaddr) ) == -1 ) 
+		    report(LOG_WARNING, "tcp_start : bind failed for %s: %s",
+    	        	intoa(ipaddr,from->sin_addr), strerror(*(__error())) );
+	    }	
 	}
 
 	/* turn on non-blocking I/O before connecting */
@@ -378,7 +382,7 @@
 	}
 }
 
-static void
+void
 tcp_close(op, sd, reqid)
 	int op;
 	SESSION *sd;
@@ -414,6 +418,7 @@
 	dump_var_list(target->var_list);
 
 	tcp_stop(method);
+	if ((method->sd)->pid > 0) { kill((method->sd)->pid, SIGTERM); (method->sd)->pid=-1; }
 
 	method_finished(target, method, diag, !op);
 }
@@ -424,7 +429,7 @@
 	METHOD *method;
 {
 	SESSION template;
-	struct sockaddr_in *to;
+	struct sockaddr_in *to, *from;
 
 	dprintf(("tcp_init(%s/%s)\n", target->name, method->name));
 
@@ -435,10 +440,15 @@
 	template.owner = target;
 	template.method = method;
 	template.sock = -1;	/* not yet opened */
+	template.pid = -1;	
 	to = (struct sockaddr_in *)&template.peer;
 	to->sin_family = AF_INET;
 	to->sin_port = htons(method->rport);
 	to->sin_addr = method->address ? method->ip_addr : target->ip_addr;
+	from = (struct sockaddr_in *)&template.me;
+	bzero((char *)from, sizeof(struct sockaddr_in));
+	from->sin_family = AF_INET;
+	from->sin_addr = target->ip_srcaddr;
 	template.timeout = method->timeout * 1000000L; /* make microseconds */
 	template.retries = method->retries;
 	template.connect = tcp_connect;
--- trap.c.orig	Thu Aug 21 09:45:25 2003
+++ trap.c	Thu Nov  2 13:35:27 2006
@@ -40,9 +40,10 @@
 {
 	static struct sockaddr_in sin;
 
+	if (trap_sock != -1) /* already enabled */
+		close(trap_sock);
+
 	if (enable) {
-		if (trap_sock != -1) /* already enabled */
-			return 0;
 
 		if ((trap_sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
 			report(LOG_ERR, "socket: %m");
@@ -51,17 +52,15 @@
 		memset(&sin, 0, sizeof(sin));
 		sin.sin_family = AF_INET;
 		sin.sin_port = htons(SNMPTRAP_PORT);
-		sin.sin_addr.s_addr = INADDR_ANY;
+		sin.sin_addr = cf->trap_ip_addr;
 		if (bind(trap_sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
 			report(LOG_ERR, "bind port %d: %m", ntohs(sin.sin_port));
 			close(trap_sock);
 			trap_sock = -1;
 			return -1;
 		}
-	} else if (trap_sock != -1) {
-		close(trap_sock);
+	} else
 		trap_sock = -1;
-	}
 	return 0;
 }
 
--- udp.c.orig	Sat Aug  2 11:40:56 2003
+++ udp.c	Thu Nov  2 13:35:27 2006
@@ -197,6 +197,8 @@
 {
 	SESSION *sd = method->sd;
 	int tmpval;
+	struct sockaddr_in *from;
+	char ipaddr[20];
 
 	/* sanity check */
 	if (!sd) return;
@@ -208,17 +210,13 @@
 		udp_close(errno, sd, 0);
 		return;
 	}
-
+	from = (struct sockaddr_in *)&sd->me;
 	/* allocate local port if required */
 	if (method->lport_min) {
-		struct sockaddr_in sin;
-
-		sin.sin_family = AF_INET;
-		sin.sin_addr.s_addr = htonl(INADDR_ANY);
 		tmpval = method->lport_min;
 		do {
-			sin.sin_port = htons((u_short)tmpval);
-			if (!bind(sd->sock, (struct sockaddr *)&sin, sizeof(sin))) {
+			from->sin_port = htons((u_short)tmpval);
+			if (!bind(sd->sock, &sd->me, sizeof(struct sockaddr))) {
 				tmpval = 0;
 				break;
 			}
@@ -232,6 +230,13 @@
 			udp_close(EAGAIN, sd, 0);
 			return;
 		}
+	} else {
+	    /* bind socket to local source address */
+	    if ( from->sin_addr.s_addr != INADDR_ANY ) {		
+		if( bind(sd->sock, &sd->me, sizeof(struct sockaddr) ) == -1 ) 
+		    report(LOG_WARNING, "udp_start : bind failed for %s: %s",
+		    	intoa(ipaddr,from->sin_addr), strerror(*(__error())) );
+	    }
 	}
 
 	/* turn on non-blocking I/O */
@@ -298,7 +303,7 @@
 	METHOD *method;
 {
 	SESSION template;
-	struct sockaddr_in *to;
+	struct sockaddr_in *to, *from;
 
 	dprintf(("udp_init(%s/%s)\n", target->name, method->name));
 
@@ -313,6 +318,10 @@
 	to->sin_family = AF_INET;
 	to->sin_port = htons(method->rport);
 	to->sin_addr = method->address ? method->ip_addr : target->ip_addr;
+	from = (struct sockaddr_in *)&template.me;
+	bzero((char *)from, sizeof(struct sockaddr_in));
+	from->sin_family = AF_INET;
+	from->sin_addr = target->ip_srcaddr;
 	template.timeout = method->timeout * 1000000L; /* make microseconds */
 	template.retries = method->retries;
 	template.send = udp_send;
--- util.c.orig	Tue Aug 26 10:53:17 2003
+++ util.c	Thu Dec 28 13:31:06 2006
@@ -275,6 +275,8 @@
 	if (method->address) free(method->address);
 	if (method->sd) session_free(method->sd);
 	if (method->chatscript) free_chatscript(method->chatscript);
+	if (method->when) free(method->when);
+	if (method->when_fmt) free(method->when_fmt);
 	if (method->snmpreq) {
 		free_var_ref(method->snmpreq->var_ref);
 		free(method->snmpreq);
@@ -1236,11 +1238,9 @@
 		if (method->address)
 			printf("%s\tAddress = \"%s\" [%s]\n", prepend,
 			       method->address, intoa(ipaddr, method->ip_addr));
-		if ((proto = getprotobynumber(method->protocol)) == NULL) {
-			printf("%s\tUnknown protocol %d\n", prepend, method->protocol);
-			continue;
+		if ((proto = getprotobynumber(method->protocol)) != NULL) {
+		    printf("%s\t%s ", prepend, proto->p_name);
 		}
-		printf("%s\t%s ", prepend, proto->p_name);
 		switch (method->protocol) {
 		case IPPROTO_ICMP:
 			if (method->rport)
@@ -1265,6 +1265,14 @@
 				printf("..%d", method->lport_max);
 			}
 			break;
+		case WHEN_PROTO:
+			printf("%s\tWHEN = \"%s\"",prepend, method->when);
+			printf(" delay = %d sec.", method->timeout);
+			printf(" Report Format = \"%s\"", method->when_fmt);
+			break;
+		case PIPE_PROTO:
+			printf("%s\tPIPE programm = \"%s\"",prepend, method->when);
+			break;
 		default:
 			printf("Unsupported");
 		}
@@ -1409,22 +1417,36 @@
 	if (cf->saving > 0)
 		printf("Saving = %d sec.\n", cf->saving);
 	else	printf("Saving disabled\n");
+	if (cf->compatibility_flag > 0)
+		printf("Compatibility flag SET\n");
+	else 	printf("Compatibility flag NOT SET\n");
 
 	print_group_list("", cf->group_list);
 
 	printf("NetState %s\n", cf->ns_port ? "enabled" : "disabled");
 	if (cf->ns_port) {
 		printf("\tPort = %d\n", cf->ns_port);
+		if (cf->ns_address) 
+    		    printf("\tBindAddress = \"%s\" [%s]\n", cf->ns_address, intoa(ipaddr, cf->ns_ip_addr));		
 #ifndef	HAVE_PTHREAD
 		printf("\tTimeout = %d sec.\n", cf->ns_timo);
 #endif
 		print_group_ref("\t", cf->ns_acl);
 	}
+	printf("SrcAddress = \"%s\" [%s]\n", (cf->srcaddress!=NULL ) ? cf->srcaddress : "default",
+	    intoa(ipaddr, cf->ip_srcaddr));
+
+	printf("UserName = \"%s\" [%d]\n", cf->username, cf->uid);
+	printf("GroupName = \"%s\" [%d]\n", cf->groupname, cf->gid);
 
+	if (cf->chrootdir) 
+	    printf("ChRootDir = \"%s\"\n", cf->chrootdir );
 	printf("Traps ");
 	if (cf->enable_traps > 0) {
 		printf("enabled");
 		if (cf->source_traps > 0) printf(" (sourcecheck)");
+		if (cf->trap_address) 
+		    printf("\n\tTrapBindAddress = \"%s\" [%s]", cf->trap_address, intoa(ipaddr, cf->trap_ip_addr));		
 	} else	printf("disabled");
 	printf("\n");
 
@@ -1434,6 +1456,8 @@
 			printf("\tDescription = \"%s\"\n", target->descr);
 		printf("\tAddress = \"%s\" [%s]\n", target->address,
 		       intoa(ipaddr, target->ip_addr));
+		printf("\tSrcAddress = \"%s\" [%s]\n", (target->srcaddress!=NULL) ? target->srcaddress : "default",
+		       intoa(ipaddr, target->ip_srcaddr));
 		if (target->polling > 0)
 			printf("\tPolling = %d sec.\n", target->polling);
 		else	printf("\tPolling disabled\n");
@@ -1463,6 +1487,8 @@
 			if (iface->ns_acl)
 				print_group_ref("\t\tNetState ", iface->ns_acl);
 			else	printf("\t\tNetState Group = free access\n");
+			if (iface->ignore_state)
+				printf("\t\tIgnoreState flag set.\n");			
 			print_var_list("\t\t", iface->var_list);
 			print_save_list("\t\t", iface->save_list);
 		}
@@ -1475,6 +1501,8 @@
 			if (iface->ns_acl)
 				print_group_ref("\t\tNetState ", iface->ns_acl);
 			else	printf("\t\tNetState Group = free access\n");
+			if (iface->ignore_state)
+				printf("\t\tIgnoreState flag set.\n");			
 			print_var_list("\t\t", iface->var_list);
 			print_save_list("\t\t", iface->save_list);
 		}
@@ -1495,6 +1523,8 @@
 			if (bgp->ns_acl)
 				print_group_ref("\t\tNetState ", bgp->ns_acl);
 			else	printf("\t\tNetState Group = free access\n");
+			if (bgp->ignore_state)
+				printf("\t\tIgnoreState flag set.\n");			
 			print_save_list("\t\t", bgp->save_list);
 		}
 
@@ -1514,6 +1544,8 @@
 			if (env->ns_acl)
 				print_group_ref("\t\tNetState ", env->ns_acl);
 			else	printf("\t\tNetState Group = free access\n");
+			if (env->ignore_state)
+				printf("\t\tIgnoreState flag set.\n");			
 			print_save_list("\t\t", env->save_list);
 		}
 
@@ -1524,6 +1556,8 @@
 			if (service->ns_acl)
 				print_group_ref("\t\tNetState ", service->ns_acl);
 			else	printf("\t\tNetState Group = free access\n");
+			if (service->ignore_state)
+				printf("\t\tIgnoreState flag set.\n");			
 			print_var_list("\t\t", service->var_list);
 			print_method_list("\t\t", service->method_list);
 			print_trap_list("\t\t", service->trap_list);
--- variables.c.orig	Tue Aug 26 10:55:14 2003
+++ variables.c	Thu Nov  2 13:35:27 2006
@@ -39,8 +39,8 @@
 static char buf[BUFSIZ];
 static char *strbuf = NULL;
 
-static char *obj_states[2] = {
-	"UP", "DOWN" };
+static char *obj_states[4] = {
+	"UP", "DOWN","DEGRADED","WARNING" };
 static char *if_states[5] = {
 	"UP", "DOWN", "TESTING", "UNKNOWN", "DORMANT" };
 static char *bgp_states[6] = {
@@ -52,7 +52,7 @@
 	int size;
 	char **name;
 } states[4] = {
-	{ 2, obj_states },
+	{ 4, obj_states },
 	{ 5, if_states },
 	{ 6, bgp_states },
 	{ 5, env_states },
@@ -69,7 +69,7 @@
 
 	sp = &states[what];
 	if (!state)
-		cp = "NONE";
+		cp = "UNKNOWN";
 	else if (state > 0 && state <= sp->size)
 		cp = sp->name[state-1];
 	else	cp = "ERROR";
@@ -1511,6 +1511,7 @@
 		}
 		memcpy(var, vb, len);
 		var[len] = '\0';
+		
 		len = 0;
 		next = var;
 		while ((vb = my_strsep(&next, "!")) != NULL) {
