1/* IPv4 specific functions of netfilter core */ 2#include <linux/kernel.h> 3#include <linux/netfilter.h> 4#include <linux/netfilter_ipv4.h> 5#include <linux/ip.h> 6#include <net/route.h> 7#include <net/xfrm.h> 8#include <net/ip.h> 9 10/* route_me_harder function, used by iptable_nat, iptable_mangle + ip_queue */ 11int ip_route_me_harder(struct sk_buff **pskb, unsigned addr_type) 12{ 13 const struct iphdr *iph = ip_hdr(*pskb); 14 struct rtable *rt; 15 struct flowi fl = {}; 16 struct dst_entry *odst; 17 unsigned int hh_len; 18 unsigned int type; 19 20 type = inet_addr_type(iph->saddr); 21 if (addr_type == RTN_UNSPEC) 22 addr_type = type; 23 24 /* some non-standard hacks like ipt_REJECT.c:send_reset() can cause 25 * packets with foreign saddr to appear on the NF_IP_LOCAL_OUT hook. 26 */ 27 if (addr_type == RTN_LOCAL) { 28 fl.nl_u.ip4_u.daddr = iph->daddr; 29 if (type == RTN_LOCAL) 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 fl.mark = (*pskb)->mark; 34 if (ip_route_output_key(&rt, &fl) != 0) 35 return -1; 36 37 /* Drop old route. */ 38 dst_release((*pskb)->dst); 39 (*pskb)->dst = &rt->u.dst; 40 } else { 41 /* non-local src, find valid iif to satisfy 42 * rp-filter when calling ip_route_input. */ 43 fl.nl_u.ip4_u.daddr = iph->saddr; 44 if (ip_route_output_key(&rt, &fl) != 0) 45 return -1; 46 47 odst = (*pskb)->dst; 48 if (ip_route_input(*pskb, iph->daddr, iph->saddr, 49 RT_TOS(iph->tos), rt->u.dst.dev) != 0) { 50 dst_release(&rt->u.dst); 51 return -1; 52 } 53 dst_release(&rt->u.dst); 54 dst_release(odst); 55 } 56 57 if ((*pskb)->dst->error) 58 return -1; 59 60#ifdef CONFIG_XFRM 61 if (!(IPCB(*pskb)->flags & IPSKB_XFRM_TRANSFORMED) && 62 xfrm_decode_session(*pskb, &fl, AF_INET) == 0) 63 if (xfrm_lookup(&(*pskb)->dst, &fl, (*pskb)->sk, 0)) 64 return -1; 65#endif 66 67 /* Change in oif may mean change in hh_len. */ 68 hh_len = (*pskb)->dst->dev->hard_header_len; 69 if (skb_headroom(*pskb) < hh_len) { 70 struct sk_buff *nskb; 71 72 nskb = skb_realloc_headroom(*pskb, hh_len); 73 if (!nskb) 74 return -1; 75 if ((*pskb)->sk) 76 skb_set_owner_w(nskb, (*pskb)->sk); 77 kfree_skb(*pskb); 78 *pskb = nskb; 79 } 80 81 return 0; 82} 83EXPORT_SYMBOL(ip_route_me_harder); 84 85#ifdef CONFIG_XFRM 86int ip_xfrm_me_harder(struct sk_buff **pskb) 87{ 88 struct flowi fl; 89 unsigned int hh_len; 90 struct dst_entry *dst; 91 92 if (IPCB(*pskb)->flags & IPSKB_XFRM_TRANSFORMED) 93 return 0; 94 if (xfrm_decode_session(*pskb, &fl, AF_INET) < 0) 95 return -1; 96 97 dst = (*pskb)->dst; 98 if (dst->xfrm) 99 dst = ((struct xfrm_dst *)dst)->route; 100 dst_hold(dst); 101 102 if (xfrm_lookup(&dst, &fl, (*pskb)->sk, 0) < 0) 103 return -1; 104 105 dst_release((*pskb)->dst); 106 (*pskb)->dst = dst; 107 108 /* Change in oif may mean change in hh_len. */ 109 hh_len = (*pskb)->dst->dev->hard_header_len; 110 if (skb_headroom(*pskb) < hh_len) { 111 struct sk_buff *nskb; 112 113 nskb = skb_realloc_headroom(*pskb, hh_len); 114 if (!nskb) 115 return -1; 116 if ((*pskb)->sk) 117 skb_set_owner_w(nskb, (*pskb)->sk); 118 kfree_skb(*pskb); 119 *pskb = nskb; 120 } 121 return 0; 122} 123EXPORT_SYMBOL(ip_xfrm_me_harder); 124#endif 125 126void (*ip_nat_decode_session)(struct sk_buff *, struct flowi *); 127EXPORT_SYMBOL(ip_nat_decode_session); 128 129/* 130 * Extra routing may needed on local out, as the QUEUE target never 131 * returns control to the table. 132 */ 133 134struct ip_rt_info { 135 __be32 daddr; 136 __be32 saddr; 137 u_int8_t tos; 138}; 139 140static void nf_ip_saveroute(const struct sk_buff *skb, struct nf_info *info) 141{ 142 struct ip_rt_info *rt_info = nf_info_reroute(info); 143 144 if (info->hook == NF_IP_LOCAL_OUT) { 145 const struct iphdr *iph = ip_hdr(skb); 146 147 rt_info->tos = iph->tos; 148 rt_info->daddr = iph->daddr; 149 rt_info->saddr = iph->saddr; 150 } 151} 152 153static int nf_ip_reroute(struct sk_buff **pskb, const struct nf_info *info) 154{ 155 const struct ip_rt_info *rt_info = nf_info_reroute(info); 156 157 if (info->hook == NF_IP_LOCAL_OUT) { 158 const struct iphdr *iph = ip_hdr(*pskb); 159 160 if (!(iph->tos == rt_info->tos 161 && iph->daddr == rt_info->daddr 162 && iph->saddr == rt_info->saddr)) 163 return ip_route_me_harder(pskb, RTN_UNSPEC); 164 } 165 return 0; 166} 167 168__sum16 nf_ip_checksum(struct sk_buff *skb, unsigned int hook, 169 unsigned int dataoff, u_int8_t protocol) 170{ 171 const struct iphdr *iph = ip_hdr(skb); 172 __sum16 csum = 0; 173 174 switch (skb->ip_summed) { 175 case CHECKSUM_COMPLETE: 176 if (hook != NF_IP_PRE_ROUTING && hook != NF_IP_LOCAL_IN) 177 break; 178 if ((protocol == 0 && !csum_fold(skb->csum)) || 179 !csum_tcpudp_magic(iph->saddr, iph->daddr, 180 skb->len - dataoff, protocol, 181 skb->csum)) { 182 skb->ip_summed = CHECKSUM_UNNECESSARY; 183 break; 184 } 185 /* fall through */ 186 case CHECKSUM_NONE: 187 if (protocol == 0) 188 skb->csum = 0; 189 else 190 skb->csum = csum_tcpudp_nofold(iph->saddr, iph->daddr, 191 skb->len - dataoff, 192 protocol, 0); 193 csum = __skb_checksum_complete(skb); 194 } 195 return csum; 196} 197 198EXPORT_SYMBOL(nf_ip_checksum); 199 200static struct nf_afinfo nf_ip_afinfo = { 201 .family = AF_INET, 202 .checksum = nf_ip_checksum, 203 .saveroute = nf_ip_saveroute, 204 .reroute = nf_ip_reroute, 205 .route_key_size = sizeof(struct ip_rt_info), 206}; 207 208static int ipv4_netfilter_init(void) 209{ 210 return nf_register_afinfo(&nf_ip_afinfo); 211} 212 213static void ipv4_netfilter_fini(void) 214{ 215 nf_unregister_afinfo(&nf_ip_afinfo); 216} 217 218module_init(ipv4_netfilter_init); 219module_exit(ipv4_netfilter_fini); 220