Skip to content

Commit 7a0364f

Browse files
authored
Merge pull request #21 from projectdiscovery/maintenance-freeport-bind
bind logic refactor
2 parents 3ae260a + 254d461 commit 7a0364f

File tree

6 files changed

+59
-58
lines changed

6 files changed

+59
-58
lines changed

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ module github.com/projectdiscovery/simplehttpserver
33
go 1.15
44

55
require (
6+
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2
67
github.com/projectdiscovery/gologger v1.1.4
78
gopkg.in/yaml.v2 v2.4.0
89
)

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ
1919
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
2020
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
2121
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
22+
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 h1:JhzVVoYvbOACxoUmOs6V/G4D5nPVUW73rKvXxP4XUJc=
23+
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
2224
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
2325
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
2426
github.com/projectdiscovery/gologger v1.1.4 h1:qWxGUq7ukHWT849uGPkagPKF3yBPYAsTtMKunQ8O2VI=

internal/runner/runner.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package runner
22

33
import (
4+
"github.com/projectdiscovery/gologger"
5+
"github.com/projectdiscovery/simplehttpserver/pkg/binder"
46
"github.com/projectdiscovery/simplehttpserver/pkg/httpserver"
57
"github.com/projectdiscovery/simplehttpserver/pkg/tcpserver"
68
)
@@ -14,6 +16,16 @@ type Runner struct {
1416

1517
func New(options *Options) (*Runner, error) {
1618
r := Runner{options: options}
19+
// Check if the process can listen on the specified ip:port
20+
if !binder.CanListenOn(r.options.ListenAddress) {
21+
newListenAddress, err := binder.GetRandomListenAddress(r.options.ListenAddress)
22+
if err != nil {
23+
return nil, err
24+
}
25+
gologger.Print().Msgf("Can't listen on %s: %s - Using %s\n", r.options.ListenAddress, err, newListenAddress)
26+
r.options.ListenAddress = newListenAddress
27+
}
28+
1729
if r.options.EnableTCP {
1830
serverTCP, err := tcpserver.New(tcpserver.Options{
1931
Listen: r.options.ListenAddress,
@@ -55,16 +67,25 @@ func New(options *Options) (*Runner, error) {
5567

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

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

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

6883
func (r *Runner) Close() error {
84+
if r.serverTCP != nil {
85+
r.serverTCP.Close()
86+
}
87+
if r.httpServer != nil {
88+
r.httpServer.Close()
89+
}
6990
return nil
7091
}

pkg/binder/binder.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package binder
2+
3+
import (
4+
"fmt"
5+
"net"
6+
7+
"github.com/phayes/freeport"
8+
)
9+
10+
func CanListenOn(address string) bool {
11+
listener, err := net.Listen("tcp4", address)
12+
if err != nil {
13+
return false
14+
}
15+
defer listener.Close()
16+
return true
17+
}
18+
19+
func GetRandomListenAddress(currentAddress string) (string, error) {
20+
addrOrig, _, err := net.SplitHostPort(currentAddress)
21+
if err != nil {
22+
return "", err
23+
}
24+
25+
newPort, err := freeport.GetFreePort()
26+
if err != nil {
27+
return "", err
28+
}
29+
30+
return net.JoinHostPort(addrOrig, fmt.Sprintf("%d", newPort)), nil
31+
32+
}

pkg/httpserver/httpserver.go

Lines changed: 3 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,9 @@
11
package httpserver
22

33
import (
4-
"errors"
54
"net"
65
"net/http"
7-
"os"
8-
"runtime"
9-
"strconv"
10-
"syscall"
116

12-
"github.com/projectdiscovery/gologger"
137
"github.com/projectdiscovery/simplehttpserver/pkg/sslcert"
148
)
159

@@ -46,26 +40,10 @@ func New(options *Options) (*HTTPServer, error) {
4640
}
4741

4842
func (t *HTTPServer) ListenAndServe() error {
49-
var err error
50-
retry_listen:
51-
gologger.Print().Msgf("Serving %s on http://%s/...", t.options.Folder, t.options.ListenAddress)
52-
err = http.ListenAndServe(t.options.ListenAddress, t.layers)
53-
if err != nil {
54-
if isErrorAddressAlreadyInUse(err) {
55-
gologger.Print().Msgf("Can't listen on %s: %s - retrying with another port\n", t.options.ListenAddress, err)
56-
newListenAddress, err := incPort(t.options.ListenAddress)
57-
if err != nil {
58-
return err
59-
}
60-
t.options.ListenAddress = newListenAddress
61-
goto retry_listen
62-
}
63-
}
64-
return nil
43+
return http.ListenAndServe(t.options.ListenAddress, t.layers)
6544
}
6645

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

86-
func isErrorAddressAlreadyInUse(err error) bool {
87-
var eOsSyscall *os.SyscallError
88-
if !errors.As(err, &eOsSyscall) {
89-
return false
90-
}
91-
var errErrno syscall.Errno // doesn't need a "*" (ptr) because it's already a ptr (uintptr)
92-
if !errors.As(eOsSyscall, &errErrno) {
93-
return false
94-
}
95-
if errErrno == syscall.EADDRINUSE {
96-
return true
97-
}
98-
const WSAEADDRINUSE = 10048
99-
if runtime.GOOS == "windows" && errErrno == WSAEADDRINUSE {
100-
return true
101-
}
102-
return false
103-
}
104-
105-
func incPort(address string) (string, error) {
106-
addrOrig, portOrig, err := net.SplitHostPort(address)
107-
if err != nil {
108-
return address, err
109-
}
110-
111-
// increment port
112-
portNumber, err := strconv.Atoi(portOrig)
113-
if err != nil {
114-
return address, err
115-
}
116-
portNumber++
117-
newPort := strconv.FormatInt(int64(portNumber), 10)
118-
119-
return net.JoinHostPort(addrOrig, newPort), nil
64+
func (t *HTTPServer) Close() error {
65+
return nil
12066
}

pkg/tcpserver/tcpserver.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ func (t *TCPServer) AddRule(rule Rule) error {
3636
}
3737

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

0 commit comments

Comments
 (0)