Hi,

I just pushed the attached patch to
git://github.com/fobser/icinga-nrpe-ipv6.git

nrpe now correctly listens on :: and 0.0.0.0 if server_address is not
configured. As an added bonus you can also configure a name with A and
AAAA records and nrpe listens on both addresses. I didn't try what
happens if you have multiple A or AAAA records, but I suspect it might
just work.

I removed Mike's(?) comments as I think this is resolved now:

//             server_address = "::";
/* it's better to work on IPv6 if not set as IPv4 Addresspace is included in IPv6 but shuld be discussed if this is ok as getaddrinfo will look in IPv6 Mode after a AAAA Entry if not a IP is in allowed hosts*/

This was in the following block:

        if(!server_address || !strlen(server_address)) {
                server_address = NULL;
                addrinfo.ai_flags=AI_PASSIVE;
                }

Btw. checking for strlen(server_address) == 0 is just paranoia, with the current code you can't get a string of length 0, it's either bigger or NULL.

Best regards,
Florian
diff --git a/src/nrpe.c b/src/nrpe.c
index 137fe5b..b86fa4e 100644
--- a/src/nrpe.c
+++ b/src/nrpe.c
@@ -44,8 +44,12 @@ int use_ssl=FALSE;
 #define MAXFD                   64
 #define NASTY_METACHARS         "|`&><'\"\\[]{};"
 
-#define BUFLEN 16384
-char buf[BUFLEN];
+#define BUFLEN 			16384
+char    buf[BUFLEN];
+
+#define	MAX_LISTEN_SOCKS	16
+int     listen_socks[MAX_LISTEN_SOCKS];
+int     num_listen_socks = 0;
 
 char    *command_name=NULL;
 char    *macro_argv[MAX_COMMAND_ARGUMENTS];
@@ -707,6 +711,8 @@ void wait_for_connections(void){
 	int sock, new_sd;
 	pid_t pid;
 	int flag=1;
+	int max_fd = 0;
+	int i = 0, j = 0;
 	fd_set fdread;
 	struct timeval timeout;
 	int retval;
@@ -715,7 +721,6 @@ void wait_for_connections(void){
 #endif
 
 	int rval;
-	int success=0;
 	struct addrinfo addrinfo;
 	struct addrinfo *res, *r;
 
@@ -725,9 +730,7 @@ void wait_for_connections(void){
 	addrinfo.ai_protocol=IPPROTO_TCP;
 
 	if(!server_address || !strlen(server_address)) {
-//		server_address = "::"; 
 		server_address = NULL;
-/* it's better to work on IPv6 if not set as IPv4 Addresspace is included in IPv6  but shuld be discussed if this is ok as getaddrinfo will look in IPv6 Mode after a AAAA Entry if not a IP is in allowed hosts*/
 		addrinfo.ai_flags=AI_PASSIVE;
 		}
 	if (rval = getaddrinfo(server_address, server_port, &addrinfo, &res) != 0) {
@@ -735,8 +738,17 @@ void wait_for_connections(void){
 		exit(STATE_CRITICAL);
 		}
 	else {
-		for (r=res; r; r = r->ai_next) {   
+		for (r=res; r; r = r->ai_next){
+			if (r->ai_family != AF_INET && r->ai_family != AF_INET6)
+				continue;
+			if (num_listen_socks >= MAX_LISTEN_SOCKS){
+				syslog(LOG_ERR,"Too many listen sockets. Enlarge MAX_LISTEN_SOCKS\n");
+				exit(STATE_UNKNOWN);
+				}
 			sock = socket(r->ai_family, r->ai_socktype, r->ai_protocol);
+			if (sock < 0)
+				/* kernel may not support ipv6 */
+				continue;
 			/* socket should be non-blocking */
 			fcntl(sock,F_SETFL,O_NONBLOCK);
 			/* set the reuse address flag so we don't get errors when restarting */
@@ -745,26 +757,35 @@ void wait_for_connections(void){
 				syslog(LOG_ERR,"Could not set reuse address option on socket!\n");
 				exit(STATE_UNKNOWN);
 				}
+#ifdef IPV6_V6ONLY
+			/* Only communicate in IPv6 over AF_INET6 sockets. */
+			flag=1;
+			if (r->ai_family == AF_INET6)
+				if(setsockopt(sock,IPPROTO_IPV6,IPV6_V6ONLY,(char *)&flag,sizeof(flag))<0) {
+					syslog(LOG_ERR,"Could not set IPV6_V6ONLY option on socket!\n");
+					exit(STATE_UNKNOWN);
+					}
+#endif
 			if(bind(sock, r->ai_addr, r->ai_addrlen) < 0) {
 				syslog(LOG_ERR,"Network server bind failure (%d: %s)\n",errno,strerror(errno));
 				(void) close(sock);
+				exit(STATE_CRITICAL);
 				}
-			else {
-				success=1;
-				break;
+			listen_socks[num_listen_socks] = sock;
+			num_listen_socks++;
+			if (listen(sock, 5) < 0){
+				syslog(LOG_ERR,"Network server listen failure (%d: %s)\n",errno,strerror(errno));
+	        		exit(STATE_CRITICAL);
 				}
+			if(sock > max_fd)
+				max_fd = sock;
 			}
 		freeaddrinfo(res);
-		if(success == 0) {
+		if(num_listen_socks == 0) {
 			exit(STATE_CRITICAL);
 			}
 		}
 
-	/* open the socket for listening */
-	if(listen(sock,5)<0){
-	    	syslog(LOG_ERR,"Network server listen failure (%d: %s)\n",errno,strerror(errno));
-	        exit(STATE_CRITICAL);
-		}
 
 	/* log warning about command arguments */
 #ifdef ENABLE_COMMAND_ARGUMENTS
@@ -781,28 +802,31 @@ void wait_for_connections(void){
 	while(1){
 
 		/* wait for a connection request */
-	        while(1){
 
-			/* wait until there's something to do */
-			FD_ZERO(&fdread);
-			FD_SET(sock,&fdread);
-			timeout.tv_sec=0;
-			timeout.tv_usec=500000;
-			retval=select(sock+1,&fdread,NULL,&fdread,&timeout);
+		/* wait until there's something to do */
+		FD_ZERO(&fdread);
+		for(i=0; i < num_listen_socks; i++)
+			FD_SET(listen_socks[i],&fdread);
 
-			/* bail out if necessary */
-			if(sigrestart==TRUE || sigshutdown==TRUE)
-				break;
+		timeout.tv_sec=0;
+		timeout.tv_usec=500000;
+		retval=select(max_fd+1,&fdread,NULL,NULL,&timeout);
+		/* bail out if necessary */
+		if(sigrestart==TRUE || sigshutdown==TRUE)
+			break;
+
+		/* error */
+		if(retval<0)
+			continue;
 
-			/* error */
-			if(retval<0)
+		/* accept a new connection request */
+		for (i = 0; i < num_listen_socks; i++){
+			if (!FD_ISSET(listen_socks[i], &fdread))
 				continue;
+			new_sd=accept(listen_socks[i], remoteaddr, &socklen);
 
-			/* accept a new connection request */
-			new_sd=accept(sock, remoteaddr, &socklen);
 			/* some kind of error occurred... */
 			if(new_sd<0){
-
 				/* bail out if necessary */
 				if(sigrestart==TRUE || sigshutdown==TRUE)
 					break;
@@ -819,125 +843,121 @@ void wait_for_connections(void){
 				if(errno==ENOBUFS)
 					continue;
 
-				/* else handle the error later */
-				break;
-			        }
-
-			/* connection was good */
-			break;
-		        }
+			        }		
 
-		/* bail out if necessary */
-		if(sigrestart==TRUE || sigshutdown==TRUE)
-			break;
+			/* bail out if necessary */
+			if(sigrestart==TRUE || sigshutdown==TRUE)
+				break;
 
-		/* child process should handle the connection */
-    		pid=fork();
-    		if(pid==0){
+			/* child process should handle the connection */
+	    		pid=fork();
+	    		if(pid==0){
 
-			/* fork again so we don't create zombies */
-			pid=fork();
-			if(pid==0){
-				/* hey, there was an error... */
-				if(new_sd<0){
+				/* fork again so we don't create zombies */
+				pid=fork();
+				if(pid==0){
+					/* hey, there was an error... */
+					if(new_sd<0){
 
-					/* log error to syslog facility */
-					syslog(LOG_ERR,"Network server accept failure (%d: %s)",errno,strerror(errno));
+						/* log error to syslog facility */
+						syslog(LOG_ERR,"Network server accept failure (%d: %s)",errno,strerror(errno));
 
-					/* close socket prioer to exiting */
-					close(sock);
+						/* close sockets prioer to exiting */
+						for(j=0; j < num_listen_socks; j++)
+							close(listen_socks[j]);
 			
-					return;
-				        }
-
-				/* handle signals */
-				signal(SIGQUIT,child_sighandler);
-				signal(SIGTERM,child_sighandler);
-				signal(SIGHUP,child_sighandler);
+						return;
+					        }
 
-				/* grandchild does not need to listen for connections, so close the socket */
-				close(sock);  
+					/* handle siOAgnals */
+					signal(SIGQUIT,child_sighandler);
+					signal(SIGTERM,child_sighandler);
+					signal(SIGHUP,child_sighandler);
 
-				/* log info to syslog facility */
-				if(debug==TRUE)
-				  syslog(LOG_DEBUG,"Connection from %s port %d",get_ip_str(remoteaddr, buf, BUFLEN),get_port(remoteaddr));
+					/* grandchild does not need to listen for connections, so close the sockets */
+					for(j=0; j < num_listen_socks; j++)
+						close(listen_socks[j]);
 
-                                /* is this is a blessed machine? */
-				if(allowed_hosts){
-				  if(!is_an_allowed_host(remoteaddr)){
+					/* log info to syslog facility */
+					if(debug==TRUE)
+						syslog(LOG_DEBUG,"Connection from %s port %d",get_ip_str(remoteaddr, buf, BUFLEN),get_port(remoteaddr));
 
-                                               /* log error to syslog facility */
-						syslog(LOG_ERR,"Host %s is not allowed to talk to us!",get_ip_str(remoteaddr, buf, BUFLEN));
+                                	/* is this is a blessed machine? */
+					if(allowed_hosts){
+						if(!is_an_allowed_host(remoteaddr)){
+							/* log error to syslog facility */
+							syslog(LOG_ERR,"Host %s is not allowed to talk to us!",get_ip_str(remoteaddr, buf, BUFLEN));
 
-                                               /* log info to syslog facility */
-					       if(debug==TRUE)
-						       syslog(LOG_DEBUG,"Connection from %s closed.",get_ip_str(remoteaddr, buf, BUFLEN));
+							/* log info to syslog facility */
+							if(debug==TRUE)
+								syslog(LOG_DEBUG,"Connection from %s closed.",get_ip_str(remoteaddr, buf, BUFLEN));
 
-					       /* close socket prior to exiting */
-                                               close(new_sd);
+							/* close socket prior to exiting */
+							close(new_sd);
 
-					       exit(STATE_OK);
-				               }
-                                       else{
+							exit(STATE_OK);
+							}
+						else{
 
-                                               /* log info to syslog facility */
-                                               if(debug==TRUE)
-                                                       syslog(LOG_DEBUG,"Host address is in allowed_hosts");
-				               }
-				        }
+							/* log info to syslog facility */
+							if(debug==TRUE)
+							syslog(LOG_DEBUG,"Host address is in allowed_hosts");
+							}
+						}
 
 #ifdef HAVE_LIBWRAP
 
-				/* Check whether or not connections are allowed from this host */
-				request_init(&req,RQ_DAEMON,"nrpe",RQ_FILE,new_sd,0);
-				fromhost(&req);
+					/* Check whether or not connections are allowed from this host */
+					request_init(&req,RQ_DAEMON,"nrpe",RQ_FILE,new_sd,0);
+					fromhost(&req);
 
-				if(!hosts_access(&req)){
+					if(!hosts_access(&req)){
 
-					syslog(LOG_DEBUG,"Connection refused by TCP wrapper");
+						syslog(LOG_DEBUG,"Connection refused by TCP wrapper");
 
-					/* refuse the connection */
-					refuse(&req);
-					close(new_sd);
+						/* refuse the connection */
+						refuse(&req);
+						close(new_sd);
 
-					/* should not be reached */
-					syslog(LOG_ERR,"libwrap refuse() returns!");
-					exit(STATE_CRITICAL);
-					}
+						/* should not be reached */
+						syslog(LOG_ERR,"libwrap refuse() returns!");
+						exit(STATE_CRITICAL);
+						}
 #endif
 
-				/* handle the client connection */
-				handle_connection(new_sd);
+					/* handle the client connection */
+					handle_connection(new_sd);
 
-				/* log info to syslog facility */
-				if(debug==TRUE)
-					syslog(LOG_DEBUG,"Connection from %s closed.",get_ip_str(remoteaddr, buf, BUFLEN));
+					/* log info to syslog facility */
+					if(debug==TRUE)
+						syslog(LOG_DEBUG,"Connection from %s closed.",get_ip_str(remoteaddr, buf, BUFLEN));
 
-				/* close socket prior to exiting */
-				close(new_sd);
+					/* close socket prior to exiting */
+					close(new_sd);
 
-				exit(STATE_OK);
-    			        }
+					exit(STATE_OK);
+    			        	}
 
-			/* first child returns immediately, grandchild is inherited by INIT process -> no zombies... */
-			else
-				exit(STATE_OK);
-		        }
+				/* first child returns immediately, grandchild is inherited by INIT process -> no zombies... */
+				else
+					exit(STATE_OK);
+		        	}
 		
-		/* parent ... */
-		else{
-			/* parent doesn't need the new connection */
-			close(new_sd);
-
-			/* parent waits for first child to exit */
-			waitpid(pid,NULL,0);
-		        }
-  		}
+			/* parent ... */
+			else{
+				/* parent doesn't need the new connection */
+				close(new_sd);
 
-	/* close the socket we're listening on */
-	close(sock);
+				/* parent waits for first child to exit */
+				waitpid(pid,NULL,0);
+		        	}
+  			}
+		}
+		/* close the sockets we're listening on */
+		for(j=0; j < num_listen_socks; j++)
+			close(listen_socks[j]);
 
-	return;
+		return;
 	}
 
 
------------------------------------------------------------------------------
This SF.net Dev2Dev email is sponsored by:

Show off your parallel programming skills.
Enter the Intel(R) Threading Challenge 2010.
http://p.sf.net/sfu/intel-thread-sfd
_______________________________________________
icinga-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/icinga-devel

Reply via email to