^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * INET An implementation of the TCP/IP protocol suite for the LINUX
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * operating system. INET is implemented using the BSD Socket
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * interface as the means of communication with the user level.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * The options processing module for ip.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * Authors: A.N.Kuznetsov
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #define pr_fmt(fmt) "IPv4: " fmt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/capability.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/uaccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <asm/unaligned.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/skbuff.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/ip.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/icmp.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/netdevice.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <linux/rtnetlink.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <net/sock.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <net/ip.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include <net/icmp.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include <net/route.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #include <net/cipso_ipv4.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #include <net/ip_fib.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) * Write options to IP header, record destination address to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) * source route option, address of outgoing interface
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) * (we should already know it, so that this function is allowed be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) * called only after routing decision) and timestamp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) * if we originate this datagram.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) * daddr is real destination address, next hop is recorded in IP header.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) * saddr is address of outgoing interface.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) void ip_options_build(struct sk_buff *skb, struct ip_options *opt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) __be32 daddr, struct rtable *rt, int is_frag)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) unsigned char *iph = skb_network_header(skb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) memcpy(&(IPCB(skb)->opt), opt, sizeof(struct ip_options));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) memcpy(iph + sizeof(struct iphdr), opt->__data, opt->optlen);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) opt = &(IPCB(skb)->opt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) if (opt->srr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) memcpy(iph + opt->srr + iph[opt->srr + 1] - 4, &daddr, 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) if (!is_frag) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) if (opt->rr_needaddr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) ip_rt_get_source(iph + opt->rr + iph[opt->rr + 2] - 5, skb, rt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) if (opt->ts_needaddr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) ip_rt_get_source(iph + opt->ts + iph[opt->ts + 2] - 9, skb, rt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) if (opt->ts_needtime) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) __be32 midtime;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) midtime = inet_current_timestamp();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) memcpy(iph + opt->ts + iph[opt->ts + 2] - 5, &midtime, 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) if (opt->rr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) memset(iph + opt->rr, IPOPT_NOP, iph[opt->rr + 1]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) opt->rr = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) opt->rr_needaddr = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) if (opt->ts) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) memset(iph + opt->ts, IPOPT_NOP, iph[opt->ts + 1]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) opt->ts = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) opt->ts_needaddr = opt->ts_needtime = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) * Provided (sopt, skb) points to received options,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) * build in dopt compiled option set appropriate for answering.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) * i.e. invert SRR option, copy anothers,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) * and grab room in RR/TS options.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) * NOTE: dopt cannot point to skb.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) int __ip_options_echo(struct net *net, struct ip_options *dopt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) struct sk_buff *skb, const struct ip_options *sopt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) unsigned char *sptr, *dptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) int soffset, doffset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) int optlen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) memset(dopt, 0, sizeof(struct ip_options));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) if (sopt->optlen == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) sptr = skb_network_header(skb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) dptr = dopt->__data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) if (sopt->rr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) optlen = sptr[sopt->rr+1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) soffset = sptr[sopt->rr+2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) dopt->rr = dopt->optlen + sizeof(struct iphdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) memcpy(dptr, sptr+sopt->rr, optlen);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) if (sopt->rr_needaddr && soffset <= optlen) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) if (soffset + 3 > optlen)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) dptr[2] = soffset + 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) dopt->rr_needaddr = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) dptr += optlen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) dopt->optlen += optlen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) if (sopt->ts) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) optlen = sptr[sopt->ts+1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) soffset = sptr[sopt->ts+2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) dopt->ts = dopt->optlen + sizeof(struct iphdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) memcpy(dptr, sptr+sopt->ts, optlen);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) if (soffset <= optlen) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) if (sopt->ts_needaddr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) if (soffset + 3 > optlen)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) dopt->ts_needaddr = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) soffset += 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) if (sopt->ts_needtime) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) if (soffset + 3 > optlen)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) if ((dptr[3]&0xF) != IPOPT_TS_PRESPEC) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) dopt->ts_needtime = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) soffset += 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) dopt->ts_needtime = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) if (soffset + 7 <= optlen) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) __be32 addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) memcpy(&addr, dptr+soffset-1, 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) if (inet_addr_type(net, addr) != RTN_UNICAST) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) dopt->ts_needtime = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) soffset += 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) dptr[2] = soffset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) dptr += optlen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) dopt->optlen += optlen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) if (sopt->srr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) unsigned char *start = sptr+sopt->srr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) __be32 faddr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) optlen = start[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) soffset = start[2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) doffset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) if (soffset > optlen)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) soffset = optlen + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) soffset -= 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) if (soffset > 3) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) memcpy(&faddr, &start[soffset-1], 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) for (soffset -= 4, doffset = 4; soffset > 3; soffset -= 4, doffset += 4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) memcpy(&dptr[doffset-1], &start[soffset-1], 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) * RFC1812 requires to fix illegal source routes.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) if (memcmp(&ip_hdr(skb)->saddr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) &start[soffset + 3], 4) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) doffset -= 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) if (doffset > 3) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) dopt->faddr = faddr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) dptr[0] = start[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) dptr[1] = doffset+3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) dptr[2] = 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) dptr += doffset+3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) dopt->srr = dopt->optlen + sizeof(struct iphdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) dopt->optlen += doffset+3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) dopt->is_strictroute = sopt->is_strictroute;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) if (sopt->cipso) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) optlen = sptr[sopt->cipso+1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) dopt->cipso = dopt->optlen+sizeof(struct iphdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) memcpy(dptr, sptr+sopt->cipso, optlen);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) dptr += optlen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) dopt->optlen += optlen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) while (dopt->optlen & 3) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) *dptr++ = IPOPT_END;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) dopt->optlen++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) * Options "fragmenting", just fill options not
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) * allowed in fragments with NOOPs.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) * Simple and stupid 8), but the most efficient way.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) void ip_options_fragment(struct sk_buff *skb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) unsigned char *optptr = skb_network_header(skb) + sizeof(struct iphdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) struct ip_options *opt = &(IPCB(skb)->opt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) int l = opt->optlen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) int optlen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) while (l > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) switch (*optptr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) case IPOPT_END:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) case IPOPT_NOOP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) l--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) optptr++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) optlen = optptr[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) if (optlen < 2 || optlen > l)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) if (!IPOPT_COPIED(*optptr))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) memset(optptr, IPOPT_NOOP, optlen);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) l -= optlen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) optptr += optlen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) opt->ts = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) opt->rr = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) opt->rr_needaddr = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) opt->ts_needaddr = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) opt->ts_needtime = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) /* helper used by ip_options_compile() to call fib_compute_spec_dst()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) * at most one time.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) static void spec_dst_fill(__be32 *spec_dst, struct sk_buff *skb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) if (*spec_dst == htonl(INADDR_ANY))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) *spec_dst = fib_compute_spec_dst(skb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) * Verify options and fill pointers in struct options.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) * Caller should clear *opt, and set opt->data.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) * If opt == NULL, then skb->data should point to IP header.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) int __ip_options_compile(struct net *net,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) struct ip_options *opt, struct sk_buff *skb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) __be32 *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) __be32 spec_dst = htonl(INADDR_ANY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) unsigned char *pp_ptr = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) struct rtable *rt = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) unsigned char *optptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) unsigned char *iph;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) int optlen, l;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) if (skb) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) rt = skb_rtable(skb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) optptr = (unsigned char *)&(ip_hdr(skb)[1]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) optptr = opt->__data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) iph = optptr - sizeof(struct iphdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) for (l = opt->optlen; l > 0; ) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) switch (*optptr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) case IPOPT_END:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) for (optptr++, l--; l > 0; optptr++, l--) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) if (*optptr != IPOPT_END) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) *optptr = IPOPT_END;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) opt->is_changed = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) goto eol;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) case IPOPT_NOOP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) l--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) optptr++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) if (unlikely(l < 2)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) pp_ptr = optptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) optlen = optptr[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) if (optlen < 2 || optlen > l) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) pp_ptr = optptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) switch (*optptr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) case IPOPT_SSRR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) case IPOPT_LSRR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) if (optlen < 3) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) pp_ptr = optptr + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) if (optptr[2] < 4) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) pp_ptr = optptr + 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) /* NB: cf RFC-1812 5.2.4.1 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) if (opt->srr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) pp_ptr = optptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) if (!skb) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) if (optptr[2] != 4 || optlen < 7 || ((optlen-3) & 3)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) pp_ptr = optptr + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) memcpy(&opt->faddr, &optptr[3], 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) if (optlen > 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) memmove(&optptr[3], &optptr[7], optlen-7);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) opt->is_strictroute = (optptr[0] == IPOPT_SSRR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) opt->srr = optptr - iph;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) case IPOPT_RR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) if (opt->rr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) pp_ptr = optptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) if (optlen < 3) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) pp_ptr = optptr + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) if (optptr[2] < 4) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) pp_ptr = optptr + 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) if (optptr[2] <= optlen) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) if (optptr[2]+3 > optlen) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) pp_ptr = optptr + 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) if (rt) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) spec_dst_fill(&spec_dst, skb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) memcpy(&optptr[optptr[2]-1], &spec_dst, 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) opt->is_changed = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) optptr[2] += 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) opt->rr_needaddr = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) opt->rr = optptr - iph;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) case IPOPT_TIMESTAMP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) if (opt->ts) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) pp_ptr = optptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) if (optlen < 4) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) pp_ptr = optptr + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) if (optptr[2] < 5) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) pp_ptr = optptr + 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) if (optptr[2] <= optlen) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) unsigned char *timeptr = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) if (optptr[2]+3 > optlen) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) pp_ptr = optptr + 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) switch (optptr[3]&0xF) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) case IPOPT_TS_TSONLY:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) if (skb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) timeptr = &optptr[optptr[2]-1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) opt->ts_needtime = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) optptr[2] += 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) case IPOPT_TS_TSANDADDR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) if (optptr[2]+7 > optlen) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) pp_ptr = optptr + 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) if (rt) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) spec_dst_fill(&spec_dst, skb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) memcpy(&optptr[optptr[2]-1], &spec_dst, 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) timeptr = &optptr[optptr[2]+3];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) opt->ts_needaddr = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) opt->ts_needtime = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) optptr[2] += 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) case IPOPT_TS_PRESPEC:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) if (optptr[2]+7 > optlen) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) pp_ptr = optptr + 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) __be32 addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) memcpy(&addr, &optptr[optptr[2]-1], 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) if (inet_addr_type(net, addr) == RTN_UNICAST)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) if (skb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) timeptr = &optptr[optptr[2]+3];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) opt->ts_needtime = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) optptr[2] += 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) if (!skb && !ns_capable(net->user_ns, CAP_NET_RAW)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) pp_ptr = optptr + 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) if (timeptr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) __be32 midtime;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) midtime = inet_current_timestamp();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) memcpy(timeptr, &midtime, 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) opt->is_changed = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) } else if ((optptr[3]&0xF) != IPOPT_TS_PRESPEC) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) unsigned int overflow = optptr[3]>>4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) if (overflow == 15) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) pp_ptr = optptr + 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) if (skb) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) optptr[3] = (optptr[3]&0xF)|((overflow+1)<<4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) opt->is_changed = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) opt->ts = optptr - iph;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) case IPOPT_RA:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) if (optlen < 4) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) pp_ptr = optptr + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) if (optptr[2] == 0 && optptr[3] == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) opt->router_alert = optptr - iph;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) case IPOPT_CIPSO:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) if ((!skb && !ns_capable(net->user_ns, CAP_NET_RAW)) || opt->cipso) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) pp_ptr = optptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) opt->cipso = optptr - iph;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) if (cipso_v4_validate(skb, &optptr)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) pp_ptr = optptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) case IPOPT_SEC:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) case IPOPT_SID:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) if (!skb && !ns_capable(net->user_ns, CAP_NET_RAW)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) pp_ptr = optptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) l -= optlen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) optptr += optlen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) eol:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) if (!pp_ptr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) error:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) if (info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) *info = htonl((pp_ptr-iph)<<24);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) EXPORT_SYMBOL(__ip_options_compile);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) int ip_options_compile(struct net *net,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) struct ip_options *opt, struct sk_buff *skb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) __be32 info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) ret = __ip_options_compile(net, opt, skb, &info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) if (ret != 0 && skb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) icmp_send(skb, ICMP_PARAMETERPROB, 0, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) EXPORT_SYMBOL(ip_options_compile);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) * Undo all the changes done by ip_options_compile().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) void ip_options_undo(struct ip_options *opt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) if (opt->srr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) unsigned char *optptr = opt->__data + opt->srr - sizeof(struct iphdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) memmove(optptr + 7, optptr + 3, optptr[1] - 7);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) memcpy(optptr + 3, &opt->faddr, 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) if (opt->rr_needaddr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) unsigned char *optptr = opt->__data + opt->rr - sizeof(struct iphdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) optptr[2] -= 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) memset(&optptr[optptr[2] - 1], 0, 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) if (opt->ts) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) unsigned char *optptr = opt->__data + opt->ts - sizeof(struct iphdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) if (opt->ts_needtime) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) optptr[2] -= 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) memset(&optptr[optptr[2] - 1], 0, 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) if ((optptr[3] & 0xF) == IPOPT_TS_PRESPEC)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) optptr[2] -= 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) if (opt->ts_needaddr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) optptr[2] -= 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) memset(&optptr[optptr[2] - 1], 0, 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) int ip_options_get(struct net *net, struct ip_options_rcu **optp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) sockptr_t data, int optlen)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) struct ip_options_rcu *opt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) opt = kzalloc(sizeof(struct ip_options_rcu) + ((optlen + 3) & ~3),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) if (!opt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) if (optlen && copy_from_sockptr(opt->opt.__data, data, optlen)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) kfree(opt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) while (optlen & 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) opt->opt.__data[optlen++] = IPOPT_END;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) opt->opt.optlen = optlen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) if (optlen && ip_options_compile(net, &opt->opt, NULL)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) kfree(opt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) kfree(*optp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) *optp = opt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) void ip_forward_options(struct sk_buff *skb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) struct ip_options *opt = &(IPCB(skb)->opt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) unsigned char *optptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) struct rtable *rt = skb_rtable(skb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) unsigned char *raw = skb_network_header(skb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) if (opt->rr_needaddr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) optptr = (unsigned char *)raw + opt->rr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) ip_rt_get_source(&optptr[optptr[2]-5], skb, rt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) opt->is_changed = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) if (opt->srr_is_hit) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) int srrptr, srrspace;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) optptr = raw + opt->srr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) for ( srrptr = optptr[2], srrspace = optptr[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) srrptr <= srrspace;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) srrptr += 4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) ) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) if (srrptr + 3 > srrspace)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) if (memcmp(&opt->nexthop, &optptr[srrptr-1], 4) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) if (srrptr + 3 <= srrspace) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) opt->is_changed = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) ip_hdr(skb)->daddr = opt->nexthop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) ip_rt_get_source(&optptr[srrptr-1], skb, rt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) optptr[2] = srrptr+4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) net_crit_ratelimited("%s(): Argh! Destination lost!\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) if (opt->ts_needaddr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) optptr = raw + opt->ts;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) ip_rt_get_source(&optptr[optptr[2]-9], skb, rt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) opt->is_changed = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) if (opt->is_changed) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) opt->is_changed = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) ip_send_check(ip_hdr(skb));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) int ip_options_rcv_srr(struct sk_buff *skb, struct net_device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) struct ip_options *opt = &(IPCB(skb)->opt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) int srrspace, srrptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) __be32 nexthop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) struct iphdr *iph = ip_hdr(skb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) unsigned char *optptr = skb_network_header(skb) + opt->srr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) struct rtable *rt = skb_rtable(skb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) struct rtable *rt2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) unsigned long orefdst;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) if (!rt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) if (skb->pkt_type != PACKET_HOST)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) if (rt->rt_type == RTN_UNICAST) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) if (!opt->is_strictroute)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) icmp_send(skb, ICMP_PARAMETERPROB, 0, htonl(16<<24));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) if (rt->rt_type != RTN_LOCAL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) for (srrptr = optptr[2], srrspace = optptr[1]; srrptr <= srrspace; srrptr += 4) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) if (srrptr + 3 > srrspace) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) icmp_send(skb, ICMP_PARAMETERPROB, 0, htonl((opt->srr+2)<<24));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) memcpy(&nexthop, &optptr[srrptr-1], 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) orefdst = skb->_skb_refdst;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) skb_dst_set(skb, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) err = ip_route_input(skb, nexthop, iph->saddr, iph->tos, dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) rt2 = skb_rtable(skb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) if (err || (rt2->rt_type != RTN_UNICAST && rt2->rt_type != RTN_LOCAL)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) skb_dst_drop(skb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) skb->_skb_refdst = orefdst;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) refdst_drop(orefdst);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) if (rt2->rt_type != RTN_LOCAL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) /* Superfast 8) loopback forward */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) iph->daddr = nexthop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) opt->is_changed = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) if (srrptr <= srrspace) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) opt->srr_is_hit = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) opt->nexthop = nexthop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) opt->is_changed = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) EXPORT_SYMBOL(ip_options_rcv_srr);