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