diff -ur -x CVS monit.orig/CHANGES.txt monit/CHANGES.txt --- monit.orig/CHANGES.txt 2004-12-19 19:43:30.000000000 +0100 +++ monit/CHANGES.txt 2004-12-19 19:41:42.000000000 +0100 @@ -29,6 +29,11 @@ the mod_status module, this test may be useful since you can test the internals of Apache as reported by mod_status. +* Allow statements accept additionally numeric networks in IP/MASK + syntax: + allow 192.168.1.0/255.255.255.0 + allow 10.0.0.0/8 + BUGFIXES: * Fix total real memory usage statistic on Darwin. Binary files monit.orig/doc/presentation.sxi and monit/doc/presentation.sxi differ diff -ur -x CVS monit.orig/http/cervlet.c monit/http/cervlet.c --- monit.orig/http/cervlet.c 2004-12-19 19:43:34.000000000 +0100 +++ monit/http/cervlet.c 2004-12-19 18:11:56.000000000 +0100 @@ -433,10 +433,10 @@ out_print(res, "httpd auth. style%s", - (Run.credentials!=NULL)&&has_hosts_allow()? - "Basic Authentication and Host allow list": + (Run.credentials!=NULL)&&(has_hosts_allow())? + "Basic Authentication and Host/Net allow list": (Run.credentials!=NULL)?"Basic Authentication": - has_hosts_allow()?"Host allow list": + (has_hosts_allow())?"Host/Net allow list": "No authentication"); print_alerts(res, Run.maillist); diff -ur -x CVS monit.orig/http/engine.c monit/http/engine.c --- monit.orig/http/engine.c 2004-10-30 15:04:53.000000000 +0200 +++ monit/http/engine.c 2004-12-19 19:38:45.000000000 +0100 @@ -66,6 +66,10 @@ #include #endif +#ifdef HAVE_CTYPE_H +#include +#endif + #ifdef HAVE_STRINGS_H #include #endif @@ -117,6 +121,10 @@ static volatile int stopped= FALSE; ssl_server_connection *mySSLServerConnection= NULL; static pthread_mutex_t hostlist_mutex= PTHREAD_MUTEX_INITIALIZER; +struct ulong_net { + unsigned long network; + unsigned long mask; +}; /* -------------------------------------------------------------- Prototypes */ @@ -124,11 +132,11 @@ static void check_Impl(); static void initialize_service(); -static int authenticate(const char*); -static int is_host_allow(const char *); +static int authenticate(const struct in_addr); +static int is_host_allow(const struct in_addr); static void destroy_host_allow(HostsAllow); static Socket_T socket_producer(int, int, void*); - +static int parse_network(char *, struct ulong_net *); /* ------------------------------------------------------------------ Public */ @@ -222,6 +230,7 @@ int add_host_allow(char *name) { struct hostent *hp; + struct in_addr *inp; if(! (hp= gethostbyname(name))) { @@ -234,9 +243,12 @@ NEW(h); while(*hp->h_addr_list) { + + inp = (struct in_addr *) *hp->h_addr_list++; - h->name= xstrdup( inet_ntoa( *(struct in_addr *) *hp->h_addr_list++)); - + h->network= inp->s_addr; + h->mask= 0xffffffff; + LOCK(hostlist_mutex) if(hostlist) { @@ -244,20 +256,28 @@ HostsAllow p, n; for(n= p= hostlist; p; n= p, p= p->next) { - - if(!strcasecmp(p->name, name)) { - + + if((p->network == h->network) && ((p->mask == h->mask))) { + DEBUG("%s: Debug: Skipping redundant host '%s' (%s).\n", + prog, name, inet_ntoa(*(struct in_addr *) &h->network)); + destroy_host_allow(h); goto done; } } - + + DEBUG("%s: Debug: Adding host allow '%s' (%s).\n", + prog, name, inet_ntoa(*(struct in_addr *) &h->network)); + n->next= h; } else { + DEBUG("%s: Debug: Adding host allow '%s' (%s).\n", + prog, name, inet_ntoa(*(struct in_addr *) &h->network)); + hostlist= h; } @@ -273,6 +293,71 @@ } +/** + * Add network allowed to connect to this server. + * @param s_network A network identifier in IP/mask format to be added + * to the hosts allow list + * @return FALSE if no correct network identifier is provided, + * otherwise TRUE + */ + +int add_net_allow(char *s_network) { + + struct ulong_net net; + HostsAllow h; + + /* Add the network */ + + NEW(h); + + if (!parse_network(s_network, &net)) { + + return FALSE; + + } + + h->network=net.network; + h->mask=net.mask; + + LOCK(hostlist_mutex) + + if(hostlist) { + + HostsAllow p, n; + + for(n= p= hostlist; p; n= p, p= p->next) { + + if((p->network == net.network) && ((p->mask == net.mask))) { + + DEBUG("%s: Debug: Skipping redundant net '%s'.\n", + prog, s_network); + destroy_host_allow(h); + goto done; + + } + + } + + DEBUG("%s: Debug: Adding net allow '%s'.\n", + prog, s_network); + + n->next= h; + + } else { + + DEBUG("%s: Debug: Adding net allow '%s'.\n", + prog, s_network); + + hostlist= h; + + } + + done: + END_LOCK; + + return TRUE; +} + /** * Are any hosts present in the host allow list? @@ -307,6 +392,119 @@ } +/** + * Parse network string and return numeric IP and netmask + * @param s_network A network identifier in IP/mask format to be parsed + * @param net A structure holding IP and mask of the network + * @return FALSE if parsing failsm otherwise TRUE + */ +int parse_network(char *s_network, struct ulong_net *net) { + + char *temp=s_network; + char *copy; + char *longmask=NULL; + int shortmask=0; + int slashcount=0; + int dotcount=0; + int count=0; + int rv=FALSE; + struct in_addr inp; + + ASSERT(s_network); + ASSERT(net); + + copy=xstrdup(s_network); + temp=copy; + + /* decide if we have xxx.xxx.xxx.xxx/yyy or + xxx.xxx.xxx.xxx/yyy.yyy.yyy.yyy */ + while (*temp!=0) { + if (*temp=='/') { + if ((slashcount==1) || (dotcount !=3)) { + + goto done; + + } + *temp=0; + temp++; + longmask=temp; + count=0; + slashcount=1; + dotcount=0; + } else if (*temp=='.') { + + dotcount++; + + } else if (!isdigit(*temp)) { + + goto done; + + } + + count++; + temp++; + } + + if ((dotcount==0) && (count > 1) && (count < 4)) { + + shortmask=atoi(longmask); + longmask=NULL; + + } else if (dotcount != 3) { + + goto done; + + } + + /* Parse the network */ + + if (inet_aton(copy, &inp) == 0) { + + goto done; + + } + net->network=inp.s_addr; + + if (longmask==NULL) { + if ((shortmask > 32) || (shortmask < 0)) { + + goto done; + + } else if ( shortmask == 32 ) { + + net->mask=-1; + + } else { + + net->mask=(1<mask=inp.s_addr; + + } + + /* Remove bogus network components */ + net->network&=net->mask; + + /* Everything went fine, so we return TRUE! */ + rv=TRUE; + + done: + + FREE(copy); + return rv; + +} + /* ----------------------------------------------------------------- Private */ @@ -345,10 +543,10 @@ * FALSE. If allow Basic Authentication is defined in the Run.Auth * object, authentication is delegated to the processor module. */ -static int authenticate(const char *host) { +static int authenticate(const struct in_addr addr) { + + if(is_host_allow(addr)) { - if(is_host_allow(host)) { - return TRUE; } @@ -359,7 +557,8 @@ } - log("%s: Denied connection from non-authorized client [%s]\n", prog, host); + log("%s: Denied connection from non-authorized client [%s]\n", prog, + inet_ntoa(addr)); return FALSE; @@ -370,7 +569,7 @@ * Returns TRUE if host is allowed to connect to * this server */ -static int is_host_allow(const char *name) { +static int is_host_allow(const struct in_addr addr) { HostsAllow p; int rv= FALSE; @@ -379,8 +578,8 @@ for(p= hostlist; p; p= p->next) { - if(!strncasecmp(p->name, name, STRLEN)) { - + if((p->network & p->mask) == (addr.s_addr & p->mask)) { + rv= TRUE; break; @@ -390,6 +589,9 @@ END_LOCK; + if (rv) + return rv; + return rv; } @@ -439,7 +641,7 @@ goto error; } - if(! authenticate(inet_ntoa(in.sin_addr))) { + if(! authenticate(in.sin_addr)) { goto error; } @@ -467,7 +669,6 @@ destroy_host_allow(a->next); } - FREE(a->name); FREE(a); } diff -ur -x CVS monit.orig/http/engine.h monit/http/engine.h --- monit.orig/http/engine.h 2004-03-12 19:56:03.000000000 +0100 +++ monit/http/engine.h 2004-12-19 18:04:28.000000000 +0100 @@ -34,7 +34,8 @@ #define DEFAULT_QUEUE_LEN 10 typedef struct host_allow { - char *name; + unsigned long network; + unsigned long mask; /* For internal use */ struct host_allow *next; } *HostsAllow; @@ -43,6 +44,7 @@ void start_httpd(int port, int backlog, char *bindAddr); void stop_httpd(); int add_host_allow(char *); +int add_net_allow(char *); int has_hosts_allow(); void destroy_hosts_allow(); diff -ur -x CVS monit.orig/monit.pod monit/monit.pod --- monit.orig/monit.pod 2004-12-19 19:43:31.000000000 +0100 +++ monit/monit.pod 2004-12-19 19:39:40.000000000 +0100 @@ -2015,13 +2015,15 @@ validation). Both schema's can be used together or by itself. You B choose at least one. -=head4 Host allow list +=head4 Host and network allow list -The http server maintains an access-control list of hosts allowed -to connect to the server. You can add as many hosts as you want -to, but only hosts with a valid domain name or its IP address are -allowed. If you specify a hostname that does not resolve, monit -will write an error message in the console and not start. +The http server maintains an access-control list of hosts and +networks allowed to connect to the server. You can add as many +hosts as you want to, but only hosts with a valid domain name +or its IP address are allowed. If you specify a hostname that +does not resolve, monit will write an error message in the console +and not start. Networks require a network IP and a netmask to be +accepted. The http server will query a name server to check any hosts connecting to the server. If a host (client) is trying to connect @@ -2035,6 +2037,8 @@ allow localhost allow my.other.work.machine.com allow 10.1.1.1 + allow 192.168.1.0/255.255.255.0 + allow 10.0.0.0/8 Clients, not mentioned in the allow list that tries to connect to the server are logged with their ip-address. diff -ur -x CVS monit.orig/p.y monit/p.y --- monit.orig/p.y 2004-12-19 19:43:31.000000000 +0100 +++ monit/p.y 2004-12-19 19:46:19.000000000 +0100 @@ -569,12 +569,11 @@ | ALLOW CRYPT PATH { htpasswd_file= $3; digesttype= DIGEST_CRYPT; } allowuserlist { FREE(htpasswd_file);} - | ALLOW STRING { - if(!add_host_allow($2)) { - yyerror2("hostname did not resolve",$2); - } - FREE($2); - } + | ALLOW STRING { ;if (! (add_net_allow($2) || add_host_allow($2))) { + yyerror2("erroneous network or host identifier %s", $2); + } + FREE($2); + } ; allowuserlist : allowuser Exit 2