diff options
author | dwmalone <dwmalone@FreeBSD.org> | 2008-07-18 14:44:51 +0000 |
---|---|---|
committer | dwmalone <dwmalone@FreeBSD.org> | 2008-07-18 14:44:51 +0000 |
commit | f7cc3b4928dba59c3eead3afb623459bc1d4c80a (patch) | |
tree | 887336a69c3082404b65301ea919425f27456092 /sys/netinet | |
parent | 4efb6d2a37b496ded581b12ed193e4ebe091076a (diff) | |
download | FreeBSD-src-f7cc3b4928dba59c3eead3afb623459bc1d4c80a.zip FreeBSD-src-f7cc3b4928dba59c3eead3afb623459bc1d4c80a.tar.gz |
Add an accept filter for TCP based DNS requests. It waits until the
whole first request is present before returning from accept.
Diffstat (limited to 'sys/netinet')
-rw-r--r-- | sys/netinet/accf_dns.c | 135 |
1 files changed, 135 insertions, 0 deletions
diff --git a/sys/netinet/accf_dns.c b/sys/netinet/accf_dns.c new file mode 100644 index 0000000..1db9076 --- /dev/null +++ b/sys/netinet/accf_dns.c @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2007 David Malone <dwmalone@FreeBSD.org> + * 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. + * + * $FreeBSD$ + */ + +#define ACCEPT_FILTER_MOD + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/mbuf.h> +#include <sys/module.h> +#include <sys/signalvar.h> +#include <sys/sysctl.h> +#include <sys/socketvar.h> + +/* check for full DNS request */ +static void sohasdns(struct socket *so, void *arg, int waitflag); + +struct packet { + struct mbuf *m; /* Current mbuf. */ + struct mbuf *n; /* nextpkt mbuf. */ + unsigned long moff; /* Offset of the beginning of m. */ + unsigned long offset; /* Which offset we are working at. */ + unsigned long len; /* The number of bytes we have to play with. */ +}; + +#define DNS_OK 0 +#define DNS_WAIT -1 +#define DNS_RUN -2 + +/* check we can skip over various parts of DNS request */ +static int skippacket(struct sockbuf *sb); + +static struct accept_filter accf_dns_filter = { + "dnsready", + sohasdns, + NULL, + NULL +}; + +static moduledata_t accf_dns_mod = { + "accf_dns", + accept_filt_generic_mod_event, + &accf_dns_filter +}; + +DECLARE_MODULE(accf_dns, accf_dns_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE); + +static void +sohasdns(struct socket *so, void *arg, int waitflag) +{ + struct sockbuf *sb = &so->so_rcv; + + /* If the socket is full, we're ready. */ + if (sb->sb_cc >= sb->sb_hiwat || sb->sb_mbcnt >= sb->sb_mbmax) + goto ready; + + /* Check and see if we have a request. */ + if (skippacket(sb) == DNS_WAIT) + return; + +ready: + so->so_upcall = NULL; + so->so_rcv.sb_flags &= ~SB_UPCALL; + soisconnected(so); + return; +} + +#define GET8(p, val) do { \ + if (p->offset < p->moff) \ + return DNS_RUN; \ + while (p->offset >= p->moff + p->m->m_len) { \ + p->moff += p->m->m_len; \ + p->m = p->m->m_next; \ + if (p->m == NULL) { \ + p->m = p->n; \ + p->n = p->m->m_nextpkt; \ + } \ + if (p->m == NULL) \ + return DNS_WAIT; \ + } \ + val = *(mtod(p->m, unsigned char *) + (p->offset - p->moff)); \ + p->offset++; \ + } while (0) + +#define GET16(p, val) do { \ + unsigned int v0, v1; \ + GET8(p, v0); \ + GET8(p, v1); \ + val = v0 * 0x100 + v1; \ + } while (0) + +static int +skippacket(struct sockbuf *sb) { + unsigned long packlen; + struct packet q, *p = &q; + + if (sb->sb_cc < 2) + return DNS_WAIT; + + q.m = sb->sb_mb; + q.n = q.m->m_nextpkt; + q.moff = 0; + q.offset = 0; + q.len = sb->sb_cc; + + GET16(p, packlen); + if (packlen + 2 < q.len) + return DNS_WAIT; + + return DNS_OK; +} |