summaryrefslogtreecommitdiffstats
path: root/crypto
diff options
context:
space:
mode:
authorgreen <green@FreeBSD.org>2000-06-26 05:44:23 +0000
committergreen <green@FreeBSD.org>2000-06-26 05:44:23 +0000
commit9bccae4f2e267ca62056b16d55b797317a3060a6 (patch)
treee7fa8720c8c45d3a71b8303040261663e3c13769 /crypto
parent1f6b02c5a30aeb0ad40e2c490bd13805890ab99c (diff)
downloadFreeBSD-src-9bccae4f2e267ca62056b16d55b797317a3060a6.zip
FreeBSD-src-9bccae4f2e267ca62056b16d55b797317a3060a6.tar.gz
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>
Diffstat (limited to 'crypto')
-rw-r--r--crypto/openssh/canohost.c32
-rw-r--r--crypto/openssh/ssh.h5
-rw-r--r--crypto/openssh/sshd.c61
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
OpenPOWER on IntegriCloud