Skip to content

Commit 39080b9

Browse files
work around Docker’s non-deterministic network interface assignment (#43)
The proxy is set up with two Docker networks. This creates two network interfaces, eth0 and eth1, in the proxy container. However, the setup is not deterministic: We don't know which interface will be assigned to which network. To restore determinism, we therefore need to determine if eth0 is facing the client and eth1 is facing the server, or vice versa.
1 parent 321f13c commit 39080b9

File tree

3 files changed

+38
-8
lines changed

3 files changed

+38
-8
lines changed

integration/docker-compose.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ services:
1010
- ASSIGN_ADDR=${CLIENT_ASSIGN_IP} # address to assign to the client
1111
- ROUTE=${ROUTE_SUBNET} # route advertised to the client (into the server's subnet)
1212
- FILTER_IP_PROTOCOL=${FILTER_IP_PROTOCOL}
13+
- GATEWAY_IPV4=${GATEWAY_IPV4}
14+
- GATEWAY_IPV6=${GATEWAY_IPV6}
1315
- QUIC_GO_DISABLE_RECEIVE_BUFFER_WARNING=true
1416
- QUIC_GO_DISABLE_GSO=true
1517
cap_add:

integration/proxy/proxy.go

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import (
2828

2929
var serverSocketRcv, serverSocketSend int
3030

31-
const ifaceName = "eth1"
31+
var ifaceName = os.Getenv("SERVER_INTERFACE")
3232

3333
func main() {
3434
proxyPort, err := strconv.Atoi(os.Getenv("PROXY_PORT"))
@@ -57,11 +57,18 @@ func main() {
5757
log.Fatalf("failed to get addresses for %s: %v", ifaceName, err)
5858
}
5959
if len(addrs) == 0 {
60-
log.Fatalf("no IPv4 addresses found for %s", ifaceName)
60+
log.Fatalf("no IP addresses found for %s", ifaceName)
6161
}
62-
ethAddr, ok := netip.AddrFromSlice(addrs[0].IP)
63-
if !ok {
64-
log.Fatalf("failed to parse %s address", ifaceName)
62+
var ethAddr netip.Addr
63+
for _, addr := range addrs {
64+
a, ok := netip.AddrFromSlice(addr.IP)
65+
if !ok {
66+
log.Fatalf("failed to parse %s address", ifaceName)
67+
}
68+
if !a.IsLinkLocalUnicast() {
69+
ethAddr = a
70+
break
71+
}
6572
}
6673

6774
fdRcv, err := createReceiveSocket(ethAddr)
@@ -90,7 +97,7 @@ func createReceiveSocket(a netip.Addr) (int, error) {
9097
if err != nil {
9198
return 0, fmt.Errorf("creating socket: %w", err)
9299
}
93-
iface, err := net.InterfaceByName("eth1")
100+
iface, err := net.InterfaceByName(ifaceName)
94101
if err != nil {
95102
return 0, fmt.Errorf("interface lookup failed: %w", err)
96103
}
@@ -122,7 +129,7 @@ func createSendSocketIPv4(addr netip.Addr) (int, error) {
122129
sa := &unix.SockaddrInet4{Port: 0} // raw sockets don't use ports
123130
copy(sa.Addr[:], addr.AsSlice())
124131
if err := unix.Bind(fd, sa); err != nil {
125-
return 0, fmt.Errorf("binding socket: %w", err)
132+
return 0, fmt.Errorf("binding socket to %s: %w", addr, err)
126133
}
127134
return fd, nil
128135
}
@@ -138,7 +145,7 @@ func createSendSocketIPv6(addr netip.Addr) (int, error) {
138145
sa := &unix.SockaddrInet6{Port: 0} // raw sockets don't use ports
139146
copy(sa.Addr[:], addr.AsSlice())
140147
if err := unix.Bind(fd, sa); err != nil {
141-
return 0, fmt.Errorf("binding socket: %w", err)
148+
return 0, fmt.Errorf("binding socket to %s: %w", addr, err)
142149
}
143150
return fd, nil
144151
}

integration/proxy/run.sh

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,27 @@
22

33
set -e
44

5+
# The proxy is set up with two Docker networks.
6+
# This creates two network interfaces, eth0 and eth1.
7+
# However, the setup is not deterministic:
8+
# We don't know which interface will be assigned to which network.
9+
# We therefore need to determine which interface is facing the client, and which one the server.
10+
SERVER_INTERFACE="eth1"
11+
if [ -n "$GATEWAY_IPV4" ] && ip addr show eth0 | grep 'inet ' | awk '{print $2}' | cut -d/ -f1 | grep -q "$GATEWAY_IPV4"; then
12+
SERVER_INTERFACE="eth0"
13+
fi
14+
if [ -n "$GATEWAY_IPV6" ] && ip addr show eth0 | grep 'inet6 ' | awk '{print $2}' | cut -d/ -f1 | grep -q "$GATEWAY_IPV6"; then
15+
SERVER_INTERFACE="eth0"
16+
fi
17+
18+
echo "eth0:"
19+
ip addr show eth0
20+
echo "eth1:"
21+
ip addr show eth1
22+
23+
echo "Server facing interface: $SERVER_INTERFACE"
24+
export SERVER_INTERFACE
25+
526
ethtool -K eth0 tx off
627
ethtool -K eth1 tx off
728

0 commit comments

Comments
 (0)