Skip to content

Commit

Permalink
Merge pull request #53 from wearefair/injectable-listener
Browse files Browse the repository at this point in the history
Allow passing in an existing net.Listener and a public ip resolver.
  • Loading branch information
fclairamb committed Dec 28, 2017
2 parents ba2ee57 + 5890a0b commit 976aca6
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 14 deletions.
5 changes: 5 additions & 0 deletions server/client_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,11 @@ func (c *clientHandler) RemoteAddr() net.Addr {
return c.conn.RemoteAddr()
}

// LocalAddr returns the local network address.
func (c *clientHandler) LocalAddr() net.Addr {
return c.conn.LocalAddr()
}

func (c *clientHandler) end() {
c.daddy.driver.UserLeft(c)
c.daddy.clientDeparture(c)
Expand Down
19 changes: 14 additions & 5 deletions server/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ type ClientContext interface {

// Client's address
RemoteAddr() net.Addr

// Servers's address
LocalAddr() net.Addr
}

// FileStream is a read or write closeable stream
Expand All @@ -90,11 +93,17 @@ type PortRange struct {
End int // Range end
}

// PublicIPResolver takes a ClientContext for a connection and returns the public IP
// to use in the response to the PASV command, or an error if a public IP cannot be determined.
type PublicIPResolver func(ClientContext) (string, error)

// Settings defines all the server settings
type Settings struct {
ListenAddr string // Listening address
PublicHost string // Public IP to expose (only an IP address is accepted at this stage)
DataPortRange *PortRange // Port Range for data connections. Random one will be used if not specified
DisableMLSD bool // Disable MLSD support
NonStandardActiveDataPort bool // Allow to use a non-standard active data port
Listener net.Listener // Allow providing an already initialized listener. Mutually exclusive with ListenAddr
ListenAddr string // Listening address
PublicHost string // Public IP to expose (only an IP address is accepted at this stage)
PublicIPResolver PublicIPResolver // Optional function that can perform a public ip lookup for the given CientContext.
DataPortRange *PortRange // Port Range for data connections. Random one will be used if not specified
DisableMLSD bool // Disable MLSD support
NonStandardActiveDataPort bool // Allow to use a non-standard active data port
}
17 changes: 9 additions & 8 deletions server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ func (server *FtpServer) loadSettings() error {
return err
}

if s.ListenAddr == "" {
if s.Listener == nil && s.ListenAddr == "" {
s.ListenAddr = "0.0.0.0:2121"
}

Expand All @@ -112,14 +112,15 @@ func (server *FtpServer) Listen() error {
return fmt.Errorf("could not load settings: %v", err)
}

server.listener, err = net.Listen(
"tcp",
server.settings.ListenAddr,
)
if server.settings.Listener != nil {
server.listener = server.settings.Listener
} else {
server.listener, err = net.Listen("tcp", server.settings.ListenAddr)

if err != nil {
level.Error(server.Logger).Log(logKeyMsg, "Cannot listen", "err", err)
return err
if err != nil {
level.Error(server.Logger).Log(logKeyMsg, "Cannot listen", "err", err)
return err
}
}

level.Info(server.Logger).Log(logKeyMsg, "Listening...", logKeyAction, "ftp.listening", "address", server.listener.Addr())
Expand Down
14 changes: 13 additions & 1 deletion server/transfer_pasv.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,19 @@ func (c *clientHandler) handlePASV() {

// If we don't have an IP address, we can take the one that was used for the current connection
if ip == "" {
ip = strings.Split(c.conn.LocalAddr().String(), ":")[0]
// Defer to the user provided resolver.
if c.daddy.settings.PublicIPResolver != nil {
var err error
ip, err = c.daddy.settings.PublicIPResolver(c)
if err != nil {
// Not sure if there is better desired behavior than this.
// If we can't resolve the public ip to return to the client, is there any actual
// fallback that is better than erroring.
panic(err)
}
} else {
ip = strings.Split(c.conn.LocalAddr().String(), ":")[0]
}
}

quads := strings.Split(ip, ".")
Expand Down

0 comments on commit 976aca6

Please sign in to comment.