linux/net/ipv6/xfrm6_input.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * xfrm6_input.c: based on net/ipv4/xfrm4_input.c
   4 *
   5 * Authors:
   6 *      Mitsuru KANDA @USAGI
   7 *      Kazunori MIYAZAWA @USAGI
   8 *      Kunihiro Ishiguro <kunihiro@ipinfusion.com>
   9 *      YOSHIFUJI Hideaki @USAGI
  10 *              IPv6 support
  11 */
  12
  13#include <linux/module.h>
  14#include <linux/string.h>
  15#include <linux/netfilter.h>
  16#include <linux/netfilter_ipv6.h>
  17#include <net/ipv6.h>
  18#include <net/xfrm.h>
  19
  20int xfrm6_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi,
  21                  struct ip6_tnl *t)
  22{
  23        XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6 = t;
  24        XFRM_SPI_SKB_CB(skb)->family = AF_INET6;
  25        XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct ipv6hdr, daddr);
  26        return xfrm_input(skb, nexthdr, spi, 0);
  27}
  28EXPORT_SYMBOL(xfrm6_rcv_spi);
  29
  30static int xfrm6_transport_finish2(struct net *net, struct sock *sk,
  31                                   struct sk_buff *skb)
  32{
  33        if (xfrm_trans_queue(skb, ip6_rcv_finish)) {
  34                kfree_skb(skb);
  35                return NET_RX_DROP;
  36        }
  37
  38        return 0;
  39}
  40
  41int xfrm6_transport_finish(struct sk_buff *skb, int async)
  42{
  43        struct xfrm_offload *xo = xfrm_offload(skb);
  44        int nhlen = skb->data - skb_network_header(skb);
  45
  46        skb_network_header(skb)[IP6CB(skb)->nhoff] =
  47                XFRM_MODE_SKB_CB(skb)->protocol;
  48
  49#ifndef CONFIG_NETFILTER
  50        if (!async)
  51                return 1;
  52#endif
  53
  54        __skb_push(skb, nhlen);
  55        ipv6_hdr(skb)->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
  56        skb_postpush_rcsum(skb, skb_network_header(skb), nhlen);
  57
  58        if (xo && (xo->flags & XFRM_GRO)) {
  59                skb_mac_header_rebuild(skb);
  60                skb_reset_transport_header(skb);
  61                return 0;
  62        }
  63
  64        NF_HOOK(NFPROTO_IPV6, NF_INET_PRE_ROUTING,
  65                dev_net(skb->dev), NULL, skb, skb->dev, NULL,
  66                xfrm6_transport_finish2);
  67        return 0;
  68}
  69
  70/* If it's a keepalive packet, then just eat it.
  71 * If it's an encapsulated packet, then pass it to the
  72 * IPsec xfrm input.
  73 * Returns 0 if skb passed to xfrm or was dropped.
  74 * Returns >0 if skb should be passed to UDP.
  75 * Returns <0 if skb should be resubmitted (-ret is protocol)
  76 */
  77int xfrm6_udp_encap_rcv(struct sock *sk, struct sk_buff *skb)
  78{
  79        struct udp_sock *up = udp_sk(sk);
  80        struct udphdr *uh;
  81        struct ipv6hdr *ip6h;
  82        int len;
  83        int ip6hlen = sizeof(struct ipv6hdr);
  84
  85        __u8 *udpdata;
  86        __be32 *udpdata32;
  87        __u16 encap_type = up->encap_type;
  88
  89        /* if this is not encapsulated socket, then just return now */
  90        if (!encap_type)
  91                return 1;
  92
  93        /* If this is a paged skb, make sure we pull up
  94         * whatever data we need to look at. */
  95        len = skb->len - sizeof(struct udphdr);
  96        if (!pskb_may_pull(skb, sizeof(struct udphdr) + min(len, 8)))
  97                return 1;
  98
  99        /* Now we can get the pointers */
 100        uh = udp_hdr(skb);
 101        udpdata = (__u8 *)uh + sizeof(struct udphdr);
 102        udpdata32 = (__be32 *)udpdata;
 103
 104        switch (encap_type) {
 105        default:
 106        case UDP_ENCAP_ESPINUDP:
 107                /* Check if this is a keepalive packet.  If so, eat it. */
 108                if (len == 1 && udpdata[0] == 0xff) {
 109                        goto drop;
 110                } else if (len > sizeof(struct ip_esp_hdr) && udpdata32[0] != 0) {
 111                        /* ESP Packet without Non-ESP header */
 112                        len = sizeof(struct udphdr);
 113                } else
 114                        /* Must be an IKE packet.. pass it through */
 115                        return 1;
 116                break;
 117        case UDP_ENCAP_ESPINUDP_NON_IKE:
 118                /* Check if this is a keepalive packet.  If so, eat it. */
 119                if (len == 1 && udpdata[0] == 0xff) {
 120                        goto drop;
 121                } else if (len > 2 * sizeof(u32) + sizeof(struct ip_esp_hdr) &&
 122                           udpdata32[0] == 0 && udpdata32[1] == 0) {
 123
 124                        /* ESP Packet with Non-IKE marker */
 125                        len = sizeof(struct udphdr) + 2 * sizeof(u32);
 126                } else
 127                        /* Must be an IKE packet.. pass it through */
 128                        return 1;
 129                break;
 130        }
 131
 132        /* At this point we are sure that this is an ESPinUDP packet,
 133         * so we need to remove 'len' bytes from the packet (the UDP
 134         * header and optional ESP marker bytes) and then modify the
 135         * protocol to ESP, and then call into the transform receiver.
 136         */
 137        if (skb_unclone(skb, GFP_ATOMIC))
 138                goto drop;
 139
 140        /* Now we can update and verify the packet length... */
 141        ip6h = ipv6_hdr(skb);
 142        ip6h->payload_len = htons(ntohs(ip6h->payload_len) - len);
 143        if (skb->len < ip6hlen + len) {
 144                /* packet is too small!?! */
 145                goto drop;
 146        }
 147
 148        /* pull the data buffer up to the ESP header and set the
 149         * transport header to point to ESP.  Keep UDP on the stack
 150         * for later.
 151         */
 152        __skb_pull(skb, len);
 153        skb_reset_transport_header(skb);
 154
 155        /* process ESP */
 156        return xfrm6_rcv_encap(skb, IPPROTO_ESP, 0, encap_type);
 157
 158drop:
 159        kfree_skb(skb);
 160        return 0;
 161}
 162
 163int xfrm6_rcv_tnl(struct sk_buff *skb, struct ip6_tnl *t)
 164{
 165        return xfrm6_rcv_spi(skb, skb_network_header(skb)[IP6CB(skb)->nhoff],
 166                             0, t);
 167}
 168EXPORT_SYMBOL(xfrm6_rcv_tnl);
 169
 170int xfrm6_rcv(struct sk_buff *skb)
 171{
 172        return xfrm6_rcv_tnl(skb, NULL);
 173}
 174EXPORT_SYMBOL(xfrm6_rcv);
 175int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr,
 176                     xfrm_address_t *saddr, u8 proto)
 177{
 178        struct net *net = dev_net(skb->dev);
 179        struct xfrm_state *x = NULL;
 180        struct sec_path *sp;
 181        int i = 0;
 182
 183        sp = secpath_set(skb);
 184        if (!sp) {
 185                XFRM_INC_STATS(net, LINUX_MIB_XFRMINERROR);
 186                goto drop;
 187        }
 188
 189        if (1 + sp->len == XFRM_MAX_DEPTH) {
 190                XFRM_INC_STATS(net, LINUX_MIB_XFRMINBUFFERERROR);
 191                goto drop;
 192        }
 193
 194        for (i = 0; i < 3; i++) {
 195                xfrm_address_t *dst, *src;
 196
 197                switch (i) {
 198                case 0:
 199                        dst = daddr;
 200                        src = saddr;
 201                        break;
 202                case 1:
 203                        /* lookup state with wild-card source address */
 204                        dst = daddr;
 205                        src = (xfrm_address_t *)&in6addr_any;
 206                        break;
 207                default:
 208                        /* lookup state with wild-card addresses */
 209                        dst = (xfrm_address_t *)&in6addr_any;
 210                        src = (xfrm_address_t *)&in6addr_any;
 211                        break;
 212                }
 213
 214                x = xfrm_state_lookup_byaddr(net, skb->mark, dst, src, proto, AF_INET6);
 215                if (!x)
 216                        continue;
 217
 218                spin_lock(&x->lock);
 219
 220                if ((!i || (x->props.flags & XFRM_STATE_WILDRECV)) &&
 221                    likely(x->km.state == XFRM_STATE_VALID) &&
 222                    !xfrm_state_check_expire(x)) {
 223                        spin_unlock(&x->lock);
 224                        if (x->type->input(x, skb) > 0) {
 225                                /* found a valid state */
 226                                break;
 227                        }
 228                } else
 229                        spin_unlock(&x->lock);
 230
 231                xfrm_state_put(x);
 232                x = NULL;
 233        }
 234
 235        if (!x) {
 236                XFRM_INC_STATS(net, LINUX_MIB_XFRMINNOSTATES);
 237                xfrm_audit_state_notfound_simple(skb, AF_INET6);
 238                goto drop;
 239        }
 240
 241        sp->xvec[sp->len++] = x;
 242
 243        spin_lock(&x->lock);
 244
 245        x->curlft.bytes += skb->len;
 246        x->curlft.packets++;
 247
 248        spin_unlock(&x->lock);
 249
 250        return 1;
 251
 252drop:
 253        return -1;
 254}
 255EXPORT_SYMBOL(xfrm6_input_addr);
 256