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

Linux/Unix编程

开发平台:

Unix_Linux

  1. /* ip_nat_mangle.c - generic support functions for NAT helpers 
  2.  *
  3.  * (C) 2000-2002 by Harald Welte <laforge@gnumonks.org>
  4.  *
  5.  * distributed under the terms of GNU GPL
  6.  *
  7.  *  14 Jan 2002 Harald Welte <laforge@gnumonks.org>:
  8.  * - add support for SACK adjustment 
  9.  * 14 Mar 2002 Harald Welte <laforge@gnumonks.org>:
  10.  * - merge SACK support into newnat API
  11.  */
  12. #include <linux/version.h>
  13. #include <linux/config.h>
  14. #include <linux/module.h>
  15. #include <linux/kmod.h>
  16. #include <linux/types.h>
  17. #include <linux/timer.h>
  18. #include <linux/skbuff.h>
  19. #include <linux/netfilter_ipv4.h>
  20. #include <linux/brlock.h>
  21. #include <net/checksum.h>
  22. #include <net/icmp.h>
  23. #include <net/ip.h>
  24. #include <net/tcp.h>
  25. #define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_nat_lock)
  26. #define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_nat_lock)
  27. #include <linux/netfilter_ipv4/ip_conntrack.h>
  28. #include <linux/netfilter_ipv4/ip_conntrack_helper.h>
  29. #include <linux/netfilter_ipv4/ip_nat.h>
  30. #include <linux/netfilter_ipv4/ip_nat_protocol.h>
  31. #include <linux/netfilter_ipv4/ip_nat_core.h>
  32. #include <linux/netfilter_ipv4/ip_nat_helper.h>
  33. #include <linux/netfilter_ipv4/listhelp.h>
  34. #if 0
  35. #define DEBUGP printk
  36. #define DUMP_OFFSET(x) printk("offset_before=%d, offset_after=%d, correction_pos=%un", x->offset_before, x->offset_after, x->correction_pos);
  37. #else
  38. #define DEBUGP(format, args...)
  39. #define DUMP_OFFSET(x)
  40. #endif
  41. DECLARE_LOCK(ip_nat_seqofs_lock);
  42.  
  43. static inline int 
  44. ip_nat_resize_packet(struct sk_buff **skb,
  45.      struct ip_conntrack *ct, 
  46.      enum ip_conntrack_info ctinfo,
  47.      int new_size)
  48. {
  49. struct iphdr *iph;
  50. struct tcphdr *tcph;
  51. void *data;
  52. int dir;
  53. struct ip_nat_seq *this_way, *other_way;
  54. DEBUGP("ip_nat_resize_packet: old_size = %u, new_size = %un",
  55. (*skb)->len, new_size);
  56. iph = (*skb)->nh.iph;
  57. tcph = (void *)iph + iph->ihl*4;
  58. data = (void *)tcph + tcph->doff*4;
  59. dir = CTINFO2DIR(ctinfo);
  60. this_way = &ct->nat.info.seq[dir];
  61. other_way = &ct->nat.info.seq[!dir];
  62. if (new_size > (*skb)->len + skb_tailroom(*skb)) {
  63. struct sk_buff *newskb;
  64. newskb = skb_copy_expand(*skb, skb_headroom(*skb),
  65.  new_size - (*skb)->len,
  66.  GFP_ATOMIC);
  67. if (!newskb) {
  68. printk("ip_nat_resize_packet: oomn");
  69. return 0;
  70. } else {
  71. kfree_skb(*skb);
  72. *skb = newskb;
  73. }
  74. }
  75. iph = (*skb)->nh.iph;
  76. tcph = (void *)iph + iph->ihl*4;
  77. data = (void *)tcph + tcph->doff*4;
  78. DEBUGP("ip_nat_resize_packet: Seq_offset before: ");
  79. DUMP_OFFSET(this_way);
  80. LOCK_BH(&ip_nat_seqofs_lock);
  81. /* SYN adjust. If it's uninitialized, of this is after last 
  82.  * correction, record it: we don't handle more than one 
  83.  * adjustment in the window, but do deal with common case of a 
  84.  * retransmit */
  85. if (this_way->offset_before == this_way->offset_after
  86.     || before(this_way->correction_pos, ntohl(tcph->seq))) {
  87. this_way->correction_pos = ntohl(tcph->seq);
  88. this_way->offset_before = this_way->offset_after;
  89. this_way->offset_after = (int32_t)
  90. this_way->offset_before + new_size - (*skb)->len;
  91. }
  92. UNLOCK_BH(&ip_nat_seqofs_lock);
  93. DEBUGP("ip_nat_resize_packet: Seq_offset after: ");
  94. DUMP_OFFSET(this_way);
  95. return 1;
  96. }
  97. /* Generic function for mangling variable-length address changes inside
  98.  * NATed connections (like the PORT XXX,XXX,XXX,XXX,XXX,XXX command in FTP).
  99.  *
  100.  * Takes care about all the nasty sequence number changes, checksumming,
  101.  * skb enlargement, ...
  102.  *
  103.  * */
  104. int 
  105. ip_nat_mangle_tcp_packet(struct sk_buff **skb,
  106.  struct ip_conntrack *ct,
  107.  enum ip_conntrack_info ctinfo,
  108.  unsigned int match_offset,
  109.  unsigned int match_len,
  110.  char *rep_buffer,
  111.  unsigned int rep_len)
  112. {
  113. struct iphdr *iph = (*skb)->nh.iph;
  114. struct tcphdr *tcph;
  115. unsigned char *data;
  116. u_int32_t tcplen, newlen, newtcplen;
  117. tcplen = (*skb)->len - iph->ihl*4;
  118. newtcplen = tcplen - match_len + rep_len;
  119. newlen = iph->ihl*4 + newtcplen;
  120. if (newlen > 65535) {
  121. if (net_ratelimit())
  122. printk("ip_nat_mangle_tcp_packet: nat'ed packet "
  123. "exceeds maximum packet sizen");
  124. return 0;
  125. }
  126. if ((*skb)->len != newlen) {
  127. if (!ip_nat_resize_packet(skb, ct, ctinfo, newlen)) {
  128. printk("resize_packet failed!!n");
  129. return 0;
  130. }
  131. }
  132. /* Alexey says: if a hook changes _data_ ... it can break
  133.    original packet sitting in tcp queue and this is fatal */
  134. if (skb_cloned(*skb)) {
  135. struct sk_buff *nskb = skb_copy(*skb, GFP_ATOMIC);
  136. if (!nskb) {
  137. if (net_ratelimit())
  138. printk("Out of memory cloning TCP packetn");
  139. return 0;
  140. }
  141. /* Rest of kernel will get very unhappy if we pass it
  142.    a suddenly-orphaned skbuff */
  143. if ((*skb)->sk)
  144. skb_set_owner_w(nskb, (*skb)->sk);
  145. kfree_skb(*skb);
  146. *skb = nskb;
  147. }
  148. /* skb may be copied !! */
  149. iph = (*skb)->nh.iph;
  150. tcph = (void *)iph + iph->ihl*4;
  151. data = (void *)tcph + tcph->doff*4;
  152. /* move post-replacement */
  153. memmove(data + match_offset + rep_len,
  154.  data + match_offset + match_len,
  155.  (*skb)->tail - (data + match_offset + match_len));
  156. /* insert data from buffer */
  157. memcpy(data + match_offset, rep_buffer, rep_len);
  158. /* update skb info */
  159. if (newlen > (*skb)->len) {
  160. DEBUGP("ip_nat_mangle_tcp_packet: Extending packet by "
  161. "%u to %u bytesn", newlen - (*skb)->len, newlen);
  162. skb_put(*skb, newlen - (*skb)->len);
  163. } else {
  164. DEBUGP("ip_nat_mangle_tcp_packet: Shrinking packet from "
  165. "%u to %u bytesn", (*skb)->len, newlen);
  166. skb_trim(*skb, newlen);
  167. }
  168. /* fix checksum information */
  169. iph->tot_len = htons(newlen);
  170. (*skb)->csum = csum_partial((char *)tcph + tcph->doff*4,
  171.     newtcplen - tcph->doff*4, 0);
  172. tcph->check = 0;
  173. tcph->check = tcp_v4_check(tcph, newtcplen, iph->saddr, iph->daddr,
  174.    csum_partial((char *)tcph, tcph->doff*4,
  175.    (*skb)->csum));
  176. ip_send_check(iph);
  177. return 1;
  178. }
  179. /* Adjust one found SACK option including checksum correction */
  180. static void
  181. sack_adjust(struct tcphdr *tcph, 
  182.     unsigned char *ptr, 
  183.     struct ip_nat_seq *natseq)
  184. {
  185. struct tcp_sack_block *sp = (struct tcp_sack_block *)(ptr+2);
  186. int num_sacks = (ptr[1] - TCPOLEN_SACK_BASE)>>3;
  187. int i;
  188. for (i = 0; i < num_sacks; i++, sp++) {
  189. u_int32_t new_start_seq, new_end_seq;
  190. if (after(ntohl(sp->start_seq) - natseq->offset_before,
  191.   natseq->correction_pos))
  192. new_start_seq = ntohl(sp->start_seq) 
  193. - natseq->offset_after;
  194. else
  195. new_start_seq = ntohl(sp->start_seq) 
  196. - natseq->offset_before;
  197. new_start_seq = htonl(new_start_seq);
  198. if (after(ntohl(sp->end_seq) - natseq->offset_before,
  199.   natseq->correction_pos))
  200. new_end_seq = ntohl(sp->end_seq)
  201.       - natseq->offset_after;
  202. else
  203. new_end_seq = ntohl(sp->end_seq)
  204.       - natseq->offset_before;
  205. new_end_seq = htonl(new_end_seq);
  206. DEBUGP("sack_adjust: start_seq: %d->%d, end_seq: %d->%dn",
  207. ntohl(sp->start_seq), new_start_seq,
  208. ntohl(sp->end_seq), new_end_seq);
  209. tcph->check = 
  210. ip_nat_cheat_check(~sp->start_seq, new_start_seq,
  211.    ip_nat_cheat_check(~sp->end_seq, 
  212.           new_end_seq,
  213.       tcph->check));
  214. sp->start_seq = new_start_seq;
  215. sp->end_seq = new_end_seq;
  216. }
  217. }
  218. /* TCP SACK sequence number adjustment, return 0 if sack found and adjusted */
  219. static inline int
  220. ip_nat_sack_adjust(struct sk_buff *skb,
  221. struct ip_conntrack *ct,
  222. enum ip_conntrack_info ctinfo)
  223. {
  224. struct iphdr *iph;
  225. struct tcphdr *tcph;
  226. unsigned char *ptr;
  227. int length, dir, sack_adjusted = 0;
  228. iph = skb->nh.iph;
  229. tcph = (void *)iph + iph->ihl*4;
  230. length = (tcph->doff*4)-sizeof(struct tcphdr);
  231. ptr = (unsigned char *)(tcph+1);
  232. dir = CTINFO2DIR(ctinfo);
  233. while (length > 0) {
  234. int opcode = *ptr++;
  235. int opsize;
  236. switch (opcode) {
  237. case TCPOPT_EOL:
  238. return !sack_adjusted;
  239. case TCPOPT_NOP:
  240. length--;
  241. continue;
  242. default:
  243. opsize = *ptr++;
  244. if (opsize > length) /* no partial opts */
  245. return !sack_adjusted;
  246. if (opcode == TCPOPT_SACK) {
  247. /* found SACK */
  248. if((opsize >= (TCPOLEN_SACK_BASE
  249.        +TCPOLEN_SACK_PERBLOCK)) &&
  250.    !((opsize - TCPOLEN_SACK_BASE)
  251.      % TCPOLEN_SACK_PERBLOCK))
  252. sack_adjust(tcph, ptr-2,
  253.     &ct->nat.info.seq[!dir]);
  254. sack_adjusted = 1;
  255. }
  256. ptr += opsize-2;
  257. length -= opsize;
  258. }
  259. }
  260. return !sack_adjusted;
  261. }
  262. /* TCP sequence number adjustment */
  263. int 
  264. ip_nat_seq_adjust(struct sk_buff *skb, 
  265.   struct ip_conntrack *ct, 
  266.   enum ip_conntrack_info ctinfo)
  267. {
  268. struct iphdr *iph;
  269. struct tcphdr *tcph;
  270. int dir, newseq, newack;
  271. struct ip_nat_seq *this_way, *other_way;
  272. iph = skb->nh.iph;
  273. tcph = (void *)iph + iph->ihl*4;
  274. dir = CTINFO2DIR(ctinfo);
  275. this_way = &ct->nat.info.seq[dir];
  276. other_way = &ct->nat.info.seq[!dir];
  277. if (after(ntohl(tcph->seq), this_way->correction_pos))
  278. newseq = ntohl(tcph->seq) + this_way->offset_after;
  279. else
  280. newseq = ntohl(tcph->seq) + this_way->offset_before;
  281. newseq = htonl(newseq);
  282. if (after(ntohl(tcph->ack_seq) - other_way->offset_before,
  283.   other_way->correction_pos))
  284. newack = ntohl(tcph->ack_seq) - other_way->offset_after;
  285. else
  286. newack = ntohl(tcph->ack_seq) - other_way->offset_before;
  287. newack = htonl(newack);
  288. tcph->check = ip_nat_cheat_check(~tcph->seq, newseq,
  289.  ip_nat_cheat_check(~tcph->ack_seq, 
  290.       newack, 
  291.     tcph->check));
  292. DEBUGP("Adjusting sequence number from %u->%u, ack from %u->%un",
  293. ntohl(tcph->seq), ntohl(newseq), ntohl(tcph->ack_seq),
  294. ntohl(newack));
  295. tcph->seq = newseq;
  296. tcph->ack_seq = newack;
  297. ip_nat_sack_adjust(skb, ct, ctinfo);
  298. return 0;
  299. }
  300. static inline int
  301. helper_cmp(const struct ip_nat_helper *helper,
  302.    const struct ip_conntrack_tuple *tuple)
  303. {
  304. return ip_ct_tuple_mask_cmp(tuple, &helper->tuple, &helper->mask);
  305. }
  306. #define MODULE_MAX_NAMELEN 32
  307. int ip_nat_helper_register(struct ip_nat_helper *me)
  308. {
  309. int ret = 0;
  310. if (me->me && !(me->flags & IP_NAT_HELPER_F_STANDALONE)) {
  311. struct ip_conntrack_helper *ct_helper;
  312. if ((ct_helper = ip_ct_find_helper(&me->tuple))
  313.     && ct_helper->me) {
  314. __MOD_INC_USE_COUNT(ct_helper->me);
  315. } else {
  316. /* We are a NAT helper for protocol X.  If we need
  317.  * respective conntrack helper for protoccol X, compute
  318.  * conntrack helper name and try to load module */
  319. char name[MODULE_MAX_NAMELEN];
  320. const char *tmp = me->me->name;
  321. if (strlen(tmp) + 6 > MODULE_MAX_NAMELEN) {
  322. printk(__FUNCTION__ ": unable to "
  323.        "compute conntrack helper name "
  324.        "from %sn", tmp);
  325. return -EBUSY;
  326. }
  327. tmp += 6;
  328. sprintf(name, "ip_conntrack%s", tmp);
  329. #ifdef CONFIG_KMOD
  330. if (!request_module(name)
  331.     && (ct_helper = ip_ct_find_helper(&me->tuple))
  332.     && ct_helper->me) {
  333. __MOD_INC_USE_COUNT(ct_helper->me);
  334. } else {
  335. printk("unable to load module %sn", name);
  336. return -EBUSY;
  337. }
  338. #else
  339. printk("unable to load module %s automatically "
  340.        "because kernel was compiled without kernel "
  341.        "module loader supportn", name);
  342. return -EBUSY;
  343. #endif
  344. }
  345. }
  346. WRITE_LOCK(&ip_nat_lock);
  347. if (LIST_FIND(&helpers, helper_cmp, struct ip_nat_helper *,&me->tuple))
  348. ret = -EBUSY;
  349. else {
  350. list_prepend(&helpers, me);
  351. MOD_INC_USE_COUNT;
  352. }
  353. WRITE_UNLOCK(&ip_nat_lock);
  354. return ret;
  355. }
  356. static int
  357. kill_helper(const struct ip_conntrack *i, void *helper)
  358. {
  359. int ret;
  360. READ_LOCK(&ip_nat_lock);
  361. ret = (i->nat.info.helper == helper);
  362. READ_UNLOCK(&ip_nat_lock);
  363. return ret;
  364. }
  365. void ip_nat_helper_unregister(struct ip_nat_helper *me)
  366. {
  367. int found = 0;
  368. WRITE_LOCK(&ip_nat_lock);
  369. /* Autoloading conntrack helper might have failed */
  370. if (LIST_FIND(&helpers, helper_cmp, struct ip_nat_helper *,&me->tuple)) {
  371. LIST_DELETE(&helpers, me);
  372. found = 1;
  373. }
  374. WRITE_UNLOCK(&ip_nat_lock);
  375. /* Someone could be still looking at the helper in a bh. */
  376. br_write_lock_bh(BR_NETPROTO_LOCK);
  377. br_write_unlock_bh(BR_NETPROTO_LOCK);
  378. /* Find anything using it, and umm, kill them.  We can't turn
  379.    them into normal connections: if we've adjusted SYNs, then
  380.    they'll ackstorm.  So we just drop it.  We used to just
  381.    bump module count when a connection existed, but that
  382.    forces admins to gen fake RSTs or bounce box, either of
  383.    which is just a long-winded way of making things
  384.    worse. --RR */
  385. ip_ct_selective_cleanup(kill_helper, me);
  386. if (found)
  387. MOD_DEC_USE_COUNT;
  388. /* If we are no standalone NAT helper, we need to decrement usage count
  389.  * on our conntrack helper */
  390. if (me->me && !(me->flags & IP_NAT_HELPER_F_STANDALONE)) {
  391. struct ip_conntrack_helper *ct_helper;
  392. if ((ct_helper = ip_ct_find_helper(&me->tuple))
  393.     && ct_helper->me) {
  394. __MOD_DEC_USE_COUNT(ct_helper->me);
  395. } else 
  396. printk(__FUNCTION__ ": unable to decrement usage count"
  397.        " of conntrack helper %sn", me->me->name);
  398. }
  399. }