xref: /openbmc/linux/net/ipv6/xfrm6_input.c (revision 4a9771c0)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  * xfrm6_input.c: based on net/ipv4/xfrm4_input.c
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  * Authors:
61da177e4SLinus Torvalds  *	Mitsuru KANDA @USAGI
71da177e4SLinus Torvalds  *	Kazunori MIYAZAWA @USAGI
81da177e4SLinus Torvalds  *	Kunihiro Ishiguro <kunihiro@ipinfusion.com>
91da177e4SLinus Torvalds  *	YOSHIFUJI Hideaki @USAGI
101da177e4SLinus Torvalds  *		IPv6 support
111da177e4SLinus Torvalds  */
121da177e4SLinus Torvalds 
131da177e4SLinus Torvalds #include <linux/module.h>
141da177e4SLinus Torvalds #include <linux/string.h>
15b05e1066SPatrick McHardy #include <linux/netfilter.h>
16b05e1066SPatrick McHardy #include <linux/netfilter_ipv6.h>
171da177e4SLinus Torvalds #include <net/ipv6.h>
181da177e4SLinus Torvalds #include <net/xfrm.h>
191da177e4SLinus Torvalds 
xfrm6_rcv_spi(struct sk_buff * skb,int nexthdr,__be32 spi,struct ip6_tnl * t)2063c43787SNicolas Dichtel int xfrm6_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi,
2163c43787SNicolas Dichtel 		  struct ip6_tnl *t)
221da177e4SLinus Torvalds {
2363c43787SNicolas Dichtel 	XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6 = t;
242fcb45b6SHerbert Xu 	XFRM_SPI_SKB_CB(skb)->family = AF_INET6;
25716062fdSHerbert Xu 	XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct ipv6hdr, daddr);
26716062fdSHerbert Xu 	return xfrm_input(skb, nexthdr, spi, 0);
271da177e4SLinus Torvalds }
28716062fdSHerbert Xu EXPORT_SYMBOL(xfrm6_rcv_spi);
291da177e4SLinus Torvalds 
xfrm6_transport_finish2(struct net * net,struct sock * sk,struct sk_buff * skb)30acf568eeSHerbert Xu static int xfrm6_transport_finish2(struct net *net, struct sock *sk,
31acf568eeSHerbert Xu 				   struct sk_buff *skb)
32acf568eeSHerbert Xu {
330146dca7SSabrina Dubroca 	if (xfrm_trans_queue(skb, ip6_rcv_finish)) {
340146dca7SSabrina Dubroca 		kfree_skb(skb);
350146dca7SSabrina Dubroca 		return NET_RX_DROP;
360146dca7SSabrina Dubroca 	}
370146dca7SSabrina Dubroca 
380146dca7SSabrina Dubroca 	return 0;
39acf568eeSHerbert Xu }
40acf568eeSHerbert Xu 
xfrm6_transport_finish(struct sk_buff * skb,int async)41716062fdSHerbert Xu int xfrm6_transport_finish(struct sk_buff *skb, int async)
42716062fdSHerbert Xu {
437785bba2SSteffen Klassert 	struct xfrm_offload *xo = xfrm_offload(skb);
44e9cba694SYossi Kuperman 	int nhlen = skb->data - skb_network_header(skb);
457785bba2SSteffen Klassert 
4660d5fcfbSHerbert Xu 	skb_network_header(skb)[IP6CB(skb)->nhoff] =
4760d5fcfbSHerbert Xu 		XFRM_MODE_SKB_CB(skb)->protocol;
4860d5fcfbSHerbert Xu 
490883ae0eSHerbert Xu #ifndef CONFIG_NETFILTER
500883ae0eSHerbert Xu 	if (!async)
510883ae0eSHerbert Xu 		return 1;
520883ae0eSHerbert Xu #endif
530883ae0eSHerbert Xu 
54e9cba694SYossi Kuperman 	__skb_push(skb, nhlen);
557c88e21aSYossi Kuperman 	ipv6_hdr(skb)->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
56e9cba694SYossi Kuperman 	skb_postpush_rcsum(skb, skb_network_header(skb), nhlen);
57b05e1066SPatrick McHardy 
587785bba2SSteffen Klassert 	if (xo && (xo->flags & XFRM_GRO)) {
594a9771c0SPaul Davey 		/* The full l2 header needs to be preserved so that re-injecting the packet at l2
604a9771c0SPaul Davey 		 * works correctly in the presence of vlan tags.
614a9771c0SPaul Davey 		 */
624a9771c0SPaul Davey 		skb_mac_header_rebuild_full(skb, xo->orig_mac_len);
634a9771c0SPaul Davey 		skb_reset_network_header(skb);
64bfc0698bSSowmini Varadhan 		skb_reset_transport_header(skb);
650146dca7SSabrina Dubroca 		return 0;
667785bba2SSteffen Klassert 	}
677785bba2SSteffen Klassert 
6829a26a56SEric W. Biederman 	NF_HOOK(NFPROTO_IPV6, NF_INET_PRE_ROUTING,
6929a26a56SEric W. Biederman 		dev_net(skb->dev), NULL, skb, skb->dev, NULL,
70acf568eeSHerbert Xu 		xfrm6_transport_finish2);
710146dca7SSabrina Dubroca 	return 0;
720146dca7SSabrina Dubroca }
730146dca7SSabrina Dubroca 
740146dca7SSabrina Dubroca /* If it's a keepalive packet, then just eat it.
750146dca7SSabrina Dubroca  * If it's an encapsulated packet, then pass it to the
760146dca7SSabrina Dubroca  * IPsec xfrm input.
770146dca7SSabrina Dubroca  * Returns 0 if skb passed to xfrm or was dropped.
780146dca7SSabrina Dubroca  * Returns >0 if skb should be passed to UDP.
790146dca7SSabrina Dubroca  * Returns <0 if skb should be resubmitted (-ret is protocol)
800146dca7SSabrina Dubroca  */
xfrm6_udp_encap_rcv(struct sock * sk,struct sk_buff * skb)810146dca7SSabrina Dubroca int xfrm6_udp_encap_rcv(struct sock *sk, struct sk_buff *skb)
820146dca7SSabrina Dubroca {
830146dca7SSabrina Dubroca 	struct udp_sock *up = udp_sk(sk);
840146dca7SSabrina Dubroca 	struct udphdr *uh;
850146dca7SSabrina Dubroca 	struct ipv6hdr *ip6h;
860146dca7SSabrina Dubroca 	int len;
870146dca7SSabrina Dubroca 	int ip6hlen = sizeof(struct ipv6hdr);
880146dca7SSabrina Dubroca 	__u8 *udpdata;
890146dca7SSabrina Dubroca 	__be32 *udpdata32;
904781a75dSEric Dumazet 	u16 encap_type;
910146dca7SSabrina Dubroca 
921166a530SMaciej Żenczykowski 	if (skb->protocol == htons(ETH_P_IP))
931166a530SMaciej Żenczykowski 		return xfrm4_udp_encap_rcv(sk, skb);
941166a530SMaciej Żenczykowski 
954781a75dSEric Dumazet 	encap_type = READ_ONCE(up->encap_type);
960146dca7SSabrina Dubroca 	/* if this is not encapsulated socket, then just return now */
970146dca7SSabrina Dubroca 	if (!encap_type)
980146dca7SSabrina Dubroca 		return 1;
990146dca7SSabrina Dubroca 
1000146dca7SSabrina Dubroca 	/* If this is a paged skb, make sure we pull up
1010146dca7SSabrina Dubroca 	 * whatever data we need to look at. */
1020146dca7SSabrina Dubroca 	len = skb->len - sizeof(struct udphdr);
1030146dca7SSabrina Dubroca 	if (!pskb_may_pull(skb, sizeof(struct udphdr) + min(len, 8)))
1040146dca7SSabrina Dubroca 		return 1;
1050146dca7SSabrina Dubroca 
1060146dca7SSabrina Dubroca 	/* Now we can get the pointers */
1070146dca7SSabrina Dubroca 	uh = udp_hdr(skb);
1080146dca7SSabrina Dubroca 	udpdata = (__u8 *)uh + sizeof(struct udphdr);
1090146dca7SSabrina Dubroca 	udpdata32 = (__be32 *)udpdata;
1100146dca7SSabrina Dubroca 
1110146dca7SSabrina Dubroca 	switch (encap_type) {
1120146dca7SSabrina Dubroca 	default:
1130146dca7SSabrina Dubroca 	case UDP_ENCAP_ESPINUDP:
1140146dca7SSabrina Dubroca 		/* Check if this is a keepalive packet.  If so, eat it. */
1150146dca7SSabrina Dubroca 		if (len == 1 && udpdata[0] == 0xff) {
1160146dca7SSabrina Dubroca 			goto drop;
1170146dca7SSabrina Dubroca 		} else if (len > sizeof(struct ip_esp_hdr) && udpdata32[0] != 0) {
1180146dca7SSabrina Dubroca 			/* ESP Packet without Non-ESP header */
1190146dca7SSabrina Dubroca 			len = sizeof(struct udphdr);
1200146dca7SSabrina Dubroca 		} else
1210146dca7SSabrina Dubroca 			/* Must be an IKE packet.. pass it through */
1220146dca7SSabrina Dubroca 			return 1;
1230146dca7SSabrina Dubroca 		break;
1240146dca7SSabrina Dubroca 	case UDP_ENCAP_ESPINUDP_NON_IKE:
1250146dca7SSabrina Dubroca 		/* Check if this is a keepalive packet.  If so, eat it. */
1260146dca7SSabrina Dubroca 		if (len == 1 && udpdata[0] == 0xff) {
1270146dca7SSabrina Dubroca 			goto drop;
1280146dca7SSabrina Dubroca 		} else if (len > 2 * sizeof(u32) + sizeof(struct ip_esp_hdr) &&
1290146dca7SSabrina Dubroca 			   udpdata32[0] == 0 && udpdata32[1] == 0) {
1300146dca7SSabrina Dubroca 
1310146dca7SSabrina Dubroca 			/* ESP Packet with Non-IKE marker */
1320146dca7SSabrina Dubroca 			len = sizeof(struct udphdr) + 2 * sizeof(u32);
1330146dca7SSabrina Dubroca 		} else
1340146dca7SSabrina Dubroca 			/* Must be an IKE packet.. pass it through */
1350146dca7SSabrina Dubroca 			return 1;
1360146dca7SSabrina Dubroca 		break;
1370146dca7SSabrina Dubroca 	}
1380146dca7SSabrina Dubroca 
1390146dca7SSabrina Dubroca 	/* At this point we are sure that this is an ESPinUDP packet,
1400146dca7SSabrina Dubroca 	 * so we need to remove 'len' bytes from the packet (the UDP
1410146dca7SSabrina Dubroca 	 * header and optional ESP marker bytes) and then modify the
1420146dca7SSabrina Dubroca 	 * protocol to ESP, and then call into the transform receiver.
1430146dca7SSabrina Dubroca 	 */
1440146dca7SSabrina Dubroca 	if (skb_unclone(skb, GFP_ATOMIC))
1450146dca7SSabrina Dubroca 		goto drop;
1460146dca7SSabrina Dubroca 
1470146dca7SSabrina Dubroca 	/* Now we can update and verify the packet length... */
1480146dca7SSabrina Dubroca 	ip6h = ipv6_hdr(skb);
1490146dca7SSabrina Dubroca 	ip6h->payload_len = htons(ntohs(ip6h->payload_len) - len);
1500146dca7SSabrina Dubroca 	if (skb->len < ip6hlen + len) {
1510146dca7SSabrina Dubroca 		/* packet is too small!?! */
1520146dca7SSabrina Dubroca 		goto drop;
1530146dca7SSabrina Dubroca 	}
1540146dca7SSabrina Dubroca 
1550146dca7SSabrina Dubroca 	/* pull the data buffer up to the ESP header and set the
1560146dca7SSabrina Dubroca 	 * transport header to point to ESP.  Keep UDP on the stack
1570146dca7SSabrina Dubroca 	 * for later.
1580146dca7SSabrina Dubroca 	 */
1590146dca7SSabrina Dubroca 	__skb_pull(skb, len);
1600146dca7SSabrina Dubroca 	skb_reset_transport_header(skb);
1610146dca7SSabrina Dubroca 
1620146dca7SSabrina Dubroca 	/* process ESP */
1630146dca7SSabrina Dubroca 	return xfrm6_rcv_encap(skb, IPPROTO_ESP, 0, encap_type);
1640146dca7SSabrina Dubroca 
1650146dca7SSabrina Dubroca drop:
1660146dca7SSabrina Dubroca 	kfree_skb(skb);
1670146dca7SSabrina Dubroca 	return 0;
1681da177e4SLinus Torvalds }
1691da177e4SLinus Torvalds 
xfrm6_rcv_tnl(struct sk_buff * skb,struct ip6_tnl * t)17063c43787SNicolas Dichtel int xfrm6_rcv_tnl(struct sk_buff *skb, struct ip6_tnl *t)
1711da177e4SLinus Torvalds {
17233b5ecb8SHerbert Xu 	return xfrm6_rcv_spi(skb, skb_network_header(skb)[IP6CB(skb)->nhoff],
17363c43787SNicolas Dichtel 			     0, t);
17463c43787SNicolas Dichtel }
17563c43787SNicolas Dichtel EXPORT_SYMBOL(xfrm6_rcv_tnl);
17663c43787SNicolas Dichtel 
xfrm6_rcv(struct sk_buff * skb)17763c43787SNicolas Dichtel int xfrm6_rcv(struct sk_buff *skb)
17863c43787SNicolas Dichtel {
17963c43787SNicolas Dichtel 	return xfrm6_rcv_tnl(skb, NULL);
1801da177e4SLinus Torvalds }
1817159039aSYOSHIFUJI Hideaki EXPORT_SYMBOL(xfrm6_rcv);
xfrm6_input_addr(struct sk_buff * skb,xfrm_address_t * daddr,xfrm_address_t * saddr,u8 proto)182fbd9a5b4SMasahide NAKAMURA int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr,
183fbd9a5b4SMasahide NAKAMURA 		     xfrm_address_t *saddr, u8 proto)
184fbd9a5b4SMasahide NAKAMURA {
18559c9940eSAlexey Dobriyan 	struct net *net = dev_net(skb->dev);
186fbd9a5b4SMasahide NAKAMURA 	struct xfrm_state *x = NULL;
1870ca64da1SFlorian Westphal 	struct sec_path *sp;
188fbd9a5b4SMasahide NAKAMURA 	int i = 0;
189fbd9a5b4SMasahide NAKAMURA 
1900ca64da1SFlorian Westphal 	sp = secpath_set(skb);
1910ca64da1SFlorian Westphal 	if (!sp) {
19259c9940eSAlexey Dobriyan 		XFRM_INC_STATS(net, LINUX_MIB_XFRMINERROR);
1939473e1f6SMasahide NAKAMURA 		goto drop;
1949473e1f6SMasahide NAKAMURA 	}
1959473e1f6SMasahide NAKAMURA 
1960ca64da1SFlorian Westphal 	if (1 + sp->len == XFRM_MAX_DEPTH) {
19759c9940eSAlexey Dobriyan 		XFRM_INC_STATS(net, LINUX_MIB_XFRMINBUFFERERROR);
1989473e1f6SMasahide NAKAMURA 		goto drop;
1999473e1f6SMasahide NAKAMURA 	}
2009473e1f6SMasahide NAKAMURA 
201fbd9a5b4SMasahide NAKAMURA 	for (i = 0; i < 3; i++) {
202fbd9a5b4SMasahide NAKAMURA 		xfrm_address_t *dst, *src;
203a002c6fdSYOSHIFUJI Hideaki 
204fbd9a5b4SMasahide NAKAMURA 		switch (i) {
205fbd9a5b4SMasahide NAKAMURA 		case 0:
206fbd9a5b4SMasahide NAKAMURA 			dst = daddr;
207fbd9a5b4SMasahide NAKAMURA 			src = saddr;
208fbd9a5b4SMasahide NAKAMURA 			break;
209fbd9a5b4SMasahide NAKAMURA 		case 1:
210fbd9a5b4SMasahide NAKAMURA 			/* lookup state with wild-card source address */
211fbd9a5b4SMasahide NAKAMURA 			dst = daddr;
212a002c6fdSYOSHIFUJI Hideaki 			src = (xfrm_address_t *)&in6addr_any;
213fbd9a5b4SMasahide NAKAMURA 			break;
214fbd9a5b4SMasahide NAKAMURA 		default:
215fbd9a5b4SMasahide NAKAMURA 			/* lookup state with wild-card addresses */
216a002c6fdSYOSHIFUJI Hideaki 			dst = (xfrm_address_t *)&in6addr_any;
217a002c6fdSYOSHIFUJI Hideaki 			src = (xfrm_address_t *)&in6addr_any;
218fbd9a5b4SMasahide NAKAMURA 			break;
219fbd9a5b4SMasahide NAKAMURA 		}
220fbd9a5b4SMasahide NAKAMURA 
221bd55775cSJamal Hadi Salim 		x = xfrm_state_lookup_byaddr(net, skb->mark, dst, src, proto, AF_INET6);
222fbd9a5b4SMasahide NAKAMURA 		if (!x)
223fbd9a5b4SMasahide NAKAMURA 			continue;
224fbd9a5b4SMasahide NAKAMURA 
225fbd9a5b4SMasahide NAKAMURA 		spin_lock(&x->lock);
226fbd9a5b4SMasahide NAKAMURA 
227a002c6fdSYOSHIFUJI Hideaki 		if ((!i || (x->props.flags & XFRM_STATE_WILDRECV)) &&
228a002c6fdSYOSHIFUJI Hideaki 		    likely(x->km.state == XFRM_STATE_VALID) &&
229a002c6fdSYOSHIFUJI Hideaki 		    !xfrm_state_check_expire(x)) {
230fbd9a5b4SMasahide NAKAMURA 			spin_unlock(&x->lock);
231a002c6fdSYOSHIFUJI Hideaki 			if (x->type->input(x, skb) > 0) {
232a002c6fdSYOSHIFUJI Hideaki 				/* found a valid state */
2339473e1f6SMasahide NAKAMURA 				break;
2349473e1f6SMasahide NAKAMURA 			}
235a002c6fdSYOSHIFUJI Hideaki 		} else
236a002c6fdSYOSHIFUJI Hideaki 			spin_unlock(&x->lock);
237a002c6fdSYOSHIFUJI Hideaki 
238a002c6fdSYOSHIFUJI Hideaki 		xfrm_state_put(x);
239a002c6fdSYOSHIFUJI Hideaki 		x = NULL;
240a002c6fdSYOSHIFUJI Hideaki 	}
2419473e1f6SMasahide NAKAMURA 
2429473e1f6SMasahide NAKAMURA 	if (!x) {
24359c9940eSAlexey Dobriyan 		XFRM_INC_STATS(net, LINUX_MIB_XFRMINNOSTATES);
244afeb14b4SPaul Moore 		xfrm_audit_state_notfound_simple(skb, AF_INET6);
2459473e1f6SMasahide NAKAMURA 		goto drop;
2469473e1f6SMasahide NAKAMURA 	}
2479473e1f6SMasahide NAKAMURA 
2482294be0fSFlorian Westphal 	sp->xvec[sp->len++] = x;
2499473e1f6SMasahide NAKAMURA 
2509473e1f6SMasahide NAKAMURA 	spin_lock(&x->lock);
2519473e1f6SMasahide NAKAMURA 
252fbd9a5b4SMasahide NAKAMURA 	x->curlft.bytes += skb->len;
253fbd9a5b4SMasahide NAKAMURA 	x->curlft.packets++;
254fbd9a5b4SMasahide NAKAMURA 
255fbd9a5b4SMasahide NAKAMURA 	spin_unlock(&x->lock);
256fbd9a5b4SMasahide NAKAMURA 
257fbd9a5b4SMasahide NAKAMURA 	return 1;
2589473e1f6SMasahide NAKAMURA 
259fbd9a5b4SMasahide NAKAMURA drop:
260fbd9a5b4SMasahide NAKAMURA 	return -1;
261fbd9a5b4SMasahide NAKAMURA }
2627159039aSYOSHIFUJI Hideaki EXPORT_SYMBOL(xfrm6_input_addr);
263