1 /* IPv4 specific functions of netfilter core */ 2 3 #include <linux/config.h> 4 #ifdef CONFIG_NETFILTER 5 6 #include <linux/kernel.h> 7 #include <linux/netfilter.h> 8 #include <linux/netfilter_ipv4.h> 9 10 #include <linux/tcp.h> 11 #include <linux/udp.h> 12 #include <linux/icmp.h> 13 #include <net/route.h> 14 #include <linux/ip.h> 15 16 /* route_me_harder function, used by iptable_nat, iptable_mangle + ip_queue */ 17 int ip_route_me_harder(struct sk_buff **pskb) 18 { 19 struct iphdr *iph = (*pskb)->nh.iph; 20 struct rtable *rt; 21 struct flowi fl = {}; 22 struct dst_entry *odst; 23 unsigned int hh_len; 24 25 /* some non-standard hacks like ipt_REJECT.c:send_reset() can cause 26 * packets with foreign saddr to appear on the NF_IP_LOCAL_OUT hook. 27 */ 28 if (inet_addr_type(iph->saddr) == RTN_LOCAL) { 29 fl.nl_u.ip4_u.daddr = iph->daddr; 30 fl.nl_u.ip4_u.saddr = iph->saddr; 31 fl.nl_u.ip4_u.tos = RT_TOS(iph->tos); 32 fl.oif = (*pskb)->sk ? (*pskb)->sk->sk_bound_dev_if : 0; 33 #ifdef CONFIG_IP_ROUTE_FWMARK 34 fl.nl_u.ip4_u.fwmark = (*pskb)->nfmark; 35 #endif 36 fl.proto = iph->protocol; 37 if (ip_route_output_key(&rt, &fl) != 0) 38 return -1; 39 40 /* Drop old route. */ 41 dst_release((*pskb)->dst); 42 (*pskb)->dst = &rt->u.dst; 43 } else { 44 /* non-local src, find valid iif to satisfy 45 * rp-filter when calling ip_route_input. */ 46 fl.nl_u.ip4_u.daddr = iph->saddr; 47 if (ip_route_output_key(&rt, &fl) != 0) 48 return -1; 49 50 odst = (*pskb)->dst; 51 if (ip_route_input(*pskb, iph->daddr, iph->saddr, 52 RT_TOS(iph->tos), rt->u.dst.dev) != 0) { 53 dst_release(&rt->u.dst); 54 return -1; 55 } 56 dst_release(&rt->u.dst); 57 dst_release(odst); 58 } 59 60 if ((*pskb)->dst->error) 61 return -1; 62 63 /* Change in oif may mean change in hh_len. */ 64 hh_len = (*pskb)->dst->dev->hard_header_len; 65 if (skb_headroom(*pskb) < hh_len) { 66 struct sk_buff *nskb; 67 68 nskb = skb_realloc_headroom(*pskb, hh_len); 69 if (!nskb) 70 return -1; 71 if ((*pskb)->sk) 72 skb_set_owner_w(nskb, (*pskb)->sk); 73 kfree_skb(*pskb); 74 *pskb = nskb; 75 } 76 77 return 0; 78 } 79 EXPORT_SYMBOL(ip_route_me_harder); 80 81 /* 82 * Extra routing may needed on local out, as the QUEUE target never 83 * returns control to the table. 84 */ 85 86 struct ip_rt_info { 87 u_int32_t daddr; 88 u_int32_t saddr; 89 u_int8_t tos; 90 }; 91 92 static void queue_save(const struct sk_buff *skb, struct nf_info *info) 93 { 94 struct ip_rt_info *rt_info = nf_info_reroute(info); 95 96 if (info->hook == NF_IP_LOCAL_OUT) { 97 const struct iphdr *iph = skb->nh.iph; 98 99 rt_info->tos = iph->tos; 100 rt_info->daddr = iph->daddr; 101 rt_info->saddr = iph->saddr; 102 } 103 } 104 105 static int queue_reroute(struct sk_buff **pskb, const struct nf_info *info) 106 { 107 const struct ip_rt_info *rt_info = nf_info_reroute(info); 108 109 if (info->hook == NF_IP_LOCAL_OUT) { 110 struct iphdr *iph = (*pskb)->nh.iph; 111 112 if (!(iph->tos == rt_info->tos 113 && iph->daddr == rt_info->daddr 114 && iph->saddr == rt_info->saddr)) 115 return ip_route_me_harder(pskb); 116 } 117 return 0; 118 } 119 120 static struct nf_queue_rerouter ip_reroute = { 121 .rer_size = sizeof(struct ip_rt_info), 122 .save = queue_save, 123 .reroute = queue_reroute, 124 }; 125 126 static int init(void) 127 { 128 return nf_register_queue_rerouter(PF_INET, &ip_reroute); 129 } 130 131 static void fini(void) 132 { 133 nf_unregister_queue_rerouter(PF_INET); 134 } 135 136 module_init(init); 137 module_exit(fini); 138 139 #endif /* CONFIG_NETFILTER */ 140