Not so long ago, I was able to connect to a specific destination address from a primary or secondary IP address on this interface with the following steps.
- add a secondary IP address to this interface using
ip addr add ...
, - bind the socket to the primary or secondary address, if you want,
- Connect to the destination IP address using the primary or secondary address associated in # 2.
I recently upgraded my machine to Linux 3.3.6 and it no longer works, but I donโt remember the latest version I tried, it actually worked. Does anyone know how to do the same thing in new kernels? I just checked the same code on 2.6.23 on another machine.
UPDATE 2 This is similar to the NIC driver. With 3.3.6 and 8139too everything is in order. The same computer, but using a different NIC and via-rhine , then the problem occurs.
Here's what happens when I run the code (source at the end) on 3.3.6 (package output from tshark
runs in the background):
$ ./bind_connect 10.0.1.124 10.0.1.120 Bound socket: 10.0.1.120 [10.0.1.120->10.0.1.124]
And then the same on 2.6.23:
$ ./bind_connect 10.0.0.123 10.0.0.226 > Bound socket: 10.0.0.226 [10.0.0.226->10.0.0.123] $ 231.566278 10.0.0.226 -> 10.0.0.123 TCP 54109 > http [SYN] Seq=0 Win=5840 Len=0 MSS=1460 TSV=99922052 TSER=0 WS=5 231.566448 10.0.0.123 -> 10.0.0.226 TCP http > 54109 [SYN, ACK] Seq=0 Ack=1 Win=5792 Len=0 MSS=1460 TSV=7060755 TSER=99922052 WS=1 231.566463 10.0.0.226 -> 10.0.0.123 TCP 54109 > http [ACK] Seq=1 Ack=1 Win=5856 Len=0 TSV=99922052 TSER=7060755 231.566510 10.0.0.226 -> 10.0.0.123 TCP 54109 > http [FIN, ACK] Seq=1 Ack=1 Win=5856 Len=0 TSV=99922052 TSER=7060755 231.566593 10.0.0.123 -> 10.0.0.226 TCP http > 54109 [ACK] Seq=1 Ack=2 Win=5792 Len=0 TSV=7060755 TSER=99922052 231.566704 10.0.0.123 -> 10.0.0.226 TCP http > 54109 [FIN, ACK] Seq=1 Ack=2 Win=5792 Len=0 TSV=7060755 TSER=99922052 231.566737 10.0.0.226 -> 10.0.0.123 TCP 54109 > http [ACK] Seq=2 Ack=2 Win=5856 Len=0 TSV=99922052 TSER=7060755 $ ./bind_connect 10.0.0.123 10.0.0.126 > Bound socket: 10.0.0.126 [10.0.0.126->10.0.0.123] $ 235.824867 10.0.0.126 -> 10.0.0.123 TCP 34228 > http [SYN] Seq=0 Win=5840 Len=0 MSS=1460 TSV=99926310 TSER=0 WS=5 235.825185 10.0.0.123 -> 10.0.0.126 TCP http > 34228 [SYN, ACK] Seq=0 Ack=1 Win=5792 Len=0 MSS=1460 TSV=7061180 TSER=99926310 WS=1 235.825236 10.0.0.126 -> 10.0.0.123 TCP 34228 > http [ACK] Seq=1 Ack=1 Win=5856 Len=0 TSV=99926311 TSER=7061180 235.825273 10.0.0.126 -> 10.0.0.123 TCP 34228 > http [FIN, ACK] Seq=1 Ack=1 Win=5856 Len=0 TSV=99926311 TSER=7061180 235.825721 10.0.0.123 -> 10.0.0.126 TCP http > 34228 [ACK] Seq=1 Ack=2 Win=5792 Len=0 TSV=7061180 TSER=99926311 235.825722 10.0.0.123 -> 10.0.0.126 TCP http > 34228 [FIN, ACK] Seq=1 Ack=2 Win=5792 Len=0 TSV=7061180 TSER=99926311 235.825756 10.0.0.126 -> 10.0.0.123 TCP 34228 > http [ACK] Seq=2 Ack=2 Win=5856 Len=0 TSV=99926311 TSER=7061180 $ uname -a Linux gaia.mn.ca 2.6.23.17-88.fc7
Code for bind_connect:
#include <arpa/inet.h> #include <errno.h> #include <netinet/in.h> #include <netinet/tcp.h> #include <stdio.h> #include <sys/socket.h> #include <sys/types.h> #include <unistd.h> int main(int argc, char **argv) { struct sockaddr_in sn; socklen_t sn_len; struct sockaddr_in src; struct sockaddr_in dst; int sock; char b1[INET_ADDRSTRLEN]; char b2[INET_ADDRSTRLEN]; char b3[INET_ADDRSTRLEN]; src.sin_family = dst.sin_family = AF_INET; src.sin_port = 0; dst.sin_port = htons(80); if (argc < 3) { printf("missing argument\n"); return 1; } if (inet_pton(AF_INET, argv[1], &dst.sin_addr) != 1) { perror("pton"); return -errno; } if (inet_pton(AF_INET, argv[2], &src.sin_addr) != 1) { perror("pton"); return -errno; } sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) { perror("socket"); return -errno; } if (bind(sock, (struct sockaddr*)&src, sizeof src) != 0) { perror("bind"); return -errno; } sn_len = sizeof sn; if (getsockname(sock, (struct sockaddr*)&sn, &sn_len) != 0) { perror("getsockname"); return -errno; } printf("Bound socket: %s [%s->%s]\n", inet_ntop(AF_INET, &sn.sin_addr, b1, sizeof b1), inet_ntop(AF_INET, &src.sin_addr, b2, sizeof b2), inet_ntop(AF_INET, &dst.sin_addr, b3, sizeof b3)); if (connect(sock, (struct sockaddr*)&dst, sizeof dst) != 0) { perror("connect"); return -errno; } close(sock); return 0; }