1 // SPDX-License-Identifier: GPL-2.0
3 * INET An implementation of the TCP/IP protocol suite for the LINUX
4 * operating system. INET is implemented using the BSD Socket
5 * interface as the means of communication with the user level.
7 * The options processing module for ip.c
9 * Authors: A.N.Kuznetsov
13 #define pr_fmt(fmt) "IPv4: " fmt
15 #include <linux/capability.h>
16 #include <linux/module.h>
17 #include <linux/slab.h>
18 #include <linux/types.h>
19 #include <linux/uaccess.h>
20 #include <asm/unaligned.h>
21 #include <linux/skbuff.h>
23 #include <linux/icmp.h>
24 #include <linux/netdevice.h>
25 #include <linux/rtnetlink.h>
29 #include <net/route.h>
30 #include <net/cipso_ipv4.h>
31 #include <net/ip_fib.h>
34 * Write options to IP header, record destination address to
35 * source route option, address of outgoing interface
36 * (we should already know it, so that this function is allowed be
37 * called only after routing decision) and timestamp,
38 * if we originate this datagram.
40 * daddr is real destination address, next hop is recorded in IP header.
41 * saddr is address of outgoing interface.
44 void ip_options_build(struct sk_buff
*skb
, struct ip_options
*opt
,
45 __be32 daddr
, struct rtable
*rt
, int is_frag
)
47 unsigned char *iph
= skb_network_header(skb
);
49 memcpy(&(IPCB(skb
)->opt
), opt
, sizeof(struct ip_options
));
50 memcpy(iph
+sizeof(struct iphdr
), opt
->__data
, opt
->optlen
);
51 opt
= &(IPCB(skb
)->opt
);
54 memcpy(iph
+opt
->srr
+iph
[opt
->srr
+1]-4, &daddr
, 4);
58 ip_rt_get_source(iph
+opt
->rr
+iph
[opt
->rr
+2]-5, skb
, rt
);
60 ip_rt_get_source(iph
+opt
->ts
+iph
[opt
->ts
+2]-9, skb
, rt
);
61 if (opt
->ts_needtime
) {
64 midtime
= inet_current_timestamp();
65 memcpy(iph
+opt
->ts
+iph
[opt
->ts
+2]-5, &midtime
, 4);
70 memset(iph
+opt
->rr
, IPOPT_NOP
, iph
[opt
->rr
+1]);
75 memset(iph
+opt
->ts
, IPOPT_NOP
, iph
[opt
->ts
+1]);
77 opt
->ts_needaddr
= opt
->ts_needtime
= 0;
82 * Provided (sopt, skb) points to received options,
83 * build in dopt compiled option set appropriate for answering.
84 * i.e. invert SRR option, copy anothers,
85 * and grab room in RR/TS options.
87 * NOTE: dopt cannot point to skb.
90 int __ip_options_echo(struct net
*net
, struct ip_options
*dopt
,
91 struct sk_buff
*skb
, const struct ip_options
*sopt
)
93 unsigned char *sptr
, *dptr
;
97 memset(dopt
, 0, sizeof(struct ip_options
));
99 if (sopt
->optlen
== 0)
102 sptr
= skb_network_header(skb
);
106 optlen
= sptr
[sopt
->rr
+1];
107 soffset
= sptr
[sopt
->rr
+2];
108 dopt
->rr
= dopt
->optlen
+ sizeof(struct iphdr
);
109 memcpy(dptr
, sptr
+sopt
->rr
, optlen
);
110 if (sopt
->rr_needaddr
&& soffset
<= optlen
) {
111 if (soffset
+ 3 > optlen
)
113 dptr
[2] = soffset
+ 4;
114 dopt
->rr_needaddr
= 1;
117 dopt
->optlen
+= optlen
;
120 optlen
= sptr
[sopt
->ts
+1];
121 soffset
= sptr
[sopt
->ts
+2];
122 dopt
->ts
= dopt
->optlen
+ sizeof(struct iphdr
);
123 memcpy(dptr
, sptr
+sopt
->ts
, optlen
);
124 if (soffset
<= optlen
) {
125 if (sopt
->ts_needaddr
) {
126 if (soffset
+ 3 > optlen
)
128 dopt
->ts_needaddr
= 1;
131 if (sopt
->ts_needtime
) {
132 if (soffset
+ 3 > optlen
)
134 if ((dptr
[3]&0xF) != IPOPT_TS_PRESPEC
) {
135 dopt
->ts_needtime
= 1;
138 dopt
->ts_needtime
= 0;
140 if (soffset
+ 7 <= optlen
) {
143 memcpy(&addr
, dptr
+soffset
-1, 4);
144 if (inet_addr_type(net
, addr
) != RTN_UNICAST
) {
145 dopt
->ts_needtime
= 1;
154 dopt
->optlen
+= optlen
;
157 unsigned char *start
= sptr
+sopt
->srr
;
163 if (soffset
> optlen
)
164 soffset
= optlen
+ 1;
167 memcpy(&faddr
, &start
[soffset
-1], 4);
168 for (soffset
-= 4, doffset
= 4; soffset
> 3; soffset
-= 4, doffset
+= 4)
169 memcpy(&dptr
[doffset
-1], &start
[soffset
-1], 4);
171 * RFC1812 requires to fix illegal source routes.
173 if (memcmp(&ip_hdr(skb
)->saddr
,
174 &start
[soffset
+ 3], 4) == 0)
183 dopt
->srr
= dopt
->optlen
+ sizeof(struct iphdr
);
184 dopt
->optlen
+= doffset
+3;
185 dopt
->is_strictroute
= sopt
->is_strictroute
;
189 optlen
= sptr
[sopt
->cipso
+1];
190 dopt
->cipso
= dopt
->optlen
+sizeof(struct iphdr
);
191 memcpy(dptr
, sptr
+sopt
->cipso
, optlen
);
193 dopt
->optlen
+= optlen
;
195 while (dopt
->optlen
& 3) {
203 * Options "fragmenting", just fill options not
204 * allowed in fragments with NOOPs.
205 * Simple and stupid 8), but the most efficient way.
208 void ip_options_fragment(struct sk_buff
*skb
)
210 unsigned char *optptr
= skb_network_header(skb
) + sizeof(struct iphdr
);
211 struct ip_options
*opt
= &(IPCB(skb
)->opt
);
225 if (optlen
< 2 || optlen
> l
)
227 if (!IPOPT_COPIED(*optptr
))
228 memset(optptr
, IPOPT_NOOP
, optlen
);
234 opt
->rr_needaddr
= 0;
235 opt
->ts_needaddr
= 0;
236 opt
->ts_needtime
= 0;
239 /* helper used by ip_options_compile() to call fib_compute_spec_dst()
242 static void spec_dst_fill(__be32
*spec_dst
, struct sk_buff
*skb
)
244 if (*spec_dst
== htonl(INADDR_ANY
))
245 *spec_dst
= fib_compute_spec_dst(skb
);
249 * Verify options and fill pointers in struct options.
250 * Caller should clear *opt, and set opt->data.
251 * If opt == NULL, then skb->data should point to IP header.
254 int __ip_options_compile(struct net
*net
,
255 struct ip_options
*opt
, struct sk_buff
*skb
,
258 __be32 spec_dst
= htonl(INADDR_ANY
);
259 unsigned char *pp_ptr
= NULL
;
260 struct rtable
*rt
= NULL
;
261 unsigned char *optptr
;
266 rt
= skb_rtable(skb
);
267 optptr
= (unsigned char *)&(ip_hdr(skb
)[1]);
269 optptr
= opt
->__data
;
270 iph
= optptr
- sizeof(struct iphdr
);
272 for (l
= opt
->optlen
; l
> 0; ) {
275 for (optptr
++, l
--; l
> 0; optptr
++, l
--) {
276 if (*optptr
!= IPOPT_END
) {
287 if (unlikely(l
< 2)) {
292 if (optlen
< 2 || optlen
> l
) {
307 /* NB: cf RFC-1812 5.2.4.1 */
313 if (optptr
[2] != 4 || optlen
< 7 || ((optlen
-3) & 3)) {
317 memcpy(&opt
->faddr
, &optptr
[3], 4);
319 memmove(&optptr
[3], &optptr
[7], optlen
-7);
321 opt
->is_strictroute
= (optptr
[0] == IPOPT_SSRR
);
322 opt
->srr
= optptr
- iph
;
337 if (optptr
[2] <= optlen
) {
338 if (optptr
[2]+3 > optlen
) {
343 spec_dst_fill(&spec_dst
, skb
);
344 memcpy(&optptr
[optptr
[2]-1], &spec_dst
, 4);
348 opt
->rr_needaddr
= 1;
350 opt
->rr
= optptr
- iph
;
352 case IPOPT_TIMESTAMP
:
365 if (optptr
[2] <= optlen
) {
366 unsigned char *timeptr
= NULL
;
367 if (optptr
[2]+3 > optlen
) {
371 switch (optptr
[3]&0xF) {
372 case IPOPT_TS_TSONLY
:
374 timeptr
= &optptr
[optptr
[2]-1];
375 opt
->ts_needtime
= 1;
378 case IPOPT_TS_TSANDADDR
:
379 if (optptr
[2]+7 > optlen
) {
384 spec_dst_fill(&spec_dst
, skb
);
385 memcpy(&optptr
[optptr
[2]-1], &spec_dst
, 4);
386 timeptr
= &optptr
[optptr
[2]+3];
388 opt
->ts_needaddr
= 1;
389 opt
->ts_needtime
= 1;
392 case IPOPT_TS_PRESPEC
:
393 if (optptr
[2]+7 > optlen
) {
399 memcpy(&addr
, &optptr
[optptr
[2]-1], 4);
400 if (inet_addr_type(net
, addr
) == RTN_UNICAST
)
403 timeptr
= &optptr
[optptr
[2]+3];
405 opt
->ts_needtime
= 1;
409 if (!skb
&& !ns_capable(net
->user_ns
, CAP_NET_RAW
)) {
418 midtime
= inet_current_timestamp();
419 memcpy(timeptr
, &midtime
, 4);
422 } else if ((optptr
[3]&0xF) != IPOPT_TS_PRESPEC
) {
423 unsigned int overflow
= optptr
[3]>>4;
424 if (overflow
== 15) {
429 optptr
[3] = (optptr
[3]&0xF)|((overflow
+1)<<4);
433 opt
->ts
= optptr
- iph
;
440 if (optptr
[2] == 0 && optptr
[3] == 0)
441 opt
->router_alert
= optptr
- iph
;
444 if ((!skb
&& !ns_capable(net
->user_ns
, CAP_NET_RAW
)) || opt
->cipso
) {
448 opt
->cipso
= optptr
- iph
;
449 if (cipso_v4_validate(skb
, &optptr
)) {
457 if (!skb
&& !ns_capable(net
->user_ns
, CAP_NET_RAW
)) {
473 *info
= htonl((pp_ptr
-iph
)<<24);
476 EXPORT_SYMBOL(__ip_options_compile
);
478 int ip_options_compile(struct net
*net
,
479 struct ip_options
*opt
, struct sk_buff
*skb
)
484 ret
= __ip_options_compile(net
, opt
, skb
, &info
);
486 icmp_send(skb
, ICMP_PARAMETERPROB
, 0, info
);
489 EXPORT_SYMBOL(ip_options_compile
);
492 * Undo all the changes done by ip_options_compile().
495 void ip_options_undo(struct ip_options
*opt
)
498 unsigned char *optptr
= opt
->__data
+opt
->srr
-sizeof(struct iphdr
);
499 memmove(optptr
+7, optptr
+3, optptr
[1]-7);
500 memcpy(optptr
+3, &opt
->faddr
, 4);
502 if (opt
->rr_needaddr
) {
503 unsigned char *optptr
= opt
->__data
+opt
->rr
-sizeof(struct iphdr
);
505 memset(&optptr
[optptr
[2]-1], 0, 4);
508 unsigned char *optptr
= opt
->__data
+opt
->ts
-sizeof(struct iphdr
);
509 if (opt
->ts_needtime
) {
511 memset(&optptr
[optptr
[2]-1], 0, 4);
512 if ((optptr
[3]&0xF) == IPOPT_TS_PRESPEC
)
515 if (opt
->ts_needaddr
) {
517 memset(&optptr
[optptr
[2]-1], 0, 4);
522 static struct ip_options_rcu
*ip_options_get_alloc(const int optlen
)
524 return kzalloc(sizeof(struct ip_options_rcu
) + ((optlen
+ 3) & ~3),
528 static int ip_options_get_finish(struct net
*net
, struct ip_options_rcu
**optp
,
529 struct ip_options_rcu
*opt
, int optlen
)
532 opt
->opt
.__data
[optlen
++] = IPOPT_END
;
533 opt
->opt
.optlen
= optlen
;
534 if (optlen
&& ip_options_compile(net
, &opt
->opt
, NULL
)) {
543 int ip_options_get_from_user(struct net
*net
, struct ip_options_rcu
**optp
,
544 unsigned char __user
*data
, int optlen
)
546 struct ip_options_rcu
*opt
= ip_options_get_alloc(optlen
);
550 if (optlen
&& copy_from_user(opt
->opt
.__data
, data
, optlen
)) {
554 return ip_options_get_finish(net
, optp
, opt
, optlen
);
557 int ip_options_get(struct net
*net
, struct ip_options_rcu
**optp
,
558 unsigned char *data
, int optlen
)
560 struct ip_options_rcu
*opt
= ip_options_get_alloc(optlen
);
565 memcpy(opt
->opt
.__data
, data
, optlen
);
566 return ip_options_get_finish(net
, optp
, opt
, optlen
);
569 void ip_forward_options(struct sk_buff
*skb
)
571 struct ip_options
*opt
= &(IPCB(skb
)->opt
);
572 unsigned char *optptr
;
573 struct rtable
*rt
= skb_rtable(skb
);
574 unsigned char *raw
= skb_network_header(skb
);
576 if (opt
->rr_needaddr
) {
577 optptr
= (unsigned char *)raw
+ opt
->rr
;
578 ip_rt_get_source(&optptr
[optptr
[2]-5], skb
, rt
);
581 if (opt
->srr_is_hit
) {
582 int srrptr
, srrspace
;
584 optptr
= raw
+ opt
->srr
;
586 for ( srrptr
= optptr
[2], srrspace
= optptr
[1];
590 if (srrptr
+ 3 > srrspace
)
592 if (memcmp(&opt
->nexthop
, &optptr
[srrptr
-1], 4) == 0)
595 if (srrptr
+ 3 <= srrspace
) {
597 ip_hdr(skb
)->daddr
= opt
->nexthop
;
598 ip_rt_get_source(&optptr
[srrptr
-1], skb
, rt
);
599 optptr
[2] = srrptr
+4;
601 net_crit_ratelimited("%s(): Argh! Destination lost!\n",
604 if (opt
->ts_needaddr
) {
605 optptr
= raw
+ opt
->ts
;
606 ip_rt_get_source(&optptr
[optptr
[2]-9], skb
, rt
);
610 if (opt
->is_changed
) {
612 ip_send_check(ip_hdr(skb
));
616 int ip_options_rcv_srr(struct sk_buff
*skb
, struct net_device
*dev
)
618 struct ip_options
*opt
= &(IPCB(skb
)->opt
);
619 int srrspace
, srrptr
;
621 struct iphdr
*iph
= ip_hdr(skb
);
622 unsigned char *optptr
= skb_network_header(skb
) + opt
->srr
;
623 struct rtable
*rt
= skb_rtable(skb
);
625 unsigned long orefdst
;
631 if (skb
->pkt_type
!= PACKET_HOST
)
633 if (rt
->rt_type
== RTN_UNICAST
) {
634 if (!opt
->is_strictroute
)
636 icmp_send(skb
, ICMP_PARAMETERPROB
, 0, htonl(16<<24));
639 if (rt
->rt_type
!= RTN_LOCAL
)
642 for (srrptr
= optptr
[2], srrspace
= optptr
[1]; srrptr
<= srrspace
; srrptr
+= 4) {
643 if (srrptr
+ 3 > srrspace
) {
644 icmp_send(skb
, ICMP_PARAMETERPROB
, 0, htonl((opt
->srr
+2)<<24));
647 memcpy(&nexthop
, &optptr
[srrptr
-1], 4);
649 orefdst
= skb
->_skb_refdst
;
650 skb_dst_set(skb
, NULL
);
651 err
= ip_route_input(skb
, nexthop
, iph
->saddr
, iph
->tos
, dev
);
652 rt2
= skb_rtable(skb
);
653 if (err
|| (rt2
->rt_type
!= RTN_UNICAST
&& rt2
->rt_type
!= RTN_LOCAL
)) {
655 skb
->_skb_refdst
= orefdst
;
658 refdst_drop(orefdst
);
659 if (rt2
->rt_type
!= RTN_LOCAL
)
661 /* Superfast 8) loopback forward */
662 iph
->daddr
= nexthop
;
665 if (srrptr
<= srrspace
) {
667 opt
->nexthop
= nexthop
;
672 EXPORT_SYMBOL(ip_options_rcv_srr
);