Prev: How to detect own IP (assigned by DHCP server)?
Next: Mozilla Firefox: Fixing the proxer server settings for all users
From: Florian Weingarten on 17 Dec 2008 14:52 Hello, I have a problem with the SO_BINDTODEVICE socket option. Maybe somebody here can help me. Basically, I want to know how to FORCE the transmission of some TCP/UDP packets via some specific interface, even if the routing table says something different. I have a system with a tun/tap interface and some specific network is routed through that interface (via 'route add -net ... dev tun0'). I now want some userspace application (run as root) send packets to a host in that network through the default route (which is some gateway attached to eth0). What I am doing so far is (basically): * create the socket with socket() * setsockopt(SO_BINDTODEVICE, eth0) * bind() the socket to IN_ADDR_ANY and some port * connect() to the remote host * send() data If the route through the tun0 interface is not there, this works fine and the remote host receives the packets. However, if the tun0 route is up, nothing is transmitted through the default route (but nothing trough the tun0 route either). If I first start my client, THEN add the route, the transmission is interrupted (not closed! there is just no data arriving). If I delete the route again (while the client is running), the server suddenly receives all data (that should have been transmitted in between). Any ideas what the problem might be? Flo
From: David Schwartz on 17 Dec 2008 18:11 On Dec 17, 11:52 am, Florian Weingarten <f...(a)go.cc> wrote: > I have a problem with the SO_BINDTODEVICE socket option. Maybe somebody > here can help me. Basically, I want to know how to FORCE the > transmission of some TCP/UDP packets via some specific interface, > even if the routing table says something different. You cannot without using policy routing. > Any ideas what the problem might be? SO_BINDTODEVICE does not do what you think it does. Specifically, it does *NOT* force outgoing UDP or TCP packets to take the "wrong" interface, against the routing table. If taking the right interface, according to the routing table, doesn't work, then the routing table is wrong. You cannot fake around that with anything but system-level policy routing. Depending on your application, the right solution might also be to use raw sockets or bpf. DS
From: Florian Weingarten on 18 Dec 2008 04:29 Hello David, thank you for your answer! David Schwartz <davids(a)webmaster.com> wrote: > SO_BINDTODEVICE does not do what you think it does. Specifically, it > does *NOT* force outgoing UDP or TCP packets to take the "wrong" > interface, against the routing table. Hm. Then maybe I misunderstood something. Some manpage I found on the web says: SO_BINDTODEVICE Bind this socket to a particular device like "eth0", as specified in the passed interface name. (...) If a socket is bound to an interface, only packets received from that particular interface are processed by the socket. Note that this only works for some socket types, particularly AF_INET sockets And some really old kernel docu I found says: Once the BINDTODEVICE socket option has been set for a socket, as above, any data sent over this socket is guaranteed to go out of the "eth1" interface, and any data received through the socket is guaranteed to have arrived on eth1. (...) Note that the routing table is still consulted when packets are transmitted. Basically, routing proceeds as usual, except that any routes which go through a network interface other than the one specified in the BINDTODEVICE call are ignored. > If taking the right interface, according to the routing table, doesn't > work, then the routing table is wrong. You cannot fake around that > with anything but system-level policy routing. Well, to be concrete. What I want to do is to write a small tunnel software (as a university exercise). I have a default route for some network which goes to the tun0 interface, and the userspace program which is associated with that tun0 interface (the "daemon") is then supposed to send the raw packets, encapsulated as UDP packets, to the destination host, but of course I cant just send them, because then they would get delivered to the tun interface again (because of the route for that net!). So I wanted something like "this particular program should NOT use that route, all others should!". SO_BINDTODEVICE sounded like a solution :-( > Depending on your application, the right solution might also be to use > raw sockets or bpf. Why? Whats the difference? Does SO_BINDTODEVICE does what I want, except it does not work with UDP/TCP, but with RAW sockets? Why is that? Does that mean I have to use RAW sockets, then create my own UDP packet (create the headers myself and stuff) and then it would work? Thanks for your time! > DS Flo
From: David Schwartz on 18 Dec 2008 06:19
On Dec 18, 1:29 am, Florian Weingarten <f...(a)go.cc> wrote: > Hm. Then maybe I misunderstood something. Some manpage I found > on the web says: Definitely. > SO_BINDTODEVICE > Bind this socket to a particular device like "eth0", as specified > in the passed interface name. (...) If a socket is bound to an > interface, only packets received from that particular interface are > processed by the socket. Note that this only works for some socket > types, particularly AF_INET sockets This is mostly correct. Note that "received from that particular interface" does not mean what you think it means. Specifically, this does not mean that if you bind to an Ethernet interface, only packets received over the wire connected to that physical interface will be processed by the socket. > And some really old kernel docu I found says: > > Once the BINDTODEVICE socket option has been set for a socket, as above, > any data sent over this socket is guaranteed to go out of the "eth1" > interface, and any data received through the socket is guaranteed to > have arrived on eth1. (...) Note that the routing table is still > consulted when packets are transmitted. Basically, routing proceeds > as usual, except that any routes which go through a network interface > other than the one specified in the BINDTODEVICE call are ignored. This is not correct for TCP or UDP. It is correct for raw. > > If taking the right interface, according to the routing table, doesn't > > work, then the routing table is wrong. You cannot fake around that > > with anything but system-level policy routing. > Well, to be concrete. What I want to do is to write a small tunnel > software (as a university exercise). I have a default route for some > network which goes to the tun0 interface, and the userspace program > which is associated with that tun0 interface (the "daemon") is then > supposed to send the raw packets, encapsulated as UDP packets, to > the destination host, but of course I cant just send them, because > then they would get delivered to the tun interface again (because > of the route for that net!). So I wanted something like "this > particular program should NOT use that route, all others should!". > SO_BINDTODEVICE sounded like a solution :-( The usual way is to make a more specific route for the other end of the tunnel. Alternatively, you can use policy routing. As is, your routing table is simply disastrously wrong, it has an implosion route for the other end of the tunnel. Nothing you can do to one particular socket can fix the fact that your routing table is wrong. > > Depending on your application, the right solution might also be to use > > raw sockets or bpf. > Why? Whats the difference? Does SO_BINDTODEVICE does what I want, > except it does not work with UDP/TCP, but with RAW sockets? Why is > that? Because the kernel's implementation of UDP/TCP has to have certain assumptions for its own sanity. One of them is that the routing table does not contain fatal defects such as implosion routes. If you want to use the kernel's UDP/TCP, you must make sure the assumptions it relies on are in fact correct. One of them is that routing table doesn't contain routes that fail horribly. > Does that mean I have to use RAW sockets, then create my own > UDP packet (create the headers myself and stuff) and then it would > work? You could do it that way. The preferred way is either a more-specific route for the other end of the tunnel or not using UDP as the encapsulation protocol. DS |