patch-pre2.0.7 linux/net/ipv4/af_inet.c
Next file: linux/net/ipv4/arp.c
Previous file: linux/net/ipv4/Config.in
Back to the patch index
Back to the overall index
- Lines: 196
- Date:
Mon May 20 08:08:36 1996
- Orig file:
pre2.0.6/linux/net/ipv4/af_inet.c
- Orig date:
Wed May 15 11:01:15 1996
diff -u --recursive --new-file pre2.0.6/linux/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c
@@ -49,6 +49,7 @@
* Alan Cox : Locked down bind (see security list).
* Alan Cox : Loosened bind a little.
* Mike McLagan : ADD/DEL DLCI Ioctls
+ * Willy Konynenberg : Transparent proxying support.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -160,10 +161,10 @@
struct sock *sk;
if (base == 0)
- base = PROT_SOCK+1+(start % 1024);
+ base = PROT_SOCK+1+(start & 1023);
if (base <= PROT_SOCK)
{
- base += PROT_SOCK+(start % 1024);
+ base += PROT_SOCK+(start & 1023);
}
/*
@@ -181,7 +182,7 @@
}
if (j == 0)
{
- start =(i+1+start )%1024;
+ start =(i+1+start )&1023;
return(i+base+1);
}
if (j < size)
@@ -841,11 +842,25 @@
}
chk_addr_ret = ip_chk_addr(addr->sin_addr.s_addr);
+#ifdef CONFIG_IP_TRANSPARENT_PROXY
+ /*
+ * Superuser may bind to any address to allow transparent proxying.
+ */
+ if (addr->sin_addr.s_addr != 0 && chk_addr_ret != IS_MYADDR && chk_addr_ret != IS_MULTICAST && chk_addr_ret != IS_BROADCAST && !suser())
+#else
if (addr->sin_addr.s_addr != 0 && chk_addr_ret != IS_MYADDR && chk_addr_ret != IS_MULTICAST && chk_addr_ret != IS_BROADCAST)
+#endif
return(-EADDRNOTAVAIL); /* Source address MUST be ours! */
+#ifndef CONFIG_IP_TRANSPARENT_PROXY
+ /*
+ * Am I just thick or is this test really always true after the one
+ * above? Just taking the test out appears to be the easiest way to
+ * make binds to remote addresses for transparent proxying work.
+ */
if (chk_addr_ret || addr->sin_addr.s_addr == 0)
{
+#endif
/*
* We keep a pair of addresses. rcv_saddr is the one
* used by get_sock_*(), and saddr is used for transmit.
@@ -859,7 +874,9 @@
sk->saddr = 0; /* Use device */
else
sk->saddr = addr->sin_addr.s_addr;
+#ifndef CONFIG_IP_TRANSPARENT_PROXY
}
+#endif
if(sock->type != SOCK_RAW)
{
/* Make sure we are allowed to bind here. */
@@ -1332,6 +1349,36 @@
return(0);
}
+#ifdef CONFIG_IP_TRANSPARENT_PROXY
+/*
+ * Some routines for the for loop in get_sock which sometimes needs to walk
+ * two linked lists in sequence. Could use macros as well.
+ * Does anyone know a nicer way to code this?
+ */
+static __inline__ struct sock *secondlist(unsigned short hpnum, struct sock *s,
+ int *pfirstpass, struct proto *prot)
+{
+ if (hpnum && s == NULL && (*pfirstpass)-- )
+ return prot->sock_array[hpnum & (SOCK_ARRAY_SIZE - 1)];
+ else
+ return s;
+}
+static __inline__ struct sock *get_sock_loop_init(unsigned short hnum,
+ unsigned short hpnum, struct sock *s,
+ int *pfirstpass, struct proto *prot)
+{
+ s = prot->sock_array[hnum & (SOCK_ARRAY_SIZE - 1)];
+ return secondlist(hpnum, s, pfirstpass, prot);
+}
+static __inline__ struct sock *get_sock_loop_next(unsigned short hnum,
+ unsigned short hpnum, struct sock *s,
+ int *pfirstpass, struct proto *prot)
+{
+ s = s->next;
+ return secondlist(hpnum, s, pfirstpass, prot);
+}
+#endif
+
/*
* This routine must find a socket given a TCP or UDP header.
* Everything is assumed to be in net order.
@@ -1343,14 +1390,22 @@
struct sock *get_sock(struct proto *prot, unsigned short num,
unsigned long raddr,
- unsigned short rnum, unsigned long laddr)
+ unsigned short rnum, unsigned long laddr,
+ unsigned long paddr, unsigned short pnum)
{
- struct sock *s;
+ struct sock *s = 0;
struct sock *result = NULL;
int badness = -1;
unsigned short hnum;
+#ifdef CONFIG_IP_TRANSPARENT_PROXY
+ unsigned short hpnum;
+ int firstpass = 1;
+#endif
hnum = ntohs(num);
+#ifdef CONFIG_IP_TRANSPARENT_PROXY
+ hpnum = ntohs(pnum);
+#endif
/*
* SOCK_ARRAY_SIZE must be a power of two. This will work better
@@ -1361,19 +1416,43 @@
* socket number when we choose an arbitrary one.
*/
+#ifdef CONFIG_IP_TRANSPARENT_PROXY
+ for(s = get_sock_loop_init(hnum, hpnum, s, &firstpass, prot);
+ s != NULL;
+ s = get_sock_loop_next(hnum, hpnum, s, &firstpass, prot))
+#else
for(s = prot->sock_array[hnum & (SOCK_ARRAY_SIZE - 1)];
s != NULL; s = s->next)
+#endif
{
int score = 0;
+#ifdef CONFIG_IP_TRANSPARENT_PROXY
+ /* accept the addressed port or the redirect (proxy) port */
+ if (s->num != hnum && (hpnum == 0 || s->num != hpnum))
+#else
if (s->num != hnum)
+#endif
continue;
if(s->dead && (s->state == TCP_CLOSE))
continue;
/* local address matches? */
if (s->rcv_saddr) {
+#ifdef CONFIG_IP_TRANSPARENT_PROXY
+ /*
+ * If this is redirected traffic, it must either
+ * match on the redirected port/ip-address or on
+ * the actual destination, not on a mixture.
+ * There must be a simpler way to express this...
+ */
+ if (hpnum
+ ? ((s->num != hpnum || s->rcv_saddr != paddr)
+ && (s->num != hnum || s->rcv_saddr != laddr))
+ : (s->rcv_saddr != laddr))
+#else
if (s->rcv_saddr != laddr)
+#endif
continue;
score++;
}
@@ -1390,11 +1469,23 @@
score++;
}
/* perfect match? */
+#ifdef CONFIG_IP_TRANSPARENT_PROXY
+ if (score == 3 && s->num == hnum)
+#else
if (score == 3)
+#endif
return s;
/* no, check if this is the best so far.. */
if (score <= badness)
continue;
+#ifdef CONFIG_IP_TRANSPARENT_PROXY
+ /* don't accept near matches on the actual destination
+ * port with IN_ADDR_ANY for redirected traffic, but do
+ * allow explicit remote address listens. (disputable)
+ */
+ if (hpnum && s->num != hpnum && !s->rcv_saddr)
+ continue;
+#endif
result = s;
badness = score;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov
with Sam's (original) version of this