ip_conntrack_irc.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:9k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /* IRC extension for IP connection tracking, Version 1.21
  2.  * (C) 2000-2002 by Harald Welte <laforge@gnumonks.org>
  3.  * based on RR's ip_conntrack_ftp.c
  4.  *
  5.  * ip_conntrack_irc.c,v 1.21 2002/02/05 14:49:26 laforge Exp
  6.  *
  7.  *      This program is free software; you can redistribute it and/or
  8.  *      modify it under the terms of the GNU General Public License
  9.  *      as published by the Free Software Foundation; either version
  10.  *      2 of the License, or (at your option) any later version.
  11.  **
  12.  * Module load syntax:
  13.  *  insmod ip_conntrack_irc.o ports=port1,port2,...port<MAX_PORTS>
  14.  *     max_dcc_channels=n dcc_timeout=secs
  15.  *
  16.  *  please give the ports of all IRC servers You wish to connect to.
  17.  * If You don't specify ports, the default will be port 6667.
  18.  * With max_dcc_channels you can define the maximum number of not
  19.  * yet answered DCC channels per IRC session (default 8).
  20.  * With dcc_timeout you can specify how long the system waits for 
  21.  * an expected DCC channel (default 300 seconds).
  22.  *
  23.  */
  24. #include <linux/config.h>
  25. #include <linux/module.h>
  26. #include <linux/netfilter.h>
  27. #include <linux/ip.h>
  28. #include <net/checksum.h>
  29. #include <net/tcp.h>
  30. #include <linux/netfilter_ipv4/lockhelp.h>
  31. #include <linux/netfilter_ipv4/ip_conntrack_helper.h>
  32. #include <linux/netfilter_ipv4/ip_conntrack_irc.h>
  33. #define MAX_PORTS 8
  34. static int ports[MAX_PORTS];
  35. static int ports_c = 0;
  36. static int max_dcc_channels = 8;
  37. static unsigned int dcc_timeout = 300;
  38. MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
  39. MODULE_DESCRIPTION("IRC (DCC) connection tracking module");
  40. MODULE_LICENSE("GPL");
  41. #ifdef MODULE_PARM
  42. MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i");
  43. MODULE_PARM_DESC(ports, "port numbers of IRC servers");
  44. MODULE_PARM(max_dcc_channels, "i");
  45. MODULE_PARM_DESC(max_dcc_channels, "max number of expected DCC channels per IRC session");
  46. MODULE_PARM(dcc_timeout, "i");
  47. MODULE_PARM_DESC(dcc_timeout, "timeout on for unestablished DCC channels");
  48. #endif
  49. #define NUM_DCCPROTO  5
  50. struct dccproto dccprotos[NUM_DCCPROTO] = {
  51. {"SEND ", 5},
  52. {"CHAT ", 5},
  53. {"MOVE ", 5},
  54. {"TSEND ", 6},
  55. {"SCHAT ", 6}
  56. };
  57. #define MAXMATCHLEN 6
  58. DECLARE_LOCK(ip_irc_lock);
  59. struct module *ip_conntrack_irc = THIS_MODULE;
  60. #if 0
  61. #define DEBUGP(format, args...) printk(KERN_DEBUG __FILE__ ":" __FUNCTION__ 
  62. ":" format, ## args)
  63. #else
  64. #define DEBUGP(format, args...)
  65. #endif
  66. int parse_dcc(char *data, char *data_end, u_int32_t * ip, u_int16_t * port,
  67.       char **ad_beg_p, char **ad_end_p)
  68. /* tries to get the ip_addr and port out of a dcc command
  69.    return value: -1 on failure, 0 on success 
  70. data pointer to first byte of DCC command data
  71. data_end pointer to last byte of dcc command data
  72. ip returns parsed ip of dcc command
  73. port returns parsed port of dcc command
  74. ad_beg_p returns pointer to first byte of addr data
  75. ad_end_p returns pointer to last byte of addr data */
  76. {
  77. /* at least 12: "AAAAAAAA P1n" */
  78. while (*data++ != ' ')
  79. if (data > data_end - 12)
  80. return -1;
  81. *ad_beg_p = data;
  82. *ip = simple_strtoul(data, &data, 10);
  83. /* skip blanks between ip and port */
  84. while (*data == ' ')
  85. data++;
  86. *port = simple_strtoul(data, &data, 10);
  87. *ad_end_p = data;
  88. return 0;
  89. }
  90. /* FIXME: This should be in userspace.  Later. */
  91. static int help(const struct iphdr *iph, size_t len,
  92. struct ip_conntrack *ct, enum ip_conntrack_info ctinfo)
  93. {
  94. /* tcplen not negative guarenteed by ip_conntrack_tcp.c */
  95. struct tcphdr *tcph = (void *) iph + iph->ihl * 4;
  96. const char *data = (const char *) tcph + tcph->doff * 4;
  97. const char *_data = data;
  98. char *data_limit;
  99. u_int32_t tcplen = len - iph->ihl * 4;
  100. u_int32_t datalen = tcplen - tcph->doff * 4;
  101. int dir = CTINFO2DIR(ctinfo);
  102. struct ip_conntrack_expect expect, *exp = &expect;
  103. struct ip_ct_irc_expect *exp_irc_info = &exp->help.exp_irc_info;
  104. u_int32_t dcc_ip;
  105. u_int16_t dcc_port;
  106. int i;
  107. char *addr_beg_p, *addr_end_p;
  108. DEBUGP("enteredn");
  109. /* If packet is coming from IRC server */
  110. if (dir == IP_CT_DIR_REPLY)
  111. return NF_ACCEPT;
  112. /* Until there's been traffic both ways, don't look in packets. */
  113. if (ctinfo != IP_CT_ESTABLISHED
  114.     && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) {
  115. DEBUGP("Conntrackinfo = %un", ctinfo);
  116. return NF_ACCEPT;
  117. }
  118. /* Not whole TCP header? */
  119. if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4) {
  120. DEBUGP("tcplen = %un", (unsigned) tcplen);
  121. return NF_ACCEPT;
  122. }
  123. /* Checksum invalid?  Ignore. */
  124. /* FIXME: Source route IP option packets --RR */
  125. if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr,
  126.  csum_partial((char *) tcph, tcplen, 0))) {
  127. DEBUGP("bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%un",
  128.      tcph, tcplen, NIPQUAD(iph->saddr),
  129.      NIPQUAD(iph->daddr));
  130. return NF_ACCEPT;
  131. }
  132. data_limit = (char *) data + datalen;
  133. while (data < (data_limit - (22 + MAXMATCHLEN))) {
  134. if (memcmp(data, "1DCC ", 5)) {
  135. data++;
  136. continue;
  137. }
  138. data += 5;
  139. DEBUGP("DCC found in master %u.%u.%u.%u:%u %u.%u.%u.%u:%u...n",
  140. NIPQUAD(iph->saddr), ntohs(tcph->source),
  141. NIPQUAD(iph->daddr), ntohs(tcph->dest));
  142. for (i = 0; i < NUM_DCCPROTO; i++) {
  143. if (memcmp(data, dccprotos[i].match,
  144.    dccprotos[i].matchlen)) {
  145. /* no match */
  146. continue;
  147. }
  148. DEBUGP("DCC %s detectedn", dccprotos[i].match);
  149. data += dccprotos[i].matchlen;
  150. if (parse_dcc((char *) data, data_limit, &dcc_ip,
  151.        &dcc_port, &addr_beg_p, &addr_end_p)) {
  152. /* unable to parse */
  153. DEBUGP("unable to parse dcc commandn");
  154. continue;
  155. }
  156. DEBUGP("DCC bound ip/port: %u.%u.%u.%u:%un",
  157. HIPQUAD(dcc_ip), dcc_port);
  158. if (ct->tuplehash[dir].tuple.src.ip != htonl(dcc_ip)) {
  159. if (net_ratelimit())
  160. printk(KERN_WARNING
  161. "Forged DCC command from "
  162. "%u.%u.%u.%u: %u.%u.%u.%u:%un",
  163. NIPQUAD(ct->tuplehash[dir].tuple.src.ip),
  164. HIPQUAD(dcc_ip), dcc_port);
  165. continue;
  166. }
  167. memset(&expect, 0, sizeof(expect));
  168. LOCK_BH(&ip_irc_lock);
  169. /* save position of address in dcc string,
  170.  * neccessary for NAT */
  171. DEBUGP("tcph->seq = %un", tcph->seq);
  172. exp->seq = ntohl(tcph->seq) + (addr_beg_p - _data);
  173. exp_irc_info->len = (addr_end_p - addr_beg_p);
  174. exp_irc_info->port = dcc_port;
  175. DEBUGP("wrote info seq=%u (ofs=%u), len=%dn",
  176. exp->seq, (addr_end_p - _data), exp_irc_info->len);
  177. exp->tuple = ((struct ip_conntrack_tuple)
  178. { { 0, { 0 } },
  179.   { htonl(dcc_ip), { htons(dcc_port) },
  180.     IPPROTO_TCP }});
  181. exp->mask = ((struct ip_conntrack_tuple)
  182. { { 0, { 0 } },
  183.   { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF }});
  184. exp->expectfn = NULL;
  185. DEBUGP("expect_related %u.%u.%u.%u:%u-%u.%u.%u.%u:%un",
  186. NIPQUAD(exp->tuple.src.ip),
  187. ntohs(exp->tuple.src.u.tcp.port),
  188. NIPQUAD(exp->tuple.dst.ip),
  189. ntohs(exp->tuple.dst.u.tcp.port));
  190. ip_conntrack_expect_related(ct, &expect);
  191. UNLOCK_BH(&ip_irc_lock);
  192. return NF_ACCEPT;
  193. } /* for .. NUM_DCCPROTO */
  194. } /* while data < ... */
  195. return NF_ACCEPT;
  196. }
  197. static struct ip_conntrack_helper irc_helpers[MAX_PORTS];
  198. static char irc_names[MAX_PORTS][10];
  199. static void fini(void);
  200. static int __init init(void)
  201. {
  202. int i, ret;
  203. struct ip_conntrack_helper *hlpr;
  204. char *tmpname;
  205. if (max_dcc_channels < 1) {
  206. printk("ip_conntrack_irc: max_dcc_channels must be a positive integern");
  207. return -EBUSY;
  208. }
  209. if (dcc_timeout < 0) {
  210. printk("ip_conntrack_irc: dcc_timeout must be a positive integern");
  211. return -EBUSY;
  212. }
  213. /* If no port given, default to standard irc port */
  214. if (ports[0] == 0)
  215. ports[0] = IRC_PORT;
  216. for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
  217. hlpr = &irc_helpers[i];
  218. memset(hlpr, 0,
  219.        sizeof(struct ip_conntrack_helper));
  220. hlpr->tuple.src.u.tcp.port = htons(ports[i]);
  221. hlpr->tuple.dst.protonum = IPPROTO_TCP;
  222. hlpr->mask.src.u.tcp.port = 0xFFFF;
  223. hlpr->mask.dst.protonum = 0xFFFF;
  224. hlpr->max_expected = max_dcc_channels;
  225. hlpr->timeout = dcc_timeout;
  226. hlpr->flags = IP_CT_HELPER_F_REUSE_EXPECT;
  227. hlpr->me = ip_conntrack_irc;
  228. hlpr->help = help;
  229. tmpname = &irc_names[i][0];
  230. if (ports[i] == IRC_PORT)
  231. sprintf(tmpname, "irc");
  232. else
  233. sprintf(tmpname, "irc-%d", i);
  234. hlpr->name = tmpname;
  235. DEBUGP("port #%d: %dn", i, ports[i]);
  236. ret = ip_conntrack_helper_register(hlpr);
  237. if (ret) {
  238. printk("ip_conntrack_irc: ERROR registering port %dn",
  239. ports[i]);
  240. fini();
  241. return -EBUSY;
  242. }
  243. ports_c++;
  244. }
  245. return 0;
  246. }
  247. /* This function is intentionally _NOT_ defined as __exit, because 
  248.  * it is needed by the init function */
  249. static void fini(void)
  250. {
  251. int i;
  252. for (i = 0; i < ports_c; i++) {
  253. DEBUGP("unregistering port %dn",
  254.        ports[i]);
  255. ip_conntrack_helper_unregister(&irc_helpers[i]);
  256. }
  257. }
  258. #ifdef CONFIG_IP_NF_NAT_NEEDED
  259. EXPORT_SYMBOL(ip_irc_lock);
  260. #endif
  261. module_init(init);
  262. module_exit(fini);