netfilter.c 2.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. #include <linux/config.h>
  2. #ifdef CONFIG_NETFILTER
  3. /* IPv4 specific functions of netfilter core */
  4. #include <linux/kernel.h>
  5. #include <linux/netfilter.h>
  6. #include <linux/tcp.h>
  7. #include <linux/udp.h>
  8. #include <linux/icmp.h>
  9. #include <net/route.h>
  10. #include <linux/ip.h>
  11. /* route_me_harder function, used by iptable_nat, iptable_mangle + ip_queue */
  12. int ip_route_me_harder(struct sk_buff **pskb)
  13. {
  14. struct iphdr *iph = (*pskb)->nh.iph;
  15. struct rtable *rt;
  16. struct flowi fl = {};
  17. struct dst_entry *odst;
  18. unsigned int hh_len;
  19. /* some non-standard hacks like ipt_REJECT.c:send_reset() can cause
  20. * packets with foreign saddr to appear on the NF_IP_LOCAL_OUT hook.
  21. */
  22. if (inet_addr_type(iph->saddr) == RTN_LOCAL) {
  23. fl.nl_u.ip4_u.daddr = iph->daddr;
  24. fl.nl_u.ip4_u.saddr = iph->saddr;
  25. fl.nl_u.ip4_u.tos = RT_TOS(iph->tos);
  26. fl.oif = (*pskb)->sk ? (*pskb)->sk->sk_bound_dev_if : 0;
  27. #ifdef CONFIG_IP_ROUTE_FWMARK
  28. fl.nl_u.ip4_u.fwmark = (*pskb)->nfmark;
  29. #endif
  30. fl.proto = iph->protocol;
  31. if (ip_route_output_key(&rt, &fl) != 0)
  32. return -1;
  33. /* Drop old route. */
  34. dst_release((*pskb)->dst);
  35. (*pskb)->dst = &rt->u.dst;
  36. } else {
  37. /* non-local src, find valid iif to satisfy
  38. * rp-filter when calling ip_route_input. */
  39. fl.nl_u.ip4_u.daddr = iph->saddr;
  40. if (ip_route_output_key(&rt, &fl) != 0)
  41. return -1;
  42. odst = (*pskb)->dst;
  43. if (ip_route_input(*pskb, iph->daddr, iph->saddr,
  44. RT_TOS(iph->tos), rt->u.dst.dev) != 0) {
  45. dst_release(&rt->u.dst);
  46. return -1;
  47. }
  48. dst_release(&rt->u.dst);
  49. dst_release(odst);
  50. }
  51. if ((*pskb)->dst->error)
  52. return -1;
  53. /* Change in oif may mean change in hh_len. */
  54. hh_len = (*pskb)->dst->dev->hard_header_len;
  55. if (skb_headroom(*pskb) < hh_len) {
  56. struct sk_buff *nskb;
  57. nskb = skb_realloc_headroom(*pskb, hh_len);
  58. if (!nskb)
  59. return -1;
  60. if ((*pskb)->sk)
  61. skb_set_owner_w(nskb, (*pskb)->sk);
  62. kfree_skb(*pskb);
  63. *pskb = nskb;
  64. }
  65. return 0;
  66. }
  67. EXPORT_SYMBOL(ip_route_me_harder);
  68. #endif /* CONFIG_NETFILTER */