mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* Bug in nonlocal-bind (transparent proxy)?
@ 2001-06-07 14:08 Nadav Har'El
  2001-06-08  5:44 ` Andrey Savochkin
  0 siblings, 1 reply; 11+ messages in thread
From: Nadav Har'El @ 2001-06-07 14:08 UTC (permalink / raw)
  To: linux-kernel

I am writing a transparent-proxy-like application, that needs to be able to
bind a TCP socket with a non-local address (i.e., the proxy contacts the
origin-server, in the local network, pretending to be the original client.
The reply will get back to the proxy because it acts as the default
gateway, and the kernel needs to pass that reply to the socket).

Bind()ing a non-local address worked fine in the 2.2 line of kernels if a
certain compile-time option was enabled (TRANSPARENT_PROXY, or something
like that). But it no longer seems to be working in the 2.4 kernels (I
tried this on 2.4.2 coming from the Redhat 7.1 distribution).

First, bind() simply refused to work when given a non-local address (returning
EADDRNOTAVAIL). Reading the kernel's source I discovered that an undocumented
"ip_nonlocal_bind" sysctl makes the kernel agree to do such a bind (this
should really be in the bind() documentation...). Enabling this option
allowed bind to work (it can even catch the case of two sockets trying to
bind the same address), but the later connect() fails!
I tryed reading the kernel sources to figure out what's wrong with the
connect(), but failed to understand why it returns a EINVAL. I think this
is a bug, and include below a short program to reproduce it:

If you run the program below, connect() will fail with EINVAL (it will do
so before even trying to output a packet). To see that nothing's actually
wrong with the connect, change the #if 1 to #if 0, eliminating the bind(),
and see that the connect works (or at least fails with a connection refused,
as it should because of the random IP address).
Note that you must run the program as root, and do
	echo 1 > /proc/sys/net/ipv4/ip_nonlocal_bind 
to get the bind() to work at all. But once you do that, and bind() works,
how come connect() doesn't work?

Thanks in advance for any insights or fixes!

Here's the program to reproduce the bug:

/* try non-local bind on 2.4 kernel...

   echo 1 > /proc/sys/net/ipv4/ip_nonlocal_bind
   doesn't seem to help :(
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#include <sys/socket.h>
#include <arpa/inet.h>

main(){
    int s,c;
    struct sockaddr_in addr;

    s=socket(PF_INET,SOCK_STREAM,0);
    if(s<0)
        perror("socket");

#if 1
    printf("binding %d\n",s);
    addr.sin_family=AF_INET;
    addr.sin_port=htons(5678);
    inet_aton("2.3.4.5",&addr.sin_addr);
    /* this requires echo 1 > /proc/sys/net/ipv4/ip_nonlocal_bind */
    if(bind(s, (struct sockaddr *)&addr, sizeof(addr))<0)
        perror("bind");
#endif

    printf("connecting %d\n",s);
    addr.sin_family=AF_INET;
    addr.sin_port=htons(22);
    inet_aton("1.2.3.4",&addr.sin_addr);
    c=connect(s,(struct sockaddr *)&addr, sizeof(addr));
    if(c<0)
        perror("connect");

    printf("end.\n");
}


-- 
Nadav Har'El                        |     Thursday, Jun  7 2001, 16 Sivan 5761
nyh@math.technion.ac.il             |-----------------------------------------
Phone: +972-53-245868, ICQ 13349191 |(On the back of a VW Beetle) Don't honk,
http://nadav.harel.org.il           |I'm peddling as fast as I can.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Bug in nonlocal-bind (transparent proxy)?
  2001-06-07 14:08 Bug in nonlocal-bind (transparent proxy)? Nadav Har'El
@ 2001-06-08  5:44 ` Andrey Savochkin
  2001-06-08  8:02   ` Nadav Har'El
                     ` (2 more replies)
  0 siblings, 3 replies; 11+ messages in thread
From: Andrey Savochkin @ 2001-06-08  5:44 UTC (permalink / raw)
  To: Nadav Har'El, linux-kernel

Hi,

It's not a bug, it's willful.

On Thu, Jun 07, 2001 at 05:08:25PM +0300, Nadav Har'El wrote:
> I am writing a transparent-proxy-like application, that needs to be able to
> bind a TCP socket with a non-local address (i.e., the proxy contacts the
> origin-server, in the local network, pretending to be the original client.
> The reply will get back to the proxy because it acts as the default
> gateway, and the kernel needs to pass that reply to the socket).
> 
> Bind()ing a non-local address worked fine in the 2.2 line of kernels if a
> certain compile-time option was enabled (TRANSPARENT_PROXY, or something
> like that). But it no longer seems to be working in the 2.4 kernels (I
> tried this on 2.4.2 coming from the Redhat 7.1 distribution).
> 
> First, bind() simply refused to work when given a non-local address (returning
> EADDRNOTAVAIL). Reading the kernel's source I discovered that an undocumented
> "ip_nonlocal_bind" sysctl makes the kernel agree to do such a bind (this
> should really be in the bind() documentation...). Enabling this option
> allowed bind to work (it can even catch the case of two sockets trying to
> bind the same address), but the later connect() fails!
> I tryed reading the kernel sources to figure out what's wrong with the
> connect(), but failed to understand why it returns a EINVAL. I think this
> is a bug, and include below a short program to reproduce it:
> 
> If you run the program below, connect() will fail with EINVAL (it will do
> so before even trying to output a packet). To see that nothing's actually
> wrong with the connect, change the #if 1 to #if 0, eliminating the bind(),
> and see that the connect works (or at least fails with a connection refused,
> as it should because of the random IP address).
> Note that you must run the program as root, and do
> 	echo 1 > /proc/sys/net/ipv4/ip_nonlocal_bind 
> to get the bind() to work at all. But once you do that, and bind() works,
> how come connect() doesn't work?
> 
> Thanks in advance for any insights or fixes!

To make a custom kernel where you can use non-local addresses more freely,
find source address checks in ip_route_output_slow() and get rid of all of
them except considering
	MULTICAST(saddr) || BADCLASS(saddr) || ZERONET(saddr) ||
		saddr == htonl(INADDR_BROADCAST)
as invalid.

	Andrey

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Bug in nonlocal-bind (transparent proxy)?
  2001-06-08  5:44 ` Andrey Savochkin
@ 2001-06-08  8:02   ` Nadav Har'El
  2001-06-08  8:25   ` David S. Miller
  2001-09-03 10:12   ` Transparent proxy support in 2.4 - revisited Nadav Har'El
  2 siblings, 0 replies; 11+ messages in thread
From: Nadav Har'El @ 2001-06-08  8:02 UTC (permalink / raw)
  To: Andrey Savochkin; +Cc: linux-kernel

On Fri, Jun 08, 2001, Andrey Savochkin wrote about "Re: Bug in nonlocal-bind (transparent proxy)?":
> On Thu, Jun 07, 2001 at 05:08:25PM +0300, Nadav Har'El wrote:
> Hi,
> > Bind()ing a non-local address worked fine in the 2.2 line of kernels if a
> > certain compile-time option was enabled (TRANSPARENT_PROXY, or something
> > like that). But it no longer seems to be working in the 2.4 kernels (I
> > tried this on 2.4.2 coming from the Redhat 7.1 distribution).
> 
> It's not a bug, it's willful.

I don't understand what is willful: why does the ip_nonlocal_bind sysctl
exist if it doesn't help? Getting bind() to work (which is what
ip_nonlocal_bind does) but later not being able to connect() this socket
isn't very useful...

> To make a custom kernel where you can use non-local addresses more freely,
> find source address checks in ip_route_output_slow() and get rid of all of
> them except considering
> 	MULTICAST(saddr) || BADCLASS(saddr) || ZERONET(saddr) ||
> 		saddr == htonl(INADDR_BROADCAST)
> as invalid.

Thanks for the idea - I'll try doing that, and see if it works.

Is there any special reason why, instead of that ip_nonlocal_bind that doesn't
work, we don't have instead a compile-time variable (obviously a run-time
sysctl or socket-specific option would be even better) which enables both
ip_nonlocal_bind and the hacks needed to get connect() to work?

-- 
Nadav Har'El                        |       Friday, Jun  8 2001, 17 Sivan 5761
nyh@math.technion.ac.il             |-----------------------------------------
Phone: +972-53-245868, ICQ 13349191 |A conscience does not prevent sin. It
http://nadav.harel.org.il           |only prevents you from enjoying it.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Bug in nonlocal-bind (transparent proxy)?
  2001-06-08  5:44 ` Andrey Savochkin
  2001-06-08  8:02   ` Nadav Har'El
@ 2001-06-08  8:25   ` David S. Miller
  2001-09-03 10:12   ` Transparent proxy support in 2.4 - revisited Nadav Har'El
  2 siblings, 0 replies; 11+ messages in thread
From: David S. Miller @ 2001-06-08  8:25 UTC (permalink / raw)
  To: Nadav Har'El; +Cc: Andrey Savochkin, linux-kernel


Nadav Har'El writes:
 > I don't understand what is willful: why does the ip_nonlocal_bind sysctl
 > exist if it doesn't help? Getting bind() to work (which is what
 > ip_nonlocal_bind does) but later not being able to connect() this socket
 > isn't very useful...

ip_nonlocal_bind is meant for another purpose all together.
It allows you to bind to IP addresses which aren't configured
up at the moment.

It's meant for dial-on-demand type situations, nothing more.

Later,
David S. Miller
davem@redhat.com

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Transparent proxy support in 2.4 - revisited
  2001-06-08  5:44 ` Andrey Savochkin
  2001-06-08  8:02   ` Nadav Har'El
  2001-06-08  8:25   ` David S. Miller
@ 2001-09-03 10:12   ` Nadav Har'El
  2001-09-03 10:44     ` Andrey Savochkin
  2001-09-03 22:50     ` Alexey Kuznetsov
  2 siblings, 2 replies; 11+ messages in thread
From: Nadav Har'El @ 2001-09-03 10:12 UTC (permalink / raw)
  To: Andrey Savochkin; +Cc: linux-kernel

A few months ago, I asked on this list why the transparent proxy feature
(CONFIG_IP_TRANSPARENT_PROXY) that was supported in Linux 2.2 is no longer
supported in Linux 2.4:

> > I am writing a transparent-proxy-like application, that needs to be able to
> > bind a TCP socket with a non-local address (i.e., the proxy contacts the
> > origin-server, in the local network, pretending to be the original client.
> > The reply will get back to the proxy because it acts as the default
> > gateway, and the kernel needs to pass that reply to the socket).

I included an example code, where bind() on a foreign address would work (if
I set ip_nonlocal_bind sysctl to 1), but a later connect() on that socket
would not.

Andrey Savochkin wrote a useful reply, on how to make the connect work():

> To make a custom kernel where you can use non-local addresses more freely,
> find source address checks in ip_route_output_slow() and get rid of all of
> them except considering
> 	MULTICAST(saddr) || BADCLASS(saddr) || ZERONET(saddr) ||
> 		saddr == htonl(INADDR_BROADCAST)
> as invalid.

I did that, and indeed now connect() works, and sends out (when considering
TCP) the appropriate SYN packet.

Unfortunately, that's not enough. When the return SYN-ACK packet carrying a
non-local destination address is received (in practice, the transparent
proxy machine is acting as a default gateway to the other machine), this
packet is either ignored or forwarded out (depending on ip_forward), but is
never accepted as a local packet and transfered to the appropriate socket
as it should.
To do that, some cache of open sockets will need to be consulted for
incoming packets that are not destined to local addresses (whether or not
ip_forward is enabled). This was done in kernel 2.2, where I found
CONFIG_IP_TRANSPARENT_PROXY-related changes in several files (af_inet.c,
icmp.c, ip_forward.c, ip_fw.c, ip_input.c, raw.c, route.c, syncookies.c,
tcp_ipv4.c and udp.c).

As I'm not an experienced Linux kernel hacker, and I'm barely familar with
Linux's networking code, so I hesitate to attempt such a feat (resurrecting
the transparent proxy code) myself, so I was wondering if anyone else had any
plans of doing that?

If not, does anyone know of a reason why this feature was abandoned on the
change to Linux 2.4: Was it a deliberate decision (e.g., because of performance
reasons, because it blurred the distinction between layer 2 and 3 when routing,
etc.) or simply a matter of priorities (e.g., adding transparent proxy support
would take up valuable kernel programmer time and was not deemed important
enough)?

Thanks,
	Nadav.

-- 
Nadav Har'El                        |        Monday, Sep  3 2001, 15 Elul 5761
nyh@math.technion.ac.il             |-----------------------------------------
Phone: +972-53-245868, ICQ 13349191 |It's fortunate I have back luck - without
http://nadav.harel.org.il           |it I would have no luck at all!

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Transparent proxy support in 2.4 - revisited
  2001-09-03 10:12   ` Transparent proxy support in 2.4 - revisited Nadav Har'El
@ 2001-09-03 10:44     ` Andrey Savochkin
  2001-09-03 13:16       ` Nadav Har'El
  2001-09-03 22:50     ` Alexey Kuznetsov
  1 sibling, 1 reply; 11+ messages in thread
From: Andrey Savochkin @ 2001-09-03 10:44 UTC (permalink / raw)
  To: Nadav Har'El; +Cc: linux-kernel

Hi,

On Mon, Sep 03, 2001 at 01:12:40PM +0300, Nadav Har'El wrote:
> A few months ago, I asked on this list why the transparent proxy feature
> (CONFIG_IP_TRANSPARENT_PROXY) that was supported in Linux 2.2 is no longer
> supported in Linux 2.4:
> 
[snip]
> Andrey Savochkin wrote a useful reply, on how to make the connect work():
> 
> > To make a custom kernel where you can use non-local addresses more freely,
> > find source address checks in ip_route_output_slow() and get rid of all of
> > them except considering
> > 	MULTICAST(saddr) || BADCLASS(saddr) || ZERONET(saddr) ||
> > 		saddr == htonl(INADDR_BROADCAST)
> > as invalid.
> 
> I did that, and indeed now connect() works, and sends out (when considering
> TCP) the appropriate SYN packet.
> 
> Unfortunately, that's not enough. When the return SYN-ACK packet carrying a
> non-local destination address is received (in practice, the transparent
> proxy machine is acting as a default gateway to the other machine), this
> packet is either ignored or forwarded out (depending on ip_forward), but is
> never accepted as a local packet and transfered to the appropriate socket
> as it should.

Right.
In 2.2 kernel you also needed to configure which incoming packets you want to
handle locally.

If you want to handle locally all packets destined to a specific IP address,
just add local route.
If you want some complex matching rules, check iptables, there was something
about "redirects" there.  Alternatively, you may set up policy routing, but
it'll be considerably more difficult.

You seemed to start to solve your problems from the wrong end.
First of all, decide how to handle incoming packets.
Then consider outgoing.

	Andrey

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Transparent proxy support in 2.4 - revisited
  2001-09-03 10:44     ` Andrey Savochkin
@ 2001-09-03 13:16       ` Nadav Har'El
  2001-09-03 13:55         ` Andrey Savochkin
  2001-09-03 20:07         ` Nerijus Baliunas
  0 siblings, 2 replies; 11+ messages in thread
From: Nadav Har'El @ 2001-09-03 13:16 UTC (permalink / raw)
  To: Andrey Savochkin; +Cc: linux-kernel

On Mon, Sep 03, 2001, Andrey Savochkin wrote about "Re: Transparent proxy support in 2.4 - revisited":
> > Unfortunately, that's not enough. When the return SYN-ACK packet carrying a
> > non-local destination address is received (in practice, the transparent
> > proxy machine is acting as a default gateway to the other machine), this
> > packet is either ignored or forwarded out (depending on ip_forward), but is
> > never accepted as a local packet and transfered to the appropriate socket
> > as it should.
> 
> Right.
> In 2.2 kernel you also needed to configure which incoming packets you want to
> handle locally.

If I remember correctly, no such configuration was needed if the
CONFIG_IP_TRANSPARENT_PROXY compilation flag was enabled. As I understand from
a cursory examination of the 2.2 source, Whenever packets were received and
were not meant for the local address, a check would be made if they meant for
one of the transparent-proxied connections (i.e., connections whose local
endpoint isn't local).

This is the kind of thing I need in Linux 2.4 too.
I'm still puzzled by the fact that this support simply disappeared between
2.2 and 2.4, and nobody seems to know why (or people who know why don't
reply).

> If you want to handle locally all packets destined to a specific IP address,
> just add local route.
> If you want some complex matching rules, check iptables, there was something
> about "redirects" there.

Remember that the reverse proxy machine, the one faking connections with an
adjacent server (as if they are coming from the actual clients) also serves
as the the gateway for that server and needs to forward packets for it.
So I can't redirect *all* packets to local sockets, yet I also can't pick
specific IP addresses to redirect (unless I write some sort of hack to
modify the iptables tables dynamically as new non-local bind()s happen).
Not to mention that the standard redirect, which also rewrites the destination
address on the packet (if I remember correctly), isn't quite what I need when
I already have a socket bound to a non-local address.


> You seemed to start to solve your problems from the wrong end.
> First of all, decide how to handle incoming packets.
> Then consider outgoing.

You're right. But I started at the easier end :)



-- 
Nadav Har'El                        |        Monday, Sep  3 2001, 15 Elul 5761
nyh@math.technion.ac.il             |-----------------------------------------
Phone: +972-53-245868, ICQ 13349191 |I'm a peripheral visionary: I see into
http://nadav.harel.org.il           |the future, but mostly off to the sides.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Transparent proxy support in 2.4 - revisited
  2001-09-03 13:16       ` Nadav Har'El
@ 2001-09-03 13:55         ` Andrey Savochkin
  2001-09-03 16:43           ` Julio Sanchez Fernandez
  2001-09-03 20:07         ` Nerijus Baliunas
  1 sibling, 1 reply; 11+ messages in thread
From: Andrey Savochkin @ 2001-09-03 13:55 UTC (permalink / raw)
  To: Nadav Har'El; +Cc: linux-kernel

Hi,

On Mon, Sep 03, 2001 at 04:16:21PM +0300, Nadav Har'El wrote:
> On Mon, Sep 03, 2001, Andrey Savochkin wrote about "Re: Transparent proxy support in 2.4 - revisited":
> > In 2.2 kernel you also needed to configure which incoming packets you want to
> > handle locally.
> 
> If I remember correctly, no such configuration was needed if the
> CONFIG_IP_TRANSPARENT_PROXY compilation flag was enabled. As I understand from
> a cursory examination of the 2.2 source, Whenever packets were received and
> were not meant for the local address, a check would be made if they meant for
> one of the transparent-proxied connections (i.e., connections whose local
> endpoint isn't local).

I don't remember for sure, but packet processing layering suggests that you
still needed to do something.  Otherwise the packet will be forwarded on the
routing level and will never reach socket layer.
So, ipchains rule was still necessary.
The really difference of 2.2 was amasingly complex socket lookup procedure
with CONFIG_IP_TRANSPARENT_PROXY turned on.

> This is the kind of thing I need in Linux 2.4 too.
> I'm still puzzled by the fact that this support simply disappeared between
> 2.2 and 2.4, and nobody seems to know why (or people who know why don't
> reply).

It had been broken in 2.2 for months and nobody repaired it => nobody needed
it.  I don't know, whether it works now or not.
The implementation was crooked, difficult to understand and maintain...

> > If you want to handle locally all packets destined to a specific IP address,
> > just add local route.
> > If you want some complex matching rules, check iptables, there was something
> > about "redirects" there.
> 
> Remember that the reverse proxy machine, the one faking connections with an
> adjacent server (as if they are coming from the actual clients) also serves
> as the the gateway for that server and needs to forward packets for it.

How are you going to determine whether the packet is destined to you or two
the real server?
That's the main question.

> So I can't redirect *all* packets to local sockets, yet I also can't pick
> specific IP addresses to redirect (unless I write some sort of hack to
> modify the iptables tables dynamically as new non-local bind()s happen).
> Not to mention that the standard redirect, which also rewrites the destination
> address on the packet (if I remember correctly), isn't quite what I need when

If it's true, the redirecting module is the place to change the policy to what
you need.
If the module always rewrites the destination IP address, and it can't be
turned off, it's certainly a misfeature.
Make it conditional, or just make a quick hack for yourself, or copy the
existing redirect module, fix it and use the new module.

> I already have a socket bound to a non-local address.

Best regards
		Andrey

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Transparent proxy support in 2.4 - revisited
  2001-09-03 13:55         ` Andrey Savochkin
@ 2001-09-03 16:43           ` Julio Sanchez Fernandez
  0 siblings, 0 replies; 11+ messages in thread
From: Julio Sanchez Fernandez @ 2001-09-03 16:43 UTC (permalink / raw)
  To: linux-kernel

Andrey Savochkin <saw@saw.sw.com.sg> writes:

> It had been broken in 2.2 for months and nobody repaired it => nobody needed
> it.  I don't know, whether it works now or not.

Broken?  It worked for me on all kernels I tried from RH, I currently
run it on 2.2.19.

> How are you going to determine whether the packet is destined to you or two
> the real server?
> That's the main question.

Maybe follow the method used by NAT now?  I mean, I presume no one
wants to go back to the old implementation...

> If the module always rewrites the destination IP address, and it can't be
> turned off, it's certainly a misfeature.
> Make it conditional, or just make a quick hack for yourself, or copy the
> existing redirect module, fix it and use the new module.

Well, that's another one to get used to, the old code made the output
from netstat or lsof extremely informative, something that is pretty
much lost now in 2.4.x.  Right?

Julio

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Transparent proxy support in 2.4 - revisited
  2001-09-03 13:16       ` Nadav Har'El
  2001-09-03 13:55         ` Andrey Savochkin
@ 2001-09-03 20:07         ` Nerijus Baliunas
  1 sibling, 0 replies; 11+ messages in thread
From: Nerijus Baliunas @ 2001-09-03 20:07 UTC (permalink / raw)
  To: Nadav Har'El, linux-kernel

NH> This is the kind of thing I need in Linux 2.4 too.
NH> I'm still puzzled by the fact that this support simply disappeared between
NH> 2.2 and 2.4, and nobody seems to know why (or people who know why don't
NH> reply).

Please look at the archives here: http://lists.samba.org/mailman/listinfo/netfilter-devel

Regards,
Nerijus



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Transparent proxy support in 2.4 - revisited
  2001-09-03 10:12   ` Transparent proxy support in 2.4 - revisited Nadav Har'El
  2001-09-03 10:44     ` Andrey Savochkin
@ 2001-09-03 22:50     ` Alexey Kuznetsov
  1 sibling, 0 replies; 11+ messages in thread
From: Alexey Kuznetsov @ 2001-09-03 22:50 UTC (permalink / raw)
  To: Nadav Har'El; +Cc: linux-kernel, davem

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain, Size: 11006 bytes --]

Hello!

> As I'm not an experienced Linux kernel hacker, and I'm barely familar with
> Linux's networking code, so I hesitate to attempt such a feat (resurrecting
> the transparent proxy code) myself, so I was wondering if anyone else had any
> plans of doing that?

Well, the patch which I used for this purpose, is enclosed.

The patch does not contain line óONFIG_IP_NONLOCAL_CONNECT in Config.in,
so that you have to add it yourself. Also it requires to call
setsockopt(..., SOL_IP, IP_NONLOCAL, 1, ) before binding to foreign
address.


> If not, does anyone know of a reason why this feature was abandoned 

Not __this__ feature was abandoned. The feature to __listen__ foreign
addresses and redirecting them to another port inside TCP i.e.
"transparent proxÕ" was moved to netfilter (not abandoned!).
Its implementation inside TCP even in 2.2 was full of bugs and
in 2.4 it is just impossible.

What's about active connect(), using nonlocal address, it was not abandoned.
Actually, I even was not aware of this feature and consider its presence
in 2.2 as very hard bug. It was not supposed to work and I have no idea
who opened this ugly hole. Even the person was me, it was misprint. :-)

But, actually, if someone reminded about this in time it could be repaired
in 2.2 in way proposed in the enclosed patch. I also would prefer to have it
in core, it is useful.

[ Dave, this forward is purely informational, of course. It is not a patch
 to apply :-) ]

Alexey


diff -ur ../vger3-010728/linux/include/linux/in.h linux/include/linux/in.h
--- ../vger3-010728/linux/include/linux/in.h	Thu Oct 26 18:06:21 2000
+++ linux/include/linux/in.h	Sun Aug  5 22:37:54 2001
@@ -67,6 +67,7 @@
 #define	IP_RECVTOS	13
 #define IP_MTU		14
 #define IP_FREEBIND	15
+#define IP_NONLOCAL	16
 
 /* BSD compatibility */
 #define IP_RECVRETOPTS	IP_RETOPTS
diff -ur ../vger3-010728/linux/include/net/route.h linux/include/net/route.h
--- ../vger3-010728/linux/include/net/route.h	Fri Jul 20 22:12:10 2001
+++ linux/include/net/route.h	Sun Aug  5 22:34:40 2001
@@ -36,10 +36,17 @@
 #endif
 
 #define RTO_ONLINK	0x01
-#define RTO_TPROXY	0x80000000
+#define RTO_TPROXY	0x8000
 
 #define RTO_CONN	0
 
+#ifdef CONFIG_IP_NONLOCAL_CONNECT
+#define RTO_SCONN(sk)	((sk)->reuse > 1 ? RTO_TPROXY : 0)
+#else
+#define RTO_SCONN(sk)	0
+#endif
+#define RT_CONN_FLAGS(sk)   (RT_TOS(sk->protinfo.af_inet.tos) | RTO_SCONN(sk) | sk->localroute)
+
 struct rt_key
 {
 	__u32			dst;
@@ -49,7 +56,7 @@
 #ifdef CONFIG_IP_ROUTE_FWMARK
 	__u32			fwmark;
 #endif
-	__u8			tos;
+	__u16			tos;
 	__u8			scope;
 };
 
diff -ur ../vger3-010728/linux/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c
--- ../vger3-010728/linux/net/ipv4/af_inet.c	Wed Jun 13 21:14:05 2001
+++ linux/net/ipv4/af_inet.c	Sun Aug  5 23:24:15 2001
@@ -485,6 +485,24 @@
 
 	chk_addr_ret = inet_addr_type(addr->sin_addr.s_addr);
 
+#ifdef CONFIG_IP_NONLOCAL_CONNECT
+	if (sk->reuse > 1) {
+		if (chk_addr_ret != RTN_UNICAST) {
+			/* Not a foreign address really, hence port is ours. */ 
+			sk->reuse = 1;
+		} else {
+			if (!addr->sin_port)
+				return -EINVAL;
+			printk(KERN_DEBUG "bind to nonlocal\n");
+			sk->protinfo.af_inet.freebind = 1;
+		}
+	} else {
+		/* Not priviledged freebind option is not compatible with
+		 * nonlocal connect. */
+		sk->protinfo.af_inet.freebind = 0;
+	}
+#endif
+
 	/* Not specified by any standard per-se, however it breaks too
 	 * many applications when removed.  It is unfortunate since
 	 * allowing applications to make a non-local bind solves
diff -ur ../vger3-010728/linux/net/ipv4/ip_forward.c linux/net/ipv4/ip_forward.c
--- ../vger3-010728/linux/net/ipv4/ip_forward.c	Wed Dec 13 22:23:13 2000
+++ linux/net/ipv4/ip_forward.c	Sun Aug  5 22:01:02 2001
@@ -84,6 +84,15 @@
 	if (skb->pkt_type != PACKET_HOST)
 		goto drop;
 
+#ifdef CONFIG_IP_NONLOCAL_CONNECT
+	/* Could be done with a netfilter hook. Not clear how exactly. */
+	if (skb->nh.iph->protocol == IPPROTO_TCP) {
+		if ((skb = tcp_v4_nonlocal_deliver(skb)) == NULL)
+			return NET_RX_SUCCESS;
+		opt = &(IPCB(skb)->opt);
+	}
+#endif
+
 	skb->ip_summed = CHECKSUM_NONE;
 	
 	/*
diff -ur ../vger3-010728/linux/net/ipv4/ip_output.c linux/net/ipv4/ip_output.c
--- ../vger3-010728/linux/net/ipv4/ip_output.c	Fri Jul 20 22:12:11 2001
+++ linux/net/ipv4/ip_output.c	Sun Aug  5 22:01:02 2001
@@ -357,7 +357,7 @@
 		 * out.
 		 */
 		if (ip_route_output(&rt, daddr, sk->saddr,
-				    RT_TOS(sk->protinfo.af_inet.tos) | RTO_CONN | sk->localroute,
+				    RT_CONN_FLAGS(sk),
 				    sk->bound_dev_if))
 			goto no_route;
 		__sk_dst_set(sk, &rt->u.dst);
diff -ur ../vger3-010728/linux/net/ipv4/ip_sockglue.c linux/net/ipv4/ip_sockglue.c
--- ../vger3-010728/linux/net/ipv4/ip_sockglue.c	Tue Feb 20 22:13:53 2001
+++ linux/net/ipv4/ip_sockglue.c	Sun Aug  5 23:24:57 2001
@@ -392,7 +392,7 @@
 			    (1<<IP_RETOPTS) | (1<<IP_TOS) | 
 			    (1<<IP_TTL) | (1<<IP_HDRINCL) | 
 			    (1<<IP_MTU_DISCOVER) | (1<<IP_RECVERR) | 
-			    (1<<IP_ROUTER_ALERT) | (1<<IP_FREEBIND))) || 
+			    (1<<IP_ROUTER_ALERT) | (1<<IP_FREEBIND) | (1<<IP_NONLOCAL))) || 
 				optname == IP_MULTICAST_TTL || 
 				optname == IP_MULTICAST_LOOP) { 
 		if (optlen >= sizeof(int)) {
@@ -624,6 +624,17 @@
 			sk->protinfo.af_inet.freebind = !!val; 
 	                break;			
  
+		case IP_NONLOCAL:
+			if (optlen<1)
+				goto e_inval;
+			if (!capable(CAP_NET_ADMIN))
+				goto e_inval;
+			if (val)
+				sk->reuse = 2;
+			else if (sk->reuse == 2)
+				sk->reuse = 1;
+	                break;			
+
 		default:
 #ifdef CONFIG_NETFILTER
 			err = nf_setsockopt(sk, PF_INET, optname, optval, 
diff -ur ../vger3-010728/linux/net/ipv4/route.c linux/net/ipv4/route.c
--- ../vger3-010728/linux/net/ipv4/route.c	Fri Jul 20 22:12:11 2001
+++ linux/net/ipv4/route.c	Sun Aug  5 23:24:15 2001
@@ -1689,6 +1689,16 @@
 
 /*
  * Major route resolver routine.
+ *
+ * NOTE: about CONFIG_IP_NONLOCAL_CONNECT. Here it concides to
+ * CONFIG_IP_TRANSPARENT_PROXY used in linux-2.2. However, 
+ * [ Also, I constructed new song: "Yesterday, all my troubles..."
+ *   Whaat?! Well, words are the same, music may be the same too. Why not?
+ *   But its sense is absolutely different!
+ * ]
+ * jokes apart, it is _not_ used to steal connections, only
+ * connections opened by us are nonlocal, hence we have
+ * no problems with TCP port shifting etc.
  */
 
 int ip_route_output_slow(struct rtable **rp, const struct rt_key *oldkey)
@@ -1728,8 +1738,19 @@
 
 		/* It is equivalent to inet_addr_type(saddr) == RTN_LOCAL */
 		dev_out = ip_dev_find(oldkey->src);
+#ifdef CONFIG_IP_NONLOCAL_CONNECT
+		/* If address is not local, test for nonlocal flag;
+		 * if address is local --- clear the flag.
+		 */
+		if (dev_out == NULL) {
+			if (!(oldkey->tos & RTO_TPROXY) || inet_addr_type(oldkey->src) != RTN_UNICAST)
+				goto out;
+			flags |= RTCF_TPROXY;
+		}
+#else
 		if (dev_out == NULL)
 			goto out;
+#endif
 
 		/* I removed check for oif == dev_out->oif here.
 		   It was wrong by three reasons:
@@ -1740,6 +1761,9 @@
 		 */
 
 		if (oldkey->oif == 0
+#ifdef CONFIG_IP_NONLOCAL_CONNECT
+		    && dev_out
+#endif
 		    && (MULTICAST(oldkey->dst) || oldkey->dst == 0xFFFFFFFF)) {
 			/* Special hack: user can direct multicasts
 			   and limited broadcast via necessary interface
diff -ur ../vger3-010728/linux/net/ipv4/syncookies.c linux/net/ipv4/syncookies.c
--- ../vger3-010728/linux/net/ipv4/syncookies.c	Fri May 11 21:40:10 2001
+++ linux/net/ipv4/syncookies.c	Sun Aug  5 22:01:12 2001
@@ -178,7 +178,7 @@
 			    opt && 
 			    opt->srr ? opt->faddr : req->af.v4_req.rmt_addr,
 			    req->af.v4_req.loc_addr,
-			    sk->protinfo.af_inet.tos | RTO_CONN,
+			    RT_TOS(sk->protinfo.af_inet.tos) | RTO_CONN,
 			    0)) { 
 		tcp_openreq_free(req);
 		goto out; 
diff -ur ../vger3-010728/linux/net/ipv4/tcp_ipv4.c linux/net/ipv4/tcp_ipv4.c
--- ../vger3-010728/linux/net/ipv4/tcp_ipv4.c	Wed Apr 25 21:02:18 2001
+++ linux/net/ipv4/tcp_ipv4.c	Sun Aug  5 23:24:15 2001
@@ -213,6 +213,8 @@
 				break;
 	}
 	if (tb != NULL && tb->owners != NULL) {
+		if (sk->reuse > 1)
+			goto success;
 		if (tb->fastreuse != 0 && sk->reuse != 0 && sk->state != TCP_LISTEN) {
 			goto success;
 		} else {
@@ -221,6 +223,7 @@
 
 			for( ; sk2 != NULL; sk2 = sk2->bind_next) {
 				if (sk != sk2 &&
+				    sk2->reuse <= 1 &&
 				    sk->bound_dev_if == sk2->bound_dev_if) {
 					if (!sk_reuse	||
 					    !sk2->reuse	||
@@ -660,7 +663,8 @@
 	}
 
 	tmp = ip_route_connect(&rt, nexthop, sk->saddr,
-			       RT_TOS(sk->protinfo.af_inet.tos)|RTO_CONN|sk->localroute, sk->bound_dev_if);
+			       RT_CONN_FLAGS(sk),
+			       sk->bound_dev_if);
 	if (tmp < 0)
 		return tmp;
 
@@ -676,7 +680,7 @@
 		daddr = rt->rt_dst;
 
 	err = -ENOBUFS;
-	buff = alloc_skb(MAX_TCP_HEADER + 15, GFP_KERNEL);
+	buff = alloc_skb(MAX_TCP_HEADER + 15, sk->allocation);
 
 	if (buff == NULL)
 		goto failure;
@@ -1704,6 +1708,44 @@
 	goto discard_it;
 }
 
+#ifdef CONFIG_IP_NONLOCAL_CONNECT
+/* Could be done with netfilter hook. Not clear how to hook this in right place. */
+
+struct sk_buff *tcp_v4_nonlocal_deliver(struct sk_buff *skb)
+{
+	struct sock *sk;
+	struct tcphdr *th;
+	int ihl;
+
+	if (skb->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
+		skb = ip_defrag(skb);
+		if (!skb)
+			return NULL;
+	}
+
+	ihl = skb->nh.iph->ihl*4;
+
+	if (!pskb_may_pull(skb, ihl+8))
+		goto out;
+
+	th = (struct tcphdr*)(skb->nh.raw + ihl);
+
+	sk = __tcp_v4_lookup_established(skb->nh.iph->saddr, th->source,
+					 skb->nh.iph->daddr, ntohs(th->dest),
+					 0);
+	if (sk) {
+		sock_put(sk);
+		ip_local_deliver(skb);
+		return NULL;
+	}
+
+out:
+	return skb;
+}
+#endif
+
+
+
 /* With per-bucket locks this operation is not-atomic, so that
  * this version is not worse.
  */
@@ -1776,7 +1818,7 @@
 		daddr = sk->protinfo.af_inet.opt->faddr;
 
 	err = ip_route_output(&rt, daddr, sk->saddr,
-			      RT_TOS(sk->protinfo.af_inet.tos) | RTO_CONN | sk->localroute,
+			      RT_CONN_FLAGS(sk),
 			      sk->bound_dev_if);
 	if (!err) {
 		__sk_dst_set(sk, &rt->u.dst);
diff -ur ../vger3-010728/linux/net/ipv4/udp.c linux/net/ipv4/udp.c
--- ../vger3-010728/linux/net/ipv4/udp.c	Wed Mar  7 22:17:47 2001
+++ linux/net/ipv4/udp.c	Sun Aug  5 22:01:15 2001
@@ -724,7 +724,7 @@
 	sk_dst_reset(sk);
 
 	err = ip_route_connect(&rt, usin->sin_addr.s_addr, sk->saddr,
-			       sk->protinfo.af_inet.tos|sk->localroute, sk->bound_dev_if);
+			       RT_TOS(sk->protinfo.af_inet.tos), sk->bound_dev_if);
 	if (err)
 		return err;
 	if ((rt->rt_flags&RTCF_BROADCAST) && !sk->broadcast) {
diff -ur ../vger3-010728/linux/net/ipv6/tcp_ipv6.c linux/net/ipv6/tcp_ipv6.c
--- ../vger3-010728/linux/net/ipv6/tcp_ipv6.c	Wed Jun 13 21:14:05 2001
+++ linux/net/ipv6/tcp_ipv6.c	Sun Aug  5 22:01:18 2001
@@ -656,7 +656,7 @@
 	tp->mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr);
 
 	err = -ENOBUFS;
-	buff = alloc_skb(MAX_TCP_HEADER + 15, GFP_KERNEL);
+	buff = alloc_skb(MAX_TCP_HEADER + 15, sk->allocation);
 
 	if (buff == NULL)
 		goto failure;


^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2001-09-04 15:56 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2001-06-07 14:08 Bug in nonlocal-bind (transparent proxy)? Nadav Har'El
2001-06-08  5:44 ` Andrey Savochkin
2001-06-08  8:02   ` Nadav Har'El
2001-06-08  8:25   ` David S. Miller
2001-09-03 10:12   ` Transparent proxy support in 2.4 - revisited Nadav Har'El
2001-09-03 10:44     ` Andrey Savochkin
2001-09-03 13:16       ` Nadav Har'El
2001-09-03 13:55         ` Andrey Savochkin
2001-09-03 16:43           ` Julio Sanchez Fernandez
2001-09-03 20:07         ` Nerijus Baliunas
2001-09-03 22:50     ` Alexey Kuznetsov

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®