免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 7035 | 回复: 5
打印 上一主题 下一主题

请教一个问题,如何杀掉TIME_WAIT的tcp端口?? [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2004-08-24 18:01 |只看该作者 |倒序浏览
程序使用tcp的短连接,如果交易过于频繁的话,就会有很多TIME_WAIT的tcp问题。(用netstat -an|grep 9000查看)

由于要使用9000端口,一旦程序需要重新启动,就会出现端口被占用之类的错误!!因此,我想找到一个杀掉这些讨厌的TIME_WAIT东东!!!

找到的一份资料,但不知道怎么用在unixware上,大家帮忙看看,出出主意!!

SPARC/Solaris 8下快速终结TCP有限状态机的TIME_WAIT状态

发布日期:2002-09-17
文章内容:
--------------------------------------------------------------------------------
作者:NSFocus Security Team <security@nsfocus.com>
主页:http://www.nsfocus.com
日期:2002-07-17

我们这里讨论的是在程序不可控的情况下,比如别人的程序,又未使用SO_REUSEADDR选项,如何快 速终结TCP有限状态机的TIME_WAIT状态。

参看这个链接"closing half-open connections"

http://www-mice.cs.ucl.ac.uk/multimedia/misc/tcp_ip/8707.mm.www/0009.html

1987年10月1日(可真够早的)cdjohns@nswc-g.arpa提供了一个shell script,用于
SunOS 4.x系统下快速终结TCP有限状态机的TIME_WAIT状态。很奇怪,这个脚本并未
得到人们的足够重视并广泛流传,直到SunOS 4.x退出历史舞台,它也就销声匿迹了。
昨天被backend从故纸堆里翻了出来,我们就趁机移植到SPARC/Solaris 8下来。

参看UNP 图2.4了解TCP有限状态机的变迁过程。

/usr/include/netinet里的文件多是为用户空间编程准备的,/usr/include/inet里
的文件多是为内核空间编程准备的。下面内容取自SPARC/Solaris 8

--------------------------------------------------------------------------
/*
* /usr/include/inet/tcp.h
*/

/*
* TCP states
*/
#define TCPS_CLOSED      -6
#define TCPS_IDLE        -5  /* idle (opened, but not bound)      */
#define TCPS_BOUND      -4  /* bound, ready to connect or accept */
#define TCPS_LISTEN      -3  /* listening for connection          */
#define TCPS_SYN_SENT    -2  /* active, have sent syn            */
#define TCPS_SYN_RCVD    -1  /* have received syn (and sent ours) */
/*
* states < TCPS_ESTABLISHED are those where connections not established
*/
#define TCPS_ESTABLISHED  0  /* established                      */
#define TCPS_CLOSE_WAIT  1  /* rcvd fin, waiting for close      */
/*
* states > TCPS_CLOSE_WAIT are those where user has closed
*/
#define TCPS_FIN_WAIT_1  2  /* have closed and sent fin          */
#define TCPS_CLOSING      3  /* closed, xchd FIN, await FIN ACK  */
#define TCPS_LAST_ACK    4  /* had fin and close; await FIN ACK  */
/*
* states > TCPS_CLOSE_WAIT && < TCPS_FIN_WAIT_2 await ACK of FIN
*/
#define TCPS_FIN_WAIT_2  5  /* have closed, fin is acked        */
#define TCPS_TIME_WAIT    6  /* in 2*msl quiet wait after close  */

#if (defined(_KERNEL) || defined(_KMEMUSER))

/*
* If the information represented by the field is required even in the
* TIME_WAIT state, it must be part of tcpb_t. Otherwise it must be part
* of tcp_t. In other words, the tcp_t captures the information that is
* not required, after a connection has entered the TIME_WAIT state.
*/
typedef struct tcp_base_s
{
    struct tcp_base_s  *tcpb_bind_hash;        /* Bind hash chain                    */
    struct tcp_base_s **tcpb_ptpbhn;          /* Pointer to previous bind hash next. */
    struct tcp_base_s *tcpb_conn_hash;        /* Connect hash chain                  */
    struct tcp_base_s **tcpb_ptpchn;          /* Pointer to previous conn hash next. */
    struct tcp_base_s *tcpb_time_wait_next;    /* Pointer to next T/W block          */
    struct tcp_base_s *tcpb_time_wait_prev;    /* Pointer to previous T/W next        */
    /*
    * /usr/include/sys/types.h
    * typedef long clock_t;
    * offset: 8 * 6 -> 48 -> 0x30,clock_t占8个字节(64-bit kernel mode)
    */
    clock_t            tcpb_time_wait_expire;  /* time in hz when t/w expires        */
    clock_t            tcpb_last_rcv_lbolt;    /* lbolt on last packet, used for PAWS */
    /*
    * offset: 0x40
    */
    int32_t            tcpb_state;
    int32_t            tcpb_rcv_ws;            /* My window scale power              */
    int32_t            tcpb_snd_ws;            /* Sender's window scale power        */
    uint32_t          tcpb_ts_recent;        /* Timestamp of earliest unacked      */
    /*
    * data segment
    * offset: 0x50
    */
    clock_t            tcpb_rto;              /* Round trip timeout                  */
    uint32_t          tcpb_snd_ts_ok  : 1,
                      tcpb_snd_ws_ok  : 1,
                      tcpb_is_secure  : 1,
                      tcpb_reuseaddr  : 1,    /* SO_REUSEADDR "socket" option.      */
                      tcpb_exclbind  : 1,    /* ``exclusive'' binding              */
                      tcpb_junk_fill_thru_bit_31 : 27;
    /*
    * offset: 0x5c
    */
    uint32_t          tcpb_snxt;              /* Senders next seq num                */
    uint32_t          tcpb_swnd;              /* Senders window (relative to suna)  */
    uint32_t          tcpb_mss;              /* Max segment size                    */
    uint32_t          tcpb_iss;              /* Initial send seq num                */
    /*
    * offset: 0x6c
    */
    uint32_t          tcpb_rnxt;              /* Seq we expect to recv next          */
    uint32_t          tcpb_rwnd;              /* Current receive window              */
    /*
    * /usr/include/sys/mutex.h
    * 无论64-bit还是32-bit kernel mode,kmutex_t都占8字节空间,这里需要对
    * 齐在数据类型自然连界上,0x6c + 8 -> 0x74不在kmutex_t自然边界上,继
    * 续后移4个字节
    *
    * offset: 0x78
    */
    kmutex_t          tcpb_reflock;          /* Protects tcp_refcnt                */
    /*
    * offset: 0x80
    */
    ushort_t          tcpb_refcnt;            /* Number of pending upstream msg      */
    union
    {
        struct
        {
            uchar_t v4_ttl;  /* Dup of tcp_ipha.iph_type_of_service */
            uchar_t v4_tos;  /* Dup of tcp_ipha.iph_ttl            */
        } v4_hdr_info;
        struct
        {
            /*
            * 对齐在uint_t的自然边界上
            * offset: 0x84
            */
            uint_t  v6_vcf;  /* Dup of tcp_ip6h.ip6h_vcf            */
            /*
            * offset: 0x88
            */
            uchar_t v6_hops;  /* Dup of tcp_ip6h.ip6h_hops          */
        } v6_hdr_info;
    } tcpb_hdr_info;

#define tcpb_ttl      tcpb_hdr_info.v4_hdr_info.v4_ttl
#define tcpb_tos      tcpb_hdr_info.v4_hdr_info.v4_tos
#define tcpb_ip6_vcf  tcpb_hdr_info.v6_hdr_info.v6_vcf
#define tcpb_ip6_hops tcpb_hdr_info.v6_hdr_info.v6_hops

    /*
    * offset: 0x8c,先是远端地址,后是本地地址
    * /usr/include/netinet/in.h
    * in6_addr_t长16字节,在内核空间里这个结构对齐在uint32_t的自然边界上
    */
    in6_addr_t        tcpb_remote_v6;        /* true remote address - needed for    */
                                              /* source routing.                    */
    in6_addr_t        tcpb_bound_source_v6;  /* IP address in bind_req              */
    /*
    * offset: 0xac
    */
    in6_addr_t        tcpb_ip_src_v6;        /* same as tcp_iph.iph_src.            */

#ifdef _KERNEL
/*
* Note: V4_PART_OF_V6 is meant to be used only for _KERNEL defined stuff
*/
#define tcpb_remote      V4_PART_OF_V6(tcpb_remote_v6)
#define tcpb_bound_source V4_PART_OF_V6(tcpb_bound_source_v6)
#define tcpb_ip_src      V4_PART_OF_V6(tcpb_ip_src_v6)
#endif  /* _KERNEL */

    /*
    * These fields contain the same information as tcp_tcph->th_*port.
    * However, the lookup functions can not use the header fields
    * since during IP option manipulation the tcp_tcph pointer
    * changes.
    */
    /*
    * offset: 0xbc,先是远端端口,后是本地端口
    */
    union
    {
        struct
        {
            in_port_t tcpu_fport;  /* Remote port          */
            in_port_t tcpu_lport;  /* Local port          */
        } tcpu_ports1;
        uint32_t      tcpu_ports2;  /* Rem port, local port */
        /*
        * Used for TCP_MATCH performance
        */
    } tcpb_tcpu;
#define tcpb_fport tcpb_tcpu.tcpu_ports1.tcpu_fport
#define tcpb_lport tcpb_tcpu.tcpu_ports1.tcpu_lport
#define tcpb_ports tcpb_tcpu.tcpu_ports2
    /*
    * IP sends back 2 mblks with the unbind ACK for handling
    * IPSEC policy for detached connections. Following two fields
    * are initialized then.
    */
    mblk_t            *tcpb_ipsec_out;
    mblk_t            *tcpb_ipsec_req_in;
    /*
    * offset: 0xd0
    */
    tcp_t            *tcpb_tcp;
    /*
    * offset: 0xd8
    */
    /*
    * IP format that packets transmitted from this struct should use.
    * Value can be IPV4_VERSION or IPV6_VERSION.  Determines whether
    * IP+TCP header template above stores an IPv4 or IPv6 header.
    */
    ushort_t          tcpb_ipversion;
    uint_t            tcpb_bound_if;          /* IPV6_BOUND_IF                      */
    uid_t              tcpb_ownerid;          /* uid of process that did open        */
#define tcp_bind_hash        tcp_base->tcpb_bind_hash
#define tcp_ptpbhn          tcp_base->tcpb_ptpbhn
#define tcp_conn_hash        tcp_base->tcpb_conn_hash
#define tcp_ptpchn          tcp_base->tcpb_ptpchn
#define tcp_time_wait_next  tcp_base->tcpb_time_wait_next
#define tcp_time_wait_prev  tcp_base->tcpb_time_wait_prev
#define tcp_time_wait_expire tcp_base->tcpb_time_wait_expire
#define tcp_last_rcv_lbolt  tcp_base->tcpb_last_rcv_lbolt
#define tcp_state            tcp_base->tcpb_state
#define tcp_rcv_ws          tcp_base->tcpb_rcv_ws
#define tcp_snd_ws          tcp_base->tcpb_snd_ws
#define tcp_ts_recent        tcp_base->tcpb_ts_recent
#define tcp_rto              tcp_base->tcpb_rto
#define tcp_snd_ts_ok        tcp_base->tcpb_snd_ts_ok
#define tcp_snd_ws_ok        tcp_base->tcpb_snd_ws_ok
#define tcp_is_secure        tcp_base->tcpb_is_secure
#define tcp_snxt            tcp_base->tcpb_snxt
#define tcp_swnd            tcp_base->tcpb_swnd
#define tcp_mss              tcp_base->tcpb_mss
#define tcp_iss              tcp_base->tcpb_iss
#define tcp_rnxt            tcp_base->tcpb_rnxt
#define tcp_rwnd            tcp_base->tcpb_rwnd
#define tcp_reflock          tcp_base->tcpb_reflock
#define tcp_refcnt          tcp_base->tcpb_refcnt
#define tcp_remote_v6        tcp_base->tcpb_remote_v6
#define tcp_remote          tcp_base->tcpb_remote
#define tcp_bound_source_v6  tcp_base->tcpb_bound_source_v6
#define tcp_bound_source    tcp_base->tcpb_bound_source
#define tcp_lport            tcp_base->tcpb_tcpu.tcpu_ports1.tcpu_lport
#define tcp_fport            tcp_base->tcpb_tcpu.tcpu_ports1.tcpu_fport
#define tcp_ports            tcp_base->tcpb_tcpu.tcpu_ports2
#define tcp_ipsec_out        tcp_base->tcpb_ipsec_out
#define tcp_ipsec_req_in    tcp_base->tcpb_ipsec_req_in
#define tcp_ipversion        tcp_base->tcpb_ipversion
#define tcp_bound_if        tcp_base->tcpb_bound_if
#define tcp_reuseaddr        tcp_base->tcpb_reuseaddr
#define tcp_exclbind        tcp_base->tcpb_exclbind
#define tcp_ownerid          tcp_base->tcpb_ownerid
} tcpb_t;
#endif  /* (defined(_KERNEL) || defined(_KMEMUSER)) */
--------------------------------------------------------------------------

下面这两条命令其实是用分号连在一起执行的,否则前后数据不对应,我是telnet上
去执行命令。

# ndd /dev/tcp tcp_status | grep ESTABLISHED
TCPB        dest              snxt    suna    swnd      rnxt    rack    rwnd      rto  mss  w sw rw t recent  [lport,fport] state
30000cc21d0 ::ffff:192.168.5.8 8e0e46dc 8e0e46da 0000064010 3d49e751 3d49e751 0000024820 00583 01460 0 00 00 0 00000000 [23, 4613]    TCP_ESTABLISHED
# skd64 0x30000cc21d0 256
byteArray [ 256 bytes ] ---->
0000000000000000  00 00 03 00 00 47 C1 80-00 00 00 00 10 48 18 88    .....G羳.....H.?
0000000000000010  00 00 00 00 00 00 00 00-00 00 03 00 00 3A 60 80    .............:`�
0000000000000020  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00    ................
0000000000000030  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00    ................
0000000000000040  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00    ................
0000000000000050  00 00 00 00 00 00 02 47-10 00 00 00 8E 0E 46 DC    .......G....?F?
0000000000000060  00 00 FA 0A 00 00 05 B4-8E 0B 77 07 3D 49 E7 51    ..?...磶.w.=I鏠
0000000000000070  00 00 60 F4 00 00 00 00-00 00 00 00 00 00 00 00    ..`?...........
0000000000000080  00 01 00 00 3C 00 00 00-3C 00 00 00 00 00 00 00    ....<...<.......
0000000000000090  00 00 00 00 00 00 FF FF-C0 A8 05 08 00 00 00 00    ......��括......
00000000000000A0  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00    ................
00000000000000B0  00 00 00 00 00 00 FF FF-C0 A8 05 82 12 05 00 17    ......��括.?...
00000000000000C0  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00    ................
00000000000000D0  00 00 03 00 00 BB 6F D0-00 04 00 00 00 00 00 00    .....籵?.......
00000000000000E0  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00    ................
00000000000000F0  00 00 03 00 00 08 2B 68-00 00 00 00 00 00 00 00    ......+h........
#

显然0x30000cc21d0对应着一个tcpb_t结构。

# adb -k /dev/ksyms /dev/mem
physmem 3b68
0x30000cc21d0$<tcpb

30000cc21d0:    tcp_bind_hash  tcp_ptpbhn      tcp_conn_hash
            3000047c180      10481888        0
30000cc21e8:    tcp_ptpchn      time_wait_next  time_wait_prev
            300003a6080      0                0
30000cc2200:    time_wait_expir last_rcv_lbolt  tcp_state
            0                0                0
30000cc2214:    tcp_rcv_ws      tcp_snd_ws      tcp_ts_recent
                0              0              0
30000cc2220:    tcp_rto
            24c
                snd_ts_ok      0
                snd_ws_ok      0
                is_secure      0
                reuseaddr      1
                exclbind        0

30000cc222c:    tcp_snxt        tcp_swnd        tcp_mss
                8e176ce4        f8dc            5b4
30000cc2238:    tcp_iss        tcp_rnxt        tcp_rwnd
                8e0b7707        3d49ecf0        60f4
30000cc2248:    tcpb_reflock
30000cc2248:    owner/waiters
            0


30000cc2250:    tcp_refcnt      tcpb_vcf        tcpb_hops
                1              3c000000        3c
30000cc225c:    tcpb_remote_v6

30000cc225c:    0              0              ffff            c0a80508

30000cc226c:    tcpb_bound_source_v6

30000cc226c:    0              0              0              0

30000cc227c:    tcpb_ip_src_v6

30000cc227c:    0              0              ffff            c0a80582

30000cc228c:    tcpu_fport      tcpu_lport      ipsec_out
                1205            17              0
30000cc2298:    ipsec_req_in    tcpb_tcp        tcpb_ipversion
            0                30000bb6fd0      4
30000cc22ac:    bound_if        ownerid
                0              0

$q
#

于是我们可以写这样一个脚本kill_timewait.sh

--------------------------------------------------------------------------
#! /sbin/sh
#

#
# @(#)kill_timewait.sh 2002-07-07 NSFocus Copyleft 2002-2012
#
# Notice here is copyleft but not copyright, enjoy it by yourself.
#
# ------------------------------------------------------------------------
# File    : kill_timewait.sh
# Platform : SPARC/Solaris 8 64-bit kernel mode
# Author  : NSFocus Security Team <security@nsfocus.com>
#          : http://www.nsfocus.com
# Date    : 2002-07-07 12:27
# Modify  :
# Thanks  : cdjohns@nswc-g.arpa for SunOS 4.x implementation
#

netstat -na -P tcp -f inet | grep TIME_WAIT

echo
echo 'TCPB dest [lport,fport] state'
echo
ndd /dev/tcp tcp_status | nawk '{print $1 " " $2 " " $16 $17 " " $18}' | egrep 'TIME_WAIT'

echo
/usr/bin/echo 'TCPB address to terminate: \c'
read tcpb_addr
echo

adb -k /dev/ksyms /dev/mem << NSFOCUS_EOF
$tcpb_addr\$</usr/lib/adb/sparcv9/tcpb
\$q
NSFOCUS_EOF

#
# Check to see if this was the correct address and TCPB. state should be 6
#
echo
echo 'tcp_state = 6 = TCPS_TIME_WAIT'
/usr/bin/echo 'Is this the correct TCPB (y/n)? \c'
read answer
echo
case $answer in
  [Yy]*)
;;
  *)
echo 'No Changes.'
exit
;;
esac

#
# Kernel Hacking, please. These value are expressed in hexadecimal.
#
TIME_WAIT_EXPIRE_OFFSET=0x30
STATE_OFFSET=0x40

#
# This value is expressed in decimal and must be greater than zero.
#
TIME_WAIT_EXPIRE=0t06

#
# Use adb on kernel to set the tcpb_time_wait_expire=6 and
# tcpb_state=TCPS_CLOSED (-6)
#
adb -kw /dev/ksyms /dev/mem << NSFOCUS_EOF
$tcpb_addr+$TIME_WAIT_EXPIRE_OFFSET/Z $TIME_WAIT_EXPIRE
$tcpb_addr+$STATE_OFFSET/W -6
\$q
NSFOCUS_EOF

echo
echo "TIME_WAIT state will disappear."
echo

netstat -na -P tcp -f inet | grep TIME_WAIT
--------------------------------------------------------------------------

不要设置tcpb_time_wait_expire成零,只要是一个很小的值就可以了。这里必须同
时设置tcpb_time_wait_expire和tcpb_state,只设置其中一个达不到效果。

利用adb从TCPS_ESTABLISHED变为TCPS_CLOSE_WAIT,可以使一条TCP连接不再工作,
但这条连接并未销毁,tcpb_t结构也未删除。

利用adb从TCPS_ESTABLISHED变为TCPS_CLOSED,会导致整个操作系统崩溃。可能是下
层tcpb_t结构被删除,而上层socket并不了解,出现非法指针。

简化一下kill_timewait.sh

--------------------------------------------------------------------------
#! /sbin/sh

ndd /dev/tcp tcp_status | nawk '{print $1 " " $2 " " $16 $17 " " $18}' | egrep 'TIME_WAIT'

echo
/usr/bin/echo 'TCPB address to terminate: \c'
read tcpb_addr
echo

adb -kw /dev/ksyms /dev/mem << NSFOCUS_EOF
$tcpb_addr+0x30/Z 0t6
$tcpb_addr+0x40/W -6
\$q
NSFOCUS_EOF
--------------------------------------------------------------------------

还可以写一个脚本自动清除所有TIME_WAIT状态TCP连接

--------------------------------------------------------------------------
#! /sbin/sh

ndd /dev/tcp tcp_status | nawk '{print $1 " " $2 " " $16 $17 " " $18}' | \
egrep 'TIME_WAIT' | cut -d' ' -f1 | while read tcpb_addr
do
adb -kw /dev/ksyms /dev/mem << NSFOCUS_EOF
$tcpb_addr+0x30/Z 0t6
$tcpb_addr+0x40/W -6
\$q
NSFOCUS_EOF
done
----------------------------------------------------------------------

论坛徽章:
0
2 [报告]
发表于 2004-08-24 23:46 |只看该作者

请教一个问题,如何杀掉TIME_WAIT的tcp端口??

用lsof可以

论坛徽章:
1
荣誉版主
日期:2011-11-23 16:44:17
3 [报告]
发表于 2004-08-25 00:02 |只看该作者

请教一个问题,如何杀掉TIME_WAIT的tcp端口??

TIME_WAIT 已進入結束階段了, 這跟你要殺死它也沒太大差別吧?
若你想殺的是 PID, 那 netstat -nap (多加個 -p 參數)就可抓到,
然後 grep/cut/awk 一下, 交給 kill 就是了... 或許還要寫個 for loop?

论坛徽章:
0
4 [报告]
发表于 2004-08-25 09:33 |只看该作者

请教一个问题,如何杀掉TIME_WAIT的tcp端口??

不是要杀进程,是要在主程序退出后,把这些讨厌的东东干掉

论坛徽章:
1
荣誉版主
日期:2011-11-23 16:44:17
5 [报告]
发表于 2004-08-25 10:51 |只看该作者

请教一个问题,如何杀掉TIME_WAIT的tcp端口??

那不妨花些時間看看 tcp state , 了解一下 TIME_WAIT 的階段性,
再來決定是否要殺不遲...

论坛徽章:
0
6 [报告]
发表于 2004-08-26 08:57 |只看该作者

请教一个问题,如何杀掉TIME_WAIT的tcp端口??

我记得在linux下可以用

fuser -k -n tcp /path(程序的绝对路径)这个命令杀掉这些东东

就是不知unixware下该怎么搞??
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP