// 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 }
//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 }
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 }
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 }
// 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 }
//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 }
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)) }
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 }
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 }