1 |
1625 |
jcastillo |
SO_BINDTODEVICE socket option for Linux 2.0.30+
|
2 |
|
|
by Elliot Poger (elliot@poger.com)
|
3 |
|
|
of Stanford's MosquitoNet project (http://mosquitonet.stanford.edu)
|
4 |
|
|
|
5 |
|
|
Using the SO_BINDTODEVICE socket option allows your user-level Berkeley
|
6 |
|
|
sockets code to explicitly select which network interface is used for
|
7 |
|
|
both input and output on a per-socket basis. I originally wrote it to
|
8 |
|
|
allow the Internet Software Consortium DHCP server
|
9 |
|
|
(http://www.fugue.com/dhcp/) to run on Linux machines with multiple
|
10 |
|
|
interfaces. It has been tested with UDP and TCP sockets.
|
11 |
|
|
|
12 |
|
|
Usage is as follows:
|
13 |
|
|
|
14 |
|
|
|
15 |
|
|
int skfd;
|
16 |
|
|
struct ifreq interface;
|
17 |
|
|
|
18 |
|
|
skfd = socket(AF_INET, SOCK_DGRAM, 0);
|
19 |
|
|
strncpy(interface.ifr_ifrn.ifrn_name, "eth1", IFNAMSIZ);
|
20 |
|
|
if (setsockopt(skfd, SOL_SOCKET, SO_BINDTODEVICE,
|
21 |
|
|
(char *)&interface, sizeof(interface)) < 0) {
|
22 |
|
|
perror("sendpacket: setting SO_BINDTODEVICE");
|
23 |
|
|
exit(1);
|
24 |
|
|
}
|
25 |
|
|
|
26 |
|
|
|
27 |
|
|
Once the BINDTODEVICE socket option has been set for a socket, as above,
|
28 |
|
|
any data sent over this socket is guaranteed to go out of the "eth1"
|
29 |
|
|
interface, and any data received through the socket is guaranteed to
|
30 |
|
|
have arrived on eth1. If you want to send and receive over multiple
|
31 |
|
|
interfaces, keeping them separate, you can open several sockets and bind
|
32 |
|
|
each one to a different interface with SO_BINDTODEVICE. (You _can_ call
|
33 |
|
|
BINDTODEVICE more than once for a socket to change the interface it's
|
34 |
|
|
bound to, but results may be unpredictable because of caching effects
|
35 |
|
|
in the kernel...)
|
36 |
|
|
|
37 |
|
|
Note that the routing table is still consulted when packets are transmitted.
|
38 |
|
|
Basically, routing proceeds as usual, except that any routes which go
|
39 |
|
|
through a network interface other than the one specified in the BINDTODEVICE
|
40 |
|
|
call are ignored. If you attempt to send a packet to a certain IP address
|
41 |
|
|
through an interface which provides no route to that IP address, you'll get
|
42 |
|
|
a "network unreachable" error. Here is an example of a routing table which
|
43 |
|
|
will allow you to send packets to any IP address through either eth0 or
|
44 |
|
|
eth1:
|
45 |
|
|
|
46 |
|
|
Destination Gateway Genmask Flags Metric Ref Use Iface
|
47 |
|
|
171.64.69.0 0.0.0.0 255.255.255.192 U 0 0 37 eth0
|
48 |
|
|
171.64.69.192 0.0.0.0 255.255.255.192 U 0 0 677 eth1
|
49 |
|
|
127.0.0.0 0.0.0.0 255.0.0.0 U 0 0 4 lo
|
50 |
|
|
0.0.0.0 171.64.69.1 0.0.0.0 UG 0 0 45 eth0
|
51 |
|
|
0.0.0.0 171.64.69.193 0.0.0.0 UG 1 0 5 eth1
|
52 |
|
|
|
53 |
|
|
Note that there are actually TWO default routes. The routing table is
|
54 |
|
|
searched from top to bottom, so every time you send out a packet, the first
|
55 |
|
|
(uppermost) matching route which the kernel routing function finds which
|
56 |
|
|
matches the destination IP address is used. In this case, packets sent to
|
57 |
|
|
the IP address 152.2.128.159 will normally be sent through eth0 and gateway
|
58 |
|
|
171.64.69.1; if the socket is bound to the eth1 device, the packets will be
|
59 |
|
|
sent through eth1 and gateway 171.64.69.193; if the socket is bound to some
|
60 |
|
|
other device, you will get a "network unreachable" error.
|
61 |
|
|
|
62 |
|
|
By the way, you can add multiple default routes and set the order of
|
63 |
|
|
preference as follows:
|
64 |
|
|
|
65 |
|
|
route add default gateway 171.64.69.1
|
66 |
|
|
route add default gateway 171.64.69.193 metric 1
|
67 |
|
|
|
68 |
|
|
Routes with a higher "metric" are put lower in the table and thus have a
|
69 |
|
|
lower preference.
|