nf_conntrack_tftp.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /* (C) 2001-2002 Magnus Boden <mb@ozaba.mine.nu>
  3. * (C) 2006-2012 Patrick McHardy <kaber@trash.net>
  4. */
  5. #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  6. #include <linux/module.h>
  7. #include <linux/moduleparam.h>
  8. #include <linux/in.h>
  9. #include <linux/udp.h>
  10. #include <linux/netfilter.h>
  11. #include <net/netfilter/nf_conntrack.h>
  12. #include <net/netfilter/nf_conntrack_tuple.h>
  13. #include <net/netfilter/nf_conntrack_expect.h>
  14. #include <net/netfilter/nf_conntrack_ecache.h>
  15. #include <net/netfilter/nf_conntrack_helper.h>
  16. #include <linux/netfilter/nf_conntrack_tftp.h>
  17. #define HELPER_NAME "tftp"
  18. MODULE_AUTHOR("Magnus Boden <mb@ozaba.mine.nu>");
  19. MODULE_DESCRIPTION("TFTP connection tracking helper");
  20. MODULE_LICENSE("GPL");
  21. MODULE_ALIAS("ip_conntrack_tftp");
  22. MODULE_ALIAS_NFCT_HELPER(HELPER_NAME);
  23. #define MAX_PORTS 8
  24. static unsigned short ports[MAX_PORTS];
  25. static unsigned int ports_c;
  26. module_param_array(ports, ushort, &ports_c, 0400);
  27. MODULE_PARM_DESC(ports, "Port numbers of TFTP servers");
  28. unsigned int (*nf_nat_tftp_hook)(struct sk_buff *skb,
  29. enum ip_conntrack_info ctinfo,
  30. struct nf_conntrack_expect *exp) __read_mostly;
  31. EXPORT_SYMBOL_GPL(nf_nat_tftp_hook);
  32. static int tftp_help(struct sk_buff *skb,
  33. unsigned int protoff,
  34. struct nf_conn *ct,
  35. enum ip_conntrack_info ctinfo)
  36. {
  37. const struct tftphdr *tfh;
  38. struct tftphdr _tftph;
  39. struct nf_conntrack_expect *exp;
  40. struct nf_conntrack_tuple *tuple;
  41. unsigned int ret = NF_ACCEPT;
  42. typeof(nf_nat_tftp_hook) nf_nat_tftp;
  43. tfh = skb_header_pointer(skb, protoff + sizeof(struct udphdr),
  44. sizeof(_tftph), &_tftph);
  45. if (tfh == NULL)
  46. return NF_ACCEPT;
  47. switch (ntohs(tfh->opcode)) {
  48. case TFTP_OPCODE_READ:
  49. case TFTP_OPCODE_WRITE:
  50. /* RRQ and WRQ works the same way */
  51. nf_ct_dump_tuple(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
  52. nf_ct_dump_tuple(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
  53. exp = nf_ct_expect_alloc(ct);
  54. if (exp == NULL) {
  55. nf_ct_helper_log(skb, ct, "cannot alloc expectation");
  56. return NF_DROP;
  57. }
  58. tuple = &ct->tuplehash[IP_CT_DIR_REPLY].tuple;
  59. nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT,
  60. nf_ct_l3num(ct),
  61. &tuple->src.u3, &tuple->dst.u3,
  62. IPPROTO_UDP, NULL, &tuple->dst.u.udp.port);
  63. pr_debug("expect: ");
  64. nf_ct_dump_tuple(&exp->tuple);
  65. nf_nat_tftp = rcu_dereference(nf_nat_tftp_hook);
  66. if (nf_nat_tftp && ct->status & IPS_NAT_MASK)
  67. ret = nf_nat_tftp(skb, ctinfo, exp);
  68. else if (nf_ct_expect_related(exp, 0) != 0) {
  69. nf_ct_helper_log(skb, ct, "cannot add expectation");
  70. ret = NF_DROP;
  71. }
  72. nf_ct_expect_put(exp);
  73. break;
  74. case TFTP_OPCODE_DATA:
  75. case TFTP_OPCODE_ACK:
  76. pr_debug("Data/ACK opcode\n");
  77. break;
  78. case TFTP_OPCODE_ERROR:
  79. pr_debug("Error opcode\n");
  80. break;
  81. default:
  82. pr_debug("Unknown opcode\n");
  83. }
  84. return ret;
  85. }
  86. static struct nf_conntrack_helper tftp[MAX_PORTS * 2] __read_mostly;
  87. static const struct nf_conntrack_expect_policy tftp_exp_policy = {
  88. .max_expected = 1,
  89. .timeout = 5 * 60,
  90. };
  91. static void __exit nf_conntrack_tftp_fini(void)
  92. {
  93. nf_conntrack_helpers_unregister(tftp, ports_c * 2);
  94. }
  95. static int __init nf_conntrack_tftp_init(void)
  96. {
  97. int i, ret;
  98. NF_CT_HELPER_BUILD_BUG_ON(0);
  99. if (ports_c == 0)
  100. ports[ports_c++] = TFTP_PORT;
  101. for (i = 0; i < ports_c; i++) {
  102. nf_ct_helper_init(&tftp[2 * i], AF_INET, IPPROTO_UDP,
  103. HELPER_NAME, TFTP_PORT, ports[i], i,
  104. &tftp_exp_policy, 0, tftp_help, NULL,
  105. THIS_MODULE);
  106. nf_ct_helper_init(&tftp[2 * i + 1], AF_INET6, IPPROTO_UDP,
  107. HELPER_NAME, TFTP_PORT, ports[i], i,
  108. &tftp_exp_policy, 0, tftp_help, NULL,
  109. THIS_MODULE);
  110. }
  111. ret = nf_conntrack_helpers_register(tftp, ports_c * 2);
  112. if (ret < 0) {
  113. pr_err("failed to register helpers\n");
  114. return ret;
  115. }
  116. return 0;
  117. }
  118. module_init(nf_conntrack_tftp_init);
  119. module_exit(nf_conntrack_tftp_fini);