Skip to content

Instantly share code, notes, and snippets.

@athomason
Created November 17, 2019 22:48
Show Gist options
  • Save athomason/6d962fbcff9b9a53efc23e3e80d52099 to your computer and use it in GitHub Desktop.
Save athomason/6d962fbcff9b9a53efc23e3e80d52099 to your computer and use it in GitHub Desktop.
// +build linux
package reset
import (
"net"
"strings"
"testing"
"unsafe"
"golang.org/x/sys/unix"
)
// resetTCPConn injects a RST on the provided ipv4 tcp connection.
func resetTCPConn(conn *net.TCPConn) error {
// via https://stackoverflow.com/a/46264137
// http://man7.org/linux/man-pages/man3/connect.3p.html
// "If the sa_family member of address is AF_UNSPEC, the socket's peer
// address shall be reset."
sc, err := conn.SyscallConn()
if err != nil {
return err
}
tcpaddr := conn.LocalAddr().(*net.TCPAddr)
var errno unix.Errno
err = sc.Control(func(fd uintptr) {
if ip := tcpaddr.IP.To4(); ip == nil {
sa := unix.RawSockaddrInet6{
Family: unix.AF_UNSPEC,
Port: uint16(tcpaddr.Port),
}
copy(sa.Addr[:], ip)
e, _, _ := unix.Syscall(
unix.SYS_CONNECT,
fd,
uintptr(unsafe.Pointer(&sa)),
unsafe.Sizeof(sa),
)
errno = unix.Errno(e)
} else {
sa := unix.RawSockaddrInet4{
Family: unix.AF_UNSPEC,
Port: uint16(tcpaddr.Port),
}
copy(sa.Addr[:], ip)
e, _, _ := unix.Syscall(
unix.SYS_CONNECT,
fd,
uintptr(unsafe.Pointer(&sa)),
unsafe.Sizeof(sa),
)
errno = unix.Errno(e)
}
})
if err != nil {
return err
}
if errno != 0 {
return errno
}
return nil
}
func TestResetTCPConn(t *testing.T) {
for _, addr := range []string{"127.0.0.1", "[::1]"} {
t.Run(addr, func(t *testing.T) {
l, err := net.Listen("tcp", addr+":0")
if err != nil {
t.Fatal(err)
}
c := make(chan struct{})
go func() {
if conn, err := l.Accept(); err == nil {
<-c
resetTCPConn(conn.(*net.TCPConn))
}
}()
conn, err := net.Dial("tcp", l.Addr().String())
if err != nil {
t.Fatal(err)
}
close(c)
_, err = conn.Read([]byte{0})
if err == nil || !strings.Contains(err.Error(), "connection reset by peer") {
t.Errorf("unexpected error %q", err)
}
})
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment