📄 ip_conntrack_proto_tcp.c
字号:
/* (C) 1999-2001 Paul `Rusty' Russell * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>: * - Real stateful connection tracking * - Modified state transitions table * - Window scaling support added * - SACK support added * * Willy Tarreau: * - State table bugfixes * - More robust state changes * - Tuning timer parameters * * version 2.2 */#include <linux/config.h>#include <linux/types.h>#include <linux/sched.h>#include <linux/timer.h>#include <linux/netfilter.h>#include <linux/module.h>#include <linux/in.h>#include <linux/ip.h>#include <linux/tcp.h>#include <linux/spinlock.h>#include <net/tcp.h>#include <linux/netfilter.h>#include <linux/netfilter_ipv4.h>#include <linux/netfilter_ipv4/ip_conntrack.h>#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>#if 0#define DEBUGP printk#define DEBUGP_VARS#else#define DEBUGP(format, args...)#endif/* Protects conntrack->proto.tcp */static DEFINE_RWLOCK(tcp_lock);/* "Be conservative in what you do, be liberal in what you accept from others." If it's non-zero, we mark only out of window RST segments as INVALID. */int ip_ct_tcp_be_liberal = 0;/* When connection is picked up from the middle, how many packets are required to pass in each direction when we assume we are in sync - if any side uses window scaling, we lost the game. If it is set to zero, we disable picking up already established connections. */int ip_ct_tcp_loose = 3;/* Max number of the retransmitted packets without receiving an (acceptable) ACK from the destination. If this number is reached, a shorter timer will be started. */int ip_ct_tcp_max_retrans = 3; /* FIXME: Examine ipfilter's timeouts and conntrack transitions more closely. They're more complex. --RR */static const char *tcp_conntrack_names[] = { "NONE", "SYN_SENT", "SYN_RECV", "ESTABLISHED", "FIN_WAIT", "CLOSE_WAIT", "LAST_ACK", "TIME_WAIT", "CLOSE", "LISTEN"}; #define SECS * HZ#define MINS * 60 SECS#define HOURS * 60 MINS#define DAYS * 24 HOURSunsigned long ip_ct_tcp_timeout_syn_sent = 2 MINS;unsigned long ip_ct_tcp_timeout_syn_recv = 60 SECS;unsigned long ip_ct_tcp_timeout_established = 5 DAYS;unsigned long ip_ct_tcp_timeout_fin_wait = 2 MINS;unsigned long ip_ct_tcp_timeout_close_wait = 60 SECS;unsigned long ip_ct_tcp_timeout_last_ack = 30 SECS;unsigned long ip_ct_tcp_timeout_time_wait = 2 MINS;unsigned long ip_ct_tcp_timeout_close = 10 SECS;/* RFC1122 says the R2 limit should be at least 100 seconds. Linux uses 15 packets as limit, which corresponds to ~13-30min depending on RTO. */unsigned long ip_ct_tcp_timeout_max_retrans = 5 MINS; static const unsigned long * tcp_timeouts[]= { NULL, /* TCP_CONNTRACK_NONE */ &ip_ct_tcp_timeout_syn_sent, /* TCP_CONNTRACK_SYN_SENT, */ &ip_ct_tcp_timeout_syn_recv, /* TCP_CONNTRACK_SYN_RECV, */ &ip_ct_tcp_timeout_established, /* TCP_CONNTRACK_ESTABLISHED, */ &ip_ct_tcp_timeout_fin_wait, /* TCP_CONNTRACK_FIN_WAIT, */ &ip_ct_tcp_timeout_close_wait, /* TCP_CONNTRACK_CLOSE_WAIT, */ &ip_ct_tcp_timeout_last_ack, /* TCP_CONNTRACK_LAST_ACK, */ &ip_ct_tcp_timeout_time_wait, /* TCP_CONNTRACK_TIME_WAIT, */ &ip_ct_tcp_timeout_close, /* TCP_CONNTRACK_CLOSE, */ NULL, /* TCP_CONNTRACK_LISTEN */ }; #define sNO TCP_CONNTRACK_NONE#define sSS TCP_CONNTRACK_SYN_SENT#define sSR TCP_CONNTRACK_SYN_RECV#define sES TCP_CONNTRACK_ESTABLISHED#define sFW TCP_CONNTRACK_FIN_WAIT#define sCW TCP_CONNTRACK_CLOSE_WAIT#define sLA TCP_CONNTRACK_LAST_ACK#define sTW TCP_CONNTRACK_TIME_WAIT#define sCL TCP_CONNTRACK_CLOSE#define sLI TCP_CONNTRACK_LISTEN#define sIV TCP_CONNTRACK_MAX#define sIG TCP_CONNTRACK_IGNORE/* What TCP flags are set from RST/SYN/FIN/ACK. */enum tcp_bit_set { TCP_SYN_SET, TCP_SYNACK_SET, TCP_FIN_SET, TCP_ACK_SET, TCP_RST_SET, TCP_NONE_SET,}; /* * The TCP state transition table needs a few words... * * We are the man in the middle. All the packets go through us * but might get lost in transit to the destination. * It is assumed that the destinations can't receive segments * we haven't seen. * * The checked segment is in window, but our windows are *not* * equivalent with the ones of the sender/receiver. We always * try to guess the state of the current sender. * * The meaning of the states are: * * NONE: initial state * SYN_SENT: SYN-only packet seen * SYN_RECV: SYN-ACK packet seen * ESTABLISHED: ACK packet seen * FIN_WAIT: FIN packet seen * CLOSE_WAIT: ACK seen (after FIN) * LAST_ACK: FIN seen (after FIN) * TIME_WAIT: last ACK seen * CLOSE: closed connection * * LISTEN state is not used. * * Packets marked as IGNORED (sIG): * if they may be either invalid or valid * and the receiver may send back a connection * closing RST or a SYN/ACK. * * Packets marked as INVALID (sIV): * if they are invalid * or we do not support the request (simultaneous open) */static const enum tcp_conntrack tcp_conntracks[2][6][TCP_CONNTRACK_MAX] = { {/* ORIGINAL *//* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI *//*syn*/ { sSS, sSS, sIG, sIG, sIG, sIG, sIG, sSS, sSS, sIV },/* * sNO -> sSS Initialize a new connection * sSS -> sSS Retransmitted SYN * sSR -> sIG Late retransmitted SYN? * sES -> sIG Error: SYNs in window outside the SYN_SENT state * are errors. Receiver will reply with RST * and close the connection. * Or we are not in sync and hold a dead connection. * sFW -> sIG * sCW -> sIG * sLA -> sIG * sTW -> sSS Reopened connection (RFC 1122). * sCL -> sSS *//* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI *//*synack*/ { sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV },/* * A SYN/ACK from the client is always invalid: * - either it tries to set up a simultaneous open, which is * not supported; * - or the firewall has just been inserted between the two hosts * during the session set-up. The SYN will be retransmitted * by the true client (or it'll time out). *//* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI *//*fin*/ { sIV, sIV, sFW, sFW, sLA, sLA, sLA, sTW, sCL, sIV },/* * sNO -> sIV Too late and no reason to do anything... * sSS -> sIV Client migth not send FIN in this state: * we enforce waiting for a SYN/ACK reply first. * sSR -> sFW Close started. * sES -> sFW * sFW -> sLA FIN seen in both directions, waiting for * the last ACK. * Migth be a retransmitted FIN as well... * sCW -> sLA * sLA -> sLA Retransmitted FIN. Remain in the same state. * sTW -> sTW * sCL -> sCL *//* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI *//*ack*/ { sES, sIV, sES, sES, sCW, sCW, sTW, sTW, sCL, sIV },/* * sNO -> sES Assumed. * sSS -> sIV ACK is invalid: we haven't seen a SYN/ACK yet. * sSR -> sES Established state is reached. * sES -> sES :-) * sFW -> sCW Normal close request answered by ACK. * sCW -> sCW * sLA -> sTW Last ACK detected. * sTW -> sTW Retransmitted last ACK. Remain in the same state. * sCL -> sCL *//* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI *//*rst*/ { sIV, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sIV },/*none*/ { sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV } }, {/* REPLY *//* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI *//*syn*/ { sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV },/* * sNO -> sIV Never reached. * sSS -> sIV Simultaneous open, not supported * sSR -> sIV Simultaneous open, not supported. * sES -> sIV Server may not initiate a connection. * sFW -> sIV * sCW -> sIV * sLA -> sIV * sTW -> sIV Reopened connection, but server may not do it. * sCL -> sIV *//* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI *//*synack*/ { sIV, sSR, sSR, sIG, sIG, sIG, sIG, sIG, sIG, sIV },/* * sSS -> sSR Standard open. * sSR -> sSR Retransmitted SYN/ACK. * sES -> sIG Late retransmitted SYN/ACK? * sFW -> sIG Might be SYN/ACK answering ignored SYN * sCW -> sIG * sLA -> sIG * sTW -> sIG * sCL -> sIG *//* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI *//*fin*/ { sIV, sIV, sFW, sFW, sLA, sLA, sLA, sTW, sCL, sIV },/* * sSS -> sIV Server might not send FIN in this state. * sSR -> sFW Close started. * sES -> sFW * sFW -> sLA FIN seen in both directions. * sCW -> sLA * sLA -> sLA Retransmitted FIN. * sTW -> sTW * sCL -> sCL *//* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI *//*ack*/ { sIV, sIG, sSR, sES, sCW, sCW, sTW, sTW, sCL, sIV },/* * sSS -> sIG Might be a half-open connection. * sSR -> sSR Might answer late resent SYN. * sES -> sES :-) * sFW -> sCW Normal close request answered by ACK. * sCW -> sCW * sLA -> sTW Last ACK detected. * sTW -> sTW Retransmitted last ACK. * sCL -> sCL *//* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI *//*rst*/ { sIV, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sIV },/*none*/ { sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV } }};static int tcp_pkt_to_tuple(const struct sk_buff *skb, unsigned int dataoff, struct ip_conntrack_tuple *tuple){ struct tcphdr _hdr, *hp; /* Actually only need first 8 bytes. */ hp = skb_header_pointer(skb, dataoff, 8, &_hdr); if (hp == NULL) return 0; tuple->src.u.tcp.port = hp->source; tuple->dst.u.tcp.port = hp->dest; return 1;}static int tcp_invert_tuple(struct ip_conntrack_tuple *tuple, const struct ip_conntrack_tuple *orig){ tuple->src.u.tcp.port = orig->dst.u.tcp.port; tuple->dst.u.tcp.port = orig->src.u.tcp.port; return 1;}/* Print out the per-protocol part of the tuple. */static int tcp_print_tuple(struct seq_file *s, const struct ip_conntrack_tuple *tuple){ return seq_printf(s, "sport=%hu dport=%hu ", ntohs(tuple->src.u.tcp.port), ntohs(tuple->dst.u.tcp.port));}/* Print out the private part of the conntrack. */static int tcp_print_conntrack(struct seq_file *s, const struct ip_conntrack *conntrack){ enum tcp_conntrack state; read_lock_bh(&tcp_lock); state = conntrack->proto.tcp.state; read_unlock_bh(&tcp_lock); return seq_printf(s, "%s ", tcp_conntrack_names[state]);}#if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \ defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE)static int tcp_to_nfattr(struct sk_buff *skb, struct nfattr *nfa, const struct ip_conntrack *ct){ struct nfattr *nest_parms; read_lock_bh(&tcp_lock); nest_parms = NFA_NEST(skb, CTA_PROTOINFO_TCP); NFA_PUT(skb, CTA_PROTOINFO_TCP_STATE, sizeof(u_int8_t), &ct->proto.tcp.state); read_unlock_bh(&tcp_lock); NFA_NEST_END(skb, nest_parms); return 0;nfattr_failure: read_unlock_bh(&tcp_lock); return -1;}static const size_t cta_min_tcp[CTA_PROTOINFO_TCP_MAX] = { [CTA_PROTOINFO_TCP_STATE-1] = sizeof(u_int8_t),};static int nfattr_to_tcp(struct nfattr *cda[], struct ip_conntrack *ct){ struct nfattr *attr = cda[CTA_PROTOINFO_TCP-1]; struct nfattr *tb[CTA_PROTOINFO_TCP_MAX]; /* updates could not contain anything about the private * protocol info, in that case skip the parsing */ if (!attr) return 0; nfattr_parse_nested(tb, CTA_PROTOINFO_TCP_MAX, attr); if (nfattr_bad_size(tb, CTA_PROTOINFO_TCP_MAX, cta_min_tcp)) return -EINVAL; if (!tb[CTA_PROTOINFO_TCP_STATE-1]) return -EINVAL; write_lock_bh(&tcp_lock); ct->proto.tcp.state = *(u_int8_t *)NFA_DATA(tb[CTA_PROTOINFO_TCP_STATE-1]); write_unlock_bh(&tcp_lock); return 0;}#endifstatic unsigned int get_conntrack_index(const struct tcphdr *tcph){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -