Disconnecting the power connector without fake RST, Linux

I have a network client that is stuck in a recvfrom server, which is not under my control, which after 24 hours will probably never respond. The program processed a large amount of data, so I do not want to kill it; I want him to abandon the current connection and continue. (He will do it right if recvfrom returns EOF or -1.) I have already tried several different programs that supposedly can disable legacy TCP channels by faking RST ( tcpkill , cutter , killcx ); none of them had any effect, the program remained stuck in recvfrom . I also tried connecting to the network interface; again, no effect.

It seems to me that there really should be a way to force disconnect at the socket API level without faking network packets. I do not mind the terrible hacks, even to the point of being a disaster recovery situation. Any suggestions?

(For clarity, the TCP channel here is in the ESTABLISHED state according to lsof .)

+4
source share
2 answers

I don't mind horrible hacks

That is all you can say. I assume the tools you tried did not work because they sniff the traffic in order to get an acceptable ACK number to kill the connection. Without the flow of traffic, they are unable to take possession of it.

Here is what you can try:

Call all serial numbers

If these tools fail, you can still do it. Make a simple python script and with scapy, for each serial number, send the RST segment with the correct 4-tuple (ports and addresses). There are no more than 4 billion (actually less than a suitable window - you can find a window for free without using ss -i ).

Make a kernel module to get a socket

  • Make a kernel module that receives a list of TCP sockets: find sk_nulls_for_each(sk, node, &tcp_hashinfo.ehash[i].chain)

  • Identify your victim sk

At this point, you have access to your socket. So

  • You can call tcp_reset or tcp_disconnect on it. You cannot directly call tcp_reset (since it does not have EXPORT_SYMBOL ), but you have to mimic it: most of the functions that it calls are exported

  • Or you can get the expected ACK number with tcp_sk(sk) and directly fake the RST packet with scapy


Here is the function that I use to print installed sockets - I cut out fragments from the kernel to do this some time ago:

 #include <net/inet_hashtables.h> #define NIPQUAD(addr) \ ((unsigned char *)&addr)[0], \ ((unsigned char *)&addr)[1], \ ((unsigned char *)&addr)[2], \ ((unsigned char *)&addr)[3] #define NIPQUAD_FMT "%u.%u.%u.%u" extern struct inet_hashinfo tcp_hashinfo; /* Decides whether a bucket has any sockets in it. */ static inline bool empty_bucket(int i) { return hlist_nulls_empty(&tcp_hashinfo.ehash[i].chain); } void print_tcp_socks(void) { int i = 0; struct inet_sock *inet; /* Walk hash array and lock each if not empty. */ printk("Established ---\n"); for (i = 0; i <= tcp_hashinfo.ehash_mask; i++) { struct sock *sk; struct hlist_nulls_node *node; spinlock_t *lock = inet_ehash_lockp(&tcp_hashinfo, i); /* Lockless fast path for the common case of empty buckets */ if (empty_bucket(i)) continue; spin_lock_bh(lock); sk_nulls_for_each(sk, node, &tcp_hashinfo.ehash[i].chain) { if (sk->sk_family != PF_INET) continue; inet = inet_sk(sk); printk(NIPQUAD_FMT":%hu ---> " NIPQUAD_FMT ":%hu\n", NIPQUAD(inet->inet_saddr), ntohs(inet->inet_sport), NIPQUAD(inet->inet_daddr), ntohs(inet->inet_dport)); } spin_unlock_bh(lock); } } 

You can use this module in a simple Hello World module, and after inserting it into dmesg you will see sockets (for example, ss or netstat ).

+4
source

I understand that you want to do this to automate the process to do the test. But if you just want to verify that recvfrom error handling is correct, you can connect to GDB and close fd by calling close ().

Here you can see an example.

Another option is to use scapy to create RST boxes (which are not on your list). This is how I tested RST connections in a bridge system (IMHO is the best option), you can also implement a graceful shutdown.

Here is an example scapy script.

+1
source

All Articles