Support for IPFW based transparent forwarding.
Any packet that can be matched by a ipfw rule can be redirected transparently to another port or machine. Redirection to another port mostly makes sense with tcp, where a session can be set up between a proxy and an unsuspecting client. Redirection to another machine requires that the other machine also be expecting to receive the forwarded packets, as their headers will not have been modified. /sbin/ipfw must be recompiled!!! Reviewed by: Peter Wemm <peter@freebsd.org> Submitted by: Chrisy Luke <chrisy@flix.net>
This commit is contained in:
parent
28e9d7db55
commit
4483ce4f11
@ -195,7 +195,31 @@ Send a copy of packets matching this rule to the
|
|||||||
.Xr divert 4
|
.Xr divert 4
|
||||||
socket bound to port
|
socket bound to port
|
||||||
.Ar port .
|
.Ar port .
|
||||||
The search continues with the next rule.
|
The search continues with the next rule. This feature is not yet implemeted.
|
||||||
|
.It Ar fwd ipaddr Op ,port
|
||||||
|
Change the next-hop on matching packets to
|
||||||
|
.Ar ipaddr ,
|
||||||
|
which can be an IP address in dotted quad or a host name.
|
||||||
|
If
|
||||||
|
.Ar ipaddr
|
||||||
|
is not a directly-reachable address, the route
|
||||||
|
as found in the local routing table for that IP is used
|
||||||
|
instead.
|
||||||
|
If
|
||||||
|
.Ar ipaddr
|
||||||
|
is a local address, then on a packet entering the system from a remote
|
||||||
|
host it will be diverted to
|
||||||
|
.Ar port
|
||||||
|
on the local machine, keeping the local address of the socket set
|
||||||
|
to the original IP address the packet was destined for. This is intended
|
||||||
|
for use with transparent proxy servers. If the IP is not
|
||||||
|
a local address then the port number (if specified) is ignored and
|
||||||
|
the rule only applies to packets leaving the system. This will
|
||||||
|
also map addresses to local ports when packets are generated locally.
|
||||||
|
The search terminates if this rule matches. If the port number is not
|
||||||
|
given then the port number in the packet is used, so that a packet for
|
||||||
|
an external machine port Y would be forwarded to local port Y. The kernel
|
||||||
|
must have been compiled with optiions IPFIREWALL_FORWARD.
|
||||||
.It Ar skipto number
|
.It Ar skipto number
|
||||||
Skip all subsequent rules numbered less than
|
Skip all subsequent rules numbered less than
|
||||||
.Ar number .
|
.Ar number .
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
*
|
*
|
||||||
* NEW command line interface for IP firewall facility
|
* NEW command line interface for IP firewall facility
|
||||||
*
|
*
|
||||||
* $Id: ipfw.c,v 1.56 1998/04/22 06:20:20 phk Exp $
|
* $Id: ipfw.c,v 1.57 1998/05/15 12:38:07 danny Exp $
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -224,6 +224,11 @@ show_ipfw(struct ip_fw *chain, int pcwidth, int bcwidth)
|
|||||||
print_reject_code(chain->fw_reject_code);
|
print_reject_code(chain->fw_reject_code);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case IP_FW_F_FWD:
|
||||||
|
printf("fwd %s", inet_ntoa(chain->fw_fwd_ip.sin_addr));
|
||||||
|
if(chain->fw_fwd_ip.sin_port)
|
||||||
|
printf(",%d", chain->fw_fwd_ip.sin_port);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
errx(EX_OSERR, "impossible");
|
errx(EX_OSERR, "impossible");
|
||||||
}
|
}
|
||||||
@ -497,7 +502,7 @@ show_usage(const char *fmt, ...)
|
|||||||
" rule: action proto src dst extras...\n"
|
" rule: action proto src dst extras...\n"
|
||||||
" action:\n"
|
" action:\n"
|
||||||
" {allow|permit|accept|pass|deny|drop|reject|unreach code|\n"
|
" {allow|permit|accept|pass|deny|drop|reject|unreach code|\n"
|
||||||
" reset|count|skipto num|divert port|tee port} [log]\n"
|
" reset|count|skipto num|divert port|tee port|fwd ip} [log]\n"
|
||||||
" proto: {ip|tcp|udp|icmp|<number>}\n"
|
" proto: {ip|tcp|udp|icmp|<number>}\n"
|
||||||
" src: from [not] {any|ip[{/bits|:mask}]} [{port|port-port},[port],...]\n"
|
" src: from [not] {any|ip[{/bits|:mask}]} [{port|port-port},[port],...]\n"
|
||||||
" dst: to [not] {any|ip[{/bits|:mask}]} [{port|port-port},[port],...]\n"
|
" dst: to [not] {any|ip[{/bits|:mask}]} [{port|port-port},[port],...]\n"
|
||||||
@ -896,6 +901,30 @@ add(ac,av)
|
|||||||
else
|
else
|
||||||
show_usage("illegal divert port");
|
show_usage("illegal divert port");
|
||||||
}
|
}
|
||||||
|
} else if (!strncmp(*av,"fwd",strlen(*av)) ||
|
||||||
|
!strncmp(*av,"forward",strlen(*av))) {
|
||||||
|
struct in_addr dummyip;
|
||||||
|
char *pp;
|
||||||
|
rule.fw_flg |= IP_FW_F_FWD; av++; ac--;
|
||||||
|
if (!ac)
|
||||||
|
show_usage("missing forwarding IP address");
|
||||||
|
rule.fw_fwd_ip.sin_len = sizeof(struct sockaddr_in);
|
||||||
|
rule.fw_fwd_ip.sin_family = AF_INET;
|
||||||
|
rule.fw_fwd_ip.sin_port = 0;
|
||||||
|
pp = strchr(*av, ':');
|
||||||
|
if(pp == NULL)
|
||||||
|
pp = strchr(*av, ',');
|
||||||
|
if(pp != NULL)
|
||||||
|
{
|
||||||
|
*(pp++) = '\0';
|
||||||
|
rule.fw_fwd_ip.sin_port = lookup_port(pp, 1, 1);
|
||||||
|
if(rule.fw_fwd_ip.sin_port == (unsigned int)-1)
|
||||||
|
show_usage("illegal forwarding port");
|
||||||
|
}
|
||||||
|
fill_ip(&(rule.fw_fwd_ip.sin_addr), &dummyip, &ac, &av);
|
||||||
|
if (rule.fw_fwd_ip.sin_addr.s_addr == 0)
|
||||||
|
show_usage("illegal forwarding IP address");
|
||||||
|
|
||||||
} else if (!strncmp(*av,"skipto",strlen(*av))) {
|
} else if (!strncmp(*av,"skipto",strlen(*av))) {
|
||||||
rule.fw_flg |= IP_FW_F_SKIPTO; av++; ac--;
|
rule.fw_flg |= IP_FW_F_SKIPTO; av++; ac--;
|
||||||
if (!ac)
|
if (!ac)
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* @(#)in.h 8.3 (Berkeley) 1/3/94
|
* @(#)in.h 8.3 (Berkeley) 1/3/94
|
||||||
* $Id: in.h,v 1.34 1998/06/06 19:39:08 julian Exp $
|
* $Id: in.h,v 1.35 1998/06/06 20:45:25 julian Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _NETINET_IN_H_
|
#ifndef _NETINET_IN_H_
|
||||||
@ -431,7 +431,7 @@ char *inet_ntoa __P((struct in_addr)); /* in libkern */
|
|||||||
|
|
||||||
/* Firewall hooks */
|
/* Firewall hooks */
|
||||||
struct ip;
|
struct ip;
|
||||||
typedef int ip_fw_chk_t __P((struct ip**, int, struct ifnet*, u_int16_t*, struct mbuf**));
|
typedef int ip_fw_chk_t __P((struct ip**, int, struct ifnet*, u_int16_t*, struct mbuf**, struct sockaddr_in**));
|
||||||
typedef int ip_fw_ctl_t __P((int, struct mbuf**));
|
typedef int ip_fw_ctl_t __P((int, struct mbuf**));
|
||||||
extern ip_fw_chk_t *ip_fw_chk_ptr;
|
extern ip_fw_chk_t *ip_fw_chk_ptr;
|
||||||
extern ip_fw_ctl_t *ip_fw_ctl_ptr;
|
extern ip_fw_ctl_t *ip_fw_ctl_ptr;
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
*
|
*
|
||||||
* This software is provided ``AS IS'' without any warranties of any kind.
|
* This software is provided ``AS IS'' without any warranties of any kind.
|
||||||
*
|
*
|
||||||
* $Id: ip_fw.c,v 1.90 1998/06/21 14:53:30 bde Exp $
|
* $Id: ip_fw.c,v 1.91 1998/07/02 05:49:08 julian Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -103,7 +103,8 @@ static ip_fw_ctl_t *old_ctl_ptr;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int ip_fw_chk __P((struct ip **pip, int hlen,
|
static int ip_fw_chk __P((struct ip **pip, int hlen,
|
||||||
struct ifnet *oif, u_int16_t *cookie, struct mbuf **m));
|
struct ifnet *oif, u_int16_t *cookie, struct mbuf **m,
|
||||||
|
struct sockaddr_in **next_hop));
|
||||||
static int ip_fw_ctl __P((int stage, struct mbuf **mm));
|
static int ip_fw_ctl __P((int stage, struct mbuf **mm));
|
||||||
|
|
||||||
static char err_prefix[] = "ip_fw_ctl:";
|
static char err_prefix[] = "ip_fw_ctl:";
|
||||||
@ -320,6 +321,14 @@ ipfw_report(struct ip_fw *f, struct ip *ip,
|
|||||||
case IP_FW_F_SKIPTO:
|
case IP_FW_F_SKIPTO:
|
||||||
printf("SkipTo %d", f->fw_skipto_rule);
|
printf("SkipTo %d", f->fw_skipto_rule);
|
||||||
break;
|
break;
|
||||||
|
#ifdef IPFIREWALL_FORWARD
|
||||||
|
case IP_FW_F_FWD:
|
||||||
|
printf("Forward to ");
|
||||||
|
print_ip(f->fw_fwd_ip.sin_addr);
|
||||||
|
if (f->fw_fwd_ip.sin_port)
|
||||||
|
printf(":%d", f->fw_fwd_ip.sin_port);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
default:
|
default:
|
||||||
printf("UNKNOWN");
|
printf("UNKNOWN");
|
||||||
break;
|
break;
|
||||||
@ -393,7 +402,8 @@ ipfw_report(struct ip_fw *f, struct ip *ip,
|
|||||||
|
|
||||||
static int
|
static int
|
||||||
ip_fw_chk(struct ip **pip, int hlen,
|
ip_fw_chk(struct ip **pip, int hlen,
|
||||||
struct ifnet *oif, u_int16_t *cookie, struct mbuf **m)
|
struct ifnet *oif, u_int16_t *cookie, struct mbuf **m,
|
||||||
|
struct sockaddr_in **next_hop)
|
||||||
{
|
{
|
||||||
struct ip_fw_chain *chain;
|
struct ip_fw_chain *chain;
|
||||||
struct ip_fw *rule = NULL;
|
struct ip_fw *rule = NULL;
|
||||||
@ -606,11 +616,28 @@ ip_fw_chk(struct ip **pip, int hlen,
|
|||||||
#endif
|
#endif
|
||||||
chain = LIST_NEXT(chain, chain);
|
chain = LIST_NEXT(chain, chain);
|
||||||
continue;
|
continue;
|
||||||
|
#ifdef IPFIREWALL_FORWARD
|
||||||
|
case IP_FW_F_FWD:
|
||||||
|
/* Change the next-hop address for this packet.
|
||||||
|
* Initially we'll only worry about directly
|
||||||
|
* reachable next-hop's, but ultimately
|
||||||
|
* we will work out for next-hops that aren't
|
||||||
|
* direct the route we would take for it. We
|
||||||
|
* [cs]ould leave this latter problem to
|
||||||
|
* ip_output.c. We hope to high [name the abode of
|
||||||
|
* your favourite deity] that ip_output doesn't modify
|
||||||
|
* the new value of next_hop (which is dst there)
|
||||||
|
*/
|
||||||
|
if (next_hop != NULL) /* Make sure, first... */
|
||||||
|
*next_hop = &(f->fw_fwd_ip);
|
||||||
|
return(0); /* Allow the packet */
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Deny/reject this packet using this rule */
|
/* Deny/reject this packet using this rule */
|
||||||
rule = f;
|
rule = f;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DIAGNOSTIC
|
#ifdef DIAGNOSTIC
|
||||||
@ -950,6 +977,9 @@ check_ipfw_struct(struct ip_fw *frwl)
|
|||||||
case IP_FW_F_ACCEPT:
|
case IP_FW_F_ACCEPT:
|
||||||
case IP_FW_F_COUNT:
|
case IP_FW_F_COUNT:
|
||||||
case IP_FW_F_SKIPTO:
|
case IP_FW_F_SKIPTO:
|
||||||
|
#ifdef IPFIREWALL_FORWARD
|
||||||
|
case IP_FW_F_FWD:
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
dprintf(("%s invalid command\n", err_prefix));
|
dprintf(("%s invalid command\n", err_prefix));
|
||||||
@ -982,7 +1012,7 @@ ip_fw_ctl(int stage, struct mbuf **mm)
|
|||||||
if (m == NULL)
|
if (m == NULL)
|
||||||
return (ENOBUFS);
|
return (ENOBUFS);
|
||||||
MCLGET(m, M_WAIT);
|
MCLGET(m, M_WAIT);
|
||||||
if(!(m->m_flags & M_EXT)) {
|
if (!(m->m_flags & M_EXT)) {
|
||||||
abort: m_freem(*mm);
|
abort: m_freem(*mm);
|
||||||
*mm = NULL;
|
*mm = NULL;
|
||||||
return (ENOBUFS);
|
return (ENOBUFS);
|
||||||
@ -990,7 +1020,7 @@ abort: m_freem(*mm);
|
|||||||
m->m_len = 0;
|
m->m_len = 0;
|
||||||
for (; fcp; fcp = LIST_NEXT(fcp, chain)) {
|
for (; fcp; fcp = LIST_NEXT(fcp, chain)) {
|
||||||
/* Will we need a new cluster? */
|
/* Will we need a new cluster? */
|
||||||
if((m->m_len + sizeof *(fcp->rule)) > MCLBYTES) {
|
if ((m->m_len + sizeof *(fcp->rule)) > MCLBYTES) {
|
||||||
m = m->m_next = m_get(M_WAIT, MT_SOOPTS);
|
m = m->m_next = m_get(M_WAIT, MT_SOOPTS);
|
||||||
if (m == NULL) {
|
if (m == NULL) {
|
||||||
goto abort;
|
goto abort;
|
||||||
@ -1094,6 +1124,11 @@ ip_fw_init(void)
|
|||||||
#else
|
#else
|
||||||
"divert disabled, ");
|
"divert disabled, ");
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef IPFIREWALL_FORWARD
|
||||||
|
printf("rule-based forwarding enabled, ");
|
||||||
|
#else
|
||||||
|
printf("rule-based forwarding disabled, ");
|
||||||
|
#endif
|
||||||
#ifdef IPFIREWALL_DEFAULT_TO_ACCEPT
|
#ifdef IPFIREWALL_DEFAULT_TO_ACCEPT
|
||||||
printf("default to accept, ");
|
printf("default to accept, ");
|
||||||
#endif
|
#endif
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
*
|
*
|
||||||
* This software is provided ``AS IS'' without any warranties of any kind.
|
* This software is provided ``AS IS'' without any warranties of any kind.
|
||||||
*
|
*
|
||||||
* $Id: ip_fw.h,v 1.31 1998/01/08 03:03:54 alex Exp $
|
* $Id: ip_fw.h,v 1.32 1998/02/03 22:15:03 bde Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _IP_FW_H
|
#ifndef _IP_FW_H
|
||||||
@ -71,6 +71,7 @@ struct ip_fw {
|
|||||||
u_short fu_divert_port; /* Divert/tee port (options IPDIVERT) */
|
u_short fu_divert_port; /* Divert/tee port (options IPDIVERT) */
|
||||||
u_short fu_skipto_rule; /* SKIPTO command rule number */
|
u_short fu_skipto_rule; /* SKIPTO command rule number */
|
||||||
u_short fu_reject_code; /* REJECT response code */
|
u_short fu_reject_code; /* REJECT response code */
|
||||||
|
struct sockaddr_in fu_fwd_ip;
|
||||||
} fw_un;
|
} fw_un;
|
||||||
u_char fw_prot; /* IP protocol */
|
u_char fw_prot; /* IP protocol */
|
||||||
u_char fw_nports; /* N'of src ports and # of dst ports */
|
u_char fw_nports; /* N'of src ports and # of dst ports */
|
||||||
@ -93,6 +94,7 @@ struct ip_fw {
|
|||||||
#define fw_divert_port fw_un.fu_divert_port
|
#define fw_divert_port fw_un.fu_divert_port
|
||||||
#define fw_skipto_rule fw_un.fu_skipto_rule
|
#define fw_skipto_rule fw_un.fu_skipto_rule
|
||||||
#define fw_reject_code fw_un.fu_reject_code
|
#define fw_reject_code fw_un.fu_reject_code
|
||||||
|
#define fw_fwd_ip fw_un.fu_fwd_ip
|
||||||
|
|
||||||
struct ip_fw_chain {
|
struct ip_fw_chain {
|
||||||
LIST_ENTRY(ip_fw_chain) chain;
|
LIST_ENTRY(ip_fw_chain) chain;
|
||||||
@ -115,6 +117,7 @@ struct ip_fw_chain {
|
|||||||
#define IP_FW_F_DIVERT 0x0040 /* This is a divert rule */
|
#define IP_FW_F_DIVERT 0x0040 /* This is a divert rule */
|
||||||
#define IP_FW_F_TEE 0x0050 /* This is a tee rule */
|
#define IP_FW_F_TEE 0x0050 /* This is a tee rule */
|
||||||
#define IP_FW_F_SKIPTO 0x0060 /* This is a skipto rule */
|
#define IP_FW_F_SKIPTO 0x0060 /* This is a skipto rule */
|
||||||
|
#define IP_FW_F_FWD 0x0070 /* This is a "change forwarding address" rule */
|
||||||
|
|
||||||
#define IP_FW_F_PRN 0x0080 /* Print if this rule matches */
|
#define IP_FW_F_PRN 0x0080 /* Print if this rule matches */
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* @(#)ip_input.c 8.2 (Berkeley) 1/4/94
|
* @(#)ip_input.c 8.2 (Berkeley) 1/4/94
|
||||||
* $Id: ip_input.c,v 1.90 1998/06/12 03:48:16 julian Exp $
|
* $Id: ip_input.c,v 1.91 1998/07/02 05:49:12 julian Exp $
|
||||||
* $ANA: ip_input.c,v 1.5 1996/09/18 14:34:59 wollman Exp $
|
* $ANA: ip_input.c,v 1.5 1996/09/18 14:34:59 wollman Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -181,6 +181,8 @@ static struct ip_srcrt {
|
|||||||
static u_short frag_divert_port;
|
static u_short frag_divert_port;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
struct sockaddr_in *ip_fw_fwd_addr;
|
||||||
|
|
||||||
static void save_rte __P((u_char *, struct in_addr));
|
static void save_rte __P((u_char *, struct in_addr));
|
||||||
static void ip_deq __P((struct ipasfrag *));
|
static void ip_deq __P((struct ipasfrag *));
|
||||||
static int ip_dooptions __P((struct mbuf *));
|
static int ip_dooptions __P((struct mbuf *));
|
||||||
@ -354,30 +356,43 @@ ip_input(struct mbuf *m)
|
|||||||
#endif
|
#endif
|
||||||
#ifdef COMPAT_IPFW
|
#ifdef COMPAT_IPFW
|
||||||
if (ip_fw_chk_ptr) {
|
if (ip_fw_chk_ptr) {
|
||||||
#ifdef IPDIVERT
|
u_int16_t port;
|
||||||
u_short port;
|
|
||||||
|
|
||||||
port = (*ip_fw_chk_ptr)(&ip, hlen, NULL, &ip_divert_cookie, &m);
|
#ifdef IPFIREWALL_FORWARD
|
||||||
|
/*
|
||||||
|
* If we've been forwarded from the output side, then
|
||||||
|
* skip the firewall a second time
|
||||||
|
*/
|
||||||
|
if (ip_fw_fwd_addr)
|
||||||
|
goto ours;
|
||||||
|
#endif /* IPFIREWALL_FORWARD */
|
||||||
|
#ifdef IPDIVERT
|
||||||
|
port = (*ip_fw_chk_ptr)(&ip, hlen, NULL, &ip_divert_cookie,
|
||||||
|
&m, &ip_fw_fwd_addr);
|
||||||
if (port) {
|
if (port) {
|
||||||
/* Divert packet */
|
/* Divert packet */
|
||||||
frag_divert_port = port;
|
frag_divert_port = port;
|
||||||
goto ours;
|
goto ours;
|
||||||
}
|
}
|
||||||
#else
|
#else /* !DIVERT */
|
||||||
u_int16_t dummy = 0;
|
/*
|
||||||
/* If ipfw says divert, we have to just drop packet */
|
* If ipfw says divert, we have to just drop packet */
|
||||||
if ((*ip_fw_chk_ptr)(&ip, hlen, NULL, &dummy, &m)) {
|
* Use port as a dummy argument.
|
||||||
|
*/
|
||||||
|
port = 0;
|
||||||
|
if ((*ip_fw_chk_ptr)(&ip, hlen, NULL, &port,
|
||||||
|
&m, &ip_fw_fwd_addr)) {
|
||||||
m_freem(m);
|
m_freem(m);
|
||||||
m = NULL;
|
m = NULL;
|
||||||
}
|
}
|
||||||
#endif
|
#endif /* !DIVERT */
|
||||||
if (!m)
|
if (!m)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ip_nat_ptr && !(*ip_nat_ptr)(&ip, &m, m->m_pkthdr.rcvif, IP_NAT_IN))
|
if (ip_nat_ptr && !(*ip_nat_ptr)(&ip, &m, m->m_pkthdr.rcvif, IP_NAT_IN))
|
||||||
return;
|
return;
|
||||||
#endif
|
#endif /* !COMPAT_IPFW */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Process options and, if not destined for us,
|
* Process options and, if not destined for us,
|
||||||
@ -401,7 +416,8 @@ ip_input(struct mbuf *m)
|
|||||||
/*
|
/*
|
||||||
* Check our list of addresses, to see if the packet is for us.
|
* Check our list of addresses, to see if the packet is for us.
|
||||||
*/
|
*/
|
||||||
for (ia = in_ifaddrhead.tqh_first; ia; ia = ia->ia_link.tqe_next) {
|
for (ia = TAILQ_FIRST(in_ifaddrhead); ia;
|
||||||
|
ia = TAILQ_NEXT(ia, ia_link)) {
|
||||||
#define satosin(sa) ((struct sockaddr_in *)(sa))
|
#define satosin(sa) ((struct sockaddr_in *)(sa))
|
||||||
|
|
||||||
if (IA_SIN(ia)->sin_addr.s_addr == ip->ip_dst.s_addr)
|
if (IA_SIN(ia)->sin_addr.s_addr == ip->ip_dst.s_addr)
|
||||||
@ -409,6 +425,16 @@ ip_input(struct mbuf *m)
|
|||||||
#ifdef BOOTP_COMPAT
|
#ifdef BOOTP_COMPAT
|
||||||
if (IA_SIN(ia)->sin_addr.s_addr == INADDR_ANY)
|
if (IA_SIN(ia)->sin_addr.s_addr == INADDR_ANY)
|
||||||
goto ours;
|
goto ours;
|
||||||
|
#endif
|
||||||
|
#ifdef IPFIREWALL_FORWARD
|
||||||
|
/*
|
||||||
|
* If the addr to forward to is one of ours, we pretend to
|
||||||
|
* be the destination for this packet.
|
||||||
|
*/
|
||||||
|
if (ip_fw_fwd_addr != NULL &&
|
||||||
|
IA_SIN(ia)->sin_addr.s_addr ==
|
||||||
|
ip_fw_fwd_addr->sin_addr.s_addr)
|
||||||
|
goto ours;
|
||||||
#endif
|
#endif
|
||||||
if (ia->ia_ifp && ia->ia_ifp->if_flags & IFF_BROADCAST) {
|
if (ia->ia_ifp && ia->ia_ifp->if_flags & IFF_BROADCAST) {
|
||||||
if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr ==
|
if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr ==
|
||||||
@ -548,8 +574,12 @@ ip_input(struct mbuf *m)
|
|||||||
if (((struct ipasfrag *)ip)->ipf_mff & 1 || ip->ip_off) {
|
if (((struct ipasfrag *)ip)->ipf_mff & 1 || ip->ip_off) {
|
||||||
ipstat.ips_fragments++;
|
ipstat.ips_fragments++;
|
||||||
ip = ip_reass((struct ipasfrag *)ip, fp, &ipq[sum]);
|
ip = ip_reass((struct ipasfrag *)ip, fp, &ipq[sum]);
|
||||||
if (ip == 0)
|
if (ip == 0) {
|
||||||
|
#ifdef IPFIREWALL_FORWARD
|
||||||
|
ip_fw_fwd_addr = NULL;
|
||||||
|
#endif
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
/* Get the length of the reassembled packets header */
|
/* Get the length of the reassembled packets header */
|
||||||
hlen = IP_VHL_HL(ip->ip_vhl) << 2;
|
hlen = IP_VHL_HL(ip->ip_vhl) << 2;
|
||||||
ipstat.ips_reassembled++;
|
ipstat.ips_reassembled++;
|
||||||
@ -599,8 +629,14 @@ ip_input(struct mbuf *m)
|
|||||||
*/
|
*/
|
||||||
ipstat.ips_delivered++;
|
ipstat.ips_delivered++;
|
||||||
(*inetsw[ip_protox[ip->ip_p]].pr_input)(m, hlen);
|
(*inetsw[ip_protox[ip->ip_p]].pr_input)(m, hlen);
|
||||||
|
#ifdef IPFIREWALL_FORWARD
|
||||||
|
ip_fw_fwd_addr = NULL; /* tcp needed it */
|
||||||
|
#endif
|
||||||
return;
|
return;
|
||||||
bad:
|
bad:
|
||||||
|
#ifdef IPFIREWALL_FORWARD
|
||||||
|
ip_fw_fwd_addr = NULL;
|
||||||
|
#endif
|
||||||
m_freem(m);
|
m_freem(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* @(#)ip_output.c 8.3 (Berkeley) 1/21/94
|
* @(#)ip_output.c 8.3 (Berkeley) 1/21/94
|
||||||
* $Id: ip_output.c,v 1.74 1998/06/15 00:35:47 julian Exp $
|
* $Id: ip_output.c,v 1.75 1998/06/21 14:53:32 bde Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define _IP_VHL
|
#define _IP_VHL
|
||||||
@ -71,6 +71,13 @@ static MALLOC_DEFINE(M_IPMOPTS, "ip_moptions", "internet multicast options");
|
|||||||
#undef COMPAT_IPFW
|
#undef COMPAT_IPFW
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef IPFIREWALL_FORWARD_DEBUG
|
||||||
|
#define print_ip(a) printf("%ld.%ld.%ld.%ld",(ntohl(a.s_addr)>>24)&0xFF,\
|
||||||
|
(ntohl(a.s_addr)>>16)&0xFF,\
|
||||||
|
(ntohl(a.s_addr)>>8)&0xFF,\
|
||||||
|
(ntohl(a.s_addr))&0xFF);
|
||||||
|
#endif
|
||||||
|
|
||||||
u_short ip_id;
|
u_short ip_id;
|
||||||
|
|
||||||
static struct mbuf *ip_insertoptions __P((struct mbuf *, struct mbuf *, int *));
|
static struct mbuf *ip_insertoptions __P((struct mbuf *, struct mbuf *, int *));
|
||||||
@ -114,6 +121,9 @@ ip_output(m0, opt, ro, flags, imo)
|
|||||||
struct sockaddr_in *dst;
|
struct sockaddr_in *dst;
|
||||||
struct in_ifaddr *ia;
|
struct in_ifaddr *ia;
|
||||||
int isbroadcast;
|
int isbroadcast;
|
||||||
|
#ifdef IPFIREWALL_FORWARD
|
||||||
|
int fwd_rewrite_src = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef DIAGNOSTIC
|
#ifdef DIAGNOSTIC
|
||||||
if ((m->m_flags & M_PKTHDR) == 0)
|
if ((m->m_flags & M_PKTHDR) == 0)
|
||||||
@ -304,9 +314,18 @@ ip_output(m0, opt, ro, flags, imo)
|
|||||||
* If source address not specified yet, use address
|
* If source address not specified yet, use address
|
||||||
* of outgoing interface.
|
* of outgoing interface.
|
||||||
*/
|
*/
|
||||||
if (ip->ip_src.s_addr == INADDR_ANY)
|
if (ip->ip_src.s_addr == INADDR_ANY) {
|
||||||
ip->ip_src = IA_SIN(ia)->sin_addr;
|
ip->ip_src = IA_SIN(ia)->sin_addr;
|
||||||
#endif
|
#ifdef IPFIREWALL_FORWARD
|
||||||
|
/* Keep note that we did this - if the firewall changes
|
||||||
|
* the next-hop, our interface may change, changing the
|
||||||
|
* default source IP. It's a shame so much effort happens
|
||||||
|
* twice. Oh well.
|
||||||
|
*/
|
||||||
|
fwd_rewrite_src++;
|
||||||
|
#endif /* IPFIREWALL_FORWARD */
|
||||||
|
}
|
||||||
|
#endif /* notdef */
|
||||||
/*
|
/*
|
||||||
* Verify that we have any chance at all of being able to queue
|
* Verify that we have any chance at all of being able to queue
|
||||||
* the packet or packet fragments
|
* the packet or packet fragments
|
||||||
@ -369,28 +388,134 @@ ip_output(m0, opt, ro, flags, imo)
|
|||||||
* Check with the firewall...
|
* Check with the firewall...
|
||||||
*/
|
*/
|
||||||
if (ip_fw_chk_ptr) {
|
if (ip_fw_chk_ptr) {
|
||||||
|
#ifdef IPFIREWALL_FORWARD
|
||||||
|
struct sockaddr_in *old;
|
||||||
|
old = dst;
|
||||||
|
#endif
|
||||||
#ifdef IPDIVERT
|
#ifdef IPDIVERT
|
||||||
ip_divert_port = (*ip_fw_chk_ptr)(&ip,
|
ip_divert_port = (*ip_fw_chk_ptr)(&ip,
|
||||||
hlen, ifp, &ip_divert_cookie, &m);
|
hlen, ifp, &ip_divert_cookie, &m, &dst);
|
||||||
if (ip_divert_port) { /* Divert packet */
|
if (ip_divert_port) { /* Divert packet */
|
||||||
(*inetsw[ip_protox[IPPROTO_DIVERT]].pr_input)(m, 0);
|
(*inetsw[ip_protox[IPPROTO_DIVERT]].pr_input)(m, 0);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
#else
|
#else /* !IPDIVERT */
|
||||||
u_int16_t dummy = 0;
|
u_int16_t dummy = 0;
|
||||||
/* If ipfw says divert, we have to just drop packet */
|
/* If ipfw says divert, we have to just drop packet */
|
||||||
if ((*ip_fw_chk_ptr)(&ip, hlen, ifp, &dummy, &m)) {
|
if ((*ip_fw_chk_ptr)(&ip, hlen, ifp, &dummy, &m, &dst)) {
|
||||||
m_freem(m);
|
m_freem(m);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
#endif
|
#endif /* !IPDIVERT */
|
||||||
if (!m) {
|
if (!m) {
|
||||||
error = EACCES;
|
error = EACCES;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
#ifdef IPFIREWALL_FORWARD
|
||||||
|
/* Here we check dst to make sure it's directly reachable on the
|
||||||
|
* interface we previously thought it was.
|
||||||
|
* If it isn't (which may be likely in some situations) we have
|
||||||
|
* to re-route it (ie, find a route for the next-hop and the
|
||||||
|
* associated interface) and set them here. This is nested
|
||||||
|
* forwarding which in most cases is undesirable, except where
|
||||||
|
* such control is nigh impossible. So we do it here.
|
||||||
|
* And I'm babbling.
|
||||||
|
*/
|
||||||
|
if (old != dst) {
|
||||||
|
struct in_ifaddr *ia;
|
||||||
|
|
||||||
|
/* It's changed... */
|
||||||
|
/* There must be a better way to do this next line... */
|
||||||
|
static struct route sro_fwd, *ro_fwd = &sro_fwd;
|
||||||
|
#ifdef IPFIREWALL_FORWARD_DEBUG
|
||||||
|
printf("IPFIREWALL_FORWARD: New dst ip: ");
|
||||||
|
print_ip(dst->sin_addr);
|
||||||
|
printf("\n");
|
||||||
|
#endif
|
||||||
|
/*
|
||||||
|
* We need to figure out if we have been forwarded
|
||||||
|
* to a local socket. If so then we should somehow
|
||||||
|
* "loop back" to ip_input, and get directed to the
|
||||||
|
* PCB as if we had received this packet. This is
|
||||||
|
* because it may be dificult to identify the packets
|
||||||
|
* you want to forward until they are being output
|
||||||
|
* and have selected an interface. (e.g. locally
|
||||||
|
* initiated packets) If we used the loopback inteface,
|
||||||
|
* we would not be able to control what happens
|
||||||
|
* as the packet runs through ip_input() as
|
||||||
|
* it is done through a ISR.
|
||||||
|
*/
|
||||||
|
for (ia = TAILQ_FIRST(in_ifaddrhead); ia;
|
||||||
|
ia = TAILQ_NEXT(ia, ia_link)) {
|
||||||
|
/*
|
||||||
|
* If the addr to forward to is one
|
||||||
|
* of ours, we pretend to
|
||||||
|
* be the destination for this packet.
|
||||||
|
*/
|
||||||
|
if (IA_SIN(ia)->sin_addr.s_addr ==
|
||||||
|
dst->sin_addr.s_addr)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (ia) {
|
||||||
|
/* tell ip_input "dont filter" */
|
||||||
|
ip_fw_fwd_addr = dst;
|
||||||
|
if (m->m_pkthdr.rcvif == NULL)
|
||||||
|
m->m_pkthdr.rcvif = ifunit("lo0");
|
||||||
|
ip->ip_len = htons((u_short)ip->ip_len);
|
||||||
|
ip->ip_off = htons((u_short)ip->ip_off);
|
||||||
|
ip->ip_sum = 0;
|
||||||
|
if (ip->ip_vhl == IP_VHL_BORING) {
|
||||||
|
ip->ip_sum = in_cksum_hdr(ip);
|
||||||
|
} else {
|
||||||
|
ip->ip_sum = in_cksum(m, hlen);
|
||||||
|
}
|
||||||
|
ip_input(m);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
/* Some of the logic for this was
|
||||||
|
* nicked from above.
|
||||||
|
*
|
||||||
|
* This rewrites the cached route in a local PCB.
|
||||||
|
* Is this what we want to do?
|
||||||
|
*/
|
||||||
|
bcopy(dst, &ro_fwd->ro_dst, sizeof(*dst));
|
||||||
|
|
||||||
|
ro_fwd->ro_rt = 0;
|
||||||
|
rtalloc_ign(ro_fwd, RTF_PRCLONING);
|
||||||
|
|
||||||
|
if (ro_fwd->ro_rt == 0) {
|
||||||
|
ipstat.ips_noroute++;
|
||||||
|
error = EHOSTUNREACH;
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
|
||||||
|
ia = ifatoia(ro_fwd->ro_rt->rt_ifa);
|
||||||
|
ifp = ro_fwd->ro_rt->rt_ifp;
|
||||||
|
ro_fwd->ro_rt->rt_use++;
|
||||||
|
if (ro_fwd->ro_rt->rt_flags & RTF_GATEWAY)
|
||||||
|
dst = (struct sockaddr_in *)ro_fwd->ro_rt->rt_gateway;
|
||||||
|
if (ro_fwd->ro_rt->rt_flags & RTF_HOST)
|
||||||
|
isbroadcast =
|
||||||
|
(ro_fwd->ro_rt->rt_flags & RTF_BROADCAST);
|
||||||
|
else
|
||||||
|
isbroadcast = in_broadcast(dst->sin_addr, ifp);
|
||||||
|
RTFREE(ro->ro_rt);
|
||||||
|
ro->ro_rt = ro_fwd->ro_rt;
|
||||||
|
dst = (struct sockaddr_in *)&ro_fwd->ro_dst;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we added a default src ip earlier,
|
||||||
|
* which would have been gotten from the-then
|
||||||
|
* interface, do it again, from the new one.
|
||||||
|
*/
|
||||||
|
if (fwd_rewrite_src)
|
||||||
|
ip->ip_src = IA_SIN(ia)->sin_addr;
|
||||||
|
}
|
||||||
|
#endif /* IPFIREWALL_FORWARD */
|
||||||
}
|
}
|
||||||
#endif /* COMPAT_IPFW */
|
#endif /* COMPAT_IPFW */
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If small enough for interface, can just send directly.
|
* If small enough for interface, can just send directly.
|
||||||
*/
|
*/
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* @(#)ip_var.h 8.2 (Berkeley) 1/9/95
|
* @(#)ip_var.h 8.2 (Berkeley) 1/9/95
|
||||||
* $Id: ip_var.h,v 1.40 1998/06/06 19:39:10 julian Exp $
|
* $Id: ip_var.h,v 1.41 1998/06/08 09:47:42 bde Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _NETINET_IP_VAR_H_
|
#ifndef _NETINET_IP_VAR_H_
|
||||||
@ -211,6 +211,9 @@ extern u_short ip_divert_port;
|
|||||||
extern u_short ip_divert_cookie;
|
extern u_short ip_divert_cookie;
|
||||||
#endif /* IPDIVERT */
|
#endif /* IPDIVERT */
|
||||||
|
|
||||||
|
struct sockaddr_in;
|
||||||
|
extern struct sockaddr_in *ip_fw_fwd_addr;
|
||||||
|
|
||||||
#endif /* KERNEL */
|
#endif /* KERNEL */
|
||||||
|
|
||||||
#endif /* _NETINET_IP_VAR_H_ */
|
#endif /* _NETINET_IP_VAR_H_ */
|
||||||
|
@ -31,9 +31,10 @@
|
|||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* @(#)tcp_input.c 8.12 (Berkeley) 5/24/95
|
* @(#)tcp_input.c 8.12 (Berkeley) 5/24/95
|
||||||
* $Id: tcp_input.c,v 1.77 1998/05/18 17:11:24 guido Exp $
|
* $Id: tcp_input.c,v 1.78 1998/05/31 18:42:49 peter Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "opt_ipfw.h" /* for ipfw_fwd */
|
||||||
#include "opt_tcpdebug.h"
|
#include "opt_tcpdebug.h"
|
||||||
|
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
@ -339,6 +340,33 @@ tcp_input(m, iphlen)
|
|||||||
* Locate pcb for segment.
|
* Locate pcb for segment.
|
||||||
*/
|
*/
|
||||||
findpcb:
|
findpcb:
|
||||||
|
#ifdef IPFIREWALL_FORWARD
|
||||||
|
if (ip_fw_fwd_addr != NULL) {
|
||||||
|
/*
|
||||||
|
* Diverted. Pretend to be the destination.
|
||||||
|
* already got one like this?
|
||||||
|
*/
|
||||||
|
inp = in_pcblookup_hash(&tcbinfo, ti->ti_src, ti->ti_sport,
|
||||||
|
ti->ti_dst, ti->ti_dport, 0);
|
||||||
|
if (!inp) {
|
||||||
|
/*
|
||||||
|
* No, then it's new. Try find the ambushing socket
|
||||||
|
*/
|
||||||
|
if (!ip_fw_fwd_addr->sin_port) {
|
||||||
|
inp = in_pcblookup_hash(&tcbinfo, ti->ti_src,
|
||||||
|
ti->ti_sport, ip_fw_fwd_addr->sin_addr,
|
||||||
|
ti->ti_dport, 1);
|
||||||
|
} else {
|
||||||
|
inp = in_pcblookup_hash(&tcbinfo,
|
||||||
|
ti->ti_src, ti->ti_sport,
|
||||||
|
ip_fw_fwd_addr->sin_addr,
|
||||||
|
ntohs(ip_fw_fwd_addr->sin_port), 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ip_fw_fwd_addr = NULL;
|
||||||
|
} else
|
||||||
|
#endif /* IPFIREWALL_FORWARD */
|
||||||
|
|
||||||
inp = in_pcblookup_hash(&tcbinfo, ti->ti_src, ti->ti_sport,
|
inp = in_pcblookup_hash(&tcbinfo, ti->ti_src, ti->ti_sport,
|
||||||
ti->ti_dst, ti->ti_dport, 1);
|
ti->ti_dst, ti->ti_dport, 1);
|
||||||
|
|
||||||
|
@ -31,9 +31,10 @@
|
|||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* @(#)tcp_input.c 8.12 (Berkeley) 5/24/95
|
* @(#)tcp_input.c 8.12 (Berkeley) 5/24/95
|
||||||
* $Id: tcp_input.c,v 1.77 1998/05/18 17:11:24 guido Exp $
|
* $Id: tcp_input.c,v 1.78 1998/05/31 18:42:49 peter Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "opt_ipfw.h" /* for ipfw_fwd */
|
||||||
#include "opt_tcpdebug.h"
|
#include "opt_tcpdebug.h"
|
||||||
|
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
@ -339,6 +340,33 @@ tcp_input(m, iphlen)
|
|||||||
* Locate pcb for segment.
|
* Locate pcb for segment.
|
||||||
*/
|
*/
|
||||||
findpcb:
|
findpcb:
|
||||||
|
#ifdef IPFIREWALL_FORWARD
|
||||||
|
if (ip_fw_fwd_addr != NULL) {
|
||||||
|
/*
|
||||||
|
* Diverted. Pretend to be the destination.
|
||||||
|
* already got one like this?
|
||||||
|
*/
|
||||||
|
inp = in_pcblookup_hash(&tcbinfo, ti->ti_src, ti->ti_sport,
|
||||||
|
ti->ti_dst, ti->ti_dport, 0);
|
||||||
|
if (!inp) {
|
||||||
|
/*
|
||||||
|
* No, then it's new. Try find the ambushing socket
|
||||||
|
*/
|
||||||
|
if (!ip_fw_fwd_addr->sin_port) {
|
||||||
|
inp = in_pcblookup_hash(&tcbinfo, ti->ti_src,
|
||||||
|
ti->ti_sport, ip_fw_fwd_addr->sin_addr,
|
||||||
|
ti->ti_dport, 1);
|
||||||
|
} else {
|
||||||
|
inp = in_pcblookup_hash(&tcbinfo,
|
||||||
|
ti->ti_src, ti->ti_sport,
|
||||||
|
ip_fw_fwd_addr->sin_addr,
|
||||||
|
ntohs(ip_fw_fwd_addr->sin_port), 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ip_fw_fwd_addr = NULL;
|
||||||
|
} else
|
||||||
|
#endif /* IPFIREWALL_FORWARD */
|
||||||
|
|
||||||
inp = in_pcblookup_hash(&tcbinfo, ti->ti_src, ti->ti_sport,
|
inp = in_pcblookup_hash(&tcbinfo, ti->ti_src, ti->ti_sport,
|
||||||
ti->ti_dst, ti->ti_dport, 1);
|
ti->ti_dst, ti->ti_dport, 1);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user