aboutsummaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorJulian Elischer <julian@FreeBSD.org>1996-07-10 19:44:30 +0000
committerJulian Elischer <julian@FreeBSD.org>1996-07-10 19:44:30 +0000
commit93e0e11657c61975fdd909f535d89bc6f0eaeceb (patch)
tree5affe14a214c46b4bd58b410a49350e34137ed18 /sys
parent265c33c02735b31902caed1f0bc5fe3bdfc644d3 (diff)
Notes
Diffstat (limited to 'sys')
-rw-r--r--sys/conf/NOTES5
-rw-r--r--sys/conf/files1
-rw-r--r--sys/i386/conf/LINT5
-rw-r--r--sys/i386/conf/NOTES5
-rw-r--r--sys/netinet/in.h3
-rw-r--r--sys/netinet/in_proto.c12
-rw-r--r--sys/netinet/ip_divert.c365
-rw-r--r--sys/netinet/ip_fw.c126
-rw-r--r--sys/netinet/ip_fw.h15
-rw-r--r--sys/netinet/ip_input.c71
-rw-r--r--sys/netinet/ip_output.c33
-rw-r--r--sys/netinet/ip_var.h16
12 files changed, 597 insertions, 60 deletions
diff --git a/sys/conf/NOTES b/sys/conf/NOTES
index d4884f6e71b7c..586ac17b33d69 100644
--- a/sys/conf/NOTES
+++ b/sys/conf/NOTES
@@ -2,7 +2,7 @@
# LINT -- config file for checking all the sources, tries to pull in
# as much of the source tree as it can.
#
-# $Id: LINT,v 1.272 1996/06/26 19:42:06 gpalmer Exp $
+# $Id: LINT,v 1.273 1996/07/05 18:48:59 jhay Exp $
#
# NB: You probably don't want to try running a kernel built from this
# file. Instead, you should start from GENERIC, and add options from
@@ -233,6 +233,8 @@ pseudo-device tun 1 #Tunnel driver(user process ppp)
# logged packets to the system logger. IPFIREWALL_VERBOSE_LIMIT
# limits the number of times a matching entry can be logged.
#
+# IPDIVERT enables the divert IP sockets, used by ``ipfw divert''
+#
# TCPDEBUG is undocumented.
#
options "TCP_COMPAT_42" #emulate 4.2BSD TCP bugs
@@ -241,6 +243,7 @@ options IPFIREWALL #firewall
options IPFIREWALL_VERBOSE #print information about
# dropped packets
options "IPFIREWALL_VERBOSE_LIMIT=100" #limit verbosity
+options IPDIVERT #divert sockets
options TCPDEBUG
diff --git a/sys/conf/files b/sys/conf/files
index 1a4752e08e496..fd3d22bf233e2 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -198,6 +198,7 @@ netinet/ip_icmp.c optional inet
netinet/ip_input.c optional inet
netinet/ip_mroute.c optional inet
netinet/ip_output.c optional inet
+netinet/ip_divert.c optional ipdivert
netinet/raw_ip.c optional inet
netinet/ip_fw.c optional ipfirewall
netinet/tcp_debug.c optional tcpdebug
diff --git a/sys/i386/conf/LINT b/sys/i386/conf/LINT
index d4884f6e71b7c..586ac17b33d69 100644
--- a/sys/i386/conf/LINT
+++ b/sys/i386/conf/LINT
@@ -2,7 +2,7 @@
# LINT -- config file for checking all the sources, tries to pull in
# as much of the source tree as it can.
#
-# $Id: LINT,v 1.272 1996/06/26 19:42:06 gpalmer Exp $
+# $Id: LINT,v 1.273 1996/07/05 18:48:59 jhay Exp $
#
# NB: You probably don't want to try running a kernel built from this
# file. Instead, you should start from GENERIC, and add options from
@@ -233,6 +233,8 @@ pseudo-device tun 1 #Tunnel driver(user process ppp)
# logged packets to the system logger. IPFIREWALL_VERBOSE_LIMIT
# limits the number of times a matching entry can be logged.
#
+# IPDIVERT enables the divert IP sockets, used by ``ipfw divert''
+#
# TCPDEBUG is undocumented.
#
options "TCP_COMPAT_42" #emulate 4.2BSD TCP bugs
@@ -241,6 +243,7 @@ options IPFIREWALL #firewall
options IPFIREWALL_VERBOSE #print information about
# dropped packets
options "IPFIREWALL_VERBOSE_LIMIT=100" #limit verbosity
+options IPDIVERT #divert sockets
options TCPDEBUG
diff --git a/sys/i386/conf/NOTES b/sys/i386/conf/NOTES
index d4884f6e71b7c..586ac17b33d69 100644
--- a/sys/i386/conf/NOTES
+++ b/sys/i386/conf/NOTES
@@ -2,7 +2,7 @@
# LINT -- config file for checking all the sources, tries to pull in
# as much of the source tree as it can.
#
-# $Id: LINT,v 1.272 1996/06/26 19:42:06 gpalmer Exp $
+# $Id: LINT,v 1.273 1996/07/05 18:48:59 jhay Exp $
#
# NB: You probably don't want to try running a kernel built from this
# file. Instead, you should start from GENERIC, and add options from
@@ -233,6 +233,8 @@ pseudo-device tun 1 #Tunnel driver(user process ppp)
# logged packets to the system logger. IPFIREWALL_VERBOSE_LIMIT
# limits the number of times a matching entry can be logged.
#
+# IPDIVERT enables the divert IP sockets, used by ``ipfw divert''
+#
# TCPDEBUG is undocumented.
#
options "TCP_COMPAT_42" #emulate 4.2BSD TCP bugs
@@ -241,6 +243,7 @@ options IPFIREWALL #firewall
options IPFIREWALL_VERBOSE #print information about
# dropped packets
options "IPFIREWALL_VERBOSE_LIMIT=100" #limit verbosity
+options IPDIVERT #divert sockets
options TCPDEBUG
diff --git a/sys/netinet/in.h b/sys/netinet/in.h
index f19aaeb2d988b..437489f1541a3 100644
--- a/sys/netinet/in.h
+++ b/sys/netinet/in.h
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* @(#)in.h 8.3 (Berkeley) 1/3/94
- * $Id: in.h,v 1.16 1996/03/14 16:59:18 fenner Exp $
+ * $Id: in.h,v 1.17 1996/04/03 13:52:11 phk Exp $
*/
#ifndef _NETINET_IN_H_
@@ -60,6 +60,7 @@
#define IPPROTO_EON 80 /* ISO cnlp */
#define IPPROTO_ENCAP 98 /* encapsulation header */
+#define IPPROTO_DIVERT 254 /* divert pseudo-protocol */
#define IPPROTO_RAW 255 /* raw IP packet */
#define IPPROTO_MAX 256
diff --git a/sys/netinet/in_proto.c b/sys/netinet/in_proto.c
index ab9591bd6e8de..fef71acc53bac 100644
--- a/sys/netinet/in_proto.c
+++ b/sys/netinet/in_proto.c
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* @(#)in_proto.c 8.2 (Berkeley) 2/9/95
- * $Id: in_proto.c,v 1.30 1996/05/08 04:34:03 gpalmer Exp $
+ * $Id: in_proto.c,v 1.31 1996/06/20 17:52:32 fenner Exp $
*/
#include <sys/param.h>
@@ -132,6 +132,13 @@ struct protosw inetsw[] = {
rip_usrreq,
0, 0, 0, 0,
},
+#ifdef IPDIVERT
+{ SOCK_RAW, &inetdomain, IPPROTO_DIVERT, PR_ATOMIC|PR_ADDR,
+ div_input, 0, 0, ip_ctloutput,
+ div_usrreq,
+ div_init, 0, 0, 0,
+},
+#endif
#ifdef TPIP
{ SOCK_SEQPACKET,&inetdomain, IPPROTO_TP, PR_CONNREQUIRED|PR_WANTRCVD,
tpip_input, 0, tpip_ctlinput, tp_ctloutput,
@@ -187,4 +194,7 @@ SYSCTL_NODE(_net_inet, IPPROTO_ICMP, icmp, CTLFLAG_RW, 0, "ICMP");
SYSCTL_NODE(_net_inet, IPPROTO_UDP, udp, CTLFLAG_RW, 0, "UDP");
SYSCTL_NODE(_net_inet, IPPROTO_TCP, tcp, CTLFLAG_RW, 0, "TCP");
SYSCTL_NODE(_net_inet, IPPROTO_IGMP, igmp, CTLFLAG_RW, 0, "IGMP");
+#ifdef IPDIVERT
+SYSCTL_NODE(_net_inet, IPPROTO_DIVERT, div, CTLFLAG_RW, 0, "DIVERT");
+#endif
diff --git a/sys/netinet/ip_divert.c b/sys/netinet/ip_divert.c
new file mode 100644
index 0000000000000..7720f8484268c
--- /dev/null
+++ b/sys/netinet/ip_divert.c
@@ -0,0 +1,365 @@
+/*
+ * Copyright (c) 1982, 1986, 1988, 1993
+ * The Regents of the University of California. 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ *
+ * $Id: ip_divert.c,v 1.2 1996/06/14 00:28:38 archie Exp $
+ */
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/protosw.h>
+#include <sys/socketvar.h>
+#include <sys/errno.h>
+#include <sys/systm.h>
+
+#include <net/if.h>
+#include <net/route.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/in_pcb.h>
+#include <netinet/in_var.h>
+#include <netinet/ip_var.h>
+
+/*
+ * Divert sockets
+ */
+
+/*
+ * Allocate enough space to hold a full IP packet
+ */
+#define DIVSNDQ (65536 + 100)
+#define DIVRCVQ (65536 + 100)
+
+/* Global variables */
+
+/*
+ * ip_input() and ip_output() set this secret value before calling us to
+ * let us know which divert port to divert a packet to; this is done so
+ * we can use the existing prototype for struct protosw's pr_input().
+ * This is stored in host order.
+ */
+u_short ip_divert_port;
+
+/*
+ * We set this value to a non-zero port number when we want the call to
+ * ip_fw_chk() in ip_input() or ip_output() to ignore ``divert <port>''
+ * chain entries. This is stored in host order.
+ */
+u_short ip_divert_ignore;
+
+/* Internal variables */
+
+static struct inpcbhead divcb;
+static struct inpcbinfo divcbinfo;
+
+static u_long div_sendspace = DIVSNDQ; /* XXX sysctl ? */
+static u_long div_recvspace = DIVRCVQ; /* XXX sysctl ? */
+
+/* Optimization: have this preinitialized */
+static struct sockaddr_in divsrc = { sizeof(divsrc), AF_INET };
+
+/* Internal functions */
+
+static int div_output(struct socket *so,
+ struct mbuf *m, struct mbuf *addr, struct mbuf *control);
+
+/*
+ * Initialize divert connection block queue.
+ */
+void
+div_init(void)
+{
+ LIST_INIT(&divcb);
+ divcbinfo.listhead = &divcb;
+ /*
+ * XXX We don't use the hash list for divert IP, but it's easier
+ * to allocate a one entry hash list than it is to check all
+ * over the place for hashbase == NULL.
+ */
+ divcbinfo.hashbase = phashinit(1, M_PCB, &divcbinfo.hashsize);
+}
+
+/*
+ * Setup generic address and protocol structures
+ * for div_input routine, then pass them along with
+ * mbuf chain. ip->ip_len is assumed to have had
+ * the header length (hlen) subtracted out already.
+ * We tell whether the packet was incoming or outgoing
+ * by seeing if hlen == 0, which is a hack.
+ */
+void
+div_input(struct mbuf *m, int hlen)
+{
+ register struct ip *ip = mtod(m, struct ip *);
+ register struct inpcb *inp;
+ register struct socket *sa;
+
+ /* Sanity check */
+ if (ip_divert_port == 0)
+ panic("div_input");
+
+ /* Record divert port */
+ divsrc.sin_port = htons(ip_divert_port);
+
+ /* Restore packet header fields */
+ ip->ip_len += hlen;
+ HTONS(ip->ip_len);
+ HTONS(ip->ip_off);
+
+ /* Record receive interface address, if any */
+ divsrc.sin_addr.s_addr = 0;
+ if (hlen) {
+ struct ifaddr *ifa;
+
+ /* More fields affected by ip_input() */
+ HTONS(ip->ip_id);
+
+ /* Find IP address for recieve interface */
+ for (ifa = m->m_pkthdr.rcvif->if_addrlist;
+ ifa != NULL; ifa = ifa->ifa_next) {
+ if (ifa->ifa_addr == NULL)
+ continue;
+ if (ifa->ifa_addr->sa_family != AF_INET)
+ continue;
+ divsrc.sin_addr =
+ ((struct sockaddr_in *) ifa->ifa_addr)->sin_addr;
+ break;
+ }
+ }
+
+ /* Put packet on socket queue, if any */
+ sa = NULL;
+ for (inp = divcb.lh_first; inp != NULL; inp = inp->inp_list.le_next) {
+ if (inp->inp_lport == htons(ip_divert_port))
+ sa = inp->inp_socket;
+ }
+ if (sa) {
+ if (sbappendaddr(&sa->so_rcv, (struct sockaddr *)&divsrc,
+ m, (struct mbuf *)0) == 0)
+ m_freem(m);
+ else
+ sorwakeup(sa);
+ } else {
+ m_freem(m);
+ ipstat.ips_noproto++;
+ ipstat.ips_delivered--;
+ }
+}
+
+/*
+ * Deliver packet back into the IP processing machinery.
+ *
+ * If no address specified, or address is 0.0.0.0, send to ip_output();
+ * otherwise, send to ip_input() and mark as having been received on
+ * the interface with that address.
+ *
+ * If no address specified, or dest port is 0, allow packet to divert
+ * back to this socket; otherwise, don't.
+ */
+static int
+div_output(so, m, addr, control)
+ struct socket *so;
+ register struct mbuf *m;
+ struct mbuf *addr, *control;
+{
+ register struct inpcb *const inp = sotoinpcb(so);
+ register struct ip *const ip = mtod(m, struct ip *);
+ struct sockaddr_in *sin = NULL;
+ int error = 0;
+
+ if (control)
+ m_freem(control); /* XXX */
+ if (addr)
+ sin = mtod(addr, struct sockaddr_in *);
+
+ /* Loopback avoidance option */
+ if (sin && sin->sin_port)
+ ip_divert_ignore = ntohs(inp->inp_lport);
+
+ /* Reinject packet into the system as incoming or outgoing */
+ if (!sin || sin->sin_addr.s_addr == 0) {
+ /* Don't allow both user specified and setsockopt options,
+ and don't allow packet length sizes that will crash */
+ if (((ip->ip_hl != (sizeof (*ip) >> 2)) && inp->inp_options) ||
+ ((u_short)ntohs(ip->ip_len) > m->m_pkthdr.len)) {
+ error = EINVAL;
+ goto cantsend;
+ }
+
+ /* Convert fields to host order for ip_output() */
+ NTOHS(ip->ip_len);
+ NTOHS(ip->ip_off);
+
+ /* Send packet to output processing */
+ ipstat.ips_rawout++; /* XXX */
+ error = ip_output(m, inp->inp_options, &inp->inp_route,
+ (so->so_options & SO_DONTROUTE) |
+ IP_ALLOWBROADCAST | IP_RAWOUTPUT, inp->inp_moptions);
+ } else {
+ struct ifaddr *ifa;
+
+ /* Find receive interface with the given IP address */
+ sin->sin_port = 0;
+ if ((ifa = ifa_ifwithaddr((struct sockaddr *) sin)) == 0) {
+ error = EADDRNOTAVAIL;
+ goto cantsend;
+ }
+ m->m_pkthdr.rcvif = ifa->ifa_ifp;
+
+ /* Send packet to input processing */
+ ip_input(m);
+ }
+
+ /* Reset for next time (and other packets) */
+ ip_divert_ignore = 0;
+ return error;
+
+cantsend:
+ ip_divert_ignore = 0;
+ m_freem(m);
+ return error;
+}
+
+/*ARGSUSED*/
+int
+div_usrreq(so, req, m, nam, control)
+ register struct socket *so;
+ int req;
+ struct mbuf *m, *nam, *control;
+{
+ register int error = 0;
+ register struct inpcb *inp = sotoinpcb(so);
+ int s = 0;
+
+ if (inp == NULL && req != PRU_ATTACH) {
+ error = EINVAL;
+ goto release;
+ }
+ switch (req) {
+
+ case PRU_ATTACH:
+ if (inp)
+ panic("div_attach");
+ if ((so->so_state & SS_PRIV) == 0) {
+ error = EACCES;
+ break;
+ }
+ if ((error = soreserve(so, div_sendspace, div_recvspace)) ||
+ (error = in_pcballoc(so, &divcbinfo)))
+ break;
+ inp = (struct inpcb *)so->so_pcb;
+ inp->inp_ip.ip_p = (int)nam; /* XXX */
+ inp->inp_flags |= INP_HDRINCL;
+ /* The socket is always "connected" because
+ we always know "where" to send the packet */
+ so->so_state |= SS_ISCONNECTED;
+ break;
+
+ case PRU_DISCONNECT:
+ if ((so->so_state & SS_ISCONNECTED) == 0) {
+ error = ENOTCONN;
+ break;
+ }
+ /* FALLTHROUGH */
+ case PRU_ABORT:
+ soisdisconnected(so);
+ /* FALLTHROUGH */
+ case PRU_DETACH:
+ if (inp == 0)
+ panic("div_detach");
+ in_pcbdetach(inp);
+ break;
+
+ case PRU_BIND:
+ s = splnet();
+ error = in_pcbbind(inp, nam);
+ splx(s);
+ break;
+
+ /*
+ * Mark the connection as being incapable of further input.
+ */
+ case PRU_SHUTDOWN:
+ socantsendmore(so);
+ break;
+
+ case PRU_SEND:
+ /* Packet must have a header (but that's about it) */
+ if (m->m_len < sizeof (struct ip) ||
+ (m = m_pullup(m, sizeof (struct ip))) == 0) {
+ ipstat.ips_toosmall++;
+ error = EINVAL;
+ break;
+ }
+
+ /* Send packet */
+ error = div_output(so, m, nam, control);
+ m = NULL;
+ break;
+
+ case PRU_SOCKADDR:
+ in_setsockaddr(inp, nam);
+ break;
+
+ case PRU_SENSE:
+ /*
+ * stat: don't bother with a blocksize.
+ */
+ return (0);
+
+ /*
+ * Not supported.
+ */
+ case PRU_CONNECT:
+ case PRU_CONNECT2:
+ case PRU_CONTROL:
+ case PRU_RCVOOB:
+ case PRU_RCVD:
+ case PRU_LISTEN:
+ case PRU_ACCEPT:
+ case PRU_SENDOOB:
+ case PRU_PEERADDR:
+ error = EOPNOTSUPP;
+ break;
+
+ default:
+ panic("div_usrreq");
+ }
+release:
+ if (m)
+ m_freem(m);
+ return (error);
+}
diff --git a/sys/netinet/ip_fw.c b/sys/netinet/ip_fw.c
index c8b34ff08b38b..4308250bd7184 100644
--- a/sys/netinet/ip_fw.c
+++ b/sys/netinet/ip_fw.c
@@ -12,7 +12,7 @@
*
* This software is provided ``AS IS'' without any warranties of any kind.
*
- * $Id: ip_fw.c,v 1.43 1996/06/29 03:33:20 alex Exp $
+ * $Id: ip_fw.c,v 1.44 1996/07/09 20:49:38 nate Exp $
*/
/*
@@ -32,11 +32,13 @@
#include <sys/time.h>
#include <sys/sysctl.h>
#include <net/if.h>
+#include <net/route.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <netinet/udp.h>
+#include <netinet/ip_var.h>
#include <netinet/ip_icmp.h>
#include <netinet/ip_fw.h>
@@ -88,7 +90,7 @@ static ip_fw_ctl_t *old_ctl_ptr;
#endif
static int ip_fw_chk __P((struct ip **pip, int hlen, struct ifnet *rif,
- int dir, struct mbuf **m));
+ int dirport, struct mbuf **m));
static int ip_fw_ctl __P((int stage, struct mbuf **mm));
@@ -257,11 +259,24 @@ ipfw_report(char *txt, int rule, struct ip *ip, int counter)
}
/*
- * Returns 1 if it should be accepted, 0 otherwise.
+ * We overload the "dirport" parameter:
+ *
+ * If dirport is negative, packet is outgoing; otherwise incoming.
+ * The low order 16 bits of dirport, if non-zero, indicate that
+ * we should ignore all ``divert <port>'' rules, where <port> is
+ * the low order 16 bits.
+ *
+ * Return value:
+ *
+ * -1 The packet was denied/rejected and has been dropped
+ * 0 The packet is to be accepted; route normally
+ * <port> Divert the packet to divert <port>, if any socket
+ * is bound to it; otherwise just drop it.
*/
static int
-ip_fw_chk(struct ip **pip, int hlen, struct ifnet *rif, int dir, struct mbuf **m)
+ip_fw_chk(struct ip **pip, int hlen,
+ struct ifnet *rif, int dirport, struct mbuf **m)
{
struct ip_fw_chain *chain;
register struct ip_fw *f = NULL;
@@ -284,7 +299,7 @@ ip_fw_chk(struct ip **pip, int hlen, struct ifnet *rif, int dir, struct mbuf **m
++frag_counter;
ipfw_report("Refuse", -1, ip, frag_counter);
m_freem(*m);
- return 0;
+ return -1;
}
src = ip->ip_src;
@@ -331,11 +346,11 @@ ip_fw_chk(struct ip **pip, int hlen, struct ifnet *rif, int dir, struct mbuf **m
f = chain->rule;
/* Check direction inbound */
- if (!dir && !(f->fw_flg & IP_FW_F_IN))
+ if (dirport >= 0 && !(f->fw_flg & IP_FW_F_IN))
continue;
/* Check direction outbound */
- if (dir && !(f->fw_flg & IP_FW_F_OUT))
+ if (dirport < 0 && !(f->fw_flg & IP_FW_F_OUT))
continue;
/* Fragments */
@@ -437,41 +452,65 @@ got_match:
f->fw_bcnt+=ip->ip_len;
f->timestamp = time.tv_sec;
if (f->fw_flg & IP_FW_F_PRN) {
- if (f->fw_flg & IP_FW_F_ACCEPT)
- ipfw_report("Allow", f->fw_number, ip, f->fw_pcnt);
- else if (f->fw_flg & IP_FW_F_COUNT)
- ipfw_report("Count", f->fw_number, ip, f->fw_pcnt);
- else
- ipfw_report("Deny", f->fw_number, ip, f->fw_pcnt);
+ if ((f->fw_flg & IP_FW_F_COMMAND) == IP_FW_F_ACCEPT) {
+ ipfw_report("Accept",
+ f->fw_number, ip, f->fw_pcnt);
+ } else if ((f->fw_flg & IP_FW_F_COMMAND)
+ == IP_FW_F_DIVERT) {
+ if (f->fw_divert_port != (dirport & 0xffff))
+ ipfw_report("Divert", f->fw_number,
+ ip, f->fw_pcnt);
+ } else if ((f->fw_flg & IP_FW_F_COMMAND)
+ == IP_FW_F_COUNT) {
+ ipfw_report("Count",
+ f->fw_number, ip, f->fw_pcnt);
+ } else {
+ ipfw_report("Deny",
+ f->fw_number, ip, f->fw_pcnt);
+ }
}
- if (f->fw_flg & IP_FW_F_ACCEPT)
- return 1;
- if (f->fw_flg & IP_FW_F_COUNT)
- continue;
- break;
+ /* Take appropriate action */
+ if ((f->fw_flg & IP_FW_F_COMMAND) == IP_FW_F_ACCEPT) {
+ return 0;
+ } else if ((f->fw_flg & IP_FW_F_COMMAND) == IP_FW_F_COUNT) {
+ continue;
+ } else if ((f->fw_flg & IP_FW_F_COMMAND) == IP_FW_F_DIVERT) {
+ if (f->fw_divert_port == (dirport & 0xffff))
+ continue; /* ignore this rule */
+ return (f->fw_divert_port);
+ } else
+ break; /* ie, deny/reject */
}
+#ifdef DIAGNOSTIC
+ if (!chain) /* rule 65535 should always be there */
+ panic("ip_fw: chain");
+ if (!f)
+ panic("ip_fw: entry");
+#endif
+
/*
- * Don't icmp outgoing packets at all
+ * At this point, we're going to drop the packet.
+ * Send an ICMP only if all of the following are true:
+ *
+ * - The packet is an incoming packet
+ * - The packet matched a deny rule
+ * - The packet is not an ICMP packet
+ * - The rule has the special ICMP reply flag set
*/
- if (f != NULL && !dir) {
- /*
- * Do not ICMP reply to icmp packets....:) or to packets
- * rejected by entry without the special ICMP reply flag.
- */
- if ((f_prt != IP_FW_F_ICMP) && (f->fw_flg & IP_FW_F_ICMPRPL)) {
- if (f_prt == IP_FW_F_ALL)
- icmp_error(*m, ICMP_UNREACH,
- ICMP_UNREACH_HOST, 0L, 0);
- else
- icmp_error(*m, ICMP_UNREACH,
- ICMP_UNREACH_PORT, 0L, 0);
- return 0;
- }
+ if (dirport >= 0
+ && (f->fw_flg & IP_FW_F_COMMAND) == IP_FW_F_DENY
+ && (f_prt != IP_FW_F_ICMP)
+ && (f->fw_flg & IP_FW_F_ICMPRPL)) {
+ if (f_prt == IP_FW_F_ALL)
+ icmp_error(*m, ICMP_UNREACH, ICMP_UNREACH_HOST, 0L, 0);
+ else
+ icmp_error(*m, ICMP_UNREACH, ICMP_UNREACH_PORT, 0L, 0);
+ return -1;
}
m_freem(*m);
- return 0;
+ return -1;
}
static int
@@ -659,6 +698,13 @@ check_ipfw_struct(struct mbuf *m)
dprintf(("ip_fw_ctl: rule never matches\n"));
return(NULL);
}
+
+ /* Diverting to port zero is illegal */
+ if ((frwl->fw_flg & IP_FW_F_COMMAND) == IP_FW_F_DIVERT
+ && frwl->fw_divert_port == 0) {
+ dprintf(("ip_fw_ctl: can't divert to port 0\n"));
+ return (NULL);
+ }
return frwl;
}
@@ -742,15 +788,21 @@ ip_fw_init(void)
deny.fw_flg = IP_FW_F_ALL;
deny.fw_number = (u_short)-1;
add_entry(&ip_fw_chain, &deny);
-
- printf("IP firewall initialized, ");
+
+ printf("IP packet filtering initialized, "
+#ifdef IPDIVERT
+ "divert enabled, ");
+#else
+ "divert disabled, ");
+#endif
#ifndef IPFIREWALL_VERBOSE
printf("logging disabled\n");
#else
if (fw_verbose_limit == 0)
printf("unlimited logging\n");
else
- printf("logging limited to %d packets/entry\n", fw_verbose_limit);
+ printf("logging limited to %d packets/entry\n",
+ fw_verbose_limit);
#endif
}
diff --git a/sys/netinet/ip_fw.h b/sys/netinet/ip_fw.h
index a8b11a811b678..b63bc74aa6283 100644
--- a/sys/netinet/ip_fw.h
+++ b/sys/netinet/ip_fw.h
@@ -11,7 +11,7 @@
*
* This software is provided ``AS IS'' without any warranties of any kind.
*
- * $Id: ip_fw.h,v 1.19 1996/06/02 00:14:50 gpalmer Exp $
+ * $Id: ip_fw.h,v 1.20 1996/06/09 23:46:21 alex Exp $
*/
/*
@@ -29,8 +29,8 @@ struct ip_fw {
struct in_addr fw_src, fw_dst; /* Source and destination IP addr */
struct in_addr fw_smsk, fw_dmsk; /* Mask for src and dest IP addr */
union {
- struct in_addr fu_via_ip;
- struct {
+ struct in_addr fu_via_ip; /* Specified by IP address */
+ struct { /* Specified by interface name */
#define FW_IFNLEN 6 /* To keep structure on 2^x boundary */
char fu_via_name[FW_IFNLEN];
short fu_via_unit;
@@ -52,6 +52,7 @@ struct ip_fw {
#define IP_FW_ICMPTYPES_DIM (256 / (sizeof(unsigned) * 8))
unsigned fw_icmptypes[IP_FW_ICMPTYPES_DIM]; /* ICMP types bitmap */
long timestamp; /* timestamp (tv_sec) of last match */
+ u_short fw_divert_port; /* Divert port (options IPDIVERT) */
};
struct ip_fw_chain {
@@ -72,11 +73,15 @@ struct ip_fw_chain {
#define IP_FW_F_IN 0x0004 /* Inbound */
#define IP_FW_F_OUT 0x0008 /* Outbound */
+#define IP_FW_F_COMMAND 0x0030 /* Mask for type of chain entry: */
#define IP_FW_F_ACCEPT 0x0010 /* This is an accept rule */
-#define IP_FW_F_COUNT 0x0020 /* This is an accept rule */
+#define IP_FW_F_COUNT 0x0020 /* This is a count rule */
+#define IP_FW_F_DIVERT 0x0030 /* This is a divert rule */
+#define IP_FW_F_DENY 0x0000 /* This is a deny rule */
+
#define IP_FW_F_PRN 0x0040 /* Print if this rule matches */
#define IP_FW_F_ICMPRPL 0x0080 /* Send back icmp unreachable packet */
-
+
#define IP_FW_F_SRNG 0x0100 /* The first two src ports are a min *
* and max range (stored in host byte *
* order). */
diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c
index 5db23ec79546e..2a17342017f30 100644
--- a/sys/netinet/ip_input.c
+++ b/sys/netinet/ip_input.c
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* @(#)ip_input.c 8.2 (Berkeley) 1/4/94
- * $Id: ip_input.c,v 1.43 1996/06/08 08:18:57 bde Exp $
+ * $Id: ip_input.c,v 1.44 1996/06/12 19:34:33 gpalmer Exp $
*/
#include "opt_ipfw.h"
@@ -129,6 +129,15 @@ static struct ip_srcrt {
struct in_addr route[MAX_IPOPTLEN/sizeof(struct in_addr)];
} ip_srcrt;
+#ifdef IPDIVERT
+/*
+ * Shared variable between ip_input() and ip_reass() to communicate
+ * about which packets, once assembled from fragments, get diverted,
+ * and to which port.
+ */
+static u_short frag_divert_port;
+#endif
+
static void save_rte __P((u_char *, struct in_addr));
static void ip_deq __P((struct ipasfrag *));
static int ip_dooptions __P((struct mbuf *));
@@ -255,14 +264,31 @@ ip_input(struct mbuf *m)
* Right now when no processing on packet has done
* and it is still fresh out of network we do our black
* deals with it.
- * - Firewall: deny/allow
+ * - Firewall: deny/allow/divert
* - Wrap: fake packet's addr/port <unimpl.>
* - Encapsulate: put it in another IP and send out. <unimp.>
*/
- if (ip_fw_chk_ptr &&
- !(*ip_fw_chk_ptr)(&ip, hlen, m->m_pkthdr.rcvif, 0, &m))
- return;
+ if (ip_fw_chk_ptr) {
+ int action;
+
+#ifdef IPDIVERT
+ action = (*ip_fw_chk_ptr)(&ip, hlen,
+ m->m_pkthdr.rcvif, ip_divert_ignore, &m);
+#else
+ action = (*ip_fw_chk_ptr)(&ip, hlen, m->m_pkthdr.rcvif, 0, &m);
+#endif
+ if (action == -1)
+ return;
+ if (action != 0) {
+#ifdef IPDIVERT
+ frag_divert_port = action;
+ goto ours;
+#else
+ goto bad; /* ipfw said divert but we can't */
+#endif
+ }
+ }
/*
* Process options and, if not destined for us,
@@ -386,6 +412,9 @@ ours:
if (m->m_flags & M_EXT) { /* XXX */
if ((m = m_pullup(m, sizeof (struct ip))) == 0) {
ipstat.ips_toosmall++;
+#ifdef IPDIVERT
+ frag_divert_port = 0;
+#endif
return;
}
ip = mtod(m, struct ip *);
@@ -432,6 +461,18 @@ found:
} else
ip->ip_len -= hlen;
+#ifdef IPDIVERT
+ /*
+ * Divert packets here to the divert protocol if required
+ */
+ if (frag_divert_port) {
+ ip_divert_port = frag_divert_port;
+ frag_divert_port = 0;
+ (*inetsw[ip_protox[IPPROTO_DIVERT]].pr_input)(m, hlen);
+ return;
+ }
+#endif
+
/*
* Switch out to protocol's input routine.
*/
@@ -501,6 +542,9 @@ ip_reass(ip, fp)
fp->ipq_next = fp->ipq_prev = (struct ipasfrag *)fp;
fp->ipq_src = ((struct ip *)ip)->ip_src;
fp->ipq_dst = ((struct ip *)ip)->ip_dst;
+#ifdef IPDIVERT
+ fp->ipq_divert = 0;
+#endif
q = (struct ipasfrag *)fp;
goto insert;
}
@@ -546,6 +590,16 @@ ip_reass(ip, fp)
}
insert:
+
+#ifdef IPDIVERT
+ /*
+ * Any fragment diverting causes the whole packet to divert
+ */
+ if (frag_divert_port != 0)
+ fp->ipq_divert = frag_divert_port;
+ frag_divert_port = 0;
+#endif
+
/*
* Stick new segment in its place;
* check for complete reassembly.
@@ -575,6 +629,13 @@ insert:
m_cat(m, t);
}
+#ifdef IPDIVERT
+ /*
+ * Record divert port for packet, if any
+ */
+ frag_divert_port = fp->ipq_divert;
+#endif
+
/*
* Create header for new ip packet by
* modifying header of first packet;
diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c
index 7777114bbbf7a..bb30a9fc8589f 100644
--- a/sys/netinet/ip_output.c
+++ b/sys/netinet/ip_output.c
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* @(#)ip_output.c 8.3 (Berkeley) 1/21/94
- * $Id: ip_output.c,v 1.39 1996/05/22 17:23:08 wollman Exp $
+ * $Id: ip_output.c,v 1.40 1996/06/08 08:18:59 bde Exp $
*/
#define _IP_VHL
@@ -80,6 +80,8 @@ static int ip_pcbopts __P((struct mbuf **, struct mbuf *));
static int ip_setmoptions
__P((int, struct ip_moptions **, struct mbuf *));
+extern struct protosw inetsw[];
+
/*
* IP output. The packet in mbuf chain m contains a skeletal IP
* header (with len, off, ttl, proto, tos, src, dst).
@@ -329,15 +331,34 @@ ip_output(m0, opt, ro, flags, imo)
}
sendit:
+#ifdef COMPAT_IPFW
/*
* Check with the firewall...
*/
-#ifdef COMPAT_IPFW
- if (ip_fw_chk_ptr && !(*ip_fw_chk_ptr)(&ip, hlen, ifp, 1, &m)) {
- error = EACCES;
- goto done;
- }
+ if (ip_fw_chk_ptr) {
+ int action;
+
+#ifdef IPDIVERT
+ action = (*ip_fw_chk_ptr)(&ip,
+ hlen, ifp, (~0 << 16) | ip_divert_ignore, &m);
+#else
+ action = (*ip_fw_chk_ptr)(&ip, hlen, ifp, (~0 << 16), &m);
#endif
+ if (action == -1) {
+ error = EACCES; /* XXX is this appropriate? */
+ goto done;
+ } else if (action != 0) {
+#ifdef IPDIVERT
+ ip_divert_port = action; /* divert to port */
+ (*inetsw[ip_protox[IPPROTO_DIVERT]].pr_input)(m, 0);
+ goto done;
+#else
+ m_freem(m); /* ipfw says divert, but we can't */
+ goto done;
+#endif
+ }
+ }
+#endif /* COMPAT_IPFW */
/*
* If small enough for interface, can just send directly.
diff --git a/sys/netinet/ip_var.h b/sys/netinet/ip_var.h
index 01d42d146792c..91b3bd83dddee 100644
--- a/sys/netinet/ip_var.h
+++ b/sys/netinet/ip_var.h
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* @(#)ip_var.h 8.2 (Berkeley) 1/9/95
- * $Id: ip_var.h,v 1.19 1996/01/30 22:58:27 mpp Exp $
+ * $Id: ip_var.h,v 1.20 1996/03/26 19:16:45 fenner Exp $
*/
#ifndef _NETINET_IP_VAR_H_
@@ -63,6 +63,9 @@ struct ipq {
struct ipasfrag *ipq_next,*ipq_prev;
/* to ip headers of fragments */
struct in_addr ipq_src,ipq_dst;
+#ifdef IPDIVERT
+ u_short ipq_divert; /* divert protocol port */
+#endif
};
/*
@@ -189,6 +192,15 @@ int ip_rsvp_vif_init __P((struct socket *, struct mbuf *));
int ip_rsvp_vif_done __P((struct socket *, struct mbuf *));
void ip_rsvp_force_done __P((struct socket *));
-#endif
+#ifdef IPDIVERT
+void div_init __P((void));
+void div_input __P((struct mbuf *, int));
+int div_usrreq __P((struct socket *,
+ int, struct mbuf *, struct mbuf *, struct mbuf *));
+extern u_short ip_divert_port;
+extern u_short ip_divert_ignore;
+#endif /* IPDIVERT */
+
+#endif /* KERNEL */
#endif