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
|
||||
socket bound to 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
|
||||
Skip all subsequent rules numbered less than
|
||||
.Ar number .
|
||||
|
@ -16,7 +16,7 @@
|
||||
*
|
||||
* 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);
|
||||
}
|
||||
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:
|
||||
errx(EX_OSERR, "impossible");
|
||||
}
|
||||
@ -497,7 +502,7 @@ show_usage(const char *fmt, ...)
|
||||
" rule: action proto src dst extras...\n"
|
||||
" action:\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"
|
||||
" src: from [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
|
||||
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))) {
|
||||
rule.fw_flg |= IP_FW_F_SKIPTO; av++; ac--;
|
||||
if (!ac)
|
||||
|
@ -31,7 +31,7 @@
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)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_
|
||||
@ -431,7 +431,7 @@ char *inet_ntoa __P((struct in_addr)); /* in libkern */
|
||||
|
||||
/* Firewall hooks */
|
||||
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**));
|
||||
extern ip_fw_chk_t *ip_fw_chk_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.
|
||||
*
|
||||
* $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
|
||||
|
||||
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 char err_prefix[] = "ip_fw_ctl:";
|
||||
@ -320,6 +321,14 @@ ipfw_report(struct ip_fw *f, struct ip *ip,
|
||||
case IP_FW_F_SKIPTO:
|
||||
printf("SkipTo %d", f->fw_skipto_rule);
|
||||
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:
|
||||
printf("UNKNOWN");
|
||||
break;
|
||||
@ -393,7 +402,8 @@ ipfw_report(struct ip_fw *f, struct ip *ip,
|
||||
|
||||
static int
|
||||
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 *rule = NULL;
|
||||
@ -606,11 +616,28 @@ ip_fw_chk(struct ip **pip, int hlen,
|
||||
#endif
|
||||
chain = LIST_NEXT(chain, chain);
|
||||
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 */
|
||||
rule = f;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
#ifdef DIAGNOSTIC
|
||||
@ -950,6 +977,9 @@ check_ipfw_struct(struct ip_fw *frwl)
|
||||
case IP_FW_F_ACCEPT:
|
||||
case IP_FW_F_COUNT:
|
||||
case IP_FW_F_SKIPTO:
|
||||
#ifdef IPFIREWALL_FORWARD
|
||||
case IP_FW_F_FWD:
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
dprintf(("%s invalid command\n", err_prefix));
|
||||
@ -982,7 +1012,7 @@ ip_fw_ctl(int stage, struct mbuf **mm)
|
||||
if (m == NULL)
|
||||
return (ENOBUFS);
|
||||
MCLGET(m, M_WAIT);
|
||||
if(!(m->m_flags & M_EXT)) {
|
||||
if (!(m->m_flags & M_EXT)) {
|
||||
abort: m_freem(*mm);
|
||||
*mm = NULL;
|
||||
return (ENOBUFS);
|
||||
@ -990,7 +1020,7 @@ abort: m_freem(*mm);
|
||||
m->m_len = 0;
|
||||
for (; fcp; fcp = LIST_NEXT(fcp, chain)) {
|
||||
/* 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);
|
||||
if (m == NULL) {
|
||||
goto abort;
|
||||
@ -1094,6 +1124,11 @@ ip_fw_init(void)
|
||||
#else
|
||||
"divert disabled, ");
|
||||
#endif
|
||||
#ifdef IPFIREWALL_FORWARD
|
||||
printf("rule-based forwarding enabled, ");
|
||||
#else
|
||||
printf("rule-based forwarding disabled, ");
|
||||
#endif
|
||||
#ifdef IPFIREWALL_DEFAULT_TO_ACCEPT
|
||||
printf("default to accept, ");
|
||||
#endif
|
||||
|
@ -11,7 +11,7 @@
|
||||
*
|
||||
* 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
|
||||
@ -71,6 +71,7 @@ struct ip_fw {
|
||||
u_short fu_divert_port; /* Divert/tee port (options IPDIVERT) */
|
||||
u_short fu_skipto_rule; /* SKIPTO command rule number */
|
||||
u_short fu_reject_code; /* REJECT response code */
|
||||
struct sockaddr_in fu_fwd_ip;
|
||||
} fw_un;
|
||||
u_char fw_prot; /* IP protocol */
|
||||
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_skipto_rule fw_un.fu_skipto_rule
|
||||
#define fw_reject_code fw_un.fu_reject_code
|
||||
#define fw_fwd_ip fw_un.fu_fwd_ip
|
||||
|
||||
struct ip_fw_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_TEE 0x0050 /* This is a tee 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 */
|
||||
|
||||
|
@ -31,7 +31,7 @@
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)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 $
|
||||
*/
|
||||
|
||||
@ -181,6 +181,8 @@ static struct ip_srcrt {
|
||||
static u_short frag_divert_port;
|
||||
#endif
|
||||
|
||||
struct sockaddr_in *ip_fw_fwd_addr;
|
||||
|
||||
static void save_rte __P((u_char *, struct in_addr));
|
||||
static void ip_deq __P((struct ipasfrag *));
|
||||
static int ip_dooptions __P((struct mbuf *));
|
||||
@ -354,30 +356,43 @@ ip_input(struct mbuf *m)
|
||||
#endif
|
||||
#ifdef COMPAT_IPFW
|
||||
if (ip_fw_chk_ptr) {
|
||||
#ifdef IPDIVERT
|
||||
u_short port;
|
||||
u_int16_t 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) {
|
||||
/* Divert packet */
|
||||
frag_divert_port = port;
|
||||
goto ours;
|
||||
}
|
||||
#else
|
||||
u_int16_t dummy = 0;
|
||||
/* If ipfw says divert, we have to just drop packet */
|
||||
if ((*ip_fw_chk_ptr)(&ip, hlen, NULL, &dummy, &m)) {
|
||||
#else /* !DIVERT */
|
||||
/*
|
||||
* If ipfw says divert, we have to just drop packet */
|
||||
* 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 = NULL;
|
||||
}
|
||||
#endif
|
||||
#endif /* !DIVERT */
|
||||
if (!m)
|
||||
return;
|
||||
}
|
||||
|
||||
if (ip_nat_ptr && !(*ip_nat_ptr)(&ip, &m, m->m_pkthdr.rcvif, IP_NAT_IN))
|
||||
return;
|
||||
#endif
|
||||
#endif /* !COMPAT_IPFW */
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
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))
|
||||
|
||||
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
|
||||
if (IA_SIN(ia)->sin_addr.s_addr == INADDR_ANY)
|
||||
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
|
||||
if (ia->ia_ifp && ia->ia_ifp->if_flags & IFF_BROADCAST) {
|
||||
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) {
|
||||
ipstat.ips_fragments++;
|
||||
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;
|
||||
}
|
||||
/* Get the length of the reassembled packets header */
|
||||
hlen = IP_VHL_HL(ip->ip_vhl) << 2;
|
||||
ipstat.ips_reassembled++;
|
||||
@ -599,8 +629,14 @@ ip_input(struct mbuf *m)
|
||||
*/
|
||||
ipstat.ips_delivered++;
|
||||
(*inetsw[ip_protox[ip->ip_p]].pr_input)(m, hlen);
|
||||
#ifdef IPFIREWALL_FORWARD
|
||||
ip_fw_fwd_addr = NULL; /* tcp needed it */
|
||||
#endif
|
||||
return;
|
||||
bad:
|
||||
#ifdef IPFIREWALL_FORWARD
|
||||
ip_fw_fwd_addr = NULL;
|
||||
#endif
|
||||
m_freem(m);
|
||||
}
|
||||
|
||||
|
@ -31,7 +31,7 @@
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)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
|
||||
@ -71,6 +71,13 @@ static MALLOC_DEFINE(M_IPMOPTS, "ip_moptions", "internet multicast options");
|
||||
#undef COMPAT_IPFW
|
||||
#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;
|
||||
|
||||
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 in_ifaddr *ia;
|
||||
int isbroadcast;
|
||||
#ifdef IPFIREWALL_FORWARD
|
||||
int fwd_rewrite_src = 0;
|
||||
#endif
|
||||
|
||||
#ifdef DIAGNOSTIC
|
||||
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
|
||||
* 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;
|
||||
#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
|
||||
* the packet or packet fragments
|
||||
@ -369,28 +388,134 @@ ip_output(m0, opt, ro, flags, imo)
|
||||
* Check with the firewall...
|
||||
*/
|
||||
if (ip_fw_chk_ptr) {
|
||||
#ifdef IPFIREWALL_FORWARD
|
||||
struct sockaddr_in *old;
|
||||
old = dst;
|
||||
#endif
|
||||
#ifdef IPDIVERT
|
||||
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 */
|
||||
(*inetsw[ip_protox[IPPROTO_DIVERT]].pr_input)(m, 0);
|
||||
goto done;
|
||||
}
|
||||
#else
|
||||
#else /* !IPDIVERT */
|
||||
u_int16_t dummy = 0;
|
||||
/* 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);
|
||||
goto done;
|
||||
}
|
||||
#endif
|
||||
#endif /* !IPDIVERT */
|
||||
if (!m) {
|
||||
error = EACCES;
|
||||
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 */
|
||||
|
||||
|
||||
/*
|
||||
* If small enough for interface, can just send directly.
|
||||
*/
|
||||
|
@ -31,7 +31,7 @@
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)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_
|
||||
@ -211,6 +211,9 @@ extern u_short ip_divert_port;
|
||||
extern u_short ip_divert_cookie;
|
||||
#endif /* IPDIVERT */
|
||||
|
||||
struct sockaddr_in;
|
||||
extern struct sockaddr_in *ip_fw_fwd_addr;
|
||||
|
||||
#endif /* KERNEL */
|
||||
|
||||
#endif /* _NETINET_IP_VAR_H_ */
|
||||
|
@ -31,9 +31,10 @@
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)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 <sys/param.h>
|
||||
@ -339,6 +340,33 @@ tcp_input(m, iphlen)
|
||||
* Locate pcb for segment.
|
||||
*/
|
||||
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,
|
||||
ti->ti_dst, ti->ti_dport, 1);
|
||||
|
||||
|
@ -31,9 +31,10 @@
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)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 <sys/param.h>
|
||||
@ -339,6 +340,33 @@ tcp_input(m, iphlen)
|
||||
* Locate pcb for segment.
|
||||
*/
|
||||
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,
|
||||
ti->ti_dst, ti->ti_dport, 1);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user