Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module github.com/projectdiscovery/simplehttpserver
go 1.15

require (
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2
github.com/projectdiscovery/gologger v1.1.4
gopkg.in/yaml.v2 v2.4.0
)
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 h1:JhzVVoYvbOACxoUmOs6V/G4D5nPVUW73rKvXxP4XUJc=
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/projectdiscovery/gologger v1.1.4 h1:qWxGUq7ukHWT849uGPkagPKF3yBPYAsTtMKunQ8O2VI=
Expand Down
21 changes: 21 additions & 0 deletions internal/runner/runner.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package runner

import (
"github.com/projectdiscovery/gologger"
"github.com/projectdiscovery/simplehttpserver/pkg/binder"
"github.com/projectdiscovery/simplehttpserver/pkg/httpserver"
"github.com/projectdiscovery/simplehttpserver/pkg/tcpserver"
)
Expand All @@ -14,6 +16,16 @@ type Runner struct {

func New(options *Options) (*Runner, error) {
r := Runner{options: options}
// Check if the process can listen on the specified ip:port
if !binder.CanListenOn(r.options.ListenAddress) {
newListenAddress, err := binder.GetRandomListenAddress(r.options.ListenAddress)
if err != nil {
return nil, err
}
gologger.Print().Msgf("Can't listen on %s: %s - Using %s\n", r.options.ListenAddress, err, newListenAddress)
r.options.ListenAddress = newListenAddress
}

if r.options.EnableTCP {
serverTCP, err := tcpserver.New(tcpserver.Options{
Listen: r.options.ListenAddress,
Expand Down Expand Up @@ -55,16 +67,25 @@ func New(options *Options) (*Runner, error) {

func (r *Runner) Run() error {
if r.options.EnableTCP {
gologger.Print().Msgf("Serving TCP rule based server on tcp://%s", r.options.ListenAddress)
return r.serverTCP.ListenAndServe()
}

if r.options.HTTPS {
gologger.Print().Msgf("Serving %s on https://%s/...", r.options.Folder, r.options.ListenAddress)
return r.httpServer.ListenAndServeTLS()
}

gologger.Print().Msgf("Serving %s on http://%s/...", r.options.Folder, r.options.ListenAddress)
return r.httpServer.ListenAndServe()
}

func (r *Runner) Close() error {
if r.serverTCP != nil {
r.serverTCP.Close()
}
if r.httpServer != nil {
r.httpServer.Close()
}
return nil
}
32 changes: 32 additions & 0 deletions pkg/binder/binder.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package binder

import (
"fmt"
"net"

"github.com/phayes/freeport"
)

func CanListenOn(address string) bool {
listener, err := net.Listen("tcp4", address)
if err != nil {
return false
}
defer listener.Close()
return true
}

func GetRandomListenAddress(currentAddress string) (string, error) {
addrOrig, _, err := net.SplitHostPort(currentAddress)
if err != nil {
return "", err
}

newPort, err := freeport.GetFreePort()
if err != nil {
return "", err
}

return net.JoinHostPort(addrOrig, fmt.Sprintf("%d", newPort)), nil

}
60 changes: 3 additions & 57 deletions pkg/httpserver/httpserver.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,9 @@
package httpserver

import (
"errors"
"net"
"net/http"
"os"
"runtime"
"strconv"
"syscall"

"github.com/projectdiscovery/gologger"
"github.com/projectdiscovery/simplehttpserver/pkg/sslcert"
)

Expand Down Expand Up @@ -46,26 +40,10 @@ func New(options *Options) (*HTTPServer, error) {
}

func (t *HTTPServer) ListenAndServe() error {
var err error
retry_listen:
gologger.Print().Msgf("Serving %s on http://%s/...", t.options.Folder, t.options.ListenAddress)
err = http.ListenAndServe(t.options.ListenAddress, t.layers)
if err != nil {
if isErrorAddressAlreadyInUse(err) {
gologger.Print().Msgf("Can't listen on %s: %s - retrying with another port\n", t.options.ListenAddress, err)
newListenAddress, err := incPort(t.options.ListenAddress)
if err != nil {
return err
}
t.options.ListenAddress = newListenAddress
goto retry_listen
}
}
return nil
return http.ListenAndServe(t.options.ListenAddress, t.layers)
}

func (t *HTTPServer) ListenAndServeTLS() error {
gologger.Print().Msgf("Serving %s on https://%s/...", t.options.Folder, t.options.ListenAddress)
if t.options.Certificate == "" || t.options.CertificateKey == "" {
tlsOptions := sslcert.DefaultOptions
tlsOptions.Host = t.options.CertificateDomain
Expand All @@ -83,38 +61,6 @@ func (t *HTTPServer) ListenAndServeTLS() error {
return http.ListenAndServeTLS(t.options.ListenAddress, t.options.Certificate, t.options.CertificateKey, t.layers)
}

func isErrorAddressAlreadyInUse(err error) bool {
var eOsSyscall *os.SyscallError
if !errors.As(err, &eOsSyscall) {
return false
}
var errErrno syscall.Errno // doesn't need a "*" (ptr) because it's already a ptr (uintptr)
if !errors.As(eOsSyscall, &errErrno) {
return false
}
if errErrno == syscall.EADDRINUSE {
return true
}
const WSAEADDRINUSE = 10048
if runtime.GOOS == "windows" && errErrno == WSAEADDRINUSE {
return true
}
return false
}

func incPort(address string) (string, error) {
addrOrig, portOrig, err := net.SplitHostPort(address)
if err != nil {
return address, err
}

// increment port
portNumber, err := strconv.Atoi(portOrig)
if err != nil {
return address, err
}
portNumber++
newPort := strconv.FormatInt(int64(portNumber), 10)

return net.JoinHostPort(addrOrig, newPort), nil
func (t *HTTPServer) Close() error {
return nil
}
1 change: 0 additions & 1 deletion pkg/tcpserver/tcpserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ func (t *TCPServer) AddRule(rule Rule) error {
}

func (t *TCPServer) ListenAndServe() error {
gologger.Print().Msgf("Serving %s on tcp://%s", t.options.Listen)
listener, err := net.Listen("tcp4", t.options.Listen)
if err != nil {
return err
Expand Down