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