Skip to content

Commit 8c4d602

Browse files
committed
Kernel: T8605: net/l2tp: allow unmanaged tunnel setup without route to peer
Kernel-created L2TPv3 tunnels (genetlink L2TP_CMD_TUNNEL_CREATE without L2TP_ATTR_FD) used udp_sock_create() and kernel_connect(), which invoke __ip4_datagram_connect() / __ip6_datagram_connect(). Those paths insist on a successful FIB lookup at connect time. If no route to the configured remote existed yet, tunnel and interface creation failed. The data path already resolves routes on transmit (e.g. __ip_queue_xmit(), inet6_csk_route_socket()). This change defers requiring a route until packets are sent. Details: - UDP encapsulation: bind with udp_sock_create() after zeroing peer_udp_port, then l2tp_udp_sk_set_peer() sets daddr/dport and socket "connected" state without caching sk_dst from connect. - IPv4 L2TP/IP (l2tp_ip): on -ENETUNREACH / -EHOSTUNREACH from __ip4_datagram_connect(), l2tp_ip_connect_deferred() installs peer and bind-table updates without a connect-time route. - IPv6 L2TP/IP (l2tp_ip6): same for __ip6_datagram_connect(), including IPv4-mapped peers and scope / bound-device checks aligned with the normal connect path. Forwarding still only happens once the FIB can reach the peer. Until then outgoing packets follow the existing no-route drop path. Assisted-by: Cursor:claude-4.6-opus Signed-off-by: Christian Breunig <christian@breunig.cc>
1 parent 8669f15 commit 8c4d602

1 file changed

Lines changed: 326 additions & 0 deletions

File tree

Lines changed: 326 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,326 @@
1+
From: Christian Breunig <christian@breunig.cc>
2+
Date: Mon, 14 May 2026 13:11:00 +0200
3+
Subject: [PATCH] net/l2tp: allow unmanaged tunnel setup without route to peer
4+
5+
Kernel-created L2TPv3 tunnels (genetlink L2TP_CMD_TUNNEL_CREATE without
6+
L2TP_ATTR_FD) used udp_sock_create() and kernel_connect(), which invoke
7+
__ip4_datagram_connect() / __ip6_datagram_connect(). Those paths insist on
8+
a successful FIB lookup at connect time. If no route to the configured
9+
remote existed yet, tunnel and interface creation failed.
10+
11+
The data path already resolves routes on transmit (e.g. __ip_queue_xmit(),
12+
inet6_csk_route_socket()). This change defers requiring a route until
13+
packets are sent.
14+
15+
Details:
16+
- UDP encapsulation: bind with udp_sock_create() after zeroing peer_udp_port,
17+
then l2tp_udp_sk_set_peer() sets daddr/dport and socket "connected" state
18+
without caching sk_dst from connect.
19+
- IPv4 L2TP/IP (l2tp_ip): on -ENETUNREACH / -EHOSTUNREACH from
20+
__ip4_datagram_connect(), l2tp_ip_connect_deferred() installs peer and
21+
bind-table updates without a connect-time route.
22+
- IPv6 L2TP/IP (l2tp_ip6): same for __ip6_datagram_connect(), including
23+
IPv4-mapped peers and scope / bound-device checks aligned with the normal
24+
connect path.
25+
26+
Forwarding still only happens once the FIB can reach the peer. Until then
27+
outgoing packets follow the existing no-route drop path.
28+
29+
Assisted-by: Cursor:claude-4.8-opus
30+
Signed-off-by: Christian Breunig <christian@breunig.cc>
31+
32+
---
33+
diff --git i/net/l2tp/l2tp_core.c w/net/l2tp/l2tp_core.c
34+
index 9156a937334a..6fd9c1d89533 100644
35+
--- i/net/l2tp/l2tp_core.c
36+
+++ w/net/l2tp/l2tp_core.c
37+
@@ -55,6 +55,8 @@
38+
#include <net/inet_ecn.h>
39+
#include <net/ip6_route.h>
40+
#include <net/ip6_checksum.h>
41+
+#include <net/sock_reuseport.h>
42+
+#include <net/transp_v6.h>
43+
44+
#include <asm/byteorder.h>
45+
#include <linux/atomic.h>
46+
@@ -1453,6 +1455,67 @@ static void l2tp_tunnel_del_work(struct work_struct *work)
47+
* These sockets are freed when the namespace exits using the pernet
48+
* exit hook.
49+
*/
50+
+
51+
+static int l2tp_udp_sk_set_peer(struct socket *sock, struct udp_port_cfg *cfg)
52+
+{
53+
+ struct sock *sk = sock->sk;
54+
+ struct inet_sock *inet;
55+
+
56+
+ lock_sock(sk);
57+
+ inet = inet_sk(sk);
58+
+ sk_dst_reset(sk);
59+
+
60+
+#if IS_ENABLED(CONFIG_IPV6)
61+
+ if (cfg->family == AF_INET6) {
62+
+ struct ipv6_pinfo *np = inet6_sk(sk);
63+
+
64+
+ sk->sk_v6_daddr = cfg->peer_ip6;
65+
+ np->flow_label = 0;
66+
+ inet->inet_dport = cfg->peer_udp_port;
67+
+ } else
68+
+#endif
69+
+ {
70+
+ inet->inet_daddr = cfg->peer_ip.s_addr;
71+
+ inet->inet_dport = cfg->peer_udp_port;
72+
+ }
73+
+
74+
+ reuseport_has_conns_set(sk);
75+
+ sk->sk_state = TCP_ESTABLISHED;
76+
+ sk_set_txhash(sk);
77+
+ atomic_set(&inet->inet_id, get_random_u16());
78+
+ release_sock(sk);
79+
+ return 0;
80+
+}
81+
+
82+
+static int l2tp_tunnel_udp_sock_create(struct net *net, struct udp_port_cfg *cfg,
83+
+ struct socket **sockp)
84+
+{
85+
+ struct udp_port_cfg cfg_bind = *cfg;
86+
+ int err;
87+
+ struct socket *sock;
88+
+
89+
+ cfg_bind.peer_udp_port = 0;
90+
+
91+
+ err = udp_sock_create(net, &cfg_bind, &sock);
92+
+ if (err < 0)
93+
+ return err;
94+
+
95+
+ if (!cfg->peer_udp_port) {
96+
+ *sockp = sock;
97+
+ return 0;
98+
+ }
99+
+
100+
+ err = l2tp_udp_sk_set_peer(sock, cfg);
101+
+ if (err < 0) {
102+
+ kernel_sock_shutdown(sock, SHUT_RDWR);
103+
+ sock_release(sock);
104+
+ return err;
105+
+ }
106+
+
107+
+ *sockp = sock;
108+
+ return 0;
109+
+}
110+
+
111+
static int l2tp_tunnel_sock_create(struct net *net,
112+
u32 tunnel_id,
113+
u32 peer_tunnel_id,
114+
@@ -1490,7 +1553,7 @@ static int l2tp_tunnel_sock_create(struct net *net,
115+
udp_conf.local_udp_port = htons(cfg->local_udp_port);
116+
udp_conf.peer_udp_port = htons(cfg->peer_udp_port);
117+
118+
- err = udp_sock_create(net, &udp_conf, &sock);
119+
+ err = l2tp_tunnel_udp_sock_create(net, &udp_conf, &sock);
120+
if (err < 0)
121+
goto out;
122+
123+
diff --git i/net/l2tp/l2tp_ip.c w/net/l2tp/l2tp_ip.c
124+
index 29795d2839e8..d63b00f09421 100644
125+
--- i/net/l2tp/l2tp_ip.c
126+
+++ w/net/l2tp/l2tp_ip.c
127+
@@ -24,6 +24,7 @@
128+
#include <net/xfrm.h>
129+
#include <net/net_namespace.h>
130+
#include <net/netns/generic.h>
131+
+#include <net/sock_reuseport.h>
132+
133+
#include "l2tp_core.h"
134+
135+
@@ -328,6 +329,37 @@ static int l2tp_ip_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
136+
return ret;
137+
}
138+
139+
+/* Install peer address without capturing a route. Outgoing packets resolve
140+
+ * the path in __ip_queue_xmit(); this matches on-demand forwarding once the
141+
+ * FIB can reach the remote.
142+
+ */
143+
+static void __l2tp_ip4_sk_set_peer(struct sock *sk, __be32 daddr, __be16 dport)
144+
+{
145+
+ struct inet_sock *inet = inet_sk(sk);
146+
+
147+
+ sk_dst_reset(sk);
148+
+ inet->inet_daddr = daddr;
149+
+ inet->inet_dport = dport;
150+
+ reuseport_has_conns_set(sk);
151+
+ sk->sk_state = TCP_ESTABLISHED;
152+
+ sk_set_txhash(sk);
153+
+ atomic_set(&inet->inet_id, get_random_u16());
154+
+}
155+
+
156+
+static int l2tp_ip_connect_deferred(struct sock *sk, struct sockaddr_l2tpip *lsa)
157+
+{
158+
+ struct l2tp_ip_net *pn = l2tp_ip_pernet(sock_net(sk));
159+
+
160+
+ __l2tp_ip4_sk_set_peer(sk, lsa->l2tp_addr.s_addr, lsa->l2tp_unused);
161+
+ l2tp_ip_sk(sk)->peer_conn_id = lsa->l2tp_conn_id;
162+
+
163+
+ write_lock_bh(&pn->l2tp_ip_lock);
164+
+ hlist_del_init(&sk->sk_bind_node);
165+
+ sk_add_bind_node(sk, &pn->l2tp_ip_bind_table);
166+
+ write_unlock_bh(&pn->l2tp_ip_lock);
167+
+ return 0;
168+
+}
169+
+
170+
static int l2tp_ip_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
171+
{
172+
struct sockaddr_l2tpip *lsa = (struct sockaddr_l2tpip *)uaddr;
173+
@@ -349,6 +381,11 @@ static int l2tp_ip_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len
174+
}
175+
176+
rc = __ip4_datagram_connect(sk, uaddr, addr_len);
177+
+ if (rc == -ENETUNREACH || rc == -EHOSTUNREACH) {
178+
+ rc = l2tp_ip_connect_deferred(sk, lsa);
179+
+ goto out_sk;
180+
+ }
181+
+
182+
if (rc < 0)
183+
goto out_sk;
184+
185+
diff --git i/net/l2tp/l2tp_ip6.c w/net/l2tp/l2tp_ip6.c
186+
index ea232f338dcb..610e666c0a58 100644
187+
--- i/net/l2tp/l2tp_ip6.c
188+
+++ w/net/l2tp/l2tp_ip6.c
189+
@@ -28,6 +28,8 @@
190+
#include <net/transp_v6.h>
191+
#include <net/addrconf.h>
192+
#include <net/ip6_route.h>
193+
+#include <net/l3mdev.h>
194+
+#include <net/sock_reuseport.h>
195+
196+
#include "l2tp_core.h"
197+
198+
@@ -383,6 +385,116 @@ static int l2tp_ip6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
199+
return err;
200+
}
201+
202+
+static bool l2tp_ipv6_mapped_addr_any(const struct in6_addr *a)
203+
+{
204+
+ return ipv6_addr_v4mapped(a) && a->s6_addr32[3] == 0;
205+
+}
206+
+
207+
+/* Peer address without a cached dst; outbound path resolves the route. */
208+
+static void __l2tp_ip6_sk_set_peer(struct sock *sk, const struct in6_addr *daddr,
209+
+ __be16 dport, __be32 flowlabel)
210+
+{
211+
+ struct inet_sock *inet = inet_sk(sk);
212+
+ struct ipv6_pinfo *np = inet6_sk(sk);
213+
+
214+
+ sk_dst_reset(sk);
215+
+ sk->sk_v6_daddr = *daddr;
216+
+ np->flow_label = flowlabel;
217+
+ inet->inet_dport = dport;
218+
+ reuseport_has_conns_set(sk);
219+
+ sk->sk_state = TCP_ESTABLISHED;
220+
+ sk_set_txhash(sk);
221+
+}
222+
+
223+
+static int __l2tp_ip6_connect_deferred_mapped(struct sock *sk,
224+
+ struct sockaddr_l2tpip6 *lsa,
225+
+ struct sockaddr_in6 *usin)
226+
+{
227+
+ struct inet_sock *inet = inet_sk(sk);
228+
+ struct ipv6_pinfo *np = inet6_sk(sk);
229+
+ struct sockaddr_in sin;
230+
+ struct l2tp_ip6_net *pn;
231+
+ int err;
232+
+
233+
+ memset(&sin, 0, sizeof(sin));
234+
+ sin.sin_family = AF_INET;
235+
+ sin.sin_addr.s_addr = usin->sin6_addr.s6_addr32[3];
236+
+ sin.sin_port = usin->sin6_port;
237+
+
238+
+ err = __ip4_datagram_connect(sk, (struct sockaddr *)&sin, sizeof(sin));
239+
+ if (err == -ENETUNREACH || err == -EHOSTUNREACH) {
240+
+ sk_dst_reset(sk);
241+
+ inet->inet_daddr = sin.sin_addr.s_addr;
242+
+ inet->inet_dport = sin.sin_port;
243+
+ reuseport_has_conns_set(sk);
244+
+ sk->sk_state = TCP_ESTABLISHED;
245+
+ sk_set_txhash(sk);
246+
+ atomic_set(&inet->inet_id, get_random_u16());
247+
+ } else if (err) {
248+
+ return err;
249+
+ }
250+
+
251+
+ ipv6_addr_set_v4mapped(inet->inet_daddr, &sk->sk_v6_daddr);
252+
+ if (ipv6_addr_any(&np->saddr) || l2tp_ipv6_mapped_addr_any(&np->saddr))
253+
+ ipv6_addr_set_v4mapped(inet->inet_saddr, &np->saddr);
254+
+ if (ipv6_addr_any(&sk->sk_v6_rcv_saddr) ||
255+
+ l2tp_ipv6_mapped_addr_any(&sk->sk_v6_rcv_saddr)) {
256+
+ ipv6_addr_set_v4mapped(inet->inet_rcv_saddr, &sk->sk_v6_rcv_saddr);
257+
+ if (sk->sk_prot->rehash)
258+
+ sk->sk_prot->rehash(sk);
259+
+ }
260+
+
261+
+ l2tp_ip6_sk(sk)->peer_conn_id = lsa->l2tp_conn_id;
262+
+ pn = l2tp_ip6_pernet(sock_net(sk));
263+
+ write_lock_bh(&pn->l2tp_ip6_lock);
264+
+ hlist_del_init(&sk->sk_bind_node);
265+
+ sk_add_bind_node(sk, &pn->l2tp_ip6_bind_table);
266+
+ write_unlock_bh(&pn->l2tp_ip6_lock);
267+
+ return 0;
268+
+}
269+
+
270+
+static int l2tp_ip6_connect_deferred(struct sock *sk, struct sockaddr_l2tpip6 *lsa,
271+
+ struct sockaddr_in6 *usin,
272+
+ int addr_len)
273+
+{
274+
+ struct ipv6_pinfo *np = inet6_sk(sk);
275+
+ struct l2tp_ip6_net *pn;
276+
+ int addr_type = ipv6_addr_type(&usin->sin6_addr);
277+
+ const struct in6_addr *daddr = &usin->sin6_addr;
278+
+ __be32 fl6_flowlabel = 0;
279+
+
280+
+ if (addr_type & IPV6_ADDR_MAPPED)
281+
+ return __l2tp_ip6_connect_deferred_mapped(sk, lsa, usin);
282+
+
283+
+ if (inet6_test_bit(SNDFLOW, sk))
284+
+ fl6_flowlabel = usin->sin6_flowinfo & IPV6_FLOWINFO_MASK;
285+
+
286+
+ if (__ipv6_addr_needs_scope_id(addr_type)) {
287+
+ if (addr_len >= sizeof(struct sockaddr_in6) &&
288+
+ usin->sin6_scope_id) {
289+
+ if (!sk_dev_equal_l3scope(sk, usin->sin6_scope_id))
290+
+ return -EINVAL;
291+
+ WRITE_ONCE(sk->sk_bound_dev_if, usin->sin6_scope_id);
292+
+ }
293+
+
294+
+ if (!sk->sk_bound_dev_if && (addr_type & IPV6_ADDR_MULTICAST))
295+
+ WRITE_ONCE(sk->sk_bound_dev_if, READ_ONCE(np->mcast_oif));
296+
+
297+
+ if (!sk->sk_bound_dev_if)
298+
+ return -EINVAL;
299+
+ }
300+
+
301+
+ __l2tp_ip6_sk_set_peer(sk, daddr, usin->sin6_port, fl6_flowlabel);
302+
+ l2tp_ip6_sk(sk)->peer_conn_id = lsa->l2tp_conn_id;
303+
+
304+
+ pn = l2tp_ip6_pernet(sock_net(sk));
305+
+ write_lock_bh(&pn->l2tp_ip6_lock);
306+
+ hlist_del_init(&sk->sk_bind_node);
307+
+ sk_add_bind_node(sk, &pn->l2tp_ip6_bind_table);
308+
+ write_unlock_bh(&pn->l2tp_ip6_lock);
309+
+ return 0;
310+
+}
311+
+
312+
static int l2tp_ip6_connect(struct sock *sk, struct sockaddr *uaddr,
313+
int addr_len)
314+
{
315+
@@ -418,6 +530,11 @@ static int l2tp_ip6_connect(struct sock *sk, struct sockaddr *uaddr,
316+
}
317+
318+
rc = __ip6_datagram_connect(sk, uaddr, addr_len);
319+
+ if (rc == -ENETUNREACH || rc == -EHOSTUNREACH) {
320+
+ rc = l2tp_ip6_connect_deferred(sk, lsa, usin, addr_len);
321+
+ goto out_sk;
322+
+ }
323+
+
324+
if (rc < 0)
325+
goto out_sk;
326+

0 commit comments

Comments
 (0)