From 46d199d1e8e75c4df5689031ae0dcd47ce079a80 Mon Sep 17 00:00:00 2001 From: Steven Barth Date: Tue, 11 Jun 2013 09:27:53 +0000 Subject: [PATCH] linux: add ipv6 failed-policy routing action (by Jonas Gorski) SVN-Revision: 36911 --- ...ng-with-source-address-failed-policy.patch | 263 ++++++++++++++++++ ...ng-with-source-address-failed-policy.patch | 263 ++++++++++++++++++ ...ng-with-source-address-failed-policy.patch | 263 ++++++++++++++++++ 3 files changed, 789 insertions(+) create mode 100644 target/linux/generic/patches-3.10/670-ipv6-allow-rejecting-with-source-address-failed-policy.patch create mode 100644 target/linux/generic/patches-3.8/670-ipv6-allow-rejecting-with-source-address-failed-policy.patch create mode 100644 target/linux/generic/patches-3.9/670-ipv6-allow-rejecting-with-source-address-failed-policy.patch diff --git a/target/linux/generic/patches-3.10/670-ipv6-allow-rejecting-with-source-address-failed-policy.patch b/target/linux/generic/patches-3.10/670-ipv6-allow-rejecting-with-source-address-failed-policy.patch new file mode 100644 index 0000000000..505bc2bd53 --- /dev/null +++ b/target/linux/generic/patches-3.10/670-ipv6-allow-rejecting-with-source-address-failed-policy.patch @@ -0,0 +1,263 @@ +diff --git a/include/net/netns/ipv6.h b/include/net/netns/ipv6.h +index 005e2c2..a6a1df4 100644 +--- a/include/net/netns/ipv6.h ++++ b/include/net/netns/ipv6.h +@@ -55,6 +55,7 @@ struct netns_ipv6 { + unsigned long ip6_rt_last_gc; + #ifdef CONFIG_IPV6_MULTIPLE_TABLES + struct rt6_info *ip6_prohibit_entry; ++ struct rt6_info *ip6_failed_policy_entry; + struct rt6_info *ip6_blk_hole_entry; + struct fib6_table *fib6_local_tbl; + struct fib_rules_ops *fib6_rules_ops; +diff --git a/include/uapi/linux/fib_rules.h b/include/uapi/linux/fib_rules.h +index 51da65b..1429852 100644 +--- a/include/uapi/linux/fib_rules.h ++++ b/include/uapi/linux/fib_rules.h +@@ -64,6 +64,10 @@ enum { + FR_ACT_BLACKHOLE, /* Drop without notification */ + FR_ACT_UNREACHABLE, /* Drop with ENETUNREACH */ + FR_ACT_PROHIBIT, /* Drop with EACCES */ ++ FR_ACT_RES9, ++ FR_ACT_RES10, ++ FR_ACT_RES11, ++ FR_ACT_FAILED_POLICY, /* Drop with EPERM */ + __FR_ACT_MAX, + }; + +diff --git a/include/uapi/linux/icmpv6.h b/include/uapi/linux/icmpv6.h +index e0133c7..dabfa1a 100644 +--- a/include/uapi/linux/icmpv6.h ++++ b/include/uapi/linux/icmpv6.h +@@ -115,6 +115,7 @@ struct icmp6hdr { + #define ICMPV6_NOT_NEIGHBOUR 2 + #define ICMPV6_ADDR_UNREACH 3 + #define ICMPV6_PORT_UNREACH 4 ++#define ICMPV6_FAILED_POLICY 5 + + /* + * Codes for Time Exceeded +diff --git a/include/uapi/linux/rtnetlink.h b/include/uapi/linux/rtnetlink.h +index 7a2144e..8f643f1 100644 +--- a/include/uapi/linux/rtnetlink.h ++++ b/include/uapi/linux/rtnetlink.h +@@ -203,6 +203,7 @@ enum { + RTN_THROW, /* Not in this table */ + RTN_NAT, /* Translate this address */ + RTN_XRESOLVE, /* Use external resolver */ ++ RTN_FAILED_POLICY, /* Failed ingress/egress policy */ + __RTN_MAX + }; + +diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c +index 26aa65d..2f66341 100644 +--- a/net/ipv4/fib_rules.c ++++ b/net/ipv4/fib_rules.c +@@ -84,6 +84,10 @@ static int fib4_rule_action(struct fib_rule *rule, struct flowi *flp, + err = -EACCES; + goto errout; + ++ case FR_ACT_FAILED_POLICY: ++ err = -EPERM; ++ goto errout; ++ + case FR_ACT_BLACKHOLE: + default: + err = -EINVAL; +diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c +index 8f6cb7a..dbae75d 100644 +--- a/net/ipv4/fib_semantics.c ++++ b/net/ipv4/fib_semantics.c +@@ -138,6 +138,10 @@ const struct fib_prop fib_props[RTN_MAX + 1] = { + .error = -EINVAL, + .scope = RT_SCOPE_NOWHERE, + }, ++ [RTN_FAILED_POLICY] = { ++ .error = -EPERM, ++ .scope = RT_SCOPE_UNIVERSE, ++ }, + }; + + static void rt_fibinfo_free(struct rtable __rcu **rtp) +diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c +index 49616fe..e2845bd 100644 +--- a/net/ipv4/fib_trie.c ++++ b/net/ipv4/fib_trie.c +@@ -2334,6 +2334,7 @@ static const char *const rtn_type_names[__RTN_MAX] = { + [RTN_THROW] = "THROW", + [RTN_NAT] = "NAT", + [RTN_XRESOLVE] = "XRESOLVE", ++ [RTN_FAILED_POLICY] = "FAILED_POLICY", + }; + + static inline const char *rtn_type(char *buf, size_t len, unsigned int t) +diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c +index df97f0a..2bd33cc 100644 +--- a/net/ipv4/ipmr.c ++++ b/net/ipv4/ipmr.c +@@ -181,6 +181,7 @@ static int ipmr_rule_action(struct fib_rule *rule, struct flowi *flp, + case FR_ACT_UNREACHABLE: + return -ENETUNREACH; + case FR_ACT_PROHIBIT: ++ case FR_ACT_FAILED_POLICY: + return -EACCES; + case FR_ACT_BLACKHOLE: + default: +diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c +index 2e1a432..c4413b2 100644 +--- a/net/ipv6/fib6_rules.c ++++ b/net/ipv6/fib6_rules.c +@@ -69,6 +69,9 @@ static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp, + case FR_ACT_PROHIBIT: + rt = net->ipv6.ip6_prohibit_entry; + goto discard_pkt; ++ case FR_ACT_FAILED_POLICY: ++ rt = net->ipv6.ip6_failed_policy_entry; ++ goto discard_pkt; + } + + table = fib6_get_table(net, rule->table); +diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c +index 583e8d4..1e524da 100644 +--- a/net/ipv6/ip6mr.c ++++ b/net/ipv6/ip6mr.c +@@ -166,6 +166,8 @@ static int ip6mr_rule_action(struct fib_rule *rule, struct flowi *flp, + return -ENETUNREACH; + case FR_ACT_PROHIBIT: + return -EACCES; ++ case FR_ACT_FAILED_POLICY: ++ return -EPERM; + case FR_ACT_BLACKHOLE: + default: + return -EINVAL; +diff --git a/net/ipv6/route.c b/net/ipv6/route.c +index 2b87418..864f5fe 100644 +--- a/net/ipv6/route.c ++++ b/net/ipv6/route.c +@@ -245,6 +245,24 @@ static const struct rt6_info ip6_prohibit_entry_template = { + .rt6i_ref = ATOMIC_INIT(1), + }; + ++static int ip6_pkt_failed_policy(struct sk_buff *skb); ++static int ip6_pkt_failed_policy_out(struct sk_buff *skb); ++ ++static const struct rt6_info ip6_failed_policy_entry_template = { ++ .dst = { ++ .__refcnt = ATOMIC_INIT(1), ++ .__use = 1, ++ .obsolete = DST_OBSOLETE_FORCE_CHK, ++ .error = -EPERM, ++ .input = ip6_pkt_failed_policy, ++ .output = ip6_pkt_failed_policy_out, ++ }, ++ .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP), ++ .rt6i_protocol = RTPROT_KERNEL, ++ .rt6i_metric = ~(u32) 0, ++ .rt6i_ref = ATOMIC_INIT(1), ++}; ++ + static const struct rt6_info ip6_blk_hole_entry_template = { + .dst = { + .__refcnt = ATOMIC_INIT(1), +@@ -1459,6 +1477,9 @@ int ip6_route_add(struct fib6_config *cfg) + case RTN_THROW: + rt->dst.error = -EAGAIN; + break; ++ case RTN_FAILED_POLICY: ++ rt->dst.error = -EPERM; ++ break; + default: + rt->dst.error = -ENETUNREACH; + break; +@@ -2035,6 +2056,17 @@ static int ip6_pkt_prohibit_out(struct sk_buff *skb) + return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES); + } + ++static int ip6_pkt_failed_policy(struct sk_buff *skb) ++{ ++ return ip6_pkt_drop(skb, ICMPV6_FAILED_POLICY, IPSTATS_MIB_INNOROUTES); ++} ++ ++static int ip6_pkt_failed_policy_out(struct sk_buff *skb) ++{ ++ skb->dev = skb_dst(skb)->dev; ++ return ip6_pkt_drop(skb, ICMPV6_FAILED_POLICY, IPSTATS_MIB_OUTNOROUTES); ++} ++ + #endif + + /* +@@ -2240,7 +2272,8 @@ static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh, + if (rtm->rtm_type == RTN_UNREACHABLE || + rtm->rtm_type == RTN_BLACKHOLE || + rtm->rtm_type == RTN_PROHIBIT || +- rtm->rtm_type == RTN_THROW) ++ rtm->rtm_type == RTN_THROW || ++ rtm->rtm_type == RTN_FAILED_POLICY) + cfg->fc_flags |= RTF_REJECT; + + if (rtm->rtm_type == RTN_LOCAL) +@@ -2442,6 +2475,9 @@ static int rt6_fill_node(struct net *net, + case -EACCES: + rtm->rtm_type = RTN_PROHIBIT; + break; ++ case -EPERM: ++ rtm->rtm_type = RTN_FAILED_POLICY; ++ break; + case -EAGAIN: + rtm->rtm_type = RTN_THROW; + break; +@@ -2692,6 +2728,8 @@ static int ip6_route_dev_notify(struct notifier_block *this, + #ifdef CONFIG_IPV6_MULTIPLE_TABLES + net->ipv6.ip6_prohibit_entry->dst.dev = dev; + net->ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(dev); ++ net->ipv6.ip6_failed_policy_entry->dst.dev = dev; ++ net->ipv6.ip6_failed_policy_entry->rt6i_idev = in6_dev_get(dev); + net->ipv6.ip6_blk_hole_entry->dst.dev = dev; + net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev); + #endif +@@ -2952,6 +2990,17 @@ static int __net_init ip6_route_net_init(struct net *net) + net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops; + dst_init_metrics(&net->ipv6.ip6_blk_hole_entry->dst, + ip6_template_metrics, true); ++ ++ net->ipv6.ip6_failed_policy_entry = ++ kmemdup(&ip6_failed_policy_entry_template, ++ sizeof(*net->ipv6.ip6_failed_policy_entry), GFP_KERNEL); ++ if (!net->ipv6.ip6_failed_policy_entry) ++ goto out_ip6_blk_hole_entry; ++ net->ipv6.ip6_failed_policy_entry->dst.path = ++ (struct dst_entry *)net->ipv6.ip6_failed_policy_entry; ++ net->ipv6.ip6_failed_policy_entry->dst.ops = &net->ipv6.ip6_dst_ops; ++ dst_init_metrics(&net->ipv6.ip6_failed_policy_entry->dst, ++ ip6_template_metrics, true); + #endif + + net->ipv6.sysctl.flush_delay = 0; +@@ -2970,6 +3019,8 @@ out: + return ret; + + #ifdef CONFIG_IPV6_MULTIPLE_TABLES ++out_ip6_blk_hole_entry: ++ kfree(net->ipv6.ip6_blk_hole_entry); + out_ip6_prohibit_entry: + kfree(net->ipv6.ip6_prohibit_entry); + out_ip6_null_entry: +@@ -2987,6 +3038,7 @@ static void __net_exit ip6_route_net_exit(struct net *net) + #ifdef CONFIG_IPV6_MULTIPLE_TABLES + kfree(net->ipv6.ip6_prohibit_entry); + kfree(net->ipv6.ip6_blk_hole_entry); ++ kfree(net->ipv6.ip6_failed_policy_entry); + #endif + dst_entries_destroy(&net->ipv6.ip6_dst_ops); + } +@@ -3083,6 +3135,9 @@ int __init ip6_route_init(void) + init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); + init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev; + init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); ++ init_net.ipv6.ip6_failed_policy_entry->dst.dev = init_net.loopback_dev; ++ init_net.ipv6.ip6_failed_policy_entry->rt6i_idev = ++ in6_dev_get(init_net.loopback_dev); + #endif + ret = fib6_init(); + if (ret) diff --git a/target/linux/generic/patches-3.8/670-ipv6-allow-rejecting-with-source-address-failed-policy.patch b/target/linux/generic/patches-3.8/670-ipv6-allow-rejecting-with-source-address-failed-policy.patch new file mode 100644 index 0000000000..f4d78533e6 --- /dev/null +++ b/target/linux/generic/patches-3.8/670-ipv6-allow-rejecting-with-source-address-failed-policy.patch @@ -0,0 +1,263 @@ +Index: linux-3.8.13/include/net/netns/ipv6.h +=================================================================== +--- linux-3.8.13.orig/include/net/netns/ipv6.h 2013-06-10 14:14:20.910911309 +0200 ++++ linux-3.8.13/include/net/netns/ipv6.h 2013-06-10 14:14:20.898911309 +0200 +@@ -54,6 +54,7 @@ + unsigned long ip6_rt_last_gc; + #ifdef CONFIG_IPV6_MULTIPLE_TABLES + struct rt6_info *ip6_prohibit_entry; ++ struct rt6_info *ip6_failed_policy_entry; + struct rt6_info *ip6_blk_hole_entry; + struct fib6_table *fib6_local_tbl; + struct fib_rules_ops *fib6_rules_ops; +Index: linux-3.8.13/include/uapi/linux/fib_rules.h +=================================================================== +--- linux-3.8.13.orig/include/uapi/linux/fib_rules.h 2013-06-10 14:14:20.910911309 +0200 ++++ linux-3.8.13/include/uapi/linux/fib_rules.h 2013-06-10 14:14:20.898911309 +0200 +@@ -64,6 +64,10 @@ + FR_ACT_BLACKHOLE, /* Drop without notification */ + FR_ACT_UNREACHABLE, /* Drop with ENETUNREACH */ + FR_ACT_PROHIBIT, /* Drop with EACCES */ ++ FR_ACT_RES9, ++ FR_ACT_RES10, ++ FR_ACT_RES11, ++ FR_ACT_FAILED_POLICY, /* Drop with EPERM */ + __FR_ACT_MAX, + }; + +Index: linux-3.8.13/include/uapi/linux/icmpv6.h +=================================================================== +--- linux-3.8.13.orig/include/uapi/linux/icmpv6.h 2013-06-10 14:14:20.910911309 +0200 ++++ linux-3.8.13/include/uapi/linux/icmpv6.h 2013-06-10 14:14:20.898911309 +0200 +@@ -115,6 +115,7 @@ + #define ICMPV6_NOT_NEIGHBOUR 2 + #define ICMPV6_ADDR_UNREACH 3 + #define ICMPV6_PORT_UNREACH 4 ++#define ICMPV6_FAILED_POLICY 5 + + /* + * Codes for Time Exceeded +Index: linux-3.8.13/include/uapi/linux/rtnetlink.h +=================================================================== +--- linux-3.8.13.orig/include/uapi/linux/rtnetlink.h 2013-06-10 14:14:20.910911309 +0200 ++++ linux-3.8.13/include/uapi/linux/rtnetlink.h 2013-06-10 14:14:20.898911309 +0200 +@@ -203,6 +203,7 @@ + RTN_THROW, /* Not in this table */ + RTN_NAT, /* Translate this address */ + RTN_XRESOLVE, /* Use external resolver */ ++ RTN_FAILED_POLICY, /* Failed ingress/egress policy */ + __RTN_MAX + }; + +Index: linux-3.8.13/net/ipv4/fib_rules.c +=================================================================== +--- linux-3.8.13.orig/net/ipv4/fib_rules.c 2013-06-10 14:14:20.910911309 +0200 ++++ linux-3.8.13/net/ipv4/fib_rules.c 2013-06-10 14:14:20.898911309 +0200 +@@ -84,6 +84,10 @@ + err = -EACCES; + goto errout; + ++ case FR_ACT_FAILED_POLICY: ++ err = -EPERM; ++ goto errout; ++ + case FR_ACT_BLACKHOLE: + default: + err = -EINVAL; +Index: linux-3.8.13/net/ipv4/fib_semantics.c +=================================================================== +--- linux-3.8.13.orig/net/ipv4/fib_semantics.c 2013-06-10 14:14:20.910911309 +0200 ++++ linux-3.8.13/net/ipv4/fib_semantics.c 2013-06-10 14:14:20.898911309 +0200 +@@ -138,6 +138,10 @@ + .error = -EINVAL, + .scope = RT_SCOPE_NOWHERE, + }, ++ [RTN_FAILED_POLICY] = { ++ .error = -EPERM, ++ .scope = RT_SCOPE_UNIVERSE, ++ }, + }; + + static void rt_fibinfo_free(struct rtable __rcu **rtp) +Index: linux-3.8.13/net/ipv4/fib_trie.c +=================================================================== +--- linux-3.8.13.orig/net/ipv4/fib_trie.c 2013-06-10 14:14:20.910911309 +0200 ++++ linux-3.8.13/net/ipv4/fib_trie.c 2013-06-10 14:14:20.902911309 +0200 +@@ -2350,6 +2350,7 @@ + [RTN_THROW] = "THROW", + [RTN_NAT] = "NAT", + [RTN_XRESOLVE] = "XRESOLVE", ++ [RTN_FAILED_POLICY] = "FAILED_POLICY", + }; + + static inline const char *rtn_type(char *buf, size_t len, unsigned int t) +Index: linux-3.8.13/net/ipv4/ipmr.c +=================================================================== +--- linux-3.8.13.orig/net/ipv4/ipmr.c 2013-06-10 14:14:20.910911309 +0200 ++++ linux-3.8.13/net/ipv4/ipmr.c 2013-06-10 14:14:20.902911309 +0200 +@@ -181,6 +181,7 @@ + case FR_ACT_UNREACHABLE: + return -ENETUNREACH; + case FR_ACT_PROHIBIT: ++ case FR_ACT_FAILED_POLICY: + return -EACCES; + case FR_ACT_BLACKHOLE: + default: +Index: linux-3.8.13/net/ipv6/fib6_rules.c +=================================================================== +--- linux-3.8.13.orig/net/ipv6/fib6_rules.c 2013-06-10 14:14:20.910911309 +0200 ++++ linux-3.8.13/net/ipv6/fib6_rules.c 2013-06-10 14:14:20.902911309 +0200 +@@ -69,6 +69,9 @@ + case FR_ACT_PROHIBIT: + rt = net->ipv6.ip6_prohibit_entry; + goto discard_pkt; ++ case FR_ACT_FAILED_POLICY: ++ rt = net->ipv6.ip6_failed_policy_entry; ++ goto discard_pkt; + } + + table = fib6_get_table(net, rule->table); +Index: linux-3.8.13/net/ipv6/ip6mr.c +=================================================================== +--- linux-3.8.13.orig/net/ipv6/ip6mr.c 2013-06-10 14:14:20.910911309 +0200 ++++ linux-3.8.13/net/ipv6/ip6mr.c 2013-06-10 14:14:20.902911309 +0200 +@@ -166,6 +166,8 @@ + return -ENETUNREACH; + case FR_ACT_PROHIBIT: + return -EACCES; ++ case FR_ACT_FAILED_POLICY: ++ return -EPERM; + case FR_ACT_BLACKHOLE: + default: + return -EINVAL; +Index: linux-3.8.13/net/ipv6/route.c +=================================================================== +--- linux-3.8.13.orig/net/ipv6/route.c 2013-06-10 14:14:20.910911309 +0200 ++++ linux-3.8.13/net/ipv6/route.c 2013-06-10 14:14:20.906911309 +0200 +@@ -258,6 +258,24 @@ + .rt6i_ref = ATOMIC_INIT(1), + }; + ++static int ip6_pkt_failed_policy(struct sk_buff *skb); ++static int ip6_pkt_failed_policy_out(struct sk_buff *skb); ++ ++static const struct rt6_info ip6_failed_policy_entry_template = { ++ .dst = { ++ .__refcnt = ATOMIC_INIT(1), ++ .__use = 1, ++ .obsolete = DST_OBSOLETE_FORCE_CHK, ++ .error = -EPERM, ++ .input = ip6_pkt_failed_policy, ++ .output = ip6_pkt_failed_policy_out, ++ }, ++ .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP), ++ .rt6i_protocol = RTPROT_KERNEL, ++ .rt6i_metric = ~(u32) 0, ++ .rt6i_ref = ATOMIC_INIT(1), ++}; ++ + static const struct rt6_info ip6_blk_hole_entry_template = { + .dst = { + .__refcnt = ATOMIC_INIT(1), +@@ -1516,6 +1534,9 @@ + case RTN_THROW: + rt->dst.error = -EAGAIN; + break; ++ case RTN_FAILED_POLICY: ++ rt->dst.error = -EPERM; ++ break; + default: + rt->dst.error = -ENETUNREACH; + break; +@@ -2110,6 +2131,17 @@ + return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES); + } + ++static int ip6_pkt_failed_policy(struct sk_buff *skb) ++{ ++ return ip6_pkt_drop(skb, ICMPV6_FAILED_POLICY, IPSTATS_MIB_INNOROUTES); ++} ++ ++static int ip6_pkt_failed_policy_out(struct sk_buff *skb) ++{ ++ skb->dev = skb_dst(skb)->dev; ++ return ip6_pkt_drop(skb, ICMPV6_FAILED_POLICY, IPSTATS_MIB_OUTNOROUTES); ++} ++ + #endif + + /* +@@ -2321,7 +2353,8 @@ + if (rtm->rtm_type == RTN_UNREACHABLE || + rtm->rtm_type == RTN_BLACKHOLE || + rtm->rtm_type == RTN_PROHIBIT || +- rtm->rtm_type == RTN_THROW) ++ rtm->rtm_type == RTN_THROW || ++ rtm->rtm_type == RTN_FAILED_POLICY) + cfg->fc_flags |= RTF_REJECT; + + if (rtm->rtm_type == RTN_LOCAL) +@@ -2524,6 +2557,9 @@ + case -EACCES: + rtm->rtm_type = RTN_PROHIBIT; + break; ++ case -EPERM: ++ rtm->rtm_type = RTN_FAILED_POLICY; ++ break; + case -EAGAIN: + rtm->rtm_type = RTN_THROW; + break; +@@ -2775,6 +2811,8 @@ + #ifdef CONFIG_IPV6_MULTIPLE_TABLES + net->ipv6.ip6_prohibit_entry->dst.dev = dev; + net->ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(dev); ++ net->ipv6.ip6_failed_policy_entry->dst.dev = dev; ++ net->ipv6.ip6_failed_policy_entry->rt6i_idev = in6_dev_get(dev); + net->ipv6.ip6_blk_hole_entry->dst.dev = dev; + net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev); + #endif +@@ -3037,6 +3075,17 @@ + net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops; + dst_init_metrics(&net->ipv6.ip6_blk_hole_entry->dst, + ip6_template_metrics, true); ++ ++ net->ipv6.ip6_failed_policy_entry = ++ kmemdup(&ip6_failed_policy_entry_template, ++ sizeof(*net->ipv6.ip6_failed_policy_entry), GFP_KERNEL); ++ if (!net->ipv6.ip6_failed_policy_entry) ++ goto out_ip6_blk_hole_entry; ++ net->ipv6.ip6_failed_policy_entry->dst.path = ++ (struct dst_entry *)net->ipv6.ip6_failed_policy_entry; ++ net->ipv6.ip6_failed_policy_entry->dst.ops = &net->ipv6.ip6_dst_ops; ++ dst_init_metrics(&net->ipv6.ip6_failed_policy_entry->dst, ++ ip6_template_metrics, true); + #endif + + net->ipv6.sysctl.flush_delay = 0; +@@ -3055,6 +3104,8 @@ + return ret; + + #ifdef CONFIG_IPV6_MULTIPLE_TABLES ++out_ip6_blk_hole_entry: ++ kfree(net->ipv6.ip6_blk_hole_entry); + out_ip6_prohibit_entry: + kfree(net->ipv6.ip6_prohibit_entry); + out_ip6_null_entry: +@@ -3072,6 +3123,7 @@ + #ifdef CONFIG_IPV6_MULTIPLE_TABLES + kfree(net->ipv6.ip6_prohibit_entry); + kfree(net->ipv6.ip6_blk_hole_entry); ++ kfree(net->ipv6.ip6_failed_policy_entry); + #endif + dst_entries_destroy(&net->ipv6.ip6_dst_ops); + } +@@ -3168,6 +3220,9 @@ + init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); + init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev; + init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); ++ init_net.ipv6.ip6_failed_policy_entry->dst.dev = init_net.loopback_dev; ++ init_net.ipv6.ip6_failed_policy_entry->rt6i_idev = ++ in6_dev_get(init_net.loopback_dev); + #endif + ret = fib6_init(); + if (ret) diff --git a/target/linux/generic/patches-3.9/670-ipv6-allow-rejecting-with-source-address-failed-policy.patch b/target/linux/generic/patches-3.9/670-ipv6-allow-rejecting-with-source-address-failed-policy.patch new file mode 100644 index 0000000000..254ab670f9 --- /dev/null +++ b/target/linux/generic/patches-3.9/670-ipv6-allow-rejecting-with-source-address-failed-policy.patch @@ -0,0 +1,263 @@ +diff --git a/include/net/netns/ipv6.h b/include/net/netns/ipv6.h +index 005e2c2..a6a1df4 100644 +--- a/include/net/netns/ipv6.h ++++ b/include/net/netns/ipv6.h +@@ -55,6 +55,7 @@ struct netns_ipv6 { + unsigned long ip6_rt_last_gc; + #ifdef CONFIG_IPV6_MULTIPLE_TABLES + struct rt6_info *ip6_prohibit_entry; ++ struct rt6_info *ip6_failed_policy_entry; + struct rt6_info *ip6_blk_hole_entry; + struct fib6_table *fib6_local_tbl; + struct fib_rules_ops *fib6_rules_ops; +diff --git a/include/uapi/linux/fib_rules.h b/include/uapi/linux/fib_rules.h +index 51da65b..1429852 100644 +--- a/include/uapi/linux/fib_rules.h ++++ b/include/uapi/linux/fib_rules.h +@@ -64,6 +64,10 @@ enum { + FR_ACT_BLACKHOLE, /* Drop without notification */ + FR_ACT_UNREACHABLE, /* Drop with ENETUNREACH */ + FR_ACT_PROHIBIT, /* Drop with EACCES */ ++ FR_ACT_RES9, ++ FR_ACT_RES10, ++ FR_ACT_RES11, ++ FR_ACT_FAILED_POLICY, /* Drop with EPERM */ + __FR_ACT_MAX, + }; + +diff --git a/include/uapi/linux/icmpv6.h b/include/uapi/linux/icmpv6.h +index e0133c7..dabfa1a 100644 +--- a/include/uapi/linux/icmpv6.h ++++ b/include/uapi/linux/icmpv6.h +@@ -115,6 +115,7 @@ struct icmp6hdr { + #define ICMPV6_NOT_NEIGHBOUR 2 + #define ICMPV6_ADDR_UNREACH 3 + #define ICMPV6_PORT_UNREACH 4 ++#define ICMPV6_FAILED_POLICY 5 + + /* + * Codes for Time Exceeded +diff --git a/include/uapi/linux/rtnetlink.h b/include/uapi/linux/rtnetlink.h +index 7a2144e..8f643f1 100644 +--- a/include/uapi/linux/rtnetlink.h ++++ b/include/uapi/linux/rtnetlink.h +@@ -203,6 +203,7 @@ enum { + RTN_THROW, /* Not in this table */ + RTN_NAT, /* Translate this address */ + RTN_XRESOLVE, /* Use external resolver */ ++ RTN_FAILED_POLICY, /* Failed ingress/egress policy */ + __RTN_MAX + }; + +diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c +index 26aa65d..2f66341 100644 +--- a/net/ipv4/fib_rules.c ++++ b/net/ipv4/fib_rules.c +@@ -84,6 +84,10 @@ static int fib4_rule_action(struct fib_rule *rule, struct flowi *flp, + err = -EACCES; + goto errout; + ++ case FR_ACT_FAILED_POLICY: ++ err = -EPERM; ++ goto errout; ++ + case FR_ACT_BLACKHOLE: + default: + err = -EINVAL; +diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c +index 8f6cb7a..dbae75d 100644 +--- a/net/ipv4/fib_semantics.c ++++ b/net/ipv4/fib_semantics.c +@@ -138,6 +138,10 @@ const struct fib_prop fib_props[RTN_MAX + 1] = { + .error = -EINVAL, + .scope = RT_SCOPE_NOWHERE, + }, ++ [RTN_FAILED_POLICY] = { ++ .error = -EPERM, ++ .scope = RT_SCOPE_UNIVERSE, ++ }, + }; + + static void rt_fibinfo_free(struct rtable __rcu **rtp) +diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c +index 49616fe..e2845bd 100644 +--- a/net/ipv4/fib_trie.c ++++ b/net/ipv4/fib_trie.c +@@ -2343,6 +2343,7 @@ static const char *const rtn_type_names[__RTN_MAX] = { + [RTN_THROW] = "THROW", + [RTN_NAT] = "NAT", + [RTN_XRESOLVE] = "XRESOLVE", ++ [RTN_FAILED_POLICY] = "FAILED_POLICY", + }; + + static inline const char *rtn_type(char *buf, size_t len, unsigned int t) +diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c +index df97f0a..2bd33cc 100644 +--- a/net/ipv4/ipmr.c ++++ b/net/ipv4/ipmr.c +@@ -181,6 +181,7 @@ static int ipmr_rule_action(struct fib_rule *rule, struct flowi *flp, + case FR_ACT_UNREACHABLE: + return -ENETUNREACH; + case FR_ACT_PROHIBIT: ++ case FR_ACT_FAILED_POLICY: + return -EACCES; + case FR_ACT_BLACKHOLE: + default: +diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c +index 2e1a432..c4413b2 100644 +--- a/net/ipv6/fib6_rules.c ++++ b/net/ipv6/fib6_rules.c +@@ -69,6 +69,9 @@ static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp, + case FR_ACT_PROHIBIT: + rt = net->ipv6.ip6_prohibit_entry; + goto discard_pkt; ++ case FR_ACT_FAILED_POLICY: ++ rt = net->ipv6.ip6_failed_policy_entry; ++ goto discard_pkt; + } + + table = fib6_get_table(net, rule->table); +diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c +index 583e8d4..1e524da 100644 +--- a/net/ipv6/ip6mr.c ++++ b/net/ipv6/ip6mr.c +@@ -166,6 +166,8 @@ static int ip6mr_rule_action(struct fib_rule *rule, struct flowi *flp, + return -ENETUNREACH; + case FR_ACT_PROHIBIT: + return -EACCES; ++ case FR_ACT_FAILED_POLICY: ++ return -EPERM; + case FR_ACT_BLACKHOLE: + default: + return -EINVAL; +diff --git a/net/ipv6/route.c b/net/ipv6/route.c +index 2b87418..864f5fe 100644 +--- a/net/ipv6/route.c ++++ b/net/ipv6/route.c +@@ -245,6 +245,24 @@ static const struct rt6_info ip6_prohibit_entry_template = { + .rt6i_ref = ATOMIC_INIT(1), + }; + ++static int ip6_pkt_failed_policy(struct sk_buff *skb); ++static int ip6_pkt_failed_policy_out(struct sk_buff *skb); ++ ++static const struct rt6_info ip6_failed_policy_entry_template = { ++ .dst = { ++ .__refcnt = ATOMIC_INIT(1), ++ .__use = 1, ++ .obsolete = DST_OBSOLETE_FORCE_CHK, ++ .error = -EPERM, ++ .input = ip6_pkt_failed_policy, ++ .output = ip6_pkt_failed_policy_out, ++ }, ++ .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP), ++ .rt6i_protocol = RTPROT_KERNEL, ++ .rt6i_metric = ~(u32) 0, ++ .rt6i_ref = ATOMIC_INIT(1), ++}; ++ + static const struct rt6_info ip6_blk_hole_entry_template = { + .dst = { + .__refcnt = ATOMIC_INIT(1), +@@ -1459,6 +1477,9 @@ int ip6_route_add(struct fib6_config *cfg) + case RTN_THROW: + rt->dst.error = -EAGAIN; + break; ++ case RTN_FAILED_POLICY: ++ rt->dst.error = -EPERM; ++ break; + default: + rt->dst.error = -ENETUNREACH; + break; +@@ -2035,6 +2056,17 @@ static int ip6_pkt_prohibit_out(struct sk_buff *skb) + return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES); + } + ++static int ip6_pkt_failed_policy(struct sk_buff *skb) ++{ ++ return ip6_pkt_drop(skb, ICMPV6_FAILED_POLICY, IPSTATS_MIB_INNOROUTES); ++} ++ ++static int ip6_pkt_failed_policy_out(struct sk_buff *skb) ++{ ++ skb->dev = skb_dst(skb)->dev; ++ return ip6_pkt_drop(skb, ICMPV6_FAILED_POLICY, IPSTATS_MIB_OUTNOROUTES); ++} ++ + #endif + + /* +@@ -2240,7 +2272,8 @@ static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh, + if (rtm->rtm_type == RTN_UNREACHABLE || + rtm->rtm_type == RTN_BLACKHOLE || + rtm->rtm_type == RTN_PROHIBIT || +- rtm->rtm_type == RTN_THROW) ++ rtm->rtm_type == RTN_THROW || ++ rtm->rtm_type == RTN_FAILED_POLICY) + cfg->fc_flags |= RTF_REJECT; + + if (rtm->rtm_type == RTN_LOCAL) +@@ -2442,6 +2475,9 @@ static int rt6_fill_node(struct net *net, + case -EACCES: + rtm->rtm_type = RTN_PROHIBIT; + break; ++ case -EPERM: ++ rtm->rtm_type = RTN_FAILED_POLICY; ++ break; + case -EAGAIN: + rtm->rtm_type = RTN_THROW; + break; +@@ -2692,6 +2728,8 @@ static int ip6_route_dev_notify(struct notifier_block *this, + #ifdef CONFIG_IPV6_MULTIPLE_TABLES + net->ipv6.ip6_prohibit_entry->dst.dev = dev; + net->ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(dev); ++ net->ipv6.ip6_failed_policy_entry->dst.dev = dev; ++ net->ipv6.ip6_failed_policy_entry->rt6i_idev = in6_dev_get(dev); + net->ipv6.ip6_blk_hole_entry->dst.dev = dev; + net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev); + #endif +@@ -2952,6 +2990,17 @@ static int __net_init ip6_route_net_init(struct net *net) + net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops; + dst_init_metrics(&net->ipv6.ip6_blk_hole_entry->dst, + ip6_template_metrics, true); ++ ++ net->ipv6.ip6_failed_policy_entry = ++ kmemdup(&ip6_failed_policy_entry_template, ++ sizeof(*net->ipv6.ip6_failed_policy_entry), GFP_KERNEL); ++ if (!net->ipv6.ip6_failed_policy_entry) ++ goto out_ip6_blk_hole_entry; ++ net->ipv6.ip6_failed_policy_entry->dst.path = ++ (struct dst_entry *)net->ipv6.ip6_failed_policy_entry; ++ net->ipv6.ip6_failed_policy_entry->dst.ops = &net->ipv6.ip6_dst_ops; ++ dst_init_metrics(&net->ipv6.ip6_failed_policy_entry->dst, ++ ip6_template_metrics, true); + #endif + + net->ipv6.sysctl.flush_delay = 0; +@@ -2970,6 +3019,8 @@ out: + return ret; + + #ifdef CONFIG_IPV6_MULTIPLE_TABLES ++out_ip6_blk_hole_entry: ++ kfree(net->ipv6.ip6_blk_hole_entry); + out_ip6_prohibit_entry: + kfree(net->ipv6.ip6_prohibit_entry); + out_ip6_null_entry: +@@ -2987,6 +3038,7 @@ static void __net_exit ip6_route_net_exit(struct net *net) + #ifdef CONFIG_IPV6_MULTIPLE_TABLES + kfree(net->ipv6.ip6_prohibit_entry); + kfree(net->ipv6.ip6_blk_hole_entry); ++ kfree(net->ipv6.ip6_failed_policy_entry); + #endif + dst_entries_destroy(&net->ipv6.ip6_dst_ops); + } +@@ -3083,6 +3135,9 @@ int __init ip6_route_init(void) + init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); + init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev; + init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); ++ init_net.ipv6.ip6_failed_policy_entry->dst.dev = init_net.loopback_dev; ++ init_net.ipv6.ip6_failed_policy_entry->rt6i_idev = ++ in6_dev_get(init_net.loopback_dev); + #endif + ret = fib6_init(); + if (ret)