Commit Diff
Diff:
ec3f221d8854ac30e07b011761724efac1e4adbf
4667e76dbdc2409441098ed55e813abd46d27f62
Commit:
4667e76dbdc2409441098ed55e813abd46d27f62
Tree:
a8cdb2c860c7aca822106e1b473e19cc7b3eb41d
Author:
pjp <pjp@delphinusdns.org>
Committer:
pjp <pjp@delphinusdns.org>
Date:
Mon May 5 08:46:17 2014 UTC
Message:
* add a defineable ratelimit between 1 and 127 packets per second per a 16 bit hash of IP (IPv4 and IPv6). * example configuration is in example8.conf where it's 6 packets per second. * this will add memory to the order of 65536 * (((pps * 2) * 8) + 1) so 12 pps would be 12648448 bytes of shared memory added... * also there is a race that I know about in the adding of a packet to the backlog, but I don't use the -n flag in production so it's limited compiles and tested on OpenBSD 5.5
blob - 89f81f2648f155ed2a28e8bc0a1e90f54ff52769
blob + 7311d06d8ccefed07e03ed0201592f38597673a7
--- CHANGES
+++ CHANGES
@@ -7,6 +7,7 @@ Changes in BETA_9 from BETA_8
- SPF (RR 99) RFC 4408 support
- fix a bug related to truncation
- SSHFP (RR 44) RFC 4255 (+ RFC 6594) support
+- defineable ratelimit between 1 and 127 pps , see example8.conf for sample
Changes in BETA_8 from BETA_7
blob - e7729fc4d378ffef214e7a10b3c927dcd4677912
blob + 9aa9bbb263fbcbec746d8a7bc7a80c3cf29f1bd3
--- Makefile.freebsd
+++ Makefile.freebsd
@@ -1,6 +1,6 @@
PROG=wildcarddnsd
-SRCS=main.c parse.y reply.c additional.c region.c wildcard.c recurse.c res_random.c log.c axfr.c filter.c
+SRCS=main.c parse.y reply.c additional.c region.c wildcard.c recurse.c res_random.c log.c axfr.c filter.c ratelimit.c
CFLAGS= -Wall -g -I/usr/local/include/db5/
LDFLAGS= -Wall -g -L/usr/local/lib/db5/
blob - d9f650534e3003c31d502f7aabcd2df9bf8e2dc3
blob + eb87a348ea3d2b9ae0e6785e4f8c90c78b473e4f
--- Makefile.linux
+++ Makefile.linux
@@ -21,7 +21,8 @@ build:
$(CC) $(CFLAGS) -c log.c
$(CC) $(CFLAGS) -c axfr.c
$(CC) $(CFLAGS) -c filter.c
- $(CC) $(CFLAGS) -o wildcarddnsd additional.o main.o parse.o reply.o region.o wildcard.o recurse.o bsd-arc4random.o res_random.o log.o axfr.o filter.o $(LDADD)
+ $(CC) $(CFLAGS) -c ratelimit.c
+ $(CC) $(CFLAGS) -o wildcarddnsd additional.o main.o parse.o reply.o region.o wildcard.o recurse.o bsd-arc4random.o res_random.o log.o axfr.o filter.o ratelimit.o $(LDADD)
install:
blob - aa118cfe3fbdcf69f8d473c818efdb9ddfc7ada5
blob + e20d9ba43fef050435f5c93e74b1e9b12c7a68e4
--- Makefile.macosx
+++ Makefile.macosx
@@ -16,9 +16,10 @@ build:
$(CC) $(CFLAGS) -c recurse.c
$(CC) $(CFLAGS) -c axfr.c
$(CC) $(CFLAGS) -c filter.c
+ $(CC) $(CFLAGS) -c ratelimit.c
$(CC) $(CFLAGS) -c res_random.c
$(CC) $(CFLAGS) -c bsd-arc4random.c
- $(CC) $(CFLAGS) -o wildcarddnsd additional.o main.o parse.o reply.o region.o wildcard.o log.o recurse.o axfr.o res_random.c bsd-arc4random.o filter.o $(LDADD)
+ $(CC) $(CFLAGS) -o wildcarddnsd additional.o main.o parse.o reply.o region.o wildcard.o log.o recurse.o axfr.o res_random.c bsd-arc4random.o filter.o ratelimit.o $(LDADD)
clean:
rm -f *.o wildcarddnsd config.h Makefile
blob - d66ff587db00ee9d01ee85aed299e6982a61d741
blob + 7f3415e43128d56eb0199a0b0da63607e09e7045
--- Makefile.netbsd
+++ Makefile.netbsd
@@ -1,6 +1,6 @@
PROG=wildcarddnsd
-SRCS=main.c parse.y reply.c additional.c region.c wildcard.c recurse.c res_random.c bsd-arc4random.c log.c axfr.c filter.c
+SRCS=main.c parse.y reply.c additional.c region.c wildcard.c recurse.c res_random.c bsd-arc4random.c log.c axfr.c filter.c ratelimit.c
CFLAGS= -Wall -g -I/usr/pkg/include/db46/
LDFLAGS= -Wall -g -L/usr/pkg/lib -R/usr/pkg/lib
blob - 0eb70a6de7ddd55f7e1493e211486141de2831ef
blob + 2530de2465462c07bbda680f0391c396321df12d
--- Makefile.openbsd
+++ Makefile.openbsd
@@ -1,6 +1,6 @@
PROG=wildcarddnsd
-SRCS=main.c parse.y reply.c additional.c region.c wildcard.c recurse.c res_random.c log.c axfr.c filter.c
+SRCS=main.c parse.y reply.c additional.c region.c wildcard.c recurse.c res_random.c log.c axfr.c filter.c ratelimit.c
#CFLAGS= -DDEBUG -g -Wall
CFLAGS= -Wall -g -I/usr/local/include/db4
blob - 4d286b6369ca40628a97fe85f0308008910c904e
blob + 6a2b46bcc7a54abbd343fc29c3d3e283decac966
--- example8.conf
+++ example8.conf
@@ -9,6 +9,8 @@ options "cool stuff" {
;bind 127.0.0.1;
;bind 192.168.34.4;
+ ratelimit-pps 6;
+
port 53;
;fork 2;
blob - 72de798c7d7fe6872559f2a8a9889960f6994b2e
blob + 79912675c00f74e97bf80a6715aa8a4b41accb1a
--- main.c
+++ main.c
@@ -70,6 +70,9 @@ extern int remotelog(int, char *, ...);
extern void receivelog(char *buf, int len);
extern void axfrloop(int *afd, int sockcount, char **ident, DB *db);
extern void dolog(int, char *, ...);
+extern char * rrlimit_setup(int);
+extern void add_rrlimit(int, u_int16_t *, int, char *);
+extern int check_rrlimit(int, u_int16_t *, int, char *);
char * dns_label(char *, int *);
int compress_label(u_char *, u_int16_t, int);
@@ -118,6 +121,8 @@ struct typetable {
extern char *__progname;
extern struct logging logging;
extern int axfrport;
+extern int ratelimit;
+extern int ratelimit_packets_per_second;
static int *ptr = NULL;
static int reload = 0;
@@ -125,6 +130,8 @@ static int mshutdown = 0;
static int msig;
static char *database;
static char mydatabase[512];
+static char *rptr;
+static ratelimit_backlog;
int debug = 0;
int verbose = 0;
@@ -159,7 +166,7 @@ static struct tcps {
} *tn1, *tnp, *tntmp;
-static const char rcsid[] = "$Id: main.c,v 1.87 2014/05/01 20:16:51 pjp Exp $";
+static const char rcsid[] = "$Id: main.c,v 1.88 2014/05/05 08:46:17 pjp Exp $";
/*
* MAIN - set up arguments, set up database, set up sockets, call mainloop
@@ -423,6 +430,18 @@ main(int argc, char *argv[])
exit(1);
}
+ /* ratelimiting setup */
+ if (ratelimit) {
+ ratelimit_backlog = ratelimit_packets_per_second * 2;
+ rptr = rrlimit_setup(ratelimit_backlog);
+ if (rptr == NULL) {
+ dolog(LOG_INFO, "ratelimiting error\n");
+ slave_shutdown();
+ exit(1);
+ }
+ }
+
+
pw = getpwnam(DEFAULT_PRIVILEGE);
if (pw == NULL) {
dolog(LOG_INFO, "getpwnam: %s\n", strerror(errno));
@@ -2124,6 +2143,7 @@ mainloop(struct cfg *cfg)
int lzerrno;
int wildcard = 0;
int filter = 0;
+ int rcheck = 0;
int sp;
int lfd;
@@ -2891,6 +2911,12 @@ axfrentry:
fromlen = sizeof(struct sockaddr_in6);
sin6 = (struct sockaddr_in6 *)from;
inet_ntop(AF_INET6, (void *)&sin6->sin6_addr, (char *)&address, sizeof(address));
+ if (ratelimit) {
+ add_rrlimit(ratelimit_backlog, (u_int16_t *)&sin6->sin6_addr, sizeof(sin6->sin6_addr), rptr);
+
+ rcheck = check_rrlimit(ratelimit_backlog, (u_int16_t *)&sin6->sin6_addr, sizeof(sin6->sin6_addr), rptr);
+ }
+
aregion = find_region((struct sockaddr_storage *)sin6, AF_INET6);
wildcard = find_wildcard((struct sockaddr_storage *)sin6, AF_INET6);
filter = find_filter((struct sockaddr_storage *)sin6, AF_INET6);
@@ -2904,6 +2930,12 @@ axfrentry:
fromlen = sizeof(struct sockaddr_in);
sin = (struct sockaddr_in *)from;
inet_ntop(AF_INET, (void *)&sin->sin_addr, (char *)&address, sizeof(address));
+ if (ratelimit) {
+ add_rrlimit(ratelimit_backlog, (u_int16_t *)&sin->sin_addr.s_addr, sizeof(sin->sin_addr.s_addr), rptr);
+
+ rcheck = check_rrlimit(ratelimit_backlog, (u_int16_t *)&sin->sin_addr.s_addr, sizeof(sin->sin_addr.s_addr), rptr);
+ }
+
aregion = find_region((struct sockaddr_storage *)sin, AF_INET);
wildcard = find_wildcard((struct sockaddr_storage *)sin, AF_INET);
filter = find_filter((struct sockaddr_storage *)sin, AF_INET);
@@ -2954,6 +2986,10 @@ axfrentry:
goto drop;
}
+ if (ratelimit && rcheck) {
+ dolog(LOG_INFO, "UDP connection refused on descriptor %u interface \"%s\" from %s (ttl=%d, region=%d) ratelimit policy dropping packet\n", so, cfg->ident[i], address, received_ttl, aregion);
+ goto drop;
+ }
if (rflag && recursion) {
memcpy(&rh.buf, buf, len);
blob - 9b80333efd439209ed9f92fcb0d401a8c2c7c3fd
blob + 7a6ee8fdcc60bafc8e470732306ac3550300fb19
--- parse.y
+++ parse.y
@@ -58,7 +58,7 @@ typedef struct {
int lineno;
} YYSTYPE;
-static const char rcsid[] = "$Id: parse.y,v 1.16 2014/05/01 15:26:24 pjp Exp $";
+static const char rcsid[] = "$Id: parse.y,v 1.17 2014/05/05 08:46:17 pjp Exp $";
static int version = 0;
static int state = 0;
static uint8_t region = 0;
@@ -77,6 +77,8 @@ extern int nflag;
extern int rflag;
extern int bcount;
extern int icount;
+extern int ratelimit;
+extern int ratelimit_packets_per_second;
extern u_int16_t port;
extern u_int32_t cachesize;
extern char *bind_list[255];
@@ -576,6 +578,14 @@ optionsstatement:
} else if (strcasecmp($1, "port") == 0) {
port = $2 & 0xffff;
dolog(LOG_DEBUG, "listening on port %d\n", port);
+ } else if (strcasecmp($1, "ratelimit-pps") == 0) {
+ if ($2 > 127 || $2 < 1) {
+ dolog(LOG_ERR, "ratelimit packets per second must be between 1 and 127, or leave it off!\n");
+ return -1;
+ }
+ ratelimit = 1;
+ ratelimit_packets_per_second = $2;
+ dolog(LOG_DEBUG, "ratelimiting to %d packets per second", ratelimit_packets_per_second);
}
}
blob - /dev/null
blob + ca6ea1da0e410c4b5a4b5f5e223de9a273658aa6 (mode 644)
--- /dev/null
+++ ratelimit.c
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2014 Peter J. Philipp
+ * 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.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 "include.h"
+#include "dns.h"
+#include "db.h"
+
+extern void dolog(int, char *, ...);
+static u_int16_t hash_rrlimit(u_int16_t *, int);
+char * rrlimit_setup(int size);
+void add_rrlimit(int size, u_int16_t *ip, int sizeip, char *rrlimit_ptr);
+int check_rrlimit(int size, u_int16_t *ip, int sizeip, char *rrlimit_ptr);
+
+struct rrlimit {
+ u_int8_t pointer;
+ time_t times[256];
+};
+
+int ratelimit = 0;
+int ratelimit_packets_per_second = 6;
+
+char *
+rrlimit_setup(int size)
+{
+ char *ptr;
+
+ if (size > 255)
+ return NULL;
+
+ size = 65536 * ((size * sizeof(time_t)) + sizeof(u_int8_t));
+
+ ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED |\
+ MAP_ANON, -1, 0);
+
+ if (ptr == MAP_FAILED) {
+ dolog(LOG_ERR, "failed to setup rlimit mmap segment, exit\n");
+ exit(1);
+ }
+
+ memset(ptr, 0, size);
+
+ return (ptr);
+}
+
+int
+check_rrlimit(int size, u_int16_t *ip, int sizeip, char *rrlimit_ptr)
+{
+ struct rrlimit *rl;
+ u_int16_t hash;
+ int count = 0, i;
+ u_int8_t offset;
+ time_t now;
+ char *tmp;
+
+ hash = hash_rrlimit(ip, sizeip);
+
+ tmp = rrlimit_ptr + (hash * ((size * sizeof(time_t)) + sizeof(u_int8_t)));
+ rl = (struct rrlimit *)tmp;
+
+ offset = rl->pointer;
+
+ now = time(NULL);
+
+ for (i = 0; i < size; i++) {
+ if (difftime(now, rl->times[(offset + i) % size]) <= 1)
+ count++;
+ else
+ break;
+ }
+
+ if (count > ratelimit_packets_per_second)
+ return 1;
+
+ return 0;
+}
+
+
+void
+add_rrlimit(int size, u_int16_t *ip, int sizeip, char *rrlimit_ptr)
+{
+ struct rrlimit *rl;
+ u_int16_t hash;
+ int offset;
+ time_t now;
+ char *tmp;
+
+ hash = hash_rrlimit(ip, sizeip);
+
+ tmp = rrlimit_ptr + (hash * ((size * sizeof(time_t)) + sizeof(u_int8_t)));
+ rl = (struct rrlimit *)tmp;
+
+ offset = rl->pointer;
+
+ offset--;
+ if (offset < 0)
+ offset = size - 1;
+
+ now = time(NULL);
+
+ rl->times[offset] = now;
+ rl->pointer = offset; /* XXX race */
+
+}
+
+static u_int16_t
+hash_rrlimit(u_int16_t *ip, int size)
+{
+ u_int64_t total = 0;
+ int i;
+
+ for (i = 0; i < size; i += 2) {
+ total += (u_int64_t)ip[i];
+ }
+
+ total %= 0xffff;
+
+ return ((u_int16_t)total);
+}
repomaster@centroid.eu