diff options
-rw-r--r-- | MAINTAINERS | 3 | ||||
-rw-r--r-- | drivers/net/ovpn/crypto_aead.c | 18 | ||||
-rw-r--r-- | drivers/net/ovpn/io.c | 18 | ||||
-rw-r--r-- | drivers/net/ovpn/main.c | 5 | ||||
-rw-r--r-- | drivers/net/ovpn/peer.c | 5 | ||||
-rw-r--r-- | drivers/net/ovpn/udp.c | 10 | ||||
-rw-r--r-- | tools/testing/selftests/net/ovpn/Makefile | 1 | ||||
-rw-r--r-- | tools/testing/selftests/net/ovpn/common.sh | 18 | ||||
-rw-r--r-- | tools/testing/selftests/net/ovpn/ovpn-cli.c | 19 | ||||
-rwxr-xr-x | tools/testing/selftests/net/ovpn/test.sh | 6 | ||||
-rw-r--r-- | tools/testing/selftests/net/ovpn/udp_peers.txt | 11 |
11 files changed, 88 insertions, 26 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 84e99e991f53..c8e91820b527 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -18256,10 +18256,11 @@ F: drivers/irqchip/irq-or1k-* OPENVPN DATA CHANNEL OFFLOAD M: Antonio Quartulli <antonio@openvpn.net> +R: Sabrina Dubroca <sd@queasysnail.net> L: openvpn-devel@lists.sourceforge.net (subscribers-only) L: netdev@vger.kernel.org S: Supported -T: git https://github.com/OpenVPN/linux-kernel-ovpn.git +T: git https://github.com/OpenVPN/ovpn-net-next.git F: Documentation/netlink/specs/ovpn.yaml F: drivers/net/ovpn/ F: include/uapi/linux/ovpn.h diff --git a/drivers/net/ovpn/crypto_aead.c b/drivers/net/ovpn/crypto_aead.c index 74ee639ac868..2cca759feffa 100644 --- a/drivers/net/ovpn/crypto_aead.c +++ b/drivers/net/ovpn/crypto_aead.c @@ -88,12 +88,15 @@ int ovpn_aead_encrypt(struct ovpn_peer *peer, struct ovpn_crypto_key_slot *ks, /* build scatterlist to encrypt packet payload */ ret = skb_to_sgvec_nomark(skb, sg + 1, 0, skb->len); - if (unlikely(nfrags != ret)) - return -EINVAL; + if (unlikely(ret < 0)) { + netdev_err(peer->ovpn->dev, + "encrypt: cannot map skb to sg: %d\n", ret); + return ret; + } /* append auth_tag onto scatterlist */ __skb_push(skb, tag_size); - sg_set_buf(sg + nfrags + 1, skb->data, tag_size); + sg_set_buf(sg + ret + 1, skb->data, tag_size); /* obtain packet ID, which is used both as a first * 4 bytes of nonce and last 4 bytes of associated data. @@ -201,11 +204,14 @@ int ovpn_aead_decrypt(struct ovpn_peer *peer, struct ovpn_crypto_key_slot *ks, /* build scatterlist to decrypt packet payload */ ret = skb_to_sgvec_nomark(skb, sg + 1, payload_offset, payload_len); - if (unlikely(nfrags != ret)) - return -EINVAL; + if (unlikely(ret < 0)) { + netdev_err(peer->ovpn->dev, + "decrypt: cannot map skb to sg: %d\n", ret); + return ret; + } /* append auth_tag onto scatterlist */ - sg_set_buf(sg + nfrags + 1, skb->data + OVPN_AAD_SIZE, tag_size); + sg_set_buf(sg + ret + 1, skb->data + OVPN_AAD_SIZE, tag_size); /* iv may be required by async crypto */ ovpn_skb_cb(skb)->iv = kmalloc(OVPN_NONCE_SIZE, GFP_ATOMIC); diff --git a/drivers/net/ovpn/io.c b/drivers/net/ovpn/io.c index dd8a8055d967..10d8afecec55 100644 --- a/drivers/net/ovpn/io.c +++ b/drivers/net/ovpn/io.c @@ -394,10 +394,22 @@ netdev_tx_t ovpn_net_xmit(struct sk_buff *skb, struct net_device *dev) /* retrieve peer serving the destination IP of this packet */ peer = ovpn_peer_get_by_dst(ovpn, skb); if (unlikely(!peer)) { - net_dbg_ratelimited("%s: no peer to send data to\n", - netdev_name(ovpn->dev)); + switch (skb->protocol) { + case htons(ETH_P_IP): + net_dbg_ratelimited("%s: no peer to send data to dst=%pI4\n", + netdev_name(ovpn->dev), + &ip_hdr(skb)->daddr); + break; + case htons(ETH_P_IPV6): + net_dbg_ratelimited("%s: no peer to send data to dst=%pI6c\n", + netdev_name(ovpn->dev), + &ipv6_hdr(skb)->daddr); + break; + } goto drop; } + /* dst was needed for peer selection - it can now be dropped */ + skb_dst_drop(skb); ovpn_peer_stats_increment_tx(&peer->vpn_stats, skb->len); ovpn_send(ovpn, skb_list.next, peer); @@ -408,7 +420,7 @@ drop: dev_dstats_tx_dropped(ovpn->dev); skb_tx_error(skb); kfree_skb_list(skb); - return NET_XMIT_DROP; + return NETDEV_TX_OK; } /** diff --git a/drivers/net/ovpn/main.c b/drivers/net/ovpn/main.c index 0acb0934c1be..1bb1afe766a4 100644 --- a/drivers/net/ovpn/main.c +++ b/drivers/net/ovpn/main.c @@ -157,6 +157,11 @@ static void ovpn_setup(struct net_device *dev) dev->type = ARPHRD_NONE; dev->flags = IFF_POINTOPOINT | IFF_NOARP; dev->priv_flags |= IFF_NO_QUEUE; + /* when routing packets to a LAN behind a client, we rely on the + * route entry that originally brought the packet into ovpn, so + * don't release it + */ + netif_keep_dst(dev); dev->lltx = true; dev->features |= feat; diff --git a/drivers/net/ovpn/peer.c b/drivers/net/ovpn/peer.c index a37f89fffb02..a1fd27b9c038 100644 --- a/drivers/net/ovpn/peer.c +++ b/drivers/net/ovpn/peer.c @@ -258,7 +258,7 @@ void ovpn_peer_endpoints_update(struct ovpn_peer *peer, struct sk_buff *skb) */ if (unlikely(!ipv6_addr_equal(&bind->local.ipv6, &ipv6_hdr(skb)->daddr))) { - net_dbg_ratelimited("%s: learning local IPv6 for peer %d (%pI6c -> %pI6c\n", + net_dbg_ratelimited("%s: learning local IPv6 for peer %d (%pI6c -> %pI6c)\n", netdev_name(peer->ovpn->dev), peer->id, &bind->local.ipv6, &ipv6_hdr(skb)->daddr); @@ -1353,8 +1353,7 @@ void ovpn_peer_keepalive_work(struct work_struct *work) } /* prevent rearming if the interface is being destroyed */ - if (next_run > 0 && - READ_ONCE(ovpn->dev->reg_state) == NETREG_REGISTERED) { + if (next_run > 0) { netdev_dbg(ovpn->dev, "scheduling keepalive work: now=%llu next_run=%llu delta=%llu\n", next_run, now, next_run - now); diff --git a/drivers/net/ovpn/udp.c b/drivers/net/ovpn/udp.c index c9e189056f33..aef8c0406ec9 100644 --- a/drivers/net/ovpn/udp.c +++ b/drivers/net/ovpn/udp.c @@ -262,6 +262,16 @@ static int ovpn_udp6_output(struct ovpn_peer *peer, struct ovpn_bind *bind, dst_cache_set_ip6(cache, dst, &fl.saddr); transmit: + /* user IPv6 packets may be larger than the transport interface + * MTU (after encapsulation), however, since they are locally + * generated we should ensure they get fragmented. + * Setting the ignore_df flag to 1 will instruct ip6_fragment() to + * fragment packets if needed. + * + * NOTE: this is not needed for IPv4 because we pass df=0 to + * udp_tunnel_xmit_skb() + */ + skb->ignore_df = 1; udp_tunnel6_xmit_skb(dst, sk, skb, skb->dev, &fl.saddr, &fl.daddr, 0, ip6_dst_hoplimit(dst), 0, fl.fl6_sport, fl.fl6_dport, udp_get_no_check6_tx(sk)); diff --git a/tools/testing/selftests/net/ovpn/Makefile b/tools/testing/selftests/net/ovpn/Makefile index 2d102878cb6d..e0926d76b4c8 100644 --- a/tools/testing/selftests/net/ovpn/Makefile +++ b/tools/testing/selftests/net/ovpn/Makefile @@ -20,6 +20,7 @@ LDLIBS += $(VAR_LDLIBS) TEST_FILES = common.sh TEST_PROGS = test.sh \ + test-large-mtu.sh \ test-chachapoly.sh \ test-tcp.sh \ test-float.sh \ diff --git a/tools/testing/selftests/net/ovpn/common.sh b/tools/testing/selftests/net/ovpn/common.sh index 7502292a1ee0..88869c675d03 100644 --- a/tools/testing/selftests/net/ovpn/common.sh +++ b/tools/testing/selftests/net/ovpn/common.sh @@ -11,6 +11,8 @@ ALG=${ALG:-aes} PROTO=${PROTO:-UDP} FLOAT=${FLOAT:-0} +LAN_IP="11.11.11.11" + create_ns() { ip netns add peer${1} } @@ -24,15 +26,25 @@ setup_ns() { ip link add veth${p} netns peer0 type veth peer name veth${p} netns peer${p} ip -n peer0 addr add 10.10.${p}.1/24 dev veth${p} + ip -n peer0 addr add fd00:0:0:${p}::1/64 dev veth${p} ip -n peer0 link set veth${p} up ip -n peer${p} addr add 10.10.${p}.2/24 dev veth${p} + ip -n peer${p} addr add fd00:0:0:${p}::2/64 dev veth${p} ip -n peer${p} link set veth${p} up done fi ip netns exec peer${1} ${OVPN_CLI} new_iface tun${1} $MODE ip -n peer${1} addr add ${2} dev tun${1} + # add a secondary IP to peer 1, to test a LAN behind a client + if [ ${1} -eq 1 -a -n "${LAN_IP}" ]; then + ip -n peer${1} addr add ${LAN_IP} dev tun${1} + ip -n peer0 route add ${LAN_IP} via $(echo ${2} |sed -e s'!/.*!!') dev tun0 + fi + if [ -n "${3}" ]; then + ip -n peer${1} link set mtu ${3} dev tun${1} + fi ip -n peer${1} link set tun${1} up } @@ -46,7 +58,11 @@ add_peer() { data64.key done else - ip netns exec peer${1} ${OVPN_CLI} new_peer tun${1} ${1} 1 10.10.${1}.1 1 + RADDR=$(awk "NR == ${1} {print \$2}" ${UDP_PEERS_FILE}) + RPORT=$(awk "NR == ${1} {print \$3}" ${UDP_PEERS_FILE}) + LPORT=$(awk "NR == ${1} {print \$5}" ${UDP_PEERS_FILE}) + ip netns exec peer${1} ${OVPN_CLI} new_peer tun${1} ${1} ${LPORT} \ + ${RADDR} ${RPORT} ip netns exec peer${1} ${OVPN_CLI} new_key tun${1} ${1} 1 0 ${ALG} 1 \ data64.key fi diff --git a/tools/testing/selftests/net/ovpn/ovpn-cli.c b/tools/testing/selftests/net/ovpn/ovpn-cli.c index 69e41fc07fbc..de9c26f98b2e 100644 --- a/tools/testing/selftests/net/ovpn/ovpn-cli.c +++ b/tools/testing/selftests/net/ovpn/ovpn-cli.c @@ -1753,8 +1753,11 @@ static int ovpn_parse_remote(struct ovpn_ctx *ovpn, const char *host, if (host) { ret = getaddrinfo(host, service, &hints, &result); - if (ret == EAI_NONAME || ret == EAI_FAIL) + if (ret) { + fprintf(stderr, "getaddrinfo on remote error: %s\n", + gai_strerror(ret)); return -1; + } if (!(result->ai_family == AF_INET && result->ai_addrlen == sizeof(struct sockaddr_in)) && @@ -1769,8 +1772,11 @@ static int ovpn_parse_remote(struct ovpn_ctx *ovpn, const char *host, if (vpnip) { ret = getaddrinfo(vpnip, NULL, &hints, &result); - if (ret == EAI_NONAME || ret == EAI_FAIL) + if (ret) { + fprintf(stderr, "getaddrinfo on vpnip error: %s\n", + gai_strerror(ret)); return -1; + } if (!(result->ai_family == AF_INET && result->ai_addrlen == sizeof(struct sockaddr_in)) && @@ -1928,7 +1934,8 @@ static void ovpn_waitbg(void) static int ovpn_run_cmd(struct ovpn_ctx *ovpn) { - char peer_id[10], vpnip[INET6_ADDRSTRLEN], raddr[128], rport[10]; + char peer_id[10], vpnip[INET6_ADDRSTRLEN], laddr[128], lport[10]; + char raddr[128], rport[10]; int n, ret; FILE *fp; @@ -2044,8 +2051,8 @@ static int ovpn_run_cmd(struct ovpn_ctx *ovpn) return -1; } - while ((n = fscanf(fp, "%s %s %s %s\n", peer_id, raddr, rport, - vpnip)) == 4) { + while ((n = fscanf(fp, "%s %s %s %s %s %s\n", peer_id, laddr, + lport, raddr, rport, vpnip)) == 6) { struct ovpn_ctx peer_ctx = { 0 }; peer_ctx.ifindex = ovpn->ifindex; @@ -2349,7 +2356,7 @@ int main(int argc, char *argv[]) } memset(&ovpn, 0, sizeof(ovpn)); - ovpn.sa_family = AF_INET; + ovpn.sa_family = AF_UNSPEC; ovpn.cipher = OVPN_CIPHER_ALG_NONE; ovpn.cmd = ovpn_parse_cmd(argv[1]); diff --git a/tools/testing/selftests/net/ovpn/test.sh b/tools/testing/selftests/net/ovpn/test.sh index 7b62897b0240..e8acdc303307 100755 --- a/tools/testing/selftests/net/ovpn/test.sh +++ b/tools/testing/selftests/net/ovpn/test.sh @@ -18,7 +18,7 @@ for p in $(seq 0 ${NUM_PEERS}); do done for p in $(seq 0 ${NUM_PEERS}); do - setup_ns ${p} 5.5.5.$((${p} + 1))/24 + setup_ns ${p} 5.5.5.$((${p} + 1))/24 ${MTU} done for p in $(seq 0 ${NUM_PEERS}); do @@ -34,8 +34,12 @@ sleep 1 for p in $(seq 1 ${NUM_PEERS}); do ip netns exec peer0 ping -qfc 500 -w 3 5.5.5.$((${p} + 1)) + ip netns exec peer0 ping -qfc 500 -s 3000 -w 3 5.5.5.$((${p} + 1)) done +# ping LAN behind client 1 +ip netns exec peer0 ping -qfc 500 -w 3 ${LAN_IP} + if [ "$FLOAT" == "1" ]; then # make clients float.. for p in $(seq 1 ${NUM_PEERS}); do diff --git a/tools/testing/selftests/net/ovpn/udp_peers.txt b/tools/testing/selftests/net/ovpn/udp_peers.txt index 32f14bd9347a..e9773ddf875c 100644 --- a/tools/testing/selftests/net/ovpn/udp_peers.txt +++ b/tools/testing/selftests/net/ovpn/udp_peers.txt @@ -1,5 +1,6 @@ -1 10.10.1.2 1 5.5.5.2 -2 10.10.2.2 1 5.5.5.3 -3 10.10.3.2 1 5.5.5.4 -4 10.10.4.2 1 5.5.5.5 -5 10.10.5.2 1 5.5.5.6 +1 10.10.1.1 1 10.10.1.2 1 5.5.5.2 +2 10.10.2.1 1 10.10.2.2 1 5.5.5.3 +3 10.10.3.1 1 10.10.3.2 1 5.5.5.4 +4 fd00:0:0:4::1 1 fd00:0:0:4::2 1 5.5.5.5 +5 fd00:0:0:5::1 1 fd00:0:0:5::2 1 5.5.5.6 +6 fd00:0:0:6::1 1 fd00:0:0:6::2 1 5.5.5.7 |