Example #1
1
func sendfile(c *net.TCPConn, f *os.File, fi os.FileInfo) {
	sockFile, err := c.File()
	if err != nil {
		fmt.Fprint(c, Error(fmt.Sprintf("couldn't get file sock: %x", err)))
	}
	syscall.Sendfile(int(sockFile.Fd()), int(f.Fd()), nil, int(fi.Size()))
}
Example #2
0
func SetKeepAlive(c *net.TCPConn, cfg *KeepAliveConfig) error {
	if err := c.SetKeepAlive(cfg.KeepAlive); err != nil {
		return err
	}

	file, err := c.File()
	if err != nil {
		return err
	}

	fd := int(file.Fd())

	if cfg.KeepAliveIdle != 0 {
		if err := setIdle(fd, secs(cfg.KeepAliveIdle)); err != nil {
			return err
		}
	}

	if cfg.KeepAliveCount != 0 {
		if err := setCount(fd, cfg.KeepAliveCount); err != nil {
			return err
		}
	}

	if cfg.KeepAliveInterval != 0 {
		if err := setInterval(fd, secs(cfg.KeepAliveInterval)); err != nil {
			return nil
		}
	}

	return nil
}
Example #3
0
func LessDelayTcpConn(conn *net.TCPConn) (connOut net.Conn, err error) {
	//err = conn.SetKeepAlive(true)
	//if err!=nil{
	//	kmgErr.LogErrorWithStack(err)
	//	return nil,err
	//}
	//err = conn.SetKeepAlivePeriod(5*time.Second) //5s太小,耗流量非常凶残.
	//if err!=nil{
	//	kmgErr.LogErrorWithStack(err)
	//	return nil,err
	//}
	fd, err := conn.File()
	if err != nil {
		kmgErr.LogErrorWithStack(err)
		return
	}
	conn1, err := net.FileConn(fd)
	if err != nil {
		fd.Close()
		kmgErr.LogErrorWithStack(err)
		return
	}
	conn.Close()
	//尝试将连接重新设置回 block 模式,减少cpu占用,此方案不稳定,并且不知道如何解决不稳定的问题.
	//err = unix.SetNonblock(int(fd.Fd()),true)
	//if err!=nil{
	//	fd.Close()
	//	kmgErr.LogErrorWithStack(err)
	//	return nil,err
	//}
	//return NewDebugConn(fasterTcpConn{TCPConn: conn, fd: fd},conn.LocalAddr().String()+"_"+conn.RemoteAddr().String()), nil
	return &fasterTcpConn{TCPConn: conn1.(*net.TCPConn), fd: fd}, nil
}
Example #4
0
func snd(what *net.TCPConn, on *net.UnixConn) error {
	f, err := what.File()
	if err != nil {
		return err
	}
	defer f.Close()
	return fd.Put(on, f)
}
Example #5
0
func SysfdByTcpConn(tcpConn *net.TCPConn) (int, error) {
	file, err := tcpConn.File()
	if err != nil {
		return -1, err
	}
	defer file.Close()
	return int(file.Fd()), nil
}
Example #6
0
// setTCPUserTimeout sets TCP_RXT_CONNDROPTIME on darwin
func setTCPUserTimeout(conn *net.TCPConn, uto time.Duration) error {
	f, err := conn.File()
	if err != nil {
		return err
	}
	defer f.Close()

	secs := int(uto.Nanoseconds() / 1e9)
	return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(int(f.Fd()), syscall.IPPROTO_TCP, unix.TCP_RXT_CONNDROPTIME, secs))
}
Example #7
0
// SetTCPUserTimeout sets TCP_USER_TIMEOUT according to RFC5842
func SetTCPUserTimeout(conn *net.TCPConn, uto time.Duration) error {
	f, err := conn.File()
	if err != nil {
		return err
	}
	defer f.Close()

	msecs := int(uto.Nanoseconds() / 1e6)
	return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(int(f.Fd()), syscall.SOL_TCP, C.TCP_USER_TIMEOUT, msecs))
}
Example #8
0
// GetOriginalDST retrieves the original destination address from
// NATed connection.  Currently, only Linux iptables using DNAT/REDIRECT
// is supported.  For other operating systems, this will just return
// conn.LocalAddr().
//
// Note that this function only works when nf_conntrack_ipv4 and/or
// nf_conntrack_ipv6 is loaded in the kernel.
func GetOriginalDST(conn *net.TCPConn) (*net.TCPAddr, error) {
	f, err := conn.File()
	if err != nil {
		return nil, err
	}
	defer f.Close()

	fd := int(f.Fd())
	// revert to non-blocking mode.
	// see http://stackoverflow.com/a/28968431/1493661
	if err = syscall.SetNonblock(fd, true); err != nil {
		return nil, os.NewSyscallError("setnonblock", err)
	}

	v6 := conn.LocalAddr().(*net.TCPAddr).IP.To4() == nil
	if v6 {
		var addr syscall.RawSockaddrInet6
		var len uint32
		len = uint32(unsafe.Sizeof(addr))
		err = getsockopt(fd, syscall.IPPROTO_IPV6, IP6T_SO_ORIGINAL_DST,
			unsafe.Pointer(&addr), &len)
		if err != nil {
			return nil, os.NewSyscallError("getsockopt", err)
		}
		ip := make([]byte, 16)
		for i, b := range addr.Addr {
			ip[i] = b
		}
		pb := *(*[2]byte)(unsafe.Pointer(&addr.Port))
		return &net.TCPAddr{
			IP:   ip,
			Port: int(pb[0])*256 + int(pb[1]),
		}, nil
	}

	// IPv4
	var addr syscall.RawSockaddrInet4
	var len uint32
	len = uint32(unsafe.Sizeof(addr))
	err = getsockopt(fd, syscall.IPPROTO_IP, SO_ORIGINAL_DST,
		unsafe.Pointer(&addr), &len)
	if err != nil {
		return nil, os.NewSyscallError("getsockopt", err)
	}
	ip := make([]byte, 4)
	for i, b := range addr.Addr {
		ip[i] = b
	}
	pb := *(*[2]byte)(unsafe.Pointer(&addr.Port))
	return &net.TCPAddr{
		IP:   ip,
		Port: int(pb[0])*256 + int(pb[1]),
	}, nil
}
// SetTCPUserTimeout sets TCP_MAXRT in Windows
func SetTCPUserTimeout(conn *net.TCPConn, uto time.Duration) error {
	f, err := conn.File()
	if err != nil {
		return err
	}
	defer f.Close()

	// TCP_MAXRT in Windows is set as seconds
	secs := int(uto.Nanoseconds() / 1e9)

	// from MSDN, TCP_MAXRT is supported since Windows Vista
	return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(int(f.Fd()), syscall.SOL_TCP, C.TCP_MAXRT, secs))
}
Example #10
0
// Not used anymore but kept for now. Trying to get keepalive in linux going
// Above in the source code is a link to a blog post. Stolen from there.
func linuxEnableKeepAlive(tcp *net.TCPConn) {
	file, err := tcp.File()
	if err == nil {
		// LINUX ONLY!!
		// If we error we just don't set these options. No harm.
		fd := int(file.Fd())
		os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, syscall.IPPROTO_TCP,
			syscall.TCP_KEEPIDLE, TCP_KEEP_ALIVE))
		os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, syscall.IPPROTO_TCP,
			syscall.TCP_KEEPCNT, 9)) // _probes
		os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, syscall.IPPROTO_TCP,
			syscall.TCP_KEEPINTVL, 75)) // _intvl
	}
}
Example #11
0
// setTCPUserTimeout sets TCP_USER_TIMEOUT according to RFC5842
func setTCPUserTimeout(conn *net.TCPConn, uto time.Duration) error {
	f, err := conn.File()
	if err != nil {
		return err
	}
	defer f.Close()

	msecs := int(uto.Nanoseconds() / 1e6)
	// TCP_USER_TIMEOUT is a relatively new feature to detect dead peer from sender side.
	// Linux supports it since kernel 2.6.37. It's among Golang experimental under
	// golang.org/x/sys/unix but it doesn't support all Linux platforms yet.
	// we explicitly define it here until it becomes official in golang.
	// TODO: replace it with proper package when TCP_USER_TIMEOUT is supported in golang.
	const tcpUserTimeout = 0x12
	return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(int(f.Fd()), syscall.IPPROTO_TCP, tcpUserTimeout, msecs))
}
Example #12
0
func SetTcpTTLSockopts(conn *net.TCPConn, ttl int) error {
	level := syscall.IPPROTO_IP
	name := syscall.IP_TTL
	if strings.Contains(conn.RemoteAddr().String(), "[") {
		level = syscall.IPPROTO_IPV6
		name = syscall.IPV6_UNICAST_HOPS
	}
	fi, err := conn.File()
	defer fi.Close()
	if err != nil {
		return err
	}
	if conn, err := net.FileConn(fi); err == nil {
		defer conn.Close()
	}
	return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(int(fi.Fd()), level, name, ttl))
}
Example #13
0
func sendFile(conn *net.TCPConn, fn string, offset int64) {
	f, err := os.Open(fn)
	if err != nil {
		fmt.Println(err.Error())
		return
	}
	nf, err := conn.File()
	if err != nil {
		fmt.Println(err.Error())
		return
	}
	dst := nf.Fd()
	for i := 0; i < 1000000; i++ {
		_, err = syscall.Sendfile(int(dst), int(f.Fd()), &offset, 1033)
		if err != nil {
			fmt.Println(err.Error())
			break
		}
	}
	conn.CloseWrite()
}
Example #14
0
func NewTCPPipe(id uint, sourceConn net.TCPConn) (pipe TCPPipe, err error) {
	tcppipe := new(TCPPipe)
	f, err := sourceConn.File()
	if err != nil {
		log.Println("[DEBUG] Failed to read connection file descriptor.")
		sourceConn.Close()
		return *tcppipe, err
	}
	//TODO: Investigate this more. This seems arbitrary. If a linux machine: syscall.SOL_IP
	originalAddrBytes, err := syscall.GetsockoptIPv6Mreq(int(f.Fd()), syscall.IPPROTO_IP, SO_ORIGINAL_DST)
	if err != nil {
		log.Println("[DEBUG] Getsockopt failed.")
		sourceConn.Close()
		return *tcppipe, err
	}
	destConn, err := net.Dial("tcp", ByteToConnString(originalAddrBytes.Multiaddr))
	if err != nil {
		log.Printf("[ERR] Unable to connect to destination. Closing connection %v.\n", id)
		sourceConn.Close()
		return *tcppipe, err
	}
	tcppipe = &TCPPipe{id: id, source: sourceConn, destination: destConn}
	return *tcppipe, nil
}
Example #15
0
func getOriginalDst(clientConn *net.TCPConn) (ipv4 string, port uint16, newTCPConn *net.TCPConn, err error) {
	if clientConn == nil {
		log.Debugf("copy(): oops, dst is nil!")
		err = errors.New("ERR: clientConn is nil")
		return
	}

	// test if the underlying fd is nil
	remoteAddr := clientConn.RemoteAddr()
	if remoteAddr == nil {
		log.Debugf("getOriginalDst(): oops, clientConn.fd is nil!")
		err = errors.New("ERR: clientConn.fd is nil")
		return
	}

	srcipport := fmt.Sprintf("%v", clientConn.RemoteAddr())

	newTCPConn = nil
	// net.TCPConn.File() will cause the receiver's (clientConn) socket to be placed in blocking mode.
	// The workaround is to take the File returned by .File(), do getsockopt() to get the original
	// destination, then create a new *net.TCPConn by calling net.Conn.FileConn().  The new TCPConn
	// will be in non-blocking mode.  What a pain.
	clientConnFile, err := clientConn.File()
	if err != nil {
		log.Infof("GETORIGINALDST|%v->?->FAILEDTOBEDETERMINED|ERR: could not get a copy of the client connection's file object", srcipport)
		return
	} else {
		clientConn.Close()
	}

	// Get original destination
	// this is the only syscall in the Golang libs that I can find that returns 16 bytes
	// Example result: &{Multiaddr:[2 0 31 144 206 190 36 45 0 0 0 0 0 0 0 0] Interface:0}
	// port starts at the 3rd byte and is 2 bytes long (31 144 = port 8080)
	// IPv4 address starts at the 5th byte, 4 bytes long (206 190 36 45)
	addr, err := syscall.GetsockoptIPv6Mreq(int(clientConnFile.Fd()), syscall.IPPROTO_IP, SO_ORIGINAL_DST)
	log.Debugf("getOriginalDst(): SO_ORIGINAL_DST=%+v\n", addr)
	if err != nil {
		log.Infof("GETORIGINALDST|%v->?->FAILEDTOBEDETERMINED|ERR: getsocketopt(SO_ORIGINAL_DST) failed: %v", srcipport, err)
		return
	}
	newConn, err := net.FileConn(clientConnFile)
	if err != nil {
		log.Infof("GETORIGINALDST|%v->?->%v|ERR: could not create a FileConn fron clientConnFile=%+v: %v", srcipport, addr, clientConnFile, err)
		return
	}
	if _, ok := newConn.(*net.TCPConn); ok {
		newTCPConn = newConn.(*net.TCPConn)
		clientConnFile.Close()
	} else {
		errmsg := fmt.Sprintf("ERR: newConn is not a *net.TCPConn, instead it is: %T (%v)", newConn, newConn)
		log.Infof("GETORIGINALDST|%v->?->%v|%s", srcipport, addr, errmsg)
		err = errors.New(errmsg)
		return
	}

	ipv4 = itod(uint(addr.Multiaddr[4])) + "." +
		itod(uint(addr.Multiaddr[5])) + "." +
		itod(uint(addr.Multiaddr[6])) + "." +
		itod(uint(addr.Multiaddr[7]))
	port = uint16(addr.Multiaddr[2])<<8 + uint16(addr.Multiaddr[3])

	return
}