- Add npf_tcpfl2case() and make TCP state table more compact.
- Adjust the state for FIN case on sim-SYN and SYN-RECEIVED.
This commit is contained in:
parent
a2b939da56
commit
f2701a6f1c
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: npf_state_tcp.c,v 1.1 2011/11/29 20:05:30 rmind Exp $ */
|
||||
/* $NetBSD: npf_state_tcp.c,v 1.2 2011/12/05 00:34:25 rmind Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2010-2011 The NetBSD Foundation, Inc.
|
||||
@ -34,7 +34,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: npf_state_tcp.c,v 1.1 2011/11/29 20:05:30 rmind Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: npf_state_tcp.c,v 1.2 2011/12/05 00:34:25 rmind Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
@ -79,7 +79,7 @@ void npf_state_sample(npf_state_t *);
|
||||
/*
|
||||
* TCP connection timeout table (in seconds).
|
||||
*/
|
||||
static const u_int npf_tcp_timeouts[] __read_mostly = {
|
||||
static u_int npf_tcp_timeouts[] __read_mostly = {
|
||||
/* Closed, timeout nearly immediately. */
|
||||
[NPF_TCPS_CLOSED] = 10,
|
||||
/* Unsynchronised states. */
|
||||
@ -99,71 +99,92 @@ static const u_int npf_tcp_timeouts[] __read_mostly = {
|
||||
|
||||
#define NPF_TCP_MAXACKWIN 66000
|
||||
|
||||
#define TH_STATE_MASK (TH_SYN | TH_ACK | TH_FIN)
|
||||
#define TH_SYNACK (TH_SYN | TH_ACK)
|
||||
#define TH_FINACK (TH_FIN | TH_ACK)
|
||||
/*
|
||||
* List of TCP flag cases and conversion of flags to a case (index).
|
||||
*/
|
||||
|
||||
#define TCPFC_INVALID 0
|
||||
#define TCPFC_SYN 1
|
||||
#define TCPFC_SYNACK 2
|
||||
#define TCPFC_ACK 3
|
||||
#define TCPFC_FIN 4
|
||||
#define TCPFC_COUNT 5
|
||||
|
||||
static inline u_int
|
||||
npf_tcpfl2case(const int tcpfl)
|
||||
{
|
||||
u_int i, c;
|
||||
|
||||
/*
|
||||
* Magic value maps flag combinations to TCPFC case numbers.
|
||||
* Other cases are zero. Note: FIN-ACK is mapped to FIN.
|
||||
*/
|
||||
i = (tcpfl & (TH_SYN | TH_FIN)) | ((tcpfl & TH_ACK) >> 2);
|
||||
c = (0x2430140 >> (i << 2)) & 7;
|
||||
|
||||
KASSERT(c < TCPFC_COUNT);
|
||||
return c;
|
||||
}
|
||||
|
||||
/*
|
||||
* NPF transition table of a tracked TCP connection.
|
||||
*
|
||||
* There is a single state, which is changed in the following way:
|
||||
*
|
||||
* new_state = npf_tcp_fsm[old_state][direction][tcp_flags & TH_STATE_MASK];
|
||||
* new_state = npf_tcp_fsm[old_state][direction][npf_tcpfl2case(tcp_flags)];
|
||||
*
|
||||
* Note that this state is different from the state in each end (host).
|
||||
*/
|
||||
|
||||
static const int npf_tcp_fsm[NPF_TCP_NSTATES][2][TH_STATE_MASK + 1]
|
||||
__read_mostly = {
|
||||
static const int npf_tcp_fsm[NPF_TCP_NSTATES][2][TCPFC_COUNT] = {
|
||||
[NPF_TCPS_CLOSED] = {
|
||||
[NPF_FLOW_FORW] = {
|
||||
/* Handshake (1): initial SYN. */
|
||||
[TH_SYN] = NPF_TCPS_SYN_SENT,
|
||||
[TCPFC_SYN] = NPF_TCPS_SYN_SENT,
|
||||
},
|
||||
},
|
||||
[NPF_TCPS_SYN_SENT] = {
|
||||
[NPF_FLOW_FORW] = {
|
||||
/* SYN may be retransmitted. */
|
||||
[TH_SYN] = NPF_TCPS_OK,
|
||||
[TCPFC_SYN] = NPF_TCPS_OK,
|
||||
},
|
||||
[NPF_FLOW_BACK] = {
|
||||
/* Handshake (2): SYN-ACK is expected. */
|
||||
[TH_SYNACK] = NPF_TCPS_SYN_RECEIVED,
|
||||
[TCPFC_SYNACK] = NPF_TCPS_SYN_RECEIVED,
|
||||
/* Simultaneous initiation - SYN. */
|
||||
[TH_SYN] = NPF_TCPS_SIMSYN_SENT,
|
||||
[TCPFC_SYN] = NPF_TCPS_SIMSYN_SENT,
|
||||
},
|
||||
},
|
||||
[NPF_TCPS_SIMSYN_SENT] = {
|
||||
[NPF_FLOW_FORW] = {
|
||||
/* Original SYN re-transmission. */
|
||||
[TH_SYN] = NPF_TCPS_OK,
|
||||
[TCPFC_SYN] = NPF_TCPS_OK,
|
||||
/* SYN-ACK response to simultaneous SYN. */
|
||||
[TH_SYNACK] = NPF_TCPS_SYN_RECEIVED,
|
||||
[TCPFC_SYNACK] = NPF_TCPS_SYN_RECEIVED,
|
||||
},
|
||||
[NPF_FLOW_BACK] = {
|
||||
/* Simultaneous SYN re-transmission.*/
|
||||
[TH_SYN] = NPF_TCPS_OK,
|
||||
[TCPFC_SYN] = NPF_TCPS_OK,
|
||||
/* SYN-ACK response to original SYN. */
|
||||
[TH_SYNACK] = NPF_TCPS_SYN_RECEIVED,
|
||||
/* FIN may be sent at this point. */
|
||||
[TH_FIN] = NPF_TCPS_FIN_SEEN,
|
||||
[TH_FINACK] = NPF_TCPS_FIN_SEEN,
|
||||
[TCPFC_SYNACK] = NPF_TCPS_SYN_RECEIVED,
|
||||
/* FIN may be sent early. */
|
||||
[TCPFC_FIN] = NPF_TCPS_FIN_SEEN,
|
||||
},
|
||||
},
|
||||
[NPF_TCPS_SYN_RECEIVED] = {
|
||||
[NPF_FLOW_FORW] = {
|
||||
/* Handshake (3): ACK is expected. */
|
||||
[TH_ACK] = NPF_TCPS_ESTABLISHED,
|
||||
[TH_FIN] = NPF_TCPS_CLOSING,
|
||||
[TH_FINACK] = NPF_TCPS_CLOSING,
|
||||
[TCPFC_ACK] = NPF_TCPS_ESTABLISHED,
|
||||
/* FIN may be sent early. */
|
||||
[TCPFC_FIN] = NPF_TCPS_FIN_SEEN,
|
||||
},
|
||||
[NPF_FLOW_BACK] = {
|
||||
/* SYN-ACK may be retransmitted. */
|
||||
[TH_SYNACK] = NPF_TCPS_OK,
|
||||
[TCPFC_SYNACK] = NPF_TCPS_OK,
|
||||
/* XXX: ACK of late SYN in simultaneous case? */
|
||||
[TH_ACK] = NPF_TCPS_OK,
|
||||
/* XXX: Can this happen?
|
||||
[TH_FIN] = NPF_TCPS_CLOSING, */
|
||||
[TCPFC_ACK] = NPF_TCPS_OK,
|
||||
/* FIN may be sent early. */
|
||||
[TCPFC_FIN] = NPF_TCPS_FIN_SEEN,
|
||||
},
|
||||
},
|
||||
[NPF_TCPS_ESTABLISHED] = {
|
||||
@ -172,16 +193,14 @@ static const int npf_tcp_fsm[NPF_TCP_NSTATES][2][TH_STATE_MASK + 1]
|
||||
* FIN packets may have ACK set.
|
||||
*/
|
||||
[NPF_FLOW_FORW] = {
|
||||
[TH_ACK] = NPF_TCPS_OK,
|
||||
[TCPFC_ACK] = NPF_TCPS_OK,
|
||||
/* FIN by the sender. */
|
||||
[TH_FIN] = NPF_TCPS_FIN_SEEN,
|
||||
[TH_FINACK] = NPF_TCPS_FIN_SEEN,
|
||||
[TCPFC_FIN] = NPF_TCPS_FIN_SEEN,
|
||||
},
|
||||
[NPF_FLOW_BACK] = {
|
||||
[TH_ACK] = NPF_TCPS_OK,
|
||||
[TCPFC_ACK] = NPF_TCPS_OK,
|
||||
/* FIN by the receiver. */
|
||||
[TH_FIN] = NPF_TCPS_FIN_SEEN,
|
||||
[TH_FINACK] = NPF_TCPS_FIN_SEEN,
|
||||
[TCPFC_FIN] = NPF_TCPS_FIN_SEEN,
|
||||
},
|
||||
},
|
||||
[NPF_TCPS_FIN_SEEN] = {
|
||||
@ -192,64 +211,58 @@ static const int npf_tcp_fsm[NPF_TCP_NSTATES][2][TH_STATE_MASK + 1]
|
||||
* case we are closing immediately.
|
||||
*/
|
||||
[NPF_FLOW_FORW] = {
|
||||
[TH_ACK] = NPF_TCPS_CLOSE_WAIT,
|
||||
[TH_FIN] = NPF_TCPS_CLOSING,
|
||||
[TH_FINACK] = NPF_TCPS_CLOSING,
|
||||
[TCPFC_ACK] = NPF_TCPS_CLOSE_WAIT,
|
||||
[TCPFC_FIN] = NPF_TCPS_CLOSING,
|
||||
},
|
||||
[NPF_FLOW_BACK] = {
|
||||
[TH_ACK] = NPF_TCPS_FIN_WAIT,
|
||||
[TH_FIN] = NPF_TCPS_CLOSING,
|
||||
[TH_FINACK] = NPF_TCPS_CLOSING,
|
||||
[TCPFC_ACK] = NPF_TCPS_FIN_WAIT,
|
||||
[TCPFC_FIN] = NPF_TCPS_CLOSING,
|
||||
},
|
||||
},
|
||||
[NPF_TCPS_CLOSE_WAIT] = {
|
||||
/* Sender has sent the FIN and closed its end. */
|
||||
[NPF_FLOW_FORW] = {
|
||||
[TH_ACK] = NPF_TCPS_OK,
|
||||
[TH_FIN] = NPF_TCPS_LAST_ACK,
|
||||
[TH_FINACK] = NPF_TCPS_LAST_ACK,
|
||||
[TCPFC_ACK] = NPF_TCPS_OK,
|
||||
[TCPFC_FIN] = NPF_TCPS_LAST_ACK,
|
||||
},
|
||||
[NPF_FLOW_BACK] = {
|
||||
[TH_ACK] = NPF_TCPS_OK,
|
||||
[TH_FIN] = NPF_TCPS_LAST_ACK,
|
||||
[TH_FINACK] = NPF_TCPS_LAST_ACK,
|
||||
[TCPFC_ACK] = NPF_TCPS_OK,
|
||||
[TCPFC_FIN] = NPF_TCPS_LAST_ACK,
|
||||
},
|
||||
},
|
||||
[NPF_TCPS_FIN_WAIT] = {
|
||||
/* Receiver has closed its end. */
|
||||
[NPF_FLOW_FORW] = {
|
||||
[TH_ACK] = NPF_TCPS_OK,
|
||||
[TH_FIN] = NPF_TCPS_LAST_ACK,
|
||||
[TH_FINACK] = NPF_TCPS_LAST_ACK,
|
||||
[TCPFC_ACK] = NPF_TCPS_OK,
|
||||
[TCPFC_FIN] = NPF_TCPS_LAST_ACK,
|
||||
},
|
||||
[NPF_FLOW_BACK] = {
|
||||
[TH_ACK] = NPF_TCPS_OK,
|
||||
[TH_FIN] = NPF_TCPS_LAST_ACK,
|
||||
[TH_FINACK] = NPF_TCPS_LAST_ACK,
|
||||
[TCPFC_ACK] = NPF_TCPS_OK,
|
||||
[TCPFC_FIN] = NPF_TCPS_LAST_ACK,
|
||||
},
|
||||
},
|
||||
[NPF_TCPS_CLOSING] = {
|
||||
/* Race of FINs - expecting ACK. */
|
||||
[NPF_FLOW_FORW] = {
|
||||
[TH_ACK] = NPF_TCPS_LAST_ACK,
|
||||
[TCPFC_ACK] = NPF_TCPS_LAST_ACK,
|
||||
},
|
||||
[NPF_FLOW_BACK] = {
|
||||
[TH_ACK] = NPF_TCPS_LAST_ACK,
|
||||
[TCPFC_ACK] = NPF_TCPS_LAST_ACK,
|
||||
},
|
||||
},
|
||||
[NPF_TCPS_LAST_ACK] = {
|
||||
/* FINs exchanged - expecting last ACK. */
|
||||
[NPF_FLOW_FORW] = {
|
||||
[TH_ACK] = NPF_TCPS_TIME_WAIT,
|
||||
[TCPFC_ACK] = NPF_TCPS_TIME_WAIT,
|
||||
},
|
||||
[NPF_FLOW_BACK] = {
|
||||
[TH_ACK] = NPF_TCPS_TIME_WAIT,
|
||||
[TCPFC_ACK] = NPF_TCPS_TIME_WAIT,
|
||||
},
|
||||
},
|
||||
[NPF_TCPS_TIME_WAIT] = {
|
||||
/* May re-open the connection as per RFC 1122. */
|
||||
[NPF_FLOW_FORW] = {
|
||||
[TH_SYN] = NPF_TCPS_SYN_SENT,
|
||||
[TCPFC_SYN] = NPF_TCPS_SYN_SENT,
|
||||
},
|
||||
},
|
||||
};
|
||||
@ -280,7 +293,7 @@ npf_tcp_inwindow(const npf_cache_t *npc, nbuf_t *nbuf, npf_state_t *nst,
|
||||
*
|
||||
* There four boundaries are defined as following:
|
||||
* I) SEQ + LEN <= MAX { SND.ACK + MAX(SND.WIN, 1) }
|
||||
* II) SEQ >= MAX { SND.SEQ + SND.LEN }
|
||||
* II) SEQ >= MAX { SND.SEQ + SND.LEN - MAX(RCV.WIN, 1) }
|
||||
* III) ACK <= MAX { RCV.SEQ + RCV.LEN }
|
||||
* IV) ACK >= MAX { RCV.SEQ + RCV.LEN } - MAXACKWIN
|
||||
*
|
||||
@ -427,7 +440,8 @@ npf_state_tcp(const npf_cache_t *npc, nbuf_t *nbuf, npf_state_t *nst, int di)
|
||||
|
||||
/* Look for a transition to a new state. */
|
||||
if (__predict_true((tcpfl & TH_RST) == 0)) {
|
||||
nstate = npf_tcp_fsm[state][di][tcpfl & TH_STATE_MASK];
|
||||
const int flagcase = npf_tcpfl2case(tcpfl);
|
||||
nstate = npf_tcp_fsm[state][di][flagcase];
|
||||
} else if (state == NPF_TCPS_TIME_WAIT) {
|
||||
/* Prevent TIME-WAIT assassination (RFC 1337). */
|
||||
nstate = NPF_TCPS_OK;
|
||||
|
Loading…
Reference in New Issue
Block a user