Example #1
0
// GetOriginalDst returns original destination of Conn
func GetOriginalDst(c net.Conn) (string, error) {
	tcp, ok := c.(*net.TCPConn)
	if !ok {
		return "", errors.New("socket is not tcp")
	}
	file, err := tcp.File()
	if err != nil {
		return "", err
	}
	defer file.Close()
	fd := file.Fd()

	addr, err :=
		syscall.GetsockoptIPv6Mreq(
			int(fd),
			syscall.IPPROTO_IP,
			soOriginalDst)
	if err != nil {
		return "", err
	}

	ip := strings.Join([]string{
		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 fmt.Sprintf("%s:%d", ip, int(port)), nil
}
func getDestAddr(clientConn *net.TCPConn) (net.IP, uint16, *net.TCPConn, error) {
	// http://lkml.iu.edu/hypermail/linux/kernel/9910.0/0221.html
	// http://comments.gmane.org/gmane.comp.lang.go.general/108326
	var destAddr net.IP
	var destPort uint16
	var newTCPConn *net.TCPConn
	fd, err := sysfd(clientConn)
	if err != nil {
		msg := fmt.Sprintf("Error get net.Conn fd in getDestAddr: %s",
			err)
		LogWriter.Err(msg)
	}
	addr, err := syscall.GetsockoptIPv6Mreq(fd,
		syscall.IPPROTO_IP, SO_ORIGINAL_DST)
	if err != nil {
		msg := fmt.Sprintf("Err in syscall.Getsockopt in getDestAddr: %s",
			err)
		LogWriter.Err(msg)
		return destAddr, destPort, newTCPConn, err
	}
	newTCPConn = clientConn
	destAddr = sockaddrToIP(addr.Multiaddr[4:8])
	destPort = uint16(addr.Multiaddr[2])<<8 + uint16(addr.Multiaddr[3])
	return destAddr, destPort, newTCPConn, nil
}
Example #3
0
//New builds a new TrudyPipe. New will get the original destination of traffic
//that was mangled by iptables and get the original destination. New will then
//open a connection to that original destination and, upon success, will set
//all the internalf values needed for a TrudyPipe.
func (t *TrudyPipe) New(id uint, fd int, clientConn net.Conn, useTLS bool) (err error) {
	//TODO(kkl): Make the second argument system-dependent. E.g. If a linux machine: syscall.SOL_IP
	originalAddrBytes, err := syscall.GetsockoptIPv6Mreq(fd, syscall.IPPROTO_IP, SO_ORIGINAL_DST)
	if err != nil {
		log.Println("[DEBUG] Getsockopt failed.")
		clientConn.Close()
		return err
	}

	var serverConn net.Conn
	if useTLS {
		tlsconfig := &tls.Config{InsecureSkipVerify: true}
		serverConn, err = tls.Dial("tcp", byteToConnString(originalAddrBytes.Multiaddr), tlsconfig)
		if err != nil {
			log.Printf("[ERR] Unable to connect to destination. Closing connection %v.\n", id)
			clientConn.Close()
			return err
		}
	} else {
		serverConn, err = net.Dial("tcp", byteToConnString(originalAddrBytes.Multiaddr))
		if err != nil {
			log.Printf("[ERR] ( %v ) Unable to connect to destination. Closing pipe.\n", id)
			clientConn.Close()
			return err
		}
	}
	t.id = id
	t.clientConn = clientConn
	t.serverConn = serverConn
	t.pipeMutex = new(sync.Mutex)
	t.userMutex = new(sync.Mutex)
	return nil
}
Example #4
0
func originalDestinationPort(conn net.Conn) (string, error) {
	f, err := conn.(*net.TCPConn).File()
	if err != nil {
		return "", err
	}
	defer f.Close()
	addr, err := syscall.GetsockoptIPv6Mreq(int(f.Fd()), syscall.IPPROTO_IP, SO_ORIGINAL_DST)
	if err != nil {
		return "", err
	}
	port := uint16(addr.Multiaddr[2])<<8 + uint16(addr.Multiaddr[3])
	return strconv.Itoa(int(port)), nil
}
Example #5
0
func GetAddrFromFile(f *os.File) net.Addr {

	const SO_ORIGINAL_DST = 80

	addr, err := syscall.GetsockoptIPv6Mreq(int(f.Fd()), syscall.IPPROTO_IP,
		SO_ORIGINAL_DST)
	if err != nil {
		log.Printf("getsockopt(SO_ORIGINAL_DST) failed on %v: %v", f, err)
	}

	ipv4 := itod(uint(addr.Multiaddr[4])) + "." +
		itod(uint(addr.Multiaddr[5])) + "." +
		itod(uint(addr.Multiaddr[6])) + "." +
		itod(uint(addr.Multiaddr[7]))

	target := &net.TCPAddr{IP: net.ParseIP(ipv4), Port: int(addr.Multiaddr[2])*256 + int(addr.Multiaddr[3])}
	return target
}
Example #6
0
// Get original destination from redirect of iptables.
func (c *conn) GetOriginalDestination(addr *TCPAddr, err error) {
	if !c.ok() {
		err = os.ErrInvalid
		return
	}
	c.fd.incref()
	defer c.fd.decref()

	const SO_ORIGINAL_DST = 80

	var a *syscall.IPv6Mreq
	if a, err = syscall.GetsockoptIPv6Mreq(c.fd.sysfd, syscall.SOL_IP, SO_ORIGINAL_DST); err == nil {
		data := a.Multiaddr
		addr = &TCPAddr{IP: IP(data[4:8]), Port: int(data[2])<<8 + int(data[3])}
	} else {
		err = os.NewSyscallError("getsockopt", err)
	}
	return
}
Example #7
0
//New creates a new TCPPipe.
func (t *TCPPipe) New(id uint, fd int, sourceConn net.Conn) (err error) {
	//TODO: Make the second argument system-dependent. E.g. If a linux machine: syscall.SOL_IP
	originalAddrBytes, err := syscall.GetsockoptIPv6Mreq(fd, syscall.IPPROTO_IP, SO_ORIGINAL_DST)
	if err != nil {
		log.Println("[DEBUG] Getsockopt failed.")
		sourceConn.Close()
		return 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 err
	}
	t.id = id
	t.source = sourceConn
	t.destination = destConn
	return nil
}
Example #8
0
func GetOriginalDestination(conn internet.Connection) net.Destination {
	tcpConn, ok := conn.(internet.SysFd)
	if !ok {
		log.Info("Dokodemo: Failed to get sys fd.")
		return net.Destination{}
	}
	fd, err := tcpConn.SysFd()
	if err != nil {
		log.Info("Dokodemo: Failed to get original destination: ", err)
		return net.Destination{}
	}

	addr, err := syscall.GetsockoptIPv6Mreq(fd, syscall.IPPROTO_IP, SO_ORIGINAL_DST)
	if err != nil {
		log.Info("Dokodemo: Failed to call getsockopt: ", err)
		return net.Destination{}
	}
	ip := net.IPAddress(addr.Multiaddr[4:8])
	port := uint16(addr.Multiaddr[2])<<8 + uint16(addr.Multiaddr[3])
	return net.TCPDestination(ip, net.Port(port))
}
Example #9
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 #10
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
}