[PACTH] NRPE IPv6 (updated)
Leo Baltus
Leo.Baltus at omroep.nl
Mon Apr 2 11:10:09 CEST 2012
Hi,
Attached patch fixes a small memory leak introduced by my IPv6 patch I
sent earlier, see below.
As I haven't got any reponse on my first post so I'll just resubmit the
complete patch.
Op 02/05/2011 om 17:32:55 +0200, schreef Leo Baltus:
> We have prepared attached patch that allows nrpe & check_nrpe to support
> ipv6 and it also add a '-b' commandline argument to select the source address.
>
> It has been running here for a few weeks now so it seems it's pretty stable.
>
> Most of the code is 'inspired' by openssh, so you may find similarities.
>
> It has successfully been compiled on a number of Linux distros, as well as a
> recent version of FreeBSD.
>
> I have seen the post from Kristian Lyngstøl in March last only today, so
> we may be doing the same thing. As Kristian seems to be more ambitious
> than I am to clean up the code, maybe this patch can help to get the server-
> part in place en to get it upstream some day.
>
> In the mean time this patch adds ipv6 capabilities to nrpe & check_nrpe
> for anyone who has an interest in it.
>
--
Leo Baltus, internetbeheerder /\
NPO ICT Internet Services /NPO/\
Sumatralaan 45, 1217 GP Hilversum, Filmcentrum, west \ /\/
beheer at omroep.nl, 035-6773555 \/
-------------- next part --------------
diff -ruN nrpe-2.12.org/include/utils.h nrpe-2.12/include/utils.h
--- nrpe-2.12.org/include/utils.h 2006-12-12 03:04:00.000000000 +0100
+++ nrpe-2.12/include/utils.h 2012-02-24 16:43:53.000000000 +0100
@@ -41,9 +41,9 @@
void randomize_buffer(char *,int);
int my_tcp_connect(char *,int,int *);
-int my_connect(char *,int,int *,char *);
+int my_connect(const char *host, struct sockaddr_storage * hostaddr, u_short port, int address_family, const char *bind_address);
-int my_inet_aton(register const char *,struct in_addr *);
+void add_listen_addr(struct addrinfo **listen_addrs, int address_family, char *addr, int port);
void strip(char *);
diff -ruN nrpe-2.12.org/src/check_nrpe.c nrpe-2.12/src/check_nrpe.c
--- nrpe-2.12.org/src/check_nrpe.c 2008-03-10 22:04:43.000000000 +0100
+++ nrpe-2.12/src/check_nrpe.c 2012-02-24 16:43:53.000000000 +0100
@@ -24,8 +24,11 @@
#define DEFAULT_NRPE_COMMAND "_NRPE_CHECK" /* check version of NRPE daemon */
-int server_port=DEFAULT_SERVER_PORT;
+u_short server_port=DEFAULT_SERVER_PORT;
char *server_name=NULL;
+char *bind_address=NULL;
+struct sockaddr_storage hostaddr;
+int address_family=AF_UNSPEC;
char *command_name=NULL;
int socket_timeout=DEFAULT_SOCKET_TIMEOUT;
int timeout_return_code=STATE_CRITICAL;
@@ -38,7 +41,6 @@
int show_version=FALSE;
#ifdef HAVE_SSL
-SSL_METHOD *meth;
SSL_CTX *ctx;
SSL *ssl;
int use_ssl=TRUE;
@@ -84,12 +86,15 @@
if(result!=OK || show_help==TRUE){
- printf("Usage: check_nrpe -H <host> [-n] [-u] [-p <port>] [-t <timeout>] [-c <command>] [-a <arglist...>]\n");
+ printf("Usage: check_nrpe -H <host> [ -b <bindaddr> ] [-4] [-6] [-n] [-u] [-p <port>] [-t <timeout>] [-c <command>] [-a <arglist...>]\n");
printf("\n");
printf("Options:\n");
printf(" -n = Do no use SSL\n");
printf(" -u = Make socket timeouts return an UNKNOWN state instead of CRITICAL\n");
- printf(" <host> = The address of the host running the NRPE daemon\n");
+ printf(" <host> = The address of the NRPE daemon\n");
+ printf(" <bindaddr> = bind to local address\n");
+ printf(" -4 = user ipv4 only\n");
+ printf(" -6 = user ipv6 only\n");
printf(" [port] = The port on which the daemon is running (default=%d)\n",DEFAULT_SERVER_PORT);
printf(" [timeout] = Number of seconds before connection times out (default=%d)\n",DEFAULT_SOCKET_TIMEOUT);
printf(" [command] = The name of the command that the remote daemon should run\n");
@@ -123,9 +128,8 @@
if(use_ssl==TRUE){
SSL_library_init();
SSLeay_add_ssl_algorithms();
- meth=SSLv23_client_method();
SSL_load_error_strings();
- if((ctx=SSL_CTX_new(meth))==NULL){
+ if((ctx=SSL_CTX_new(SSLv23_client_method()))==NULL){
printf("CHECK_NRPE: Error - could not create SSL context.\n");
exit(STATE_CRITICAL);
}
@@ -143,7 +147,10 @@
alarm(socket_timeout);
/* try to connect to the host at the given port number */
- result=my_tcp_connect(server_name,server_port,&sd);
+
+ if ((sd=my_connect(server_name, &hostaddr, server_port, address_family, bind_address)) < 0 )
+ exit (255);
+ else result=STATE_OK;
#ifdef HAVE_SSL
/* do SSL handshake */
@@ -320,10 +327,13 @@
int option_index=0;
static struct option long_options[]={
{"host", required_argument, 0, 'H'},
+ {"bind", required_argument, 0, 'b'},
{"command", required_argument, 0, 'c'},
{"args", required_argument, 0, 'a'},
{"no-ssl", no_argument, 0, 'n'},
{"unknown-timeout", no_argument, 0, 'u'},
+ {"ipv4", no_argument, 0, '4'},
+ {"ipv6", no_argument, 0, '6'},
{"timeout", required_argument, 0, 't'},
{"port", required_argument, 0, 'p'},
{"help", no_argument, 0, 'h'},
@@ -336,7 +346,7 @@
if(argc<2)
return ERROR;
- snprintf(optchars,MAX_INPUT_BUFFER,"H:c:a:t:p:nuhl");
+ snprintf(optchars,MAX_INPUT_BUFFER,"H:b:c:a:t:p:nu46hl");
while(1){
#ifdef HAVE_GETOPT_LONG
@@ -354,6 +364,9 @@
case 'h':
show_help=TRUE;
break;
+ case 'b':
+ bind_address=strdup(optarg);
+ break;
case 'V':
show_version=TRUE;
break;
@@ -385,6 +398,12 @@
case 'u':
timeout_return_code=STATE_UNKNOWN;
break;
+ case '4':
+ address_family=AF_INET;
+ break;
+ case '6':
+ address_family=AF_INET6;
+ break;
default:
return ERROR;
break;
diff -ruN nrpe-2.12.org/src/nrpe.c nrpe-2.12/src/nrpe.c
--- nrpe-2.12.org/src/nrpe.c 2008-03-10 22:04:43.000000000 +0100
+++ nrpe-2.12/src/nrpe.c 2012-02-24 16:44:26.000000000 +0100
@@ -18,11 +18,15 @@
*
******************************************************************************/
+#include <stdlib.h>
#include "../include/common.h"
#include "../include/config.h"
#include "../include/nrpe.h"
#include "../include/utils.h"
+# define howmany(x,y) (((x)+((y)-1))/(y))
+
+
#ifdef HAVE_SSL
#include "../include/dh.h"
#endif
@@ -33,7 +37,6 @@
#endif
#ifdef HAVE_SSL
-SSL_METHOD *meth;
SSL_CTX *ctx;
int use_ssl=TRUE;
#else
@@ -50,7 +53,15 @@
char config_file[MAX_INPUT_BUFFER]="nrpe.cfg";
int log_facility=LOG_DAEMON;
int server_port=DEFAULT_SERVER_PORT;
-char server_address[16]="0.0.0.0";
+char server_address[NI_MAXHOST]="";
+struct addrinfo *listen_addrs=NULL;
+
+#define MAX_LISTEN_SOCKS 16
+int listen_socks[MAX_LISTEN_SOCKS];
+int num_listen_socks = 0;
+
+
+int address_family=AF_UNSPEC;
int socket_timeout=DEFAULT_SOCKET_TIMEOUT;
int command_timeout=DEFAULT_COMMAND_TIMEOUT;
int connection_timeout=DEFAULT_CONNECTION_TIMEOUT;
@@ -138,11 +149,13 @@
else if(result!=OK || show_help==TRUE){
- printf("Usage: nrpe [-n] -c <config_file> <mode>\n");
+ printf("Usage: nrpe [-n] -c <config_file> [-4|-6] <mode>\n");
printf("\n");
printf("Options:\n");
printf(" -n = Do not use SSL\n");
printf(" <config_file> = Name of config file to use\n");
+ printf(" -4 = use ipv4 only\n");
+ printf(" -6 = use ipv6 only\n");
printf(" <mode> = One of the following two operating modes:\n");
printf(" -i = Run as a service under inetd or xinetd\n");
printf(" -d = Run as a standalone daemon\n");
@@ -208,7 +221,6 @@
if(use_ssl==TRUE){
SSL_library_init();
SSLeay_add_ssl_algorithms();
- meth=SSLv23_server_method();
SSL_load_error_strings();
/* use week random seed if necessary */
@@ -230,7 +242,7 @@
}
}
- if((ctx=SSL_CTX_new(meth))==NULL){
+ if((ctx=SSL_CTX_new(SSLv23_server_method()))==NULL){
syslog(LOG_ERR,"Error: could not create SSL context.\n");
exit(STATE_CRITICAL);
}
@@ -691,12 +703,38 @@
}
+/*
+ * Close all listening sockets
+ */
+static void
+close_listen_socks(void)
+{
+ int i;
+
+ for (i = 0; i <= num_listen_socks; i++) {
+ close(listen_socks[i]);
+ num_listen_socks--;
+ }
+}
+
/* wait for incoming connection requests */
void wait_for_connections(void){
+ struct addrinfo *ai;
+ char ntop[NI_MAXHOST], strport[NI_MAXSERV];
+ fd_set *fdset=NULL;
+ int maxfd=0;
+ struct sockaddr_storage from;
+ socklen_t fromlen;
+ char ipstr[INET6_ADDRSTRLEN];
+ int ret;
+ int listen_sock;
+ int i;
+ int r;
+
struct sockaddr_in myname;
struct sockaddr_in *nptr;
- struct sockaddr addr;
+ struct sockaddr_storage addr;
int rc;
int sock, new_sd;
socklen_t addrlen;
@@ -708,50 +746,77 @@
#ifdef HAVE_LIBWRAP
struct request_info req;
#endif
+
+ add_listen_addr(&listen_addrs, address_family,
+ (strcmp(server_address,"")==0)?NULL:server_address, server_port);
- /* create a socket for listening */
- sock=socket(AF_INET,SOCK_STREAM,0);
-
- /* exit if we couldn't create the socket */
- if(sock<0){
- syslog(LOG_ERR,"Network server socket failure (%d: %s)",errno,strerror(errno));
- exit(STATE_CRITICAL);
+ for (ai = listen_addrs; ai; ai = ai->ai_next) {
+ if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
+ continue;
+ if (num_listen_socks >= MAX_LISTEN_SOCKS) {
+ syslog(LOG_ERR, "Too many listen sockets. "
+ "Enlarge MAX_LISTEN_SOCKS");
+ exit(1);
+ }
+ if ((ret = getnameinfo(ai->ai_addr, ai->ai_addrlen,
+ ntop, sizeof(ntop), strport, sizeof(strport),
+ NI_NUMERICHOST|NI_NUMERICSERV)) != 0) {
+ syslog(LOG_ERR, "getnameinfo failed: %.100s",
+ gai_strerror(ret));
+ continue;
+ }
+ /* Create socket for listening. */
+ listen_sock = socket(ai->ai_family, ai->ai_socktype,
+ ai->ai_protocol);
+ if (listen_sock < 0) {
+ /* kernel may not support ipv6 */
+ syslog(LOG_ERR, "socket: %.100s", strerror(errno));
+ continue;
+ }
+ /* socket should be non-blocking */
+ fcntl(listen_sock,F_SETFL,O_NONBLOCK);
+ /* set the reuse address flag so we don't get errors when
+ restarting */
+ if(setsockopt(listen_sock, SOL_SOCKET,SO_REUSEADDR,
+ &flag,sizeof(flag))<0){
+ syslog(LOG_ERR, "setsockopt SO_REUSEADDR: %s",
+ strerror(errno));
+ 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 */
- flag=1;
- if(setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(char *)&flag,sizeof(flag))<0){
- syslog(LOG_ERR,"Could not set reuse address option on socket!\n");
- exit(STATE_UNKNOWN);
- }
-
- myname.sin_family=AF_INET;
- myname.sin_port=htons(server_port);
- bzero(&myname.sin_zero,8);
-
- /* what address should we bind to? */
- if(!strlen(server_address))
- myname.sin_addr.s_addr=INADDR_ANY;
-
- else if(!my_inet_aton(server_address,&myname.sin_addr)){
- syslog(LOG_ERR,"Server address is not a valid IP address\n");
- exit(STATE_CRITICAL);
+#ifdef IPV6_V6ONLY
+ /* Only communicate in IPv6 over AF_INET6 sockets. */
+ if (ai->ai_family == AF_INET6) {
+ if (setsockopt(listen_sock, IPPROTO_IPV6, IPV6_V6ONLY,
+ &flag, sizeof(flag)) == -1)
+ error("setsockopt IPV6_V6ONLY: %s",
+ strerror(errno));
}
+#endif
- /* bind the address to the Internet socket */
- if(bind(sock,(struct sockaddr *)&myname,sizeof(myname))<0){
- syslog(LOG_ERR,"Network server bind failure (%d: %s)\n",errno,strerror(errno));
- exit(STATE_CRITICAL);
- }
+ /* Bind the socket to the desired port. */
+ if (bind(listen_sock, ai->ai_addr, ai->ai_addrlen) < 0) {
+ syslog(LOG_ERR, "Bind to port %s on %s failed: %.200s.",
+ strport, ntop, strerror(errno));
+ close(listen_sock);
+ continue;
+ }
+ listen_socks[num_listen_socks] = listen_sock;
+ num_listen_socks++;
- /* 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);
+ /* Start listening on the port. */
+ if (listen(listen_sock, 5) < 0) {
+ syslog(LOG_ERR, "listen on [%s]:%s: %.100s",
+ ntop, strport, strerror(errno));
+ exit(1);
}
+ syslog(LOG_INFO, "Server listening on %s port %s.", ntop, strport);
+ }
+
+ if (!num_listen_socks) {
+ syslog(LOG_ERR, "Cannot bind to any address.");
+ exit(1);
+ }
/* log warning about command arguments */
#ifdef ENABLE_COMMAND_ARGUMENTS
@@ -759,142 +824,124 @@
syslog(LOG_NOTICE,"Warning: Daemon is configured to accept command arguments from clients!");
#endif
- syslog(LOG_INFO,"Listening for connections on port %d\n",htons(myname.sin_port));
-
if(allowed_hosts)
syslog(LOG_INFO,"Allowing connections from: %s\n",allowed_hosts);
/* listen for connection requests - fork() if we get one */
while(1){
+ /* bail out if necessary */
+ if(sigrestart==TRUE || sigshutdown==TRUE)
+ break;
- /* wait for a connection request */
- while(1){
+ for (i = 0; i < num_listen_socks; i++)
+ if (listen_socks[i] > maxfd)
+ maxfd = listen_socks[i];
+
+ if (fdset != NULL)
+ free(fdset);
+ fdset = (fd_set *)calloc(howmany(maxfd + 1, NFDBITS),
+ sizeof(fd_mask));
- /* 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);
+ for (i = 0; i < num_listen_socks; i++)
+ FD_SET(listen_socks[i], fdset);
+
+ /* Wait in select until there is a connection. */
+ retval = select(maxfd+1, fdset, NULL, NULL, NULL);
/* bail out if necessary */
if(sigrestart==TRUE || sigshutdown==TRUE)
break;
-
/* error */
if(retval<0)
continue;
+ for (i = 0; i < num_listen_socks; i++) {
+ if (!FD_ISSET(listen_socks[i], fdset))
+ continue;
+ fromlen = sizeof(from);
/* accept a new connection request */
- new_sd=accept(sock,0,0);
+ new_sd = accept(listen_socks[i],
+ (struct sockaddr *)&from, &fromlen);
+ // {{{
/* some kind of error occurred... */
if(new_sd<0){
-
/* bail out if necessary */
if(sigrestart==TRUE || sigshutdown==TRUE)
break;
-
/* retry */
if(errno==EWOULDBLOCK || errno==EINTR)
continue;
-
/* socket is nonblocking and we don't have a connection yet */
if(errno==EAGAIN)
continue;
-
/* fix for HP-UX 11.0 - just retry */
if(errno==ENOBUFS)
continue;
-
/* else handle the error later */
break;
- }
-
- /* connection was good */
- break;
- }
-
- /* bail out if necessary */
- if(sigrestart==TRUE || sigshutdown==TRUE)
- break;
-
- /* 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){
-
- /* log error to syslog facility */
- syslog(LOG_ERR,"Network server accept failure (%d: %s)",errno,strerror(errno));
+ }
+ // }}}
+// {{{
+ /* child process should handle the connection */
+ if(pid=fork() == 0) {
- /* close socket prioer to exiting */
- close(sock);
-
- return;
- }
+ /* fork again so we don't create zombies */
+ if(pid=fork() == 0) {
+// {{{
/* handle signals */
signal(SIGQUIT,child_sighandler);
signal(SIGTERM,child_sighandler);
signal(SIGHUP,child_sighandler);
- /* grandchild does not need to listen for connections, so close the socket */
- close(sock);
+ /* grandchild does not need to listen for connections */
+ close_listen_socks();
/* find out who just connected... */
addrlen=sizeof(addr);
- rc=getpeername(new_sd,&addr,&addrlen);
+ rc=getpeername(new_sd, (struct sockaddr *)&addr, &addrlen);
if(rc<0){
-
/* log error to syslog facility */
syslog(LOG_ERR,"Error: Network server getpeername() failure (%d: %s)",errno,strerror(errno));
-
/* close socket prior to exiting */
close(new_sd);
-
return;
- }
+ }
- nptr=(struct sockaddr_in *)&addr;
+ if ((r = getnameinfo((struct sockaddr *)&addr, addrlen, ipstr,
+ sizeof(ipstr), NULL, 0, NI_NUMERICHOST)) != 0) {
+ syslog(LOG_ERR,"get_socket_address: getnameinfo %d failed: %s", NI_NUMERICHOST,
+ gai_strerror(r));
+ close(new_sd);
+ return;
+ }
- /* log info to syslog facility */
+// }}}
+// {{{
if(debug==TRUE)
- syslog(LOG_DEBUG,"Connection from %s port %d",inet_ntoa(nptr->sin_addr),nptr->sin_port);
+ syslog(LOG_DEBUG,"Connection from %s",ipstr);
/* is this is a blessed machine? */
if(allowed_hosts){
-
- if(!is_an_allowed_host(inet_ntoa(nptr->sin_addr))){
-
+ if(!is_an_allowed_host(ipstr)){
/* log error to syslog facility */
- syslog(LOG_ERR,"Host %s is not allowed to talk to us!",inet_ntoa(nptr->sin_addr));
-
+ syslog(LOG_ERR,"Host %s is not allowed to talk to us!",ipstr);
/* log info to syslog facility */
if(debug==TRUE)
- syslog(LOG_DEBUG,"Connection from %s closed.",inet_ntoa(nptr->sin_addr));
-
+ syslog(LOG_DEBUG,"Connection from %s closed.",ipstr);
/* close socket prior to exiting */
close(new_sd);
-
exit(STATE_OK);
- }
- else{
-
- /* log info to syslog facility */
+ } else {
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);
@@ -912,41 +959,40 @@
exit(STATE_CRITICAL);
}
#endif
+// }}}
- /* handle the client connection */
- handle_connection(new_sd);
-
- /* log info to syslog facility */
- if(debug==TRUE)
- syslog(LOG_DEBUG,"Connection from %s closed.",inet_ntoa(nptr->sin_addr));
-
- /* close socket prior to exiting */
+ /* handle the client connection */
+ handle_connection(new_sd);
+
+ /* log info to syslog facility */
+ if(debug==TRUE)
+ syslog(LOG_DEBUG,"Connection from %s closed.",ipstr);
+
+ /* close socket prior to exiting */
+ close(new_sd);
+
+ exit(STATE_OK);
+ } else {
+ /* first child returns immediately, grandchild is inherited by INIT process -> no zombies... */
+ exit(STATE_OK);
+ }
+ } else {
+ /* parent doesn't need the new connection */
close(new_sd);
+ /* parent waits for first child to exit */
+ waitpid(pid,NULL,0);
+ }
+// }}}
+ }
+ }
- 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);
- }
- }
-
- /* close the socket we're listening on */
- close(sock);
+ /* close the sockets we're listening on */
+ close_listen_socks();
+ freeaddrinfo(listen_addrs);
+ listen_addrs=NULL;
return;
- }
-
+}
/* checks to see if a given host is allowed to talk to us */
@@ -958,6 +1004,9 @@
char **pptr=NULL;
char *save_connecting_host=NULL;
struct in_addr addr;
+ int gaierr;
+ struct addrinfo hints, *res, *ai;
+
/* make sure we have something */
if(connecting_host==NULL)
@@ -987,18 +1036,25 @@
save_connecting_host=strdup(connecting_host);
for(temp_ptr=strtok(temp_buffer,",");temp_ptr!=NULL;temp_ptr=strtok(NULL,",")){
- myhost=gethostbyname(temp_ptr);
- if(myhost!=NULL){
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_flags = AI_PASSIVE;
+ if ( ( gaierr = getaddrinfo(temp_ptr, NULL, &hints, &ai) ) != 0) {
+ break;
+ }
- /* check all addresses for the host... */
- for(pptr=myhost->h_addr_list;*pptr!=NULL;pptr++){
- memcpy(&addr, *pptr, sizeof(addr));
- if(!strcmp(save_connecting_host, inet_ntoa(addr))){
- result=1;
- break;
- }
- }
- }
+ /* loop over all returned results and do inverse lookup */
+ for (res = ai; res != NULL; res = res->ai_next) {
+ char hostname[NI_MAXHOST] = "";
+ if ( (gaierr = getnameinfo(res->ai_addr, res->ai_addrlen,
+ hostname, NI_MAXHOST, NULL, 0, NI_NUMERICHOST)) != 0 ) {
+ continue;
+ }
+ if (*hostname != '\0' && !strcmp(save_connecting_host, hostname)){
+ result=1;
+ break;
+ }
+ }
if(result==1)
break;
@@ -1006,6 +1062,7 @@
strcpy(connecting_host, save_connecting_host);
free(save_connecting_host);
+ freeaddrinfo(ai);
}
free(temp_buffer);
@@ -1902,6 +1959,8 @@
static struct option long_options[]={
{"config", required_argument, 0, 'c'},
{"inetd", no_argument, 0, 'i'},
+ {"4", no_argument, 0, '4'},
+ {"6", no_argument, 0, '4'},
{"daemon", no_argument, 0, 'd'},
{"no-ssl", no_argument, 0, 'n'},
{"help", no_argument, 0, 'h'},
@@ -1914,7 +1973,7 @@
if(argc<2)
return ERROR;
- snprintf(optchars,MAX_INPUT_BUFFER,"c:hVldin");
+ snprintf(optchars,MAX_INPUT_BUFFER,"c:hVldi46n");
while(1){
#ifdef HAVE_GETOPT_LONG
@@ -1950,6 +2009,12 @@
use_inetd=TRUE;
have_mode=TRUE;
break;
+ case '4':
+ address_family=AF_INET;
+ break;
+ case '6':
+ address_family=AF_INET6;
+ break;
case 'n':
use_ssl=FALSE;
break;
diff -ruN nrpe-2.12.org/src/utils.c nrpe-2.12/src/utils.c
--- nrpe-2.12.org/src/utils.c 2006-12-12 03:04:01.000000000 +0100
+++ nrpe-2.12/src/utils.c 2012-02-24 16:43:53.000000000 +0100
@@ -29,6 +29,10 @@
*
****************************************************************************/
+#include "sys/types.h"
+#include <sys/socket.h>
+#include <netdb.h>
+#include <stdio.h>
#include "../include/common.h"
#include "../include/utils.h"
@@ -109,177 +113,134 @@
}
-/* opens a connection to a remote host/tcp port */
-int my_tcp_connect(char *host_name,int port,int *sd){
- int result;
-
- result=my_connect(host_name,port,sd,"tcp");
-
- return result;
- }
-
-
-/* opens a tcp or udp connection to a remote host */
-int my_connect(char *host_name,int port,int *sd,char *proto){
- struct sockaddr_in servaddr;
- struct hostent *hp;
- struct protoent *ptrp;
- int result;
-
- bzero((char *)&servaddr,sizeof(servaddr));
- servaddr.sin_family=AF_INET;
- servaddr.sin_port=htons(port);
-
- /* try to bypass using a DNS lookup if this is just an IP address */
- if(!my_inet_aton(host_name,&servaddr.sin_addr)){
-
- /* else do a DNS lookup */
- hp=gethostbyname((const char *)host_name);
- if(hp==NULL){
- printf("Invalid host name '%s'\n",host_name);
- return STATE_UNKNOWN;
- }
-
- memcpy(&servaddr.sin_addr,hp->h_addr,hp->h_length);
- }
+#ifndef NI_MAXSERV
+# define NI_MAXSERV 32
+#endif
+
+#ifndef NI_MAXHOST
+# define NI_MAXHOST 1025
+#endif
+
+/* opens a connection to a remote host */
+int my_connect(const char *host, struct sockaddr_storage * hostaddr, u_short port, int address_family, const char *bind_address){
+ int gaierr;
+ int sock = -1;
+ char ntop[NI_MAXHOST], strport[NI_MAXSERV];
+ struct addrinfo hints, *ai, *aitop;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = address_family;
+ hints.ai_socktype = SOCK_STREAM;
+ snprintf(strport, sizeof strport, "%u", port);
+ if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0) {
+ fprintf(stderr,"Could not resolve hostname %.100s: %s\n",
+ host, gai_strerror(gaierr));
+ exit(1);
+ }
- /* map transport protocol name to protocol number */
- if(((ptrp=getprotobyname(proto)))==NULL){
- printf("Cannot map \"%s\" to protocol number\n",proto);
- return STATE_UNKNOWN;
- }
+ /*
+ * Loop through addresses for this host, and try each one in
+ * sequence until the connection succeeds.
+ */
+ for (ai = aitop; ai; ai = ai->ai_next) {
+ if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
+ continue;
+ if (getnameinfo(ai->ai_addr, ai->ai_addrlen,
+ ntop, sizeof(ntop), strport, sizeof(strport),
+ NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
+ fprintf(stderr, "my_connect: getnameinfo failed\n");
+ continue;
+ }
- /* create a socket */
- *sd=socket(PF_INET,(!strcmp(proto,"udp"))?SOCK_DGRAM:SOCK_STREAM,ptrp->p_proto);
- if(*sd<0){
- printf("Socket creation failed\n");
- return STATE_UNKNOWN;
- }
+ /* Create a socket for connecting. */
+ sock = my_create_socket(ai, bind_address);
+ if (sock < 0)
+ /* Any error is already output */
+ continue;
- /* open a connection */
- result=connect(*sd,(struct sockaddr *)&servaddr,sizeof(servaddr));
- if(result<0){
- switch(errno){
- case ECONNREFUSED:
- printf("Connection refused by host\n");
- break;
- case ETIMEDOUT:
- printf("Timeout while attempting connection\n");
- break;
- case ENETUNREACH:
- printf("Network is unreachable\n");
+ if (connect(sock, ai->ai_addr, ai->ai_addrlen) >= 0) {
+ /* Successful connection. */
+ memcpy(hostaddr, ai->ai_addr, ai->ai_addrlen);
break;
- default:
- printf("Connection refused or timed out\n");
- }
-
- return STATE_CRITICAL;
- }
-
- return STATE_OK;
- }
-
-
-
-/* This code was taken from Fyodor's nmap utility, which was originally taken from
- the GLIBC 2.0.6 libraries because Solaris doesn't contain the inet_aton() funtion. */
-int my_inet_aton(register const char *cp, struct in_addr *addr){
- register unsigned int val; /* changed from u_long --david */
- register int base, n;
- register char c;
- u_int parts[4];
- register u_int *pp = parts;
-
- c=*cp;
-
- for(;;){
-
- /*
- * Collect number up to ``.''.
- * Values are specified as for C:
- * 0x=hex, 0=octal, isdigit=decimal.
- */
- if (!isdigit((int)c))
- return (0);
- val=0;
- base=10;
-
- if(c=='0'){
- c=*++cp;
- if(c=='x'||c=='X')
- base=16,c=*++cp;
- else
- base=8;
- }
-
- for(;;){
- if(isascii((int)c) && isdigit((int)c)){
- val=(val*base)+(c -'0');
- c=*++cp;
- }
- else if(base==16 && isascii((int)c) && isxdigit((int)c)){
- val=(val<<4) | (c+10-(islower((int)c)?'a':'A'));
- c = *++cp;
- }
- else
- break;
- }
-
- if(c=='.'){
+ } else {
+ fprintf(stderr,"connect to address %s port %s: %s\n",
+ ntop, strport, strerror(errno));
+ close(sock);
+ sock = -1;
+ }
+ }
- /*
- * Internet format:
- * a.b.c.d
- * a.b.c (with c treated as 16 bits)
- * a.b (with b treated as 24 bits)
- */
- if(pp>=parts+3)
- return (0);
- *pp++=val;
- c=*++cp;
- }
- else
- break;
- }
+ freeaddrinfo(aitop);
- /* Check for trailing characters */
- if(c!='\0' && (!isascii((int)c) || !isspace((int)c)))
- return (0);
-
- /* Concoct the address according to the number of parts specified */
- n=pp-parts+1;
- switch(n){
-
- case 0:
- return (0); /* initial nondigit */
-
- case 1: /* a -- 32 bits */
- break;
-
- case 2: /* a.b -- 8.24 bits */
- if(val>0xffffff)
- return (0);
- val|=parts[0]<<24;
- break;
-
- case 3: /* a.b.c -- 8.8.16 bits */
- if(val>0xffff)
- return (0);
- val|=(parts[0]<< 24) | (parts[1]<<16);
- break;
-
- case 4: /* a.b.c.d -- 8.8.8.8 bits */
- if(val>0xff)
- return (0);
- val|=(parts[0]<<24) | (parts[1]<<16) | (parts[2]<<8);
- break;
- }
+ /* Return failure if we didn't get a successful connection. */
+ if (sock == -1) {
+ error("connect to host %s port %s: %s",
+ host, strport, strerror(errno));
+ return -1;
+ }
- if(addr)
- addr->s_addr=htonl(val);
+ return sock;
+}
- return (1);
+/* Creates a socket for the connection. */
+int my_create_socket(struct addrinfo *ai, const char *bind_address)
+{
+ int sock, gaierr;
+ struct addrinfo hints, *res;
+
+ sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+ if (sock < 0)
+ fprintf(stderr,"socket: %.100s\n", strerror(errno));
+
+ /* Bind the socket to an alternative local IP address */
+ if (bind_address == NULL)
+ return sock;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = ai->ai_family;
+ hints.ai_socktype = ai->ai_socktype;
+ hints.ai_protocol = ai->ai_protocol;
+ hints.ai_flags = AI_PASSIVE;
+ gaierr = getaddrinfo(bind_address, NULL, &hints, &res);
+ if (gaierr) {
+ fprintf(stderr, "getaddrinfo: %s: %s\n", bind_address,
+ gai_strerror(gaierr));
+ close(sock);
+ return -1;
+ }
+ if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) {
+ fprintf(stderr, "bind: %s: %s\n", bind_address, strerror(errno));
+ close(sock);
+ freeaddrinfo(res);
+ return -1;
}
+ freeaddrinfo(res);
+ return sock;
+}
+
+void add_listen_addr(struct addrinfo **listen_addrs, int address_family, char *addr, int port)
+{
+ struct addrinfo hints, *ai, *aitop;
+ char strport[NI_MAXSERV];
+ int gaierr;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = address_family;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = (addr == NULL) ? AI_PASSIVE : 0;
+ snprintf(strport, sizeof strport, "%d", port);
+ if ((gaierr = getaddrinfo(addr, strport, &hints, &aitop)) != 0) {
+ syslog(LOG_ERR,"bad addr or host: %s (%s)\n",
+ addr ? addr : "<NULL>",
+ gai_strerror(gaierr));
+ exit(1);
+ }
+ for (ai = aitop; ai->ai_next; ai = ai->ai_next)
+ ;
+ ai->ai_next = *listen_addrs;
+ *listen_addrs = aitop;
+}
+
void strip(char *buffer){
-------------- next part --------------
------------------------------------------------------------------------------
This SF email is sponsosred by:
Try Windows Azure free for 90 days Click Here
http://p.sf.net/sfu/sfd2d-msazure
-------------- next part --------------
_______________________________________________
Nagios-devel mailing list
Nagios-devel at lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/nagios-devel
More information about the Developers
mailing list