@@ -2,45 +2,58 @@ package main
22
33import (
44 "bytes"
5+ "errors"
56 "flag"
67 "fmt"
78 "io/ioutil"
8- "log "
9+ "net "
910 "net/http"
1011 "net/http/httputil"
12+ "os"
1113 "path"
14+ "runtime"
15+ "strconv"
16+ "strings"
17+ "syscall"
1218
1319 "github.com/projectdiscovery/gologger"
1420 "github.com/projectdiscovery/simplehttpserver/pkg/sslcert"
21+ "github.com/projectdiscovery/simplehttpserver/pkg/tcpserver"
1522)
1623
1724type options struct {
1825 ListenAddress string
1926 Folder string
20- Username string
21- Password string
27+ BasicAuth string
28+ username string
29+ password string
2230 Realm string
2331 Certificate string
2432 Key string
2533 Domain string
2634 HTTPS bool
2735 Verbose bool
2836 Upload bool
37+ TCP bool
38+ RulesFile string
39+ TLS bool
2940}
3041
3142var opts options
3243
3344func main () {
3445 flag .StringVar (& opts .ListenAddress , "listen" , "0.0.0.0:8000" , "Address:Port" )
46+ flag .BoolVar (& opts .TCP , "tcp" , false , "TCP Server" )
47+ flag .BoolVar (& opts .TLS , "tls" , false , "Enable TCP TLS" )
48+ flag .StringVar (& opts .RulesFile , "rules" , "" , "Rules yaml file" )
3549 flag .StringVar (& opts .Folder , "path" , "." , "Folder" )
3650 flag .BoolVar (& opts .Upload , "upload" , false , "Enable upload via PUT" )
3751 flag .BoolVar (& opts .HTTPS , "https" , false , "HTTPS" )
3852 flag .StringVar (& opts .Certificate , "cert" , "" , "Certificate" )
3953 flag .StringVar (& opts .Key , "key" , "" , "Key" )
4054 flag .StringVar (& opts .Domain , "domain" , "local.host" , "Domain" )
4155 flag .BoolVar (& opts .Verbose , "v" , false , "Verbose" )
42- flag .StringVar (& opts .Username , "username" , "" , "Basic auth username" )
43- flag .StringVar (& opts .Password , "password" , "" , "Basic auth password" )
56+ flag .StringVar (& opts .BasicAuth , "basic-auth" , "" , "Basic auth (username:password)" )
4457 flag .StringVar (& opts .Realm , "realm" , "Please enter username and password" , "Realm" )
4558
4659 flag .Parse ()
@@ -49,15 +62,37 @@ func main() {
4962 opts .Folder = flag .Args ()[0 ]
5063 }
5164
65+ if opts .TCP {
66+ serverTCP , err := tcpserver .New (tcpserver.Options {Listen : opts .ListenAddress , TLS : opts .TLS , Domain : "local.host" })
67+ if err != nil {
68+ gologger .Fatal ().Msgf ("%s\n " , err )
69+ }
70+ err = serverTCP .LoadTemplate (opts .RulesFile )
71+ if err != nil {
72+ gologger .Fatal ().Msgf ("%s\n " , err )
73+ }
74+
75+ gologger .Print ().Msgf ("%s\n " , serverTCP .ListenAndServe ())
76+ }
77+
5278 gologger .Print ().Msgf ("Serving %s on http://%s/..." , opts .Folder , opts .ListenAddress )
5379 layers := loglayer (http .FileServer (http .Dir (opts .Folder )))
54- if opts .Username != "" || opts .Password != "" {
80+ if opts .BasicAuth != "" {
81+ baTokens := strings .SplitN (opts .BasicAuth , ":" , 2 )
82+ if len (baTokens ) > 0 {
83+ opts .username = baTokens [0 ]
84+ }
85+ if len (baTokens ) > 1 {
86+ opts .password = baTokens [1 ]
87+ }
5588 layers = loglayer (basicauthlayer (http .FileServer (http .Dir (opts .Folder ))))
5689 }
57-
5890 if opts .Upload {
59- gologger .Print ().Msgf ( " Upload enabled" )
91+ gologger .Print ().Msg ( "Starting service with Upload enabled" )
6092 }
93+ retry_listen:
94+ gologger .Print ().Msgf ("Serving %s on http://%s/..." , opts .Folder , opts .ListenAddress )
95+ var err error
6196 if opts .HTTPS {
6297 if opts .Certificate == "" || opts .Key == "" {
6398 tlsOptions := sslcert .DefaultOptions
@@ -76,7 +111,19 @@ func main() {
76111 gologger .Print ().Msgf ("%s\n " , http .ListenAndServeTLS (opts .ListenAddress , opts .Certificate , opts .Key , layers ))
77112 }
78113 } else {
79- gologger .Print ().Msgf ("%s\n " , http .ListenAndServe (opts .ListenAddress , layers ))
114+ err = http .ListenAndServe (opts .ListenAddress , layers )
115+ }
116+ if err != nil {
117+ if isErrorAddressAlreadyInUse (err ) {
118+ gologger .Print ().Msgf ("Can't listen on %s: %s - retrying with another port\n " , opts .ListenAddress , err )
119+ newListenAddress , err := incPort (opts .ListenAddress )
120+ if err != nil {
121+ gologger .Fatal ().Msgf ("%s\n " , err )
122+ }
123+ opts .ListenAddress = newListenAddress
124+ goto retry_listen
125+ }
126+ gologger .Print ().Msgf ("%s\n " , err )
80127 }
81128}
82129
@@ -90,11 +137,11 @@ func loglayer(handler http.Handler) http.Handler {
90137 if opts .Upload && r .Method == http .MethodPut {
91138 data , err := ioutil .ReadAll (r .Body )
92139 if err != nil {
93- log . Println ( err )
140+ gologger . Print (). Msgf ( "%s \n " , err )
94141 }
95142 err = handleUpload (path .Base (r .URL .Path ), data )
96143 if err != nil {
97- log . Println ( err )
144+ gologger . Print (). Msgf ( "%s \n " , err )
98145 }
99146 }
100147
@@ -111,7 +158,7 @@ func loglayer(handler http.Handler) http.Handler {
111158func basicauthlayer (handler http.Handler ) http.HandlerFunc {
112159 return http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
113160 user , pass , ok := r .BasicAuth ()
114- if ! ok || user != opts .Username || pass != opts .Password {
161+ if ! ok || user != opts .username || pass != opts .password {
115162 w .Header ().Set ("WWW-Authenticate" , fmt .Sprintf ("Basic realm=\" %s\" " , opts .Realm ))
116163 w .WriteHeader (http .StatusUnauthorized )
117164 w .Write ([]byte ("Unauthorized.\n " )) //nolint
@@ -148,3 +195,39 @@ func (lrw *loggingResponseWriter) WriteHeader(code int) {
148195func handleUpload (file string , data []byte ) error {
149196 return ioutil .WriteFile (file , data , 0655 )
150197}
198+
199+ func isErrorAddressAlreadyInUse (err error ) bool {
200+ var eOsSyscall * os.SyscallError
201+ if ! errors .As (err , & eOsSyscall ) {
202+ return false
203+ }
204+ var errErrno syscall.Errno // doesn't need a "*" (ptr) because it's already a ptr (uintptr)
205+ if ! errors .As (eOsSyscall , & errErrno ) {
206+ return false
207+ }
208+ if errErrno == syscall .EADDRINUSE {
209+ return true
210+ }
211+ const WSAEADDRINUSE = 10048
212+ if runtime .GOOS == "windows" && errErrno == WSAEADDRINUSE {
213+ return true
214+ }
215+ return false
216+ }
217+
218+ func incPort (address string ) (string , error ) {
219+ addrOrig , portOrig , err := net .SplitHostPort (address )
220+ if err != nil {
221+ return address , err
222+ }
223+
224+ // increment port
225+ portNumber , err := strconv .Atoi (portOrig )
226+ if err != nil {
227+ return address , err
228+ }
229+ portNumber ++
230+ newPort := strconv .FormatInt (int64 (portNumber ), 10 )
231+
232+ return net .JoinHostPort (addrOrig , newPort ), nil
233+ }
0 commit comments