summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/netinet/accf_dns.c
diff options
context:
space:
mode:
Diffstat (limited to 'freebsd/sys/netinet/accf_dns.c')
-rw-r--r--freebsd/sys/netinet/accf_dns.c134
1 files changed, 134 insertions, 0 deletions
diff --git a/freebsd/sys/netinet/accf_dns.c b/freebsd/sys/netinet/accf_dns.c
new file mode 100644
index 00000000..f91cbb08
--- /dev/null
+++ b/freebsd/sys/netinet/accf_dns.c
@@ -0,0 +1,134 @@
+#include <freebsd/machine/rtems-bsd-config.h>
+
+/*
+ * 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 <freebsd/sys/param.h>
+#include <freebsd/sys/kernel.h>
+#include <freebsd/sys/mbuf.h>
+#include <freebsd/sys/module.h>
+#include <freebsd/sys/signalvar.h>
+#include <freebsd/sys/sysctl.h>
+#include <freebsd/sys/socketvar.h>
+
+/* check for full DNS request */
+static int 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 int
+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 to see if we have a request. */
+ if (skippacket(sb) == DNS_WAIT)
+ return (SU_OK);
+
+ready:
+ return (SU_ISCONNECTED);
+}
+
+#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;
+}