Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * xfrm6_input.c: based on net/ipv4/xfrm4_input.c
0004  *
0005  * Authors:
0006  *  Mitsuru KANDA @USAGI
0007  *  Kazunori MIYAZAWA @USAGI
0008  *  Kunihiro Ishiguro <kunihiro@ipinfusion.com>
0009  *  YOSHIFUJI Hideaki @USAGI
0010  *      IPv6 support
0011  */
0012 
0013 #include <linux/module.h>
0014 #include <linux/string.h>
0015 #include <linux/netfilter.h>
0016 #include <linux/netfilter_ipv6.h>
0017 #include <net/ipv6.h>
0018 #include <net/xfrm.h>
0019 
0020 int xfrm6_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi,
0021           struct ip6_tnl *t)
0022 {
0023     XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6 = t;
0024     XFRM_SPI_SKB_CB(skb)->family = AF_INET6;
0025     XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct ipv6hdr, daddr);
0026     return xfrm_input(skb, nexthdr, spi, 0);
0027 }
0028 EXPORT_SYMBOL(xfrm6_rcv_spi);
0029 
0030 static int xfrm6_transport_finish2(struct net *net, struct sock *sk,
0031                    struct sk_buff *skb)
0032 {
0033     if (xfrm_trans_queue(skb, ip6_rcv_finish)) {
0034         kfree_skb(skb);
0035         return NET_RX_DROP;
0036     }
0037 
0038     return 0;
0039 }
0040 
0041 int xfrm6_transport_finish(struct sk_buff *skb, int async)
0042 {
0043     struct xfrm_offload *xo = xfrm_offload(skb);
0044     int nhlen = skb->data - skb_network_header(skb);
0045 
0046     skb_network_header(skb)[IP6CB(skb)->nhoff] =
0047         XFRM_MODE_SKB_CB(skb)->protocol;
0048 
0049 #ifndef CONFIG_NETFILTER
0050     if (!async)
0051         return 1;
0052 #endif
0053 
0054     __skb_push(skb, nhlen);
0055     ipv6_hdr(skb)->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
0056     skb_postpush_rcsum(skb, skb_network_header(skb), nhlen);
0057 
0058     if (xo && (xo->flags & XFRM_GRO)) {
0059         skb_mac_header_rebuild(skb);
0060         skb_reset_transport_header(skb);
0061         return 0;
0062     }
0063 
0064     NF_HOOK(NFPROTO_IPV6, NF_INET_PRE_ROUTING,
0065         dev_net(skb->dev), NULL, skb, skb->dev, NULL,
0066         xfrm6_transport_finish2);
0067     return 0;
0068 }
0069 
0070 /* If it's a keepalive packet, then just eat it.
0071  * If it's an encapsulated packet, then pass it to the
0072  * IPsec xfrm input.
0073  * Returns 0 if skb passed to xfrm or was dropped.
0074  * Returns >0 if skb should be passed to UDP.
0075  * Returns <0 if skb should be resubmitted (-ret is protocol)
0076  */
0077 int xfrm6_udp_encap_rcv(struct sock *sk, struct sk_buff *skb)
0078 {
0079     struct udp_sock *up = udp_sk(sk);
0080     struct udphdr *uh;
0081     struct ipv6hdr *ip6h;
0082     int len;
0083     int ip6hlen = sizeof(struct ipv6hdr);
0084 
0085     __u8 *udpdata;
0086     __be32 *udpdata32;
0087     __u16 encap_type = up->encap_type;
0088 
0089     /* if this is not encapsulated socket, then just return now */
0090     if (!encap_type)
0091         return 1;
0092 
0093     /* If this is a paged skb, make sure we pull up
0094      * whatever data we need to look at. */
0095     len = skb->len - sizeof(struct udphdr);
0096     if (!pskb_may_pull(skb, sizeof(struct udphdr) + min(len, 8)))
0097         return 1;
0098 
0099     /* Now we can get the pointers */
0100     uh = udp_hdr(skb);
0101     udpdata = (__u8 *)uh + sizeof(struct udphdr);
0102     udpdata32 = (__be32 *)udpdata;
0103 
0104     switch (encap_type) {
0105     default:
0106     case UDP_ENCAP_ESPINUDP:
0107         /* Check if this is a keepalive packet.  If so, eat it. */
0108         if (len == 1 && udpdata[0] == 0xff) {
0109             goto drop;
0110         } else if (len > sizeof(struct ip_esp_hdr) && udpdata32[0] != 0) {
0111             /* ESP Packet without Non-ESP header */
0112             len = sizeof(struct udphdr);
0113         } else
0114             /* Must be an IKE packet.. pass it through */
0115             return 1;
0116         break;
0117     case UDP_ENCAP_ESPINUDP_NON_IKE:
0118         /* Check if this is a keepalive packet.  If so, eat it. */
0119         if (len == 1 && udpdata[0] == 0xff) {
0120             goto drop;
0121         } else if (len > 2 * sizeof(u32) + sizeof(struct ip_esp_hdr) &&
0122                udpdata32[0] == 0 && udpdata32[1] == 0) {
0123 
0124             /* ESP Packet with Non-IKE marker */
0125             len = sizeof(struct udphdr) + 2 * sizeof(u32);
0126         } else
0127             /* Must be an IKE packet.. pass it through */
0128             return 1;
0129         break;
0130     }
0131 
0132     /* At this point we are sure that this is an ESPinUDP packet,
0133      * so we need to remove 'len' bytes from the packet (the UDP
0134      * header and optional ESP marker bytes) and then modify the
0135      * protocol to ESP, and then call into the transform receiver.
0136      */
0137     if (skb_unclone(skb, GFP_ATOMIC))
0138         goto drop;
0139 
0140     /* Now we can update and verify the packet length... */
0141     ip6h = ipv6_hdr(skb);
0142     ip6h->payload_len = htons(ntohs(ip6h->payload_len) - len);
0143     if (skb->len < ip6hlen + len) {
0144         /* packet is too small!?! */
0145         goto drop;
0146     }
0147 
0148     /* pull the data buffer up to the ESP header and set the
0149      * transport header to point to ESP.  Keep UDP on the stack
0150      * for later.
0151      */
0152     __skb_pull(skb, len);
0153     skb_reset_transport_header(skb);
0154 
0155     /* process ESP */
0156     return xfrm6_rcv_encap(skb, IPPROTO_ESP, 0, encap_type);
0157 
0158 drop:
0159     kfree_skb(skb);
0160     return 0;
0161 }
0162 
0163 int xfrm6_rcv_tnl(struct sk_buff *skb, struct ip6_tnl *t)
0164 {
0165     return xfrm6_rcv_spi(skb, skb_network_header(skb)[IP6CB(skb)->nhoff],
0166                  0, t);
0167 }
0168 EXPORT_SYMBOL(xfrm6_rcv_tnl);
0169 
0170 int xfrm6_rcv(struct sk_buff *skb)
0171 {
0172     return xfrm6_rcv_tnl(skb, NULL);
0173 }
0174 EXPORT_SYMBOL(xfrm6_rcv);
0175 int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr,
0176              xfrm_address_t *saddr, u8 proto)
0177 {
0178     struct net *net = dev_net(skb->dev);
0179     struct xfrm_state *x = NULL;
0180     struct sec_path *sp;
0181     int i = 0;
0182 
0183     sp = secpath_set(skb);
0184     if (!sp) {
0185         XFRM_INC_STATS(net, LINUX_MIB_XFRMINERROR);
0186         goto drop;
0187     }
0188 
0189     if (1 + sp->len == XFRM_MAX_DEPTH) {
0190         XFRM_INC_STATS(net, LINUX_MIB_XFRMINBUFFERERROR);
0191         goto drop;
0192     }
0193 
0194     for (i = 0; i < 3; i++) {
0195         xfrm_address_t *dst, *src;
0196 
0197         switch (i) {
0198         case 0:
0199             dst = daddr;
0200             src = saddr;
0201             break;
0202         case 1:
0203             /* lookup state with wild-card source address */
0204             dst = daddr;
0205             src = (xfrm_address_t *)&in6addr_any;
0206             break;
0207         default:
0208             /* lookup state with wild-card addresses */
0209             dst = (xfrm_address_t *)&in6addr_any;
0210             src = (xfrm_address_t *)&in6addr_any;
0211             break;
0212         }
0213 
0214         x = xfrm_state_lookup_byaddr(net, skb->mark, dst, src, proto, AF_INET6);
0215         if (!x)
0216             continue;
0217 
0218         spin_lock(&x->lock);
0219 
0220         if ((!i || (x->props.flags & XFRM_STATE_WILDRECV)) &&
0221             likely(x->km.state == XFRM_STATE_VALID) &&
0222             !xfrm_state_check_expire(x)) {
0223             spin_unlock(&x->lock);
0224             if (x->type->input(x, skb) > 0) {
0225                 /* found a valid state */
0226                 break;
0227             }
0228         } else
0229             spin_unlock(&x->lock);
0230 
0231         xfrm_state_put(x);
0232         x = NULL;
0233     }
0234 
0235     if (!x) {
0236         XFRM_INC_STATS(net, LINUX_MIB_XFRMINNOSTATES);
0237         xfrm_audit_state_notfound_simple(skb, AF_INET6);
0238         goto drop;
0239     }
0240 
0241     sp->xvec[sp->len++] = x;
0242 
0243     spin_lock(&x->lock);
0244 
0245     x->curlft.bytes += skb->len;
0246     x->curlft.packets++;
0247 
0248     spin_unlock(&x->lock);
0249 
0250     return 1;
0251 
0252 drop:
0253     return -1;
0254 }
0255 EXPORT_SYMBOL(xfrm6_input_addr);