Skip to content

Commit 5adf6f2

Browse files
author
Paolo Abeni
committed
Merge branch 'ipv4-icmp-fix-source-ip-derivation-in-presence-of-vrfs'
Ido Schimmel says: ==================== ipv4: icmp: Fix source IP derivation in presence of VRFs Align IPv4 with IPv6 and in the presence of VRFs generate ICMP error messages with a source IP that is derived from the receiving interface and not from its VRF master. This is especially important when the error messages are "Time Exceeded" messages as it means that utilities like traceroute will show an incorrect packet path. Patches kernel-patches#1-kernel-patches#2 are preparations. Patch kernel-patches#3 is the actual change. Patches kernel-patches#4-kernel-patches#7 make small improvements in the existing traceroute test. Patch kernel-patches#8 extends the traceroute test with VRF test cases for both IPv4 and IPv6. Changes since v1 [1]: * Rebase. [1] https://lore.kernel.org/netdev/[email protected]/ ==================== Link: https://patch.msgid.link/[email protected] Signed-off-by: Paolo Abeni <[email protected]>
2 parents 7f0b763 + f724099 commit 5adf6f2

File tree

5 files changed

+229
-69
lines changed

5 files changed

+229
-69
lines changed

include/net/icmp.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,19 +37,21 @@ struct sk_buff;
3737
struct net;
3838

3939
void __icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info,
40-
const struct ip_options *opt);
40+
const struct inet_skb_parm *parm);
4141
static inline void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info)
4242
{
43-
__icmp_send(skb_in, type, code, info, &IPCB(skb_in)->opt);
43+
__icmp_send(skb_in, type, code, info, IPCB(skb_in));
4444
}
4545

4646
#if IS_ENABLED(CONFIG_NF_NAT)
4747
void icmp_ndo_send(struct sk_buff *skb_in, int type, int code, __be32 info);
4848
#else
4949
static inline void icmp_ndo_send(struct sk_buff *skb_in, int type, int code, __be32 info)
5050
{
51-
struct ip_options opts = { 0 };
52-
__icmp_send(skb_in, type, code, info, &opts);
51+
struct inet_skb_parm parm;
52+
53+
memset(&parm, 0, sizeof(parm));
54+
__icmp_send(skb_in, type, code, info, &parm);
5355
}
5456
#endif
5557

net/ipv4/cipso_ipv4.c

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1715,8 +1715,7 @@ int cipso_v4_validate(const struct sk_buff *skb, unsigned char **option)
17151715
*/
17161716
void cipso_v4_error(struct sk_buff *skb, int error, u32 gateway)
17171717
{
1718-
unsigned char optbuf[sizeof(struct ip_options) + 40];
1719-
struct ip_options *opt = (struct ip_options *)optbuf;
1718+
struct inet_skb_parm parm;
17201719
int res;
17211720

17221721
if (ip_hdr(skb)->protocol == IPPROTO_ICMP || error != -EACCES)
@@ -1727,19 +1726,19 @@ void cipso_v4_error(struct sk_buff *skb, int error, u32 gateway)
17271726
* so we can not use icmp_send and IPCB here.
17281727
*/
17291728

1730-
memset(opt, 0, sizeof(struct ip_options));
1731-
opt->optlen = ip_hdr(skb)->ihl*4 - sizeof(struct iphdr);
1729+
memset(&parm, 0, sizeof(parm));
1730+
parm.opt.optlen = ip_hdr(skb)->ihl * 4 - sizeof(struct iphdr);
17321731
rcu_read_lock();
1733-
res = __ip_options_compile(dev_net(skb->dev), opt, skb, NULL);
1732+
res = __ip_options_compile(dev_net(skb->dev), &parm.opt, skb, NULL);
17341733
rcu_read_unlock();
17351734

17361735
if (res)
17371736
return;
17381737

17391738
if (gateway)
1740-
__icmp_send(skb, ICMP_DEST_UNREACH, ICMP_NET_ANO, 0, opt);
1739+
__icmp_send(skb, ICMP_DEST_UNREACH, ICMP_NET_ANO, 0, &parm);
17411740
else
1742-
__icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_ANO, 0, opt);
1741+
__icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_ANO, 0, &parm);
17431742
}
17441743

17451744
/**

net/ipv4/icmp.c

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -594,7 +594,7 @@ static struct rtable *icmp_route_lookup(struct net *net, struct flowi4 *fl4,
594594
*/
595595

596596
void __icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info,
597-
const struct ip_options *opt)
597+
const struct inet_skb_parm *parm)
598598
{
599599
struct iphdr *iph;
600600
int room;
@@ -710,7 +710,8 @@ void __icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info,
710710
rcu_read_lock();
711711
if (rt_is_input_route(rt) &&
712712
READ_ONCE(net->ipv4.sysctl_icmp_errors_use_inbound_ifaddr))
713-
dev = dev_get_by_index_rcu(net, inet_iif(skb_in));
713+
dev = dev_get_by_index_rcu(net, parm->iif ? parm->iif :
714+
inet_iif(skb_in));
714715

715716
if (dev)
716717
saddr = inet_select_addr(dev, iph->saddr,
@@ -725,7 +726,8 @@ void __icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info,
725726
iph->tos;
726727
mark = IP4_REPLY_MARK(net, skb_in->mark);
727728

728-
if (__ip_options_echo(net, &icmp_param.replyopts.opt.opt, skb_in, opt))
729+
if (__ip_options_echo(net, &icmp_param.replyopts.opt.opt, skb_in,
730+
&parm->opt))
729731
goto out_unlock;
730732

731733

@@ -799,15 +801,16 @@ EXPORT_SYMBOL(__icmp_send);
799801
void icmp_ndo_send(struct sk_buff *skb_in, int type, int code, __be32 info)
800802
{
801803
struct sk_buff *cloned_skb = NULL;
802-
struct ip_options opts = { 0 };
803804
enum ip_conntrack_info ctinfo;
804805
enum ip_conntrack_dir dir;
806+
struct inet_skb_parm parm;
805807
struct nf_conn *ct;
806808
__be32 orig_ip;
807809

810+
memset(&parm, 0, sizeof(parm));
808811
ct = nf_ct_get(skb_in, &ctinfo);
809812
if (!ct || !(READ_ONCE(ct->status) & IPS_NAT_MASK)) {
810-
__icmp_send(skb_in, type, code, info, &opts);
813+
__icmp_send(skb_in, type, code, info, &parm);
811814
return;
812815
}
813816

@@ -823,7 +826,7 @@ void icmp_ndo_send(struct sk_buff *skb_in, int type, int code, __be32 info)
823826
orig_ip = ip_hdr(skb_in)->saddr;
824827
dir = CTINFO2DIR(ctinfo);
825828
ip_hdr(skb_in)->saddr = ct->tuplehash[dir].tuple.src.u3.ip;
826-
__icmp_send(skb_in, type, code, info, &opts);
829+
__icmp_send(skb_in, type, code, info, &parm);
827830
ip_hdr(skb_in)->saddr = orig_ip;
828831
out:
829832
consume_skb(cloned_skb);

net/ipv4/route.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1222,8 +1222,8 @@ EXPORT_INDIRECT_CALLABLE(ipv4_dst_check);
12221222

12231223
static void ipv4_send_dest_unreach(struct sk_buff *skb)
12241224
{
1225+
struct inet_skb_parm parm;
12251226
struct net_device *dev;
1226-
struct ip_options opt;
12271227
int res;
12281228

12291229
/* Recompile ip options since IPCB may not be valid anymore.
@@ -1233,21 +1233,21 @@ static void ipv4_send_dest_unreach(struct sk_buff *skb)
12331233
ip_hdr(skb)->version != 4 || ip_hdr(skb)->ihl < 5)
12341234
return;
12351235

1236-
memset(&opt, 0, sizeof(opt));
1236+
memset(&parm, 0, sizeof(parm));
12371237
if (ip_hdr(skb)->ihl > 5) {
12381238
if (!pskb_network_may_pull(skb, ip_hdr(skb)->ihl * 4))
12391239
return;
1240-
opt.optlen = ip_hdr(skb)->ihl * 4 - sizeof(struct iphdr);
1240+
parm.opt.optlen = ip_hdr(skb)->ihl * 4 - sizeof(struct iphdr);
12411241

12421242
rcu_read_lock();
12431243
dev = skb->dev ? skb->dev : skb_rtable(skb)->dst.dev;
1244-
res = __ip_options_compile(dev_net(dev), &opt, skb, NULL);
1244+
res = __ip_options_compile(dev_net(dev), &parm.opt, skb, NULL);
12451245
rcu_read_unlock();
12461246

12471247
if (res)
12481248
return;
12491249
}
1250-
__icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0, &opt);
1250+
__icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0, &parm);
12511251
}
12521252

12531253
static void ipv4_link_failure(struct sk_buff *skb)

0 commit comments

Comments
 (0)