Imported Upstream version 2.15
This commit is contained in:
64
src/Makefile.in
Normal file
64
src/Makefile.in
Normal file
@@ -0,0 +1,64 @@
|
||||
###############################
|
||||
# Makefile for NRPE
|
||||
#
|
||||
# Last Modified: 08-13-2007
|
||||
###############################
|
||||
|
||||
srcdir=@srcdir@
|
||||
|
||||
# Source code directories
|
||||
SRC_INCLUDE=@srcdir@/../include
|
||||
CFG_INCLUDE=../include
|
||||
|
||||
CC=@CC@
|
||||
CFLAGS=@CFLAGS@ @DEFS@ -I $(CFG_INCLUDE) -I $(SRC_INCLUDE)
|
||||
LDFLAGS=@LDFLAGS@ @LIBS@
|
||||
SOCKETLIBS=@SOCKETLIBS@
|
||||
LIBWRAPLIBS=@LIBWRAPLIBS@
|
||||
OTHERLIBS=@OTHERLIBS@
|
||||
|
||||
CP=@CP@
|
||||
|
||||
prefix=@prefix@
|
||||
exec_prefix=@exec_prefix@
|
||||
CFGDIR=@sysconfdir@
|
||||
BINDIR=@bindir@
|
||||
SBINDIR=@sbindir@
|
||||
LIBEXECDIR=@libexecdir@
|
||||
INSTALL=@INSTALL@
|
||||
NAGIOS_INSTALL_OPTS=@NAGIOS_INSTALL_OPTS@
|
||||
NRPE_INSTALL_OPTS=@NRPE_INSTALL_OPTS@
|
||||
|
||||
# Generated automatically from configure script
|
||||
SNPRINTF_O=@SNPRINTF_O@
|
||||
|
||||
|
||||
all: nrpe check_nrpe
|
||||
|
||||
nrpe: $(srcdir)/nrpe.c $(srcdir)/utils.c $(srcdir)/acl.c $(SRC_INCLUDE)/nrpe.h $(SRC_INCLUDE)/utils.h $(SRC_INCLUDE)/common.h $(CFG_INCLUDE)/config.h $(SRC_INCLUDE)/acl.h $(SNPRINTF_O)
|
||||
$(CC) $(CFLAGS) -o $@ $(srcdir)/nrpe.c $(srcdir)/utils.c $(srcdir)/acl.c $(LDFLAGS) $(SOCKETLIBS) $(LIBWRAPLIBS) $(SNPRINTF_O) $(OTHERLIBS)
|
||||
|
||||
check_nrpe: $(srcdir)/check_nrpe.c $(srcdir)/utils.c $(SRC_INCLUDE)/utils.h $(SRC_INCLUDE)/common.h $(CFG_INCLUDE)/config.h
|
||||
$(CC) $(CFLAGS) -o $@ $(srcdir)/check_nrpe.c $(srcdir)/utils.c $(LDFLAGS) $(SOCKETLIBS) $(OTHERLIBS)
|
||||
|
||||
install:
|
||||
$(MAKE) install-plugin
|
||||
$(MAKE) install-daemon
|
||||
|
||||
install-plugin:
|
||||
$(INSTALL) -m 775 $(NAGIOS_INSTALL_OPTS) -d $(DESTDIR)$(LIBEXECDIR)
|
||||
$(INSTALL) -m 775 $(NAGIOS_INSTALL_OPTS) check_nrpe $(DESTDIR)$(LIBEXECDIR)
|
||||
|
||||
install-daemon:
|
||||
$(INSTALL) -m 775 $(NAGIOS_INSTALL_OPTS) -d $(DESTDIR)$(BINDIR)
|
||||
$(INSTALL) -m 775 $(NRPE_INSTALL_OPTS) nrpe $(DESTDIR)$(BINDIR)
|
||||
|
||||
clean:
|
||||
rm -f core nrpe check_nrpe $(SNPRINTF_O)
|
||||
rm -f *~ */*~
|
||||
rm -rf nrpe.dSYM check_nrpe.dSYM
|
||||
|
||||
distclean: clean
|
||||
rm -f Makefile
|
||||
|
||||
devclean: distclean
|
||||
613
src/acl.c
Normal file
613
src/acl.c
Normal file
@@ -0,0 +1,613 @@
|
||||
/*-
|
||||
* acl.c - a small library for nrpe.c. It adds IPv4 subnets support to ACL in nrpe.
|
||||
* Copyright (c) 2011 Kaspersky Lab ZAO
|
||||
* Last Modified: 08-10-2011 by Konstantin Malov with Oleg Koreshkov's help
|
||||
*
|
||||
* Description:
|
||||
* acl.c creates two linked lists. One is for IPv4 hosts and networks, another is for domain names.
|
||||
* All connecting hosts (if allowed_hosts is defined) are checked in these two lists.
|
||||
*
|
||||
* Some notes:
|
||||
* 1) IPv6 isn't supported in ACL.
|
||||
* 2) Only ANCII names are supported in ACL.
|
||||
*
|
||||
* License: GPL
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <netdb.h>
|
||||
#include <syslog.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "../include/acl.h"
|
||||
|
||||
/* This function checks if a char argumnet from valid char range.
|
||||
* Valid range is: ASCII only, a number or a letter, a space, a dot, a slash, a dash, a comma.
|
||||
*
|
||||
* Returns:
|
||||
* 0 - char isn't from valid group
|
||||
* 1 - char is a number
|
||||
* 2 - char is a letter
|
||||
* 3 - char is a space(' ')
|
||||
* 4 - char is a dot('.')
|
||||
* 5 - char is a slash('/')
|
||||
* 6 - char is a dash('-')
|
||||
* 7 - char is a comma(',')
|
||||
*/
|
||||
|
||||
int isvalidchar(int c) {
|
||||
if (!isascii(c))
|
||||
return 0;
|
||||
|
||||
if (isdigit(c))
|
||||
return 1;
|
||||
|
||||
if (isalpha(c))
|
||||
return 2;
|
||||
|
||||
if (isspace(c))
|
||||
return 3;
|
||||
|
||||
switch (c) {
|
||||
case '.':
|
||||
return 4;
|
||||
break;
|
||||
case '/':
|
||||
return 5;
|
||||
break;
|
||||
case '-':
|
||||
return 6;
|
||||
break;
|
||||
case ',':
|
||||
return 7;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Get substring from allowed_hosts from s position to e position.
|
||||
*/
|
||||
|
||||
char * acl_substring(char *string, int s, int e) {
|
||||
char *substring;
|
||||
int len = e - s;
|
||||
|
||||
if (len < 0)
|
||||
return NULL;
|
||||
|
||||
if ( (substring = malloc(len + 1)) == NULL)
|
||||
return NULL;
|
||||
|
||||
memmove(substring, string + s, len + 1);
|
||||
return substring;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add IPv4 host or network to IP ACL. IPv4 format is X.X.X.X[/X].
|
||||
* Host will be added to ACL only if it has passed IPv4 format check.
|
||||
*
|
||||
* Returns:
|
||||
* 1 - on success
|
||||
* 0 - on failure
|
||||
*
|
||||
* States for IPv4 format check:
|
||||
* 0 - numbers(-> 1), dot(-> -1), slash(-> -1), other(-> -1)
|
||||
* 1 - numbers(-> 1), dot(-> 2), slash(-> -1), other(-> -1)
|
||||
* 2 - numbers(-> 3), dot(-> -1), slash(-> -1), other(-> -1)
|
||||
* 3 - numbers(-> 3), dot(-> 4), slash(-> -1), other(-> -1)
|
||||
* 4 - numbers(-> 5), dot(-> -1), slash(-> -1), other(-> -1)
|
||||
* 5 - numbers(-> 5), dot(-> 6), slash(-> -1), other(-> -1)
|
||||
* 6 - numbers(-> 7), dot(-> -1), slash(-> -1), other(-> -1)
|
||||
* 7 - numbers(-> 7), dor(-> -1), slash(-> 8), other(-> -1)
|
||||
* 8 - numbers(-> 9), dor(-> -1), slash(-> -1), other(-> -1)
|
||||
* 9 - numbers(-> 9), dot(-> -1), slash(-> -1), other(-> -1)
|
||||
*
|
||||
* Good states are 7(IPv4 host) and 9(IPv4 network)
|
||||
*/
|
||||
|
||||
int add_ipv4_to_acl(char *ipv4) {
|
||||
int state = 0;
|
||||
int octet = 0;
|
||||
int index = 0; /* position in data array */
|
||||
int data[5]; /* array to store ip octets and mask */
|
||||
int len = strlen(ipv4);
|
||||
int i, c;
|
||||
unsigned long ip, mask;
|
||||
struct ip_acl *ip_acl_curr;
|
||||
|
||||
/* Check for min and max IPv4 valid length */
|
||||
if (len < 7 || len > 18)
|
||||
return 0;
|
||||
|
||||
/* default mask for ipv4 */
|
||||
data[4] = 32;
|
||||
|
||||
/* Basic IPv4 format check */
|
||||
for (i = 0; i < len; i++) {
|
||||
/* Return 0 on error state */
|
||||
if (state == -1)
|
||||
return 0;
|
||||
|
||||
c = ipv4[i];
|
||||
|
||||
switch (c) {
|
||||
case '0': case '1': case '2': case '3': case '4':
|
||||
case '5': case '6': case '7': case '8': case '9':
|
||||
octet = octet * 10 + CHAR_TO_NUMBER(c);
|
||||
switch (state) {
|
||||
case 0: case 2: case 4: case 6: case 8:
|
||||
state++;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case '.':
|
||||
switch (state) {
|
||||
case 1: case 3: case 5:
|
||||
data[index++] = octet;
|
||||
octet = 0;
|
||||
state++;
|
||||
break;
|
||||
default:
|
||||
state = -1;
|
||||
}
|
||||
break;
|
||||
case '/':
|
||||
switch (state) {
|
||||
case 7:
|
||||
data[index++] = octet;
|
||||
octet = 0;
|
||||
state++;
|
||||
break;
|
||||
default:
|
||||
state = -1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
state = -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Exit state handling */
|
||||
switch (state) {
|
||||
case 7: case 9:
|
||||
data[index] = octet;
|
||||
break;
|
||||
default:
|
||||
/* Bad states */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Final IPv4 format check.
|
||||
*/
|
||||
for (i=0; i < 4; i++) {
|
||||
if (data[i] < 0 || data[i] > 255) {
|
||||
syslog(LOG_ERR,"Invalid IPv4 address/network format(%s) in allowed_hosts option\n",ipv4);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (data[4] < 0 || data[4] > 32) {
|
||||
syslog(LOG_ERR,"Invalid IPv4 network mask format(%s) in allowed_hosts option\n",ipv4);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Conver ip and mask to unsigned long */
|
||||
ip = htonl((data[0] << 24) + (data[1] << 16) + (data[2] << 8) + data[3]);
|
||||
mask = htonl(-1 << (32 - data[4]));
|
||||
|
||||
/* Wrong network address */
|
||||
if ( (ip & mask) != ip) {
|
||||
syslog(LOG_ERR,"IP address and mask do not match in %s\n",ipv4);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Add addr to ip_acl list */
|
||||
if ( (ip_acl_curr = malloc(sizeof(*ip_acl_curr))) == NULL) {
|
||||
syslog(LOG_ERR,"Can't allocate memory for ACL, malloc error\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Save result in ACL ip list */
|
||||
ip_acl_curr->family = AF_INET;
|
||||
ip_acl_curr->addr.s_addr = ip;
|
||||
ip_acl_curr->mask.s_addr = mask;
|
||||
ip_acl_curr->next = NULL;
|
||||
|
||||
if (ip_acl_head == NULL) {
|
||||
ip_acl_head = ip_acl_curr;
|
||||
} else {
|
||||
ip_acl_prev->next = ip_acl_curr;
|
||||
}
|
||||
ip_acl_prev = ip_acl_curr;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add IPv6 host or network to IP ACL. Host will be added to ACL only if
|
||||
* it has passed IPv6 format check.
|
||||
*
|
||||
*/
|
||||
|
||||
int add_ipv6_to_acl(char *ipv6) {
|
||||
char *ipv6tmp;
|
||||
char *addrtok;
|
||||
char *addrsave;
|
||||
struct in6_addr addr;
|
||||
struct in6_addr mask;
|
||||
int maskval;
|
||||
int byte, bit;
|
||||
int nbytes = sizeof(mask.s6_addr) / sizeof(mask.s6_addr[0]);
|
||||
int x;
|
||||
struct ip_acl *ip_acl_curr;
|
||||
|
||||
/* Save temporary copy of ipv6 so we can use the original in error
|
||||
messages if needed */
|
||||
ipv6tmp = strdup(ipv6);
|
||||
if(NULL == ipv6tmp) {
|
||||
syslog(LOG_ERR, "Memory allocation failed for copy of address: %s\n",
|
||||
ipv6);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Parse the address itself */
|
||||
addrtok = strtok_r(ipv6tmp, "/", &addrsave);
|
||||
if(inet_pton(AF_INET6, addrtok, &addr) <= 0) {
|
||||
syslog(LOG_ERR, "Invalid IPv6 address in ACL: %s\n", ipv6);
|
||||
free(ipv6tmp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check whether there is a netmask */
|
||||
addrtok = strtok_r(NULL, "/", &addrsave);
|
||||
if(NULL != addrtok) {
|
||||
/* If so, build a netmask */
|
||||
|
||||
/* Get the number of bits in the mask */
|
||||
maskval = atoi(addrtok);
|
||||
if(maskval < 0 || maskval > 128) {
|
||||
syslog(LOG_ERR, "Invalid IPv6 netmask in ACL: %s\n", ipv6);
|
||||
free(ipv6tmp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Initialize to zero */
|
||||
for(x = 0; x < nbytes; x++) {
|
||||
mask.s6_addr[x] = 0;
|
||||
}
|
||||
|
||||
/* Set mask based on mask bits */
|
||||
byte = 0;
|
||||
bit = 7;
|
||||
while(maskval > 0) {
|
||||
mask.s6_addr[byte] |= 1 << bit;
|
||||
bit -= 1;
|
||||
if(bit < 0) {
|
||||
bit = 7;
|
||||
byte++;
|
||||
}
|
||||
maskval--;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Otherwise, this is a single address */
|
||||
for(x = 0; x < nbytes; x++) {
|
||||
mask.s6_addr[x] = 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add address to ip_acl list */
|
||||
ip_acl_curr = malloc(sizeof(*ip_acl_curr));
|
||||
if(NULL == ip_acl_curr) {
|
||||
syslog(LOG_ERR, "Memory allocation failed for ACL: %s\n", ipv6);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Save result in ACL ip list */
|
||||
ip_acl_curr->family = AF_INET6;
|
||||
for(x = 0; x < nbytes; x++) {
|
||||
ip_acl_curr->addr6.s6_addr[x] =
|
||||
addr.s6_addr[x] & mask.s6_addr[x];
|
||||
ip_acl_curr->mask6.s6_addr[x] = mask.s6_addr[x];
|
||||
}
|
||||
ip_acl_curr->next = NULL;
|
||||
|
||||
if(NULL == ip_acl_head) {
|
||||
ip_acl_head = ip_acl_curr;
|
||||
}
|
||||
else {
|
||||
ip_acl_prev->next = ip_acl_curr;
|
||||
}
|
||||
ip_acl_prev = ip_acl_curr;
|
||||
|
||||
free(ipv6tmp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add domain to DNS ACL list
|
||||
* Domain will be added only if it has passed domain name check.
|
||||
*
|
||||
* In this case domain valid format is:
|
||||
* 1) Domain names must use only alphanumeric characters and dashes (-).
|
||||
* 2) Domain names mustn't begin or end with dashes (-).
|
||||
* 3) Domain names mustn't have more than 63 characters.
|
||||
*
|
||||
* Return:
|
||||
* 1 - for success
|
||||
* 0 - for failure
|
||||
*
|
||||
* 0 - alpha(-> 1), number(-> 1), dot(-> -1), dash(-> -1), all other(-> -1)
|
||||
* 1 - alpha(-> 1), number(-> 1), dot(-> 2), dash(-> 6), all other(-> -1)
|
||||
* 2 - alpha(-> 3), number(-> 1), dot(-> -1), dash(-> -1), all other(-> -1)
|
||||
* 3 - alpha(-> 4), number(-> 1), dot(-> 2), dash(-> 6), all other(-> -1)
|
||||
* 4 - alpha(-> 5), number(-> 1), dot(-> 2), dash(-> 6), all other(-> -1)
|
||||
* 5 - alpha(-> 1), number(-> 1), dot(-> 2), dash(-> 6), all other(-> -1)
|
||||
* 6 - alpha(-> 1), number(-> 1), dot(-> 2), dash(-> 6), all other(-> -1)
|
||||
|
||||
* For real FQDN only 4 and 5 states are good for exit.
|
||||
* I don't check if top domain exists (com, ru and etc.)
|
||||
* But in real life NRPE could work in LAN,
|
||||
* with local domain zones like .local or with names like 'mars' added to /etc/hosts.
|
||||
* So 1 is good state too. And maybe this check is not necessary at all...
|
||||
*/
|
||||
|
||||
int add_domain_to_acl(char *domain) {
|
||||
int state = 0;
|
||||
int len = strlen(domain);
|
||||
int i, c;
|
||||
|
||||
struct dns_acl *dns_acl_curr;
|
||||
|
||||
if (len > 63)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
c = domain[i];
|
||||
switch (isvalidchar(c)) {
|
||||
case 1:
|
||||
state = 1;
|
||||
break;
|
||||
case 2:
|
||||
switch (state) {
|
||||
case 0: case 1: case 5: case 6:
|
||||
state = 1;
|
||||
break;
|
||||
case 2: case 3: case 4:
|
||||
state++;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
switch (state) {
|
||||
case 0: case 2:
|
||||
state = -1;
|
||||
break;
|
||||
default:
|
||||
state = 2;
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
switch (state) {
|
||||
case 0: case 2:
|
||||
state = -1;
|
||||
break;
|
||||
default:
|
||||
state = 6;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* Not valid chars */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check exit code */
|
||||
switch (state) {
|
||||
case 1: case 4: case 5:
|
||||
/* Add name to domain ACL list */
|
||||
if ( (dns_acl_curr = malloc(sizeof(*dns_acl_curr))) == NULL) {
|
||||
syslog(LOG_ERR,"Can't allocate memory for ACL, malloc error\n");
|
||||
return 0;
|
||||
}
|
||||
strcpy(dns_acl_curr->domain, domain);
|
||||
dns_acl_curr->next = NULL;
|
||||
|
||||
if (dns_acl_head == NULL)
|
||||
dns_acl_head = dns_acl_curr;
|
||||
else
|
||||
dns_acl_prev->next = dns_acl_curr;
|
||||
|
||||
dns_acl_prev = dns_acl_curr;
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Checks connectiong host in ACL
|
||||
*
|
||||
* Returns:
|
||||
* 1 - on success
|
||||
* 0 - on failure
|
||||
*/
|
||||
|
||||
int is_an_allowed_host(int family, void *host) {
|
||||
struct ip_acl *ip_acl_curr = ip_acl_head;
|
||||
int nbytes;
|
||||
int x;
|
||||
struct dns_acl *dns_acl_curr = dns_acl_head;
|
||||
struct in_addr addr;
|
||||
struct in6_addr addr6;
|
||||
struct hostent *he;
|
||||
|
||||
while (ip_acl_curr != NULL) {
|
||||
if(ip_acl_curr->family == family) {
|
||||
switch(ip_acl_curr->family) {
|
||||
case AF_INET:
|
||||
if((((struct in_addr *)host)->s_addr &
|
||||
ip_acl_curr->mask.s_addr) ==
|
||||
ip_acl_curr->addr.s_addr) {
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case AF_INET6:
|
||||
nbytes = sizeof(ip_acl_curr->mask6.s6_addr) /
|
||||
sizeof(ip_acl_curr->mask6.s6_addr[0]);
|
||||
for(x = 0; x < nbytes; x++) {
|
||||
if((((struct in6_addr *)host)->s6_addr[x] &
|
||||
ip_acl_curr->mask6.s6_addr[x]) !=
|
||||
ip_acl_curr->addr6.s6_addr[x]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(x == nbytes) {
|
||||
/* All bytes in host's address pass the netmask mask */
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
ip_acl_curr = ip_acl_curr->next;
|
||||
}
|
||||
|
||||
while(dns_acl_curr != NULL) {
|
||||
he = gethostbyname(dns_acl_curr->domain);
|
||||
if (he == NULL) return 0;
|
||||
|
||||
while (*he->h_addr_list) {
|
||||
switch(he->h_addrtype) {
|
||||
case AF_INET:
|
||||
memmove((char *)&addr,*he->h_addr_list++, sizeof(addr));
|
||||
if (addr.s_addr == ((struct in_addr *)host)->s_addr) return 1;
|
||||
break;
|
||||
case AF_INET6:
|
||||
memcpy((char *)&addr6, *he->h_addr_list++, sizeof(addr6));
|
||||
for(x = 0; x < nbytes; x++) {
|
||||
if(addr6.s6_addr[x] !=
|
||||
((struct in6_addr *)host)->s6_addr[x]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(x == nbytes) {
|
||||
/* All bytes in host's address match the ACL */
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
dns_acl_curr = dns_acl_curr->next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The trim() function takes a source string and copies it to the destination string,
|
||||
* stripped of leading and training whitespace. The destination string must be
|
||||
* allocated at least as large as the source string.
|
||||
*/
|
||||
|
||||
void trim( char *src, char *dest) {
|
||||
char *sptr, *dptr;
|
||||
|
||||
for( sptr = src; isblank( *sptr) && *sptr; sptr++); /* Jump past leading spaces */
|
||||
for( dptr = dest; !isblank( *sptr) && *sptr; ) {
|
||||
*dptr = *sptr;
|
||||
sptr++;
|
||||
dptr++;
|
||||
}
|
||||
*dptr = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
/* This function splits allowed_hosts to substrings with comma(,) as a delimeter.
|
||||
* It doesn't check validness of ACL record (add_ipv4_to_acl() and add_domain_to_acl() do),
|
||||
* just trims spaces from ACL records.
|
||||
* After this it sends ACL records to add_ipv4_to_acl() or add_domain_to_acl().
|
||||
*/
|
||||
|
||||
void parse_allowed_hosts(char *allowed_hosts) {
|
||||
char *hosts = strdup( allowed_hosts); /* Copy since strtok* modifes original */
|
||||
char *saveptr;
|
||||
char *tok;
|
||||
const char *delim = ",";
|
||||
char *trimmed_tok;
|
||||
|
||||
tok = strtok_r( hosts, delim, &saveptr);
|
||||
while( tok) {
|
||||
trimmed_tok = malloc( sizeof( char) * ( strlen( tok) + 1));
|
||||
trim( tok, trimmed_tok);
|
||||
if( strlen( trimmed_tok) > 0) {
|
||||
if (!add_ipv4_to_acl(trimmed_tok) && !add_ipv6_to_acl(trimmed_tok)
|
||||
&& !add_domain_to_acl(trimmed_tok)) {
|
||||
syslog(LOG_ERR,"Can't add to ACL this record (%s). Check allowed_hosts option!\n",trimmed_tok);
|
||||
}
|
||||
}
|
||||
free( trimmed_tok);
|
||||
tok = strtok_r(( char *)0, delim, &saveptr);
|
||||
}
|
||||
|
||||
free( hosts);
|
||||
}
|
||||
|
||||
/*
|
||||
* Converts mask in unsigned long format to two digit prefix
|
||||
*/
|
||||
|
||||
unsigned int prefix_from_mask(struct in_addr mask) {
|
||||
int prefix = 0;
|
||||
unsigned long bit = 1;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 32; i++) {
|
||||
if (mask.s_addr & bit)
|
||||
prefix++;
|
||||
|
||||
bit = bit << 1;
|
||||
}
|
||||
return (prefix);
|
||||
}
|
||||
|
||||
/*
|
||||
* It shows all hosts in ACL lists
|
||||
*/
|
||||
|
||||
void show_acl_lists(void) {
|
||||
struct ip_acl *ip_acl_curr = ip_acl_head;
|
||||
struct dns_acl *dns_acl_curr = dns_acl_head;
|
||||
|
||||
while (ip_acl_curr != NULL) {
|
||||
printf(" IP ACL: %s/%u %u\n", inet_ntoa(ip_acl_curr->addr), prefix_from_mask(ip_acl_curr->mask), ip_acl_curr->addr.s_addr);
|
||||
ip_acl_curr = ip_acl_curr->next;
|
||||
}
|
||||
|
||||
while (dns_acl_curr != NULL) {
|
||||
printf("DNS ACL: %s\n", dns_acl_curr->domain);
|
||||
dns_acl_curr = dns_acl_curr->next;
|
||||
}
|
||||
}
|
||||
490
src/check_nrpe.c
Normal file
490
src/check_nrpe.c
Normal file
@@ -0,0 +1,490 @@
|
||||
/********************************************************************************************
|
||||
*
|
||||
* CHECK_NRPE.C - NRPE Plugin For Nagios
|
||||
* Copyright (c) 1999-2008 Ethan Galstad (nagios@nagios.org)
|
||||
* License: GPL
|
||||
*
|
||||
* Last Modified: 09-06-2013
|
||||
*
|
||||
* Command line: CHECK_NRPE -H <host_address> [-p port] [-c command] [-to to_sec]
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* This plugin will attempt to connect to the NRPE daemon on the specified server and port.
|
||||
* The daemon will attempt to run the command defined as [command]. Program output and
|
||||
* return code are sent back from the daemon and displayed as this plugin's own output and
|
||||
* return code.
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
#include "config.h"
|
||||
#include "common.h"
|
||||
#include "utils.h"
|
||||
|
||||
|
||||
#define DEFAULT_NRPE_COMMAND "_NRPE_CHECK" /* check version of NRPE daemon */
|
||||
|
||||
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;
|
||||
int sd;
|
||||
|
||||
char query[MAX_INPUT_BUFFER]="";
|
||||
|
||||
int show_help=FALSE;
|
||||
int show_license=FALSE;
|
||||
int show_version=FALSE;
|
||||
|
||||
#ifdef HAVE_SSL
|
||||
#ifdef __sun
|
||||
SSL_METHOD *meth;
|
||||
#else
|
||||
const SSL_METHOD *meth;
|
||||
#endif
|
||||
SSL_CTX *ctx;
|
||||
SSL *ssl;
|
||||
int use_ssl=TRUE;
|
||||
#else
|
||||
int use_ssl=FALSE;
|
||||
#endif
|
||||
|
||||
|
||||
int process_arguments(int,char **);
|
||||
void alarm_handler(int);
|
||||
int graceful_close(int,int);
|
||||
|
||||
|
||||
|
||||
|
||||
int main(int argc, char **argv){
|
||||
u_int32_t packet_crc32;
|
||||
u_int32_t calculated_crc32;
|
||||
int16_t result;
|
||||
int rc;
|
||||
packet send_packet;
|
||||
packet receive_packet;
|
||||
int bytes_to_send;
|
||||
int bytes_to_recv;
|
||||
|
||||
result=process_arguments(argc,argv);
|
||||
|
||||
if(result!=OK || show_help==TRUE || show_license==TRUE || show_version==TRUE){
|
||||
|
||||
if(result!=OK)
|
||||
printf("Incorrect command line arguments supplied\n");
|
||||
printf("\n");
|
||||
printf("NRPE Plugin for Nagios\n");
|
||||
printf("Copyright (c) 1999-2008 Ethan Galstad (nagios@nagios.org)\n");
|
||||
printf("Version: %s\n",PROGRAM_VERSION);
|
||||
printf("Last Modified: %s\n",MODIFICATION_DATE);
|
||||
printf("License: GPL v2 with exemptions (-l for more info)\n");
|
||||
#ifdef HAVE_SSL
|
||||
printf("SSL/TLS Available: Anonymous DH Mode, OpenSSL 0.9.6 or higher required\n");
|
||||
#endif
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
if(result!=OK || show_help==TRUE){
|
||||
|
||||
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(" <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");
|
||||
printf(" [arglist] = Optional arguments that should be passed to the command. Multiple\n");
|
||||
printf(" arguments should be separated by a space. If provided, this must be\n");
|
||||
printf(" the last option supplied on the command line.\n");
|
||||
printf("\n");
|
||||
printf("Note:\n");
|
||||
printf("This plugin requires that you have the NRPE daemon running on the remote host.\n");
|
||||
printf("You must also have configured the daemon to associate a specific plugin command\n");
|
||||
printf("with the [command] option you are specifying here. Upon receipt of the\n");
|
||||
printf("[command] argument, the NRPE daemon will run the appropriate plugin command and\n");
|
||||
printf("send the plugin output and return code back to *this* plugin. This allows you\n");
|
||||
printf("to execute plugins on remote hosts and 'fake' the results to make Nagios think\n");
|
||||
printf("the plugin is being run locally.\n");
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
if(show_license==TRUE)
|
||||
display_license();
|
||||
|
||||
if(result!=OK || show_help==TRUE || show_license==TRUE || show_version==TRUE)
|
||||
exit(STATE_UNKNOWN);
|
||||
|
||||
|
||||
/* generate the CRC 32 table */
|
||||
generate_crc32_table();
|
||||
|
||||
#ifdef HAVE_SSL
|
||||
/* initialize SSL */
|
||||
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){
|
||||
printf("CHECK_NRPE: Error - could not create SSL context.\n");
|
||||
exit(STATE_CRITICAL);
|
||||
}
|
||||
|
||||
/* ADDED 01/19/2004 */
|
||||
/* use only TLSv1 protocol */
|
||||
SSL_CTX_set_options(ctx,SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* initialize alarm signal handling */
|
||||
signal(SIGALRM,alarm_handler);
|
||||
|
||||
/* set socket timeout */
|
||||
alarm(socket_timeout);
|
||||
|
||||
/* try to connect to the host at the given port number */
|
||||
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 */
|
||||
if(result==STATE_OK && use_ssl==TRUE){
|
||||
if((ssl=SSL_new(ctx))!=NULL){
|
||||
SSL_CTX_set_cipher_list(ctx,"ADH");
|
||||
SSL_set_fd(ssl,sd);
|
||||
if((rc=SSL_connect(ssl))!=1){
|
||||
printf("CHECK_NRPE: Error - Could not complete SSL handshake.\n");
|
||||
#ifdef DEBUG
|
||||
printf("SSL_connect=%d\n",rc);
|
||||
/*
|
||||
rc=SSL_get_error(ssl,rc);
|
||||
printf("SSL_get_error=%d\n",rc);
|
||||
printf("ERR_get_error=%lu\n",ERR_get_error());
|
||||
printf("%s\n",ERR_error_string(rc,NULL));
|
||||
*/
|
||||
ERR_print_errors_fp(stdout);
|
||||
#endif
|
||||
result=STATE_CRITICAL;
|
||||
}
|
||||
}
|
||||
else{
|
||||
printf("CHECK_NRPE: Error - Could not create SSL connection structure.\n");
|
||||
result=STATE_CRITICAL;
|
||||
}
|
||||
|
||||
/* bail if we had errors */
|
||||
if(result!=STATE_OK){
|
||||
SSL_CTX_free(ctx);
|
||||
close(sd);
|
||||
exit(result);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* we're connected and ready to go */
|
||||
if(result==STATE_OK){
|
||||
|
||||
/* clear the packet buffer */
|
||||
bzero(&send_packet,sizeof(send_packet));
|
||||
|
||||
/* fill the packet with semi-random data */
|
||||
randomize_buffer((char *)&send_packet,sizeof(send_packet));
|
||||
|
||||
/* initialize packet data */
|
||||
send_packet.packet_version=(int16_t)htons(NRPE_PACKET_VERSION_2);
|
||||
send_packet.packet_type=(int16_t)htons(QUERY_PACKET);
|
||||
strncpy(&send_packet.buffer[0],query,MAX_PACKETBUFFER_LENGTH);
|
||||
send_packet.buffer[MAX_PACKETBUFFER_LENGTH-1]='\x0';
|
||||
|
||||
/* calculate the crc 32 value of the packet */
|
||||
send_packet.crc32_value=(u_int32_t)0L;
|
||||
calculated_crc32=calculate_crc32((char *)&send_packet,sizeof(send_packet));
|
||||
send_packet.crc32_value=(u_int32_t)htonl(calculated_crc32);
|
||||
|
||||
|
||||
/***** ENCRYPT REQUEST *****/
|
||||
|
||||
|
||||
/* send the packet */
|
||||
bytes_to_send=sizeof(send_packet);
|
||||
if(use_ssl==FALSE)
|
||||
rc=sendall(sd,(char *)&send_packet,&bytes_to_send);
|
||||
#ifdef HAVE_SSL
|
||||
else{
|
||||
rc=SSL_write(ssl,&send_packet,bytes_to_send);
|
||||
if(rc<0)
|
||||
rc=-1;
|
||||
}
|
||||
#endif
|
||||
if(rc==-1){
|
||||
printf("CHECK_NRPE: Error sending query to host.\n");
|
||||
close(sd);
|
||||
return STATE_UNKNOWN;
|
||||
}
|
||||
|
||||
/* wait for the response packet */
|
||||
bytes_to_recv=sizeof(receive_packet);
|
||||
if(use_ssl==FALSE)
|
||||
rc=recvall(sd,(char *)&receive_packet,&bytes_to_recv,socket_timeout);
|
||||
#ifdef HAVE_SSL
|
||||
else
|
||||
rc=SSL_read(ssl,&receive_packet,bytes_to_recv);
|
||||
#endif
|
||||
|
||||
/* reset timeout */
|
||||
alarm(0);
|
||||
|
||||
/* close the connection */
|
||||
#ifdef HAVE_SSL
|
||||
if(use_ssl==TRUE){
|
||||
SSL_shutdown(ssl);
|
||||
SSL_free(ssl);
|
||||
SSL_CTX_free(ctx);
|
||||
}
|
||||
#endif
|
||||
graceful_close(sd,1000);
|
||||
|
||||
/* recv() error */
|
||||
if(rc<0){
|
||||
printf("CHECK_NRPE: Error receiving data from daemon.\n");
|
||||
return STATE_UNKNOWN;
|
||||
}
|
||||
|
||||
/* server disconnected */
|
||||
else if(rc==0){
|
||||
printf("CHECK_NRPE: Received 0 bytes from daemon. Check the remote server logs for error messages.\n");
|
||||
return STATE_UNKNOWN;
|
||||
}
|
||||
|
||||
/* receive underflow */
|
||||
else if(bytes_to_recv<sizeof(receive_packet)){
|
||||
printf("CHECK_NRPE: Receive underflow - only %d bytes received (%d expected).\n",bytes_to_recv,sizeof(receive_packet));
|
||||
return STATE_UNKNOWN;
|
||||
}
|
||||
|
||||
|
||||
/***** DECRYPT RESPONSE *****/
|
||||
|
||||
|
||||
/* check the crc 32 value */
|
||||
packet_crc32=ntohl(receive_packet.crc32_value);
|
||||
receive_packet.crc32_value=0L;
|
||||
calculated_crc32=calculate_crc32((char *)&receive_packet,sizeof(receive_packet));
|
||||
if(packet_crc32!=calculated_crc32){
|
||||
printf("CHECK_NRPE: Response packet had invalid CRC32.\n");
|
||||
close(sd);
|
||||
return STATE_UNKNOWN;
|
||||
}
|
||||
|
||||
/* check packet version */
|
||||
if(ntohs(receive_packet.packet_version)!=NRPE_PACKET_VERSION_2){
|
||||
printf("CHECK_NRPE: Invalid packet version received from server.\n");
|
||||
close(sd);
|
||||
return STATE_UNKNOWN;
|
||||
}
|
||||
|
||||
/* check packet type */
|
||||
if(ntohs(receive_packet.packet_type)!=RESPONSE_PACKET){
|
||||
printf("CHECK_NRPE: Invalid packet type received from server.\n");
|
||||
close(sd);
|
||||
return STATE_UNKNOWN;
|
||||
}
|
||||
|
||||
/* get the return code from the remote plugin */
|
||||
result=(int16_t)ntohs(receive_packet.result_code);
|
||||
|
||||
/* print the output returned by the daemon */
|
||||
receive_packet.buffer[MAX_PACKETBUFFER_LENGTH-1]='\x0';
|
||||
if(!strcmp(receive_packet.buffer,""))
|
||||
printf("CHECK_NRPE: No output returned from daemon.\n");
|
||||
else
|
||||
printf("%s\n",receive_packet.buffer);
|
||||
}
|
||||
|
||||
/* reset the alarm */
|
||||
else
|
||||
alarm(0);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* process command line arguments */
|
||||
int process_arguments(int argc, char **argv){
|
||||
char optchars[MAX_INPUT_BUFFER];
|
||||
int argindex=0;
|
||||
int c=1;
|
||||
int i=1;
|
||||
|
||||
#ifdef HAVE_GETOPT_LONG
|
||||
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'},
|
||||
{"license", no_argument, 0, 'l'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
#endif
|
||||
|
||||
/* no options were supplied */
|
||||
if(argc<2)
|
||||
return ERROR;
|
||||
|
||||
snprintf(optchars,MAX_INPUT_BUFFER,"H:b:c:a:t:p:nu46hl");
|
||||
|
||||
while(1){
|
||||
#ifdef HAVE_GETOPT_LONG
|
||||
c=getopt_long(argc,argv,optchars,long_options,&option_index);
|
||||
#else
|
||||
c=getopt(argc,argv,optchars);
|
||||
#endif
|
||||
if(c==-1 || c==EOF)
|
||||
break;
|
||||
|
||||
/* process all arguments */
|
||||
switch(c){
|
||||
|
||||
case '?':
|
||||
case 'h':
|
||||
show_help=TRUE;
|
||||
break;
|
||||
case 'b':
|
||||
bind_address=strdup(optarg);
|
||||
break;
|
||||
case 'V':
|
||||
show_version=TRUE;
|
||||
break;
|
||||
case 'l':
|
||||
show_license=TRUE;
|
||||
break;
|
||||
case 't':
|
||||
socket_timeout=atoi(optarg);
|
||||
if(socket_timeout<=0)
|
||||
return ERROR;
|
||||
break;
|
||||
case 'p':
|
||||
server_port=atoi(optarg);
|
||||
if(server_port<=0)
|
||||
return ERROR;
|
||||
break;
|
||||
case 'H':
|
||||
server_name=strdup(optarg);
|
||||
break;
|
||||
case 'c':
|
||||
command_name=strdup(optarg);
|
||||
break;
|
||||
case 'a':
|
||||
argindex=optind;
|
||||
break;
|
||||
case 'n':
|
||||
use_ssl=FALSE;
|
||||
break;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/* determine (base) command query */
|
||||
snprintf(query,sizeof(query),"%s",(command_name==NULL)?DEFAULT_NRPE_COMMAND:command_name);
|
||||
query[sizeof(query)-1]='\x0';
|
||||
|
||||
/* get the command args */
|
||||
if(argindex>0){
|
||||
|
||||
for(c=argindex-1;c<argc;c++){
|
||||
|
||||
i=sizeof(query)-strlen(query)-2;
|
||||
if(i<=0)
|
||||
break;
|
||||
|
||||
strcat(query,"!");
|
||||
strncat(query,argv[c],i);
|
||||
query[sizeof(query)-1]='\x0';
|
||||
}
|
||||
}
|
||||
|
||||
/* make sure required args were supplied */
|
||||
if(server_name==NULL && show_help==FALSE && show_version==FALSE && show_license==FALSE)
|
||||
return ERROR;
|
||||
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void alarm_handler(int sig){
|
||||
|
||||
printf("CHECK_NRPE: Socket timeout after %d seconds.\n",socket_timeout);
|
||||
|
||||
exit(timeout_return_code);
|
||||
}
|
||||
|
||||
|
||||
/* submitted by Mark Plaksin 08/31/2006 */
|
||||
int graceful_close(int sd, int timeout){
|
||||
fd_set in;
|
||||
struct timeval tv;
|
||||
char buf[1000];
|
||||
|
||||
/* send FIN packet */
|
||||
shutdown(sd,SHUT_WR);
|
||||
for(;;){
|
||||
|
||||
FD_ZERO(&in);
|
||||
FD_SET(sd,&in);
|
||||
tv.tv_sec=timeout/1000;
|
||||
tv.tv_usec=(timeout % 1000)*1000;
|
||||
|
||||
/* timeout or error */
|
||||
if(1!=select(sd+1,&in,NULL,NULL,&tv))
|
||||
break;
|
||||
|
||||
/* no more data (FIN or RST) */
|
||||
if(0>=recv(sd,buf,sizeof(buf),0))
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef HAVE_CLOSESOCKET
|
||||
closesocket(sd);
|
||||
#else
|
||||
close(sd);
|
||||
#endif
|
||||
|
||||
return OK;
|
||||
}
|
||||
2162
src/nrpe.c
Normal file
2162
src/nrpe.c
Normal file
File diff suppressed because it is too large
Load Diff
1452
src/snprintf.c
Normal file
1452
src/snprintf.c
Normal file
File diff suppressed because it is too large
Load Diff
390
src/utils.c
Normal file
390
src/utils.c
Normal file
@@ -0,0 +1,390 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* UTILS.C - NRPE Utility Functions
|
||||
*
|
||||
* License: GPL
|
||||
* Copyright (c) 1999-2006 Ethan Galstad (nagios@nagios.org)
|
||||
*
|
||||
* Last Modified: 12-11-2006
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* This file contains common network functions used in nrpe and check_nrpe.
|
||||
*
|
||||
* License Information:
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include "../include/common.h"
|
||||
#include "../include/utils.h"
|
||||
|
||||
#ifndef NI_MAXSERV
|
||||
#define NI_MAXSERV 32
|
||||
#endif
|
||||
|
||||
#ifndef NI_MAXHOST
|
||||
#define NI_MAXHOST 1025
|
||||
#endif
|
||||
|
||||
static unsigned long crc32_table[256];
|
||||
|
||||
|
||||
|
||||
/* build the crc table - must be called before calculating the crc value */
|
||||
void generate_crc32_table(void){
|
||||
unsigned long crc, poly;
|
||||
int i, j;
|
||||
|
||||
poly=0xEDB88320L;
|
||||
for(i=0;i<256;i++){
|
||||
crc=i;
|
||||
for(j=8;j>0;j--){
|
||||
if(crc & 1)
|
||||
crc=(crc>>1)^poly;
|
||||
else
|
||||
crc>>=1;
|
||||
}
|
||||
crc32_table[i]=crc;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* calculates the CRC 32 value for a buffer */
|
||||
unsigned long calculate_crc32(char *buffer, int buffer_size){
|
||||
register unsigned long crc;
|
||||
int this_char;
|
||||
int current_index;
|
||||
|
||||
crc=0xFFFFFFFF;
|
||||
|
||||
for(current_index=0;current_index<buffer_size;current_index++){
|
||||
this_char=(int)buffer[current_index];
|
||||
crc=((crc>>8) & 0x00FFFFFF) ^ crc32_table[(crc ^ this_char) & 0xFF];
|
||||
}
|
||||
|
||||
return (crc ^ 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
|
||||
/* fill a buffer with semi-random data */
|
||||
void randomize_buffer(char *buffer,int buffer_size){
|
||||
FILE *fp;
|
||||
int x;
|
||||
int seed;
|
||||
|
||||
/**** FILL BUFFER WITH RANDOM ALPHA-NUMERIC CHARACTERS ****/
|
||||
|
||||
/***************************************************************
|
||||
Only use alpha-numeric characters becase plugins usually
|
||||
only generate numbers and letters in their output. We
|
||||
want the buffer to contain the same set of characters as
|
||||
plugins, so its harder to distinguish where the real output
|
||||
ends and the rest of the buffer (padded randomly) starts.
|
||||
***************************************************************/
|
||||
|
||||
/* try to get seed value from /dev/urandom, as its a better source of entropy */
|
||||
fp=fopen("/dev/urandom","r");
|
||||
if(fp!=NULL){
|
||||
seed=fgetc(fp);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
/* else fallback to using the current time as the seed */
|
||||
else
|
||||
seed=(int)time(NULL);
|
||||
|
||||
srand(seed);
|
||||
for(x=0;x<buffer_size;x++)
|
||||
buffer[x]=(int)'0'+(int)(72.0*rand()/(RAND_MAX+1.0));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 for connecting. */
|
||||
sock = my_create_socket(ai, bind_address);
|
||||
if (sock < 0) {
|
||||
/* Any error is already output */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (connect(sock, ai->ai_addr, ai->ai_addrlen) >= 0) {
|
||||
/* Successful connection. */
|
||||
memcpy(hostaddr, ai->ai_addr, ai->ai_addrlen);
|
||||
break;
|
||||
}
|
||||
else {
|
||||
fprintf(stderr,"connect to address %s port %s: %s\n", ntop, strport,
|
||||
strerror(errno));
|
||||
close(sock);
|
||||
sock = -1;
|
||||
}
|
||||
}
|
||||
|
||||
freeaddrinfo(aitop);
|
||||
|
||||
/* Return failure if we didn't get a successful connection. */
|
||||
if (sock == -1) {
|
||||
fprintf(stderr, "connect to host %s port %s: %s", host, strport,
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
return sock;
|
||||
}
|
||||
|
||||
/* 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){
|
||||
int x;
|
||||
int index;
|
||||
|
||||
for(x=strlen(buffer);x>=1;x--){
|
||||
index=x-1;
|
||||
if(buffer[index]==' ' || buffer[index]=='\r' || buffer[index]=='\n' || buffer[index]=='\t')
|
||||
buffer[index]='\x0';
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* sends all data - thanks to Beej's Guide to Network Programming */
|
||||
int sendall(int s, char *buf, int *len){
|
||||
int total=0;
|
||||
int bytesleft=*len;
|
||||
int n=0;
|
||||
|
||||
/* send all the data */
|
||||
while(total<*len){
|
||||
|
||||
/* send some data */
|
||||
n=send(s,buf+total,bytesleft,0);
|
||||
|
||||
/* break on error */
|
||||
if(n==-1)
|
||||
break;
|
||||
|
||||
/* apply bytes we sent */
|
||||
total+=n;
|
||||
bytesleft-=n;
|
||||
}
|
||||
|
||||
/* return number of bytes actually send here */
|
||||
*len=total;
|
||||
|
||||
/* return -1 on failure, 0 on success */
|
||||
return n==-1?-1:0;
|
||||
}
|
||||
|
||||
|
||||
/* receives all data - modelled after sendall() */
|
||||
int recvall(int s, char *buf, int *len, int timeout){
|
||||
int total=0;
|
||||
int bytesleft=*len;
|
||||
int n=0;
|
||||
time_t start_time;
|
||||
time_t current_time;
|
||||
|
||||
/* clear the receive buffer */
|
||||
bzero(buf,*len);
|
||||
|
||||
time(&start_time);
|
||||
|
||||
/* receive all data */
|
||||
while(total<*len){
|
||||
|
||||
/* receive some data */
|
||||
n=recv(s,buf+total,bytesleft,0);
|
||||
|
||||
/* no data has arrived yet (non-blocking socket) */
|
||||
if(n==-1 && errno==EAGAIN){
|
||||
time(¤t_time);
|
||||
if(current_time-start_time>timeout)
|
||||
break;
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* receive error or client disconnect */
|
||||
else if(n<=0)
|
||||
break;
|
||||
|
||||
/* apply bytes we received */
|
||||
total+=n;
|
||||
bytesleft-=n;
|
||||
}
|
||||
|
||||
/* return number of bytes actually received here */
|
||||
*len=total;
|
||||
|
||||
/* return <=0 on failure, bytes received on success */
|
||||
return (n<=0)?n:total;
|
||||
}
|
||||
|
||||
|
||||
/* fixes compiler problems under Solaris, since strsep() isn't included */
|
||||
/* this code is taken from the glibc source */
|
||||
char *my_strsep (char **stringp, const char *delim){
|
||||
char *begin, *end;
|
||||
|
||||
begin = *stringp;
|
||||
if (begin == NULL)
|
||||
return NULL;
|
||||
|
||||
/* A frequent case is when the delimiter string contains only one
|
||||
character. Here we don't need to call the expensive `strpbrk'
|
||||
function and instead work using `strchr'. */
|
||||
if(delim[0]=='\0' || delim[1]=='\0'){
|
||||
char ch = delim[0];
|
||||
|
||||
if(ch=='\0')
|
||||
end=NULL;
|
||||
else{
|
||||
if(*begin==ch)
|
||||
end=begin;
|
||||
else
|
||||
end=strchr(begin+1,ch);
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
/* Find the end of the token. */
|
||||
end = strpbrk (begin, delim);
|
||||
|
||||
if(end){
|
||||
|
||||
/* Terminate the token and set *STRINGP past NUL character. */
|
||||
*end++='\0';
|
||||
*stringp=end;
|
||||
}
|
||||
else
|
||||
/* No more delimiters; this is the last token. */
|
||||
*stringp=NULL;
|
||||
|
||||
return begin;
|
||||
}
|
||||
|
||||
|
||||
/* show license */
|
||||
void display_license(void){
|
||||
|
||||
printf("This program is released under the GPL (see below) with the additional\n");
|
||||
printf("exemption that compiling, linking, and/or using OpenSSL is allowed.\n\n");
|
||||
|
||||
printf("This program is free software; you can redistribute it and/or modify\n");
|
||||
printf("it under the terms of the GNU General Public License as published by\n");
|
||||
printf("the Free Software Foundation; either version 2 of the License, or\n");
|
||||
printf("(at your option) any later version.\n\n");
|
||||
printf("This program is distributed in the hope that it will be useful,\n");
|
||||
printf("but WITHOUT ANY WARRANTY; without even the implied warranty of\n");
|
||||
printf("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n");
|
||||
printf("GNU General Public License for more details.\n\n");
|
||||
printf("You should have received a copy of the GNU General Public License\n");
|
||||
printf("along with this program; if not, write to the Free Software\n");
|
||||
printf("Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user