|
@@ -55,8 +55,8 @@
|
|
/* Protects conntrack->proto.tcp */
|
|
/* Protects conntrack->proto.tcp */
|
|
static DEFINE_RWLOCK(tcp_lock);
|
|
static DEFINE_RWLOCK(tcp_lock);
|
|
|
|
|
|
-/* "Be conservative in what you do,
|
|
|
|
- be liberal in what you accept from others."
|
|
|
|
|
|
+/* "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. */
|
|
If it's non-zero, we mark only out of window RST segments as INVALID. */
|
|
int nf_ct_tcp_be_liberal __read_mostly = 0;
|
|
int nf_ct_tcp_be_liberal __read_mostly = 0;
|
|
|
|
|
|
@@ -64,8 +64,8 @@ int nf_ct_tcp_be_liberal __read_mostly = 0;
|
|
connections. */
|
|
connections. */
|
|
int nf_ct_tcp_loose __read_mostly = 1;
|
|
int nf_ct_tcp_loose __read_mostly = 1;
|
|
|
|
|
|
-/* Max number of the retransmitted packets without receiving an (acceptable)
|
|
|
|
- ACK from the destination. If this number is reached, a shorter timer
|
|
|
|
|
|
+/* 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. */
|
|
will be started. */
|
|
int nf_ct_tcp_max_retrans __read_mostly = 3;
|
|
int nf_ct_tcp_max_retrans __read_mostly = 3;
|
|
|
|
|
|
@@ -84,7 +84,7 @@ static const char *tcp_conntrack_names[] = {
|
|
"CLOSE",
|
|
"CLOSE",
|
|
"LISTEN"
|
|
"LISTEN"
|
|
};
|
|
};
|
|
-
|
|
|
|
|
|
+
|
|
#define SECS * HZ
|
|
#define SECS * HZ
|
|
#define MINS * 60 SECS
|
|
#define MINS * 60 SECS
|
|
#define HOURS * 60 MINS
|
|
#define HOURS * 60 MINS
|
|
@@ -100,10 +100,10 @@ static unsigned int nf_ct_tcp_timeout_time_wait __read_mostly = 2 MINS;
|
|
static unsigned int nf_ct_tcp_timeout_close __read_mostly = 10 SECS;
|
|
static unsigned int nf_ct_tcp_timeout_close __read_mostly = 10 SECS;
|
|
|
|
|
|
/* RFC1122 says the R2 limit should be at least 100 seconds.
|
|
/* RFC1122 says the R2 limit should be at least 100 seconds.
|
|
- Linux uses 15 packets as limit, which corresponds
|
|
|
|
|
|
+ Linux uses 15 packets as limit, which corresponds
|
|
to ~13-30min depending on RTO. */
|
|
to ~13-30min depending on RTO. */
|
|
static unsigned int nf_ct_tcp_timeout_max_retrans __read_mostly = 5 MINS;
|
|
static unsigned int nf_ct_tcp_timeout_max_retrans __read_mostly = 5 MINS;
|
|
-
|
|
|
|
|
|
+
|
|
static unsigned int * tcp_timeouts[] = {
|
|
static unsigned int * tcp_timeouts[] = {
|
|
NULL, /* TCP_CONNTRACK_NONE */
|
|
NULL, /* TCP_CONNTRACK_NONE */
|
|
&nf_ct_tcp_timeout_syn_sent, /* TCP_CONNTRACK_SYN_SENT, */
|
|
&nf_ct_tcp_timeout_syn_sent, /* TCP_CONNTRACK_SYN_SENT, */
|
|
@@ -116,7 +116,7 @@ static unsigned int * tcp_timeouts[] = {
|
|
&nf_ct_tcp_timeout_close, /* TCP_CONNTRACK_CLOSE, */
|
|
&nf_ct_tcp_timeout_close, /* TCP_CONNTRACK_CLOSE, */
|
|
NULL, /* TCP_CONNTRACK_LISTEN */
|
|
NULL, /* TCP_CONNTRACK_LISTEN */
|
|
};
|
|
};
|
|
-
|
|
|
|
|
|
+
|
|
#define sNO TCP_CONNTRACK_NONE
|
|
#define sNO TCP_CONNTRACK_NONE
|
|
#define sSS TCP_CONNTRACK_SYN_SENT
|
|
#define sSS TCP_CONNTRACK_SYN_SENT
|
|
#define sSR TCP_CONNTRACK_SYN_RECV
|
|
#define sSR TCP_CONNTRACK_SYN_RECV
|
|
@@ -139,13 +139,13 @@ enum tcp_bit_set {
|
|
TCP_RST_SET,
|
|
TCP_RST_SET,
|
|
TCP_NONE_SET,
|
|
TCP_NONE_SET,
|
|
};
|
|
};
|
|
-
|
|
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* The TCP state transition table needs a few words...
|
|
* The TCP state transition table needs a few words...
|
|
*
|
|
*
|
|
* We are the man in the middle. All the packets go through us
|
|
* We are the man in the middle. All the packets go through us
|
|
* but might get lost in transit to the destination.
|
|
* but might get lost in transit to the destination.
|
|
- * It is assumed that the destinations can't receive segments
|
|
|
|
|
|
+ * It is assumed that the destinations can't receive segments
|
|
* we haven't seen.
|
|
* we haven't seen.
|
|
*
|
|
*
|
|
* The checked segment is in window, but our windows are *not*
|
|
* The checked segment is in window, but our windows are *not*
|
|
@@ -155,11 +155,11 @@ enum tcp_bit_set {
|
|
* The meaning of the states are:
|
|
* The meaning of the states are:
|
|
*
|
|
*
|
|
* NONE: initial state
|
|
* NONE: initial state
|
|
- * SYN_SENT: SYN-only packet seen
|
|
|
|
|
|
+ * SYN_SENT: SYN-only packet seen
|
|
* SYN_RECV: SYN-ACK packet seen
|
|
* SYN_RECV: SYN-ACK packet seen
|
|
* ESTABLISHED: ACK packet seen
|
|
* ESTABLISHED: ACK packet seen
|
|
* FIN_WAIT: FIN packet seen
|
|
* FIN_WAIT: FIN packet seen
|
|
- * CLOSE_WAIT: ACK seen (after FIN)
|
|
|
|
|
|
+ * CLOSE_WAIT: ACK seen (after FIN)
|
|
* LAST_ACK: FIN seen (after FIN)
|
|
* LAST_ACK: FIN seen (after FIN)
|
|
* TIME_WAIT: last ACK seen
|
|
* TIME_WAIT: last ACK seen
|
|
* CLOSE: closed connection
|
|
* CLOSE: closed connection
|
|
@@ -167,8 +167,8 @@ enum tcp_bit_set {
|
|
* LISTEN state is not used.
|
|
* LISTEN state is not used.
|
|
*
|
|
*
|
|
* Packets marked as IGNORED (sIG):
|
|
* Packets marked as IGNORED (sIG):
|
|
- * if they may be either invalid or valid
|
|
|
|
- * and the receiver may send back a connection
|
|
|
|
|
|
+ * if they may be either invalid or valid
|
|
|
|
+ * and the receiver may send back a connection
|
|
* closing RST or a SYN/ACK.
|
|
* closing RST or a SYN/ACK.
|
|
*
|
|
*
|
|
* Packets marked as INVALID (sIV):
|
|
* Packets marked as INVALID (sIV):
|
|
@@ -185,7 +185,7 @@ static enum tcp_conntrack tcp_conntracks[2][6][TCP_CONNTRACK_MAX] = {
|
|
* sSS -> sSS Retransmitted SYN
|
|
* sSS -> sSS Retransmitted SYN
|
|
* sSR -> sIG Late retransmitted SYN?
|
|
* sSR -> sIG Late retransmitted SYN?
|
|
* sES -> sIG Error: SYNs in window outside the SYN_SENT state
|
|
* sES -> sIG Error: SYNs in window outside the SYN_SENT state
|
|
- * are errors. Receiver will reply with RST
|
|
|
|
|
|
+ * are errors. Receiver will reply with RST
|
|
* and close the connection.
|
|
* and close the connection.
|
|
* Or we are not in sync and hold a dead connection.
|
|
* Or we are not in sync and hold a dead connection.
|
|
* sFW -> sIG
|
|
* sFW -> sIG
|
|
@@ -198,10 +198,10 @@ static enum tcp_conntrack tcp_conntracks[2][6][TCP_CONNTRACK_MAX] = {
|
|
/*synack*/ { sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV },
|
|
/*synack*/ { sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV },
|
|
/*
|
|
/*
|
|
* A SYN/ACK from the client is always invalid:
|
|
* A SYN/ACK from the client is always invalid:
|
|
- * - either it tries to set up a simultaneous open, which is
|
|
|
|
|
|
+ * - either it tries to set up a simultaneous open, which is
|
|
* not supported;
|
|
* not supported;
|
|
* - or the firewall has just been inserted between the two hosts
|
|
* - or the firewall has just been inserted between the two hosts
|
|
- * during the session set-up. The SYN will be retransmitted
|
|
|
|
|
|
+ * during the session set-up. The SYN will be retransmitted
|
|
* by the true client (or it'll time out).
|
|
* by the true client (or it'll time out).
|
|
*/
|
|
*/
|
|
/* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */
|
|
/* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */
|
|
@@ -213,7 +213,7 @@ static enum tcp_conntrack tcp_conntracks[2][6][TCP_CONNTRACK_MAX] = {
|
|
* sSR -> sFW Close started.
|
|
* sSR -> sFW Close started.
|
|
* sES -> sFW
|
|
* sES -> sFW
|
|
* sFW -> sLA FIN seen in both directions, waiting for
|
|
* sFW -> sLA FIN seen in both directions, waiting for
|
|
- * the last ACK.
|
|
|
|
|
|
+ * the last ACK.
|
|
* Migth be a retransmitted FIN as well...
|
|
* Migth be a retransmitted FIN as well...
|
|
* sCW -> sLA
|
|
* sCW -> sLA
|
|
* sLA -> sLA Retransmitted FIN. Remain in the same state.
|
|
* sLA -> sLA Retransmitted FIN. Remain in the same state.
|
|
@@ -291,7 +291,7 @@ static enum tcp_conntrack tcp_conntracks[2][6][TCP_CONNTRACK_MAX] = {
|
|
/* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */
|
|
/* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */
|
|
/*rst*/ { sIV, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sIV },
|
|
/*rst*/ { sIV, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sIV },
|
|
/*none*/ { sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV }
|
|
/*none*/ { sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV }
|
|
- }
|
|
|
|
|
|
+ }
|
|
};
|
|
};
|
|
|
|
|
|
static int tcp_pkt_to_tuple(const struct sk_buff *skb,
|
|
static int tcp_pkt_to_tuple(const struct sk_buff *skb,
|
|
@@ -352,21 +352,21 @@ static unsigned int get_conntrack_index(const struct tcphdr *tcph)
|
|
|
|
|
|
/* TCP connection tracking based on 'Real Stateful TCP Packet Filtering
|
|
/* TCP connection tracking based on 'Real Stateful TCP Packet Filtering
|
|
in IP Filter' by Guido van Rooij.
|
|
in IP Filter' by Guido van Rooij.
|
|
-
|
|
|
|
|
|
+
|
|
http://www.nluug.nl/events/sane2000/papers.html
|
|
http://www.nluug.nl/events/sane2000/papers.html
|
|
http://www.iae.nl/users/guido/papers/tcp_filtering.ps.gz
|
|
http://www.iae.nl/users/guido/papers/tcp_filtering.ps.gz
|
|
-
|
|
|
|
|
|
+
|
|
The boundaries and the conditions are changed according to RFC793:
|
|
The boundaries and the conditions are changed according to RFC793:
|
|
the packet must intersect the window (i.e. segments may be
|
|
the packet must intersect the window (i.e. segments may be
|
|
after the right or before the left edge) and thus receivers may ACK
|
|
after the right or before the left edge) and thus receivers may ACK
|
|
segments after the right edge of the window.
|
|
segments after the right edge of the window.
|
|
|
|
|
|
- td_maxend = max(sack + max(win,1)) seen in reply packets
|
|
|
|
|
|
+ td_maxend = max(sack + max(win,1)) seen in reply packets
|
|
td_maxwin = max(max(win, 1)) + (sack - ack) seen in sent packets
|
|
td_maxwin = max(max(win, 1)) + (sack - ack) seen in sent packets
|
|
td_maxwin += seq + len - sender.td_maxend
|
|
td_maxwin += seq + len - sender.td_maxend
|
|
if seq + len > sender.td_maxend
|
|
if seq + len > sender.td_maxend
|
|
td_end = max(seq + len) seen in sent packets
|
|
td_end = max(seq + len) seen in sent packets
|
|
-
|
|
|
|
|
|
+
|
|
I. Upper bound for valid data: seq <= sender.td_maxend
|
|
I. Upper bound for valid data: seq <= sender.td_maxend
|
|
II. Lower bound for valid data: seq + len >= sender.td_end - receiver.td_maxwin
|
|
II. Lower bound for valid data: seq + len >= sender.td_end - receiver.td_maxwin
|
|
III. Upper bound for valid ack: sack <= receiver.td_end
|
|
III. Upper bound for valid ack: sack <= receiver.td_end
|
|
@@ -374,8 +374,8 @@ static unsigned int get_conntrack_index(const struct tcphdr *tcph)
|
|
|
|
|
|
where sack is the highest right edge of sack block found in the packet.
|
|
where sack is the highest right edge of sack block found in the packet.
|
|
|
|
|
|
- The upper bound limit for a valid ack is not ignored -
|
|
|
|
- we doesn't have to deal with fragments.
|
|
|
|
|
|
+ The upper bound limit for a valid ack is not ignored -
|
|
|
|
+ we doesn't have to deal with fragments.
|
|
*/
|
|
*/
|
|
|
|
|
|
static inline __u32 segment_seq_plus_len(__u32 seq,
|
|
static inline __u32 segment_seq_plus_len(__u32 seq,
|
|
@@ -388,19 +388,19 @@ static inline __u32 segment_seq_plus_len(__u32 seq,
|
|
return (seq + len - dataoff - tcph->doff*4
|
|
return (seq + len - dataoff - tcph->doff*4
|
|
+ (tcph->syn ? 1 : 0) + (tcph->fin ? 1 : 0));
|
|
+ (tcph->syn ? 1 : 0) + (tcph->fin ? 1 : 0));
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
/* Fixme: what about big packets? */
|
|
/* Fixme: what about big packets? */
|
|
#define MAXACKWINCONST 66000
|
|
#define MAXACKWINCONST 66000
|
|
#define MAXACKWINDOW(sender) \
|
|
#define MAXACKWINDOW(sender) \
|
|
((sender)->td_maxwin > MAXACKWINCONST ? (sender)->td_maxwin \
|
|
((sender)->td_maxwin > MAXACKWINCONST ? (sender)->td_maxwin \
|
|
: MAXACKWINCONST)
|
|
: MAXACKWINCONST)
|
|
-
|
|
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* Simplified tcp_parse_options routine from tcp_input.c
|
|
* Simplified tcp_parse_options routine from tcp_input.c
|
|
*/
|
|
*/
|
|
static void tcp_options(const struct sk_buff *skb,
|
|
static void tcp_options(const struct sk_buff *skb,
|
|
unsigned int dataoff,
|
|
unsigned int dataoff,
|
|
- struct tcphdr *tcph,
|
|
|
|
|
|
+ struct tcphdr *tcph,
|
|
struct ip_ct_tcp_state *state)
|
|
struct ip_ct_tcp_state *state)
|
|
{
|
|
{
|
|
unsigned char buff[(15 * 4) - sizeof(struct tcphdr)];
|
|
unsigned char buff[(15 * 4) - sizeof(struct tcphdr)];
|
|
@@ -414,7 +414,7 @@ static void tcp_options(const struct sk_buff *skb,
|
|
length, buff);
|
|
length, buff);
|
|
BUG_ON(ptr == NULL);
|
|
BUG_ON(ptr == NULL);
|
|
|
|
|
|
- state->td_scale =
|
|
|
|
|
|
+ state->td_scale =
|
|
state->flags = 0;
|
|
state->flags = 0;
|
|
|
|
|
|
while (length > 0) {
|
|
while (length > 0) {
|
|
@@ -434,7 +434,7 @@ static void tcp_options(const struct sk_buff *skb,
|
|
if (opsize > length)
|
|
if (opsize > length)
|
|
break; /* don't parse partial options */
|
|
break; /* don't parse partial options */
|
|
|
|
|
|
- if (opcode == TCPOPT_SACK_PERM
|
|
|
|
|
|
+ if (opcode == TCPOPT_SACK_PERM
|
|
&& opsize == TCPOLEN_SACK_PERM)
|
|
&& opsize == TCPOLEN_SACK_PERM)
|
|
state->flags |= IP_CT_TCP_FLAG_SACK_PERM;
|
|
state->flags |= IP_CT_TCP_FLAG_SACK_PERM;
|
|
else if (opcode == TCPOPT_WINDOW
|
|
else if (opcode == TCPOPT_WINDOW
|
|
@@ -457,7 +457,7 @@ static void tcp_options(const struct sk_buff *skb,
|
|
static void tcp_sack(const struct sk_buff *skb, unsigned int dataoff,
|
|
static void tcp_sack(const struct sk_buff *skb, unsigned int dataoff,
|
|
struct tcphdr *tcph, __u32 *sack)
|
|
struct tcphdr *tcph, __u32 *sack)
|
|
{
|
|
{
|
|
- unsigned char buff[(15 * 4) - sizeof(struct tcphdr)];
|
|
|
|
|
|
+ unsigned char buff[(15 * 4) - sizeof(struct tcphdr)];
|
|
unsigned char *ptr;
|
|
unsigned char *ptr;
|
|
int length = (tcph->doff*4) - sizeof(struct tcphdr);
|
|
int length = (tcph->doff*4) - sizeof(struct tcphdr);
|
|
__u32 tmp;
|
|
__u32 tmp;
|
|
@@ -472,10 +472,10 @@ static void tcp_sack(const struct sk_buff *skb, unsigned int dataoff,
|
|
/* Fast path for timestamp-only option */
|
|
/* Fast path for timestamp-only option */
|
|
if (length == TCPOLEN_TSTAMP_ALIGNED*4
|
|
if (length == TCPOLEN_TSTAMP_ALIGNED*4
|
|
&& *(__be32 *)ptr ==
|
|
&& *(__be32 *)ptr ==
|
|
- __constant_htonl((TCPOPT_NOP << 24)
|
|
|
|
- | (TCPOPT_NOP << 16)
|
|
|
|
- | (TCPOPT_TIMESTAMP << 8)
|
|
|
|
- | TCPOLEN_TIMESTAMP))
|
|
|
|
|
|
+ __constant_htonl((TCPOPT_NOP << 24)
|
|
|
|
+ | (TCPOPT_NOP << 16)
|
|
|
|
+ | (TCPOPT_TIMESTAMP << 8)
|
|
|
|
+ | TCPOLEN_TIMESTAMP))
|
|
return;
|
|
return;
|
|
|
|
|
|
while (length > 0) {
|
|
while (length > 0) {
|
|
@@ -495,15 +495,15 @@ static void tcp_sack(const struct sk_buff *skb, unsigned int dataoff,
|
|
if (opsize > length)
|
|
if (opsize > length)
|
|
break; /* don't parse partial options */
|
|
break; /* don't parse partial options */
|
|
|
|
|
|
- if (opcode == TCPOPT_SACK
|
|
|
|
- && opsize >= (TCPOLEN_SACK_BASE
|
|
|
|
- + TCPOLEN_SACK_PERBLOCK)
|
|
|
|
- && !((opsize - TCPOLEN_SACK_BASE)
|
|
|
|
- % TCPOLEN_SACK_PERBLOCK)) {
|
|
|
|
- for (i = 0;
|
|
|
|
- i < (opsize - TCPOLEN_SACK_BASE);
|
|
|
|
- i += TCPOLEN_SACK_PERBLOCK) {
|
|
|
|
- tmp = ntohl(*((__be32 *)(ptr+i)+1));
|
|
|
|
|
|
+ if (opcode == TCPOPT_SACK
|
|
|
|
+ && opsize >= (TCPOLEN_SACK_BASE
|
|
|
|
+ + TCPOLEN_SACK_PERBLOCK)
|
|
|
|
+ && !((opsize - TCPOLEN_SACK_BASE)
|
|
|
|
+ % TCPOLEN_SACK_PERBLOCK)) {
|
|
|
|
+ for (i = 0;
|
|
|
|
+ i < (opsize - TCPOLEN_SACK_BASE);
|
|
|
|
+ i += TCPOLEN_SACK_PERBLOCK) {
|
|
|
|
+ tmp = ntohl(*((__be32 *)(ptr+i)+1));
|
|
|
|
|
|
if (after(tmp, *sack))
|
|
if (after(tmp, *sack))
|
|
*sack = tmp;
|
|
*sack = tmp;
|
|
@@ -516,12 +516,12 @@ static void tcp_sack(const struct sk_buff *skb, unsigned int dataoff,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-static int tcp_in_window(struct ip_ct_tcp *state,
|
|
|
|
- enum ip_conntrack_dir dir,
|
|
|
|
- unsigned int index,
|
|
|
|
- const struct sk_buff *skb,
|
|
|
|
|
|
+static int tcp_in_window(struct ip_ct_tcp *state,
|
|
|
|
+ enum ip_conntrack_dir dir,
|
|
|
|
+ unsigned int index,
|
|
|
|
+ const struct sk_buff *skb,
|
|
unsigned int dataoff,
|
|
unsigned int dataoff,
|
|
- struct tcphdr *tcph,
|
|
|
|
|
|
+ struct tcphdr *tcph,
|
|
int pf)
|
|
int pf)
|
|
{
|
|
{
|
|
struct ip_ct_tcp_state *sender = &state->seen[dir];
|
|
struct ip_ct_tcp_state *sender = &state->seen[dir];
|
|
@@ -543,14 +543,14 @@ static int tcp_in_window(struct ip_ct_tcp *state,
|
|
DEBUGP("tcp_in_window: START\n");
|
|
DEBUGP("tcp_in_window: START\n");
|
|
DEBUGP("tcp_in_window: src=%u.%u.%u.%u:%hu dst=%u.%u.%u.%u:%hu "
|
|
DEBUGP("tcp_in_window: src=%u.%u.%u.%u:%hu dst=%u.%u.%u.%u:%hu "
|
|
"seq=%u ack=%u sack=%u win=%u end=%u\n",
|
|
"seq=%u ack=%u sack=%u win=%u end=%u\n",
|
|
- NIPQUAD(iph->saddr), ntohs(tcph->source),
|
|
|
|
|
|
+ NIPQUAD(iph->saddr), ntohs(tcph->source),
|
|
NIPQUAD(iph->daddr), ntohs(tcph->dest),
|
|
NIPQUAD(iph->daddr), ntohs(tcph->dest),
|
|
seq, ack, sack, win, end);
|
|
seq, ack, sack, win, end);
|
|
DEBUGP("tcp_in_window: sender end=%u maxend=%u maxwin=%u scale=%i "
|
|
DEBUGP("tcp_in_window: sender end=%u maxend=%u maxwin=%u scale=%i "
|
|
"receiver end=%u maxend=%u maxwin=%u scale=%i\n",
|
|
"receiver end=%u maxend=%u maxwin=%u scale=%i\n",
|
|
sender->td_end, sender->td_maxend, sender->td_maxwin,
|
|
sender->td_end, sender->td_maxend, sender->td_maxwin,
|
|
- sender->td_scale,
|
|
|
|
- receiver->td_end, receiver->td_maxend, receiver->td_maxwin,
|
|
|
|
|
|
+ sender->td_scale,
|
|
|
|
+ receiver->td_end, receiver->td_maxend, receiver->td_maxwin,
|
|
receiver->td_scale);
|
|
receiver->td_scale);
|
|
|
|
|
|
if (sender->td_end == 0) {
|
|
if (sender->td_end == 0) {
|
|
@@ -561,26 +561,26 @@ static int tcp_in_window(struct ip_ct_tcp *state,
|
|
/*
|
|
/*
|
|
* Outgoing SYN-ACK in reply to a SYN.
|
|
* Outgoing SYN-ACK in reply to a SYN.
|
|
*/
|
|
*/
|
|
- sender->td_end =
|
|
|
|
|
|
+ sender->td_end =
|
|
sender->td_maxend = end;
|
|
sender->td_maxend = end;
|
|
sender->td_maxwin = (win == 0 ? 1 : win);
|
|
sender->td_maxwin = (win == 0 ? 1 : win);
|
|
|
|
|
|
tcp_options(skb, dataoff, tcph, sender);
|
|
tcp_options(skb, dataoff, tcph, sender);
|
|
- /*
|
|
|
|
|
|
+ /*
|
|
* RFC 1323:
|
|
* RFC 1323:
|
|
* Both sides must send the Window Scale option
|
|
* Both sides must send the Window Scale option
|
|
* to enable window scaling in either direction.
|
|
* to enable window scaling in either direction.
|
|
*/
|
|
*/
|
|
if (!(sender->flags & IP_CT_TCP_FLAG_WINDOW_SCALE
|
|
if (!(sender->flags & IP_CT_TCP_FLAG_WINDOW_SCALE
|
|
&& receiver->flags & IP_CT_TCP_FLAG_WINDOW_SCALE))
|
|
&& receiver->flags & IP_CT_TCP_FLAG_WINDOW_SCALE))
|
|
- sender->td_scale =
|
|
|
|
|
|
+ sender->td_scale =
|
|
receiver->td_scale = 0;
|
|
receiver->td_scale = 0;
|
|
} else {
|
|
} else {
|
|
/*
|
|
/*
|
|
* We are in the middle of a connection,
|
|
* We are in the middle of a connection,
|
|
* its history is lost for us.
|
|
* its history is lost for us.
|
|
* Let's try to use the data from the packet.
|
|
* Let's try to use the data from the packet.
|
|
- */
|
|
|
|
|
|
+ */
|
|
sender->td_end = end;
|
|
sender->td_end = end;
|
|
sender->td_maxwin = (win == 0 ? 1 : win);
|
|
sender->td_maxwin = (win == 0 ? 1 : win);
|
|
sender->td_maxend = end + sender->td_maxwin;
|
|
sender->td_maxend = end + sender->td_maxwin;
|
|
@@ -592,7 +592,7 @@ static int tcp_in_window(struct ip_ct_tcp *state,
|
|
&& after(end, sender->td_end)) {
|
|
&& after(end, sender->td_end)) {
|
|
/*
|
|
/*
|
|
* RFC 793: "if a TCP is reinitialized ... then it need
|
|
* RFC 793: "if a TCP is reinitialized ... then it need
|
|
- * not wait at all; it must only be sure to use sequence
|
|
|
|
|
|
+ * not wait at all; it must only be sure to use sequence
|
|
* numbers larger than those recently used."
|
|
* numbers larger than those recently used."
|
|
*/
|
|
*/
|
|
sender->td_end =
|
|
sender->td_end =
|
|
@@ -607,8 +607,8 @@ static int tcp_in_window(struct ip_ct_tcp *state,
|
|
* If there is no ACK, just pretend it was set and OK.
|
|
* If there is no ACK, just pretend it was set and OK.
|
|
*/
|
|
*/
|
|
ack = sack = receiver->td_end;
|
|
ack = sack = receiver->td_end;
|
|
- } else if (((tcp_flag_word(tcph) & (TCP_FLAG_ACK|TCP_FLAG_RST)) ==
|
|
|
|
- (TCP_FLAG_ACK|TCP_FLAG_RST))
|
|
|
|
|
|
+ } else if (((tcp_flag_word(tcph) & (TCP_FLAG_ACK|TCP_FLAG_RST)) ==
|
|
|
|
+ (TCP_FLAG_ACK|TCP_FLAG_RST))
|
|
&& (ack == 0)) {
|
|
&& (ack == 0)) {
|
|
/*
|
|
/*
|
|
* Broken TCP stacks, that set ACK in RST packets as well
|
|
* Broken TCP stacks, that set ACK in RST packets as well
|
|
@@ -637,21 +637,21 @@ static int tcp_in_window(struct ip_ct_tcp *state,
|
|
DEBUGP("tcp_in_window: sender end=%u maxend=%u maxwin=%u scale=%i "
|
|
DEBUGP("tcp_in_window: sender end=%u maxend=%u maxwin=%u scale=%i "
|
|
"receiver end=%u maxend=%u maxwin=%u scale=%i\n",
|
|
"receiver end=%u maxend=%u maxwin=%u scale=%i\n",
|
|
sender->td_end, sender->td_maxend, sender->td_maxwin,
|
|
sender->td_end, sender->td_maxend, sender->td_maxwin,
|
|
- sender->td_scale,
|
|
|
|
|
|
+ sender->td_scale,
|
|
receiver->td_end, receiver->td_maxend, receiver->td_maxwin,
|
|
receiver->td_end, receiver->td_maxend, receiver->td_maxwin,
|
|
receiver->td_scale);
|
|
receiver->td_scale);
|
|
|
|
|
|
DEBUGP("tcp_in_window: I=%i II=%i III=%i IV=%i\n",
|
|
DEBUGP("tcp_in_window: I=%i II=%i III=%i IV=%i\n",
|
|
before(seq, sender->td_maxend + 1),
|
|
before(seq, sender->td_maxend + 1),
|
|
after(end, sender->td_end - receiver->td_maxwin - 1),
|
|
after(end, sender->td_end - receiver->td_maxwin - 1),
|
|
- before(sack, receiver->td_end + 1),
|
|
|
|
- after(ack, receiver->td_end - MAXACKWINDOW(sender)));
|
|
|
|
|
|
+ before(sack, receiver->td_end + 1),
|
|
|
|
+ after(ack, receiver->td_end - MAXACKWINDOW(sender)));
|
|
|
|
|
|
if (before(seq, sender->td_maxend + 1) &&
|
|
if (before(seq, sender->td_maxend + 1) &&
|
|
after(end, sender->td_end - receiver->td_maxwin - 1) &&
|
|
after(end, sender->td_end - receiver->td_maxwin - 1) &&
|
|
before(sack, receiver->td_end + 1) &&
|
|
before(sack, receiver->td_end + 1) &&
|
|
after(ack, receiver->td_end - MAXACKWINDOW(sender))) {
|
|
after(ack, receiver->td_end - MAXACKWINDOW(sender))) {
|
|
- /*
|
|
|
|
|
|
+ /*
|
|
* Take into account window scaling (RFC 1323).
|
|
* Take into account window scaling (RFC 1323).
|
|
*/
|
|
*/
|
|
if (!tcph->syn)
|
|
if (!tcph->syn)
|
|
@@ -676,7 +676,7 @@ static int tcp_in_window(struct ip_ct_tcp *state,
|
|
receiver->td_maxend++;
|
|
receiver->td_maxend++;
|
|
}
|
|
}
|
|
|
|
|
|
- /*
|
|
|
|
|
|
+ /*
|
|
* Check retransmissions.
|
|
* Check retransmissions.
|
|
*/
|
|
*/
|
|
if (index == TCP_ACK_SET) {
|
|
if (index == TCP_ACK_SET) {
|
|
@@ -712,11 +712,11 @@ static int tcp_in_window(struct ip_ct_tcp *state,
|
|
: "ACK is over the upper bound (ACKed data not seen yet)"
|
|
: "ACK is over the upper bound (ACKed data not seen yet)"
|
|
: "SEQ is under the lower bound (already ACKed data retransmitted)"
|
|
: "SEQ is under the lower bound (already ACKed data retransmitted)"
|
|
: "SEQ is over the upper bound (over the window of the receiver)");
|
|
: "SEQ is over the upper bound (over the window of the receiver)");
|
|
- }
|
|
|
|
-
|
|
|
|
|
|
+ }
|
|
|
|
+
|
|
DEBUGP("tcp_in_window: res=%i sender end=%u maxend=%u maxwin=%u "
|
|
DEBUGP("tcp_in_window: res=%i sender end=%u maxend=%u maxwin=%u "
|
|
"receiver end=%u maxend=%u maxwin=%u\n",
|
|
"receiver end=%u maxend=%u maxwin=%u\n",
|
|
- res, sender->td_end, sender->td_maxend, sender->td_maxwin,
|
|
|
|
|
|
+ res, sender->td_end, sender->td_maxend, sender->td_maxwin,
|
|
receiver->td_end, receiver->td_maxend, receiver->td_maxwin);
|
|
receiver->td_end, receiver->td_maxend, receiver->td_maxwin);
|
|
|
|
|
|
return res;
|
|
return res;
|
|
@@ -727,7 +727,7 @@ static int tcp_in_window(struct ip_ct_tcp *state,
|
|
/* Caller must linearize skb at tcp header. */
|
|
/* Caller must linearize skb at tcp header. */
|
|
void nf_conntrack_tcp_update(struct sk_buff *skb,
|
|
void nf_conntrack_tcp_update(struct sk_buff *skb,
|
|
unsigned int dataoff,
|
|
unsigned int dataoff,
|
|
- struct nf_conn *conntrack,
|
|
|
|
|
|
+ struct nf_conn *conntrack,
|
|
int dir)
|
|
int dir)
|
|
{
|
|
{
|
|
struct tcphdr *tcph = (void *)skb->data + dataoff;
|
|
struct tcphdr *tcph = (void *)skb->data + dataoff;
|
|
@@ -750,7 +750,7 @@ void nf_conntrack_tcp_update(struct sk_buff *skb,
|
|
DEBUGP("tcp_update: sender end=%u maxend=%u maxwin=%u scale=%i "
|
|
DEBUGP("tcp_update: sender end=%u maxend=%u maxwin=%u scale=%i "
|
|
"receiver end=%u maxend=%u maxwin=%u scale=%i\n",
|
|
"receiver end=%u maxend=%u maxwin=%u scale=%i\n",
|
|
sender->td_end, sender->td_maxend, sender->td_maxwin,
|
|
sender->td_end, sender->td_maxend, sender->td_maxwin,
|
|
- sender->td_scale,
|
|
|
|
|
|
+ sender->td_scale,
|
|
receiver->td_end, receiver->td_maxend, receiver->td_maxwin,
|
|
receiver->td_end, receiver->td_maxend, receiver->td_maxwin,
|
|
receiver->td_scale);
|
|
receiver->td_scale);
|
|
}
|
|
}
|
|
@@ -804,8 +804,8 @@ static int tcp_error(struct sk_buff *skb,
|
|
nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
|
|
nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
|
|
"nf_ct_tcp: short packet ");
|
|
"nf_ct_tcp: short packet ");
|
|
return -NF_ACCEPT;
|
|
return -NF_ACCEPT;
|
|
- }
|
|
|
|
-
|
|
|
|
|
|
+ }
|
|
|
|
+
|
|
/* Not whole TCP header or malformed packet */
|
|
/* Not whole TCP header or malformed packet */
|
|
if (th->doff*4 < sizeof(struct tcphdr) || tcplen < th->doff*4) {
|
|
if (th->doff*4 < sizeof(struct tcphdr) || tcplen < th->doff*4) {
|
|
if (LOG_INVALID(IPPROTO_TCP))
|
|
if (LOG_INVALID(IPPROTO_TCP))
|
|
@@ -813,7 +813,7 @@ static int tcp_error(struct sk_buff *skb,
|
|
"nf_ct_tcp: truncated/malformed packet ");
|
|
"nf_ct_tcp: truncated/malformed packet ");
|
|
return -NF_ACCEPT;
|
|
return -NF_ACCEPT;
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
/* Checksum invalid? Ignore.
|
|
/* Checksum invalid? Ignore.
|
|
* We skip checking packets on the outgoing path
|
|
* We skip checking packets on the outgoing path
|
|
* because the checksum is assumed to be correct.
|
|
* because the checksum is assumed to be correct.
|
|
@@ -870,28 +870,28 @@ static int tcp_packet(struct nf_conn *conntrack,
|
|
*
|
|
*
|
|
* a) SYN in ORIGINAL
|
|
* a) SYN in ORIGINAL
|
|
* b) SYN/ACK in REPLY
|
|
* b) SYN/ACK in REPLY
|
|
- * c) ACK in reply direction after initial SYN in original.
|
|
|
|
|
|
+ * c) ACK in reply direction after initial SYN in original.
|
|
*/
|
|
*/
|
|
if (index == TCP_SYNACK_SET
|
|
if (index == TCP_SYNACK_SET
|
|
&& conntrack->proto.tcp.last_index == TCP_SYN_SET
|
|
&& conntrack->proto.tcp.last_index == TCP_SYN_SET
|
|
&& conntrack->proto.tcp.last_dir != dir
|
|
&& conntrack->proto.tcp.last_dir != dir
|
|
&& ntohl(th->ack_seq) ==
|
|
&& ntohl(th->ack_seq) ==
|
|
- conntrack->proto.tcp.last_end) {
|
|
|
|
- /* This SYN/ACK acknowledges a SYN that we earlier
|
|
|
|
|
|
+ conntrack->proto.tcp.last_end) {
|
|
|
|
+ /* This SYN/ACK acknowledges a SYN that we earlier
|
|
* ignored as invalid. This means that the client and
|
|
* ignored as invalid. This means that the client and
|
|
* the server are both in sync, while the firewall is
|
|
* the server are both in sync, while the firewall is
|
|
* not. We kill this session and block the SYN/ACK so
|
|
* not. We kill this session and block the SYN/ACK so
|
|
- * that the client cannot but retransmit its SYN and
|
|
|
|
|
|
+ * that the client cannot but retransmit its SYN and
|
|
* thus initiate a clean new session.
|
|
* thus initiate a clean new session.
|
|
*/
|
|
*/
|
|
- write_unlock_bh(&tcp_lock);
|
|
|
|
|
|
+ write_unlock_bh(&tcp_lock);
|
|
if (LOG_INVALID(IPPROTO_TCP))
|
|
if (LOG_INVALID(IPPROTO_TCP))
|
|
nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
|
|
nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
|
|
"nf_ct_tcp: killing out of sync session ");
|
|
"nf_ct_tcp: killing out of sync session ");
|
|
- if (del_timer(&conntrack->timeout))
|
|
|
|
- conntrack->timeout.function((unsigned long)
|
|
|
|
- conntrack);
|
|
|
|
- return -NF_DROP;
|
|
|
|
|
|
+ if (del_timer(&conntrack->timeout))
|
|
|
|
+ conntrack->timeout.function((unsigned long)
|
|
|
|
+ conntrack);
|
|
|
|
+ return -NF_DROP;
|
|
}
|
|
}
|
|
conntrack->proto.tcp.last_index = index;
|
|
conntrack->proto.tcp.last_index = index;
|
|
conntrack->proto.tcp.last_dir = dir;
|
|
conntrack->proto.tcp.last_dir = dir;
|
|
@@ -921,13 +921,13 @@ static int tcp_packet(struct nf_conn *conntrack,
|
|
IP_CT_TCP_FLAG_CLOSE_INIT)
|
|
IP_CT_TCP_FLAG_CLOSE_INIT)
|
|
|| after(ntohl(th->seq),
|
|
|| after(ntohl(th->seq),
|
|
conntrack->proto.tcp.seen[dir].td_end)) {
|
|
conntrack->proto.tcp.seen[dir].td_end)) {
|
|
- /* Attempt to reopen a closed connection.
|
|
|
|
- * Delete this connection and look up again. */
|
|
|
|
- write_unlock_bh(&tcp_lock);
|
|
|
|
- if (del_timer(&conntrack->timeout))
|
|
|
|
- conntrack->timeout.function((unsigned long)
|
|
|
|
- conntrack);
|
|
|
|
- return -NF_REPEAT;
|
|
|
|
|
|
+ /* Attempt to reopen a closed connection.
|
|
|
|
+ * Delete this connection and look up again. */
|
|
|
|
+ write_unlock_bh(&tcp_lock);
|
|
|
|
+ if (del_timer(&conntrack->timeout))
|
|
|
|
+ conntrack->timeout.function((unsigned long)
|
|
|
|
+ conntrack);
|
|
|
|
+ return -NF_REPEAT;
|
|
} else {
|
|
} else {
|
|
write_unlock_bh(&tcp_lock);
|
|
write_unlock_bh(&tcp_lock);
|
|
if (LOG_INVALID(IPPROTO_TCP))
|
|
if (LOG_INVALID(IPPROTO_TCP))
|
|
@@ -938,9 +938,9 @@ static int tcp_packet(struct nf_conn *conntrack,
|
|
case TCP_CONNTRACK_CLOSE:
|
|
case TCP_CONNTRACK_CLOSE:
|
|
if (index == TCP_RST_SET
|
|
if (index == TCP_RST_SET
|
|
&& ((test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)
|
|
&& ((test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)
|
|
- && conntrack->proto.tcp.last_index == TCP_SYN_SET)
|
|
|
|
- || (!test_bit(IPS_ASSURED_BIT, &conntrack->status)
|
|
|
|
- && conntrack->proto.tcp.last_index == TCP_ACK_SET))
|
|
|
|
|
|
+ && conntrack->proto.tcp.last_index == TCP_SYN_SET)
|
|
|
|
+ || (!test_bit(IPS_ASSURED_BIT, &conntrack->status)
|
|
|
|
+ && conntrack->proto.tcp.last_index == TCP_ACK_SET))
|
|
&& ntohl(th->ack_seq) == conntrack->proto.tcp.last_end) {
|
|
&& ntohl(th->ack_seq) == conntrack->proto.tcp.last_end) {
|
|
/* RST sent to invalid SYN or ACK we had let through
|
|
/* RST sent to invalid SYN or ACK we had let through
|
|
* at a) and c) above:
|
|
* at a) and c) above:
|
|
@@ -1005,8 +1005,8 @@ static int tcp_packet(struct nf_conn *conntrack,
|
|
&& (old_state == TCP_CONNTRACK_SYN_RECV
|
|
&& (old_state == TCP_CONNTRACK_SYN_RECV
|
|
|| old_state == TCP_CONNTRACK_ESTABLISHED)
|
|
|| old_state == TCP_CONNTRACK_ESTABLISHED)
|
|
&& new_state == TCP_CONNTRACK_ESTABLISHED) {
|
|
&& new_state == TCP_CONNTRACK_ESTABLISHED) {
|
|
- /* Set ASSURED if we see see valid ack in ESTABLISHED
|
|
|
|
- after SYN_RECV or a valid answer for a picked up
|
|
|
|
|
|
+ /* Set ASSURED if we see see valid ack in ESTABLISHED
|
|
|
|
+ after SYN_RECV or a valid answer for a picked up
|
|
connection. */
|
|
connection. */
|
|
set_bit(IPS_ASSURED_BIT, &conntrack->status);
|
|
set_bit(IPS_ASSURED_BIT, &conntrack->status);
|
|
nf_conntrack_event_cache(IPCT_STATUS, skb);
|
|
nf_conntrack_event_cache(IPCT_STATUS, skb);
|
|
@@ -1015,7 +1015,7 @@ static int tcp_packet(struct nf_conn *conntrack,
|
|
|
|
|
|
return NF_ACCEPT;
|
|
return NF_ACCEPT;
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
/* Called when a new connection for this protocol found. */
|
|
/* Called when a new connection for this protocol found. */
|
|
static int tcp_new(struct nf_conn *conntrack,
|
|
static int tcp_new(struct nf_conn *conntrack,
|
|
const struct sk_buff *skb,
|
|
const struct sk_buff *skb,
|
|
@@ -1071,7 +1071,7 @@ static int tcp_new(struct nf_conn *conntrack,
|
|
if (conntrack->proto.tcp.seen[0].td_maxwin == 0)
|
|
if (conntrack->proto.tcp.seen[0].td_maxwin == 0)
|
|
conntrack->proto.tcp.seen[0].td_maxwin = 1;
|
|
conntrack->proto.tcp.seen[0].td_maxwin = 1;
|
|
conntrack->proto.tcp.seen[0].td_maxend =
|
|
conntrack->proto.tcp.seen[0].td_maxend =
|
|
- conntrack->proto.tcp.seen[0].td_end +
|
|
|
|
|
|
+ conntrack->proto.tcp.seen[0].td_end +
|
|
conntrack->proto.tcp.seen[0].td_maxwin;
|
|
conntrack->proto.tcp.seen[0].td_maxwin;
|
|
conntrack->proto.tcp.seen[0].td_scale = 0;
|
|
conntrack->proto.tcp.seen[0].td_scale = 0;
|
|
|
|
|
|
@@ -1081,20 +1081,20 @@ static int tcp_new(struct nf_conn *conntrack,
|
|
conntrack->proto.tcp.seen[1].flags = IP_CT_TCP_FLAG_SACK_PERM |
|
|
conntrack->proto.tcp.seen[1].flags = IP_CT_TCP_FLAG_SACK_PERM |
|
|
IP_CT_TCP_FLAG_BE_LIBERAL;
|
|
IP_CT_TCP_FLAG_BE_LIBERAL;
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
conntrack->proto.tcp.seen[1].td_end = 0;
|
|
conntrack->proto.tcp.seen[1].td_end = 0;
|
|
conntrack->proto.tcp.seen[1].td_maxend = 0;
|
|
conntrack->proto.tcp.seen[1].td_maxend = 0;
|
|
conntrack->proto.tcp.seen[1].td_maxwin = 1;
|
|
conntrack->proto.tcp.seen[1].td_maxwin = 1;
|
|
- conntrack->proto.tcp.seen[1].td_scale = 0;
|
|
|
|
|
|
+ conntrack->proto.tcp.seen[1].td_scale = 0;
|
|
|
|
|
|
/* tcp_packet will set them */
|
|
/* tcp_packet will set them */
|
|
conntrack->proto.tcp.state = TCP_CONNTRACK_NONE;
|
|
conntrack->proto.tcp.state = TCP_CONNTRACK_NONE;
|
|
conntrack->proto.tcp.last_index = TCP_NONE_SET;
|
|
conntrack->proto.tcp.last_index = TCP_NONE_SET;
|
|
-
|
|
|
|
|
|
+
|
|
DEBUGP("tcp_new: sender end=%u maxend=%u maxwin=%u scale=%i "
|
|
DEBUGP("tcp_new: sender end=%u maxend=%u maxwin=%u scale=%i "
|
|
"receiver end=%u maxend=%u maxwin=%u scale=%i\n",
|
|
"receiver end=%u maxend=%u maxwin=%u scale=%i\n",
|
|
sender->td_end, sender->td_maxend, sender->td_maxwin,
|
|
sender->td_end, sender->td_maxend, sender->td_maxwin,
|
|
- sender->td_scale,
|
|
|
|
|
|
+ sender->td_scale,
|
|
receiver->td_end, receiver->td_maxend, receiver->td_maxwin,
|
|
receiver->td_end, receiver->td_maxend, receiver->td_maxwin,
|
|
receiver->td_scale);
|
|
receiver->td_scale);
|
|
return 1;
|
|
return 1;
|
|
@@ -1110,7 +1110,7 @@ static int tcp_to_nfattr(struct sk_buff *skb, struct nfattr *nfa,
|
|
const struct nf_conn *ct)
|
|
const struct nf_conn *ct)
|
|
{
|
|
{
|
|
struct nfattr *nest_parms;
|
|
struct nfattr *nest_parms;
|
|
-
|
|
|
|
|
|
+
|
|
read_lock_bh(&tcp_lock);
|
|
read_lock_bh(&tcp_lock);
|
|
nest_parms = NFA_NEST(skb, CTA_PROTOINFO_TCP);
|
|
nest_parms = NFA_NEST(skb, CTA_PROTOINFO_TCP);
|
|
NFA_PUT(skb, CTA_PROTOINFO_TCP_STATE, sizeof(u_int8_t),
|
|
NFA_PUT(skb, CTA_PROTOINFO_TCP_STATE, sizeof(u_int8_t),
|
|
@@ -1140,7 +1140,7 @@ static int nfattr_to_tcp(struct nfattr *cda[], struct nf_conn *ct)
|
|
if (!attr)
|
|
if (!attr)
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
- nfattr_parse_nested(tb, CTA_PROTOINFO_TCP_MAX, attr);
|
|
|
|
|
|
+ nfattr_parse_nested(tb, CTA_PROTOINFO_TCP_MAX, attr);
|
|
|
|
|
|
if (nfattr_bad_size(tb, CTA_PROTOINFO_TCP_MAX, cta_min_tcp))
|
|
if (nfattr_bad_size(tb, CTA_PROTOINFO_TCP_MAX, cta_min_tcp))
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
@@ -1149,7 +1149,7 @@ static int nfattr_to_tcp(struct nfattr *cda[], struct nf_conn *ct)
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
|
|
|
|
write_lock_bh(&tcp_lock);
|
|
write_lock_bh(&tcp_lock);
|
|
- ct->proto.tcp.state =
|
|
|
|
|
|
+ ct->proto.tcp.state =
|
|
*(u_int8_t *)NFA_DATA(tb[CTA_PROTOINFO_TCP_STATE-1]);
|
|
*(u_int8_t *)NFA_DATA(tb[CTA_PROTOINFO_TCP_STATE-1]);
|
|
write_unlock_bh(&tcp_lock);
|
|
write_unlock_bh(&tcp_lock);
|
|
|
|
|