ip_nat_ftp.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:10k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /* FTP extension for TCP NAT alteration. */
  2. #include <linux/module.h>
  3. #include <linux/netfilter_ipv4.h>
  4. #include <linux/ip.h>
  5. #include <linux/tcp.h>
  6. #include <net/tcp.h>
  7. #include <linux/netfilter_ipv4/ip_nat.h>
  8. #include <linux/netfilter_ipv4/ip_nat_helper.h>
  9. #include <linux/netfilter_ipv4/ip_nat_rule.h>
  10. #include <linux/netfilter_ipv4/ip_conntrack_ftp.h>
  11. #include <linux/netfilter_ipv4/ip_conntrack_helper.h>
  12. #if 0
  13. #define DEBUGP printk
  14. #else
  15. #define DEBUGP(format, args...)
  16. #endif
  17. #define MAX_PORTS 8
  18. static int ports[MAX_PORTS];
  19. static int ports_c = 0;
  20. #ifdef MODULE_PARM
  21. MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i");
  22. #endif
  23. DECLARE_LOCK_EXTERN(ip_ftp_lock);
  24. /* FIXME: Time out? --RR */
  25. static int
  26. ftp_nat_expected(struct sk_buff **pskb,
  27.  unsigned int hooknum,
  28.  struct ip_conntrack *ct,
  29.  struct ip_nat_info *info,
  30.  struct ip_conntrack *master,
  31.  struct ip_nat_info *masterinfo,
  32.  unsigned int *verdict)
  33. {
  34. struct ip_nat_multi_range mr;
  35. u_int32_t newdstip, newsrcip, newip;
  36. struct ip_ct_ftp *ftpinfo;
  37. IP_NF_ASSERT(info);
  38. IP_NF_ASSERT(master);
  39. IP_NF_ASSERT(masterinfo);
  40. IP_NF_ASSERT(!(info->initialized & (1<<HOOK2MANIP(hooknum))));
  41. DEBUGP("nat_expected: We have a connection!n");
  42. /* Master must be an ftp connection */
  43. ftpinfo = &master->help.ct_ftp_info;
  44. LOCK_BH(&ip_ftp_lock);
  45. if (ftpinfo->is_ftp != IP_CONNTR_FTP) {
  46. UNLOCK_BH(&ip_ftp_lock);
  47. DEBUGP("nat_expected: master not ftpn");
  48. return 0;
  49. }
  50. if (ftpinfo->ftptype == IP_CT_FTP_PORT
  51.     || ftpinfo->ftptype == IP_CT_FTP_EPRT) {
  52. /* PORT command: make connection go to the client. */
  53. newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
  54. newsrcip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
  55. DEBUGP("nat_expected: PORT cmd. %u.%u.%u.%u->%u.%u.%u.%un",
  56.        NIPQUAD(newsrcip), NIPQUAD(newdstip));
  57. } else {
  58. /* PASV command: make the connection go to the server */
  59. newdstip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;
  60. newsrcip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
  61. DEBUGP("nat_expected: PASV cmd. %u.%u.%u.%u->%u.%u.%u.%un",
  62.        NIPQUAD(newsrcip), NIPQUAD(newdstip));
  63. }
  64. UNLOCK_BH(&ip_ftp_lock);
  65. if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC)
  66. newip = newsrcip;
  67. else
  68. newip = newdstip;
  69. DEBUGP("nat_expected: IP to %u.%u.%u.%un", NIPQUAD(newip));
  70. mr.rangesize = 1;
  71. /* We don't want to manip the per-protocol, just the IPs... */
  72. mr.range[0].flags = IP_NAT_RANGE_MAP_IPS;
  73. mr.range[0].min_ip = mr.range[0].max_ip = newip;
  74. /* ... unless we're doing a MANIP_DST, in which case, make
  75.    sure we map to the correct port */
  76. if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST) {
  77. mr.range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
  78. mr.range[0].min = mr.range[0].max
  79. = ((union ip_conntrack_manip_proto)
  80. { htons(ftpinfo->port) });
  81. }
  82. *verdict = ip_nat_setup_info(ct, &mr, hooknum);
  83. return 1;
  84. }
  85. static int
  86. mangle_rfc959_packet(struct sk_buff **pskb,
  87.      u_int32_t newip,
  88.      u_int16_t port,
  89.      unsigned int matchoff,
  90.      unsigned int matchlen,
  91.      struct ip_conntrack *ct,
  92.      enum ip_conntrack_info ctinfo)
  93. {
  94. char buffer[sizeof("nnn,nnn,nnn,nnn,nnn,nnn")];
  95. MUST_BE_LOCKED(&ip_ftp_lock);
  96. sprintf(buffer, "%u,%u,%u,%u,%u,%u",
  97. NIPQUAD(newip), port>>8, port&0xFF);
  98. DEBUGP("calling ip_nat_mangle_tcp_packetn");
  99. return ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, matchoff, 
  100. matchlen, buffer, strlen(buffer));
  101. }
  102. /* |1|132.235.1.2|6275| */
  103. static int
  104. mangle_eprt_packet(struct sk_buff **pskb,
  105.    u_int32_t newip,
  106.    u_int16_t port,
  107.    unsigned int matchoff,
  108.    unsigned int matchlen,
  109.    struct ip_conntrack *ct,
  110.    enum ip_conntrack_info ctinfo)
  111. {
  112. char buffer[sizeof("|1|255.255.255.255|65535|")];
  113. MUST_BE_LOCKED(&ip_ftp_lock);
  114. sprintf(buffer, "|1|%u.%u.%u.%u|%u|", NIPQUAD(newip), port);
  115. DEBUGP("calling ip_nat_mangle_tcp_packetn");
  116. return ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, matchoff, 
  117. matchlen, buffer, strlen(buffer));
  118. }
  119. /* |1|132.235.1.2|6275| */
  120. static int
  121. mangle_epsv_packet(struct sk_buff **pskb,
  122.    u_int32_t newip,
  123.    u_int16_t port,
  124.    unsigned int matchoff,
  125.    unsigned int matchlen,
  126.    struct ip_conntrack *ct,
  127.    enum ip_conntrack_info ctinfo)
  128. {
  129. char buffer[sizeof("|||65535|")];
  130. MUST_BE_LOCKED(&ip_ftp_lock);
  131. sprintf(buffer, "|||%u|", port);
  132. DEBUGP("calling ip_nat_mangle_tcp_packetn");
  133. return ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, matchoff, 
  134. matchlen, buffer, strlen(buffer));
  135. }
  136. static int (*mangle[])(struct sk_buff **, u_int32_t, u_int16_t,
  137.      unsigned int,
  138.      unsigned int,
  139.      struct ip_conntrack *,
  140.      enum ip_conntrack_info)
  141. = { [IP_CT_FTP_PORT] mangle_rfc959_packet,
  142.     [IP_CT_FTP_PASV] mangle_rfc959_packet,
  143.     [IP_CT_FTP_EPRT] mangle_eprt_packet,
  144.     [IP_CT_FTP_EPSV] mangle_epsv_packet
  145. };
  146. static int ftp_data_fixup(const struct ip_ct_ftp *ct_ftp_info,
  147.   struct ip_conntrack *ct,
  148.   unsigned int datalen,
  149.   struct sk_buff **pskb,
  150.   enum ip_conntrack_info ctinfo)
  151. {
  152. u_int32_t newip;
  153. struct iphdr *iph = (*pskb)->nh.iph;
  154. struct tcphdr *tcph = (void *)iph + iph->ihl*4;
  155. u_int16_t port;
  156. struct ip_conntrack_tuple tuple;
  157. /* Don't care about source port */
  158. const struct ip_conntrack_tuple mask
  159. = { { 0xFFFFFFFF, { 0 } },
  160.     { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF } };
  161. memset(&tuple, 0, sizeof(tuple));
  162. MUST_BE_LOCKED(&ip_ftp_lock);
  163. DEBUGP("FTP_NAT: seq %u + %u in %u + %un",
  164.        ct_ftp_info->seq, ct_ftp_info->len,
  165.        ntohl(tcph->seq), datalen);
  166. /* Change address inside packet to match way we're mapping
  167.    this connection. */
  168. if (ct_ftp_info->ftptype == IP_CT_FTP_PASV
  169.     || ct_ftp_info->ftptype == IP_CT_FTP_EPSV) {
  170. /* PASV/EPSV response: must be where client thinks server
  171.    is */
  172. newip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
  173. /* Expect something from client->server */
  174. tuple.src.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
  175. tuple.dst.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
  176. } else {
  177. /* PORT command: must be where server thinks client is */
  178. newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
  179. /* Expect something from server->client */
  180. tuple.src.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;
  181. tuple.dst.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
  182. }
  183. tuple.dst.protonum = IPPROTO_TCP;
  184. /* Try to get same port: if not, try to change it. */
  185. for (port = ct_ftp_info->port; port != 0; port++) {
  186. tuple.dst.u.tcp.port = htons(port);
  187. if (ip_conntrack_expect_related(ct, &tuple, &mask, NULL) == 0)
  188. break;
  189. }
  190. if (port == 0)
  191. return 0;
  192. if (!mangle[ct_ftp_info->ftptype](pskb, newip, port,
  193.   ct_ftp_info->seq - ntohl(tcph->seq),
  194.   ct_ftp_info->len, ct, ctinfo))
  195. return 0;
  196. return 1;
  197. }
  198. static unsigned int help(struct ip_conntrack *ct,
  199.  struct ip_nat_info *info,
  200.  enum ip_conntrack_info ctinfo,
  201.  unsigned int hooknum,
  202.  struct sk_buff **pskb)
  203. {
  204. struct iphdr *iph = (*pskb)->nh.iph;
  205. struct tcphdr *tcph = (void *)iph + iph->ihl*4;
  206. unsigned int datalen;
  207. int dir;
  208. int score;
  209. struct ip_ct_ftp *ct_ftp_info
  210. = &ct->help.ct_ftp_info;
  211. /* Delete SACK_OK on initial TCP SYNs. */
  212. if (tcph->syn && !tcph->ack)
  213. ip_nat_delete_sack(*pskb, tcph);
  214. /* Only mangle things once: original direction in POST_ROUTING
  215.    and reply direction on PRE_ROUTING. */
  216. dir = CTINFO2DIR(ctinfo);
  217. if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL)
  218.       || (hooknum == NF_IP_PRE_ROUTING && dir == IP_CT_DIR_REPLY))) {
  219. DEBUGP("nat_ftp: Not touching dir %s at hook %sn",
  220.        dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY",
  221.        hooknum == NF_IP_POST_ROUTING ? "POSTROUTING"
  222.        : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING"
  223.        : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???");
  224. return NF_ACCEPT;
  225. }
  226. datalen = (*pskb)->len - iph->ihl * 4 - tcph->doff * 4;
  227. score = 0;
  228. LOCK_BH(&ip_ftp_lock);
  229. if (ct_ftp_info->len) {
  230. /* If it's in the right range... */
  231. score += between(ct_ftp_info->seq, ntohl(tcph->seq),
  232.  ntohl(tcph->seq) + datalen);
  233. score += between(ct_ftp_info->seq + ct_ftp_info->len,
  234.  ntohl(tcph->seq),
  235.  ntohl(tcph->seq) + datalen);
  236. if (score == 1) {
  237. /* Half a match?  This means a partial retransmisison.
  238.    It's a cracker being funky. */
  239. if (net_ratelimit()) {
  240. printk("FTP_NAT: partial packet %u/%u in %u/%un",
  241.        ct_ftp_info->seq, ct_ftp_info->len,
  242.        ntohl(tcph->seq),
  243.        ntohl(tcph->seq) + datalen);
  244. }
  245. UNLOCK_BH(&ip_ftp_lock);
  246. return NF_DROP;
  247. } else if (score == 2) {
  248. if (!ftp_data_fixup(ct_ftp_info, ct, datalen,
  249.     pskb, ctinfo)) {
  250. UNLOCK_BH(&ip_ftp_lock);
  251. return NF_DROP;
  252. }
  253. /* skb may have been reallocated */
  254. iph = (*pskb)->nh.iph;
  255. tcph = (void *)iph + iph->ihl*4;
  256. }
  257. }
  258. UNLOCK_BH(&ip_ftp_lock);
  259. ip_nat_seq_adjust(*pskb, ct, ctinfo);
  260. return NF_ACCEPT;
  261. }
  262. static struct ip_nat_helper ftp[MAX_PORTS];
  263. static char ftp_names[MAX_PORTS][6];
  264. static struct ip_nat_expect ftp_expect
  265. = { { NULL, NULL }, ftp_nat_expected };
  266. /* Not __exit: called from init() */
  267. static void fini(void)
  268. {
  269. int i;
  270. for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
  271. DEBUGP("ip_nat_ftp: unregistering port %dn", ports[i]);
  272. ip_nat_helper_unregister(&ftp[i]);
  273. }
  274. ip_nat_expect_unregister(&ftp_expect);
  275. }
  276. static int __init init(void)
  277. {
  278. int i, ret;
  279. char *tmpname;
  280. ret = ip_nat_expect_register(&ftp_expect);
  281. if (ret == 0) {
  282. if (ports[0] == 0)
  283. ports[0] = 21;
  284. for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
  285. memset(&ftp[i], 0, sizeof(struct ip_nat_helper));
  286. ftp[i].tuple.dst.protonum = IPPROTO_TCP;
  287. ftp[i].tuple.src.u.tcp.port = htons(ports[i]);
  288. ftp[i].mask.dst.protonum = 0xFFFF;
  289. ftp[i].mask.src.u.tcp.port = 0xFFFF;
  290. ftp[i].help = help;
  291. tmpname = &ftp_names[i][0];
  292. sprintf(tmpname, "ftp%2.2d", i);
  293. ftp[i].name = tmpname;
  294. DEBUGP("ip_nat_ftp: Trying to register for port %dn",
  295. ports[i]);
  296. ret = ip_nat_helper_register(&ftp[i]);
  297. if (ret) {
  298. printk("ip_nat_ftp: error registering helper for port %dn", ports[i]);
  299. fini();
  300. return ret;
  301. }
  302. ports_c++;
  303. }
  304. } else {
  305. ip_nat_expect_unregister(&ftp_expect);
  306. }
  307. return ret;
  308. }
  309. module_init(init);
  310. module_exit(fini);
  311. MODULE_LICENSE("GPL");