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

Linux/Unix编程

开发平台:

Unix_Linux

  1. #define __NO_VERSION__
  2. #include <linux/types.h>
  3. #include <linux/sched.h>
  4. #include <linux/timer.h>
  5. #include <linux/netfilter.h>
  6. #include <linux/module.h>
  7. #include <linux/in.h>
  8. #include <linux/ip.h>
  9. #include <linux/tcp.h>
  10. #include <linux/string.h>
  11. #include <net/tcp.h>
  12. #include <linux/netfilter_ipv4/ip_conntrack.h>
  13. #include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
  14. #include <linux/netfilter_ipv4/lockhelp.h>
  15. #if 0
  16. #define DEBUGP printk
  17. #else
  18. #define DEBUGP(format, args...)
  19. #endif
  20. /* Protects conntrack->proto.tcp */
  21. static DECLARE_RWLOCK(tcp_lock);
  22. /* FIXME: Examine ipfilter's timeouts and conntrack transitions more
  23.    closely.  They're more complex. --RR */
  24. /* Actually, I believe that neither ipmasq (where this code is stolen
  25.    from) nor ipfilter do it exactly right.  A new conntrack machine taking
  26.    into account packet loss (which creates uncertainty as to exactly
  27.    the conntrack of the connection) is required.  RSN.  --RR */
  28. static const char *tcp_conntrack_names[] = {
  29. "NONE",
  30. "ESTABLISHED",
  31. "SYN_SENT",
  32. "SYN_RECV",
  33. "FIN_WAIT",
  34. "TIME_WAIT",
  35. "CLOSE",
  36. "CLOSE_WAIT",
  37. "LAST_ACK",
  38. "LISTEN"
  39. };
  40. #define SECS *HZ
  41. #define MINS * 60 SECS
  42. #define HOURS * 60 MINS
  43. #define DAYS * 24 HOURS
  44. static unsigned long tcp_timeouts[]
  45. = { 30 MINS,  /* TCP_CONNTRACK_NONE, */
  46.     5 DAYS, /* TCP_CONNTRACK_ESTABLISHED, */
  47.     2 MINS, /* TCP_CONNTRACK_SYN_SENT, */
  48.     60 SECS, /* TCP_CONNTRACK_SYN_RECV, */
  49.     2 MINS, /* TCP_CONNTRACK_FIN_WAIT, */
  50.     2 MINS, /* TCP_CONNTRACK_TIME_WAIT, */
  51.     10 SECS, /* TCP_CONNTRACK_CLOSE, */
  52.     60 SECS, /* TCP_CONNTRACK_CLOSE_WAIT, */
  53.     30 SECS, /* TCP_CONNTRACK_LAST_ACK, */
  54.     2 MINS, /* TCP_CONNTRACK_LISTEN, */
  55. };
  56. #define sNO TCP_CONNTRACK_NONE
  57. #define sES TCP_CONNTRACK_ESTABLISHED
  58. #define sSS TCP_CONNTRACK_SYN_SENT
  59. #define sSR TCP_CONNTRACK_SYN_RECV
  60. #define sFW TCP_CONNTRACK_FIN_WAIT
  61. #define sTW TCP_CONNTRACK_TIME_WAIT
  62. #define sCL TCP_CONNTRACK_CLOSE
  63. #define sCW TCP_CONNTRACK_CLOSE_WAIT
  64. #define sLA TCP_CONNTRACK_LAST_ACK
  65. #define sLI TCP_CONNTRACK_LISTEN
  66. #define sIV TCP_CONNTRACK_MAX
  67. static enum tcp_conntrack tcp_conntracks[2][5][TCP_CONNTRACK_MAX] = {
  68. {
  69. /* ORIGINAL */
  70. /*    sNO, sES, sSS, sSR, sFW, sTW, sCL, sCW, sLA, sLI  */
  71. /*syn*/ {sSS, sES, sSS, sSR, sSS, sSS, sSS, sSS, sSS, sLI },
  72. /*fin*/ {sTW, sFW, sSS, sTW, sFW, sTW, sCL, sTW, sLA, sLI },
  73. /*ack*/ {sES, sES, sSS, sES, sFW, sTW, sCL, sCW, sLA, sES },
  74. /*rst*/ {sCL, sCL, sSS, sCL, sCL, sTW, sCL, sCL, sCL, sCL },
  75. /*none*/{sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV }
  76. },
  77. {
  78. /* REPLY */
  79. /*    sNO, sES, sSS, sSR, sFW, sTW, sCL, sCW, sLA, sLI  */
  80. /*syn*/ {sSR, sES, sSR, sSR, sSR, sSR, sSR, sSR, sSR, sSR },
  81. /*fin*/ {sCL, sCW, sSS, sTW, sTW, sTW, sCL, sCW, sLA, sLI },
  82. /*ack*/ {sCL, sES, sSS, sSR, sFW, sTW, sCL, sCW, sCL, sLI },
  83. /*rst*/ {sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sLA, sLI },
  84. /*none*/{sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV }
  85. }
  86. };
  87. static int tcp_pkt_to_tuple(const void *datah, size_t datalen,
  88.     struct ip_conntrack_tuple *tuple)
  89. {
  90. const struct tcphdr *hdr = datah;
  91. tuple->src.u.tcp.port = hdr->source;
  92. tuple->dst.u.tcp.port = hdr->dest;
  93. return 1;
  94. }
  95. static int tcp_invert_tuple(struct ip_conntrack_tuple *tuple,
  96.     const struct ip_conntrack_tuple *orig)
  97. {
  98. tuple->src.u.tcp.port = orig->dst.u.tcp.port;
  99. tuple->dst.u.tcp.port = orig->src.u.tcp.port;
  100. return 1;
  101. }
  102. /* Print out the per-protocol part of the tuple. */
  103. static unsigned int tcp_print_tuple(char *buffer,
  104.     const struct ip_conntrack_tuple *tuple)
  105. {
  106. return sprintf(buffer, "sport=%hu dport=%hu ",
  107.        ntohs(tuple->src.u.tcp.port),
  108.        ntohs(tuple->dst.u.tcp.port));
  109. }
  110. /* Print out the private part of the conntrack. */
  111. static unsigned int tcp_print_conntrack(char *buffer,
  112. const struct ip_conntrack *conntrack)
  113. {
  114. enum tcp_conntrack state;
  115. READ_LOCK(&tcp_lock);
  116. state = conntrack->proto.tcp.state;
  117. READ_UNLOCK(&tcp_lock);
  118. return sprintf(buffer, "%s ", tcp_conntrack_names[state]);
  119. }
  120. static unsigned int get_conntrack_index(const struct tcphdr *tcph)
  121. {
  122. if (tcph->rst) return 3;
  123. else if (tcph->syn) return 0;
  124. else if (tcph->fin) return 1;
  125. else if (tcph->ack) return 2;
  126. else return 4;
  127. }
  128. /* Returns verdict for packet, or -1 for invalid. */
  129. static int tcp_packet(struct ip_conntrack *conntrack,
  130.       struct iphdr *iph, size_t len,
  131.       enum ip_conntrack_info ctinfo)
  132. {
  133. enum tcp_conntrack newconntrack, oldtcpstate;
  134. struct tcphdr *tcph = (struct tcphdr *)((u_int32_t *)iph + iph->ihl);
  135. /* We're guaranteed to have the base header, but maybe not the
  136.            options. */
  137. if (len < (iph->ihl + tcph->doff) * 4) {
  138. DEBUGP("ip_conntrack_tcp: Truncated packet.n");
  139. return -1;
  140. }
  141. WRITE_LOCK(&tcp_lock);
  142. oldtcpstate = conntrack->proto.tcp.state;
  143. newconntrack
  144. = tcp_conntracks
  145. [CTINFO2DIR(ctinfo)]
  146. [get_conntrack_index(tcph)][oldtcpstate];
  147. /* Invalid */
  148. if (newconntrack == TCP_CONNTRACK_MAX) {
  149. DEBUGP("ip_conntrack_tcp: Invalid dir=%i index=%u conntrack=%un",
  150.        CTINFO2DIR(ctinfo), get_conntrack_index(tcph),
  151.        conntrack->proto.tcp.state);
  152. WRITE_UNLOCK(&tcp_lock);
  153. return -1;
  154. }
  155. conntrack->proto.tcp.state = newconntrack;
  156. /* Poor man's window tracking: record SYN/ACK for handshake check */
  157. if (oldtcpstate == TCP_CONNTRACK_SYN_SENT
  158.     && CTINFO2DIR(ctinfo) == IP_CT_DIR_REPLY
  159.     && tcph->syn && tcph->ack)
  160. conntrack->proto.tcp.handshake_ack
  161. = htonl(ntohl(tcph->seq) + 1);
  162. WRITE_UNLOCK(&tcp_lock);
  163. /* If only reply is a RST, we can consider ourselves not to
  164.    have an established connection: this is a fairly common
  165.    problem case, so we can delete the conntrack
  166.    immediately.  --RR */
  167. if (!(conntrack->status & IPS_SEEN_REPLY) && tcph->rst) {
  168. if (del_timer(&conntrack->timeout))
  169. conntrack->timeout.function((unsigned long)conntrack);
  170. } else {
  171. /* Set ASSURED if we see see valid ack in ESTABLISHED after SYN_RECV */
  172. if (oldtcpstate == TCP_CONNTRACK_SYN_RECV
  173.     && CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL
  174.     && tcph->ack && !tcph->syn
  175.     && tcph->ack_seq == conntrack->proto.tcp.handshake_ack)
  176. set_bit(IPS_ASSURED_BIT, &conntrack->status);
  177. ip_ct_refresh(conntrack, tcp_timeouts[newconntrack]);
  178. }
  179. return NF_ACCEPT;
  180. }
  181. /* Called when a new connection for this protocol found. */
  182. static int tcp_new(struct ip_conntrack *conntrack,
  183.    struct iphdr *iph, size_t len)
  184. {
  185. enum tcp_conntrack newconntrack;
  186. struct tcphdr *tcph = (struct tcphdr *)((u_int32_t *)iph + iph->ihl);
  187. /* Don't need lock here: this conntrack not in circulation yet */
  188. newconntrack
  189. = tcp_conntracks[0][get_conntrack_index(tcph)]
  190. [TCP_CONNTRACK_NONE];
  191. /* Invalid: delete conntrack */
  192. if (newconntrack == TCP_CONNTRACK_MAX) {
  193. DEBUGP("ip_conntrack_tcp: invalid new deleting.n");
  194. return 0;
  195. }
  196. conntrack->proto.tcp.state = newconntrack;
  197. return 1;
  198. }
  199. static int tcp_exp_matches_pkt(struct ip_conntrack_expect *exp,
  200.        struct sk_buff **pskb)
  201. {
  202. struct iphdr *iph = (*pskb)->nh.iph;
  203. struct tcphdr *tcph = (struct tcphdr *)((u_int32_t *)iph + iph->ihl);
  204. unsigned int datalen;
  205. datalen = (*pskb)->len - iph->ihl*4 - tcph->doff*4;
  206. return between(exp->seq, ntohl(tcph->seq), ntohl(tcph->seq) + datalen);
  207. }
  208. struct ip_conntrack_protocol ip_conntrack_protocol_tcp
  209. = { { NULL, NULL }, IPPROTO_TCP, "tcp",
  210.     tcp_pkt_to_tuple, tcp_invert_tuple, tcp_print_tuple, tcp_print_conntrack,
  211.     tcp_packet, tcp_new, NULL, tcp_exp_matches_pkt, NULL };