mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-29 19:21:31 -04:00
ipv4: introduce ip_dst_mtu_maybe_forward and protect forwarding path against pmtu spoofing
While forwarding we should not use the protocol path mtu to calculate the mtu for a forwarded packet but instead use the interface mtu. We mark forwarded skbs in ip_forward with IPSKB_FORWARDED, which was introduced for multicast forwarding. But as it does not conflict with our usage in unicast code path it is perfect for reuse. I moved the functions ip_sk_accept_pmtu, ip_sk_use_pmtu and ip_skb_dst_mtu along with the new ip_dst_mtu_maybe_forward to net/ip.h to fix circular dependencies because of IPSKB_FORWARDED. Because someone might have written a software which does probe destinations manually and expects the kernel to honour those path mtus I introduced a new per-namespace "ip_forward_use_pmtu" knob so someone can disable this new behaviour. We also still use mtus which are locked on a route for forwarding. The reason for this change is, that path mtus information can be injected into the kernel via e.g. icmp_err protocol handler without verification of local sockets. As such, this could cause the IPv4 forwarding path to wrongfully emit fragmentation needed notifications or start to fragment packets along a path. Tunnel and ipsec output paths clear IPCB again, thus IPSKB_FORWARDED won't be set and further fragmentation logic will use the path mtu to determine the fragmentation size. They also recheck packet size with help of path mtu discovery and report appropriate errors. Cc: Eric Dumazet <[email protected]> Cc: David Miller <[email protected]> Cc: John Heffner <[email protected]> Cc: Steffen Klassert <[email protected]> Signed-off-by: Hannes Frederic Sowa <[email protected]> Signed-off-by: David S. Miller <[email protected]>
This commit is contained in:
parent
6c76a07a71
commit
f87c10a8aa
8 changed files with 67 additions and 24 deletions
|
|
@ -54,6 +54,7 @@ static int ip_forward_finish(struct sk_buff *skb)
|
|||
|
||||
int ip_forward(struct sk_buff *skb)
|
||||
{
|
||||
u32 mtu;
|
||||
struct iphdr *iph; /* Our header */
|
||||
struct rtable *rt; /* Route we use */
|
||||
struct ip_options *opt = &(IPCB(skb)->opt);
|
||||
|
|
@ -88,11 +89,13 @@ int ip_forward(struct sk_buff *skb)
|
|||
if (opt->is_strictroute && rt->rt_uses_gateway)
|
||||
goto sr_failed;
|
||||
|
||||
if (unlikely(skb->len > dst_mtu(&rt->dst) && !skb_is_gso(skb) &&
|
||||
IPCB(skb)->flags |= IPSKB_FORWARDED;
|
||||
mtu = ip_dst_mtu_maybe_forward(&rt->dst, true);
|
||||
if (unlikely(skb->len > mtu && !skb_is_gso(skb) &&
|
||||
(ip_hdr(skb)->frag_off & htons(IP_DF))) && !skb->local_df) {
|
||||
IP_INC_STATS(dev_net(rt->dst.dev), IPSTATS_MIB_FRAGFAILS);
|
||||
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
|
||||
htonl(dst_mtu(&rt->dst)));
|
||||
htonl(mtu));
|
||||
goto drop;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -449,6 +449,7 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
|
|||
__be16 not_last_frag;
|
||||
struct rtable *rt = skb_rtable(skb);
|
||||
int err = 0;
|
||||
bool forwarding = IPCB(skb)->flags & IPSKB_FORWARDED;
|
||||
|
||||
dev = rt->dst.dev;
|
||||
|
||||
|
|
@ -458,12 +459,13 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
|
|||
|
||||
iph = ip_hdr(skb);
|
||||
|
||||
mtu = ip_dst_mtu_maybe_forward(&rt->dst, forwarding);
|
||||
if (unlikely(((iph->frag_off & htons(IP_DF)) && !skb->local_df) ||
|
||||
(IPCB(skb)->frag_max_size &&
|
||||
IPCB(skb)->frag_max_size > dst_mtu(&rt->dst)))) {
|
||||
IPCB(skb)->frag_max_size > mtu))) {
|
||||
IP_INC_STATS(dev_net(dev), IPSTATS_MIB_FRAGFAILS);
|
||||
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
|
||||
htonl(ip_skb_dst_mtu(skb)));
|
||||
htonl(mtu));
|
||||
kfree_skb(skb);
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
|
@ -473,7 +475,7 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
|
|||
*/
|
||||
|
||||
hlen = iph->ihl * 4;
|
||||
mtu = dst_mtu(&rt->dst) - hlen; /* Size of data space */
|
||||
mtu = mtu - hlen; /* Size of data space */
|
||||
#ifdef CONFIG_BRIDGE_NETFILTER
|
||||
if (skb->nf_bridge)
|
||||
mtu -= nf_bridge_mtu_reduction(skb);
|
||||
|
|
|
|||
|
|
@ -112,9 +112,6 @@
|
|||
#define RT_FL_TOS(oldflp4) \
|
||||
((oldflp4)->flowi4_tos & (IPTOS_RT_MASK | RTO_ONLINK))
|
||||
|
||||
/* IPv4 datagram length is stored into 16bit field (tot_len) */
|
||||
#define IP_MAX_MTU 0xFFFF
|
||||
|
||||
#define RT_GC_TIMEOUT (300*HZ)
|
||||
|
||||
static int ip_rt_max_size;
|
||||
|
|
|
|||
|
|
@ -831,6 +831,13 @@ static struct ctl_table ipv4_net_table[] = {
|
|||
.mode = 0644,
|
||||
.proc_handler = proc_dointvec
|
||||
},
|
||||
{
|
||||
.procname = "ip_forward_use_pmtu",
|
||||
.data = &init_net.ipv4.sysctl_ip_fwd_use_pmtu,
|
||||
.maxlen = sizeof(int),
|
||||
.mode = 0644,
|
||||
.proc_handler = proc_dointvec,
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue