#! /bin/sh # force_close_tcp script # Use this script to force sockets in FIN_WAIT_2 state to close. # It works by setting the 2MSL timer in the TCP Protocol Control Block (PCB) # to a non-zero value. The kernel then begins to decrement this value until # it reaches zero, at which point the kernel forces a close on the socket and # deletes the TCP PCB. If both sides of the connection are hung, clearing one # side will possibly clear the other. # Changes history: # Last Change 14th Nov 1995 - Laurent Demailly - dl@hplyot.obspm.fr # MODIFIED for HPUX by dl (where time_wait is 11 not 10 !!!) # added a lot of variable for OS dependant configurations,... # tested on hpux 8.07, but *** NO WARRANTY *** # used wrongly it can probably CRASH your system... # check /usr/include/netinet/tcp_fsm.h # and /usr/include/netinet/tcp_var.h # many thx to # Look at the oooooooooooolddddddd emails of original workers : # TIMETODEATH expressed in decimal instead of hex # -- mkhaw@teknowledge-vaxc.arpa # original from cdjohns@NSWC-G.ARPA # Variable tweaking: # on HPUX : # #define TCPS_TIME_WAIT 11 /* in 2*msl quiet wait after close */ TCPS_TIME_WAIT=11 # on sunos comment out that one, other OS check /usr/include/netinet/tcp_fsm.h # TCPS_TIME_WAIT=10 # you have to change the two "adb" lines according to your OS # hpux: ADBREAD="adb /hp-ux /dev/kmem" ADBWRITE="adb -w /hp-ux /dev/kmem" # SunOs: # ADBREAD=adb -k /vmunix /dev/mem # ADBWRITE=adb -k -w /vmunix /dev/mem # lastly you'll have to play with the awk below (replace it by grep # or nothing on sunos,... see below) # MSLOFFSET is the offset in the tcpcb record for the 2MSL timer. # describes the tcpcb record. # This value is the number of bytes offset, expressed in hexadecimal. MSLOFFSET=10 # if this change, change the adb dump -- dl STATEOFFSET=8 # TIMETODEATH is the number of half seconds until the connection is # closed. This value is expressed in decimal and must be greater # than zero. TIMETODEATH=10 # Display netstat to get PCB addresses (first column). echo 'Active Internet connections PCB Proto Recv-Q Send-Q Local Address Foreign Address (state)' # damn hpux' netstat can put the state on a 2nd line :/ # so we dropped the |grep 'FIN_WAIT_[12]|CLOS|LAST_ACK' # and we use this awk wizardry instead (to be adapted to your OS # awk and netstat) : -- dl netstat -An | awk -v ve='FIN_WAIT_[12]|CLOS|LAST_ACK' '$1~ve {print prev,$1} {prev=$0} $7~ve {print $0}' # (we can also use plain -aAn to all sockets, including the listening # sockets that this script can close too) echo echo 'Choose a PCB to terminate (amongst FIN_WAIT*,CLOS* or LAST_ACK states)' echo 'Addr = ? \c' read addr echo # Use adb on kernel to display the PCB of the specified address $ADBREAD << ADBR_EOF $addr/"nxt"16t"prev"16t"state"n2Xd $addr+$MSLOFFSET/"2msl"nd \$q ADBR_EOF # Check to see if this was the correct address and PCB. state should be # 8 for LAST_ACK, 9 for FIN_WAIT_2 echo echo "CHECK: 'nxt' & 'prev' should be both = $addr. '2msl' should be 0." # change this accordingly with tcp_fsm.h -- dl echo "'state': >= 6 close in progress, but < 10 waiting for ack or fin" echo '(6=close_wait, 7=fin_wait_1, 8=closing, 9=last_ack, 10=fin_wait2, 11=timewait)' echo 'Is this the correct PCB (y/n)? \c' read ans echo case $ans in [Yy]*) ;; *) echo 'No Changes.' exit ;; esac # Use adb on kernel to set the 2MSL timer for the PCB # and state=CLOSED (0) # Eh, use TIME_WAIT instead (10 decimal) # Eh, use a variable because it is not always 10 !! -- dl $ADBWRITE << ADBW_EOF $addr+$MSLOFFSET/w 0t$TIMETODEATH $addr+$STATEOFFSET/w 0t$TCPS_TIME_WAIT \$q ADBW_EOF echo echo "Connection will be terminated in about `expr $TIMETODEATH / 2` seconds." echo