diff --git a/sys/netinet/in.c b/sys/netinet/in.c index 3a5c0e76e48c..b384c7974ab3 100644 --- a/sys/netinet/in.c +++ b/sys/netinet/in.c @@ -1,4 +1,4 @@ -/* $NetBSD: in.c,v 1.29 1996/06/23 12:12:44 mycroft Exp $ */ +/* $NetBSD: in.c,v 1.30 1996/09/06 05:07:43 mrg Exp $ */ /* * Copyright (c) 1982, 1986, 1991, 1993 @@ -43,12 +43,14 @@ #include #include #include +#include #include #include #include #include +#include #include #include #include @@ -62,6 +64,14 @@ #define SUBNETSARELOCAL 1 #endif int subnetsarelocal = SUBNETSARELOCAL; + +#ifdef PACKET_FILTER +LIST_HEAD(, packet_filter_hook) pfil_in_list; +LIST_HEAD(, packet_filter_hook) pfil_out_list; +LIST_HEAD(, packet_filter_hook) pfil_bad_list; +static int done_pfil_init; +#endif /* PACKET_FILTER */ + /* * Return 1 if an internet address is for a ``local'' host * (one to which we have a connection). If subnetsarelocal @@ -555,5 +565,118 @@ in_delmulti(inm) } splx(s); } - #endif + +#ifdef PACKET_FILTER +void pfil_init __P((void)); +int pfil_list_remove(struct packet_filter_hook *, + int (*) __P((void *, int, struct ifnet *, int, struct mbuf **)), int, + int); + +void +pfil_init() +{ + LIST_INIT(&pfil_in_list); + LIST_INIT(&pfil_out_list); + LIST_INIT(&pfil_bad_list); + done_pfil_init = 1; +} + +/* + * pfil_add_hook() adds a function to the packet filter hook. the + * flags are: + * PFIL_IN call me on incoming packets + * PFIL_OUT call me on outgoing packets + * PFIL_BAD call me when rejecting a packet (that was + * not already reject by in/out filters). + * PFIL_ALL call me on all of the above + * PFIL_WAITOK OK to call malloc with M_WAITOK. + */ +void +pfil_add_hook(func, flags) + int (*func) __P((void *, int, struct ifnet *, int, + struct mbuf **)); + int flags; +{ + struct packet_filter_hook *pfh; + + if (done_pfil_init == 0) + pfil_init(); + + pfh = (struct packet_filter_hook *)malloc(sizeof(*pfh), M_IFADDR, + flags & PFIL_WAITOK ? M_WAITOK : M_NOWAIT); + if (pfh == NULL) + panic("no memory for packet filter hook"); + + pfh->pfil_flags = flags; + pfh->pfil_func = func; + if (flags & PFIL_IN) + LIST_INSERT_HEAD(&pfil_in_list, pfh, pfil_link); + if (flags & PFIL_OUT) + LIST_INSERT_HEAD(&pfil_out_list, pfh, pfil_link); + if (flags & PFIL_BAD) + LIST_INSERT_HEAD(&pfil_bad_list, pfh, pfil_link); +} + +/* + * pfil_remove_hook removes a specific function from the packet filter + * hook list. + */ +void +pfil_remove_hook(func, flags) + int (*func) __P((void *, int, struct ifnet *, int, + struct mbuf **)); + int flags; +{ + + if (done_pfil_init == 0) + pfil_init(); + + if (flags & PFIL_IN && + pfil_list_remove(pfil_in_list.lh_first, func, flags, PFIL_IN)) + return; + if (flags & PFIL_OUT && + pfil_list_remove(pfil_out_list.lh_first, func, flags, PFIL_OUT)) + return; + if (flags & PFIL_BAD && + pfil_list_remove(pfil_bad_list.lh_first, func, flags, PFIL_BAD)) + return; +} + +int +pfil_list_remove(list, func, flags, flag) + struct packet_filter_hook *list; + int (*func) __P((void *, int, struct ifnet *, int, + struct mbuf **)); + int flags, flag; +{ + struct packet_filter_hook *pfh; + + for (pfh = list; pfh; pfh = pfh->pfil_link.le_next) + if (pfh->pfil_func == func) { + pfh->pfil_flags &= ~flag; + LIST_REMOVE(pfh, pfil_link); + if ((flags & PFIL_ALL) == 0) { + free(pfh, M_IFADDR); + return 1; + } + } + return 0; +} + +struct packet_filter_hook * +pfil_hook_get(flag) + int flag; +{ + if (done_pfil_init) + switch (flag) { + case PFIL_IN: + return (pfil_in_list.lh_first); + case PFIL_OUT: + return (pfil_out_list.lh_first); + case PFIL_BAD: + return (pfil_bad_list.lh_first); + } + return NULL; +} +#endif /* PACKET_FILTER */ diff --git a/sys/netinet/ip.h b/sys/netinet/ip.h index 54b45e31234e..8f627410cdac 100644 --- a/sys/netinet/ip.h +++ b/sys/netinet/ip.h @@ -1,4 +1,4 @@ -/* $NetBSD: ip.h,v 1.9 1995/05/15 01:22:44 cgd Exp $ */ +/* $NetBSD: ip.h,v 1.10 1996/09/06 05:07:43 mrg Exp $ */ /* * Copyright (c) 1982, 1986, 1993 @@ -160,6 +160,35 @@ struct ip_timestamp { #define IPOPT_SECUR_SECRET 0xd788 #define IPOPT_SECUR_TOPSECRET 0x6bc5 +/* we need this for the packet filter structure */ +#include +struct ifnet; + +/* + * The packet filter hooks are designed for anything to call them to + * possibly intercept the packet. + */ +struct packet_filter_hook { + LIST_ENTRY(packet_filter_hook) pfil_link; + int (*pfil_func) __P((void *, int, struct ifnet *, int, + struct mbuf **)); + int pfil_flags; +}; + +#define PFIL_IN 0x00000001 +#define PFIL_OUT 0x00000002 +#define PFIL_BAD 0x00000004 +#define PFIL_WAITOK 0x00000008 +#define PFIL_ALL (PFIL_IN|PFIL_OUT|PFIL_BAD) + +#ifdef _KERNEL +struct packet_filter_hook *pfil_hook_get __P((int)); +void pfil_add_hook __P((int (*func) __P((void *, int, + struct ifnet *, int, struct mbuf **)), int)); +void pfil_remove_hook __P((int (*func) __P((void *, int, + struct ifnet *, int, struct mbuf **)), int)); +#endif /* _KERNEL */ + /* * Internet implementation parameters. */ diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c index f0a3dbcd26c2..3805431b4eb5 100644 --- a/sys/netinet/ip_input.c +++ b/sys/netinet/ip_input.c @@ -1,4 +1,4 @@ -/* $NetBSD: ip_input.c,v 1.32 1996/08/14 03:46:44 thorpej Exp $ */ +/* $NetBSD: ip_input.c,v 1.33 1996/09/06 05:07:44 mrg Exp $ */ /* * Copyright (c) 1982, 1986, 1988, 1993 @@ -153,12 +153,16 @@ struct route ipforward_rt; void ipintr() { - register struct ip *ip; + register struct ip *ip = NULL; register struct mbuf *m; register struct ipq *fp; register struct in_ifaddr *ia; struct ipqent *ipqe; - int hlen, mff, s; + int hlen = 0, mff, s; +#ifdef PACKET_FILTER + struct packet_filter_hook *pfh; + struct mbuf *m0; +#endif /* PACKET_FILTER */ next: /* @@ -237,6 +241,19 @@ next: m_adj(m, ip->ip_len - m->m_pkthdr.len); } +#ifdef PACKET_FILTER + /* + * Run through list of hooks for input packets. + */ + m0 = m; + for (pfh = pfil_hook_get(PFIL_IN); pfh; pfh = pfh->pfil_link.le_next) + if (pfh->pfil_func) { + if (pfh->pfil_func(ip, hlen, m->m_pkthdr.rcvif, 0, &m0)) + goto bad; + ip = mtod(m = m0, struct ip *); + } +#endif /* PACKET_FILTER */ + /* * Process options and, if not destined for us, * ship it on. ip_dooptions returns 1 when an @@ -418,6 +435,14 @@ found: (*inetsw[ip_protox[ip->ip_p]].pr_input)(m, hlen); goto next; bad: +#ifdef PACKET_FILTER + m0 = m; + for (pfh = pfil_hook_get(PFIL_BAD); pfh; pfh = pfh->pfil_link.le_next) + if (pfh->pfil_func) { + (void)pfh->pfil_func(ip, hlen, m->m_pkthdr.rcvif, 2, &m0); + ip = mtod(m = m0, struct ip *); + } +#endif /* PACKET_FILTER */ m_freem(m); goto next; } diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c index 2f5c3e5b9f97..9bb3480a9557 100644 --- a/sys/netinet/ip_output.c +++ b/sys/netinet/ip_output.c @@ -1,4 +1,4 @@ -/* $NetBSD: ip_output.c,v 1.29 1996/02/26 23:17:12 mrg Exp $ */ +/* $NetBSD: ip_output.c,v 1.30 1996/09/06 05:07:45 mrg Exp $ */ /* * Copyright (c) 1982, 1986, 1988, 1990, 1993 @@ -92,6 +92,10 @@ ip_output(m0, va_alist) int flags; struct ip_moptions *imo; va_list ap; +#ifdef PACKET_FILTER + struct packet_filter_hook *pfh; + struct mbuf *m1; +#endif /* PACKET_FILTER */ va_start(ap, m0); opt = va_arg(ap, struct mbuf *); @@ -293,6 +297,20 @@ ip_output(m0, va_alist) } else m->m_flags &= ~M_BCAST; +#ifdef PACKET_FILTER + /* + * Run through list of hooks for output packets. + */ + m1 = m; + for (pfh = pfil_hook_get(PFIL_OUT); pfh; pfh = pfh->pfil_link.le_next) + if (pfh->pfil_func) { + if (pfh->pfil_func(ip, hlen, m->m_pkthdr.rcvif, 1, &m1)) { + error = EHOSTUNREACH; + goto bad; + } + ip = mtod(m = m1, struct ip *); + } +#endif /* PACKET_FILTER */ sendit: /* * If small enough for interface, can just send directly. @@ -398,6 +416,14 @@ done: RTFREE(ro->ro_rt); return (error); bad: +#ifdef PACKET_FILTER + m1 = m; + for (pfh = pfil_hook_get(PFIL_BAD); pfh; pfh = pfh->pfil_link.le_next) + if (pfh->pfil_func) { + (void)pfh->pfil_func(ip, hlen, m->m_pkthdr.rcvif, 2, &m1); + ip = mtod(m = m1, struct ip *); + } +#endif /* PACKET_FILTER */ m_freem(m0); goto done; }