//network is useless ,it will always use tcp4 func TfoListen(network string, listenAddr string) (listener net.Listener, err error) { s, err := unix.Socket(unix.AF_INET, unix.SOCK_STREAM|unix.SOCK_NONBLOCK|unix.SOCK_CLOEXEC, 0) if err != nil { return nil, err } defer unix.Close(s) err = unix.SetsockoptInt(s, unix.SOL_TCP, 23, 10) if err != nil { return nil, err } err = unix.SetsockoptInt(s, unix.SOL_SOCKET, unix.SO_REUSEADDR, 1) if err != nil { return nil, err } sa, err := kmgUnix.IPv4TcpAddrToUnixSocksAddr(listenAddr) if err != nil { return nil, err } err = unix.Bind(s, sa) if err != nil { return nil, err } err = unix.Listen(s, 10) if err != nil { return nil, err } f := os.NewFile(uintptr(s), "TFOListen") defer f.Close() return net.FileListener(f) }
func UdpTProxyConn(listenAddr string) (udp *net.UDPConn, err error) { var c net.Conn s, err := unix.Socket(unix.AF_INET6, unix.SOCK_DGRAM, 0) if err != nil { return nil, err } //Why close here ??? defer unix.Close(s) err = unix.SetsockoptInt(s, unix.SOL_SOCKET, unix.SO_REUSEADDR, 1) if err != nil { return nil, err } err = unix.SetsockoptInt(s, unix.SOL_SOCKET, unix.SO_BROADCAST, 1) if err != nil { return nil, err } err = unix.SetsockoptInt(s, unix.SOL_IP, unix.IP_TRANSPARENT, 1) if err != nil { return nil, err } err = unix.SetsockoptInt(s, unix.IPPROTO_IP, unix.IP_RECVORIGDSTADDR, 1) if err != nil { return nil, err } sa, err := IPv6TcpAddrToUnixSocksAddr(listenAddr) if err != nil { return nil, err } err = unix.Bind(s, sa) if err != nil { return nil, err } f := os.NewFile(uintptr(s), "TProxy") defer f.Close() c, err = net.FileConn(f) if err != nil { return nil, err } var ok bool if udp, ok = c.(*net.UDPConn); ok { return } else { c.Close() return nil, errors.New("type error") } }
// TcpListen is listening for incoming IP packets which are being intercepted. // In conflict to regular Listen mehtod the socket destination and source addresses // are of the intercepted connection. // Else then that it works exactly like net package net.Listen. func TcpListen(listenAddr string) (listener net.Listener, err error) { s, err := unix.Socket(unix.AF_INET6, unix.SOCK_STREAM, 0) if err != nil { return nil, err } defer unix.Close(s) err = unix.SetsockoptInt(s, unix.SOL_IP, unix.IP_TRANSPARENT, 1) if err != nil { return nil, err } sa, err := IPv6TcpAddrToUnixSocksAddr(listenAddr) if err != nil { return nil, err } err = unix.Bind(s, sa) if err != nil { return nil, err } err = unix.Listen(s, unix.SOMAXCONN) if err != nil { return nil, err } f := os.NewFile(uintptr(s), "TProxy") defer f.Close() return net.FileListener(f) }
// TfoListen announces on the local network address laddr using tcp protocol and fast open option. // laddr must be in the form of "host:port". // It returns a tfo-enabled listener and an error if any. func tfoListen(laddr string) (lst net.Listener, err error) { s, err := unix.Socket(unix.AF_INET, unix.SOCK_STREAM|unix.SOCK_NONBLOCK|unix.SOCK_CLOEXEC, 0) if err != nil { return } defer unix.Close(s) sa, err := tcpAddrToSockaddr(laddr) if err != nil { return } err = unix.Bind(s, sa) if err != nil { return } // set the socket to fast open mode err = unix.SetsockoptInt(s, unix.SOL_TCP, 23, TCP_FASTOPEN_VAL) if err != nil { return } err = unix.Listen(s, 10) if err != nil { return } f := os.NewFile(uintptr(s), "TFOListen") defer f.Close() return net.FileListener(f) }
// see also https://github.com/jbenet/go-reuseport/blob/master/impl_unix.go#L279 func NewSocket(addr *net.UDPAddr, recvBuf int) (net.PacketConn, error) { sockFD, err := unix.Socket(unix.AF_INET, unix.SOCK_DGRAM|syscall.SOCK_CLOEXEC|syscall.SOCK_NONBLOCK, 0) if err != nil { return nil, err } // unix.SO_REUSEPORT is not defined on linux 386/amd64, see // https://github.com/golang/go/issues/16075 if err := unix.SetsockoptInt(sockFD, unix.SOL_SOCKET, 0xf, 1); err != nil { return nil, err } if err := unix.SetsockoptInt(sockFD, unix.SOL_SOCKET, unix.SO_RCVBUF, recvBuf); err != nil { return nil, err } sockaddr := unix.SockaddrInet4{ Port: addr.Port, } if copied := copy(sockaddr.Addr[:], addr.IP); copied != net.IPv4len { panic("did not copy enough bytes of ip address") } if err := unix.Bind(sockFD, &sockaddr); err != nil { return nil, err } osFD := os.NewFile(uintptr(sockFD), "veneursock") // this will close the FD we passed to NewFile defer osFD.Close() // however, FilePacketConn duplicates the FD, so closing the File's FD does // not affect this object's FD ret, err := net.FilePacketConn(osFD) if err != nil { return nil, err } return ret, nil }
func (conn *fasterTcpConn) Read(b []byte) (nr int, err error) { err = conn.TCPConn.SetReadDeadline(time.Now().Add(10 * time.Minute)) if err != nil { return 0, err } nr, err = conn.TCPConn.Read(b) if err != nil { return nr, err } conn.closeLock.Lock() defer conn.closeLock.Unlock() fdNum := int(conn.fd.Fd()) if fdNum == -1 { //已经关闭过了,此处不管了. return nr, err } err = unix.SetsockoptInt(fdNum, unix.IPPROTO_TCP, unix.TCP_QUICKACK, 1) if err != nil { //TODO 此处总是会爆bad file descriptor,原因不明. kmgErr.LogErrorWithStack(err) return } return }
func listenTCPWithTOS(address *net.TCPAddr, tos byte) (*net.TCPListener, error) { lsnr, err := net.ListenTCP("tcp", address) if err != nil { return nil, err } // This works for the UNIX implementation of netFD, i.e. not on Windows and Plan9. // This kludge is needed until https://github.com/golang/go/issues/9661 is fixed. fd := int(reflect.ValueOf(lsnr).Elem().FieldByName("fd").Elem().FieldByName("sysfd").Int()) var proto, optname int if address.IP.To4() != nil { proto = unix.IPPROTO_IP optname = unix.IP_TOS } else { proto = unix.IPPROTO_IPV6 optname = unix.IPV6_TCLASS } err = unix.SetsockoptInt(fd, proto, optname, int(tos)) if err != nil { lsnr.Close() return nil, os.NewSyscallError("setsockopt", err) } return lsnr, nil }
// TestSCMCredentials tests the sending and receiving of credentials // (PID, UID, GID) in an ancillary message between two UNIX // sockets. The SO_PASSCRED socket option is enabled on the sending // socket for this to work. func TestSCMCredentials(t *testing.T) { fds, err := unix.Socketpair(unix.AF_LOCAL, unix.SOCK_STREAM, 0) if err != nil { t.Fatalf("Socketpair: %v", err) } defer unix.Close(fds[0]) defer unix.Close(fds[1]) err = unix.SetsockoptInt(fds[0], unix.SOL_SOCKET, unix.SO_PASSCRED, 1) if err != nil { t.Fatalf("SetsockoptInt: %v", err) } srvFile := os.NewFile(uintptr(fds[0]), "server") defer srvFile.Close() srv, err := net.FileConn(srvFile) if err != nil { t.Errorf("FileConn: %v", err) return } defer srv.Close() cliFile := os.NewFile(uintptr(fds[1]), "client") defer cliFile.Close() cli, err := net.FileConn(cliFile) if err != nil { t.Errorf("FileConn: %v", err) return } defer cli.Close() var ucred unix.Ucred if os.Getuid() != 0 { ucred.Pid = int32(os.Getpid()) ucred.Uid = 0 ucred.Gid = 0 oob := unix.UnixCredentials(&ucred) _, _, err := cli.(*net.UnixConn).WriteMsgUnix(nil, oob, nil) if err.(*net.OpError).Err != syscall.EPERM { t.Fatalf("WriteMsgUnix failed with %v, want EPERM", err) } } ucred.Pid = int32(os.Getpid()) ucred.Uid = uint32(os.Getuid()) ucred.Gid = uint32(os.Getgid()) oob := unix.UnixCredentials(&ucred) // this is going to send a dummy byte n, oobn, err := cli.(*net.UnixConn).WriteMsgUnix(nil, oob, nil) if err != nil { t.Fatalf("WriteMsgUnix: %v", err) } if n != 0 { t.Fatalf("WriteMsgUnix n = %d, want 0", n) } if oobn != len(oob) { t.Fatalf("WriteMsgUnix oobn = %d, want %d", oobn, len(oob)) } oob2 := make([]byte, 10*len(oob)) n, oobn2, flags, _, err := srv.(*net.UnixConn).ReadMsgUnix(nil, oob2) if err != nil { t.Fatalf("ReadMsgUnix: %v", err) } if flags != 0 { t.Fatalf("ReadMsgUnix flags = 0x%x, want 0", flags) } if n != 1 { t.Fatalf("ReadMsgUnix n = %d, want 1 (dummy byte)", n) } if oobn2 != oobn { // without SO_PASSCRED set on the socket, ReadMsgUnix will // return zero oob bytes t.Fatalf("ReadMsgUnix oobn = %d, want %d", oobn2, oobn) } oob2 = oob2[:oobn2] if !bytes.Equal(oob, oob2) { t.Fatal("ReadMsgUnix oob bytes don't match") } scm, err := unix.ParseSocketControlMessage(oob2) if err != nil { t.Fatalf("ParseSocketControlMessage: %v", err) } newUcred, err := unix.ParseUnixCredentials(&scm[0]) if err != nil { t.Fatalf("ParseUnixCredentials: %v", err) } if *newUcred != ucred { t.Fatalf("ParseUnixCredentials = %+v, want %+v", newUcred, ucred) } }
// TcpDial is a special tcp connection which binds a non local address as the source. // Except then the option to bind to a specific local address which the machine doesn't posses // it is exactly like any other net.Conn connection. // It is advised to use port numbered 0 in the localAddr and leave the kernel to choose which // Local port to use in order to avoid errors and binding conflicts. func TcpDial(localAddr, remoteAddr string) (conn net.Conn, err error) { fmt.Println(localAddr) fmt.Println(remoteAddr) s, err := unix.Socket(unix.AF_INET6, unix.SOCK_STREAM, 0) //In a case there was a need for a non-blocking socket an example //s, err := unix.Socket(unix.AF_INET6, unix.SOCK_STREAM |unix.SOCK_NONBLOCK, 0) if err != nil { fmt.Println(err) return nil, err } defer unix.Close(s) err = unix.SetsockoptInt(s, unix.SOL_IP, unix.IP_TRANSPARENT, 1) if err != nil { fmt.Println(err) return nil, err } err = unix.SetsockoptInt(s, unix.SOL_SOCKET, unix.SO_REUSEADDR, 1) if err != nil { fmt.Println(err) return nil, err } rhost, rport, err := net.SplitHostPort(localAddr) _ = rport if err != nil { fmt.Fprintln(os.Stderr, err) } sa, err := IPv6TcpAddrToUnixSocksAddr(rhost + ":0") if err != nil { fmt.Println(err) return nil, err } remoteSocket, err := IPv6TcpAddrToUnixSocksAddr(remoteAddr) if err != nil { fmt.Println(err) return nil, err } err = unix.Bind(s, sa) if err != nil { fmt.Println(err) return nil, err } err = unix.Connect(s, remoteSocket) if err != nil { fmt.Println(err) return nil, err } f := os.NewFile(uintptr(s), "TProxyTcpClient") client, err := net.FileConn(f) if err != nil { fmt.Println(err) return nil, err } fmt.Println(client.LocalAddr()) fmt.Println(client.RemoteAddr()) return client, err }