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