Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * INET     An implementation of the TCP/IP protocol suite for the LINUX
0004  *      operating system.  INET is implemented using the  BSD Socket
0005  *      interface as the means of communication with the user level.
0006  *
0007  *      The options processing module for ip.c
0008  *
0009  * Authors: A.N.Kuznetsov
0010  *
0011  */
0012 
0013 #define pr_fmt(fmt) "IPv4: " fmt
0014 
0015 #include <linux/capability.h>
0016 #include <linux/module.h>
0017 #include <linux/slab.h>
0018 #include <linux/types.h>
0019 #include <linux/uaccess.h>
0020 #include <asm/unaligned.h>
0021 #include <linux/skbuff.h>
0022 #include <linux/ip.h>
0023 #include <linux/icmp.h>
0024 #include <linux/netdevice.h>
0025 #include <linux/rtnetlink.h>
0026 #include <net/sock.h>
0027 #include <net/ip.h>
0028 #include <net/icmp.h>
0029 #include <net/route.h>
0030 #include <net/cipso_ipv4.h>
0031 #include <net/ip_fib.h>
0032 
0033 /*
0034  * Write options to IP header, record destination address to
0035  * source route option, address of outgoing interface
0036  * (we should already know it, so that this  function is allowed be
0037  * called only after routing decision) and timestamp,
0038  * if we originate this datagram.
0039  *
0040  * daddr is real destination address, next hop is recorded in IP header.
0041  * saddr is address of outgoing interface.
0042  */
0043 
0044 void ip_options_build(struct sk_buff *skb, struct ip_options *opt,
0045               __be32 daddr, struct rtable *rt)
0046 {
0047     unsigned char *iph = skb_network_header(skb);
0048 
0049     memcpy(&(IPCB(skb)->opt), opt, sizeof(struct ip_options));
0050     memcpy(iph + sizeof(struct iphdr), opt->__data, opt->optlen);
0051     opt = &(IPCB(skb)->opt);
0052 
0053     if (opt->srr)
0054         memcpy(iph + opt->srr + iph[opt->srr + 1] - 4, &daddr, 4);
0055 
0056     if (opt->rr_needaddr)
0057         ip_rt_get_source(iph + opt->rr + iph[opt->rr + 2] - 5, skb, rt);
0058     if (opt->ts_needaddr)
0059         ip_rt_get_source(iph + opt->ts + iph[opt->ts + 2] - 9, skb, rt);
0060     if (opt->ts_needtime) {
0061         __be32 midtime;
0062 
0063         midtime = inet_current_timestamp();
0064         memcpy(iph + opt->ts + iph[opt->ts + 2] - 5, &midtime, 4);
0065     }
0066 }
0067 
0068 /*
0069  * Provided (sopt, skb) points to received options,
0070  * build in dopt compiled option set appropriate for answering.
0071  * i.e. invert SRR option, copy anothers,
0072  * and grab room in RR/TS options.
0073  *
0074  * NOTE: dopt cannot point to skb.
0075  */
0076 
0077 int __ip_options_echo(struct net *net, struct ip_options *dopt,
0078               struct sk_buff *skb, const struct ip_options *sopt)
0079 {
0080     unsigned char *sptr, *dptr;
0081     int soffset, doffset;
0082     int optlen;
0083 
0084     memset(dopt, 0, sizeof(struct ip_options));
0085 
0086     if (sopt->optlen == 0)
0087         return 0;
0088 
0089     sptr = skb_network_header(skb);
0090     dptr = dopt->__data;
0091 
0092     if (sopt->rr) {
0093         optlen  = sptr[sopt->rr+1];
0094         soffset = sptr[sopt->rr+2];
0095         dopt->rr = dopt->optlen + sizeof(struct iphdr);
0096         memcpy(dptr, sptr+sopt->rr, optlen);
0097         if (sopt->rr_needaddr && soffset <= optlen) {
0098             if (soffset + 3 > optlen)
0099                 return -EINVAL;
0100             dptr[2] = soffset + 4;
0101             dopt->rr_needaddr = 1;
0102         }
0103         dptr += optlen;
0104         dopt->optlen += optlen;
0105     }
0106     if (sopt->ts) {
0107         optlen = sptr[sopt->ts+1];
0108         soffset = sptr[sopt->ts+2];
0109         dopt->ts = dopt->optlen + sizeof(struct iphdr);
0110         memcpy(dptr, sptr+sopt->ts, optlen);
0111         if (soffset <= optlen) {
0112             if (sopt->ts_needaddr) {
0113                 if (soffset + 3 > optlen)
0114                     return -EINVAL;
0115                 dopt->ts_needaddr = 1;
0116                 soffset += 4;
0117             }
0118             if (sopt->ts_needtime) {
0119                 if (soffset + 3 > optlen)
0120                     return -EINVAL;
0121                 if ((dptr[3]&0xF) != IPOPT_TS_PRESPEC) {
0122                     dopt->ts_needtime = 1;
0123                     soffset += 4;
0124                 } else {
0125                     dopt->ts_needtime = 0;
0126 
0127                     if (soffset + 7 <= optlen) {
0128                         __be32 addr;
0129 
0130                         memcpy(&addr, dptr+soffset-1, 4);
0131                         if (inet_addr_type(net, addr) != RTN_UNICAST) {
0132                             dopt->ts_needtime = 1;
0133                             soffset += 8;
0134                         }
0135                     }
0136                 }
0137             }
0138             dptr[2] = soffset;
0139         }
0140         dptr += optlen;
0141         dopt->optlen += optlen;
0142     }
0143     if (sopt->srr) {
0144         unsigned char *start = sptr+sopt->srr;
0145         __be32 faddr;
0146 
0147         optlen  = start[1];
0148         soffset = start[2];
0149         doffset = 0;
0150         if (soffset > optlen)
0151             soffset = optlen + 1;
0152         soffset -= 4;
0153         if (soffset > 3) {
0154             memcpy(&faddr, &start[soffset-1], 4);
0155             for (soffset -= 4, doffset = 4; soffset > 3; soffset -= 4, doffset += 4)
0156                 memcpy(&dptr[doffset-1], &start[soffset-1], 4);
0157             /*
0158              * RFC1812 requires to fix illegal source routes.
0159              */
0160             if (memcmp(&ip_hdr(skb)->saddr,
0161                    &start[soffset + 3], 4) == 0)
0162                 doffset -= 4;
0163         }
0164         if (doffset > 3) {
0165             dopt->faddr = faddr;
0166             dptr[0] = start[0];
0167             dptr[1] = doffset+3;
0168             dptr[2] = 4;
0169             dptr += doffset+3;
0170             dopt->srr = dopt->optlen + sizeof(struct iphdr);
0171             dopt->optlen += doffset+3;
0172             dopt->is_strictroute = sopt->is_strictroute;
0173         }
0174     }
0175     if (sopt->cipso) {
0176         optlen  = sptr[sopt->cipso+1];
0177         dopt->cipso = dopt->optlen+sizeof(struct iphdr);
0178         memcpy(dptr, sptr+sopt->cipso, optlen);
0179         dptr += optlen;
0180         dopt->optlen += optlen;
0181     }
0182     while (dopt->optlen & 3) {
0183         *dptr++ = IPOPT_END;
0184         dopt->optlen++;
0185     }
0186     return 0;
0187 }
0188 
0189 /*
0190  *  Options "fragmenting", just fill options not
0191  *  allowed in fragments with NOOPs.
0192  *  Simple and stupid 8), but the most efficient way.
0193  */
0194 
0195 void ip_options_fragment(struct sk_buff *skb)
0196 {
0197     unsigned char *optptr = skb_network_header(skb) + sizeof(struct iphdr);
0198     struct ip_options *opt = &(IPCB(skb)->opt);
0199     int  l = opt->optlen;
0200     int  optlen;
0201 
0202     while (l > 0) {
0203         switch (*optptr) {
0204         case IPOPT_END:
0205             return;
0206         case IPOPT_NOOP:
0207             l--;
0208             optptr++;
0209             continue;
0210         }
0211         optlen = optptr[1];
0212         if (optlen < 2 || optlen > l)
0213           return;
0214         if (!IPOPT_COPIED(*optptr))
0215             memset(optptr, IPOPT_NOOP, optlen);
0216         l -= optlen;
0217         optptr += optlen;
0218     }
0219     opt->ts = 0;
0220     opt->rr = 0;
0221     opt->rr_needaddr = 0;
0222     opt->ts_needaddr = 0;
0223     opt->ts_needtime = 0;
0224 }
0225 
0226 /* helper used by ip_options_compile() to call fib_compute_spec_dst()
0227  * at most one time.
0228  */
0229 static void spec_dst_fill(__be32 *spec_dst, struct sk_buff *skb)
0230 {
0231     if (*spec_dst == htonl(INADDR_ANY))
0232         *spec_dst = fib_compute_spec_dst(skb);
0233 }
0234 
0235 /*
0236  * Verify options and fill pointers in struct options.
0237  * Caller should clear *opt, and set opt->data.
0238  * If opt == NULL, then skb->data should point to IP header.
0239  */
0240 
0241 int __ip_options_compile(struct net *net,
0242              struct ip_options *opt, struct sk_buff *skb,
0243              __be32 *info)
0244 {
0245     __be32 spec_dst = htonl(INADDR_ANY);
0246     unsigned char *pp_ptr = NULL;
0247     struct rtable *rt = NULL;
0248     unsigned char *optptr;
0249     unsigned char *iph;
0250     int optlen, l;
0251 
0252     if (skb) {
0253         rt = skb_rtable(skb);
0254         optptr = (unsigned char *)&(ip_hdr(skb)[1]);
0255     } else
0256         optptr = opt->__data;
0257     iph = optptr - sizeof(struct iphdr);
0258 
0259     for (l = opt->optlen; l > 0; ) {
0260         switch (*optptr) {
0261         case IPOPT_END:
0262             for (optptr++, l--; l > 0; optptr++, l--) {
0263                 if (*optptr != IPOPT_END) {
0264                     *optptr = IPOPT_END;
0265                     opt->is_changed = 1;
0266                 }
0267             }
0268             goto eol;
0269         case IPOPT_NOOP:
0270             l--;
0271             optptr++;
0272             continue;
0273         }
0274         if (unlikely(l < 2)) {
0275             pp_ptr = optptr;
0276             goto error;
0277         }
0278         optlen = optptr[1];
0279         if (optlen < 2 || optlen > l) {
0280             pp_ptr = optptr;
0281             goto error;
0282         }
0283         switch (*optptr) {
0284         case IPOPT_SSRR:
0285         case IPOPT_LSRR:
0286             if (optlen < 3) {
0287                 pp_ptr = optptr + 1;
0288                 goto error;
0289             }
0290             if (optptr[2] < 4) {
0291                 pp_ptr = optptr + 2;
0292                 goto error;
0293             }
0294             /* NB: cf RFC-1812 5.2.4.1 */
0295             if (opt->srr) {
0296                 pp_ptr = optptr;
0297                 goto error;
0298             }
0299             if (!skb) {
0300                 if (optptr[2] != 4 || optlen < 7 || ((optlen-3) & 3)) {
0301                     pp_ptr = optptr + 1;
0302                     goto error;
0303                 }
0304                 memcpy(&opt->faddr, &optptr[3], 4);
0305                 if (optlen > 7)
0306                     memmove(&optptr[3], &optptr[7], optlen-7);
0307             }
0308             opt->is_strictroute = (optptr[0] == IPOPT_SSRR);
0309             opt->srr = optptr - iph;
0310             break;
0311         case IPOPT_RR:
0312             if (opt->rr) {
0313                 pp_ptr = optptr;
0314                 goto error;
0315             }
0316             if (optlen < 3) {
0317                 pp_ptr = optptr + 1;
0318                 goto error;
0319             }
0320             if (optptr[2] < 4) {
0321                 pp_ptr = optptr + 2;
0322                 goto error;
0323             }
0324             if (optptr[2] <= optlen) {
0325                 if (optptr[2]+3 > optlen) {
0326                     pp_ptr = optptr + 2;
0327                     goto error;
0328                 }
0329                 if (rt) {
0330                     spec_dst_fill(&spec_dst, skb);
0331                     memcpy(&optptr[optptr[2]-1], &spec_dst, 4);
0332                     opt->is_changed = 1;
0333                 }
0334                 optptr[2] += 4;
0335                 opt->rr_needaddr = 1;
0336             }
0337             opt->rr = optptr - iph;
0338             break;
0339         case IPOPT_TIMESTAMP:
0340             if (opt->ts) {
0341                 pp_ptr = optptr;
0342                 goto error;
0343             }
0344             if (optlen < 4) {
0345                 pp_ptr = optptr + 1;
0346                 goto error;
0347             }
0348             if (optptr[2] < 5) {
0349                 pp_ptr = optptr + 2;
0350                 goto error;
0351             }
0352             if (optptr[2] <= optlen) {
0353                 unsigned char *timeptr = NULL;
0354                 if (optptr[2]+3 > optlen) {
0355                     pp_ptr = optptr + 2;
0356                     goto error;
0357                 }
0358                 switch (optptr[3]&0xF) {
0359                 case IPOPT_TS_TSONLY:
0360                     if (skb)
0361                         timeptr = &optptr[optptr[2]-1];
0362                     opt->ts_needtime = 1;
0363                     optptr[2] += 4;
0364                     break;
0365                 case IPOPT_TS_TSANDADDR:
0366                     if (optptr[2]+7 > optlen) {
0367                         pp_ptr = optptr + 2;
0368                         goto error;
0369                     }
0370                     if (rt)  {
0371                         spec_dst_fill(&spec_dst, skb);
0372                         memcpy(&optptr[optptr[2]-1], &spec_dst, 4);
0373                         timeptr = &optptr[optptr[2]+3];
0374                     }
0375                     opt->ts_needaddr = 1;
0376                     opt->ts_needtime = 1;
0377                     optptr[2] += 8;
0378                     break;
0379                 case IPOPT_TS_PRESPEC:
0380                     if (optptr[2]+7 > optlen) {
0381                         pp_ptr = optptr + 2;
0382                         goto error;
0383                     }
0384                     {
0385                         __be32 addr;
0386                         memcpy(&addr, &optptr[optptr[2]-1], 4);
0387                         if (inet_addr_type(net, addr) == RTN_UNICAST)
0388                             break;
0389                         if (skb)
0390                             timeptr = &optptr[optptr[2]+3];
0391                     }
0392                     opt->ts_needtime = 1;
0393                     optptr[2] += 8;
0394                     break;
0395                 default:
0396                     if (!skb && !ns_capable(net->user_ns, CAP_NET_RAW)) {
0397                         pp_ptr = optptr + 3;
0398                         goto error;
0399                     }
0400                     break;
0401                 }
0402                 if (timeptr) {
0403                     __be32 midtime;
0404 
0405                     midtime = inet_current_timestamp();
0406                     memcpy(timeptr, &midtime, 4);
0407                     opt->is_changed = 1;
0408                 }
0409             } else if ((optptr[3]&0xF) != IPOPT_TS_PRESPEC) {
0410                 unsigned int overflow = optptr[3]>>4;
0411                 if (overflow == 15) {
0412                     pp_ptr = optptr + 3;
0413                     goto error;
0414                 }
0415                 if (skb) {
0416                     optptr[3] = (optptr[3]&0xF)|((overflow+1)<<4);
0417                     opt->is_changed = 1;
0418                 }
0419             }
0420             opt->ts = optptr - iph;
0421             break;
0422         case IPOPT_RA:
0423             if (optlen < 4) {
0424                 pp_ptr = optptr + 1;
0425                 goto error;
0426             }
0427             if (optptr[2] == 0 && optptr[3] == 0)
0428                 opt->router_alert = optptr - iph;
0429             break;
0430         case IPOPT_CIPSO:
0431             if ((!skb && !ns_capable(net->user_ns, CAP_NET_RAW)) || opt->cipso) {
0432                 pp_ptr = optptr;
0433                 goto error;
0434             }
0435             opt->cipso = optptr - iph;
0436             if (cipso_v4_validate(skb, &optptr)) {
0437                 pp_ptr = optptr;
0438                 goto error;
0439             }
0440             break;
0441         case IPOPT_SEC:
0442         case IPOPT_SID:
0443         default:
0444             if (!skb && !ns_capable(net->user_ns, CAP_NET_RAW)) {
0445                 pp_ptr = optptr;
0446                 goto error;
0447             }
0448             break;
0449         }
0450         l -= optlen;
0451         optptr += optlen;
0452     }
0453 
0454 eol:
0455     if (!pp_ptr)
0456         return 0;
0457 
0458 error:
0459     if (info)
0460         *info = htonl((pp_ptr-iph)<<24);
0461     return -EINVAL;
0462 }
0463 EXPORT_SYMBOL(__ip_options_compile);
0464 
0465 int ip_options_compile(struct net *net,
0466                struct ip_options *opt, struct sk_buff *skb)
0467 {
0468     int ret;
0469     __be32 info;
0470 
0471     ret = __ip_options_compile(net, opt, skb, &info);
0472     if (ret != 0 && skb)
0473         icmp_send(skb, ICMP_PARAMETERPROB, 0, info);
0474     return ret;
0475 }
0476 EXPORT_SYMBOL(ip_options_compile);
0477 
0478 /*
0479  *  Undo all the changes done by ip_options_compile().
0480  */
0481 
0482 void ip_options_undo(struct ip_options *opt)
0483 {
0484     if (opt->srr) {
0485         unsigned char *optptr = opt->__data + opt->srr - sizeof(struct iphdr);
0486 
0487         memmove(optptr + 7, optptr + 3, optptr[1] - 7);
0488         memcpy(optptr + 3, &opt->faddr, 4);
0489     }
0490     if (opt->rr_needaddr) {
0491         unsigned char *optptr = opt->__data + opt->rr - sizeof(struct iphdr);
0492 
0493         optptr[2] -= 4;
0494         memset(&optptr[optptr[2] - 1], 0, 4);
0495     }
0496     if (opt->ts) {
0497         unsigned char *optptr = opt->__data + opt->ts - sizeof(struct iphdr);
0498 
0499         if (opt->ts_needtime) {
0500             optptr[2] -= 4;
0501             memset(&optptr[optptr[2] - 1], 0, 4);
0502             if ((optptr[3] & 0xF) == IPOPT_TS_PRESPEC)
0503                 optptr[2] -= 4;
0504         }
0505         if (opt->ts_needaddr) {
0506             optptr[2] -= 4;
0507             memset(&optptr[optptr[2] - 1], 0, 4);
0508         }
0509     }
0510 }
0511 
0512 int ip_options_get(struct net *net, struct ip_options_rcu **optp,
0513            sockptr_t data, int optlen)
0514 {
0515     struct ip_options_rcu *opt;
0516 
0517     opt = kzalloc(sizeof(struct ip_options_rcu) + ((optlen + 3) & ~3),
0518                GFP_KERNEL);
0519     if (!opt)
0520         return -ENOMEM;
0521     if (optlen && copy_from_sockptr(opt->opt.__data, data, optlen)) {
0522         kfree(opt);
0523         return -EFAULT;
0524     }
0525 
0526     while (optlen & 3)
0527         opt->opt.__data[optlen++] = IPOPT_END;
0528     opt->opt.optlen = optlen;
0529     if (optlen && ip_options_compile(net, &opt->opt, NULL)) {
0530         kfree(opt);
0531         return -EINVAL;
0532     }
0533     kfree(*optp);
0534     *optp = opt;
0535     return 0;
0536 }
0537 
0538 void ip_forward_options(struct sk_buff *skb)
0539 {
0540     struct   ip_options *opt    = &(IPCB(skb)->opt);
0541     unsigned char *optptr;
0542     struct rtable *rt = skb_rtable(skb);
0543     unsigned char *raw = skb_network_header(skb);
0544 
0545     if (opt->rr_needaddr) {
0546         optptr = (unsigned char *)raw + opt->rr;
0547         ip_rt_get_source(&optptr[optptr[2]-5], skb, rt);
0548         opt->is_changed = 1;
0549     }
0550     if (opt->srr_is_hit) {
0551         int srrptr, srrspace;
0552 
0553         optptr = raw + opt->srr;
0554 
0555         for ( srrptr = optptr[2], srrspace = optptr[1];
0556              srrptr <= srrspace;
0557              srrptr += 4
0558              ) {
0559             if (srrptr + 3 > srrspace)
0560                 break;
0561             if (memcmp(&opt->nexthop, &optptr[srrptr-1], 4) == 0)
0562                 break;
0563         }
0564         if (srrptr + 3 <= srrspace) {
0565             opt->is_changed = 1;
0566             ip_hdr(skb)->daddr = opt->nexthop;
0567             ip_rt_get_source(&optptr[srrptr-1], skb, rt);
0568             optptr[2] = srrptr+4;
0569         } else {
0570             net_crit_ratelimited("%s(): Argh! Destination lost!\n",
0571                          __func__);
0572         }
0573         if (opt->ts_needaddr) {
0574             optptr = raw + opt->ts;
0575             ip_rt_get_source(&optptr[optptr[2]-9], skb, rt);
0576             opt->is_changed = 1;
0577         }
0578     }
0579     if (opt->is_changed) {
0580         opt->is_changed = 0;
0581         ip_send_check(ip_hdr(skb));
0582     }
0583 }
0584 
0585 int ip_options_rcv_srr(struct sk_buff *skb, struct net_device *dev)
0586 {
0587     struct ip_options *opt = &(IPCB(skb)->opt);
0588     int srrspace, srrptr;
0589     __be32 nexthop;
0590     struct iphdr *iph = ip_hdr(skb);
0591     unsigned char *optptr = skb_network_header(skb) + opt->srr;
0592     struct rtable *rt = skb_rtable(skb);
0593     struct rtable *rt2;
0594     unsigned long orefdst;
0595     int err;
0596 
0597     if (!rt)
0598         return 0;
0599 
0600     if (skb->pkt_type != PACKET_HOST)
0601         return -EINVAL;
0602     if (rt->rt_type == RTN_UNICAST) {
0603         if (!opt->is_strictroute)
0604             return 0;
0605         icmp_send(skb, ICMP_PARAMETERPROB, 0, htonl(16<<24));
0606         return -EINVAL;
0607     }
0608     if (rt->rt_type != RTN_LOCAL)
0609         return -EINVAL;
0610 
0611     for (srrptr = optptr[2], srrspace = optptr[1]; srrptr <= srrspace; srrptr += 4) {
0612         if (srrptr + 3 > srrspace) {
0613             icmp_send(skb, ICMP_PARAMETERPROB, 0, htonl((opt->srr+2)<<24));
0614             return -EINVAL;
0615         }
0616         memcpy(&nexthop, &optptr[srrptr-1], 4);
0617 
0618         orefdst = skb->_skb_refdst;
0619         skb_dst_set(skb, NULL);
0620         err = ip_route_input(skb, nexthop, iph->saddr, iph->tos, dev);
0621         rt2 = skb_rtable(skb);
0622         if (err || (rt2->rt_type != RTN_UNICAST && rt2->rt_type != RTN_LOCAL)) {
0623             skb_dst_drop(skb);
0624             skb->_skb_refdst = orefdst;
0625             return -EINVAL;
0626         }
0627         refdst_drop(orefdst);
0628         if (rt2->rt_type != RTN_LOCAL)
0629             break;
0630         /* Superfast 8) loopback forward */
0631         iph->daddr = nexthop;
0632         opt->is_changed = 1;
0633     }
0634     if (srrptr <= srrspace) {
0635         opt->srr_is_hit = 1;
0636         opt->nexthop = nexthop;
0637         opt->is_changed = 1;
0638     }
0639     return 0;
0640 }
0641 EXPORT_SYMBOL(ip_options_rcv_srr);