diff options
| -rw-r--r-- | net/ipv4/devinet.c | 16 | ||||
| -rwxr-xr-x | tools/testing/selftests/net/route_localnet.sh | 74 |
2 files changed, 87 insertions, 3 deletions
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 914ccc7f192a..7874303220c5 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c | |||
| @@ -1287,6 +1287,7 @@ __be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope) | |||
| 1287 | { | 1287 | { |
| 1288 | const struct in_ifaddr *ifa; | 1288 | const struct in_ifaddr *ifa; |
| 1289 | __be32 addr = 0; | 1289 | __be32 addr = 0; |
| 1290 | unsigned char localnet_scope = RT_SCOPE_HOST; | ||
| 1290 | struct in_device *in_dev; | 1291 | struct in_device *in_dev; |
| 1291 | struct net *net = dev_net(dev); | 1292 | struct net *net = dev_net(dev); |
| 1292 | int master_idx; | 1293 | int master_idx; |
| @@ -1296,10 +1297,13 @@ __be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope) | |||
| 1296 | if (!in_dev) | 1297 | if (!in_dev) |
| 1297 | goto no_in_dev; | 1298 | goto no_in_dev; |
| 1298 | 1299 | ||
| 1300 | if (unlikely(IN_DEV_ROUTE_LOCALNET(in_dev))) | ||
| 1301 | localnet_scope = RT_SCOPE_LINK; | ||
| 1302 | |||
| 1299 | in_dev_for_each_ifa_rcu(ifa, in_dev) { | 1303 | in_dev_for_each_ifa_rcu(ifa, in_dev) { |
| 1300 | if (ifa->ifa_flags & IFA_F_SECONDARY) | 1304 | if (ifa->ifa_flags & IFA_F_SECONDARY) |
| 1301 | continue; | 1305 | continue; |
| 1302 | if (ifa->ifa_scope > scope) | 1306 | if (min(ifa->ifa_scope, localnet_scope) > scope) |
| 1303 | continue; | 1307 | continue; |
| 1304 | if (!dst || inet_ifa_match(dst, ifa)) { | 1308 | if (!dst || inet_ifa_match(dst, ifa)) { |
| 1305 | addr = ifa->ifa_local; | 1309 | addr = ifa->ifa_local; |
| @@ -1352,14 +1356,20 @@ EXPORT_SYMBOL(inet_select_addr); | |||
| 1352 | static __be32 confirm_addr_indev(struct in_device *in_dev, __be32 dst, | 1356 | static __be32 confirm_addr_indev(struct in_device *in_dev, __be32 dst, |
| 1353 | __be32 local, int scope) | 1357 | __be32 local, int scope) |
| 1354 | { | 1358 | { |
| 1359 | unsigned char localnet_scope = RT_SCOPE_HOST; | ||
| 1355 | const struct in_ifaddr *ifa; | 1360 | const struct in_ifaddr *ifa; |
| 1356 | __be32 addr = 0; | 1361 | __be32 addr = 0; |
| 1357 | int same = 0; | 1362 | int same = 0; |
| 1358 | 1363 | ||
| 1364 | if (unlikely(IN_DEV_ROUTE_LOCALNET(in_dev))) | ||
| 1365 | localnet_scope = RT_SCOPE_LINK; | ||
| 1366 | |||
| 1359 | in_dev_for_each_ifa_rcu(ifa, in_dev) { | 1367 | in_dev_for_each_ifa_rcu(ifa, in_dev) { |
| 1368 | unsigned char min_scope = min(ifa->ifa_scope, localnet_scope); | ||
| 1369 | |||
| 1360 | if (!addr && | 1370 | if (!addr && |
| 1361 | (local == ifa->ifa_local || !local) && | 1371 | (local == ifa->ifa_local || !local) && |
| 1362 | ifa->ifa_scope <= scope) { | 1372 | min_scope <= scope) { |
| 1363 | addr = ifa->ifa_local; | 1373 | addr = ifa->ifa_local; |
| 1364 | if (same) | 1374 | if (same) |
| 1365 | break; | 1375 | break; |
| @@ -1374,7 +1384,7 @@ static __be32 confirm_addr_indev(struct in_device *in_dev, __be32 dst, | |||
| 1374 | if (inet_ifa_match(addr, ifa)) | 1384 | if (inet_ifa_match(addr, ifa)) |
| 1375 | break; | 1385 | break; |
| 1376 | /* No, then can we use new local src? */ | 1386 | /* No, then can we use new local src? */ |
| 1377 | if (ifa->ifa_scope <= scope) { | 1387 | if (min_scope <= scope) { |
| 1378 | addr = ifa->ifa_local; | 1388 | addr = ifa->ifa_local; |
| 1379 | break; | 1389 | break; |
| 1380 | } | 1390 | } |
diff --git a/tools/testing/selftests/net/route_localnet.sh b/tools/testing/selftests/net/route_localnet.sh new file mode 100755 index 000000000000..116bfeab72fa --- /dev/null +++ b/tools/testing/selftests/net/route_localnet.sh | |||
| @@ -0,0 +1,74 @@ | |||
| 1 | #!/bin/bash | ||
| 2 | # SPDX-License-Identifier: GPL-2.0 | ||
| 3 | # | ||
| 4 | # Run a couple of tests when route_localnet = 1. | ||
| 5 | |||
| 6 | readonly PEER_NS="ns-peer-$(mktemp -u XXXXXX)" | ||
| 7 | |||
| 8 | setup() { | ||
| 9 | ip netns add "${PEER_NS}" | ||
| 10 | ip -netns "${PEER_NS}" link set dev lo up | ||
| 11 | ip link add name veth0 type veth peer name veth1 | ||
| 12 | ip link set dev veth0 up | ||
| 13 | ip link set dev veth1 netns "${PEER_NS}" | ||
| 14 | |||
| 15 | # Enable route_localnet and delete useless route 127.0.0.0/8. | ||
| 16 | sysctl -w net.ipv4.conf.veth0.route_localnet=1 | ||
| 17 | ip netns exec "${PEER_NS}" sysctl -w net.ipv4.conf.veth1.route_localnet=1 | ||
| 18 | ip route del 127.0.0.0/8 dev lo table local | ||
| 19 | ip netns exec "${PEER_NS}" ip route del 127.0.0.0/8 dev lo table local | ||
| 20 | |||
| 21 | ifconfig veth0 127.25.3.4/24 up | ||
| 22 | ip netns exec "${PEER_NS}" ifconfig veth1 127.25.3.14/24 up | ||
| 23 | |||
| 24 | ip route flush cache | ||
| 25 | ip netns exec "${PEER_NS}" ip route flush cache | ||
| 26 | } | ||
| 27 | |||
| 28 | cleanup() { | ||
| 29 | ip link del veth0 | ||
| 30 | ip route add local 127.0.0.0/8 dev lo proto kernel scope host src 127.0.0.1 | ||
| 31 | local -r ns="$(ip netns list|grep $PEER_NS)" | ||
| 32 | [ -n "$ns" ] && ip netns del $ns 2>/dev/null | ||
| 33 | } | ||
| 34 | |||
| 35 | # Run test when arp_announce = 2. | ||
| 36 | run_arp_announce_test() { | ||
| 37 | echo "run arp_announce test" | ||
| 38 | setup | ||
| 39 | |||
| 40 | sysctl -w net.ipv4.conf.veth0.arp_announce=2 | ||
| 41 | ip netns exec "${PEER_NS}" sysctl -w net.ipv4.conf.veth1.arp_announce=2 | ||
| 42 | ping -c5 -I veth0 127.25.3.14 | ||
| 43 | if [ $? -ne 0 ];then | ||
| 44 | echo "failed" | ||
| 45 | else | ||
| 46 | echo "ok" | ||
| 47 | fi | ||
| 48 | |||
| 49 | cleanup | ||
| 50 | } | ||
| 51 | |||
| 52 | # Run test when arp_ignore = 3. | ||
| 53 | run_arp_ignore_test() { | ||
| 54 | echo "run arp_ignore test" | ||
| 55 | setup | ||
| 56 | |||
| 57 | sysctl -w net.ipv4.conf.veth0.arp_ignore=3 | ||
| 58 | ip netns exec "${PEER_NS}" sysctl -w net.ipv4.conf.veth1.arp_ignore=3 | ||
| 59 | ping -c5 -I veth0 127.25.3.14 | ||
| 60 | if [ $? -ne 0 ];then | ||
| 61 | echo "failed" | ||
| 62 | else | ||
| 63 | echo "ok" | ||
| 64 | fi | ||
| 65 | |||
| 66 | cleanup | ||
| 67 | } | ||
| 68 | |||
| 69 | run_all_tests() { | ||
| 70 | run_arp_announce_test | ||
| 71 | run_arp_ignore_test | ||
| 72 | } | ||
| 73 | |||
| 74 | run_all_tests | ||
