summaryrefslogtreecommitdiffstats
path: root/contrib/ipfilter/mli_ipl.c
diff options
context:
space:
mode:
authorpeter <peter@FreeBSD.org>1997-11-16 04:52:19 +0000
committerpeter <peter@FreeBSD.org>1997-11-16 04:52:19 +0000
commit594e73c3109178aa1c5317785aaa284a0c135ff4 (patch)
tree1abde20e1d717a2bf3509de2189cbe7fa3c9f91e /contrib/ipfilter/mli_ipl.c
parentc4dc16ff2222e864e5ab4d236e0de3a2cb5b54da (diff)
downloadFreeBSD-src-594e73c3109178aa1c5317785aaa284a0c135ff4.zip
FreeBSD-src-594e73c3109178aa1c5317785aaa284a0c135ff4.tar.gz
Import ipfilter 3.2.1 (update from 3.1.8)
Diffstat (limited to 'contrib/ipfilter/mli_ipl.c')
-rw-r--r--contrib/ipfilter/mli_ipl.c580
1 files changed, 580 insertions, 0 deletions
diff --git a/contrib/ipfilter/mli_ipl.c b/contrib/ipfilter/mli_ipl.c
new file mode 100644
index 0000000..e4490c3
--- /dev/null
+++ b/contrib/ipfilter/mli_ipl.c
@@ -0,0 +1,580 @@
+/*
+ * Copyright (C) 1993-1997 by Darren Reed.
+ * (C)opyright 1997 by Marc Boucher.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and due credit is given
+ * to the original authors and the contributors.
+ */
+
+/* TODO: (MARCXXX)
+ - ipl_init failure -> open ENODEV or whatever
+ - prevent multiple LKM loads
+ - surround access to ifnet structures by IFNET_LOCK()/IFNET_UNLOCK() ?
+ - m != m1 problem
+*/
+
+#include <sys/types.h>
+#include <sys/conf.h>
+#ifdef IPFILTER_LKM
+#include <sys/mload.h>
+#endif
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <net/if.h>
+#include <net/route.h>
+#include <netinet/in.h>
+#ifdef IFF_DRVRLOCK /* IRIX6 */
+#include <sys/hashing.h>
+#include <netinet/in_var.h>
+#endif
+#include <sys/mbuf.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+#include <netinet/tcp.h>
+#include <netinet/udp.h>
+#include <netinet/tcpip.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/ipfilter.h>
+#include "ipl.h"
+#include "ip_compat.h"
+#include "ip_fil.h"
+#include "ip_nat.h"
+
+/*#define IPFDEBUG 1*/
+
+unsigned IPL_EXTERN(devflag) = D_MP;
+#ifdef IPFILTER_LKM
+char *IPL_EXTERN(mversion) = M_VERSION;
+#endif
+
+kmutex_t ipl_mutex, ipf_mutex, ipfs_mutex;
+kmutex_t ipf_frag, ipf_state, ipf_nat, ipf_natfrag, ipf_auth;
+
+int (*fr_checkp) __P((struct ip *, int, void *, int, mb_t **));
+
+#ifdef IPFILTER_LKM
+static int *ipff_addr = 0;
+static int ipff_value;
+static __psunsigned_t *ipfk_addr = 0;
+static __psunsigned_t ipfk_code[4];
+#endif
+
+typedef struct nif {
+ struct nif *nf_next;
+ struct ifnet *nf_ifp;
+ int (*nf_output)(struct ifnet *, struct mbuf *, struct sockaddr *);
+ char nf_name[IFNAMSIZ];
+ int nf_unit;
+} nif_t;
+
+static nif_t *nif_head = 0;
+static int nif_interfaces = 0;
+extern int in_interfaces;
+
+extern ipnat_t *nat_list;
+
+static int
+ipl_if_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst)
+{
+ nif_t *nif;
+
+ MUTEX_ENTER(&ipfs_mutex); /* sets interrupt priority level to splhi */
+ for (nif = nif_head; nif; nif = nif->nf_next)
+ if (nif->nf_ifp == ifp)
+ break;
+
+ MUTEX_EXIT(&ipfs_mutex);
+ if (!nif) {
+ printf("IP Filter: ipl_if_output intf %x NOT FOUND\n", ifp);
+ return ENETDOWN;
+ }
+
+#if IPFDEBUG >= 4
+ static unsigned int cnt = 0;
+ if ((++cnt % 200) == 0)
+ printf("IP Filter: ipl_if_output(ifp=0x%lx, m=0x%lx, dst=0x%lx), m_type=%d m_flags=0x%lx m_off=0x%lx\n", ifp, m, dst, m->m_type, (unsigned long)(m->m_flags), m->m_off);
+#endif
+ if (fr_checkp) {
+ struct mbuf *m1 = m;
+ struct ip *ip;
+ int hlen;
+
+ switch(m->m_type) {
+ case MT_DATA:
+ if (m->m_flags & M_BCAST) {
+#if IPFDEBUG >= 2
+ printf("IP Filter: ipl_if_output: passing M_BCAST\n");
+#endif
+ break;
+ }
+ /* FALLTHROUGH */
+ case MT_HEADER:
+#if IPFDEBUG >= 4
+ if (!MBUF_IS_CLUSTER(m) && ((m->m_off < MMINOFF) || (m->m_off > MMAXOFF))) {
+ printf("IP Filter: ipl_if_output: bad m_off m_type=%d m_flags=0x%lx m_off=0x%lx\n", m->m_type, (unsigned long)(m->m_flags), m->m_off);
+ return (*nif->nf_output)(ifp, m, dst);
+ }
+#endif
+ if (m->m_len < sizeof(char)) {
+ printf("IP Filter: ipl_if_output: mbuf block too small (m_len=%d) for IP vers+hlen, m_type=%d m_flags=0x%lx\n", m->m_len, m->m_type, (unsigned long)(m->m_flags));
+ return (*nif->nf_output)(ifp, m, dst);
+ }
+ ip = mtod(m, struct ip *);
+ if (ip->ip_v != IPVERSION) {
+#if IPFDEBUG >= 4
+ printf("IP Filter: ipl_if_output: bad ip_v m_type=%d m_flags=0x%lx m_off=0x%lx\n", m->m_type, (unsigned long)(m->m_flags), m->m_off);
+#endif
+ return (*nif->nf_output)(ifp, m, dst);
+ }
+
+ hlen = ip->ip_hl << 2;
+ if ((*fr_checkp)(ip, hlen, ifp, 1, &m1))
+ return EHOSTUNREACH;
+
+ if (!m1)
+ return 0;
+
+ m = m1;
+ break;
+
+ default:
+ printf("IP Filter: ipl_if_output: bad m_type=%d m_flags=0x%lxm_off=0x%lx\n", m->m_type, (unsigned long)(m->m_flags), m->m_off);
+ break;
+ }
+ }
+ return (*nif->nf_output)(ifp, m, dst);
+}
+
+int
+IPL_EXTERN(_kernel)(struct ifnet *rcvif, struct mbuf *m)
+{
+#if IPFDEBUG >= 4
+ static unsigned int cnt = 0;
+ if ((++cnt % 200) == 0)
+ printf("IP Filter: ipl_ipfilter_kernel(rcvif=0x%lx, m=0x%lx\n", rcvif, m);
+#endif
+
+ /*
+ * Check if we want to allow this packet to be processed.
+ * Consider it to be bad if not.
+ */
+ if (fr_checkp) {
+ struct mbuf *m1 = m;
+ struct ip *ip;
+ int hlen;
+
+ if ((m->m_type != MT_DATA) && (m->m_type != MT_HEADER)) {
+ printf("IP Filter: ipl_ipfilter_kernel: bad m_type=%d m_flags=0x%lx m_off=0x%lx\n", m->m_type, (unsigned long)(m->m_flags), m->m_off);
+ return IPF_ACCEPTIT;
+ }
+
+#if IPFDEBUG >= 4
+ if (!MBUF_IS_CLUSTER(m) && ((m->m_off < MMINOFF) || (m->m_off > MMAXOFF))) {
+ printf("IP Filter: ipl_ipfilter_kernel: bad m_off m_type=%d m_flags=0x%lx m_off=0x%lx\n", m->m_type, (unsigned long)(m->m_flags), m->m_off);
+ return IPF_ACCEPTIT;
+ }
+#endif
+ if (m->m_len < sizeof(char)) {
+ printf("IP Filter: ipl_ipfilter_kernel: mbuf block too small (m_len=%d) for IP vers+hlen, m_type=%d m_flags=0x%lx\n", m->m_len, m->m_type, (unsigned long)(m->m_flags));
+ return IPF_ACCEPTIT;
+ }
+ ip = mtod(m, struct ip *);
+ if (ip->ip_v != IPVERSION) {
+ printf("IP Filter: ipl_ipfilter_kernel: bad ip_v\n");
+ m_freem(m);
+ return IPF_DROPIT;
+ }
+
+ hlen = ip->ip_hl << 2;
+ if ((*fr_checkp)(ip, hlen, rcvif, 0, &m1) || !m1)
+ return IPF_DROPIT;
+ if (m != m1)
+ printf("IP Filter: ipl_ipfilter_kernel: m != m1\n");
+ }
+
+ return IPF_ACCEPTIT;
+}
+
+static int
+ipfilterattach(void)
+{
+#ifdef IPFILTER_LKM
+ __psunsigned_t *addr_ff, *addr_fk;
+
+ st_findaddr("ipfilterflag", &addr_ff);
+#if IPFDEBUG >= 4
+ printf("IP Filter: st_findaddr ipfilterflag=0x%lx\n", addr_ff);
+#endif
+ if (!addr_ff)
+ return ESRCH;
+
+ st_findaddr("ipfilter_kernel", &addr_fk);
+#if IPFDEBUG >= 4
+ printf("IP Filter: st_findaddr ipfilter_kernel=0x%lx\n", addr_fk);
+#endif
+ if (!addr_fk)
+ return ESRCH;
+
+ MUTEX_ENTER(&ipfs_mutex); /* sets interrupt priority level to splhi */
+
+ ipff_addr = (int *)addr_ff;
+
+ ipff_value = *ipff_addr;
+ *ipff_addr = 0;
+
+
+ ipfk_addr = addr_fk;
+
+ bcopy(ipfk_addr, ipfk_code,
+ sizeof(ipfk_code));
+
+ /* write a "li t4, ipl_ipfilter_kernel" instruction */
+ ipfk_addr[0] = 0x3c0c0000 |
+ (((__psunsigned_t)IPL_EXTERN(_kernel) >> 16) & 0xffff);
+ ipfk_addr[1] = 0x358c0000 |
+ ((__psunsigned_t)IPL_EXTERN(_kernel) & 0xffff);
+ /* write a "jr t4" instruction" */
+ ipfk_addr[2] = 0x01800008;
+
+ /* write a "nop" instruction */
+ ipfk_addr[3] = 0;
+
+ icache_inval(ipfk_addr, sizeof(ipfk_code));
+
+ *ipff_addr = 1; /* enable ipfilter_kernel */
+
+ MUTEX_EXIT(&ipfs_mutex);
+#else
+ extern int ipfilterflag;
+
+ ipfilterflag = 1;
+#endif
+
+ return 0;
+}
+
+/*
+ * attach the packet filter to each non-loopback interface that is running
+ */
+static void
+nifattach()
+{
+ nif_t *nif, *qf2;
+ struct ifnet *ifp;
+ struct frentry *f;
+ ipnat_t *np;
+
+ MUTEX_ENTER(&ipfs_mutex); /* sets interrupt priority level to splhi */
+
+ for (ifp = ifnet; ifp; ifp = ifp->if_next) {
+ if ((!(ifp->if_flags & IFF_RUNNING)) ||
+ (ifp->if_flags & IFF_LOOPBACK))
+ continue;
+
+ /*
+ * Look for entry already setup for this device
+ */
+ for (nif = nif_head; nif; nif = nif->nf_next)
+ if (nif->nf_ifp == ifp)
+ break;
+ if (nif)
+ continue;
+
+ if (ifp->if_output == ipl_if_output) {
+ printf("IP Filter: ERROR INTF 0x%lx STILL ATTACHED\n",
+ ifp);
+ continue;
+ }
+#if IPFDEBUG >= 4
+ printf("IP Filter: nifattach nif %x opt %x\n",
+ ifp, ifp->if_output);
+#endif
+ KMALLOC(nif, nif_t *, sizeof(*nif));
+ if (!nif) {
+ printf("IP Filter: malloc(%d) for nif_t failed\n",
+ sizeof(nif_t));
+ continue;
+ }
+
+ nif->nf_ifp = ifp;
+ strncpy(nif->nf_name, ifp->if_name, sizeof(nif->nf_name));
+ nif->nf_name[sizeof(nif->nf_name) - 1] = '\0';
+ nif->nf_unit = ifp->if_unit;
+
+ nif->nf_next = nif_head;
+ nif_head = nif;
+
+ /*
+ * Activate any rules directly associated with this interface
+ */
+ MUTEX_ENTER(&ipf_mutex);
+ for (f = ipfilter[0][0]; f; f = f->fr_next) {
+ if ((f->fr_ifa == (struct ifnet *)-1)) {
+ if (f->fr_ifname[0] &&
+ (GETUNIT(f->fr_ifname) == ifp))
+ f->fr_ifa = ifp;
+ }
+ }
+ for (f = ipfilter[1][0]; f; f = f->fr_next) {
+ if ((f->fr_ifa == (struct ifnet *)-1)) {
+ if (f->fr_ifname[0] &&
+ (GETUNIT(f->fr_ifname) == ifp))
+ f->fr_ifa = ifp;
+ }
+ }
+ MUTEX_EXIT(&ipf_mutex);
+ MUTEX_ENTER(&ipf_nat);
+ for (np = nat_list; np; np = np->in_next) {
+ if ((np->in_ifp == (void *)-1)) {
+ if (np->in_ifname[0] &&
+ (GETUNIT(np->in_ifname) == ifp))
+ np->in_ifp = (void *)ifp;
+ }
+ }
+ MUTEX_EXIT(&ipf_nat);
+
+ nif->nf_output = ifp->if_output;
+ ifp->if_output = ipl_if_output;
+
+#if IPFDEBUG >= 4
+ printf("IP Filter: nifattach: ifp(%lx)->if_output FROM %lx TO %lx\n",
+ ifp, nif->nf_output, ifp->if_output);
+#endif
+
+ printf("IP Filter: attach to [%s,%d]\n",
+ nif->nf_name, ifp->if_unit);
+ }
+ if (!nif_head)
+ printf("IP Filter: not attached to any interfaces\n");
+
+ nif_interfaces = in_interfaces;
+
+ MUTEX_EXIT(&ipfs_mutex);
+
+ return;
+}
+
+/*
+ * look for bad consistancies between the list of interfaces the filter knows
+ * about and those which are currently configured.
+ */
+int
+ipfsync(void)
+{
+ register struct frentry *f;
+ register ipnat_t *np;
+ register nif_t *nif, **qp;
+ register struct ifnet *ifp;
+
+ MUTEX_ENTER(&ipfs_mutex); /* sets interrupt priority level to splhi */
+ for (qp = &nif_head; (nif = *qp); ) {
+ for (ifp = ifnet; ifp; ifp = ifp->if_next)
+ if ((nif->nf_ifp == ifp) &&
+ (nif->nf_unit == ifp->if_unit) &&
+ !strcmp(nif->nf_name, ifp->if_name)) {
+ break;
+ }
+ if (ifp) {
+ qp = &nif->nf_next;
+ continue;
+ }
+ printf("IP Filter: detaching [%s]\n", nif->nf_name);
+ *qp = nif->nf_next;
+
+ /*
+ * Disable any rules directly associated with this interface
+ */
+ MUTEX_ENTER(&ipf_mutex);
+ for (f = ipfilter[0][0]; f; f = f->fr_next)
+ if (f->fr_ifa == (void *)nif->nf_ifp)
+ f->fr_ifa = (struct ifnet *)-1;
+ for (f = ipfilter[1][0]; f; f = f->fr_next)
+ if (f->fr_ifa == (void *)nif->nf_ifp)
+ f->fr_ifa = (struct ifnet *)-1;
+ MUTEX_EXIT(&ipf_mutex);
+ MUTEX_ENTER(&ipf_nat);
+ for (np = nat_list; np; np = np->in_next)
+ if (np->in_ifp == (void *)nif->nf_ifp)
+ np->in_ifp =(struct ifnet *)-1;
+ MUTEX_EXIT(&ipf_nat);
+
+ KFREE(nif);
+ nif = *qp;
+ }
+ MUTEX_EXIT(&ipfs_mutex);
+
+ nifattach();
+
+ return 0;
+}
+
+
+/*
+ * unhook the IP filter from all defined interfaces with IP addresses
+ */
+static void
+nifdetach()
+{
+ nif_t *nif, *qf2, **qp;
+ struct ifnet *ifp;
+
+ MUTEX_ENTER(&ipfs_mutex); /* sets interrupt priority level to splhi */
+ /*
+ * Make two passes, first get rid of all the unknown devices, next
+ * unlink known devices.
+ */
+ for (qp = &nif_head; (nif = *qp); ) {
+ for (ifp = ifnet; ifp; ifp = ifp->if_next)
+ if (nif->nf_ifp == ifp)
+ break;
+ if (ifp) {
+ qp = &nif->nf_next;
+ continue;
+ }
+ printf("IP Filter: removing [%s]\n", nif->nf_name);
+ *qp = nif->nf_next;
+ KFREE(nif);
+ }
+
+ while ((nif = nif_head)) {
+ nif_head = nif->nf_next;
+ for (ifp = ifnet; ifp; ifp = ifp->if_next)
+ if (nif->nf_ifp == ifp)
+ break;
+ if (ifp) {
+ printf("IP Filter: detaching [%s,%d]\n",
+ nif->nf_name, ifp->if_unit);
+
+#if IPFDEBUG >= 4
+ printf("IP Filter: nifdetach: ifp(%lx)->if_output FROM %lx TO %lx\n",
+ ifp, ifp->if_output, nif->nf_output);
+#endif
+ ifp->if_output = nif->nf_output;
+ }
+ KFREE(nif);
+ }
+ MUTEX_EXIT(&ipfs_mutex);
+
+ return;
+}
+
+
+static void
+ipfilterdetach(void)
+{
+#ifdef IPFILTER_LKM
+ MUTEX_ENTER(&ipfs_mutex); /* sets interrupt priority level to splhi */
+
+ if (ipff_addr) {
+ *ipff_addr = 0;
+
+ if (ipfk_addr)
+ bcopy(ipfk_code, ipfk_addr, sizeof(ipfk_code));
+
+ *ipff_addr = ipff_value;
+ }
+
+ MUTEX_EXIT(&ipfs_mutex);
+#else
+ extern int ipfilterflag;
+
+ ipfilterflag = 0;
+#endif
+}
+
+/* called by ipldetach() */
+void
+ipfilter_sgi_detach(void)
+{
+ nifdetach();
+
+ ipfilterdetach();
+}
+
+/* called by iplattach() */
+int
+ipfilter_sgi_attach(void)
+{
+ int error;
+
+ nif_interfaces = 0;
+
+ error = ipfilterattach();
+
+ if (!error)
+ nifattach();
+
+ return error;
+}
+
+/* this function is called from ipfr_slowtimer at 500ms intervals to
+ keep our interface list in sync */
+void
+ipfilter_sgi_intfsync(void)
+{
+ MUTEX_ENTER(&ipfs_mutex);
+ if (nif_interfaces != in_interfaces) {
+ /* if the number of interfaces has changed, resync */
+ MUTEX_EXIT(&ipfs_mutex);
+ ipfsync();
+ } else
+ MUTEX_EXIT(&ipfs_mutex);
+}
+
+#ifdef IPFILTER_LKM
+/* this routine should be treated as an interrupt routine and should
+ not call any routines that would cause it to sleep, such as: biowait(),
+ sleep(), psema() or delay().
+*/
+int
+IPL_EXTERN(unload)(void)
+{
+ int error = 0;
+
+ error = ipldetach();
+
+ LOCK_DEALLOC(ipl_mutex.l);
+ LOCK_DEALLOC(ipf_auth.l);
+ LOCK_DEALLOC(ipf_natfrag.l);
+ LOCK_DEALLOC(ipf_nat.l);
+ LOCK_DEALLOC(ipf_state.l);
+ LOCK_DEALLOC(ipf_frag.l);
+ LOCK_DEALLOC(ipf_mutex.l);
+ LOCK_DEALLOC(ipfs_mutex.l);
+
+ return error;
+}
+#endif
+
+void
+IPL_EXTERN(init)(void)
+{
+#ifdef IPFILTER_LKM
+ int error;
+#endif
+
+ ipfs_mutex.l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP);
+ ipf_mutex.l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP);
+ ipf_frag.l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP);
+ ipf_state.l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP);
+ ipf_nat.l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP);
+ ipf_natfrag.l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP);
+ ipf_auth.l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP);
+ ipl_mutex.l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP);
+
+ if (!ipfs_mutex.l || !ipf_mutex.l || !ipf_frag.l || !ipf_state.l ||
+ !ipf_nat.l || !ipf_natfrag.l || !ipf_auth.l || !ipl_mutex.l)
+ panic("IP Filter: LOCK_ALLOC failed");
+
+#ifdef IPFILTER_LKM
+ error = iplattach();
+ if (error) {
+ IPL_EXTERN(unload)();
+ }
+#endif
+
+ return;
+}
+
OpenPOWER on IntegriCloud