diff options
-rw-r--r-- | crypto/openssh/canohost.c | 32 | ||||
-rw-r--r-- | crypto/openssh/ssh.h | 5 | ||||
-rw-r--r-- | crypto/openssh/sshd.c | 61 |
3 files changed, 68 insertions, 30 deletions
diff --git a/crypto/openssh/canohost.c b/crypto/openssh/canohost.c index a73f8d0..306ec06 100644 --- a/crypto/openssh/canohost.c +++ b/crypto/openssh/canohost.c @@ -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 diff --git a/crypto/openssh/ssh.h b/crypto/openssh/ssh.h index 8024f51..bdc54a2 100644 --- a/crypto/openssh/ssh.h +++ b/crypto/openssh/ssh.h @@ -364,6 +364,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. */ diff --git a/crypto/openssh/sshd.c b/crypto/openssh/sshd.c index 2fcca59..0821b75 100644 --- a/crypto/openssh/sshd.c +++ b/crypto/openssh/sshd.c @@ -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 |