Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0
2 : : /*
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.
6 : : *
7 : : * The IP forwarding functionality.
8 : : *
9 : : * Authors: see ip.c
10 : : *
11 : : * Fixes:
12 : : * Many : Split from ip.c , see ip_input.c for
13 : : * history.
14 : : * Dave Gregorich : NULL ip_rt_put fix for multicast
15 : : * routing.
16 : : * Jos Vos : Add call_out_firewall before sending,
17 : : * use output device for accounting.
18 : : * Jos Vos : Call forward firewall after routing
19 : : * (always use output device).
20 : : * Mike McLagan : Routing by source
21 : : */
22 : :
23 : : #include <linux/types.h>
24 : : #include <linux/mm.h>
25 : : #include <linux/skbuff.h>
26 : : #include <linux/ip.h>
27 : : #include <linux/icmp.h>
28 : : #include <linux/netdevice.h>
29 : : #include <linux/slab.h>
30 : : #include <net/sock.h>
31 : : #include <net/ip.h>
32 : : #include <net/tcp.h>
33 : : #include <net/udp.h>
34 : : #include <net/icmp.h>
35 : : #include <linux/tcp.h>
36 : : #include <linux/udp.h>
37 : : #include <linux/netfilter_ipv4.h>
38 : : #include <net/checksum.h>
39 : : #include <linux/route.h>
40 : : #include <net/route.h>
41 : : #include <net/xfrm.h>
42 : :
43 : 0 : static bool ip_exceeds_mtu(const struct sk_buff *skb, unsigned int mtu)
44 : : {
45 [ # # ]: 0 : if (skb->len <= mtu)
46 : : return false;
47 : :
48 [ # # ]: 0 : if (unlikely((ip_hdr(skb)->frag_off & htons(IP_DF)) == 0))
49 : : return false;
50 : :
51 : : /* original fragment exceeds mtu and DF is set */
52 [ # # ]: 0 : if (unlikely(IPCB(skb)->frag_max_size > mtu))
53 : : return true;
54 : :
55 [ # # ]: 0 : if (skb->ignore_df)
56 : : return false;
57 : :
58 [ # # # # ]: 0 : if (skb_is_gso(skb) && skb_gso_validate_network_len(skb, mtu))
59 : 0 : return false;
60 : :
61 : : return true;
62 : : }
63 : :
64 : :
65 : 0 : static int ip_forward_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
66 : : {
67 : 0 : struct ip_options *opt = &(IPCB(skb)->opt);
68 : :
69 [ # # ]: 0 : __IP_INC_STATS(net, IPSTATS_MIB_OUTFORWDATAGRAMS);
70 [ # # # # : 0 : __IP_ADD_STATS(net, IPSTATS_MIB_OUTOCTETS, skb->len);
# # # # ]
71 : :
72 : : #ifdef CONFIG_NET_SWITCHDEV
73 : : if (skb->offload_l3_fwd_mark) {
74 : : consume_skb(skb);
75 : : return 0;
76 : : }
77 : : #endif
78 : :
79 [ # # ]: 0 : if (unlikely(opt->optlen))
80 : 0 : ip_forward_options(skb);
81 : :
82 : 0 : skb->tstamp = 0;
83 : 0 : return dst_output(net, sk, skb);
84 : : }
85 : :
86 : 0 : int ip_forward(struct sk_buff *skb)
87 : : {
88 : 0 : u32 mtu;
89 : 0 : struct iphdr *iph; /* Our header */
90 : 0 : struct rtable *rt; /* Route we use */
91 : 0 : struct ip_options *opt = &(IPCB(skb)->opt);
92 : 0 : struct net *net;
93 : :
94 : : /* that should never happen */
95 [ # # ]: 0 : if (skb->pkt_type != PACKET_HOST)
96 : 0 : goto drop;
97 : :
98 [ # # ]: 0 : if (unlikely(skb->sk))
99 : 0 : goto drop;
100 : :
101 [ # # ]: 0 : if (skb_warn_if_lro(skb))
102 : 0 : goto drop;
103 : :
104 [ # # ]: 0 : if (!xfrm4_policy_check(NULL, XFRM_POLICY_FWD, skb))
105 : 0 : goto drop;
106 : :
107 [ # # # # ]: 0 : if (IPCB(skb)->opt.router_alert && ip_call_ra_chain(skb))
108 : : return NET_RX_SUCCESS;
109 : :
110 [ # # ]: 0 : skb_forward_csum(skb);
111 [ # # ]: 0 : net = dev_net(skb->dev);
112 : :
113 : : /*
114 : : * According to the RFC, we must first decrease the TTL field. If
115 : : * that reaches zero, we must reply an ICMP control message telling
116 : : * that the packet's lifetime expired.
117 : : */
118 [ # # ]: 0 : if (ip_hdr(skb)->ttl <= 1)
119 : 0 : goto too_many_hops;
120 : :
121 [ # # ]: 0 : if (!xfrm4_route_forward(skb))
122 : 0 : goto drop;
123 : :
124 [ # # ]: 0 : rt = skb_rtable(skb);
125 : :
126 [ # # # # ]: 0 : if (opt->is_strictroute && rt->rt_uses_gateway)
127 : 0 : goto sr_failed;
128 : :
129 : 0 : IPCB(skb)->flags |= IPSKB_FORWARDED;
130 : 0 : mtu = ip_dst_mtu_maybe_forward(&rt->dst, true);
131 [ # # ]: 0 : if (ip_exceeds_mtu(skb, mtu)) {
132 : 0 : IP_INC_STATS(net, IPSTATS_MIB_FRAGFAILS);
133 : 0 : icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
134 : : htonl(mtu));
135 : 0 : goto drop;
136 : : }
137 : :
138 : : /* We are about to mangle packet. Copy it! */
139 [ # # ]: 0 : if (skb_cow(skb, LL_RESERVED_SPACE(rt->dst.dev)+rt->dst.header_len))
140 : 0 : goto drop;
141 [ # # ]: 0 : iph = ip_hdr(skb);
142 : :
143 : : /* Decrease ttl after skb cow done */
144 [ # # ]: 0 : ip_decrease_ttl(iph);
145 : :
146 : : /*
147 : : * We now generate an ICMP HOST REDIRECT giving the route
148 : : * we calculated.
149 : : */
150 [ # # # # : 0 : if (IPCB(skb)->flags & IPSKB_DOREDIRECT && !opt->srr &&
# # ]
151 : : !skb_sec_path(skb))
152 : 0 : ip_rt_send_redirect(skb);
153 : :
154 [ # # ]: 0 : if (net->ipv4.sysctl_ip_fwd_update_priority)
155 : 0 : skb->priority = rt_tos2priority(iph->tos);
156 : :
157 : 0 : return NF_HOOK(NFPROTO_IPV4, NF_INET_FORWARD,
158 : : net, NULL, skb, skb->dev, rt->dst.dev,
159 : : ip_forward_finish);
160 : :
161 : : sr_failed:
162 : : /*
163 : : * Strict routing permits no gatewaying
164 : : */
165 : 0 : icmp_send(skb, ICMP_DEST_UNREACH, ICMP_SR_FAILED, 0);
166 : 0 : goto drop;
167 : :
168 : : too_many_hops:
169 : : /* Tell the sender its packet died... */
170 : 0 : __IP_INC_STATS(net, IPSTATS_MIB_INHDRERRORS);
171 : 0 : icmp_send(skb, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL, 0);
172 : 0 : drop:
173 : 0 : kfree_skb(skb);
174 : 0 : return NET_RX_DROP;
175 : : }
|