nf_conntrack_irc.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /* IRC extension for IP connection tracking, Version 1.21
  3. * (C) 2000-2002 by Harald Welte <laforge@gnumonks.org>
  4. * based on RR's ip_conntrack_ftp.c
  5. * (C) 2006-2012 Patrick McHardy <kaber@trash.net>
  6. */
  7. #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  8. #include <linux/module.h>
  9. #include <linux/moduleparam.h>
  10. #include <linux/skbuff.h>
  11. #include <linux/in.h>
  12. #include <linux/ip.h>
  13. #include <linux/tcp.h>
  14. #include <linux/netfilter.h>
  15. #include <linux/slab.h>
  16. #include <net/netfilter/nf_conntrack.h>
  17. #include <net/netfilter/nf_conntrack_expect.h>
  18. #include <net/netfilter/nf_conntrack_helper.h>
  19. #include <linux/netfilter/nf_conntrack_irc.h>
  20. #define MAX_PORTS 8
  21. static unsigned short ports[MAX_PORTS];
  22. static unsigned int ports_c;
  23. static unsigned int max_dcc_channels = 8;
  24. static unsigned int dcc_timeout __read_mostly = 300;
  25. /* This is slow, but it's simple. --RR */
  26. static char *irc_buffer;
  27. static DEFINE_SPINLOCK(irc_buffer_lock);
  28. unsigned int (*nf_nat_irc_hook)(struct sk_buff *skb,
  29. enum ip_conntrack_info ctinfo,
  30. unsigned int protoff,
  31. unsigned int matchoff,
  32. unsigned int matchlen,
  33. struct nf_conntrack_expect *exp) __read_mostly;
  34. EXPORT_SYMBOL_GPL(nf_nat_irc_hook);
  35. #define HELPER_NAME "irc"
  36. MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
  37. MODULE_DESCRIPTION("IRC (DCC) connection tracking helper");
  38. MODULE_LICENSE("GPL");
  39. MODULE_ALIAS("ip_conntrack_irc");
  40. MODULE_ALIAS_NFCT_HELPER(HELPER_NAME);
  41. module_param_array(ports, ushort, &ports_c, 0400);
  42. MODULE_PARM_DESC(ports, "port numbers of IRC servers");
  43. module_param(max_dcc_channels, uint, 0400);
  44. MODULE_PARM_DESC(max_dcc_channels, "max number of expected DCC channels per "
  45. "IRC session");
  46. module_param(dcc_timeout, uint, 0400);
  47. MODULE_PARM_DESC(dcc_timeout, "timeout on for unestablished DCC channels");
  48. static const char *const dccprotos[] = {
  49. "SEND ", "CHAT ", "MOVE ", "TSEND ", "SCHAT "
  50. };
  51. #define MINMATCHLEN 5
  52. /* tries to get the ip_addr and port out of a dcc command
  53. * return value: -1 on failure, 0 on success
  54. * data pointer to first byte of DCC command data
  55. * data_end pointer to last byte of dcc command data
  56. * ip returns parsed ip of dcc command
  57. * port returns parsed port of dcc command
  58. * ad_beg_p returns pointer to first byte of addr data
  59. * ad_end_p returns pointer to last byte of addr data
  60. */
  61. static int parse_dcc(char *data, const char *data_end, __be32 *ip,
  62. u_int16_t *port, char **ad_beg_p, char **ad_end_p)
  63. {
  64. char *tmp;
  65. /* at least 12: "AAAAAAAA P\1\n" */
  66. while (*data++ != ' ')
  67. if (data > data_end - 12)
  68. return -1;
  69. /* Make sure we have a newline character within the packet boundaries
  70. * because simple_strtoul parses until the first invalid character. */
  71. for (tmp = data; tmp <= data_end; tmp++)
  72. if (*tmp == '\n')
  73. break;
  74. if (tmp > data_end || *tmp != '\n')
  75. return -1;
  76. *ad_beg_p = data;
  77. *ip = cpu_to_be32(simple_strtoul(data, &data, 10));
  78. /* skip blanks between ip and port */
  79. while (*data == ' ') {
  80. if (data >= data_end)
  81. return -1;
  82. data++;
  83. }
  84. *port = simple_strtoul(data, &data, 10);
  85. *ad_end_p = data;
  86. return 0;
  87. }
  88. static int help(struct sk_buff *skb, unsigned int protoff,
  89. struct nf_conn *ct, enum ip_conntrack_info ctinfo)
  90. {
  91. unsigned int dataoff;
  92. const struct iphdr *iph;
  93. const struct tcphdr *th;
  94. struct tcphdr _tcph;
  95. const char *data_limit;
  96. char *data, *ib_ptr;
  97. int dir = CTINFO2DIR(ctinfo);
  98. struct nf_conntrack_expect *exp;
  99. struct nf_conntrack_tuple *tuple;
  100. __be32 dcc_ip;
  101. u_int16_t dcc_port;
  102. __be16 port;
  103. int i, ret = NF_ACCEPT;
  104. char *addr_beg_p, *addr_end_p;
  105. typeof(nf_nat_irc_hook) nf_nat_irc;
  106. /* If packet is coming from IRC server */
  107. if (dir == IP_CT_DIR_REPLY)
  108. return NF_ACCEPT;
  109. /* Until there's been traffic both ways, don't look in packets. */
  110. if (ctinfo != IP_CT_ESTABLISHED && ctinfo != IP_CT_ESTABLISHED_REPLY)
  111. return NF_ACCEPT;
  112. /* Not a full tcp header? */
  113. th = skb_header_pointer(skb, protoff, sizeof(_tcph), &_tcph);
  114. if (th == NULL)
  115. return NF_ACCEPT;
  116. /* No data? */
  117. dataoff = protoff + th->doff*4;
  118. if (dataoff >= skb->len)
  119. return NF_ACCEPT;
  120. spin_lock_bh(&irc_buffer_lock);
  121. ib_ptr = skb_header_pointer(skb, dataoff, skb->len - dataoff,
  122. irc_buffer);
  123. BUG_ON(ib_ptr == NULL);
  124. data = ib_ptr;
  125. data_limit = ib_ptr + skb->len - dataoff;
  126. /* strlen("\1DCC SENT t AAAAAAAA P\1\n")=24
  127. * 5+MINMATCHLEN+strlen("t AAAAAAAA P\1\n")=14 */
  128. while (data < data_limit - (19 + MINMATCHLEN)) {
  129. if (memcmp(data, "\1DCC ", 5)) {
  130. data++;
  131. continue;
  132. }
  133. data += 5;
  134. /* we have at least (19+MINMATCHLEN)-5 bytes valid data left */
  135. iph = ip_hdr(skb);
  136. pr_debug("DCC found in master %pI4:%u %pI4:%u\n",
  137. &iph->saddr, ntohs(th->source),
  138. &iph->daddr, ntohs(th->dest));
  139. for (i = 0; i < ARRAY_SIZE(dccprotos); i++) {
  140. if (memcmp(data, dccprotos[i], strlen(dccprotos[i]))) {
  141. /* no match */
  142. continue;
  143. }
  144. data += strlen(dccprotos[i]);
  145. pr_debug("DCC %s detected\n", dccprotos[i]);
  146. /* we have at least
  147. * (19+MINMATCHLEN)-5-dccprotos[i].matchlen bytes valid
  148. * data left (== 14/13 bytes) */
  149. if (parse_dcc(data, data_limit, &dcc_ip,
  150. &dcc_port, &addr_beg_p, &addr_end_p)) {
  151. pr_debug("unable to parse dcc command\n");
  152. continue;
  153. }
  154. pr_debug("DCC bound ip/port: %pI4:%u\n",
  155. &dcc_ip, dcc_port);
  156. /* dcc_ip can be the internal OR external (NAT'ed) IP */
  157. tuple = &ct->tuplehash[dir].tuple;
  158. if (tuple->src.u3.ip != dcc_ip &&
  159. tuple->dst.u3.ip != dcc_ip) {
  160. net_warn_ratelimited("Forged DCC command from %pI4: %pI4:%u\n",
  161. &tuple->src.u3.ip,
  162. &dcc_ip, dcc_port);
  163. continue;
  164. }
  165. exp = nf_ct_expect_alloc(ct);
  166. if (exp == NULL) {
  167. nf_ct_helper_log(skb, ct,
  168. "cannot alloc expectation");
  169. ret = NF_DROP;
  170. goto out;
  171. }
  172. tuple = &ct->tuplehash[!dir].tuple;
  173. port = htons(dcc_port);
  174. nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT,
  175. tuple->src.l3num,
  176. NULL, &tuple->dst.u3,
  177. IPPROTO_TCP, NULL, &port);
  178. nf_nat_irc = rcu_dereference(nf_nat_irc_hook);
  179. if (nf_nat_irc && ct->status & IPS_NAT_MASK)
  180. ret = nf_nat_irc(skb, ctinfo, protoff,
  181. addr_beg_p - ib_ptr,
  182. addr_end_p - addr_beg_p,
  183. exp);
  184. else if (nf_ct_expect_related(exp, 0) != 0) {
  185. nf_ct_helper_log(skb, ct,
  186. "cannot add expectation");
  187. ret = NF_DROP;
  188. }
  189. nf_ct_expect_put(exp);
  190. goto out;
  191. }
  192. }
  193. out:
  194. spin_unlock_bh(&irc_buffer_lock);
  195. return ret;
  196. }
  197. static struct nf_conntrack_helper irc[MAX_PORTS] __read_mostly;
  198. static struct nf_conntrack_expect_policy irc_exp_policy;
  199. static int __init nf_conntrack_irc_init(void)
  200. {
  201. int i, ret;
  202. if (max_dcc_channels < 1) {
  203. pr_err("max_dcc_channels must not be zero\n");
  204. return -EINVAL;
  205. }
  206. if (max_dcc_channels > NF_CT_EXPECT_MAX_CNT) {
  207. pr_err("max_dcc_channels must not be more than %u\n",
  208. NF_CT_EXPECT_MAX_CNT);
  209. return -EINVAL;
  210. }
  211. irc_exp_policy.max_expected = max_dcc_channels;
  212. irc_exp_policy.timeout = dcc_timeout;
  213. irc_buffer = kmalloc(65536, GFP_KERNEL);
  214. if (!irc_buffer)
  215. return -ENOMEM;
  216. /* If no port given, default to standard irc port */
  217. if (ports_c == 0)
  218. ports[ports_c++] = IRC_PORT;
  219. for (i = 0; i < ports_c; i++) {
  220. nf_ct_helper_init(&irc[i], AF_INET, IPPROTO_TCP, HELPER_NAME,
  221. IRC_PORT, ports[i], i, &irc_exp_policy,
  222. 0, help, NULL, THIS_MODULE);
  223. }
  224. ret = nf_conntrack_helpers_register(&irc[0], ports_c);
  225. if (ret) {
  226. pr_err("failed to register helpers\n");
  227. kfree(irc_buffer);
  228. return ret;
  229. }
  230. return 0;
  231. }
  232. static void __exit nf_conntrack_irc_fini(void)
  233. {
  234. nf_conntrack_helpers_unregister(irc, ports_c);
  235. kfree(irc_buffer);
  236. }
  237. module_init(nf_conntrack_irc_init);
  238. module_exit(nf_conntrack_irc_fini);