summaryrefslogtreecommitdiffstats
path: root/sys/netinet
diff options
context:
space:
mode:
authorjulian <julian@FreeBSD.org>1998-05-25 10:37:48 +0000
committerjulian <julian@FreeBSD.org>1998-05-25 10:37:48 +0000
commit8c304384d07abcd64cb1542078a26c103aca8a0c (patch)
tree86945df8f3fb0f7337ec7ff3582e6b50d430cb7c /sys/netinet
parentbf79f2c5a4a882aa62556198a11b4823281da1f7 (diff)
downloadFreeBSD-src-8c304384d07abcd64cb1542078a26c103aca8a0c.zip
FreeBSD-src-8c304384d07abcd64cb1542078a26c103aca8a0c.tar.gz
Add optional code to change the way that divert and ipfw work together.
Prior to this change, Accidental recursion protection was done by the diverted daemon feeding back the divert port number it got the packet on, as the port number on a sendto(). IPFW knew not to redivert a packet to this port (again). Processing of the ruleset started at the beginning again, skipping that divert port. The new semantic (which is how we should have done it the first time) is that the port number in the sendto() is the rule number AFTER which processing should restart, and on a recvfrom(), the port number is the rule number which caused the diversion. This is much more flexible, and also more intuitive. If the user uses the same sockaddr received when resending, processing resumes at the rule number following that that caused the diversion. The user can however select to resume rule processing at any rule. (0 is restart at the beginning) To enable the new code use option IPFW_DIVERT_RESTART This should become the default as soon as people have looked at it a bit
Diffstat (limited to 'sys/netinet')
-rw-r--r--sys/netinet/ip_divert.c45
-rw-r--r--sys/netinet/ip_fw.c37
-rw-r--r--sys/netinet/ip_input.c27
-rw-r--r--sys/netinet/ip_output.c10
-rw-r--r--sys/netinet/ip_var.h11
5 files changed, 123 insertions, 7 deletions
diff --git a/sys/netinet/ip_divert.c b/sys/netinet/ip_divert.c
index 484d687..5410e8a 100644
--- a/sys/netinet/ip_divert.c
+++ b/sys/netinet/ip_divert.c
@@ -30,10 +30,11 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: ip_divert.c,v 1.24 1998/05/25 07:41:23 julian Exp $
+ * $Id: ip_divert.c,v 1.25 1998/05/25 08:44:31 julian Exp $
*/
#include "opt_inet.h"
+#include "opt_ipfw.h"
#ifndef INET
#error "IPDIVERT requires INET."
@@ -81,11 +82,29 @@
u_short ip_divert_port;
/*
+ * #ifndef IPFW_DIVERT_RESTART
* 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.
+ * #else
+ * A 16 bit cookie is passed to the user process.
+ * The user process can send it back to help the caller know something
+ * about where the packet came from.
+ *
+ * If IPFW is the caller then the IN cookie is the rule that sent
+ * us here and the OUT cookie is the rule after which processing
+ * should continue. Leaving it the same will make processing start
+ * at the rule number after that which sent it here. Setting it to
+ * 0 will restart processing at the beginning.
+ * #endif
*/
+#ifndef IPFW_DIVERT_RESTART
u_short ip_divert_ignore;
+#else
+
+u_short ip_divert_in_cookie;
+u_short ip_divert_out_cookie;
+#endif /* IPFW_DIVERT_RESTART */
/* Internal variables */
@@ -149,7 +168,12 @@ div_input(struct mbuf *m, int hlen)
ip = mtod(m, struct ip *);
/* Record divert port */
+#ifndef IPFW_DIVERT_RESTART
divsrc.sin_port = htons(ip_divert_port);
+#else
+ divsrc.sin_port = ip_divert_in_cookie;
+ ip_divert_in_cookie = 0;
+#endif /* IPFW_DIVERT_RESTART */
/* Restore packet header fields */
ip->ip_len += hlen;
@@ -249,12 +273,20 @@ div_output(so, m, addr, control)
if (control)
m_freem(control); /* XXX */
- /* Loopback avoidance option */
+ /* Loopback avoidance */
+#ifndef IPFW_DIVERT_RESTART
if (sin) {
ip_divert_ignore = ntohs(sin->sin_port);
} else {
ip_divert_ignore = 0;
}
+#else
+ if (sin) {
+ ip_divert_out_cookie = sin->sin_port;
+ } else {
+ ip_divert_out_cookie = 0;
+ }
+#endif /* IPFW_DIVERT_RESTART */
/* Reinject packet into the system as incoming or outgoing */
if (!sin || sin->sin_addr.s_addr == 0) {
@@ -282,6 +314,7 @@ div_output(so, m, addr, control)
char *c = sin->sin_zero;
sin->sin_port = 0;
+
/*
* Find receive interface with the given name or IP address.
* The name is user supplied data so don't trust it's size or
@@ -311,11 +344,19 @@ div_output(so, m, addr, control)
}
/* Reset for next time (and other packets) */
+#ifndef IPFW_DIVERT_RESTART
ip_divert_ignore = 0;
+#else
+ ip_divert_out_cookie = 0;
+#endif /* IPFW_DIVERT_RESTART */
return error;
cantsend:
+#ifndef IPFW_DIVERT_RESTART
ip_divert_ignore = 0;
+#else
+ ip_divert_out_cookie = 0;
+#endif /* IPFW_DIVERT_RESTART */
m_freem(m);
return error;
}
diff --git a/sys/netinet/ip_fw.c b/sys/netinet/ip_fw.c
index bcdfda0..112d9ca 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.82 1998/04/21 18:54:53 julian Exp $
+ * $Id: ip_fw.c,v 1.83 1998/05/19 14:04:29 dg Exp $
*/
/*
@@ -103,8 +103,13 @@ static ip_fw_chk_t *old_chk_ptr;
static ip_fw_ctl_t *old_ctl_ptr;
#endif
+#ifndef IPFW_DIVERT_RESTART
static int ip_fw_chk __P((struct ip **pip, int hlen,
struct ifnet *oif, int ignport, struct mbuf **m));
+#else
+static int ip_fw_chk __P((struct ip **pip, int hlen,
+ struct ifnet *oif, int pastrule, struct mbuf **m));
+#endif /* IPFW_DIVERT_RESTART */
static int ip_fw_ctl __P((int stage, struct mbuf **mm));
static char err_prefix[] = "ip_fw_ctl:";
@@ -381,7 +386,11 @@ ipfw_report(struct ip_fw *f, struct ip *ip,
* ip Pointer to packet header (struct ip *)
* hlen Packet header length
* oif Outgoing interface, or NULL if packet is incoming
+ * #ifndef IPFW_DIVERT_RESTART
* ignport Ignore all divert/tee rules to this port (if non-zero)
+ * #else
+ * pastrule Skip up to the first rule past this rule number;
+ * #endif
* *m The packet; we set to NULL when/if we nuke it.
*
* Return value:
@@ -393,8 +402,13 @@ ipfw_report(struct ip_fw *f, struct ip *ip,
*/
static int
+#ifndef IPFW_DIVERT_RESTART
ip_fw_chk(struct ip **pip, int hlen,
struct ifnet *oif, int ignport, struct mbuf **m)
+#else
+ip_fw_chk(struct ip **pip, int hlen,
+ struct ifnet *oif, int pastrule, struct mbuf **m)
+#endif /* IPFW_DIVERT_RESTART */
{
struct ip_fw_chain *chain;
struct ip_fw *rule = NULL;
@@ -405,8 +419,24 @@ ip_fw_chk(struct ip **pip, int hlen,
/*
* Go down the chain, looking for enlightment
+ * #ifdef IPFW_DIVERT_RESTART
+ * If we've been asked to start at a given rule immediatly, do so.
+ * #endif
*/
+#ifndef IPFW_DIVERT_RESTART
for (chain=LIST_FIRST(&ip_fw_chain); chain; chain = LIST_NEXT(chain, chain)) {
+#else
+ chain=LIST_FIRST(&ip_fw_chain);
+ if ( pastrule ) {
+ if (pastrule >= 65535)
+ goto dropit;
+ while (chain && (chain->rule->fw_number <= pastrule)) {
+ chain = LIST_NEXT(chain, chain);
+ }
+ if (! chain) goto dropit;
+ }
+ for (; chain; chain = LIST_NEXT(chain, chain)) {
+#endif /* IPFW_DIVERT_RESTART */
register struct ip_fw *const f = chain->rule;
if (oif) {
@@ -556,6 +586,7 @@ bogusfrag:
}
got_match:
+#ifndef IPFW_DIVERT_RESTART
/* Ignore divert/tee rule if socket port is "ignport" */
switch (f->fw_flg & IP_FW_F_COMMAND) {
case IP_FW_F_DIVERT:
@@ -565,6 +596,7 @@ got_match:
break;
}
+#endif /* IPFW_DIVERT_RESTART */
/* Update statistics */
f->fw_pcnt += 1;
f->fw_bcnt += ip->ip_len;
@@ -581,6 +613,9 @@ got_match:
case IP_FW_F_COUNT:
continue;
case IP_FW_F_DIVERT:
+#ifdef IPFW_DIVERT_RESTART
+ ip_divert_in_cookie = f->fw_number;
+#endif /* IPFW_DIVERT_RESTART */
return(f->fw_divert_port);
case IP_FW_F_TEE:
/*
diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c
index f80c483..fe0b3a4 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.83 1998/05/19 14:04:32 dg Exp $
+ * $Id: ip_input.c,v 1.84 1998/05/24 14:59:57 dg Exp $
* $ANA: ip_input.c,v 1.5 1996/09/18 14:34:59 wollman Exp $
*/
@@ -362,8 +362,15 @@ tooshort:
#ifdef IPDIVERT
u_short port;
+#ifndef IPFW_DIVERT_RESTART
port = (*ip_fw_chk_ptr)(&ip, hlen, NULL, ip_divert_ignore, &m);
ip_divert_ignore = 0;
+#else
+ ip_divert_in_cookie = 0;
+ port = (*ip_fw_chk_ptr)(&ip, hlen, NULL,
+ ip_divert_out_cookie, &m);
+ ip_divert_out_cookie = 0;
+#endif /* IPFW_DIVERT_RESTART */
if (port) { /* Divert packet */
frag_divert_port = port;
goto ours;
@@ -594,6 +601,12 @@ found:
ipstat.ips_noproto++;
goto bad;
}
+
+ /* Don't let packets divert themselves */
+ if (ip->ip_p == IPPROTO_DIVERT) {
+ ipstat.ips_noproto++;
+ goto bad;
+ }
#endif
/*
@@ -669,6 +682,9 @@ ip_reass(ip, fp, where)
fp->ipq_dst = ((struct ip *)ip)->ip_dst;
#ifdef IPDIVERT
fp->ipq_divert = 0;
+#ifdef IPFW_DIVERT_RESTART
+ fp->ipq_div_cookie = 0;
+#endif /* IPFW_DIVERT_RESTART */
#endif
q = (struct ipasfrag *)fp;
goto insert;
@@ -723,8 +739,12 @@ insert:
/*
* Any fragment diverting causes the whole packet to divert
*/
- if (frag_divert_port != 0)
+ if (frag_divert_port != 0) {
fp->ipq_divert = frag_divert_port;
+#ifdef IPFW_DIVERT_RESTART
+ fp->ipq_div_cookie = ip_divert_in_cookie;
+#endif /* IPFW_DIVERT_RESTART */
+ }
frag_divert_port = 0;
#endif
@@ -772,6 +792,9 @@ insert:
* Record divert port for packet, if any
*/
frag_divert_port = fp->ipq_divert;
+#ifdef IPFW_DIVERT_RESTART
+ ip_divert_in_cookie = fp->ipq_div_cookie;
+#endif /* IPFW_DIVERT_RESTART */
#endif
/*
diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c
index 158aba5..da061bb 100644
--- a/sys/netinet/ip_output.c
+++ b/sys/netinet/ip_output.c
@@ -31,11 +31,12 @@
* SUCH DAMAGE.
*
* @(#)ip_output.c 8.3 (Berkeley) 1/21/94
- * $Id: ip_output.c,v 1.65 1998/02/20 13:37:38 bde Exp $
+ * $Id: ip_output.c,v 1.66 1998/03/21 11:34:20 peter Exp $
*/
#define _IP_VHL
+#include "opt_ipfw.h"
#include "opt_ipdivert.h"
#include "opt_ipfilter.h"
@@ -370,9 +371,16 @@ sendit:
*/
if (ip_fw_chk_ptr) {
#ifdef IPDIVERT
+#ifndef IPFW_DIVERT_RESTART
ip_divert_port = (*ip_fw_chk_ptr)(&ip,
hlen, ifp, ip_divert_ignore, &m);
ip_divert_ignore = 0;
+#else
+ ip_divert_in_cookie = 0;
+ ip_divert_port = (*ip_fw_chk_ptr)(&ip,
+ hlen, ifp, ip_divert_out_cookie, &m);
+ ip_divert_out_cookie = 0;
+#endif /* IPFW_DIVERT_RESTART */
if (ip_divert_port) { /* Divert packet */
(*inetsw[ip_protox[IPPROTO_DIVERT]].pr_input)(m, 0);
goto done;
diff --git a/sys/netinet/ip_var.h b/sys/netinet/ip_var.h
index 985e17e..a0aaeef 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.36 1998/05/19 14:19:03 dg Exp $
+ * $Id: ip_var.h,v 1.37 1998/05/19 15:53:50 pb Exp $
*/
#ifndef _NETINET_IP_VAR_H_
@@ -65,6 +65,9 @@ struct ipq {
struct in_addr ipq_src,ipq_dst;
#ifdef IPDIVERT
u_short ipq_divert; /* divert protocol port */
+#ifdef IPFW_DIVERT_RESTART
+ u_short ipq_div_cookie; /* divert protocol cookie */
+#endif /* IPFW_DIVERT_RESTART */
#endif
};
@@ -207,7 +210,13 @@ void div_init __P((void));
void div_input __P((struct mbuf *, int));
extern struct pr_usrreqs div_usrreqs;
extern u_short ip_divert_port;
+#ifndef IPFW_DIVERT_RESTART
extern u_short ip_divert_ignore;
+#else
+extern u_short ip_divert_in_cookie;
+extern u_short ip_divert_out_cookie;
+
+#endif /* IPFW_DIVERT_RESTART */
#endif /* IPDIVERT */
#endif /* KERNEL */
OpenPOWER on IntegriCloud