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