📄 tcpsp_conn.c
字号:
/* * tcpsp_conn.c: connection tracking for tcp splicing * * Version: $Id: tcpsp_conn.c,v 1.6 2003/12/01 09:44:51 wensong Exp $ * * Authors: Wensong Zhang <wensong@linux-vs.org> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * * Changes: * */#include <linux/config.h>#include <linux/module.h>#include <linux/types.h>#include <linux/kernel.h>#include <linux/errno.h>#include <linux/vmalloc.h>#include <linux/ip.h>#include <linux/tcp.h> /* for tcphdr */#include <linux/in.h>#include <linux/proc_fs.h> /* for proc_net_* */#include <asm/softirq.h> /* for local_bh_* */#include <net/ip.h>#include <net/tcp.h> /* for csum_tcpudp_magic */#include <net/udp.h>#include <net/icmp.h> /* for icmp_send */#include <net/route.h> /* for ip_route_output */#include <linux/socket.h>#include <linux/netfilter.h>#include <linux/netfilter_ipv4.h>#include "tcpsp.h"//#include <net/tcpsp.h>EXPORT_SYMBOL(tcpsp_conn_new);/* SLAB cache for tcpsp connections */static kmem_cache_t *tcpsp_conn_cachep;/* tcpsp onnection hash tables */#define TCPSP_NTABLES 2static struct list_head *tcpsp_conn_tab1;static struct list_head *tcpsp_conn_tab2;static rwlock_t tcpsp_conn_lock = RW_LOCK_UNLOCKED;/* counter for current tcpsp connections */static atomic_t tcpsp_conn_count = ATOMIC_INIT(0);/* * Returns hash value for tcpsp connection entry */static inline unsignedtcpsp_conn_hash_key(__u32 addr, __u16 port){ unsigned addrh = ntohl(addr); return (addrh^(addrh>>TCPSP_CONN_TAB_BITS)^ntohs(port)) & TCPSP_CONN_TAB_MASK;}/* * Hashes tcpsp_conn in tcpsp_conn_tabs by <addr,port>. * returns bool success. */static int tcpsp_conn_hash(struct tcpsp_conn *cp){ unsigned hash; if (cp->flags & TCPSP_CONN_F_HASHED) { TCPSP_ERR("tcpsp_conn_hash(): request for already hashed, " "called from %p\n", __builtin_return_address(0)); return 0; } write_lock(&tcpsp_conn_lock); hash = tcpsp_conn_hash_key(cp->conn[0].raddr, cp->conn[0].rport); list_add(&cp->f_list, &tcpsp_conn_tab1[hash]); hash = tcpsp_conn_hash_key(cp->conn[1].laddr, cp->conn[1].lport); list_add(&cp->s_list, &tcpsp_conn_tab2[hash]); cp->flags |= TCPSP_CONN_F_HASHED; atomic_add(TCPSP_NTABLES, &cp->refcnt); write_unlock(&tcpsp_conn_lock); return 1;}/* * UNhashes tcpsp_conn from tcpsp_conn_tabs. * returns bool success. */static int tcpsp_conn_unhash(struct tcpsp_conn *cp){ if (!(cp->flags & TCPSP_CONN_F_HASHED)) { TCPSP_ERR("tcpsp_conn_unhash(): request for unhash flagged, " "called from %p\n", __builtin_return_address(0)); return 0; } write_lock(&tcpsp_conn_lock); list_del(&cp->f_list); list_del(&cp->s_list); cp->flags &= ~TCPSP_CONN_F_HASHED; atomic_sub(TCPSP_NTABLES, &cp->refcnt); write_unlock(&tcpsp_conn_lock); return 1;}struct tcpsp_conn *tcpsp_conn_get(__u32 saddr, __u16 sport, __u32 daddr, __u16 dport, int *dir){ unsigned hash; struct list_head *e; struct tcpsp_conn *cp; struct conn_tuple *t; read_lock(&tcpsp_conn_lock); hash = tcpsp_conn_hash_key(saddr, sport); list_for_each (e, &tcpsp_conn_tab1[hash]) { cp = list_entry(e, struct tcpsp_conn, f_list); t = &cp->conn[0]; if (saddr == t->raddr && sport == t->rport && dport == t->lport && daddr == t->laddr) { /* HIT */ *dir = FROM_FIRST_CONN; atomic_inc(&cp->refcnt); read_unlock(&tcpsp_conn_lock); return cp; } } hash = tcpsp_conn_hash_key(daddr, dport); list_for_each (e, &tcpsp_conn_tab2[hash]) { cp = list_entry(e, struct tcpsp_conn, s_list); t = &cp->conn[1]; if (dport == t->lport && daddr == t->laddr && saddr == t->raddr && sport == t->rport) { /* HIT */ *dir = FROM_SECOND_CONN; atomic_inc(&cp->refcnt); read_unlock(&tcpsp_conn_lock); return cp; } } read_unlock(&tcpsp_conn_lock); return NULL;}/* * Put back the conn and restart its timer with its timeout */void tcpsp_conn_put(struct tcpsp_conn *cp){ /* reset it expire in its timeout */ mod_timer(&cp->timer, jiffies+cp->timeout); __tcpsp_conn_put(cp);}/* * Timeout table[state] */struct tcpsp_timeout_table tcpsp_timeout_tbl = { ATOMIC_INIT(0), /* refcnt */ 0, /* scale */ { [TCPSP_S_NONE] = 3*60*HZ, [TCPSP_S_ESTABLISHED] = 15*60*HZ, [TCPSP_S_SYN_SENT] = 2*60*HZ, [TCPSP_S_SYN_RECV] = 1*60*HZ, [TCPSP_S_FIN_WAIT] = 2*60*HZ, [TCPSP_S_TIME_WAIT] = 2*60*HZ, [TCPSP_S_CLOSE] = 10*HZ, [TCPSP_S_CLOSE_WAIT] = 60*HZ, [TCPSP_S_LAST_ACK] = 30*HZ, [TCPSP_S_LISTEN] = 2*60*HZ, [TCPSP_S_SYNACK] = 120*HZ, [TCPSP_S_LAST] = 2*HZ, }, /* timeout */};static const char * state_name_table[TCPSP_S_LAST+1] = { [TCPSP_S_NONE] = "NONE", [TCPSP_S_ESTABLISHED] = "ESTABLISHED", [TCPSP_S_SYN_SENT] = "SYN_SENT", [TCPSP_S_SYN_RECV] = "SYN_RECV", [TCPSP_S_FIN_WAIT] = "FIN_WAIT", [TCPSP_S_TIME_WAIT] = "TIME_WAIT", [TCPSP_S_CLOSE] = "CLOSE", [TCPSP_S_CLOSE_WAIT] = "CLOSE_WAIT", [TCPSP_S_LAST_ACK] = "LAST_ACK", [TCPSP_S_LISTEN] = "LISTEN", [TCPSP_S_SYNACK] = "SYNACK", [TCPSP_S_LAST] = "BUG!",};#define sNO TCPSP_S_NONE#define sES TCPSP_S_ESTABLISHED#define sSS TCPSP_S_SYN_SENT#define sSR TCPSP_S_SYN_RECV#define sFW TCPSP_S_FIN_WAIT#define sTW TCPSP_S_TIME_WAIT#define sCL TCPSP_S_CLOSE#define sCW TCPSP_S_CLOSE_WAIT#define sLA TCPSP_S_LAST_ACK#define sLI TCPSP_S_LISTEN#define sSA TCPSP_S_SYNACKstruct tcpsp_states_t { int next_state[TCPSP_S_LAST]; /* should be _LAST_TCP */};const char * tcpsp_state_name(int state){ if (state >= TCPSP_S_LAST) return "ERR!"; return state_name_table[state] ? state_name_table[state] : "?";}static struct tcpsp_states_t tcpsp_states[] = {/* INPUT *//* sNO, sES, sSS, sSR, sFW, sTW, sCL, sCW, sLA, sLI, sSA *//*syn*/ {{sSR, sES, sES, sSR, sSR, sSR, sSR, sSR, sSR, sSR, sSR }},/*fin*/ {{sCL, sCW, sSS, sTW, sTW, sTW, sCL, sCW, sLA, sLI, sTW }},/*ack*/ {{sCL, sES, sSS, sES, sFW, sTW, sCL, sCW, sCL, sLI, sES }},/*rst*/ {{sCL, sCL, sCL, sSR, sCL, sCL, sCL, sCL, sLA, sLI, sSR }},/* OUTPUT *//* sNO, sES, sSS, sSR, sFW, sTW, sCL, sCW, sLA, sLI, sSA *//*syn*/ {{sSS, sES, sSS, sSR, sSS, sSS, sSS, sSS, sSS, sLI, sSR }},/*fin*/ {{sTW, sFW, sSS, sTW, sFW, sTW, sCL, sTW, sLA, sLI, sTW }},/*ack*/ {{sES, sES, sSS, sES, sFW, sTW, sCL, sCW, sLA, sES, sES }},/*rst*/ {{sCL, sCL, sSS, sCL, sCL, sTW, sCL, sCL, sCL, sCL, sCL }},};static struct tcpsp_states_t *tcpsp_state_table = tcpsp_states;static inline int tcp_state_idx(struct tcphdr *th, int state_off){ /* * [0-3]: input states, [4-7]: output, [8-11] input only states. */ if (th->rst) return state_off+3; if (th->syn) return state_off+0; if (th->fin) return state_off+1; if (th->ack) return state_off+2; return -1;}static inline int set_state_timeout(struct tcpsp_conn *cp, int state){ struct tcpsp_timeout_table *tt = cp->timeout_table; /* * Use default timeout table if no specific for this entry */ if (!tt) tt = &tcpsp_timeout_tbl; cp->timeout = tt->timeout[cp->state=state]; if (tt->scale) { int scale = tt->scale; if (scale<0) cp->timeout >>= -scale; else if (scale > 0) cp->timeout <<= scale; } return state;}static inline intset_state(struct tcpsp_conn *cp, int state_off, struct tcphdr *th){ int state_idx; int new_state = TCPSP_S_CLOSE; if ((state_idx = tcp_state_idx(th, state_off)) < 0) { TCPSP_DBG(8, "tcp_state_idx(%d)=%d!!!\n", state_off, state_idx); goto tcp_state_out; } new_state = tcpsp_state_table[state_idx].next_state[cp->state]; TCPSP_DBG(18, "new state %s\n", tcpsp_state_name(new_state)); tcp_state_out: return set_state_timeout(cp, new_state);}/* * Handle state transitions */int tcpsp_set_state(struct tcpsp_conn *cp, int direction, struct iphdr *iph, struct tcphdr *th){ int ret; spin_lock(&cp->lock); switch (iph->protocol) { case IPPROTO_TCP: ret = set_state(cp, direction*4, th); break; default: ret = -1; } spin_unlock(&cp->lock); return ret;}/* * tcpsp transmitter */static int tcpsp_xmit(struct sk_buff *skb){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -