Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'ovpn-net-next-20260317' of https://github.com/OpenVPN/ovpn-net-next

Antonio Quartulli says:

====================
Included features:
* use bitops.h API when possible
* send netlink notification in case of client float event
* implement support for asymmetric peer IDs
* consolidate memory allocations during crypto operations
* add netlink notification check in selftests
* add FW mark check in selftest

* tag 'ovpn-net-next-20260317' of https://github.com/OpenVPN/ovpn-net-next:
ovpn: consolidate crypto allocations in one chunk
selftests: ovpn: add test for the FW mark feature
selftests: ovpn: check asymmetric peer-id
ovpn: add support for asymmetric peer IDs
selftests: ovpn: add notification parsing and matching
ovpn: notify userspace on client float event
ovpn: pktid: use bitops.h API
ovpn: use correct array size to parse nested attributes in ovpn_nl_key_swap_doit
selftests: ovpn: allow compiling ovpn-cli.c with mbedtls3
====================

Link: https://patch.msgid.link/20260317104023.192548-1-antonio@openvpn.net
Signed-off-by: Paolo Abeni <pabeni@redhat.com>

+743 -153
+22 -1
Documentation/netlink/specs/ovpn.yaml
··· 43 43 type: u32 44 44 doc: >- 45 45 The unique ID of the peer in the device context. To be used to 46 - identify peers during operations for a specific device 46 + identify peers during operations for a specific device. 47 + Also used to match packets received from this peer. 47 48 checks: 48 49 max: 0xFFFFFF 49 50 - ··· 161 160 name: link-tx-packets 162 161 type: uint 163 162 doc: Number of packets transmitted at the transport level 163 + - 164 + name: tx-id 165 + type: u32 166 + doc: >- 167 + The ID value used when transmitting packets to this peer. This 168 + way outgoing packets can have a different ID than incoming ones. 169 + Useful in multipeer-to-multipeer connections, where each peer 170 + will advertise the tx-id to be used on the link. 171 + checks: 172 + max: 0xFFFFFF 164 173 - 165 174 name: peer-new-input 166 175 subset-of: peer ··· 199 188 name: keepalive-interval 200 189 - 201 190 name: keepalive-timeout 191 + - 192 + name: tx-id 202 193 - 203 194 name: peer-set-input 204 195 subset-of: peer ··· 227 214 name: keepalive-interval 228 215 - 229 216 name: keepalive-timeout 217 + - 218 + name: tx-id 230 219 - 231 220 name: peer-del-input 232 221 subset-of: peer ··· 516 501 attributes: 517 502 - ifindex 518 503 - keyconf 504 + 505 + - 506 + name: peer-float-ntf 507 + doc: Notification about a peer floating (changing its remote UDP endpoint) 508 + notify: peer-get 509 + mcgrp: peers 519 510 520 511 mcast-groups: 521 512 list:
+124 -38
drivers/net/ovpn/crypto_aead.c
··· 36 36 crypto_aead_authsize(ks->encrypt); /* Auth Tag */ 37 37 } 38 38 39 + /** 40 + * ovpn_aead_crypto_tmp_size - compute the size of a temporary object containing 41 + * an AEAD request structure with extra space for SG 42 + * and IV. 43 + * @tfm: the AEAD cipher handle 44 + * @nfrags: the number of fragments in the skb 45 + * 46 + * This function calculates the size of a contiguous memory block that includes 47 + * the initialization vector (IV), the AEAD request, and an array of scatterlist 48 + * entries. For alignment considerations, the IV is placed first, followed by 49 + * the request, and then the scatterlist. 50 + * Additional alignment is applied according to the requirements of the 51 + * underlying structures. 52 + * 53 + * Return: the size of the temporary memory that needs to be allocated 54 + */ 55 + static unsigned int ovpn_aead_crypto_tmp_size(struct crypto_aead *tfm, 56 + const unsigned int nfrags) 57 + { 58 + unsigned int len = OVPN_NONCE_SIZE; 59 + 60 + DEBUG_NET_WARN_ON_ONCE(crypto_aead_ivsize(tfm) != OVPN_NONCE_SIZE); 61 + 62 + /* min size for a buffer of ivsize, aligned to alignmask */ 63 + len += crypto_aead_alignmask(tfm) & ~(crypto_tfm_ctx_alignment() - 1); 64 + /* round up to the next multiple of the crypto ctx alignment */ 65 + len = ALIGN(len, crypto_tfm_ctx_alignment()); 66 + 67 + /* reserve space for the AEAD request */ 68 + len += sizeof(struct aead_request) + crypto_aead_reqsize(tfm); 69 + /* round up to the next multiple of the scatterlist alignment */ 70 + len = ALIGN(len, __alignof__(struct scatterlist)); 71 + 72 + /* add enough space for nfrags + 2 scatterlist entries */ 73 + len += array_size(sizeof(struct scatterlist), nfrags + 2); 74 + return len; 75 + } 76 + 77 + /** 78 + * ovpn_aead_crypto_tmp_iv - retrieve the pointer to the IV within a temporary 79 + * buffer allocated using ovpn_aead_crypto_tmp_size 80 + * @aead: the AEAD cipher handle 81 + * @tmp: a pointer to the beginning of the temporary buffer 82 + * 83 + * This function retrieves a pointer to the initialization vector (IV) in the 84 + * temporary buffer. If the AEAD cipher specifies an IV size, the pointer is 85 + * adjusted using the AEAD's alignment mask to ensure proper alignment. 86 + * 87 + * Returns: a pointer to the IV within the temporary buffer 88 + */ 89 + static u8 *ovpn_aead_crypto_tmp_iv(struct crypto_aead *aead, void *tmp) 90 + { 91 + return likely(crypto_aead_ivsize(aead)) ? 92 + PTR_ALIGN((u8 *)tmp, crypto_aead_alignmask(aead) + 1) : 93 + tmp; 94 + } 95 + 96 + /** 97 + * ovpn_aead_crypto_tmp_req - retrieve the pointer to the AEAD request structure 98 + * within a temporary buffer allocated using 99 + * ovpn_aead_crypto_tmp_size 100 + * @aead: the AEAD cipher handle 101 + * @iv: a pointer to the initialization vector in the temporary buffer 102 + * 103 + * This function computes the location of the AEAD request structure that 104 + * immediately follows the IV in the temporary buffer and it ensures the request 105 + * is aligned to the crypto transform context alignment. 106 + * 107 + * Returns: a pointer to the AEAD request structure 108 + */ 109 + static struct aead_request *ovpn_aead_crypto_tmp_req(struct crypto_aead *aead, 110 + const u8 *iv) 111 + { 112 + return (void *)PTR_ALIGN(iv + crypto_aead_ivsize(aead), 113 + crypto_tfm_ctx_alignment()); 114 + } 115 + 116 + /** 117 + * ovpn_aead_crypto_req_sg - locate the scatterlist following the AEAD request 118 + * within a temporary buffer allocated using 119 + * ovpn_aead_crypto_tmp_size 120 + * @aead: the AEAD cipher handle 121 + * @req: a pointer to the AEAD request structure in the temporary buffer 122 + * 123 + * This function computes the starting address of the scatterlist that is 124 + * allocated immediately after the AEAD request structure. It aligns the pointer 125 + * based on the alignment requirements of the scatterlist structure. 126 + * 127 + * Returns: a pointer to the scatterlist 128 + */ 129 + static struct scatterlist *ovpn_aead_crypto_req_sg(struct crypto_aead *aead, 130 + struct aead_request *req) 131 + { 132 + return (void *)ALIGN((unsigned long)(req + 1) + 133 + crypto_aead_reqsize(aead), 134 + __alignof__(struct scatterlist)); 135 + } 136 + 39 137 int ovpn_aead_encrypt(struct ovpn_peer *peer, struct ovpn_crypto_key_slot *ks, 40 138 struct sk_buff *skb) 41 139 { ··· 143 45 struct scatterlist *sg; 144 46 int nfrags, ret; 145 47 u32 pktid, op; 48 + void *tmp; 146 49 u8 *iv; 147 50 148 51 ovpn_skb_cb(skb)->peer = peer; ··· 170 71 if (unlikely(nfrags + 2 > (MAX_SKB_FRAGS + 2))) 171 72 return -ENOSPC; 172 73 173 - /* sg may be required by async crypto */ 174 - ovpn_skb_cb(skb)->sg = kmalloc(sizeof(*ovpn_skb_cb(skb)->sg) * 175 - (nfrags + 2), GFP_ATOMIC); 176 - if (unlikely(!ovpn_skb_cb(skb)->sg)) 74 + /* allocate temporary memory for iv, sg and req */ 75 + tmp = kmalloc(ovpn_aead_crypto_tmp_size(ks->encrypt, nfrags), 76 + GFP_ATOMIC); 77 + if (unlikely(!tmp)) 177 78 return -ENOMEM; 178 79 179 - sg = ovpn_skb_cb(skb)->sg; 80 + ovpn_skb_cb(skb)->crypto_tmp = tmp; 81 + 82 + iv = ovpn_aead_crypto_tmp_iv(ks->encrypt, tmp); 83 + req = ovpn_aead_crypto_tmp_req(ks->encrypt, iv); 84 + sg = ovpn_aead_crypto_req_sg(ks->encrypt, req); 180 85 181 86 /* sg table: 182 87 * 0: op, wire nonce (AD, len=OVPN_OP_SIZE_V2+OVPN_NONCE_WIRE_SIZE), ··· 208 105 if (unlikely(ret < 0)) 209 106 return ret; 210 107 211 - /* iv may be required by async crypto */ 212 - ovpn_skb_cb(skb)->iv = kmalloc(OVPN_NONCE_SIZE, GFP_ATOMIC); 213 - if (unlikely(!ovpn_skb_cb(skb)->iv)) 214 - return -ENOMEM; 215 - 216 - iv = ovpn_skb_cb(skb)->iv; 217 - 218 108 /* concat 4 bytes packet id and 8 bytes nonce tail into 12 bytes 219 109 * nonce 220 110 */ ··· 218 122 memcpy(skb->data, iv, OVPN_NONCE_WIRE_SIZE); 219 123 220 124 /* add packet op as head of additional data */ 221 - op = ovpn_opcode_compose(OVPN_DATA_V2, ks->key_id, peer->id); 125 + op = ovpn_opcode_compose(OVPN_DATA_V2, ks->key_id, peer->tx_id); 222 126 __skb_push(skb, OVPN_OPCODE_SIZE); 223 127 BUILD_BUG_ON(sizeof(op) != OVPN_OPCODE_SIZE); 224 128 *((__force __be32 *)skb->data) = htonl(op); 225 129 226 130 /* AEAD Additional data */ 227 131 sg_set_buf(sg, skb->data, OVPN_AAD_SIZE); 228 - 229 - req = aead_request_alloc(ks->encrypt, GFP_ATOMIC); 230 - if (unlikely(!req)) 231 - return -ENOMEM; 232 - 233 - ovpn_skb_cb(skb)->req = req; 234 132 235 133 /* setup async crypto operation */ 236 134 aead_request_set_tfm(req, ks->encrypt); ··· 246 156 struct aead_request *req; 247 157 struct sk_buff *trailer; 248 158 struct scatterlist *sg; 159 + void *tmp; 249 160 u8 *iv; 250 161 251 162 payload_offset = OVPN_AAD_SIZE + tag_size; ··· 275 184 if (unlikely(nfrags + 2 > (MAX_SKB_FRAGS + 2))) 276 185 return -ENOSPC; 277 186 278 - /* sg may be required by async crypto */ 279 - ovpn_skb_cb(skb)->sg = kmalloc(sizeof(*ovpn_skb_cb(skb)->sg) * 280 - (nfrags + 2), GFP_ATOMIC); 281 - if (unlikely(!ovpn_skb_cb(skb)->sg)) 187 + /* allocate temporary memory for iv, sg and req */ 188 + tmp = kmalloc(ovpn_aead_crypto_tmp_size(ks->decrypt, nfrags), 189 + GFP_ATOMIC); 190 + if (unlikely(!tmp)) 282 191 return -ENOMEM; 283 192 284 - sg = ovpn_skb_cb(skb)->sg; 193 + ovpn_skb_cb(skb)->crypto_tmp = tmp; 194 + 195 + iv = ovpn_aead_crypto_tmp_iv(ks->decrypt, tmp); 196 + req = ovpn_aead_crypto_tmp_req(ks->decrypt, iv); 197 + sg = ovpn_aead_crypto_req_sg(ks->decrypt, req); 285 198 286 199 /* sg table: 287 200 * 0: op, wire nonce (AD, len=OVPN_OPCODE_SIZE+OVPN_NONCE_WIRE_SIZE), ··· 308 213 /* append auth_tag onto scatterlist */ 309 214 sg_set_buf(sg + ret + 1, skb->data + OVPN_AAD_SIZE, tag_size); 310 215 311 - /* iv may be required by async crypto */ 312 - ovpn_skb_cb(skb)->iv = kmalloc(OVPN_NONCE_SIZE, GFP_ATOMIC); 313 - if (unlikely(!ovpn_skb_cb(skb)->iv)) 314 - return -ENOMEM; 315 - 316 - iv = ovpn_skb_cb(skb)->iv; 317 - 318 216 /* copy nonce into IV buffer */ 319 217 memcpy(iv, skb->data + OVPN_OPCODE_SIZE, OVPN_NONCE_WIRE_SIZE); 320 218 memcpy(iv + OVPN_NONCE_WIRE_SIZE, ks->nonce_tail_recv, 321 219 OVPN_NONCE_TAIL_SIZE); 322 - 323 - req = aead_request_alloc(ks->decrypt, GFP_ATOMIC); 324 - if (unlikely(!req)) 325 - return -ENOMEM; 326 - 327 - ovpn_skb_cb(skb)->req = req; 328 220 329 221 /* setup async crypto operation */ 330 222 aead_request_set_tfm(req, ks->decrypt); ··· 355 273 goto error; 356 274 } 357 275 358 - /* basic AEAD assumption */ 276 + /* basic AEAD assumption 277 + * all current algorithms use OVPN_NONCE_SIZE. 278 + * ovpn_aead_crypto_tmp_size and ovpn_aead_encrypt/decrypt 279 + * expect this. 280 + */ 359 281 if (crypto_aead_ivsize(aead) != OVPN_NONCE_SIZE) { 360 282 pr_err("%s IV size must be %d\n", title, OVPN_NONCE_SIZE); 361 283 ret = -EINVAL;
+2 -6
drivers/net/ovpn/io.c
··· 119 119 peer = ovpn_skb_cb(skb)->peer; 120 120 121 121 /* crypto is done, cleanup skb CB and its members */ 122 - kfree(ovpn_skb_cb(skb)->iv); 123 - kfree(ovpn_skb_cb(skb)->sg); 124 - aead_request_free(ovpn_skb_cb(skb)->req); 122 + kfree(ovpn_skb_cb(skb)->crypto_tmp); 125 123 126 124 if (unlikely(ret < 0)) 127 125 goto drop; ··· 246 248 peer = ovpn_skb_cb(skb)->peer; 247 249 248 250 /* crypto is done, cleanup skb CB and its members */ 249 - kfree(ovpn_skb_cb(skb)->iv); 250 - kfree(ovpn_skb_cb(skb)->sg); 251 - aead_request_free(ovpn_skb_cb(skb)->req); 251 + kfree(ovpn_skb_cb(skb)->crypto_tmp); 252 252 253 253 if (unlikely(ret == -ERANGE)) { 254 254 /* we ran out of IVs and we must kill the key as it can't be
+95 -3
drivers/net/ovpn/netlink.c
··· 305 305 dst_cache_reset(&peer->dst_cache); 306 306 } 307 307 308 + /* In a multipeer-to-multipeer setup we may have asymmetric peer IDs, 309 + * that is peer->id might be different from peer->tx_id. 310 + */ 311 + if (attrs[OVPN_A_PEER_TX_ID]) 312 + peer->tx_id = nla_get_u32(attrs[OVPN_A_PEER_TX_ID]); 313 + 308 314 if (attrs[OVPN_A_PEER_VPN_IPV4]) { 309 315 rehash = true; 310 316 peer->vpn_addrs.ipv4.s_addr = ··· 332 326 } 333 327 334 328 netdev_dbg(peer->ovpn->dev, 335 - "modify peer id=%u endpoint=%pIScp VPN-IPv4=%pI4 VPN-IPv6=%pI6c\n", 336 - peer->id, &ss, 329 + "modify peer id=%u tx_id=%u endpoint=%pIScp VPN-IPv4=%pI4 VPN-IPv6=%pI6c\n", 330 + peer->id, peer->tx_id, &ss, 337 331 &peer->vpn_addrs.ipv4.s_addr, &peer->vpn_addrs.ipv6); 338 332 339 333 spin_unlock_bh(&peer->lock); ··· 379 373 } 380 374 381 375 peer_id = nla_get_u32(attrs[OVPN_A_PEER_ID]); 376 + 382 377 peer = ovpn_peer_new(ovpn, peer_id); 383 378 if (IS_ERR(peer)) { 384 379 NL_SET_ERR_MSG_FMT_MOD(info->extack, ··· 577 570 rcu_read_unlock(); 578 571 579 572 if (nla_put_u32(skb, OVPN_A_PEER_ID, peer->id)) 573 + goto err; 574 + 575 + if (nla_put_u32(skb, OVPN_A_PEER_TX_ID, peer->tx_id)) 580 576 goto err; 581 577 582 578 if (peer->vpn_addrs.ipv4.s_addr != htonl(INADDR_ANY)) ··· 1071 1061 1072 1062 int ovpn_nl_key_swap_doit(struct sk_buff *skb, struct genl_info *info) 1073 1063 { 1064 + struct nlattr *attrs[OVPN_A_KEYCONF_MAX + 1]; 1074 1065 struct ovpn_priv *ovpn = info->user_ptr[0]; 1075 - struct nlattr *attrs[OVPN_A_PEER_MAX + 1]; 1076 1066 struct ovpn_peer *peer; 1077 1067 u32 peer_id; 1078 1068 int ret; ··· 1200 1190 } 1201 1191 genlmsg_multicast_netns(&ovpn_nl_family, sock_net(sock->sk), msg, 0, 1202 1192 OVPN_NLGRP_PEERS, GFP_ATOMIC); 1193 + rcu_read_unlock(); 1194 + 1195 + return 0; 1196 + 1197 + err_unlock: 1198 + rcu_read_unlock(); 1199 + err_cancel_msg: 1200 + genlmsg_cancel(msg, hdr); 1201 + err_free_msg: 1202 + nlmsg_free(msg); 1203 + return ret; 1204 + } 1205 + 1206 + /** 1207 + * ovpn_nl_peer_float_notify - notify userspace about peer floating 1208 + * @peer: the floated peer 1209 + * @ss: sockaddr representing the new remote endpoint 1210 + * 1211 + * Return: 0 on success or a negative error code otherwise 1212 + */ 1213 + int ovpn_nl_peer_float_notify(struct ovpn_peer *peer, 1214 + const struct sockaddr_storage *ss) 1215 + { 1216 + struct ovpn_socket *sock; 1217 + struct sockaddr_in6 *sa6; 1218 + struct sockaddr_in *sa; 1219 + struct sk_buff *msg; 1220 + struct nlattr *attr; 1221 + int ret = -EMSGSIZE; 1222 + void *hdr; 1223 + 1224 + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); 1225 + if (!msg) 1226 + return -ENOMEM; 1227 + 1228 + hdr = genlmsg_put(msg, 0, 0, &ovpn_nl_family, 0, 1229 + OVPN_CMD_PEER_FLOAT_NTF); 1230 + if (!hdr) { 1231 + ret = -ENOBUFS; 1232 + goto err_free_msg; 1233 + } 1234 + 1235 + if (nla_put_u32(msg, OVPN_A_IFINDEX, peer->ovpn->dev->ifindex)) 1236 + goto err_cancel_msg; 1237 + 1238 + attr = nla_nest_start(msg, OVPN_A_PEER); 1239 + if (!attr) 1240 + goto err_cancel_msg; 1241 + 1242 + if (nla_put_u32(msg, OVPN_A_PEER_ID, peer->id)) 1243 + goto err_cancel_msg; 1244 + 1245 + if (ss->ss_family == AF_INET) { 1246 + sa = (struct sockaddr_in *)ss; 1247 + if (nla_put_in_addr(msg, OVPN_A_PEER_REMOTE_IPV4, 1248 + sa->sin_addr.s_addr) || 1249 + nla_put_net16(msg, OVPN_A_PEER_REMOTE_PORT, sa->sin_port)) 1250 + goto err_cancel_msg; 1251 + } else if (ss->ss_family == AF_INET6) { 1252 + sa6 = (struct sockaddr_in6 *)ss; 1253 + if (nla_put_in6_addr(msg, OVPN_A_PEER_REMOTE_IPV6, 1254 + &sa6->sin6_addr) || 1255 + nla_put_u32(msg, OVPN_A_PEER_REMOTE_IPV6_SCOPE_ID, 1256 + sa6->sin6_scope_id) || 1257 + nla_put_net16(msg, OVPN_A_PEER_REMOTE_PORT, sa6->sin6_port)) 1258 + goto err_cancel_msg; 1259 + } else { 1260 + ret = -EAFNOSUPPORT; 1261 + goto err_cancel_msg; 1262 + } 1263 + 1264 + nla_nest_end(msg, attr); 1265 + genlmsg_end(msg, hdr); 1266 + 1267 + rcu_read_lock(); 1268 + sock = rcu_dereference(peer->sock); 1269 + if (!sock) { 1270 + ret = -EINVAL; 1271 + goto err_unlock; 1272 + } 1273 + genlmsg_multicast_netns(&ovpn_nl_family, sock_net(sock->sk), msg, 1274 + 0, OVPN_NLGRP_PEERS, GFP_ATOMIC); 1203 1275 rcu_read_unlock(); 1204 1276 1205 1277 return 0;
+2
drivers/net/ovpn/netlink.h
··· 13 13 void ovpn_nl_unregister(void); 14 14 15 15 int ovpn_nl_peer_del_notify(struct ovpn_peer *peer); 16 + int ovpn_nl_peer_float_notify(struct ovpn_peer *peer, 17 + const struct sockaddr_storage *ss); 16 18 int ovpn_nl_key_swap_notify(struct ovpn_peer *peer, u8 key_id); 17 19 18 20 #endif /* _NET_OVPN_NETLINK_H_ */
+6
drivers/net/ovpn/peer.c
··· 99 99 if (!peer) 100 100 return ERR_PTR(-ENOMEM); 101 101 102 + /* in the default case TX and RX IDs are the same. 103 + * the user may set a different TX ID via netlink 104 + */ 102 105 peer->id = id; 106 + peer->tx_id = id; 103 107 peer->ovpn = ovpn; 104 108 105 109 peer->vpn_addrs.ipv4.s_addr = htonl(INADDR_ANY); ··· 290 286 netdev_name(peer->ovpn->dev), peer->id, &ss); 291 287 292 288 spin_unlock_bh(&peer->lock); 289 + 290 + ovpn_nl_peer_float_notify(peer, &ss); 293 291 294 292 /* rehashing is required only in MP mode as P2P has one peer 295 293 * only and thus there is no hashtable
+3 -1
drivers/net/ovpn/peer.h
··· 21 21 * struct ovpn_peer - the main remote peer object 22 22 * @ovpn: main openvpn instance this peer belongs to 23 23 * @dev_tracker: reference tracker for associated dev 24 - * @id: unique identifier 24 + * @id: unique identifier, used to match incoming packets 25 + * @tx_id: identifier to be used in TX packets 25 26 * @vpn_addrs: IP addresses assigned over the tunnel 26 27 * @vpn_addrs.ipv4: IPv4 assigned to peer on the tunnel 27 28 * @vpn_addrs.ipv6: IPv6 assigned to peer on the tunnel ··· 65 64 struct ovpn_priv *ovpn; 66 65 netdevice_tracker dev_tracker; 67 66 u32 id; 67 + u32 tx_id; 68 68 struct { 69 69 struct in_addr ipv4; 70 70 struct in6_addr ipv6;
+4 -7
drivers/net/ovpn/pktid.c
··· 65 65 if (likely(pkt_id == pr->id + 1)) { 66 66 /* well-formed ID sequence (incremented by 1) */ 67 67 pr->base = REPLAY_INDEX(pr->base, -1); 68 - pr->history[pr->base / 8] |= (1 << (pr->base % 8)); 68 + __set_bit(pr->base, pr->history); 69 69 if (pr->extent < REPLAY_WINDOW_SIZE) 70 70 ++pr->extent; 71 71 pr->id = pkt_id; ··· 77 77 unsigned int i; 78 78 79 79 pr->base = REPLAY_INDEX(pr->base, -delta); 80 - pr->history[pr->base / 8] |= (1 << (pr->base % 8)); 80 + __set_bit(pr->base, pr->history); 81 81 pr->extent += delta; 82 82 if (pr->extent > REPLAY_WINDOW_SIZE) 83 83 pr->extent = REPLAY_WINDOW_SIZE; 84 84 for (i = 1; i < delta; ++i) { 85 85 unsigned int newb = REPLAY_INDEX(pr->base, i); 86 86 87 - pr->history[newb / 8] &= ~BIT(newb % 8); 87 + __clear_bit(newb, pr->history); 88 88 } 89 89 } else { 90 90 pr->base = 0; ··· 103 103 if (pkt_id > pr->id_floor) { 104 104 const unsigned int ri = REPLAY_INDEX(pr->base, 105 105 delta); 106 - u8 *p = &pr->history[ri / 8]; 107 - const u8 mask = (1 << (ri % 8)); 108 106 109 - if (*p & mask) { 107 + if (__test_and_set_bit(ri, pr->history)) { 110 108 ret = -EINVAL; 111 109 goto out; 112 110 } 113 - *p |= mask; 114 111 } else { 115 112 ret = -EINVAL; 116 113 goto out;
+1 -1
drivers/net/ovpn/pktid.h
··· 34 34 */ 35 35 struct ovpn_pktid_recv { 36 36 /* "sliding window" bitmask of recent packet IDs received */ 37 - u8 history[REPLAY_WINDOW_BYTES]; 37 + DECLARE_BITMAP(history, REPLAY_WINDOW_SIZE); 38 38 /* bit position of deque base in history */ 39 39 unsigned int base; 40 40 /* extent (in bits) of deque in history */
+10 -3
drivers/net/ovpn/skb.h
··· 18 18 #include <linux/socket.h> 19 19 #include <linux/types.h> 20 20 21 + /** 22 + * struct ovpn_cb - ovpn skb control block 23 + * @peer: the peer this skb was received from/sent to 24 + * @ks: the crypto key slot used to encrypt/decrypt this skb 25 + * @crypto_tmp: pointer to temporary memory used for crypto operations 26 + * containing the IV, the scatter gather list and the aead request 27 + * @payload_offset: offset in the skb where the payload starts 28 + * @nosignal: whether this skb should be sent with the MSG_NOSIGNAL flag (TCP) 29 + */ 21 30 struct ovpn_cb { 22 31 struct ovpn_peer *peer; 23 32 struct ovpn_crypto_key_slot *ks; 24 - struct aead_request *req; 25 - struct scatterlist *sg; 26 - u8 *iv; 33 + void *crypto_tmp; 27 34 unsigned int payload_offset; 28 35 bool nosignal; 29 36 };
+2
include/uapi/linux/ovpn.h
··· 55 55 OVPN_A_PEER_LINK_TX_BYTES, 56 56 OVPN_A_PEER_LINK_RX_PACKETS, 57 57 OVPN_A_PEER_LINK_TX_PACKETS, 58 + OVPN_A_PEER_TX_ID, 58 59 59 60 __OVPN_A_PEER_MAX, 60 61 OVPN_A_PEER_MAX = (__OVPN_A_PEER_MAX - 1) ··· 101 100 OVPN_CMD_KEY_SWAP, 102 101 OVPN_CMD_KEY_SWAP_NTF, 103 102 OVPN_CMD_KEY_DEL, 103 + OVPN_CMD_PEER_FLOAT_NTF, 104 104 105 105 __OVPN_CMD_MAX, 106 106 OVPN_CMD_MAX = (__OVPN_CMD_MAX - 1)
+24 -7
tools/testing/selftests/net/ovpn/Makefile
··· 2 2 # Copyright (C) 2020-2025 OpenVPN, Inc. 3 3 # 4 4 CFLAGS = -pedantic -Wextra -Wall -Wl,--no-as-needed -g -O0 -ggdb $(KHDR_INCLUDES) 5 + CFLAGS += $(shell pkg-config --cflags mbedcrypto-3 mbedtls-3 2>/dev/null) 6 + 5 7 VAR_CFLAGS = $(shell pkg-config --cflags libnl-3.0 libnl-genl-3.0 2>/dev/null) 6 8 ifeq ($(VAR_CFLAGS),) 7 9 VAR_CFLAGS = -I/usr/include/libnl3 8 10 endif 9 11 CFLAGS += $(VAR_CFLAGS) 10 12 11 - 12 - LDLIBS = -lmbedtls -lmbedcrypto 13 - VAR_LDLIBS = $(shell pkg-config --libs libnl-3.0 libnl-genl-3.0 2>/dev/null) 14 - ifeq ($(VAR_LDLIBS),) 15 - VAR_LDLIBS = -lnl-genl-3 -lnl-3 13 + MTLS_LDLIBS= $(shell pkg-config --libs mbedcrypto-3 mbedtls-3 2>/dev/null) 14 + ifeq ($(MTLS_LDLIBS),) 15 + MTLS_LDLIBS = -lmbedtls -lmbedcrypto 16 16 endif 17 - LDLIBS += $(VAR_LDLIBS) 17 + LDLIBS += $(MTLS_LDLIBS) 18 + 19 + NL_LDLIBS = $(shell pkg-config --libs libnl-3.0 libnl-genl-3.0 2>/dev/null) 20 + ifeq ($(NL_LDLIBS),) 21 + NL_LDLIBS = -lnl-genl-3 -lnl-3 22 + endif 23 + LDLIBS += $(NL_LDLIBS) 18 24 19 25 20 - TEST_FILES = common.sh 26 + TEST_FILES = \ 27 + common.sh \ 28 + data64.key \ 29 + json \ 30 + tcp_peers.txt \ 31 + udp_peers.txt \ 32 + ../../../../net/ynl/pyynl/cli.py \ 33 + # end of TEST_FILES 21 34 22 35 TEST_PROGS := \ 23 36 test-chachapoly.sh \ ··· 38 25 test-close-socket.sh \ 39 26 test-float.sh \ 40 27 test-large-mtu.sh \ 28 + test-mark.sh \ 29 + test-symmetric-id-float.sh \ 30 + test-symmetric-id-tcp.sh \ 31 + test-symmetric-id.sh \ 41 32 test-tcp.sh \ 42 33 test.sh \ 43 34 # end of TEST_PROGS
+88 -13
tools/testing/selftests/net/ovpn/common.sh
··· 7 7 UDP_PEERS_FILE=${UDP_PEERS_FILE:-udp_peers.txt} 8 8 TCP_PEERS_FILE=${TCP_PEERS_FILE:-tcp_peers.txt} 9 9 OVPN_CLI=${OVPN_CLI:-./ovpn-cli} 10 + YNL_CLI=${YNL_CLI:-../../../../net/ynl/pyynl/cli.py} 10 11 ALG=${ALG:-aes} 11 12 PROTO=${PROTO:-UDP} 12 13 FLOAT=${FLOAT:-0} 14 + SYMMETRIC_ID=${SYMMETRIC_ID:-0} 13 15 16 + export ID_OFFSET=$(( 9 * (SYMMETRIC_ID == 0) )) 17 + 18 + JQ_FILTER='map(select(.msg.peer | has("remote-ipv6") | not)) | 19 + map(del(.msg.ifindex)) | sort_by(.msg.peer.id)[]' 14 20 LAN_IP="11.11.11.11" 21 + 22 + declare -A tmp_jsons=() 23 + declare -A listener_pids=() 15 24 16 25 create_ns() { 17 26 ip netns add peer${1} ··· 57 48 ip -n peer${1} link set tun${1} up 58 49 } 59 50 51 + build_capture_filter() { 52 + # match the first four bytes of the openvpn data payload 53 + if [ "${PROTO}" == "UDP" ]; then 54 + # For UDP, libpcap transport indexing only works for IPv4, so 55 + # use an explicit IPv4 or IPv6 expression based on the peer 56 + # address. The IPv6 branch assumes there are no extension 57 + # headers in the outer packet. 58 + if [[ "${2}" == *:* ]]; then 59 + printf "ip6 and ip6[6] = 17 and ip6[48:4] = %s" "${1}" 60 + else 61 + printf "ip and udp[8:4] = %s" "${1}" 62 + fi 63 + else 64 + # openvpn over TCP prepends a 2-byte packet length ahead of the 65 + # DATA_V2 opcode, so skip it before matching the payload header 66 + printf "ip and tcp[(((tcp[12] & 0xf0) >> 2) + 2):4] = %s" "${1}" 67 + fi 68 + } 69 + 70 + setup_listener() { 71 + file=$(mktemp) 72 + PYTHONUNBUFFERED=1 ip netns exec peer${p} ${YNL_CLI} --family ovpn \ 73 + --subscribe peers --output-json --duration 40 > ${file} & 74 + listener_pids[$1]=$! 75 + tmp_jsons[$1]="${file}" 76 + } 77 + 60 78 add_peer() { 79 + labels=("ASYMM" "SYMM") 80 + M_ID=${labels[SYMMETRIC_ID]} 81 + 61 82 if [ "${PROTO}" == "UDP" ]; then 62 83 if [ ${1} -eq 0 ]; then 63 - ip netns exec peer0 ${OVPN_CLI} new_multi_peer tun0 1 ${UDP_PEERS_FILE} 84 + ip netns exec peer0 ${OVPN_CLI} new_multi_peer tun0 1 \ 85 + ${M_ID} ${UDP_PEERS_FILE} 64 86 65 87 for p in $(seq 1 ${NUM_PEERS}); do 66 88 ip netns exec peer0 ${OVPN_CLI} new_key tun0 ${p} 1 0 ${ALG} 0 \ 67 89 data64.key 68 90 done 69 91 else 70 - RADDR=$(awk "NR == ${1} {print \$2}" ${UDP_PEERS_FILE}) 71 - RPORT=$(awk "NR == ${1} {print \$3}" ${UDP_PEERS_FILE}) 72 - LPORT=$(awk "NR == ${1} {print \$5}" ${UDP_PEERS_FILE}) 73 - ip netns exec peer${1} ${OVPN_CLI} new_peer tun${1} ${1} ${LPORT} \ 74 - ${RADDR} ${RPORT} 75 - ip netns exec peer${1} ${OVPN_CLI} new_key tun${1} ${1} 1 0 ${ALG} 1 \ 76 - data64.key 92 + if [ "${SYMMETRIC_ID}" -eq 1 ]; then 93 + PEER_ID=${1} 94 + TX_ID="none" 95 + else 96 + PEER_ID=$(awk "NR == ${1} {print \$2}" \ 97 + ${UDP_PEERS_FILE}) 98 + TX_ID=${1} 99 + fi 100 + RADDR=$(awk "NR == ${1} {print \$3}" ${UDP_PEERS_FILE}) 101 + RPORT=$(awk "NR == ${1} {print \$4}" ${UDP_PEERS_FILE}) 102 + LPORT=$(awk "NR == ${1} {print \$6}" ${UDP_PEERS_FILE}) 103 + ip netns exec peer${1} ${OVPN_CLI} new_peer tun${1} \ 104 + ${PEER_ID} ${TX_ID} ${LPORT} ${RADDR} ${RPORT} 105 + ip netns exec peer${1} ${OVPN_CLI} new_key tun${1} \ 106 + ${PEER_ID} 1 0 ${ALG} 1 data64.key 77 107 fi 78 108 else 79 109 if [ ${1} -eq 0 ]; then 80 - (ip netns exec peer0 ${OVPN_CLI} listen tun0 1 ${TCP_PEERS_FILE} && { 110 + (ip netns exec peer0 ${OVPN_CLI} listen tun0 1 ${M_ID} \ 111 + ${TCP_PEERS_FILE} && { 81 112 for p in $(seq 1 ${NUM_PEERS}); do 82 113 ip netns exec peer0 ${OVPN_CLI} new_key tun0 ${p} 1 0 \ 83 114 ${ALG} 0 data64.key ··· 125 76 }) & 126 77 sleep 5 127 78 else 128 - ip netns exec peer${1} ${OVPN_CLI} connect tun${1} ${1} 10.10.${1}.1 1 \ 129 - data64.key 79 + if [ "${SYMMETRIC_ID}" -eq 1 ]; then 80 + PEER_ID=${1} 81 + TX_ID="none" 82 + else 83 + PEER_ID=$(awk "NR == ${1} {print \$2}" \ 84 + ${TCP_PEERS_FILE}) 85 + TX_ID=${1} 86 + fi 87 + ip netns exec peer${1} ${OVPN_CLI} connect tun${1} \ 88 + ${PEER_ID} ${TX_ID} 10.10.${1}.1 1 data64.key 130 89 fi 90 + fi 91 + } 92 + 93 + compare_ntfs() { 94 + if [ ${#tmp_jsons[@]} -gt 0 ]; then 95 + suffix="" 96 + [ "${SYMMETRIC_ID}" -eq 1 ] && suffix="${suffix}-symm" 97 + [ "$FLOAT" == 1 ] && suffix="${suffix}-float" 98 + expected="json/peer${1}${suffix}.json" 99 + received="${tmp_jsons[$1]}" 100 + 101 + kill -TERM ${listener_pids[$1]} || true 102 + wait ${listener_pids[$1]} || true 103 + printf "Checking notifications for peer ${1}... " 104 + if diff <(jq -s "${JQ_FILTER}" ${expected}) \ 105 + <(jq -s "${JQ_FILTER}" ${received}); then 106 + echo "OK" 107 + fi 108 + 109 + rm -f ${received} || true 131 110 fi 132 111 } 133 112 ··· 181 104 else 182 105 NUM_PEERS=${NUM_PEERS:-$(wc -l ${TCP_PEERS_FILE} | awk '{print $1}')} 183 106 fi 184 - 185 -
+1 -5
tools/testing/selftests/net/ovpn/data64.key
··· 1 - jRqMACN7d7/aFQNT8S7jkrBD8uwrgHbG5OQZP2eu4R1Y7tfpS2bf5RHv06Vi163CGoaIiTX99R3B 2 - ia9ycAH8Wz1+9PWv51dnBLur9jbShlgZ2QHLtUc4a/gfT7zZwULXuuxdLnvR21DDeMBaTbkgbai9 3 - uvAa7ne1liIgGFzbv+Bas4HDVrygxIxuAnP5Qgc3648IJkZ0QEXPF+O9f0n5+QIvGCxkAUVx+5K6 4 - KIs+SoeWXnAopELmoGSjUpFtJbagXK82HfdqpuUxT2Tnuef0/14SzVE/vNleBNu2ZbyrSAaah8tE 5 - BofkPJUBFY+YQcfZNM5Dgrw3i+Bpmpq/gpdg5w== 1 + jRqMACN7d7/aFQNT8S7jkrBD8uwrgHbG5OQZP2eu4R1Y7tfpS2bf5RHv06Vi163CGoaIiTX99R3Bia9ycAH8Wz1+9PWv51dnBLur9jbShlgZ2QHLtUc4a/gfT7zZwULXuuxdLnvR21DDeMBaTbkgbai9uvAa7ne1liIgGFzbv+Bas4HDVrygxIxuAnP5Qgc3648IJkZ0QEXPF+O9f0n5+QIvGCxkAUVx+5K6KIs+SoeWXnAopELmoGSjUpFtJbagXK82HfdqpuUxT2Tnuef0/14SzVE/vNleBNu2ZbyrSAaah8tEBofkPJUBFY+YQcfZNM5Dgrw3i+Bpmpq/gpdg5w==
+9
tools/testing/selftests/net/ovpn/json/peer0-float.json
··· 1 + {"name": "peer-float-ntf", "msg": {"ifindex": 0, "peer": {"id": 1, "remote-ipv4": "10.10.1.3", "remote-port": 1}}} 2 + {"name": "peer-float-ntf", "msg": {"ifindex": 0, "peer": {"id": 2, "remote-ipv4": "10.10.2.3", "remote-port": 1}}} 3 + {"name": "peer-float-ntf", "msg": {"ifindex": 0, "peer": {"id": 3, "remote-ipv4": "10.10.3.3", "remote-port": 1}}} 4 + {"name": "peer-del-ntf", "msg": {"ifindex": 0, "peer": {"del-reason": "userspace", "id": 1}}} 5 + {"name": "peer-del-ntf", "msg": {"ifindex": 0, "peer": {"del-reason": "userspace", "id": 2}}} 6 + {"name": "peer-del-ntf", "msg": {"ifindex": 0, "peer": {"del-reason": "expired", "id": 3}}} 7 + {"name": "peer-del-ntf", "msg": {"ifindex": 0, "peer": {"del-reason": "expired", "id": 4}}} 8 + {"name": "peer-del-ntf", "msg": {"ifindex": 0, "peer": {"del-reason": "expired", "id": 5}}} 9 + {"name": "peer-del-ntf", "msg": {"ifindex": 0, "peer": {"del-reason": "expired", "id": 6}}}
+6
tools/testing/selftests/net/ovpn/json/peer0.json
··· 1 + {"name": "peer-del-ntf", "msg": {"ifindex": 0, "peer": {"del-reason": "userspace", "id": 1}}} 2 + {"name": "peer-del-ntf", "msg": {"ifindex": 0, "peer": {"del-reason": "userspace", "id": 2}}} 3 + {"name": "peer-del-ntf", "msg": {"ifindex": 0, "peer": {"del-reason": "expired", "id": 3}}} 4 + {"name": "peer-del-ntf", "msg": {"ifindex": 0, "peer": {"del-reason": "expired", "id": 4}}} 5 + {"name": "peer-del-ntf", "msg": {"ifindex": 0, "peer": {"del-reason": "expired", "id": 5}}} 6 + {"name": "peer-del-ntf", "msg": {"ifindex": 0, "peer": {"del-reason": "expired", "id": 6}}}
+1
tools/testing/selftests/net/ovpn/json/peer1-symm.json
··· 1 + {"name": "peer-del-ntf", "msg": {"ifindex": 0, "peer": {"del-reason": "userspace", "id": 1}}}
+1
tools/testing/selftests/net/ovpn/json/peer1.json
··· 1 + {"name": "peer-del-ntf", "msg": {"ifindex": 0, "peer": {"del-reason": "userspace", "id": 10}}}
+1
tools/testing/selftests/net/ovpn/json/peer2-symm.json
··· 1 + {"name": "peer-del-ntf", "msg": {"ifindex": 0, "peer": {"del-reason": "userspace", "id": 2}}}
+1
tools/testing/selftests/net/ovpn/json/peer2.json
··· 1 + {"name": "peer-del-ntf", "msg": {"ifindex": 0, "peer": {"del-reason": "userspace", "id": 11}}}
+1
tools/testing/selftests/net/ovpn/json/peer3-symm.json
··· 1 + {"name": "peer-del-ntf", "msg": {"ifindex": 0, "peer": {"del-reason": "expired", "id": 3}}}
+1
tools/testing/selftests/net/ovpn/json/peer3.json
··· 1 + {"name": "peer-del-ntf", "msg": {"ifindex": 0, "peer": {"del-reason": "expired", "id": 12}}}
+1
tools/testing/selftests/net/ovpn/json/peer4-symm.json
··· 1 + {"name": "peer-del-ntf", "msg": {"ifindex": 0, "peer": {"del-reason": "expired", "id": 4}}}
+1
tools/testing/selftests/net/ovpn/json/peer4.json
··· 1 + {"name": "peer-del-ntf", "msg": {"ifindex": 0, "peer": {"del-reason": "expired", "id": 13}}}
+1
tools/testing/selftests/net/ovpn/json/peer5-symm.json
··· 1 + {"name": "peer-del-ntf", "msg": {"ifindex": 0, "peer": {"del-reason": "expired", "id": 5}}}
+1
tools/testing/selftests/net/ovpn/json/peer5.json
··· 1 + {"name": "peer-del-ntf", "msg": {"ifindex": 0, "peer": {"del-reason": "expired", "id": 14}}}
+1
tools/testing/selftests/net/ovpn/json/peer6-symm.json
··· 1 + {"name": "peer-del-ntf", "msg": {"ifindex": 0, "peer": {"del-reason": "expired", "id": 6}}}
+1
tools/testing/selftests/net/ovpn/json/peer6.json
··· 1 + {"name": "peer-del-ntf", "msg": {"ifindex": 0, "peer": {"del-reason": "expired", "id": 15}}}
+116 -36
tools/testing/selftests/net/ovpn/ovpn-cli.c
··· 6 6 * Author: Antonio Quartulli <antonio@openvpn.net> 7 7 */ 8 8 9 + #include <stdint.h> 9 10 #include <stdio.h> 10 11 #include <inttypes.h> 11 12 #include <stdbool.h> ··· 104 103 105 104 sa_family_t sa_family; 106 105 107 - unsigned long peer_id; 106 + unsigned long peer_id, tx_id; 108 107 unsigned long lport; 109 108 110 109 union { ··· 133 132 enum ovpn_key_direction key_dir; 134 133 enum ovpn_key_slot key_slot; 135 134 int key_id; 135 + 136 + uint32_t mark; 137 + bool asymm_id; 136 138 137 139 const char *peers_file; 138 140 }; ··· 525 521 return ret; 526 522 } 527 523 524 + if (ctx->mark != 0) { 525 + ret = setsockopt(s, SOL_SOCKET, SO_MARK, (void *)&ctx->mark, 526 + sizeof(ctx->mark)); 527 + if (ret < 0) { 528 + perror("setsockopt for SO_MARK"); 529 + return ret; 530 + } 531 + } 532 + 528 533 if (family == AF_INET6) { 529 534 opt = 0; 530 535 if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &opt, ··· 662 649 663 650 attr = nla_nest_start(ctx->nl_msg, OVPN_A_PEER); 664 651 NLA_PUT_U32(ctx->nl_msg, OVPN_A_PEER_ID, ovpn->peer_id); 652 + if (ovpn->asymm_id) 653 + NLA_PUT_U32(ctx->nl_msg, OVPN_A_PEER_TX_ID, ovpn->tx_id); 665 654 NLA_PUT_U32(ctx->nl_msg, OVPN_A_PEER_SOCKET, ovpn->socket); 666 655 667 656 if (!is_tcp) { ··· 781 766 if (pattrs[OVPN_A_PEER_ID]) 782 767 fprintf(stderr, "* Peer %u\n", 783 768 nla_get_u32(pattrs[OVPN_A_PEER_ID])); 769 + 770 + if (pattrs[OVPN_A_PEER_TX_ID]) 771 + fprintf(stderr, "\tTX peer ID %u\n", 772 + nla_get_u32(pattrs[OVPN_A_PEER_TX_ID])); 784 773 785 774 if (pattrs[OVPN_A_PEER_SOCKET_NETNSID]) 786 775 fprintf(stderr, "\tsocket NetNS ID: %d\n", ··· 1535 1516 case OVPN_CMD_PEER_DEL_NTF: 1536 1517 fprintf(stdout, "received CMD_PEER_DEL_NTF\n"); 1537 1518 break; 1519 + case OVPN_CMD_PEER_FLOAT_NTF: 1520 + fprintf(stdout, "received CMD_PEER_FLOAT_NTF\n"); 1521 + break; 1538 1522 case OVPN_CMD_KEY_SWAP_NTF: 1539 1523 fprintf(stdout, "received CMD_KEY_SWAP_NTF\n"); 1540 1524 break; ··· 1676 1654 fprintf(stderr, "\tiface: ovpn interface name\n"); 1677 1655 1678 1656 fprintf(stderr, 1679 - "* listen <iface> <lport> <peers_file> [ipv6]: listen for incoming peer TCP connections\n"); 1657 + "* listen <iface> <lport> <id_type> <peers_file> [ipv6]: listen for incoming peer TCP connections\n"); 1680 1658 fprintf(stderr, "\tiface: ovpn interface name\n"); 1681 1659 fprintf(stderr, "\tlport: TCP port to listen to\n"); 1660 + fprintf(stderr, "\tid_type:\n"); 1661 + fprintf(stderr, 1662 + "\t\t- SYMM for ignoring the TX peer ID from the peers_file\n"); 1663 + fprintf(stderr, 1664 + "\t\t- ASYMM for using the TX peer ID from the peers_file\n"); 1682 1665 fprintf(stderr, 1683 1666 "\tpeers_file: file containing one peer per line: Line format:\n"); 1684 - fprintf(stderr, "\t\t<peer_id> <vpnaddr>\n"); 1667 + fprintf(stderr, "\t\t<peer_id> <tx_id> <vpnaddr>\n"); 1685 1668 fprintf(stderr, 1686 1669 "\tipv6: whether the socket should listen to the IPv6 wildcard address\n"); 1687 1670 1688 1671 fprintf(stderr, 1689 - "* connect <iface> <peer_id> <raddr> <rport> [key_file]: start connecting peer of TCP-based VPN session\n"); 1672 + "* connect <iface> <peer_id> <tx_id> <raddr> <rport> [key_file]: start connecting peer of TCP-based VPN session\n"); 1690 1673 fprintf(stderr, "\tiface: ovpn interface name\n"); 1691 - fprintf(stderr, "\tpeer_id: peer ID of the connecting peer\n"); 1674 + fprintf(stderr, 1675 + "\tpeer_id: peer ID found in data packets received from this peer\n"); 1676 + fprintf(stderr, 1677 + "\ttx_id: peer ID to be used when sending to this peer, 'none' for symmetric peer ID\n"); 1692 1678 fprintf(stderr, "\traddr: peer IP address to connect to\n"); 1693 1679 fprintf(stderr, "\trport: peer TCP port to connect to\n"); 1694 1680 fprintf(stderr, 1695 1681 "\tkey_file: file containing the symmetric key for encryption\n"); 1696 1682 1697 1683 fprintf(stderr, 1698 - "* new_peer <iface> <peer_id> <lport> <raddr> <rport> [vpnaddr]: add new peer\n"); 1684 + "* new_peer <iface> <peer_id> <tx_id> <lport> <raddr> <rport> [vpnaddr]: add new peer\n"); 1699 1685 fprintf(stderr, "\tiface: ovpn interface name\n"); 1700 - fprintf(stderr, "\tlport: local UDP port to bind to\n"); 1701 1686 fprintf(stderr, 1702 - "\tpeer_id: peer ID to be used in data packets to/from this peer\n"); 1687 + "\tpeer_id: peer ID found in data packets received from this peer\n"); 1688 + fprintf(stderr, 1689 + "\ttx_id: peer ID to be used when sending to this peer, 'none' for symmetric peer ID\n"); 1690 + fprintf(stderr, "\tlport: local UDP port to bind to\n"); 1703 1691 fprintf(stderr, "\traddr: peer IP address\n"); 1704 1692 fprintf(stderr, "\trport: peer UDP port\n"); 1705 1693 fprintf(stderr, "\tvpnaddr: peer VPN IP\n"); 1706 1694 1707 1695 fprintf(stderr, 1708 - "* new_multi_peer <iface> <lport> <peers_file>: add multiple peers as listed in the file\n"); 1696 + "* new_multi_peer <iface> <lport> <id_type> <peers_file> [mark]: add multiple peers as listed in the file\n"); 1709 1697 fprintf(stderr, "\tiface: ovpn interface name\n"); 1710 1698 fprintf(stderr, "\tlport: local UDP port to bind to\n"); 1699 + fprintf(stderr, "\tid_type:\n"); 1700 + fprintf(stderr, 1701 + "\t\t- SYMM for ignoring the TX peer ID from the peers_file\n"); 1702 + fprintf(stderr, 1703 + "\t\t- ASYMM for using the TX peer ID from the peers_file\n"); 1711 1704 fprintf(stderr, 1712 1705 "\tpeers_file: text file containing one peer per line. Line format:\n"); 1713 - fprintf(stderr, "\t\t<peer_id> <raddr> <rport> <vpnaddr>\n"); 1706 + fprintf(stderr, 1707 + "\t\t<peer_id> <tx_id> <raddr> <rport> <laddr> <lport> <vpnaddr>\n"); 1708 + fprintf(stderr, "\tmark: socket FW mark value\n"); 1714 1709 1715 1710 fprintf(stderr, 1716 1711 "* set_peer <iface> <peer_id> <keepalive_interval> <keepalive_timeout>: set peer attributes\n"); ··· 1840 1801 } 1841 1802 1842 1803 static int ovpn_parse_new_peer(struct ovpn_ctx *ovpn, const char *peer_id, 1843 - const char *raddr, const char *rport, 1844 - const char *vpnip) 1804 + const char *tx_id, const char *raddr, 1805 + const char *rport, const char *vpnip) 1845 1806 { 1846 1807 ovpn->peer_id = strtoul(peer_id, NULL, 10); 1847 1808 if (errno == ERANGE || ovpn->peer_id > PEER_ID_UNDEF) { 1848 - fprintf(stderr, "peer ID value out of range\n"); 1809 + fprintf(stderr, "rx peer ID value out of range\n"); 1849 1810 return -1; 1811 + } 1812 + 1813 + if (ovpn->asymm_id) { 1814 + ovpn->tx_id = strtoul(tx_id, NULL, 10); 1815 + if (errno == ERANGE || ovpn->tx_id > PEER_ID_UNDEF) { 1816 + fprintf(stderr, "tx peer ID value out of range\n"); 1817 + return -1; 1818 + } 1850 1819 } 1851 1820 1852 1821 return ovpn_parse_remote(ovpn, raddr, rport, vpnip); ··· 1983 1936 1984 1937 static int ovpn_run_cmd(struct ovpn_ctx *ovpn) 1985 1938 { 1986 - char peer_id[10], vpnip[INET6_ADDRSTRLEN], laddr[128], lport[10]; 1987 - char raddr[128], rport[10]; 1939 + char peer_id[10], tx_id[10], vpnip[INET6_ADDRSTRLEN], laddr[128]; 1940 + char lport[10], raddr[128], rport[10]; 1988 1941 int n, ret; 1989 1942 FILE *fp; 1990 1943 ··· 2011 1964 2012 1965 int num_peers = 0; 2013 1966 2014 - while ((n = fscanf(fp, "%s %s\n", peer_id, vpnip)) == 2) { 1967 + while ((n = fscanf(fp, "%s %s %s\n", peer_id, tx_id, 1968 + vpnip)) == 3) { 2015 1969 struct ovpn_ctx peer_ctx = { 0 }; 2016 1970 2017 1971 if (num_peers == MAX_PEERS) { ··· 2022 1974 2023 1975 peer_ctx.ifindex = ovpn->ifindex; 2024 1976 peer_ctx.sa_family = ovpn->sa_family; 1977 + peer_ctx.asymm_id = ovpn->asymm_id; 2025 1978 2026 1979 peer_ctx.socket = ovpn_accept(ovpn); 2027 1980 if (peer_ctx.socket < 0) { ··· 2033 1984 /* store peer sockets to test TCP I/O */ 2034 1985 ovpn->cli_sockets[num_peers] = peer_ctx.socket; 2035 1986 2036 - ret = ovpn_parse_new_peer(&peer_ctx, peer_id, NULL, 2037 - NULL, vpnip); 1987 + ret = ovpn_parse_new_peer(&peer_ctx, peer_id, tx_id, 1988 + NULL, NULL, vpnip); 2038 1989 if (ret < 0) { 2039 1990 fprintf(stderr, "error while parsing line\n"); 2040 1991 return -1; ··· 2102 2053 return -1; 2103 2054 } 2104 2055 2105 - while ((n = fscanf(fp, "%s %s %s %s %s %s\n", peer_id, laddr, 2106 - lport, raddr, rport, vpnip)) == 6) { 2056 + while ((n = fscanf(fp, "%s %s %s %s %s %s %s\n", peer_id, tx_id, 2057 + laddr, lport, raddr, rport, vpnip)) == 7) { 2107 2058 struct ovpn_ctx peer_ctx = { 0 }; 2108 2059 2109 2060 peer_ctx.ifindex = ovpn->ifindex; 2110 2061 peer_ctx.socket = ovpn->socket; 2111 2062 peer_ctx.sa_family = AF_UNSPEC; 2063 + peer_ctx.asymm_id = ovpn->asymm_id; 2112 2064 2113 - ret = ovpn_parse_new_peer(&peer_ctx, peer_id, raddr, 2114 - rport, vpnip); 2065 + ret = ovpn_parse_new_peer(&peer_ctx, peer_id, tx_id, 2066 + raddr, rport, vpnip); 2115 2067 if (ret < 0) { 2116 2068 fprintf(stderr, "error while parsing line\n"); 2117 2069 return -1; ··· 2208 2158 case CMD_DEL_IFACE: 2209 2159 break; 2210 2160 case CMD_LISTEN: 2211 - if (argc < 5) 2161 + if (argc < 6) 2212 2162 return -EINVAL; 2213 2163 2214 2164 ovpn->lport = strtoul(argv[3], NULL, 10); ··· 2217 2167 return -1; 2218 2168 } 2219 2169 2220 - ovpn->peers_file = argv[4]; 2170 + if (strcmp(argv[4], "SYMM") == 0) { 2171 + ovpn->asymm_id = false; 2172 + } else if (strcmp(argv[4], "ASYMM") == 0) { 2173 + ovpn->asymm_id = true; 2174 + } else { 2175 + fprintf(stderr, "Cannot parse id type: %s\n", argv[4]); 2176 + return -1; 2177 + } 2178 + 2179 + ovpn->peers_file = argv[5]; 2221 2180 2222 2181 ovpn->sa_family = AF_INET; 2223 - if (argc > 5 && !strcmp(argv[5], "ipv6")) 2182 + if (argc > 6 && !strcmp(argv[6], "ipv6")) 2224 2183 ovpn->sa_family = AF_INET6; 2225 2184 break; 2226 2185 case CMD_CONNECT: 2227 - if (argc < 6) 2186 + if (argc < 7) 2228 2187 return -EINVAL; 2229 2188 2230 2189 ovpn->sa_family = AF_INET; 2190 + ovpn->asymm_id = strcmp(argv[4], "none"); 2231 2191 2232 2192 ret = ovpn_parse_new_peer(ovpn, argv[3], argv[4], argv[5], 2233 - NULL); 2193 + argv[6], NULL); 2234 2194 if (ret < 0) { 2235 2195 fprintf(stderr, "Cannot parse remote peer data\n"); 2236 2196 return -1; 2237 2197 } 2238 2198 2239 - if (argc > 6) { 2199 + if (argc > 7) { 2240 2200 ovpn->key_slot = OVPN_KEY_SLOT_PRIMARY; 2241 2201 ovpn->key_id = 0; 2242 2202 ovpn->cipher = OVPN_CIPHER_ALG_AES_GCM; 2243 2203 ovpn->key_dir = KEY_DIR_OUT; 2244 2204 2245 - ret = ovpn_parse_key(argv[6], ovpn); 2205 + ret = ovpn_parse_key(argv[7], ovpn); 2246 2206 if (ret) 2247 2207 return -1; 2248 2208 } 2249 2209 break; 2250 2210 case CMD_NEW_PEER: 2251 - if (argc < 7) 2211 + if (argc < 8) 2252 2212 return -EINVAL; 2253 2213 2254 - ovpn->lport = strtoul(argv[4], NULL, 10); 2214 + ovpn->asymm_id = strcmp(argv[4], "none"); 2215 + 2216 + ovpn->lport = strtoul(argv[5], NULL, 10); 2255 2217 if (errno == ERANGE || ovpn->lport > 65535) { 2256 2218 fprintf(stderr, "lport value out of range\n"); 2257 2219 return -1; 2258 2220 } 2259 2221 2260 - const char *vpnip = (argc > 7) ? argv[7] : NULL; 2222 + const char *vpnip = (argc > 8) ? argv[8] : NULL; 2261 2223 2262 - ret = ovpn_parse_new_peer(ovpn, argv[3], argv[5], argv[6], 2263 - vpnip); 2224 + ret = ovpn_parse_new_peer(ovpn, argv[3], argv[4], argv[6], 2225 + argv[7], vpnip); 2264 2226 if (ret < 0) 2265 2227 return -1; 2266 2228 break; 2267 2229 case CMD_NEW_MULTI_PEER: 2268 - if (argc < 5) 2230 + if (argc < 6) 2269 2231 return -EINVAL; 2270 2232 2271 2233 ovpn->lport = strtoul(argv[3], NULL, 10); ··· 2286 2224 return -1; 2287 2225 } 2288 2226 2289 - ovpn->peers_file = argv[4]; 2227 + if (!strcmp(argv[4], "SYMM")) { 2228 + ovpn->asymm_id = false; 2229 + } else if (!strcmp(argv[4], "ASYMM")) { 2230 + ovpn->asymm_id = true; 2231 + } else { 2232 + fprintf(stderr, "Cannot parse id type: %s\n", argv[4]); 2233 + return -1; 2234 + } 2235 + 2236 + ovpn->peers_file = argv[5]; 2237 + 2238 + ovpn->mark = 0; 2239 + if (argc > 6) { 2240 + ovpn->mark = strtoul(argv[6], NULL, 10); 2241 + if (errno == ERANGE || ovpn->mark > UINT32_MAX) { 2242 + fprintf(stderr, "mark value out of range\n"); 2243 + return -1; 2244 + } 2245 + } 2290 2246 break; 2291 2247 case CMD_SET_PEER: 2292 2248 if (argc < 6)
+6 -5
tools/testing/selftests/net/ovpn/tcp_peers.txt
··· 1 - 1 5.5.5.2 2 - 2 5.5.5.3 3 - 3 5.5.5.4 4 - 4 5.5.5.5 5 - 5 5.5.5.6 1 + 1 10 5.5.5.2 2 + 2 11 5.5.5.3 3 + 3 12 5.5.5.4 4 + 4 13 5.5.5.5 5 + 5 14 5.5.5.6 6 + 6 15 5.5.5.7
+1 -1
tools/testing/selftests/net/ovpn/test-close-socket.sh
··· 27 27 28 28 for p in $(seq 1 ${NUM_PEERS}); do 29 29 ip netns exec peer0 ${OVPN_CLI} set_peer tun0 ${p} 60 120 30 - ip netns exec peer${p} ${OVPN_CLI} set_peer tun${p} ${p} 60 120 30 + ip netns exec peer${p} ${OVPN_CLI} set_peer tun${p} $((${p}+9)) 60 120 31 31 done 32 32 33 33 sleep 1
+96
tools/testing/selftests/net/ovpn/test-mark.sh
··· 1 + #!/bin/bash 2 + # SPDX-License-Identifier: GPL-2.0 3 + # Copyright (C) 2020-2025 OpenVPN, Inc. 4 + # 5 + # Author: Ralf Lici <ralf@mandelbit.com> 6 + # Antonio Quartulli <antonio@openvpn.net> 7 + 8 + #set -x 9 + set -e 10 + 11 + MARK=1056 12 + 13 + source ./common.sh 14 + 15 + cleanup 16 + 17 + modprobe -q ovpn || true 18 + 19 + for p in $(seq 0 "${NUM_PEERS}"); do 20 + create_ns "${p}" 21 + done 22 + 23 + for p in $(seq 0 3); do 24 + setup_ns "${p}" 5.5.5.$((p + 1))/24 25 + done 26 + 27 + # add peer0 with mark 28 + ip netns exec peer0 "${OVPN_CLI}" new_multi_peer tun0 1 ASYMM \ 29 + "${UDP_PEERS_FILE}" \ 30 + ${MARK} 31 + for p in $(seq 1 3); do 32 + ip netns exec peer0 "${OVPN_CLI}" new_key tun0 "${p}" 1 0 "${ALG}" 0 \ 33 + data64.key 34 + done 35 + 36 + for p in $(seq 1 3); do 37 + add_peer "${p}" 38 + done 39 + 40 + for p in $(seq 1 3); do 41 + ip netns exec peer0 "${OVPN_CLI}" set_peer tun0 "${p}" 60 120 42 + ip netns exec peer"${p}" "${OVPN_CLI}" set_peer tun"${p}" \ 43 + $((p + 9)) 60 120 44 + done 45 + 46 + sleep 1 47 + 48 + for p in $(seq 1 3); do 49 + ip netns exec peer0 ping -qfc 500 -w 3 5.5.5.$((p + 1)) 50 + done 51 + 52 + echo "Adding an nftables drop rule based on mark value ${MARK}" 53 + ip netns exec peer0 nft flush ruleset 54 + ip netns exec peer0 nft 'add table inet filter' 55 + ip netns exec peer0 nft 'add chain inet filter output { 56 + type filter hook output priority 0; 57 + policy accept; 58 + }' 59 + ip netns exec peer0 nft add rule inet filter output \ 60 + meta mark == ${MARK} \ 61 + counter drop 62 + 63 + DROP_COUNTER=$(ip netns exec peer0 nft list chain inet filter output \ 64 + | sed -n 's/.*packets \([0-9]*\).*/\1/p') 65 + sleep 1 66 + 67 + # ping should fail 68 + for p in $(seq 1 3); do 69 + PING_OUTPUT=$(ip netns exec peer0 ping \ 70 + -qfc 500 -w 1 5.5.5.$((p + 1)) 2>&1) && exit 1 71 + echo "${PING_OUTPUT}" 72 + LOST_PACKETS=$(echo "$PING_OUTPUT" \ 73 + | awk '/packets transmitted/ { print $1 }') 74 + # increment the drop counter by the amount of lost packets 75 + DROP_COUNTER=$((DROP_COUNTER + LOST_PACKETS)) 76 + done 77 + 78 + # check if the final nft counter matches our counter 79 + TOTAL_COUNT=$(ip netns exec peer0 nft list chain inet filter output \ 80 + | sed -n 's/.*packets \([0-9]*\).*/\1/p') 81 + if [ "${DROP_COUNTER}" -ne "${TOTAL_COUNT}" ]; then 82 + echo "Expected ${TOTAL_COUNT} drops, got ${DROP_COUNTER}" 83 + exit 1 84 + fi 85 + 86 + echo "Removing the drop rule" 87 + ip netns exec peer0 nft flush ruleset 88 + sleep 1 89 + 90 + for p in $(seq 1 3); do 91 + ip netns exec peer0 ping -qfc 500 -w 3 5.5.5.$((p + 1)) 92 + done 93 + 94 + cleanup 95 + 96 + modprobe -r ovpn || true
+11
tools/testing/selftests/net/ovpn/test-symmetric-id-float.sh
··· 1 + #!/bin/bash 2 + # SPDX-License-Identifier: GPL-2.0 3 + # Copyright (C) 2025 OpenVPN, Inc. 4 + # 5 + # Author: Ralf Lici <ralf@mandelbit.com> 6 + # Antonio Quartulli <antonio@openvpn.net> 7 + 8 + SYMMETRIC_ID="1" 9 + FLOAT="1" 10 + 11 + source test.sh
+11
tools/testing/selftests/net/ovpn/test-symmetric-id-tcp.sh
··· 1 + #!/bin/bash 2 + # SPDX-License-Identifier: GPL-2.0 3 + # Copyright (C) 2025 OpenVPN, Inc. 4 + # 5 + # Author: Ralf Lici <ralf@mandelbit.com> 6 + # Antonio Quartulli <antonio@openvpn.net> 7 + 8 + PROTO="TCP" 9 + SYMMETRIC_ID=1 10 + 11 + source test.sh
+10
tools/testing/selftests/net/ovpn/test-symmetric-id.sh
··· 1 + #!/bin/bash 2 + # SPDX-License-Identifier: GPL-2.0 3 + # Copyright (C) 2025 OpenVPN, Inc. 4 + # 5 + # Author: Ralf Lici <ralf@mandelbit.com> 6 + # Antonio Quartulli <antonio@openvpn.net> 7 + 8 + SYMMETRIC_ID="1" 9 + 10 + source test.sh
+62 -14
tools/testing/selftests/net/ovpn/test.sh
··· 18 18 done 19 19 20 20 for p in $(seq 0 ${NUM_PEERS}); do 21 + setup_listener ${p} 22 + done 23 + 24 + for p in $(seq 0 ${NUM_PEERS}); do 21 25 setup_ns ${p} 5.5.5.$((${p} + 1))/24 ${MTU} 22 26 done 23 27 ··· 31 27 32 28 for p in $(seq 1 ${NUM_PEERS}); do 33 29 ip netns exec peer0 ${OVPN_CLI} set_peer tun0 ${p} 60 120 34 - ip netns exec peer${p} ${OVPN_CLI} set_peer tun${p} ${p} 60 120 30 + ip netns exec peer${p} ${OVPN_CLI} set_peer tun${p} \ 31 + $((${p}+ID_OFFSET)) 60 120 35 32 done 36 33 37 34 sleep 1 38 35 36 + TCPDUMP_TIMEOUT="1.5s" 39 37 for p in $(seq 1 ${NUM_PEERS}); do 38 + # The first part of the data packet header consists of: 39 + # - TCP only: 2 bytes for the packet length 40 + # - 5 bits for opcode ("9" for DATA_V2) 41 + # - 3 bits for key-id ("0" at this point) 42 + # - 12 bytes for peer-id: 43 + # - with asymmetric ID: "${p}" one way and "${p} + 9" the other way 44 + # - with symmetric ID: "${p}" both ways 45 + HEADER1=$(printf "0x4800000%x" ${p}) 46 + HEADER2=$(printf "0x4800000%x" $((${p} + ID_OFFSET))) 47 + RADDR="" 48 + if [ "${PROTO}" == "UDP" ]; then 49 + RADDR=$(awk "NR == ${p} {print \$3}" ${UDP_PEERS_FILE}) 50 + fi 51 + 52 + timeout ${TCPDUMP_TIMEOUT} ip netns exec peer${p} \ 53 + tcpdump --immediate-mode -p -ni veth${p} -c 1 \ 54 + "$(build_capture_filter "${HEADER1}" "${RADDR}")" \ 55 + >/dev/null 2>&1 & 56 + TCPDUMP_PID1=$! 57 + timeout ${TCPDUMP_TIMEOUT} ip netns exec peer${p} \ 58 + tcpdump --immediate-mode -p -ni veth${p} -c 1 \ 59 + "$(build_capture_filter "${HEADER2}" "${RADDR}")" \ 60 + >/dev/null 2>&1 & 61 + TCPDUMP_PID2=$! 62 + 63 + sleep 0.3 40 64 ip netns exec peer0 ping -qfc 500 -w 3 5.5.5.$((${p} + 1)) 41 65 ip netns exec peer0 ping -qfc 500 -s 3000 -w 3 5.5.5.$((${p} + 1)) 66 + 67 + wait ${TCPDUMP_PID1} 68 + wait ${TCPDUMP_PID2} 42 69 done 43 70 44 71 # ping LAN behind client 1 ··· 92 57 93 58 echo "Adding secondary key and then swap:" 94 59 for p in $(seq 1 ${NUM_PEERS}); do 95 - ip netns exec peer0 ${OVPN_CLI} new_key tun0 ${p} 2 1 ${ALG} 0 data64.key 96 - ip netns exec peer${p} ${OVPN_CLI} new_key tun${p} ${p} 2 1 ${ALG} 1 data64.key 97 - ip netns exec peer${p} ${OVPN_CLI} swap_keys tun${p} ${p} 60 + ip netns exec peer0 ${OVPN_CLI} new_key tun0 ${p} 2 1 ${ALG} 0 \ 61 + data64.key 62 + ip netns exec peer${p} ${OVPN_CLI} new_key tun${p} \ 63 + $((${p} + ID_OFFSET)) 2 1 ${ALG} 1 data64.key 64 + ip netns exec peer${p} ${OVPN_CLI} swap_keys tun${p} \ 65 + $((${p} + ID_OFFSET)) 98 66 done 99 67 100 68 sleep 1 ··· 109 71 echo "Querying peer 1:" 110 72 ip netns exec peer0 ${OVPN_CLI} get_peer tun0 1 111 73 112 - echo "Querying non-existent peer 10:" 113 - ip netns exec peer0 ${OVPN_CLI} get_peer tun0 10 || true 74 + echo "Querying non-existent peer 20:" 75 + ip netns exec peer0 ${OVPN_CLI} get_peer tun0 20 || true 114 76 115 77 echo "Deleting peer 1:" 116 78 ip netns exec peer0 ${OVPN_CLI} del_peer tun0 1 117 - ip netns exec peer1 ${OVPN_CLI} del_peer tun1 1 79 + ip netns exec peer1 ${OVPN_CLI} del_peer tun1 $((1 + ID_OFFSET)) 118 80 119 81 echo "Querying keys:" 120 82 for p in $(seq 2 ${NUM_PEERS}); do 121 - ip netns exec peer${p} ${OVPN_CLI} get_key tun${p} ${p} 1 122 - ip netns exec peer${p} ${OVPN_CLI} get_key tun${p} ${p} 2 83 + ip netns exec peer${p} ${OVPN_CLI} get_key tun${p} \ 84 + $((${p} + ID_OFFSET)) 1 85 + ip netns exec peer${p} ${OVPN_CLI} get_key tun${p} \ 86 + $((${p} + ID_OFFSET)) 2 123 87 done 124 88 125 89 echo "Deleting peer while sending traffic:" ··· 130 90 ip netns exec peer0 ${OVPN_CLI} del_peer tun0 2 131 91 # following command fails in TCP mode 132 92 # (both ends get conn reset when one peer disconnects) 133 - ip netns exec peer2 ${OVPN_CLI} del_peer tun2 2 || true 93 + ip netns exec peer2 ${OVPN_CLI} del_peer tun2 $((2 + ID_OFFSET)) || true 134 94 135 95 echo "Deleting keys:" 136 96 for p in $(seq 3 ${NUM_PEERS}); do 137 - ip netns exec peer${p} ${OVPN_CLI} del_key tun${p} ${p} 1 138 - ip netns exec peer${p} ${OVPN_CLI} del_key tun${p} ${p} 2 97 + ip netns exec peer${p} ${OVPN_CLI} del_key tun${p} \ 98 + $((${p} + ID_OFFSET)) 1 99 + ip netns exec peer${p} ${OVPN_CLI} del_key tun${p} \ 100 + $((${p} + ID_OFFSET)) 2 139 101 done 140 102 141 103 echo "Setting timeout to 3s MP:" 142 104 for p in $(seq 3 ${NUM_PEERS}); do 143 105 ip netns exec peer0 ${OVPN_CLI} set_peer tun0 ${p} 3 3 || true 144 - ip netns exec peer${p} ${OVPN_CLI} set_peer tun${p} ${p} 0 0 106 + ip netns exec peer${p} ${OVPN_CLI} set_peer tun${p} \ 107 + $((${p} + ID_OFFSET)) 0 0 145 108 done 146 109 # wait for peers to timeout 147 110 sleep 5 148 111 149 112 echo "Setting timeout to 3s P2P:" 150 113 for p in $(seq 3 ${NUM_PEERS}); do 151 - ip netns exec peer${p} ${OVPN_CLI} set_peer tun${p} ${p} 3 3 114 + ip netns exec peer${p} ${OVPN_CLI} set_peer tun${p} \ 115 + $((${p} + ID_OFFSET)) 3 3 152 116 done 153 117 sleep 5 118 + 119 + for p in $(seq 0 ${NUM_PEERS}); do 120 + compare_ntfs ${p} 121 + done 154 122 155 123 cleanup 156 124
+6 -6
tools/testing/selftests/net/ovpn/udp_peers.txt
··· 1 - 1 10.10.1.1 1 10.10.1.2 1 5.5.5.2 2 - 2 10.10.2.1 1 10.10.2.2 1 5.5.5.3 3 - 3 10.10.3.1 1 10.10.3.2 1 5.5.5.4 4 - 4 fd00:0:0:4::1 1 fd00:0:0:4::2 1 5.5.5.5 5 - 5 fd00:0:0:5::1 1 fd00:0:0:5::2 1 5.5.5.6 6 - 6 fd00:0:0:6::1 1 fd00:0:0:6::2 1 5.5.5.7 1 + 1 10 10.10.1.1 1 10.10.1.2 1 5.5.5.2 2 + 2 11 10.10.2.1 1 10.10.2.2 1 5.5.5.3 3 + 3 12 10.10.3.1 1 10.10.3.2 1 5.5.5.4 4 + 4 13 fd00:0:0:4::1 1 fd00:0:0:4::2 1 5.5.5.5 5 + 5 14 fd00:0:0:5::1 1 fd00:0:0:5::2 1 5.5.5.6 6 + 6 15 fd00:0:0:6::1 1 fd00:0:0:6::2 1 5.5.5.7