iptable_mangle.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * This is the 1999 rewrite of IP Firewalling, aiming for kernel 2.3.x.
  4. *
  5. * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
  6. * Copyright (C) 2000-2004 Netfilter Core Team <coreteam@netfilter.org>
  7. */
  8. #include <linux/module.h>
  9. #include <linux/netfilter_ipv4/ip_tables.h>
  10. #include <linux/netdevice.h>
  11. #include <linux/skbuff.h>
  12. #include <linux/slab.h>
  13. #include <net/sock.h>
  14. #include <net/route.h>
  15. #include <linux/ip.h>
  16. #include <net/ip.h>
  17. MODULE_LICENSE("GPL");
  18. MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
  19. MODULE_DESCRIPTION("iptables mangle table");
  20. #define MANGLE_VALID_HOOKS ((1 << NF_INET_PRE_ROUTING) | \
  21. (1 << NF_INET_LOCAL_IN) | \
  22. (1 << NF_INET_FORWARD) | \
  23. (1 << NF_INET_LOCAL_OUT) | \
  24. (1 << NF_INET_POST_ROUTING))
  25. static int __net_init iptable_mangle_table_init(struct net *net);
  26. static const struct xt_table packet_mangler = {
  27. .name = "mangle",
  28. .valid_hooks = MANGLE_VALID_HOOKS,
  29. .me = THIS_MODULE,
  30. .af = NFPROTO_IPV4,
  31. .priority = NF_IP_PRI_MANGLE,
  32. .table_init = iptable_mangle_table_init,
  33. };
  34. static unsigned int
  35. ipt_mangle_out(struct sk_buff *skb, const struct nf_hook_state *state)
  36. {
  37. unsigned int ret;
  38. const struct iphdr *iph;
  39. u_int8_t tos;
  40. __be32 saddr, daddr;
  41. u_int32_t mark;
  42. int err;
  43. /* Save things which could affect route */
  44. mark = skb->mark;
  45. iph = ip_hdr(skb);
  46. saddr = iph->saddr;
  47. daddr = iph->daddr;
  48. tos = iph->tos;
  49. ret = ipt_do_table(skb, state, state->net->ipv4.iptable_mangle);
  50. /* Reroute for ANY change. */
  51. if (ret != NF_DROP && ret != NF_STOLEN) {
  52. iph = ip_hdr(skb);
  53. if (iph->saddr != saddr ||
  54. iph->daddr != daddr ||
  55. skb->mark != mark ||
  56. iph->tos != tos) {
  57. err = ip_route_me_harder(state->net, state->sk, skb, RTN_UNSPEC);
  58. if (err < 0)
  59. ret = NF_DROP_ERR(err);
  60. }
  61. }
  62. return ret;
  63. }
  64. /* The work comes in here from netfilter.c. */
  65. static unsigned int
  66. iptable_mangle_hook(void *priv,
  67. struct sk_buff *skb,
  68. const struct nf_hook_state *state)
  69. {
  70. if (state->hook == NF_INET_LOCAL_OUT)
  71. return ipt_mangle_out(skb, state);
  72. return ipt_do_table(skb, state, state->net->ipv4.iptable_mangle);
  73. }
  74. static struct nf_hook_ops *mangle_ops __read_mostly;
  75. static int __net_init iptable_mangle_table_init(struct net *net)
  76. {
  77. struct ipt_replace *repl;
  78. int ret;
  79. if (net->ipv4.iptable_mangle)
  80. return 0;
  81. repl = ipt_alloc_initial_table(&packet_mangler);
  82. if (repl == NULL)
  83. return -ENOMEM;
  84. ret = ipt_register_table(net, &packet_mangler, repl, mangle_ops,
  85. &net->ipv4.iptable_mangle);
  86. kfree(repl);
  87. return ret;
  88. }
  89. static void __net_exit iptable_mangle_net_pre_exit(struct net *net)
  90. {
  91. if (net->ipv4.iptable_mangle)
  92. ipt_unregister_table_pre_exit(net, net->ipv4.iptable_mangle,
  93. mangle_ops);
  94. }
  95. static void __net_exit iptable_mangle_net_exit(struct net *net)
  96. {
  97. if (!net->ipv4.iptable_mangle)
  98. return;
  99. ipt_unregister_table_exit(net, net->ipv4.iptable_mangle);
  100. net->ipv4.iptable_mangle = NULL;
  101. }
  102. static struct pernet_operations iptable_mangle_net_ops = {
  103. .pre_exit = iptable_mangle_net_pre_exit,
  104. .exit = iptable_mangle_net_exit,
  105. };
  106. static int __init iptable_mangle_init(void)
  107. {
  108. int ret;
  109. mangle_ops = xt_hook_ops_alloc(&packet_mangler, iptable_mangle_hook);
  110. if (IS_ERR(mangle_ops)) {
  111. ret = PTR_ERR(mangle_ops);
  112. return ret;
  113. }
  114. ret = register_pernet_subsys(&iptable_mangle_net_ops);
  115. if (ret < 0) {
  116. kfree(mangle_ops);
  117. return ret;
  118. }
  119. ret = iptable_mangle_table_init(&init_net);
  120. if (ret) {
  121. unregister_pernet_subsys(&iptable_mangle_net_ops);
  122. kfree(mangle_ops);
  123. }
  124. return ret;
  125. }
  126. static void __exit iptable_mangle_fini(void)
  127. {
  128. unregister_pernet_subsys(&iptable_mangle_net_ops);
  129. kfree(mangle_ops);
  130. }
  131. module_init(iptable_mangle_init);
  132. module_exit(iptable_mangle_fini);