Make rate limiting work per-listening-socket. Log better messages than

before for this, requiring a new function (get_ipaddr()).  canohost.c
receives a $FreeBSD$ line.

Suggested by:	Niels Provos <niels@OpenBSD.org>
This commit is contained in:
green 2000-06-26 05:44:23 +00:00
parent 90829d8c1c
commit 6032b3e1eb
3 changed files with 68 additions and 30 deletions

View File

@ -11,6 +11,7 @@
*
* Functions for returning the canonical host name of the remote site.
*
* $FreeBSD$
*/
#include "includes.h"
@ -201,7 +202,7 @@ get_remote_ipaddr()
/* Get the IP address in ascii. */
if (getnameinfo((struct sockaddr *)&from, fromlen, ntop, sizeof(ntop),
NULL, 0, NI_NUMERICHOST) != 0)
fatal("get_remote_hostname: getnameinfo NI_NUMERICHOST failed");
fatal("get_remote_ipaddr: getnameinfo NI_NUMERICHOST failed");
canonical_host_ip = xstrdup(ntop);
@ -209,6 +210,35 @@ get_remote_ipaddr()
return canonical_host_ip;
}
/*
* Returns the IP-address of the local host as a string. The returned
* string must be freed.
*/
const char *
get_ipaddr(int socket)
{
static char *canonical_host_ip = NULL;
struct sockaddr_storage from;
socklen_t fromlen;
char ntop[NI_MAXHOST];
/* Get IP address of server. */
fromlen = sizeof(from);
memset(&from, 0, sizeof(from));
if (getsockname(socket, (struct sockaddr *)&from, &fromlen) < 0) {
debug("getsockname failed: %.100s", strerror(errno));
fatal_cleanup();
}
/* Get the IP address in ascii. */
if (getnameinfo((struct sockaddr *)&from, fromlen, ntop, sizeof(ntop),
NULL, 0, NI_NUMERICHOST) != 0)
fatal("get_local_ipaddr: getnameinfo NI_NUMERICHOST failed");
/* Return ip address string. */
return xstrdup(ntop);
}
/* Returns the local/remote port for the socket. */
int

View File

@ -363,6 +363,11 @@ char *get_remote_hostname(int socket);
*/
const char *get_canonical_hostname(void);
/*
* Returns the local IP address as an ascii string.
*/
const char *get_ipaddr(int socket);
/*
* Returns the remote IP address as an ascii string. The value need not be
* freed by the caller.

View File

@ -143,17 +143,17 @@ unsigned char *session_id2 = NULL;
int session_id2_len = 0;
/* These are used to implement connections_per_period. */
struct magic_connection {
struct ratelim_connection {
struct timeval connections_begin;
unsigned int connections_this_period;
} *magic_connections;
/* Magic number, too! TODO: this doesn't have to be static. */
const size_t MAGIC_CONNECTIONS_SIZE = 1;
} *ratelim_connections;
static __inline int
magic_hash(struct sockaddr *sa) {
return 0;
static void
ratelim_init(void) {
ratelim_connections = calloc(num_listen_socks,
sizeof(struct ratelim_connection));
if (ratelim_connections == NULL)
fatal("calloc: %s", strerror(errno));
}
static __inline struct timeval
@ -440,6 +440,7 @@ main(int ac, char **av)
int opt, sock_in = 0, sock_out = 0, newsock, i, fdsetsz, on = 1;
pid_t pid;
socklen_t fromlen;
int ratelim_exceeded = 0;
int silent = 0;
fd_set *fdset;
struct sockaddr_storage from;
@ -450,7 +451,6 @@ main(int ac, char **av)
struct addrinfo *ai;
char ntop[NI_MAXHOST], strport[NI_MAXSERV];
int listen_sock, maxfd;
int connections_per_period_exceeded = 0;
/* Save argv[0]. */
saved_argv = av;
@ -786,11 +786,7 @@ main(int ac, char **av)
fdsetsz = howmany(maxfd, NFDBITS) * sizeof(fd_mask);
fdset = (fd_set *)xmalloc(fdsetsz);
/* Initialize the magic_connections table. It's magical! */
magic_connections = calloc(MAGIC_CONNECTIONS_SIZE,
sizeof(struct magic_connection));
if (magic_connections == NULL)
fatal("calloc: %s", strerror(errno));
ratelim_init();
/*
* Stay listening for connections until the system crashes or
@ -825,22 +821,23 @@ main(int ac, char **av)
}
if (options.connections_per_period != 0) {
struct timeval diff, connections_end;
struct magic_connection *mc;
struct ratelim_connection *rc;
(void)gettimeofday(&connections_end, NULL);
mc = &magic_connections[magic_hash((struct sockaddr *)0)];
diff = timevaldiff(&mc->connections_begin, &connections_end);
rc = &ratelim_connections[i];
diff = timevaldiff(&rc->connections_begin,
&connections_end);
if (diff.tv_sec >= options.connections_period) {
/*
* Slide the window forward only after completely
* leaving it.
* Slide the window forward only after
* completely leaving it.
*/
mc->connections_begin = connections_end;
mc->connections_this_period = 1;
rc->connections_begin = connections_end;
rc->connections_this_period = 1;
} else {
if (++mc->connections_this_period >
if (++rc->connections_this_period >
options.connections_per_period)
connections_per_period_exceeded = 1;
ratelim_exceeded = 1;
}
}
@ -861,12 +858,18 @@ main(int ac, char **av)
sock_out = newsock;
pid = getpid();
break;
} else if (connections_per_period_exceeded) {
log("Connection rate limit of %u/%us has been exceeded; "
"dropping connection from %s.",
options.connections_per_period, options.connections_period,
ntop);
connections_per_period_exceeded = 0;
} else if (ratelim_exceeded) {
const char *myaddr;
myaddr = get_ipaddr(newsock);
log("rate limit (%u/%u) on %s port %d "
"exceeded by %s",
options.connections_per_period,
options.connections_period, myaddr,
get_sock_port(newsock, 1), ntop);
free((void *)myaddr);
ratelim_exceeded = 0;
continue;
} else {
/*
* Normal production daemon. Fork, and have