4

How to reset an accepted socket in application level either with IO::Socket::INET in perl or in C?

There is a programm binding, listening on a TCP port, and accepts a client connection, after that it reads and writes some data. If I simply close or shutdown the socket, TCP layer gracefully terminates (with FIN packet), rather than, I'd generate an RST packet.

4
  • AFAIK, there's no way to do so using the socket you've been sending and receiving on. You could always handcraft your own RST packet and send it to your peer, but you'd need to create a separate raw packet socket to send it. Linux also has a SOCK_DESTROY function (conditionally included in kernel) that can be used by an appropriately privileged process to close an arbitrary connection, but it's also completely out-of-band from you application socket. Why do you want to terminate with RST anyway? Commented Jul 21, 2016 at 16:03
  • 2
    You can try SO_LINGER socket option with zero timeout, according to some resources it will generate RST packet instead of FIN. Commented Jul 21, 2016 at 16:34
  • @SlavaBacherikov thanks, it works in code: $socket=IO::Socket::INET->new(Listen=1,ReuseAddr=>1,LocalPort=>...,...); $client=$socket->accept(); $client->sockopt(SO_LINGER, pack('II', 1, 0)); close $client. curl and wget always handle this condition with return code 56 and 4 respectively. however netcat nondeterministically somewhen detects "Connection refused by peer" but sometimes not. Commented Jul 22, 2016 at 7:27
  • 1
    close will produce RST if the receive buffer has data that has not yet been read by your application. Commented Sep 16, 2017 at 8:55

1 Answer 1

4

You didn't specify the exact OS you are using. I found that Linux does have an API call which will reset a TCP connection, I have no idea how portable it is. The way to do it is to use the connect system call on the already connected socket but this time with family AF_UNSPEC.

After you have reset a socket that way it is even possible to connect the socket again with another connect call.

int main(int argc, char** argv)
{
  int fd = socket(AF_INET6, SOCK_STREAM, 0);

  while (1) {
    struct sockaddr_in6 sockaddr = {
      .sin6_family = AF_INET6,
      .sin6_port = htons(80),
      .sin6_flowinfo = 0,
      .sin6_scope_id = 0,
    };
    struct timespec s = {
      .tv_sec = 2,
      .tv_nsec = 0,
    };

    /* Connect to port 80 on localhost */
    inet_pton(AF_INET6, "::1", &sockaddr.sin6_addr.s6_addr);
    connect(fd, (struct sockaddr*)&sockaddr,sizeof(sockaddr));
    nanosleep(&s, NULL);

    /* Reset previously connected socket */
    sockaddr.sin6_family = AF_UNSPEC;
    connect(fd, (struct sockaddr*)&sockaddr,sizeof(sockaddr));
    nanosleep(&s, NULL);
  }
}
Sign up to request clarification or add additional context in comments.

1 Comment

great. I tested your connect AF_UNSPEC solution also on ipv4 listening scenario, in this case I have to re-connect not the listening socket but the one returned by accept.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.