syscall.Syscall6 exception when running FTP client written in Go

0

I'm trying to write a simple FTP client in Go which will connect to an FTP server, download any files matching a particular pattern (*.xml), and then remove them from the server. I am using Go because it has easy to use support for cross-compilation (important for development) and produces a single static binary (important for deployment). The Linux binary runs fine on Ubuntu 20.04 (the host platform for development) and my Windows 10 Home laptop (cross-compiled with: GOARCH=windows go build ftp-test.go). However, on a Windows 10 Pro machine I get an exception and stack trace which seems to relate to DNS resolution (full output below).

The simplest version of the client is as follows:

package main;

import (
    "fmt"
    "time"
    "github.com/jlaffaye/ftp"
)

func main() {
    fmt.Println("Connecting to FTP server")
    _, err := ftp.Dial("ftp.mirrorservice.org:21", ftp.DialWithTimeout(60*time.Second))
    if err != nil {
        fmt.Println(err)
    }
}

The full client source code is longer, however as the exception occurs when ftp.Dial is called the above is the minimum code necessary to trigger it. The exception occurs almost instantly, well before the 60 second timeout is hit.

The full stack trace is:

.\ftp-test.exe
Connecting to FTP server
Exception 0xc0000005 0x0 0x7ffae1952fff 0x28cb44e0000
PC=0x28cb44e0000

syscall.Syscall6(0x7ffae07f4c70, 0x4, 0xc0000b60c0, 0x0, 0xc000037f18, 0xc000037e88, 0x0, 0x0, 0x0, 0x0, ...)
        /snap/go/6715/src/runtime/syscall_windows.go:201 +0xf2
syscall.GetAddrInfoW(0xc0000b60c0, 0x0, 0xc000037f18, 0xc000037e88, 0x16, 0x0)
        /snap/go/6715/src/syscall/zsyscall_windows.go:1718 +0xe5
net.(*Resolver).lookupIP.func1(0x0, 0x0, 0x0, 0x0, 0x0)
        /snap/go/6715/src/net/lookup_windows.go:109 +0x259
net.(*Resolver).lookupIP.func2(0xc0000985c0, 0xc0000e8120)
        /snap/go/6715/src/net/lookup_windows.go:146 +0x32
created by net.(*Resolver).lookupIP
        /snap/go/6715/src/net/lookup_windows.go:145 +0x41b

goroutine 1 [select]:
net.(*Resolver).lookupIPAddr(0x5268e0, 0x41e1e0, 0xc0000e8000, 0x3dbef9, 0x3, 0x3e146f, 0x15, 0x15, 0x0, 0x0, ...)
        /snap/go/6715/src/net/lookup.go:299 +0x685
net.(*Resolver).internetAddrList(0x5268e0, 0x41e1e0, 0xc0000e8000, 0x3dbef9, 0x3, 0x3e146f, 0x18, 0x0, 0x0, 0x0, ...)
        /snap/go/6715/src/net/ipsock.go:280 +0x4d4
net.(*Resolver).resolveAddrList(0x5268e0, 0x41e1e0, 0xc0000e8000, 0x3dc010, 0x4, 0x3dbef9, 0x3, 0x3e146f, 0x18, 0x0, ...)
        /snap/go/6715/src/net/dial.go:221 +0x49d
net.(*Dialer).DialContext(0xc0000e6010, 0x41e1a0, 0xc0000a2058, 0x3dbef9, 0x3, 0x3e146f, 0x18, 0x0, 0x0, 0x0, ...)
        /snap/go/6715/src/net/dial.go:403 +0x23c
github.com/jlaffaye/ftp.Dial(0x3e146f, 0x18, 0xc0000cbf50, 0x1, 0x1, 0x19, 0x0, 0x0)
        /home/paul/go/src/github.com/jlaffaye/ftp/ftp.go:105 +0x5fc
main.main()
        /home/paul/ftp-test.go:11 +0xe5

goroutine 19 [select]:
net.(*Resolver).lookupIP(0x5268e0, 0x41e160, 0xc0000ea000, 0x3dbef9, 0x3, 0x3e146f, 0x15, 0x0, 0x0, 0x0, ...)
        /snap/go/6715/src/net/lookup_windows.go:151 +0x1b9
net.glob..func1(0x41e160, 0xc0000ea000, 0xc0000886c0, 0x3dbef9, 0x3, 0x3e146f, 0x15, 0x0, 0x0, 0x0, ...)
        /snap/go/6715/src/net/hook.go:23 +0x79
net.(*Resolver).lookupIPAddr.func1(0x0, 0x0, 0x0, 0x0)
        /snap/go/6715/src/net/lookup.go:293 +0xc2
internal/singleflight.(*Group).doCall(0x5268f0, 0xc0000d60a0, 0xc0000a0760, 0x19, 0xc0000ea040)
        /snap/go/6715/src/internal/singleflight/singleflight.go:95 +0x35
created by internal/singleflight.(*Group).DoChan
        /snap/go/6715/src/internal/singleflight/singleflight.go:88 +0x2cc
rax     0x7ffaddecd84a
rbx     0x7ffaddecd848
rcx     0x77
rdi     0xffffffffffbadd11
rsi     0x0
rbp     0x28cb45135d0
rsp     0xbc5e7fe300
r8      0x94b
r9      0x94b
r10     0x94b
r11     0x94b
r12     0x7ffae1760000
r13     0x0
r14     0x7ffaddecd84a
r15     0xc000007a
rip     0x28cb44e0000
rflags  0x10202
cs      0x33
fs      0x53
gs      0x2b

I have already tried:

  • Updating all dependencies with go get -v -u all.
  • Forcing a recompilation of the code by deleting the binaries (I usually use a Makefile to only rebuild when necessary).
  • Running DNS lookups manually, e.g. nslookup ftp.mirrorservice.org - this returns the IP address I expect.
  • Connecting to the FTP server using ftp on the command line - this works.
  • Trying a simple "hello world" binary - this works (e.g. if I delete everything bar the fmt.Println("Connecting to FTP server") line, the binary runs without any problems).
  • Running the binary on Windows 10 Home when Windows Firewall is configured to block all outbound connections. This results in an error message (not an exception with a stack trace) saying that the binary is trying to access a socket and this is forbidden.
  • Compiling the source code on Windows 10 Home, i.e. not using cross-compilation from Linux. The binary runs on Ubuntu (using WINE) and Windows 10 Home but fails with the same error on the Windows 10 Pro machine.

Unfortunately I have limited access to the Windows 10 Pro machine so I can't install the Go toolchain (as one example).

I am fairly new to Go and rarely target Windows as a platform, so I am not sure if the problem is related to my code, the third party library I'm using for FTP, or Windows (or a combination).

My Go versions are: 1.15.4 linux/amd64 and 1.14.7 windows/amd64

windows
go
ftp
asked on Stack Overflow Nov 11, 2020 by pwaring

1 Answer

0

I couldn't find a definitive answer to this question - no security software appeared to be running on the machine other than Windows Firewall - but my software has been successfully deployed elsewhere now so I'm assuming this was a machine-specific problem.

answered on Stack Overflow Nov 16, 2020 by pwaring

User contributions licensed under CC BY-SA 3.0