/*-
* Copyright (c) 2004 Free (Olivier Beyssac)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <syslog.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/param.h>
#include <unistd.h>
#include <time.h>
#include <errno.h>
#include <signal.h>
#include "options.h"
#include "cmd.h"
#include "iptree.h"
#include "ipinfo.h"
#include "utils.h"
#include "netlist.h"
#include "client.h"
#define MSG_BL (421)
#define MSG_NOBL (200)
#define MSG_AUTHF (600)
#define exiterror(ident, svc, svl, buf) \
do { \
syslog(LOG_ERR, "invalid request from %s: %s", ident, buf); \
restorebuf(svc, svl, buf); \
return 500; \
} while(0)
extern struct options opt;
/* Send notifications */
static void send_notifies(const char *ip)
{
int i;
pid_t pid;
struct sigaction sa;
if (!opt.notify_hosts)
return;
if ((pid = fork()) == -1) {
syslog(LOG_ERR, "fork() error: %s", strerror(errno));
return;
}
if (pid != 0)
return;
/* Detach from previous sigactions */
xsigaction(sa, SIGTERM, SIG_DFL);
xsigaction(sa, SIGINT, SIG_DFL);
xsigaction(sa, SIGUSR1, SIG_IGN);
xsigaction(sa, SIGUSR2, SIG_IGN);
xsigaction(sa, SIGCHLD, SIG_IGN);
for (i = 0; opt.notify_hosts[i]; i += 2) {
int sd, reply;
char *host = opt.notify_hosts[i];
char *port = opt.notify_hosts[i+1];
opt.notifies++;
if ((sd = client_connect(host, port)) == -1) {
syslog(LOG_ERR, "error (connect) while notifying %s to %s:%s",
ip, host, port);
} else {
if ((reply = client_send_cmdi(sd, CMD_INSERT, ip)) != 200
&& reply != 421)
syslog(LOG_ERR, "error (reply=%d) while notifying %s to %s:%s",
reply, ip, host, port);
else
syslog(LOG_INFO, "notified %s:%s about %s", host, port, ip);
close(sd);
}
}
exit(EXIT_SUCCESS);
}
/* Do the real stuff after command has been interpreted by read_cmd */
static int cmd_commit(const iptree ipt, const int cmd, const char *val,
const char *ident)
{
struct in_addr inp;
unsigned long ip;
time_t t;
int options = 0;
int bl = 0;
int notify = 0;
int code = 200;
int wl = 0;
int count = 1;
t = time(NULL);
if (!inet_aton(val, &inp)) {
syslog(LOG_ERR, "invalid IP address submitted by %s: %s", ident, val);
return 500;
}
ip = ntohl(inp.s_addr);
if (iptree_get_bl(ipt, ip, t)) {
bl = 1;
code = MSG_BL;
}
/* Check against whitelist */
wl = (netlist_getmode(opt.whitelist, ip) == 1);
if (cmd == CMD_DECR) {
opt.decrqueries++;
if (wl) {
syslog(LOG_INFO, "%s (wl) decremented by %s", val, ident);
return code;
}
count = -1;
} else if (cmd == CMD_INSERT) {
opt.insertqueries++;
options |= IPINFO_OPT_FORCED;
if (wl) {
syslog(LOG_INFO, "%s (wl) inserted by %s", val, ident);
return code;
}
} else if (cmd == CMD_SUBMIT) {
opt.submissions++;
if (wl) {
syslog(LOG_INFO, "%s (wl) submitted by %s", val, ident);
return code;
}
}
switch (cmd) {
case CMD_DECR:
/* Decrement IP count */
case CMD_INSERT:
/* IP insertion */
case CMD_SUBMIT:
/* IP submission */
if (iptree_add(ipt, ip, t, t, count, options)) {
if (cmd == CMD_SUBMIT) {
syslog(LOG_INFO, "%s submitted by %s", val, ident);
if (iptree_get_bl(ipt, ip, t)) {
notify = 1;
}
} else if (cmd == CMD_DECR) {
syslog(LOG_INFO, "%s decremented by %s", val, ident);
} else if (cmd == CMD_INSERT && !bl) {
syslog(LOG_INFO, "%s inserted by %s", val, ident);
notify = 1;
}
/* If the IP has just been put in the blacklist, send notifies */
if (!bl && notify) {
send_notifies(val);
code = MSG_BL;
}
} else
syslog(LOG_ERR, "error in iptree_add IP %s", val);
break;
case CMD_QUERY:
/* Check if an IP is blacklisted or not */
opt.blqueries++;
if (bl) {
opt.positive_blqueries++;
return MSG_BL;
} else
return MSG_NOBL;
break;
}
return code;
}
/* Read the command pointed to by cmd and update iptree
Return the code to show to client */
extern int read_cmd(char *buf, const ssize_t len, const char *ident,
const iptree ipt, const int mode)
{
char *p;
char svc, svctmp;
ssize_t svl;
int cmd = CMD_NO;
int code;
if (buf[len-1] == '\n' && buf[len-2] == '\r')
savebufpos(svc, svl, buf, len-2);
else {
savebufpos(svc, svl, buf, len);
exiterror(ident, svc, svl, buf);
}
if ((p = strchr(buf, '=')) == NULL)
exiterror(ident, svc, svl, buf);
svctmp = *p;
*p = '\0';
if (strcmp(buf, "ip") == 0)
cmd = CMD_SUBMIT;
else if (strcmp(buf, "ip?") == 0)
cmd = CMD_QUERY;
else if (strcmp(buf, "ipbl") == 0)
cmd = CMD_INSERT;
else if (strcmp(buf, "ipdecr") == 0)
cmd = CMD_DECR;
else {
opt.bad_requests++;
}
*p++ = svctmp;
/* Check client request against ACL */
if ((cmd == CMD_SUBMIT && !(mode & ACL_M_SUBMIT))
|| (cmd == CMD_QUERY && !(mode & ACL_M_QUERY))
|| (cmd == CMD_INSERT && !(mode & ACL_M_INSERT))
|| (cmd == CMD_DECR && !(mode & ACL_M_DECR))) {
syslog(LOG_INFO, "denied request from %s", ident);
opt.denied_requests++;
restorebuf(svc, svl, buf);
return MSG_AUTHF;
}
if (cmd == CMD_NO || (code = cmd_commit(ipt, cmd, p, ident)) == 0)
exiterror(ident, svc, svl, buf);
restorebuf(svc, svl, buf);
return code;
}
syntax highlighted by Code2HTML, v. 0.9.1