Skip to content

Commit e27cca9

Browse files
qsnklassert
authored andcommitted
xfrm: add espintcp (RFC 8229)
TCP encapsulation of IKE and IPsec messages (RFC 8229) is implemented as a TCP ULP, overriding in particular the sendmsg and recvmsg operations. A Stream Parser is used to extract messages out of the TCP stream using the first 2 bytes as length marker. Received IKE messages are put on "ike_queue", waiting to be dequeued by the custom recvmsg implementation. Received ESP messages are sent to XFRM, like with UDP encapsulation. Some of this code is taken from the original submission by Herbert Xu. Currently, only IPv4 is supported, like for UDP encapsulation. Co-developed-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: Sabrina Dubroca <sd@queasysnail.net> Acked-by: David S. Miller <davem@davemloft.net> Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
1 parent eecd227 commit e27cca9

File tree

9 files changed

+760
-3
lines changed

9 files changed

+760
-3
lines changed

include/net/espintcp.h

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
#ifndef _NET_ESPINTCP_H
3+
#define _NET_ESPINTCP_H
4+
5+
#include <net/strparser.h>
6+
#include <linux/skmsg.h>
7+
8+
void __init espintcp_init(void);
9+
10+
int espintcp_push_skb(struct sock *sk, struct sk_buff *skb);
11+
int espintcp_queue_out(struct sock *sk, struct sk_buff *skb);
12+
bool tcp_is_ulp_esp(struct sock *sk);
13+
14+
struct espintcp_msg {
15+
struct sk_buff *skb;
16+
struct sk_msg skmsg;
17+
int offset;
18+
int len;
19+
};
20+
21+
struct espintcp_ctx {
22+
struct strparser strp;
23+
struct sk_buff_head ike_queue;
24+
struct sk_buff_head out_queue;
25+
struct espintcp_msg partial;
26+
void (*saved_data_ready)(struct sock *sk);
27+
void (*saved_write_space)(struct sock *sk);
28+
struct work_struct work;
29+
bool tx_running;
30+
};
31+
32+
static inline struct espintcp_ctx *espintcp_getctx(const struct sock *sk)
33+
{
34+
struct inet_connection_sock *icsk = inet_csk(sk);
35+
36+
/* RCU is only needed for diag */
37+
return (__force void *)icsk->icsk_ulp_data;
38+
}
39+
#endif

include/net/xfrm.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@ struct xfrm_state {
193193

194194
/* Data for encapsulator */
195195
struct xfrm_encap_tmpl *encap;
196+
struct sock __rcu *encap_sk;
196197

197198
/* Data for care-of address */
198199
xfrm_address_t *coaddr;

include/uapi/linux/udp.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,5 +42,6 @@ struct udphdr {
4242
#define UDP_ENCAP_GTP0 4 /* GSM TS 09.60 */
4343
#define UDP_ENCAP_GTP1U 5 /* 3GPP TS 29.060 */
4444
#define UDP_ENCAP_RXRPC 6
45+
#define TCP_ENCAP_ESPINTCP 7 /* Yikes, this is really xfrm encap types. */
4546

4647
#endif /* _UAPI_LINUX_UDP_H */

net/ipv4/Kconfig

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,17 @@ config INET_ESP_OFFLOAD
378378

379379
If unsure, say N.
380380

381+
config INET_ESPINTCP
382+
bool "IP: ESP in TCP encapsulation (RFC 8229)"
383+
depends on XFRM && INET_ESP
384+
select STREAM_PARSER
385+
select NET_SOCK_MSG
386+
help
387+
Support for RFC 8229 encapsulation of ESP and IKE over
388+
TCP/IPv4 sockets.
389+
390+
If unsure, say N.
391+
381392
config INET_IPCOMP
382393
tristate "IP: IPComp transformation"
383394
select INET_XFRM_TUNNEL

net/ipv4/esp4.c

Lines changed: 188 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
#include <net/icmp.h>
1919
#include <net/protocol.h>
2020
#include <net/udp.h>
21+
#include <net/tcp.h>
22+
#include <net/espintcp.h>
2123

2224
#include <linux/highmem.h>
2325

@@ -117,6 +119,132 @@ static void esp_ssg_unref(struct xfrm_state *x, void *tmp)
117119
put_page(sg_page(sg));
118120
}
119121

122+
#ifdef CONFIG_INET_ESPINTCP
123+
struct esp_tcp_sk {
124+
struct sock *sk;
125+
struct rcu_head rcu;
126+
};
127+
128+
static void esp_free_tcp_sk(struct rcu_head *head)
129+
{
130+
struct esp_tcp_sk *esk = container_of(head, struct esp_tcp_sk, rcu);
131+
132+
sock_put(esk->sk);
133+
kfree(esk);
134+
}
135+
136+
static struct sock *esp_find_tcp_sk(struct xfrm_state *x)
137+
{
138+
struct xfrm_encap_tmpl *encap = x->encap;
139+
struct esp_tcp_sk *esk;
140+
__be16 sport, dport;
141+
struct sock *nsk;
142+
struct sock *sk;
143+
144+
sk = rcu_dereference(x->encap_sk);
145+
if (sk && sk->sk_state == TCP_ESTABLISHED)
146+
return sk;
147+
148+
spin_lock_bh(&x->lock);
149+
sport = encap->encap_sport;
150+
dport = encap->encap_dport;
151+
nsk = rcu_dereference_protected(x->encap_sk,
152+
lockdep_is_held(&x->lock));
153+
if (sk && sk == nsk) {
154+
esk = kmalloc(sizeof(*esk), GFP_ATOMIC);
155+
if (!esk) {
156+
spin_unlock_bh(&x->lock);
157+
return ERR_PTR(-ENOMEM);
158+
}
159+
RCU_INIT_POINTER(x->encap_sk, NULL);
160+
esk->sk = sk;
161+
call_rcu(&esk->rcu, esp_free_tcp_sk);
162+
}
163+
spin_unlock_bh(&x->lock);
164+
165+
sk = inet_lookup_established(xs_net(x), &tcp_hashinfo, x->id.daddr.a4,
166+
dport, x->props.saddr.a4, sport, 0);
167+
if (!sk)
168+
return ERR_PTR(-ENOENT);
169+
170+
if (!tcp_is_ulp_esp(sk)) {
171+
sock_put(sk);
172+
return ERR_PTR(-EINVAL);
173+
}
174+
175+
spin_lock_bh(&x->lock);
176+
nsk = rcu_dereference_protected(x->encap_sk,
177+
lockdep_is_held(&x->lock));
178+
if (encap->encap_sport != sport ||
179+
encap->encap_dport != dport) {
180+
sock_put(sk);
181+
sk = nsk ?: ERR_PTR(-EREMCHG);
182+
} else if (sk == nsk) {
183+
sock_put(sk);
184+
} else {
185+
rcu_assign_pointer(x->encap_sk, sk);
186+
}
187+
spin_unlock_bh(&x->lock);
188+
189+
return sk;
190+
}
191+
192+
static int esp_output_tcp_finish(struct xfrm_state *x, struct sk_buff *skb)
193+
{
194+
struct sock *sk;
195+
int err;
196+
197+
rcu_read_lock();
198+
199+
sk = esp_find_tcp_sk(x);
200+
err = PTR_ERR_OR_ZERO(sk);
201+
if (err)
202+
goto out;
203+
204+
bh_lock_sock(sk);
205+
if (sock_owned_by_user(sk))
206+
err = espintcp_queue_out(sk, skb);
207+
else
208+
err = espintcp_push_skb(sk, skb);
209+
bh_unlock_sock(sk);
210+
211+
out:
212+
rcu_read_unlock();
213+
return err;
214+
}
215+
216+
static int esp_output_tcp_encap_cb(struct net *net, struct sock *sk,
217+
struct sk_buff *skb)
218+
{
219+
struct dst_entry *dst = skb_dst(skb);
220+
struct xfrm_state *x = dst->xfrm;
221+
222+
return esp_output_tcp_finish(x, skb);
223+
}
224+
225+
static int esp_output_tail_tcp(struct xfrm_state *x, struct sk_buff *skb)
226+
{
227+
int err;
228+
229+
local_bh_disable();
230+
err = xfrm_trans_queue_net(xs_net(x), skb, esp_output_tcp_encap_cb);
231+
local_bh_enable();
232+
233+
/* EINPROGRESS just happens to do the right thing. It
234+
* actually means that the skb has been consumed and
235+
* isn't coming back.
236+
*/
237+
return err ?: -EINPROGRESS;
238+
}
239+
#else
240+
static int esp_output_tail_tcp(struct xfrm_state *x, struct sk_buff *skb)
241+
{
242+
kfree_skb(skb);
243+
244+
return -EOPNOTSUPP;
245+
}
246+
#endif
247+
120248
static void esp_output_done(struct crypto_async_request *base, int err)
121249
{
122250
struct sk_buff *skb = base->data;
@@ -147,7 +275,11 @@ static void esp_output_done(struct crypto_async_request *base, int err)
147275
secpath_reset(skb);
148276
xfrm_dev_resume(skb);
149277
} else {
150-
xfrm_output_resume(skb, err);
278+
if (!err &&
279+
x->encap && x->encap->encap_type == TCP_ENCAP_ESPINTCP)
280+
esp_output_tail_tcp(x, skb);
281+
else
282+
xfrm_output_resume(skb, err);
151283
}
152284
}
153285

@@ -236,7 +368,7 @@ static struct ip_esp_hdr *esp_output_udp_encap(struct sk_buff *skb,
236368
unsigned int len;
237369

238370
len = skb->len + esp->tailen - skb_transport_offset(skb);
239-
if (len + sizeof(struct iphdr) >= IP_MAX_MTU)
371+
if (len + sizeof(struct iphdr) > IP_MAX_MTU)
240372
return ERR_PTR(-EMSGSIZE);
241373

242374
uh = (struct udphdr *)esp->esph;
@@ -256,6 +388,41 @@ static struct ip_esp_hdr *esp_output_udp_encap(struct sk_buff *skb,
256388
return (struct ip_esp_hdr *)(uh + 1);
257389
}
258390

391+
#ifdef CONFIG_INET_ESPINTCP
392+
static struct ip_esp_hdr *esp_output_tcp_encap(struct xfrm_state *x,
393+
struct sk_buff *skb,
394+
struct esp_info *esp)
395+
{
396+
__be16 *lenp = (void *)esp->esph;
397+
struct ip_esp_hdr *esph;
398+
unsigned int len;
399+
struct sock *sk;
400+
401+
len = skb->len + esp->tailen - skb_transport_offset(skb);
402+
if (len > IP_MAX_MTU)
403+
return ERR_PTR(-EMSGSIZE);
404+
405+
rcu_read_lock();
406+
sk = esp_find_tcp_sk(x);
407+
rcu_read_unlock();
408+
409+
if (IS_ERR(sk))
410+
return ERR_CAST(sk);
411+
412+
*lenp = htons(len);
413+
esph = (struct ip_esp_hdr *)(lenp + 1);
414+
415+
return esph;
416+
}
417+
#else
418+
static struct ip_esp_hdr *esp_output_tcp_encap(struct xfrm_state *x,
419+
struct sk_buff *skb,
420+
struct esp_info *esp)
421+
{
422+
return ERR_PTR(-EOPNOTSUPP);
423+
}
424+
#endif
425+
259426
static int esp_output_encap(struct xfrm_state *x, struct sk_buff *skb,
260427
struct esp_info *esp)
261428
{
@@ -276,6 +443,9 @@ static int esp_output_encap(struct xfrm_state *x, struct sk_buff *skb,
276443
case UDP_ENCAP_ESPINUDP_NON_IKE:
277444
esph = esp_output_udp_encap(skb, encap_type, esp, sport, dport);
278445
break;
446+
case TCP_ENCAP_ESPINTCP:
447+
esph = esp_output_tcp_encap(x, skb, esp);
448+
break;
279449
}
280450

281451
if (IS_ERR(esph))
@@ -296,7 +466,7 @@ int esp_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info *
296466
struct sk_buff *trailer;
297467
int tailen = esp->tailen;
298468

299-
/* this is non-NULL only with UDP Encapsulation */
469+
/* this is non-NULL only with TCP/UDP Encapsulation */
300470
if (x->encap) {
301471
int err = esp_output_encap(x, skb, esp);
302472

@@ -491,6 +661,9 @@ int esp_output_tail(struct xfrm_state *x, struct sk_buff *skb, struct esp_info *
491661
if (sg != dsg)
492662
esp_ssg_unref(x, tmp);
493663

664+
if (!err && x->encap && x->encap->encap_type == TCP_ENCAP_ESPINTCP)
665+
err = esp_output_tail_tcp(x, skb);
666+
494667
error_free:
495668
kfree(tmp);
496669
error:
@@ -617,10 +790,14 @@ int esp_input_done2(struct sk_buff *skb, int err)
617790

618791
if (x->encap) {
619792
struct xfrm_encap_tmpl *encap = x->encap;
793+
struct tcphdr *th = (void *)(skb_network_header(skb) + ihl);
620794
struct udphdr *uh = (void *)(skb_network_header(skb) + ihl);
621795
__be16 source;
622796

623797
switch (x->encap->encap_type) {
798+
case TCP_ENCAP_ESPINTCP:
799+
source = th->source;
800+
break;
624801
case UDP_ENCAP_ESPINUDP:
625802
case UDP_ENCAP_ESPINUDP_NON_IKE:
626803
source = uh->source;
@@ -1017,6 +1194,14 @@ static int esp_init_state(struct xfrm_state *x)
10171194
case UDP_ENCAP_ESPINUDP_NON_IKE:
10181195
x->props.header_len += sizeof(struct udphdr) + 2 * sizeof(u32);
10191196
break;
1197+
#ifdef CONFIG_INET_ESPINTCP
1198+
case TCP_ENCAP_ESPINTCP:
1199+
/* only the length field, TCP encap is done by
1200+
* the socket
1201+
*/
1202+
x->props.header_len += 2;
1203+
break;
1204+
#endif
10201205
}
10211206
}
10221207

net/xfrm/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@ obj-$(CONFIG_XFRM_ALGO) += xfrm_algo.o
1111
obj-$(CONFIG_XFRM_USER) += xfrm_user.o
1212
obj-$(CONFIG_XFRM_IPCOMP) += xfrm_ipcomp.o
1313
obj-$(CONFIG_XFRM_INTERFACE) += xfrm_interface.o
14+
obj-$(CONFIG_INET_ESPINTCP) += espintcp.o

0 commit comments

Comments
 (0)