From 52aa568c4810636152595f781e8ba4a35edb7e15 Mon Sep 17 00:00:00 2001
From: Mzack9999
Date: Mon, 15 Feb 2021 20:17:23 +0100
Subject: [PATCH 01/45] adding http basic auth
---
simplehttpserver.go | 26 +++++++++++++++++++++++++-
1 file changed, 25 insertions(+), 1 deletion(-)
diff --git a/simplehttpserver.go b/simplehttpserver.go
index 2e7ad19..86cd06f 100644
--- a/simplehttpserver.go
+++ b/simplehttpserver.go
@@ -12,6 +12,9 @@ import (
type options struct {
ListenAddress string
Folder string
+ Username string
+ Password string
+ Realm string
Verbose bool
}
@@ -21,6 +24,9 @@ func main() {
flag.StringVar(&opts.ListenAddress, "listen", "0.0.0.0:8000", "Address:Port")
flag.StringVar(&opts.Folder, "path", ".", "Folder")
flag.BoolVar(&opts.Verbose, "v", false, "Verbose")
+ flag.StringVar(&opts.Username, "username", "", "Basic auth username")
+ flag.StringVar(&opts.Password, "password", "", "Basic auth password")
+ flag.StringVar(&opts.Realm, "realm", "Please enter username and password", "Realm")
flag.Parse()
if flag.NArg() > 0 && opts.Folder == "." {
@@ -28,7 +34,12 @@ func main() {
}
log.Printf("Serving %s on http://%s/...", opts.Folder, opts.ListenAddress)
- fmt.Println(http.ListenAndServe(opts.ListenAddress, loglayer(http.FileServer(http.Dir(opts.Folder)))))
+ layers := loglayer(http.FileServer(http.Dir(opts.Folder)))
+ if opts.Username != "" || opts.Password != "" {
+ layers = loglayer(basicauthlayer(http.FileServer(http.Dir(opts.Folder))))
+ }
+
+ fmt.Println(http.ListenAndServe(opts.ListenAddress, layers))
}
func loglayer(handler http.Handler) http.Handler {
@@ -47,6 +58,19 @@ func loglayer(handler http.Handler) http.Handler {
})
}
+func basicauthlayer(handler http.Handler) http.HandlerFunc {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ user, pass, ok := r.BasicAuth()
+ if !ok || user != opts.Username || pass != opts.Password {
+ w.Header().Set("WWW-Authenticate", fmt.Sprintf("Basic realm=\"%s\"", opts.Realm))
+ w.WriteHeader(401)
+ w.Write([]byte("Unauthorized.\n"))
+ return
+ }
+ handler.ServeHTTP(w, r)
+ })
+}
+
type loggingResponseWriter struct {
http.ResponseWriter
statusCode int
From 8ad8b6e6efc9dcdb2ac541741531abfdf252f329 Mon Sep 17 00:00:00 2001
From: Mzack9999
Date: Mon, 15 Feb 2021 20:56:48 +0100
Subject: [PATCH 02/45] adding file upload support
---
simplehttpserver.go | 24 ++++++++++++++++++++++++
1 file changed, 24 insertions(+)
diff --git a/simplehttpserver.go b/simplehttpserver.go
index 2e7ad19..1bbb135 100644
--- a/simplehttpserver.go
+++ b/simplehttpserver.go
@@ -4,15 +4,18 @@ import (
"bytes"
"flag"
"fmt"
+ "io/ioutil"
"log"
"net/http"
"net/http/httputil"
+ "path"
)
type options struct {
ListenAddress string
Folder string
Verbose bool
+ Upload bool
}
var opts options
@@ -20,7 +23,9 @@ var opts options
func main() {
flag.StringVar(&opts.ListenAddress, "listen", "0.0.0.0:8000", "Address:Port")
flag.StringVar(&opts.Folder, "path", ".", "Folder")
+ flag.BoolVar(&opts.Upload, "upload", false, "Enable upload via PUT")
flag.BoolVar(&opts.Verbose, "v", false, "Verbose")
+
flag.Parse()
if flag.NArg() > 0 && opts.Folder == "." {
@@ -28,6 +33,9 @@ func main() {
}
log.Printf("Serving %s on http://%s/...", opts.Folder, opts.ListenAddress)
+ if opts.Upload {
+ log.Println("Upload enabled")
+ }
fmt.Println(http.ListenAndServe(opts.ListenAddress, loglayer(http.FileServer(http.Dir(opts.Folder)))))
}
@@ -37,6 +45,18 @@ func loglayer(handler http.Handler) http.Handler {
lrw := newLoggingResponseWriter(w)
handler.ServeHTTP(lrw, r)
+ // Handles file write if enabled
+ if opts.Upload && r.Method == http.MethodPut {
+ data, err := ioutil.ReadAll(r.Body)
+ if err != nil {
+ log.Println(err)
+ }
+ err = handleUpload(path.Base(r.URL.Path), data)
+ if err != nil {
+ log.Println(err)
+ }
+ }
+
if opts.Verbose {
headers := new(bytes.Buffer)
lrw.Header().Write(headers) //nolint
@@ -70,3 +90,7 @@ func (lrw *loggingResponseWriter) WriteHeader(code int) {
lrw.statusCode = code
lrw.ResponseWriter.WriteHeader(code)
}
+
+func handleUpload(file string, data []byte) error {
+ return ioutil.WriteFile(file, data, 0655)
+}
From 6b4eb1c947d95a706fcb2ec58efe32ca790a65ad Mon Sep 17 00:00:00 2001
From: Mzack9999
Date: Mon, 15 Feb 2021 21:11:58 +0100
Subject: [PATCH 03/45] adding https support
---
simplehttpserver.go | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/simplehttpserver.go b/simplehttpserver.go
index 2e7ad19..1aa7c54 100644
--- a/simplehttpserver.go
+++ b/simplehttpserver.go
@@ -12,6 +12,9 @@ import (
type options struct {
ListenAddress string
Folder string
+ Certificate string
+ Key string
+ HTTPS bool
Verbose bool
}
@@ -20,6 +23,9 @@ var opts options
func main() {
flag.StringVar(&opts.ListenAddress, "listen", "0.0.0.0:8000", "Address:Port")
flag.StringVar(&opts.Folder, "path", ".", "Folder")
+ flag.BoolVar(&opts.HTTPS, "https", false, "HTTPS")
+ flag.StringVar(&opts.Certificate, "cert", "", "Certificate")
+ flag.StringVar(&opts.Key, "key", "", "Key")
flag.BoolVar(&opts.Verbose, "v", false, "Verbose")
flag.Parse()
@@ -28,7 +34,14 @@ func main() {
}
log.Printf("Serving %s on http://%s/...", opts.Folder, opts.ListenAddress)
- fmt.Println(http.ListenAndServe(opts.ListenAddress, loglayer(http.FileServer(http.Dir(opts.Folder)))))
+ if opts.HTTPS {
+ if opts.Certificate == "" || opts.Key == "" {
+ log.Fatal("Certificate or Key file not specified")
+ }
+ fmt.Println(http.ListenAndServeTLS(opts.ListenAddress, opts.Certificate, opts.Key, loglayer(http.FileServer(http.Dir(opts.Folder)))))
+ } else {
+ fmt.Println(http.ListenAndServe(opts.ListenAddress, loglayer(http.FileServer(http.Dir(opts.Folder)))))
+ }
}
func loglayer(handler http.Handler) http.Handler {
From 8890cbf2942ecc8cdc73233e4440cc679faefe96 Mon Sep 17 00:00:00 2001
From: Mzack9999
Date: Mon, 15 Feb 2021 21:12:12 +0100
Subject: [PATCH 04/45] cert generation helper
---
gen_cert.sh | 5 +++++
1 file changed, 5 insertions(+)
create mode 100644 gen_cert.sh
diff --git a/gen_cert.sh b/gen_cert.sh
new file mode 100644
index 0000000..0cba96a
--- /dev/null
+++ b/gen_cert.sh
@@ -0,0 +1,5 @@
+#!/usr/bin/env bash
+
+openssl genrsa -out server.key 2048
+openssl ecparam -genkey -name secp384r1 -out server.key
+openssl req -new -x509 -sha256 -key server.key -out server.crt -days 3650
\ No newline at end of file
From 0fc0dea2669949c069f5c5678849f3a0fb686f6e Mon Sep 17 00:00:00 2001
From: sandeep <8293321+bauthard@users.noreply.github.com>
Date: Tue, 16 Feb 2021 01:53:09 +0530
Subject: [PATCH 05/45] Update build.yaml
---
.github/workflows/build.yaml | 13 ++-----------
1 file changed, 2 insertions(+), 11 deletions(-)
diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml
index a157f84..008bca6 100644
--- a/.github/workflows/build.yaml
+++ b/.github/workflows/build.yaml
@@ -6,27 +6,18 @@ on:
pull_request:
jobs:
- lint:
- name: golangci-lint
+ golangci-lint:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Run golangci-lint
- uses: golangci/golangci-lint-action@v2.2.0
+ uses: golangci/golangci-lint-action@v2.4.0
with:
# Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version.
version: v1.31
args: --timeout 5m
- # Optional: working directory, useful for monorepos
- # working-directory: somedir
-
- # Optional: golangci-lint command line arguments.
- # args: --issues-exit-code=0
-
- # Optional: show only new issues if it's a pull request. The default value is `false`.
- # only-new-issues: true
build:
name: Build
runs-on: ubuntu-latest
From ae48cc600f4eb883a6fad3de2f3bd98edaba857f Mon Sep 17 00:00:00 2001
From: sandeep <8293321+bauthard@users.noreply.github.com>
Date: Tue, 16 Feb 2021 01:53:09 +0530
Subject: [PATCH 06/45] Update build.yaml
---
.github/workflows/build.yaml | 13 ++-----------
1 file changed, 2 insertions(+), 11 deletions(-)
diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml
index a157f84..008bca6 100644
--- a/.github/workflows/build.yaml
+++ b/.github/workflows/build.yaml
@@ -6,27 +6,18 @@ on:
pull_request:
jobs:
- lint:
- name: golangci-lint
+ golangci-lint:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Run golangci-lint
- uses: golangci/golangci-lint-action@v2.2.0
+ uses: golangci/golangci-lint-action@v2.4.0
with:
# Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version.
version: v1.31
args: --timeout 5m
- # Optional: working directory, useful for monorepos
- # working-directory: somedir
-
- # Optional: golangci-lint command line arguments.
- # args: --issues-exit-code=0
-
- # Optional: show only new issues if it's a pull request. The default value is `false`.
- # only-new-issues: true
build:
name: Build
runs-on: ubuntu-latest
From 8c1cc031b82f6459765779a17bbe6a47ac3393fe Mon Sep 17 00:00:00 2001
From: sandeep <8293321+bauthard@users.noreply.github.com>
Date: Tue, 16 Feb 2021 01:53:09 +0530
Subject: [PATCH 07/45] Update build.yaml
---
.github/workflows/build.yaml | 13 ++-----------
1 file changed, 2 insertions(+), 11 deletions(-)
diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml
index a157f84..008bca6 100644
--- a/.github/workflows/build.yaml
+++ b/.github/workflows/build.yaml
@@ -6,27 +6,18 @@ on:
pull_request:
jobs:
- lint:
- name: golangci-lint
+ golangci-lint:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Run golangci-lint
- uses: golangci/golangci-lint-action@v2.2.0
+ uses: golangci/golangci-lint-action@v2.4.0
with:
# Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version.
version: v1.31
args: --timeout 5m
- # Optional: working directory, useful for monorepos
- # working-directory: somedir
-
- # Optional: golangci-lint command line arguments.
- # args: --issues-exit-code=0
-
- # Optional: show only new issues if it's a pull request. The default value is `false`.
- # only-new-issues: true
build:
name: Build
runs-on: ubuntu-latest
From b71f31edcf32618c0963f8f955cfd0901d538706 Mon Sep 17 00:00:00 2001
From: sandeep <8293321+bauthard@users.noreply.github.com>
Date: Tue, 16 Feb 2021 01:53:09 +0530
Subject: [PATCH 08/45] Update build.yaml
---
.github/workflows/build.yaml | 13 ++-----------
1 file changed, 2 insertions(+), 11 deletions(-)
diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml
index a157f84..008bca6 100644
--- a/.github/workflows/build.yaml
+++ b/.github/workflows/build.yaml
@@ -6,27 +6,18 @@ on:
pull_request:
jobs:
- lint:
- name: golangci-lint
+ golangci-lint:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Run golangci-lint
- uses: golangci/golangci-lint-action@v2.2.0
+ uses: golangci/golangci-lint-action@v2.4.0
with:
# Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version.
version: v1.31
args: --timeout 5m
- # Optional: working directory, useful for monorepos
- # working-directory: somedir
-
- # Optional: golangci-lint command line arguments.
- # args: --issues-exit-code=0
-
- # Optional: show only new issues if it's a pull request. The default value is `false`.
- # only-new-issues: true
build:
name: Build
runs-on: ubuntu-latest
From ed7e2ee2d2e987c8e173ed38914908913c4c0abe Mon Sep 17 00:00:00 2001
From: Mzack9999
Date: Mon, 15 Feb 2021 21:54:25 +0100
Subject: [PATCH 09/45] linting fix
---
simplehttpserver.go | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/simplehttpserver.go b/simplehttpserver.go
index 86cd06f..b7ff509 100644
--- a/simplehttpserver.go
+++ b/simplehttpserver.go
@@ -63,8 +63,8 @@ func basicauthlayer(handler http.Handler) http.HandlerFunc {
user, pass, ok := r.BasicAuth()
if !ok || user != opts.Username || pass != opts.Password {
w.Header().Set("WWW-Authenticate", fmt.Sprintf("Basic realm=\"%s\"", opts.Realm))
- w.WriteHeader(401)
- w.Write([]byte("Unauthorized.\n"))
+ w.WriteHeader(http.StatusUnauthorized)
+ w.Write([]byte("Unauthorized.\n")) //nolint
return
}
handler.ServeHTTP(w, r)
From 752b822207e2648c22ade4ccf2a4ebf02d26dd7f Mon Sep 17 00:00:00 2001
From: Mzack9999
Date: Wed, 17 Feb 2021 15:47:10 +0100
Subject: [PATCH 10/45] adding dep bot
---
.github/dependabot.yml | 34 ++++++++++++++++++++++++++++++++++
1 file changed, 34 insertions(+)
create mode 100644 .github/dependabot.yml
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000..4d5617f
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,34 @@
+# To get started with Dependabot version updates, you'll need to specify which
+# package ecosystems to update and where the package manifests are located.
+# Please see the documentation for all configuration options:
+# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
+
+version: 2
+updates:
+
+ # Maintain dependencies for GitHub Actions
+ - package-ecosystem: "github-actions"
+ directory: "/"
+ schedule:
+ interval: "weekly"
+ commit-message:
+ prefix: "chore"
+ include: "scope"
+
+ # Maintain dependencies for go modules
+ - package-ecosystem: "gomod"
+ directory: "/"
+ schedule:
+ interval: "weekly"
+ commit-message:
+ prefix: "chore"
+ include: "scope"
+
+ # Maintain dependencies for docker
+ - package-ecosystem: "docker"
+ directory: "/"
+ schedule:
+ interval: "weekly"
+ commit-message:
+ prefix: "chore"
+ include: "scope"
From 526bfd99472cf9dbcda081024b2f4ad5aa7c5ea2 Mon Sep 17 00:00:00 2001
From: Mzack9999
Date: Fri, 19 Feb 2021 20:59:30 +0100
Subject: [PATCH 11/45] refactoring basic auth option
---
simplehttpserver.go | 20 ++++++++++++++------
1 file changed, 14 insertions(+), 6 deletions(-)
diff --git a/simplehttpserver.go b/simplehttpserver.go
index e181945..d0314ad 100644
--- a/simplehttpserver.go
+++ b/simplehttpserver.go
@@ -9,13 +9,15 @@ import (
"net/http"
"net/http/httputil"
"path"
+ "strings"
)
type options struct {
ListenAddress string
Folder string
- Username string
- Password string
+ BasicAuth string
+ username string
+ password string
Realm string
Certificate string
Key string
@@ -34,8 +36,7 @@ func main() {
flag.StringVar(&opts.Certificate, "cert", "", "Certificate")
flag.StringVar(&opts.Key, "key", "", "Key")
flag.BoolVar(&opts.Verbose, "v", false, "Verbose")
- flag.StringVar(&opts.Username, "username", "", "Basic auth username")
- flag.StringVar(&opts.Password, "password", "", "Basic auth password")
+ flag.StringVar(&opts.BasicAuth, "basic-auth", "", "Basic auth (username:password)")
flag.StringVar(&opts.Realm, "realm", "Please enter username and password", "Realm")
flag.Parse()
@@ -46,7 +47,14 @@ func main() {
log.Printf("Serving %s on http://%s/...", opts.Folder, opts.ListenAddress)
layers := loglayer(http.FileServer(http.Dir(opts.Folder)))
- if opts.Username != "" || opts.Password != "" {
+ if opts.BasicAuth != "" {
+ baTokens := strings.SplitN(opts.BasicAuth, ":", 1)
+ if len(baTokens) > 0 {
+ opts.username = baTokens[0]
+ }
+ if len(baTokens) > 1 {
+ opts.password = baTokens[1]
+ }
layers = loglayer(basicauthlayer(http.FileServer(http.Dir(opts.Folder))))
}
@@ -94,7 +102,7 @@ func loglayer(handler http.Handler) http.Handler {
func basicauthlayer(handler http.Handler) http.HandlerFunc {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
user, pass, ok := r.BasicAuth()
- if !ok || user != opts.Username || pass != opts.Password {
+ if !ok || user != opts.username || pass != opts.password {
w.Header().Set("WWW-Authenticate", fmt.Sprintf("Basic realm=\"%s\"", opts.Realm))
w.WriteHeader(http.StatusUnauthorized)
w.Write([]byte("Unauthorized.\n")) //nolint
From 1593493b6a65f6ca659dcfa69fc6235fa203f07e Mon Sep 17 00:00:00 2001
From: Mzack9999
Date: Tue, 23 Feb 2021 01:35:25 +0100
Subject: [PATCH 12/45] fixing split amount
---
simplehttpserver.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/simplehttpserver.go b/simplehttpserver.go
index d0314ad..809e52c 100644
--- a/simplehttpserver.go
+++ b/simplehttpserver.go
@@ -48,7 +48,7 @@ func main() {
log.Printf("Serving %s on http://%s/...", opts.Folder, opts.ListenAddress)
layers := loglayer(http.FileServer(http.Dir(opts.Folder)))
if opts.BasicAuth != "" {
- baTokens := strings.SplitN(opts.BasicAuth, ":", 1)
+ baTokens := strings.SplitN(opts.BasicAuth, ":", 2)
if len(baTokens) > 0 {
opts.username = baTokens[0]
}
From 5a1f3a3ca43b46f80348756b8f293ceb30eaeebb Mon Sep 17 00:00:00 2001
From: Mzack9999
Date: Tue, 23 Feb 2021 01:39:21 +0100
Subject: [PATCH 13/45] replacing log with gologger
---
go.mod | 2 ++
go.sum | 35 +++++++++++++++++++++++++++++++++++
simplehttpserver.go | 16 +++++++++-------
3 files changed, 46 insertions(+), 7 deletions(-)
create mode 100644 go.sum
diff --git a/go.mod b/go.mod
index 1876095..120667d 100644
--- a/go.mod
+++ b/go.mod
@@ -1,3 +1,5 @@
module github.com/projectdiscovery/simplehttpserver
go 1.15
+
+require github.com/projectdiscovery/gologger v1.1.4
diff --git a/go.sum b/go.sum
new file mode 100644
index 0000000..82f8703
--- /dev/null
+++ b/go.sum
@@ -0,0 +1,35 @@
+github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68=
+github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
+github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
+github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8=
+github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
+github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+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/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=
+github.com/projectdiscovery/gologger v1.1.4/go.mod h1:Bhb6Bdx2PV1nMaFLoXNBmHIU85iROS9y1tBuv7T5pMY=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
+gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/simplehttpserver.go b/simplehttpserver.go
index e181945..98475c6 100644
--- a/simplehttpserver.go
+++ b/simplehttpserver.go
@@ -9,6 +9,8 @@ import (
"net/http"
"net/http/httputil"
"path"
+
+ "github.com/projectdiscovery/gologger"
)
type options struct {
@@ -44,22 +46,22 @@ func main() {
opts.Folder = flag.Args()[0]
}
- log.Printf("Serving %s on http://%s/...", opts.Folder, opts.ListenAddress)
+ gologger.Print().Msgf("Serving %s on http://%s/...", opts.Folder, opts.ListenAddress)
layers := loglayer(http.FileServer(http.Dir(opts.Folder)))
if opts.Username != "" || opts.Password != "" {
layers = loglayer(basicauthlayer(http.FileServer(http.Dir(opts.Folder))))
}
if opts.Upload {
- log.Println("Upload enabled")
+ gologger.Print().Msgf("Upload enabled")
}
if opts.HTTPS {
if opts.Certificate == "" || opts.Key == "" {
- log.Fatal("Certificate or Key file not specified")
+ gologger.Fatal().Msgf("Certificate or Key file not specified")
}
- fmt.Println(http.ListenAndServeTLS(opts.ListenAddress, opts.Certificate, opts.Key, layers))
+ gologger.Print().Msgf("%s\n", http.ListenAndServeTLS(opts.ListenAddress, opts.Certificate, opts.Key, layers))
} else {
- fmt.Println(http.ListenAndServe(opts.ListenAddress, layers))
+ gologger.Print().Msgf("%s\n", http.ListenAndServe(opts.ListenAddress, layers))
}
}
@@ -84,9 +86,9 @@ func loglayer(handler http.Handler) http.Handler {
if opts.Verbose {
headers := new(bytes.Buffer)
lrw.Header().Write(headers) //nolint
- log.Printf("\nRemote Address: %s\n%s\n%s %d %s\n%s\n%s\n", r.RemoteAddr, string(fullRequest), r.Proto, lrw.statusCode, http.StatusText(lrw.statusCode), headers.String(), string(lrw.Data))
+ gologger.Print().Msgf("\nRemote Address: %s\n%s\n%s %d %s\n%s\n%s\n", r.RemoteAddr, string(fullRequest), r.Proto, lrw.statusCode, http.StatusText(lrw.statusCode), headers.String(), string(lrw.Data))
} else {
- log.Printf("%s \"%s %s %s\" %d %d", r.RemoteAddr, r.Method, r.URL, r.Proto, lrw.statusCode, len(lrw.Data))
+ gologger.Print().Msgf("%s \"%s %s %s\" %d %d", r.RemoteAddr, r.Method, r.URL, r.Proto, lrw.statusCode, len(lrw.Data))
}
})
}
From 75383752133ebf463f179c45bf97223e49f7ea07 Mon Sep 17 00:00:00 2001
From: Mzack9999
Date: Tue, 23 Feb 2021 01:52:43 +0100
Subject: [PATCH 14/45] adding auto port increment
---
simplehttpserver.go | 62 +++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 60 insertions(+), 2 deletions(-)
diff --git a/simplehttpserver.go b/simplehttpserver.go
index 98475c6..1dbc260 100644
--- a/simplehttpserver.go
+++ b/simplehttpserver.go
@@ -2,13 +2,19 @@ package main
import (
"bytes"
+ "errors"
"flag"
"fmt"
"io/ioutil"
"log"
+ "net"
"net/http"
"net/http/httputil"
+ "os"
"path"
+ "runtime"
+ "strconv"
+ "syscall"
"github.com/projectdiscovery/gologger"
)
@@ -55,13 +61,29 @@ func main() {
if opts.Upload {
gologger.Print().Msgf("Upload enabled")
}
+retry_listen:
+ var err error
if opts.HTTPS {
if opts.Certificate == "" || opts.Key == "" {
gologger.Fatal().Msgf("Certificate or Key file not specified")
}
- gologger.Print().Msgf("%s\n", http.ListenAndServeTLS(opts.ListenAddress, opts.Certificate, opts.Key, layers))
+ err = http.ListenAndServeTLS(opts.ListenAddress, opts.Certificate, opts.Key, layers)
+
} else {
- gologger.Print().Msgf("%s\n", http.ListenAndServe(opts.ListenAddress, layers))
+ err = http.ListenAndServe(opts.ListenAddress, layers)
+ gologger.Print().Msgf("%s\n")
+ }
+ if err != nil {
+ if isErrorAddressAlreadyInUse(err) {
+ gologger.Warning().Msgf("Can't listen on %s: %s - retrying with another port\n", opts.ListenAddress, err)
+ newListenAddress, err := incPort(opts.ListenAddress)
+ if err != nil {
+ gologger.Fatal().Msgf("%s\n", err)
+ }
+ opts.ListenAddress = newListenAddress
+ goto retry_listen
+ }
+ gologger.Warning().Msgf("%s\n", err)
}
}
@@ -133,3 +155,39 @@ func (lrw *loggingResponseWriter) WriteHeader(code int) {
func handleUpload(file string, data []byte) error {
return ioutil.WriteFile(file, data, 0655)
}
+
+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
+}
From 69d59ffa6ddd82886dc92c461f4b9e7686fc897a Mon Sep 17 00:00:00 2001
From: Mzack9999
Date: Tue, 23 Feb 2021 01:55:37 +0100
Subject: [PATCH 15/45] fixing lint errors
---
simplehttpserver.go | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/simplehttpserver.go b/simplehttpserver.go
index 1dbc260..b366ce9 100644
--- a/simplehttpserver.go
+++ b/simplehttpserver.go
@@ -59,19 +59,17 @@ func main() {
}
if opts.Upload {
- gologger.Print().Msgf("Upload enabled")
+ gologger.Print().Msg("Upload enabled")
}
retry_listen:
var err error
if opts.HTTPS {
if opts.Certificate == "" || opts.Key == "" {
- gologger.Fatal().Msgf("Certificate or Key file not specified")
+ gologger.Fatal().Msg("Certificate or Key file not specified")
}
err = http.ListenAndServeTLS(opts.ListenAddress, opts.Certificate, opts.Key, layers)
-
} else {
err = http.ListenAndServe(opts.ListenAddress, layers)
- gologger.Print().Msgf("%s\n")
}
if err != nil {
if isErrorAddressAlreadyInUse(err) {
From bfe28042add32b69c9a6687e351e8468b9caac3f Mon Sep 17 00:00:00 2001
From: Mzack9999
Date: Tue, 23 Feb 2021 02:51:41 +0100
Subject: [PATCH 16/45] adding self certificate generation
---
pkg/sslcert/options.go | 21 ++++++
pkg/sslcert/sslcert.go | 151 +++++++++++++++++++++++++++++++++++++++
pkg/sslcert/tlsconfig.go | 19 +++++
simplehttpserver.go | 19 ++++-
4 files changed, 208 insertions(+), 2 deletions(-)
create mode 100644 pkg/sslcert/options.go
create mode 100644 pkg/sslcert/sslcert.go
create mode 100644 pkg/sslcert/tlsconfig.go
diff --git a/pkg/sslcert/options.go b/pkg/sslcert/options.go
new file mode 100644
index 0000000..54cbc0d
--- /dev/null
+++ b/pkg/sslcert/options.go
@@ -0,0 +1,21 @@
+package sslcert
+
+import "time"
+
+type Options struct {
+ Host string // Comma-separated hostnames and IPs to generate a certificate for")
+ Organization string
+ ValidFrom string // Creation date formatted as Jan 1 15:04:05 2011
+ ValidFor time.Duration // 365*24*time.Hour Duration that certificate is valid for
+ IsCA bool // whether this cert should be its own Certificate Authority
+ RSABits int // 2048 Size of RSA key to generate. Ignored if --ecdsa-curve is set
+ EcdsaCurve string // ECDSA curve to use to generate a key. Valid values are P224, P256 (recommended), P384, P521
+ Ed25519Key bool // Generate an Ed25519 key
+}
+
+var DefaultOptions = Options{
+ ValidFor: time.Duration(365 * 24 * time.Hour),
+ IsCA: false,
+ RSABits: 2048,
+ Organization: "Acme Co",
+}
diff --git a/pkg/sslcert/sslcert.go b/pkg/sslcert/sslcert.go
new file mode 100644
index 0000000..6469b78
--- /dev/null
+++ b/pkg/sslcert/sslcert.go
@@ -0,0 +1,151 @@
+// Package sslcert contains a reworked version of https://golang.org/src/crypto/tls/generate_cert.go
+package sslcert
+
+import (
+ "bufio"
+ "bytes"
+ "crypto/ecdsa"
+ "crypto/ed25519"
+ "crypto/elliptic"
+ "crypto/rand"
+ "crypto/rsa"
+ "crypto/x509"
+ "crypto/x509/pkix"
+ "encoding/pem"
+ "errors"
+ "fmt"
+ "math/big"
+ "net"
+ "strings"
+ "time"
+)
+
+func pubKey(priv interface{}) interface{} {
+ switch k := priv.(type) {
+ case *rsa.PrivateKey:
+ return &k.PublicKey
+ case *ecdsa.PrivateKey:
+ return &k.PublicKey
+ case ed25519.PrivateKey:
+ return k.Public().(ed25519.PublicKey)
+ default:
+ return nil
+ }
+}
+
+func Generate(options Options) (privateKey, publicKey []byte, err error) {
+ if options.Host == "" {
+ return nil, nil, errors.New("Empty host value")
+ }
+
+ var priv interface{}
+ switch options.EcdsaCurve {
+ case "":
+ if options.Ed25519Key {
+ _, priv, err = ed25519.GenerateKey(rand.Reader)
+ } else {
+ priv, err = rsa.GenerateKey(rand.Reader, options.RSABits)
+ }
+ case "P224":
+ priv, err = ecdsa.GenerateKey(elliptic.P224(), rand.Reader)
+ case "P256":
+ priv, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+ case "P384":
+ priv, err = ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
+ case "P521":
+ priv, err = ecdsa.GenerateKey(elliptic.P521(), rand.Reader)
+ default:
+ err = fmt.Errorf("Unrecognized elliptic curve: %q", options.EcdsaCurve)
+ return
+ }
+ if err != nil {
+ err = fmt.Errorf("Failed to generate private key: %v", err)
+ return
+ }
+
+ // ECDSA, ED25519 and RSA subject keys should have the DigitalSignature
+ // KeyUsage bits set in the x509.Certificate template
+ keyUsage := x509.KeyUsageDigitalSignature
+ // Only RSA subject keys should have the KeyEncipherment KeyUsage bits set. In
+ // the context of TLS this KeyUsage is particular to RSA key exchange and
+ // authentication.
+ if _, isRSA := priv.(*rsa.PrivateKey); isRSA {
+ keyUsage |= x509.KeyUsageKeyEncipherment
+ }
+
+ var notBefore time.Time
+ if len(options.ValidFrom) == 0 {
+ notBefore = time.Now()
+ } else {
+ notBefore, err = time.Parse("Jan 2 15:04:05 2006", options.ValidFrom)
+ if err != nil {
+ err = fmt.Errorf("Failed to parse creation date: %v", err)
+ return
+ }
+ }
+
+ notAfter := notBefore.Add(options.ValidFor)
+
+ serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
+ serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
+ if err != nil {
+ err = fmt.Errorf("Failed to generate serial number: %v", err)
+ return
+ }
+
+ template := x509.Certificate{
+ SerialNumber: serialNumber,
+ Subject: pkix.Name{
+ Organization: []string{options.Organization},
+ },
+ NotBefore: notBefore,
+ NotAfter: notAfter,
+
+ KeyUsage: keyUsage,
+ ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
+ BasicConstraintsValid: true,
+ }
+
+ hosts := strings.Split(options.Host, ",")
+ for _, h := range hosts {
+ if ip := net.ParseIP(h); ip != nil {
+ template.IPAddresses = append(template.IPAddresses, ip)
+ } else {
+ template.DNSNames = append(template.DNSNames, h)
+ }
+ }
+
+ if options.IsCA {
+ template.IsCA = true
+ template.KeyUsage |= x509.KeyUsageCertSign
+ }
+
+ derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, pubKey(priv), priv)
+ if err != nil {
+ err = fmt.Errorf("Failed to create certificate: %v", err)
+ return
+ }
+
+ var pubKeyBuf bytes.Buffer
+ pubKeyBufb := bufio.NewWriter(&pubKeyBuf)
+ err = pem.Encode(pubKeyBufb, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
+ if err != nil {
+ err = fmt.Errorf("Failed to write data to cert.pem: %v", err)
+ return
+ }
+
+ privBytes, err := x509.MarshalPKCS8PrivateKey(priv)
+ if err != nil {
+ err = fmt.Errorf("Unable to marshal private key: %v", err)
+ return
+ }
+ var privKeyBuf bytes.Buffer
+ privKeyBufb := bufio.NewWriter(&privKeyBuf)
+ err = pem.Encode(privKeyBufb, &pem.Block{Type: "PRIVATE KEY", Bytes: privBytes})
+ if err != nil {
+ err = fmt.Errorf("Failed to write data to key.pem: %v", err)
+ return
+ }
+
+ return pubKeyBuf.Bytes(), privKeyBuf.Bytes(), nil
+}
diff --git a/pkg/sslcert/tlsconfig.go b/pkg/sslcert/tlsconfig.go
new file mode 100644
index 0000000..e2bbe92
--- /dev/null
+++ b/pkg/sslcert/tlsconfig.go
@@ -0,0 +1,19 @@
+package sslcert
+
+import (
+ "crypto/tls"
+)
+
+func NewTLSConfig(options Options) (*tls.Config, error) {
+ pubKey, privKey, err := Generate(options)
+ if err != nil {
+ return nil, err
+ }
+
+ cert, err := tls.X509KeyPair(pubKey, privKey)
+ if err != nil {
+ return nil, err
+ }
+
+ return &tls.Config{Certificates: []tls.Certificate{cert}}, nil
+}
diff --git a/simplehttpserver.go b/simplehttpserver.go
index 98475c6..803d02c 100644
--- a/simplehttpserver.go
+++ b/simplehttpserver.go
@@ -11,6 +11,7 @@ import (
"path"
"github.com/projectdiscovery/gologger"
+ "github.com/projectdiscovery/simplehttpserver/pkg/sslcert"
)
type options struct {
@@ -21,6 +22,7 @@ type options struct {
Realm string
Certificate string
Key string
+ Domain string
HTTPS bool
Verbose bool
Upload bool
@@ -35,6 +37,7 @@ func main() {
flag.BoolVar(&opts.HTTPS, "https", false, "HTTPS")
flag.StringVar(&opts.Certificate, "cert", "", "Certificate")
flag.StringVar(&opts.Key, "key", "", "Key")
+ flag.StringVar(&opts.Domain, "domain", "", "Domain")
flag.BoolVar(&opts.Verbose, "v", false, "Verbose")
flag.StringVar(&opts.Username, "username", "", "Basic auth username")
flag.StringVar(&opts.Password, "password", "", "Basic auth password")
@@ -57,9 +60,21 @@ func main() {
}
if opts.HTTPS {
if opts.Certificate == "" || opts.Key == "" {
- gologger.Fatal().Msgf("Certificate or Key file not specified")
+ tlsOptions := sslcert.DefaultOptions
+ tlsOptions.Host = opts.Domain
+ tlsConfig, err := sslcert.NewTLSConfig(tlsOptions)
+ if err != nil {
+ gologger.Fatal().Msgf("%s\n", err)
+ }
+ httpServer := &http.Server{
+ Addr: opts.ListenAddress,
+ TLSConfig: tlsConfig,
+ }
+ httpServer.Handler = layers
+ gologger.Print().Msgf("%s\n", httpServer.ListenAndServeTLS("", ""))
+ } else {
+ gologger.Print().Msgf("%s\n", http.ListenAndServeTLS(opts.ListenAddress, opts.Certificate, opts.Key, layers))
}
- gologger.Print().Msgf("%s\n", http.ListenAndServeTLS(opts.ListenAddress, opts.Certificate, opts.Key, layers))
} else {
gologger.Print().Msgf("%s\n", http.ListenAndServe(opts.ListenAddress, layers))
}
From 86e2a7d6d16d98897b7c44ac943a2b1a2ebae8fb Mon Sep 17 00:00:00 2001
From: Mzack9999
Date: Tue, 23 Feb 2021 17:48:56 +0100
Subject: [PATCH 17/45] improved output
---
simplehttpserver.go | 11 +++++------
1 file changed, 5 insertions(+), 6 deletions(-)
diff --git a/simplehttpserver.go b/simplehttpserver.go
index e560113..62cb4e6 100644
--- a/simplehttpserver.go
+++ b/simplehttpserver.go
@@ -14,8 +14,8 @@ import (
"path"
"runtime"
"strconv"
- "syscall"
"strings"
+ "syscall"
"github.com/projectdiscovery/gologger"
)
@@ -53,7 +53,6 @@ func main() {
opts.Folder = flag.Args()[0]
}
- gologger.Print().Msgf("Serving %s on http://%s/...", opts.Folder, opts.ListenAddress)
layers := loglayer(http.FileServer(http.Dir(opts.Folder)))
if opts.BasicAuth != "" {
baTokens := strings.SplitN(opts.BasicAuth, ":", 2)
@@ -65,11 +64,11 @@ func main() {
}
layers = loglayer(basicauthlayer(http.FileServer(http.Dir(opts.Folder))))
}
-
if opts.Upload {
- gologger.Print().Msg("Upload enabled")
+ gologger.Print().Msg("Starting service with Upload enabled")
}
retry_listen:
+ gologger.Print().Msgf("Serving %s on http://%s/...", opts.Folder, opts.ListenAddress)
var err error
if opts.HTTPS {
if opts.Certificate == "" || opts.Key == "" {
@@ -81,7 +80,7 @@ retry_listen:
}
if err != nil {
if isErrorAddressAlreadyInUse(err) {
- gologger.Warning().Msgf("Can't listen on %s: %s - retrying with another port\n", opts.ListenAddress, err)
+ gologger.Print().Msgf("Can't listen on %s: %s - retrying with another port\n", opts.ListenAddress, err)
newListenAddress, err := incPort(opts.ListenAddress)
if err != nil {
gologger.Fatal().Msgf("%s\n", err)
@@ -89,7 +88,7 @@ retry_listen:
opts.ListenAddress = newListenAddress
goto retry_listen
}
- gologger.Warning().Msgf("%s\n", err)
+ gologger.Print().Msgf("%s\n", err)
}
}
From bd654bf7de05652c7cc25912482156fb607db277 Mon Sep 17 00:00:00 2001
From: Mzack9999
Date: Tue, 23 Feb 2021 17:58:09 +0100
Subject: [PATCH 18/45] adding missing buffer flush
---
pkg/sslcert/sslcert.go | 2 ++
simplehttpserver.go | 2 +-
2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/pkg/sslcert/sslcert.go b/pkg/sslcert/sslcert.go
index 6469b78..862ee21 100644
--- a/pkg/sslcert/sslcert.go
+++ b/pkg/sslcert/sslcert.go
@@ -133,6 +133,7 @@ func Generate(options Options) (privateKey, publicKey []byte, err error) {
err = fmt.Errorf("Failed to write data to cert.pem: %v", err)
return
}
+ pubKeyBufb.Flush()
privBytes, err := x509.MarshalPKCS8PrivateKey(priv)
if err != nil {
@@ -146,6 +147,7 @@ func Generate(options Options) (privateKey, publicKey []byte, err error) {
err = fmt.Errorf("Failed to write data to key.pem: %v", err)
return
}
+ privKeyBufb.Flush()
return pubKeyBuf.Bytes(), privKeyBuf.Bytes(), nil
}
diff --git a/simplehttpserver.go b/simplehttpserver.go
index 803d02c..f8e5875 100644
--- a/simplehttpserver.go
+++ b/simplehttpserver.go
@@ -37,7 +37,7 @@ func main() {
flag.BoolVar(&opts.HTTPS, "https", false, "HTTPS")
flag.StringVar(&opts.Certificate, "cert", "", "Certificate")
flag.StringVar(&opts.Key, "key", "", "Key")
- flag.StringVar(&opts.Domain, "domain", "", "Domain")
+ flag.StringVar(&opts.Domain, "domain", "local.host", "Domain")
flag.BoolVar(&opts.Verbose, "v", false, "Verbose")
flag.StringVar(&opts.Username, "username", "", "Basic auth username")
flag.StringVar(&opts.Password, "password", "", "Basic auth password")
From bbee79f0fca7e3577978ad06e95c1704690db3c6 Mon Sep 17 00:00:00 2001
From: Mzack9999
Date: Tue, 23 Feb 2021 20:11:28 +0100
Subject: [PATCH 19/45] adding initial implementation of template based tcp
server
---
go.mod | 5 +-
go.sum | 2 +
pkg/tcpserver/responseengine.go | 15 ++++
pkg/tcpserver/rule.go | 22 ++++++
pkg/tcpserver/tcpserver.go | 124 ++++++++++++++++++++++++++++++++
simplehttpserver.go | 20 ++++++
6 files changed, 187 insertions(+), 1 deletion(-)
create mode 100644 pkg/tcpserver/responseengine.go
create mode 100644 pkg/tcpserver/rule.go
create mode 100644 pkg/tcpserver/tcpserver.go
diff --git a/go.mod b/go.mod
index 120667d..2bc0442 100644
--- a/go.mod
+++ b/go.mod
@@ -2,4 +2,7 @@ module github.com/projectdiscovery/simplehttpserver
go 1.15
-require github.com/projectdiscovery/gologger v1.1.4
+require (
+ github.com/projectdiscovery/gologger v1.1.4
+ gopkg.in/yaml.v2 v2.4.0
+)
diff --git a/go.sum b/go.sum
index 82f8703..bd1e991 100644
--- a/go.sum
+++ b/go.sum
@@ -30,6 +30,8 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
+gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
+gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/pkg/tcpserver/responseengine.go b/pkg/tcpserver/responseengine.go
new file mode 100644
index 0000000..c3286f8
--- /dev/null
+++ b/pkg/tcpserver/responseengine.go
@@ -0,0 +1,15 @@
+package tcpserver
+
+import (
+ "errors"
+)
+
+func (t *TCPServer) BuildResponse(data []byte) ([]byte, error) {
+ // Process all the rules
+ for _, rule := range t.options.rules {
+ if rule.matchRegex.Match(data) {
+ return []byte(rule.Response), nil
+ }
+ }
+ return nil, errors.New("No matched rule")
+}
diff --git a/pkg/tcpserver/rule.go b/pkg/tcpserver/rule.go
new file mode 100644
index 0000000..ba31839
--- /dev/null
+++ b/pkg/tcpserver/rule.go
@@ -0,0 +1,22 @@
+package tcpserver
+
+import "regexp"
+
+type RulesConfiguration struct {
+ Rules []Rule `yaml:"rules"`
+}
+
+type Rule struct {
+ Match string `yaml:"match,omitempty"`
+ matchRegex *regexp.Regexp
+ Response string `yaml:"response,omitempty"`
+}
+
+func NewRule(match string, response string) (*Rule, error) {
+ regxp, err := regexp.Compile(match)
+ if err != nil {
+ return nil, err
+ }
+
+ return &Rule{Match: match, matchRegex: regxp, Response: response}, nil
+}
diff --git a/pkg/tcpserver/tcpserver.go b/pkg/tcpserver/tcpserver.go
new file mode 100644
index 0000000..607afe1
--- /dev/null
+++ b/pkg/tcpserver/tcpserver.go
@@ -0,0 +1,124 @@
+package tcpserver
+
+import (
+ "crypto/tls"
+ "io/ioutil"
+ "net"
+ "time"
+
+ "gopkg.in/yaml.v2"
+)
+
+type Options struct {
+ Listen string
+ TLS bool
+ Certificate string
+ Key string
+ Domain string
+ rules []Rule
+}
+
+type TCPServer struct {
+ options Options
+ listener net.Listener
+}
+
+func New(options Options) (*TCPServer, error) {
+ return &TCPServer{options: options}, nil
+}
+
+func (t *TCPServer) AddRule(rule Rule) error {
+ t.options.rules = append(t.options.rules, rule)
+ return nil
+}
+
+func (t *TCPServer) ListenAndServe() error {
+ listener, err := net.Listen("tcp4", t.options.Listen)
+ if err != nil {
+ return err
+ }
+ t.listener = listener
+ return t.run()
+}
+
+func (t *TCPServer) handleConnection(conn net.Conn) error {
+ defer conn.Close()
+
+ buf := make([]byte, 4096)
+ for {
+ conn.SetReadDeadline(time.Now().Add(time.Duration(5 * time.Second)))
+ _, err := conn.Read(buf)
+ if err != nil {
+ return err
+ }
+
+ resp, err := t.BuildResponse(buf)
+ if err != nil {
+ return err
+ }
+
+ conn.Write(resp)
+ }
+}
+
+func (t *TCPServer) ListenAndServeTLS() error {
+ var tlsConfig *tls.Config
+ if t.options.Certificate != "" && t.options.Key != "" {
+ cert, err := tls.LoadX509KeyPair(t.options.Certificate, t.options.Key)
+ if err != nil {
+ return err
+ }
+ tlsConfig = &tls.Config{Certificates: []tls.Certificate{cert}}
+ } else {
+ tlsOptions := sslcert.DefaultOptions
+ tlsOptions.Host = opts.Domain
+ cfg, err := sslcert.NewTLSConfig(tlsOptions)
+ if err != nil {
+ return err
+ }
+ tlsConfig = cfg
+ }
+
+ listener, err := tls.Listen("tcp", t.options.Listen, tlsConfig)
+ if err != nil {
+ return err
+ }
+ t.listener = listener
+ return t.run()
+}
+
+func (t *TCPServer) run() error {
+ for {
+ c, err := t.listener.Accept()
+ if err != nil {
+ return err
+ }
+ go t.handleConnection(c)
+ }
+}
+
+func (t *TCPServer) Close() error {
+ return t.listener.Close()
+}
+
+func (t *TCPServer) LoadTemplate(templatePath string) error {
+ var config RulesConfiguration
+ yamlFile, err := ioutil.ReadFile(templatePath)
+ if err != nil {
+ return err
+ }
+ err = yaml.Unmarshal(yamlFile, &config)
+ if err != nil {
+ return err
+ }
+
+ for _, ruleTemplate := range config.Rules {
+ rule, err := NewRule(ruleTemplate.Match, ruleTemplate.Response)
+ if err != nil {
+ return err
+ }
+ t.options.rules = append(t.options.rules, *rule)
+ }
+
+ return nil
+}
diff --git a/simplehttpserver.go b/simplehttpserver.go
index 6e5f22d..1335ce1 100644
--- a/simplehttpserver.go
+++ b/simplehttpserver.go
@@ -12,6 +12,7 @@ import (
"strings"
"github.com/projectdiscovery/gologger"
+ "github.com/projectdiscovery/simplehttpserver/pkg/tcpserver"
)
type options struct {
@@ -26,12 +27,18 @@ type options struct {
HTTPS bool
Verbose bool
Upload bool
+ TCP bool
+ RulesFile string
+ TLS bool
}
var opts options
func main() {
flag.StringVar(&opts.ListenAddress, "listen", "0.0.0.0:8000", "Address:Port")
+ flag.BoolVar(&opts.TCP, "tcp", false, "TCP Server")
+ flag.BoolVar(&opts.TLS, "tls", false, "Enable TCP TLS")
+ flag.StringVar(&opts.RulesFile, "rules", "", "Rules yaml file")
flag.StringVar(&opts.Folder, "path", ".", "Folder")
flag.BoolVar(&opts.Upload, "upload", false, "Enable upload via PUT")
flag.BoolVar(&opts.HTTPS, "https", false, "HTTPS")
@@ -47,6 +54,19 @@ func main() {
opts.Folder = flag.Args()[0]
}
+ if opts.TCP {
+ serverTCP, err := tcpserver.New(tcpserver.Options{Listen: opts.ListenAddress, TLS: opts.TLS, Domain: "local.host"})
+ if err != nil {
+ gologger.Fatal().Msgf("%s\n", err)
+ }
+ err = serverTCP.LoadTemplate(opts.RulesFile)
+ if err != nil {
+ gologger.Fatal().Msgf("%s\n", err)
+ }
+
+ gologger.Print().Msgf("%s\n", serverTCP.ListenAndServe())
+ }
+
gologger.Print().Msgf("Serving %s on http://%s/...", opts.Folder, opts.ListenAddress)
layers := loglayer(http.FileServer(http.Dir(opts.Folder)))
if opts.BasicAuth != "" {
From c8614c543900bda208d63a5103e0a40b1be5fc33 Mon Sep 17 00:00:00 2001
From: Mzack9999
Date: Tue, 23 Feb 2021 02:51:41 +0100
Subject: [PATCH 20/45] fixing conflict
---
pkg/sslcert/options.go | 21 ++++++
pkg/sslcert/sslcert.go | 151 +++++++++++++++++++++++++++++++++++++++
pkg/sslcert/tlsconfig.go | 19 +++++
simplehttpserver.go | 19 ++++-
4 files changed, 208 insertions(+), 2 deletions(-)
create mode 100644 pkg/sslcert/options.go
create mode 100644 pkg/sslcert/sslcert.go
create mode 100644 pkg/sslcert/tlsconfig.go
diff --git a/pkg/sslcert/options.go b/pkg/sslcert/options.go
new file mode 100644
index 0000000..54cbc0d
--- /dev/null
+++ b/pkg/sslcert/options.go
@@ -0,0 +1,21 @@
+package sslcert
+
+import "time"
+
+type Options struct {
+ Host string // Comma-separated hostnames and IPs to generate a certificate for")
+ Organization string
+ ValidFrom string // Creation date formatted as Jan 1 15:04:05 2011
+ ValidFor time.Duration // 365*24*time.Hour Duration that certificate is valid for
+ IsCA bool // whether this cert should be its own Certificate Authority
+ RSABits int // 2048 Size of RSA key to generate. Ignored if --ecdsa-curve is set
+ EcdsaCurve string // ECDSA curve to use to generate a key. Valid values are P224, P256 (recommended), P384, P521
+ Ed25519Key bool // Generate an Ed25519 key
+}
+
+var DefaultOptions = Options{
+ ValidFor: time.Duration(365 * 24 * time.Hour),
+ IsCA: false,
+ RSABits: 2048,
+ Organization: "Acme Co",
+}
diff --git a/pkg/sslcert/sslcert.go b/pkg/sslcert/sslcert.go
new file mode 100644
index 0000000..6469b78
--- /dev/null
+++ b/pkg/sslcert/sslcert.go
@@ -0,0 +1,151 @@
+// Package sslcert contains a reworked version of https://golang.org/src/crypto/tls/generate_cert.go
+package sslcert
+
+import (
+ "bufio"
+ "bytes"
+ "crypto/ecdsa"
+ "crypto/ed25519"
+ "crypto/elliptic"
+ "crypto/rand"
+ "crypto/rsa"
+ "crypto/x509"
+ "crypto/x509/pkix"
+ "encoding/pem"
+ "errors"
+ "fmt"
+ "math/big"
+ "net"
+ "strings"
+ "time"
+)
+
+func pubKey(priv interface{}) interface{} {
+ switch k := priv.(type) {
+ case *rsa.PrivateKey:
+ return &k.PublicKey
+ case *ecdsa.PrivateKey:
+ return &k.PublicKey
+ case ed25519.PrivateKey:
+ return k.Public().(ed25519.PublicKey)
+ default:
+ return nil
+ }
+}
+
+func Generate(options Options) (privateKey, publicKey []byte, err error) {
+ if options.Host == "" {
+ return nil, nil, errors.New("Empty host value")
+ }
+
+ var priv interface{}
+ switch options.EcdsaCurve {
+ case "":
+ if options.Ed25519Key {
+ _, priv, err = ed25519.GenerateKey(rand.Reader)
+ } else {
+ priv, err = rsa.GenerateKey(rand.Reader, options.RSABits)
+ }
+ case "P224":
+ priv, err = ecdsa.GenerateKey(elliptic.P224(), rand.Reader)
+ case "P256":
+ priv, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+ case "P384":
+ priv, err = ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
+ case "P521":
+ priv, err = ecdsa.GenerateKey(elliptic.P521(), rand.Reader)
+ default:
+ err = fmt.Errorf("Unrecognized elliptic curve: %q", options.EcdsaCurve)
+ return
+ }
+ if err != nil {
+ err = fmt.Errorf("Failed to generate private key: %v", err)
+ return
+ }
+
+ // ECDSA, ED25519 and RSA subject keys should have the DigitalSignature
+ // KeyUsage bits set in the x509.Certificate template
+ keyUsage := x509.KeyUsageDigitalSignature
+ // Only RSA subject keys should have the KeyEncipherment KeyUsage bits set. In
+ // the context of TLS this KeyUsage is particular to RSA key exchange and
+ // authentication.
+ if _, isRSA := priv.(*rsa.PrivateKey); isRSA {
+ keyUsage |= x509.KeyUsageKeyEncipherment
+ }
+
+ var notBefore time.Time
+ if len(options.ValidFrom) == 0 {
+ notBefore = time.Now()
+ } else {
+ notBefore, err = time.Parse("Jan 2 15:04:05 2006", options.ValidFrom)
+ if err != nil {
+ err = fmt.Errorf("Failed to parse creation date: %v", err)
+ return
+ }
+ }
+
+ notAfter := notBefore.Add(options.ValidFor)
+
+ serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
+ serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
+ if err != nil {
+ err = fmt.Errorf("Failed to generate serial number: %v", err)
+ return
+ }
+
+ template := x509.Certificate{
+ SerialNumber: serialNumber,
+ Subject: pkix.Name{
+ Organization: []string{options.Organization},
+ },
+ NotBefore: notBefore,
+ NotAfter: notAfter,
+
+ KeyUsage: keyUsage,
+ ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
+ BasicConstraintsValid: true,
+ }
+
+ hosts := strings.Split(options.Host, ",")
+ for _, h := range hosts {
+ if ip := net.ParseIP(h); ip != nil {
+ template.IPAddresses = append(template.IPAddresses, ip)
+ } else {
+ template.DNSNames = append(template.DNSNames, h)
+ }
+ }
+
+ if options.IsCA {
+ template.IsCA = true
+ template.KeyUsage |= x509.KeyUsageCertSign
+ }
+
+ derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, pubKey(priv), priv)
+ if err != nil {
+ err = fmt.Errorf("Failed to create certificate: %v", err)
+ return
+ }
+
+ var pubKeyBuf bytes.Buffer
+ pubKeyBufb := bufio.NewWriter(&pubKeyBuf)
+ err = pem.Encode(pubKeyBufb, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
+ if err != nil {
+ err = fmt.Errorf("Failed to write data to cert.pem: %v", err)
+ return
+ }
+
+ privBytes, err := x509.MarshalPKCS8PrivateKey(priv)
+ if err != nil {
+ err = fmt.Errorf("Unable to marshal private key: %v", err)
+ return
+ }
+ var privKeyBuf bytes.Buffer
+ privKeyBufb := bufio.NewWriter(&privKeyBuf)
+ err = pem.Encode(privKeyBufb, &pem.Block{Type: "PRIVATE KEY", Bytes: privBytes})
+ if err != nil {
+ err = fmt.Errorf("Failed to write data to key.pem: %v", err)
+ return
+ }
+
+ return pubKeyBuf.Bytes(), privKeyBuf.Bytes(), nil
+}
diff --git a/pkg/sslcert/tlsconfig.go b/pkg/sslcert/tlsconfig.go
new file mode 100644
index 0000000..e2bbe92
--- /dev/null
+++ b/pkg/sslcert/tlsconfig.go
@@ -0,0 +1,19 @@
+package sslcert
+
+import (
+ "crypto/tls"
+)
+
+func NewTLSConfig(options Options) (*tls.Config, error) {
+ pubKey, privKey, err := Generate(options)
+ if err != nil {
+ return nil, err
+ }
+
+ cert, err := tls.X509KeyPair(pubKey, privKey)
+ if err != nil {
+ return nil, err
+ }
+
+ return &tls.Config{Certificates: []tls.Certificate{cert}}, nil
+}
diff --git a/simplehttpserver.go b/simplehttpserver.go
index 1335ce1..db3195c 100644
--- a/simplehttpserver.go
+++ b/simplehttpserver.go
@@ -12,6 +12,7 @@ import (
"strings"
"github.com/projectdiscovery/gologger"
+ "github.com/projectdiscovery/simplehttpserver/pkg/sslcert"
"github.com/projectdiscovery/simplehttpserver/pkg/tcpserver"
)
@@ -24,6 +25,7 @@ type options struct {
Realm string
Certificate string
Key string
+ Domain string
HTTPS bool
Verbose bool
Upload bool
@@ -44,6 +46,7 @@ func main() {
flag.BoolVar(&opts.HTTPS, "https", false, "HTTPS")
flag.StringVar(&opts.Certificate, "cert", "", "Certificate")
flag.StringVar(&opts.Key, "key", "", "Key")
+ flag.StringVar(&opts.Domain, "domain", "", "Domain")
flag.BoolVar(&opts.Verbose, "v", false, "Verbose")
flag.StringVar(&opts.BasicAuth, "basic-auth", "", "Basic auth (username:password)")
flag.StringVar(&opts.Realm, "realm", "Please enter username and password", "Realm")
@@ -85,9 +88,21 @@ func main() {
}
if opts.HTTPS {
if opts.Certificate == "" || opts.Key == "" {
- gologger.Fatal().Msgf("Certificate or Key file not specified")
+ tlsOptions := sslcert.DefaultOptions
+ tlsOptions.Host = opts.Domain
+ tlsConfig, err := sslcert.NewTLSConfig(tlsOptions)
+ if err != nil {
+ gologger.Fatal().Msgf("%s\n", err)
+ }
+ httpServer := &http.Server{
+ Addr: opts.ListenAddress,
+ TLSConfig: tlsConfig,
+ }
+ httpServer.Handler = layers
+ gologger.Print().Msgf("%s\n", httpServer.ListenAndServeTLS("", ""))
+ } else {
+ gologger.Print().Msgf("%s\n", http.ListenAndServeTLS(opts.ListenAddress, opts.Certificate, opts.Key, layers))
}
- gologger.Print().Msgf("%s\n", http.ListenAndServeTLS(opts.ListenAddress, opts.Certificate, opts.Key, layers))
} else {
gologger.Print().Msgf("%s\n", http.ListenAndServe(opts.ListenAddress, layers))
}
From ca04767a3b974785646d4612270b598e3daa6404 Mon Sep 17 00:00:00 2001
From: Mzack9999
Date: Tue, 23 Feb 2021 17:58:09 +0100
Subject: [PATCH 21/45] adding missing buffer flush
---
pkg/sslcert/sslcert.go | 2 ++
simplehttpserver.go | 2 +-
2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/pkg/sslcert/sslcert.go b/pkg/sslcert/sslcert.go
index 6469b78..862ee21 100644
--- a/pkg/sslcert/sslcert.go
+++ b/pkg/sslcert/sslcert.go
@@ -133,6 +133,7 @@ func Generate(options Options) (privateKey, publicKey []byte, err error) {
err = fmt.Errorf("Failed to write data to cert.pem: %v", err)
return
}
+ pubKeyBufb.Flush()
privBytes, err := x509.MarshalPKCS8PrivateKey(priv)
if err != nil {
@@ -146,6 +147,7 @@ func Generate(options Options) (privateKey, publicKey []byte, err error) {
err = fmt.Errorf("Failed to write data to key.pem: %v", err)
return
}
+ privKeyBufb.Flush()
return pubKeyBuf.Bytes(), privKeyBuf.Bytes(), nil
}
diff --git a/simplehttpserver.go b/simplehttpserver.go
index db3195c..fff559f 100644
--- a/simplehttpserver.go
+++ b/simplehttpserver.go
@@ -46,7 +46,7 @@ func main() {
flag.BoolVar(&opts.HTTPS, "https", false, "HTTPS")
flag.StringVar(&opts.Certificate, "cert", "", "Certificate")
flag.StringVar(&opts.Key, "key", "", "Key")
- flag.StringVar(&opts.Domain, "domain", "", "Domain")
+ flag.StringVar(&opts.Domain, "domain", "local.host", "Domain")
flag.BoolVar(&opts.Verbose, "v", false, "Verbose")
flag.StringVar(&opts.BasicAuth, "basic-auth", "", "Basic auth (username:password)")
flag.StringVar(&opts.Realm, "realm", "Please enter username and password", "Realm")
From 7bfbf59c6bd11b08fde92673d37975d271be4234 Mon Sep 17 00:00:00 2001
From: Mzack9999
Date: Tue, 23 Feb 2021 20:22:29 +0100
Subject: [PATCH 22/45] fixing name
---
pkg/tcpserver/tcpserver.go | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/pkg/tcpserver/tcpserver.go b/pkg/tcpserver/tcpserver.go
index 607afe1..fc08f03 100644
--- a/pkg/tcpserver/tcpserver.go
+++ b/pkg/tcpserver/tcpserver.go
@@ -6,6 +6,7 @@ import (
"net"
"time"
+ "github.com/projectdiscovery/simplehttpserver/pkg/sslcert"
"gopkg.in/yaml.v2"
)
@@ -71,7 +72,7 @@ func (t *TCPServer) ListenAndServeTLS() error {
tlsConfig = &tls.Config{Certificates: []tls.Certificate{cert}}
} else {
tlsOptions := sslcert.DefaultOptions
- tlsOptions.Host = opts.Domain
+ tlsOptions.Host = t.options.Domain
cfg, err := sslcert.NewTLSConfig(tlsOptions)
if err != nil {
return err
From d728e2fb4dfa8cd35af9220d7a2edb4a478a00b5 Mon Sep 17 00:00:00 2001
From: Mzack9999
Date: Tue, 23 Feb 2021 20:24:06 +0100
Subject: [PATCH 23/45] replacing log => gologger
---
simplehttpserver.go | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/simplehttpserver.go b/simplehttpserver.go
index fff559f..47d516f 100644
--- a/simplehttpserver.go
+++ b/simplehttpserver.go
@@ -5,7 +5,6 @@ import (
"flag"
"fmt"
"io/ioutil"
- "log"
"net/http"
"net/http/httputil"
"path"
@@ -118,11 +117,11 @@ func loglayer(handler http.Handler) http.Handler {
if opts.Upload && r.Method == http.MethodPut {
data, err := ioutil.ReadAll(r.Body)
if err != nil {
- log.Println(err)
+ gologger.Print().Msgf("%s\n", err)
}
err = handleUpload(path.Base(r.URL.Path), data)
if err != nil {
- log.Println(err)
+ gologger.Print().Msgf("%s\n", err)
}
}
From ca921084993fcf7cd7b8b2e606276a2c29e3f87b Mon Sep 17 00:00:00 2001
From: Mzack9999
Date: Wed, 24 Feb 2021 23:09:19 +0100
Subject: [PATCH 24/45] removing log package
---
simplehttpserver.go | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/simplehttpserver.go b/simplehttpserver.go
index 62cb4e6..50a8af1 100644
--- a/simplehttpserver.go
+++ b/simplehttpserver.go
@@ -6,7 +6,6 @@ import (
"flag"
"fmt"
"io/ioutil"
- "log"
"net"
"net/http"
"net/http/httputil"
@@ -102,11 +101,11 @@ func loglayer(handler http.Handler) http.Handler {
if opts.Upload && r.Method == http.MethodPut {
data, err := ioutil.ReadAll(r.Body)
if err != nil {
- log.Println(err)
+ gologger.Print().Msgf("%s\n", err)
}
err = handleUpload(path.Base(r.URL.Path), data)
if err != nil {
- log.Println(err)
+ gologger.Print().Msgf("%s\n", err)
}
}
From 9be5b1adc6427e6f6d9ec737d915cdfe6a90be40 Mon Sep 17 00:00:00 2001
From: Mzack9999
Date: Wed, 24 Feb 2021 23:18:32 +0100
Subject: [PATCH 25/45] removing unused log
---
simplehttpserver.go | 1 -
1 file changed, 1 deletion(-)
diff --git a/simplehttpserver.go b/simplehttpserver.go
index 1ad66e8..f03f258 100644
--- a/simplehttpserver.go
+++ b/simplehttpserver.go
@@ -6,7 +6,6 @@ import (
"flag"
"fmt"
"io/ioutil"
- "log"
"net"
"net/http"
"net/http/httputil"
From c339cd798c40d8ec5ead8ec17b96d7bbac57df49 Mon Sep 17 00:00:00 2001
From: Mzack9999
Date: Fri, 26 Feb 2021 08:42:34 +0100
Subject: [PATCH 26/45] code refactor
---
.github/workflows/build.yaml | 4 +-
.goreleaser.yml | 2 +-
Dockerfile | 4 +-
gen_cert.sh | 5 -
internal/runner/banner.go | 24 ++++
internal/runner/doc.go | 2 +
internal/runner/options.go | 93 ++++++++++++++
internal/runner/runner.go | 70 ++++++++++
pkg/httpserver/authlayer.go | 19 +++
pkg/httpserver/httpserver.go | 120 +++++++++++++++++
pkg/httpserver/loglayer.go | 69 ++++++++++
pkg/httpserver/uploadlayer.go | 7 +
pkg/tcpserver/tcpserver.go | 7 +
simplehttpserver.go | 233 ----------------------------------
14 files changed, 416 insertions(+), 243 deletions(-)
delete mode 100644 gen_cert.sh
create mode 100644 internal/runner/banner.go
create mode 100644 internal/runner/doc.go
create mode 100644 internal/runner/options.go
create mode 100644 internal/runner/runner.go
create mode 100644 pkg/httpserver/authlayer.go
create mode 100644 pkg/httpserver/httpserver.go
create mode 100644 pkg/httpserver/loglayer.go
create mode 100644 pkg/httpserver/uploadlayer.go
delete mode 100644 simplehttpserver.go
diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml
index 008bca6..11d1658 100644
--- a/.github/workflows/build.yaml
+++ b/.github/workflows/build.yaml
@@ -32,8 +32,8 @@ jobs:
- name: Test
run: go test .
- working-directory: .
+ working-directory: cmd/simplehttpserver/
- name: Build
run: go build .
- working-directory: .
+ working-directory: cmd/simplehttpserver/
diff --git a/.goreleaser.yml b/.goreleaser.yml
index 50bb74f..f6cb1e2 100644
--- a/.goreleaser.yml
+++ b/.goreleaser.yml
@@ -1,6 +1,6 @@
builds:
- binary: simplehttpserver
- main: simplehttpserver.go
+ main: cmd/simplehttpserver/simplehttpserver.go
goos:
- linux
- windows
diff --git a/Dockerfile b/Dockerfile
index a01590c..4603b20 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,6 +1,6 @@
-FROM golang:1.14-alpine AS builder
+FROM golang:1.16-alpine AS builder
RUN apk add --no-cache git
-RUN GO111MODULE=auto go get -u -v github.com/projectdiscovery/simplehttpserver
+RUN GO111MODULE=auto go get -u -v github.com/projectdiscovery/simplehttpserver/cmd/simplehttpserver
FROM alpine:latest
COPY --from=builder /go/bin/simplehttpserver /usr/local/bin/
diff --git a/gen_cert.sh b/gen_cert.sh
deleted file mode 100644
index 0cba96a..0000000
--- a/gen_cert.sh
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/usr/bin/env bash
-
-openssl genrsa -out server.key 2048
-openssl ecparam -genkey -name secp384r1 -out server.key
-openssl req -new -x509 -sha256 -key server.key -out server.crt -days 3650
\ No newline at end of file
diff --git a/internal/runner/banner.go b/internal/runner/banner.go
new file mode 100644
index 0000000..c8972db
--- /dev/null
+++ b/internal/runner/banner.go
@@ -0,0 +1,24 @@
+package runner
+
+import "github.com/projectdiscovery/gologger"
+
+const banner = `
+ _ _ _ _ _
+ ___(_)_ __ ___ _ __ | | ___| |__ | |_| |_ _ __ ___ ___ _ ____ _____ _ __
+/ __| | '_ ' _ \| '_ \| |/ _ \ '_ \| __| __| '_ \/ __|/ _ \ '__\ \ / / _ \ '__|
+\__ \ | | | | | | |_) | | __/ | | | |_| |_| |_) \__ \ __/ | \ V / __/ |
+|___/_|_| |_| |_| .__/|_|\___|_| |_|\__|\__| .__/|___/\___|_| \_/ \___|_|
+ |_| |_|
+`
+
+// Version is the current version
+const Version = `0.0.1`
+
+// showBanner is used to show the banner to the user
+func showBanner() {
+ gologger.Print().Msgf("%s\n", banner)
+ gologger.Print().Msgf("\t\tprojectdiscovery.io\n\n")
+
+ gologger.Print().Msgf("Use with caution. You are responsible for your actions\n")
+ gologger.Print().Msgf("Developers assume no liability and are not responsible for any misuse or damage.\n")
+}
diff --git a/internal/runner/doc.go b/internal/runner/doc.go
new file mode 100644
index 0000000..6d6e364
--- /dev/null
+++ b/internal/runner/doc.go
@@ -0,0 +1,2 @@
+// Package runner contains the internal logic
+package runner
diff --git a/internal/runner/options.go b/internal/runner/options.go
new file mode 100644
index 0000000..3170cd3
--- /dev/null
+++ b/internal/runner/options.go
@@ -0,0 +1,93 @@
+package runner
+
+import (
+ "flag"
+ "os"
+ "strings"
+
+ "github.com/projectdiscovery/gologger"
+ "github.com/projectdiscovery/gologger/levels"
+)
+
+type Options struct {
+ ListenAddress string
+ Folder string
+ BasicAuth string
+ username string
+ password string
+ Realm string
+ TLSCertificate string
+ TLSKey string
+ TLSDomain string
+ HTTPS bool
+ Verbose bool
+ EnableUpload bool
+ EnableTCP bool
+ RulesFile string
+ TCPWithTLS bool
+ Version bool
+ Silent bool
+}
+
+// ParseOptions parses the command line options for application
+func ParseOptions() *Options {
+ options := &Options{}
+ flag.StringVar(&options.ListenAddress, "listen", "0.0.0.0:8000", "Address:Port")
+ flag.BoolVar(&options.EnableTCP, "tcp", false, "TCP Server")
+ flag.BoolVar(&options.TCPWithTLS, "tls", false, "Enable TCP TLS")
+ flag.StringVar(&options.RulesFile, "rules", "", "Rules yaml file")
+ flag.StringVar(&options.Folder, "path", ".", "Folder")
+ flag.BoolVar(&options.EnableUpload, "upload", false, "Enable upload via PUT")
+ flag.BoolVar(&options.HTTPS, "https", false, "HTTPS")
+ flag.StringVar(&options.TLSCertificate, "cert", "", "HTTPS Certificate")
+ flag.StringVar(&options.TLSKey, "key", "", "HTTPS Certificate Key")
+ flag.StringVar(&options.TLSDomain, "domain", "local.host", "Domain")
+ flag.BoolVar(&options.Verbose, "verbose", false, "Verbose")
+ flag.StringVar(&options.BasicAuth, "basic-auth", "", "Basic auth (username:password)")
+ flag.StringVar(&options.Realm, "realm", "Please enter username and password", "Realm")
+ flag.BoolVar(&options.Version, "version", false, "Show version of the software")
+ flag.BoolVar(&options.Silent, "silent", false, "Show only results in the output")
+
+ flag.Parse()
+
+ // Read the inputs and configure the logging
+ options.configureOutput()
+
+ showBanner()
+
+ if options.Version {
+ gologger.Info().Msgf("Current Version: %s\n", Version)
+ os.Exit(0)
+ }
+
+ options.validateOptions()
+
+ return options
+}
+
+func (options *Options) validateOptions() {
+ if flag.NArg() > 0 && options.Folder == "." {
+ options.Folder = flag.Args()[0]
+ }
+
+ if options.BasicAuth != "" {
+ baTokens := strings.SplitN(options.BasicAuth, ":", 2)
+ if len(baTokens) > 0 {
+ options.username = baTokens[0]
+ }
+ if len(baTokens) > 1 {
+ options.password = baTokens[1]
+ }
+ }
+}
+
+// configureOutput configures the output on the screen
+func (options *Options) configureOutput() {
+ // If the user desires verbose output, show verbose output
+ if options.Verbose {
+ gologger.DefaultLogger.SetMaxLevel(levels.LevelVerbose)
+ }
+ if options.Silent {
+ gologger.DefaultLogger.SetMaxLevel(levels.LevelSilent)
+ }
+}
diff --git a/internal/runner/runner.go b/internal/runner/runner.go
new file mode 100644
index 0000000..a5d5230
--- /dev/null
+++ b/internal/runner/runner.go
@@ -0,0 +1,70 @@
+package runner
+
+import (
+ "github.com/projectdiscovery/simplehttpserver/pkg/httpserver"
+ "github.com/projectdiscovery/simplehttpserver/pkg/tcpserver"
+)
+
+// Runner is a client for running the enumeration process.
+type Runner struct {
+ options *Options
+ serverTCP *tcpserver.TCPServer
+ httpServer *httpserver.HTTPServer
+}
+
+func New(options *Options) (*Runner, error) {
+ r := Runner{options: options}
+ if r.options.EnableTCP {
+ serverTCP, err := tcpserver.New(tcpserver.Options{
+ Listen: r.options.ListenAddress,
+ TLS: r.options.TCPWithTLS,
+ Domain: "local.host",
+ Verbose: r.options.Verbose,
+ })
+ if err != nil {
+ return nil, err
+ }
+ err = serverTCP.LoadTemplate(r.options.RulesFile)
+ if err != nil {
+ return nil, err
+ }
+ r.serverTCP = serverTCP
+ return &r, nil
+ }
+
+ httpServer, err := httpserver.New(&httpserver.Options{
+ Folder: r.options.Folder,
+ EnableUpload: r.options.EnableUpload,
+ ListenAddress: r.options.ListenAddress,
+ TLS: r.options.HTTPS,
+ Certificate: r.options.TLSCertificate,
+ CertificateKey: r.options.TLSKey,
+ CertificateDomain: r.options.TLSDomain,
+ BasicAuthUsername: r.options.username,
+ BasicAuthPassword: r.options.password,
+ BasicAuthReal: r.options.Realm,
+ Verbose: r.options.Verbose,
+ })
+ if err != nil {
+ return nil, err
+ }
+ r.httpServer = httpServer
+
+ return &r, nil
+}
+
+func (r *Runner) Run() error {
+ if r.options.EnableTCP {
+ return r.serverTCP.ListenAndServe()
+ }
+
+ if r.options.HTTPS {
+ return r.httpServer.ListenAndServeTLS()
+ }
+
+ return r.httpServer.ListenAndServe()
+}
+
+func (r *Runner) Close() error {
+ return nil
+}
diff --git a/pkg/httpserver/authlayer.go b/pkg/httpserver/authlayer.go
new file mode 100644
index 0000000..f2eff4b
--- /dev/null
+++ b/pkg/httpserver/authlayer.go
@@ -0,0 +1,19 @@
+package httpserver
+
+import (
+ "fmt"
+ "net/http"
+)
+
+func (t *HTTPServer) basicauthlayer(handler http.Handler) http.HandlerFunc {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ user, pass, ok := r.BasicAuth()
+ if !ok || user != t.options.BasicAuthUsername || pass != t.options.BasicAuthPassword {
+ w.Header().Set("WWW-Authenticate", fmt.Sprintf("Basic realm=\"%s\"", t.options.BasicAuthReal))
+ w.WriteHeader(http.StatusUnauthorized)
+ w.Write([]byte("Unauthorized.\n")) //nolint
+ return
+ }
+ handler.ServeHTTP(w, r)
+ })
+}
diff --git a/pkg/httpserver/httpserver.go b/pkg/httpserver/httpserver.go
new file mode 100644
index 0000000..6e817d3
--- /dev/null
+++ b/pkg/httpserver/httpserver.go
@@ -0,0 +1,120 @@
+package httpserver
+
+import (
+ "errors"
+ "net"
+ "net/http"
+ "os"
+ "runtime"
+ "strconv"
+ "syscall"
+
+ "github.com/projectdiscovery/gologger"
+ "github.com/projectdiscovery/simplehttpserver/pkg/sslcert"
+)
+
+type Options struct {
+ Folder string
+ EnableUpload bool
+ ListenAddress string
+ TLS bool
+ Certificate string
+ CertificateKey string
+ CertificateDomain string
+ BasicAuthUsername string
+ BasicAuthPassword string
+ BasicAuthReal string
+ Verbose bool
+}
+
+type HTTPServer struct {
+ options *Options
+ layers http.Handler
+ listener net.Listener
+}
+
+func New(options *Options) (*HTTPServer, error) {
+ var h HTTPServer
+ EnableUpload = options.EnableUpload
+ EnableVerbose = options.Verbose
+ layers := h.loglayer(http.FileServer(http.Dir(options.Folder)))
+ if options.BasicAuthUsername != "" || options.BasicAuthPassword != "" {
+ layers = h.loglayer(h.basicauthlayer(http.FileServer(http.Dir(options.Folder))))
+ }
+
+ return &HTTPServer{options: options, layers: layers}, nil
+}
+
+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
+}
+
+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
+ tlsConfig, err := sslcert.NewTLSConfig(tlsOptions)
+ if err != nil {
+ return err
+ }
+ httpServer := &http.Server{
+ Addr: t.options.ListenAddress,
+ TLSConfig: tlsConfig,
+ }
+ httpServer.Handler = t.layers
+ return httpServer.ListenAndServeTLS("", "")
+ }
+ 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
+}
diff --git a/pkg/httpserver/loglayer.go b/pkg/httpserver/loglayer.go
new file mode 100644
index 0000000..2d84d9a
--- /dev/null
+++ b/pkg/httpserver/loglayer.go
@@ -0,0 +1,69 @@
+package httpserver
+
+import (
+ "bytes"
+ "io/ioutil"
+ "net/http"
+ "net/http/httputil"
+ "path"
+
+ "github.com/projectdiscovery/gologger"
+)
+
+// Convenience globals
+var (
+ EnableUpload bool
+ EnableVerbose bool
+)
+
+func (t *HTTPServer) loglayer(handler http.Handler) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ fullRequest, _ := httputil.DumpRequest(r, true)
+ lrw := newLoggingResponseWriter(w)
+ handler.ServeHTTP(lrw, r)
+
+ // Handles file write if enabled
+ if EnableUpload && r.Method == http.MethodPut {
+ data, err := ioutil.ReadAll(r.Body)
+ if err != nil {
+ gologger.Print().Msgf("%s\n", err)
+ }
+ err = handleUpload(path.Base(r.URL.Path), data)
+ if err != nil {
+ gologger.Print().Msgf("%s\n", err)
+ }
+ }
+
+ if EnableVerbose {
+ headers := new(bytes.Buffer)
+ lrw.Header().Write(headers) //nolint
+ gologger.Print().Msgf("\nRemote Address: %s\n%s\n%s %d %s\n%s\n%s\n", r.RemoteAddr, string(fullRequest), r.Proto, lrw.statusCode, http.StatusText(lrw.statusCode), headers.String(), string(lrw.Data))
+ } else {
+ gologger.Print().Msgf("%s \"%s %s %s\" %d %d", r.RemoteAddr, r.Method, r.URL, r.Proto, lrw.statusCode, len(lrw.Data))
+ }
+ })
+}
+
+type loggingResponseWriter struct {
+ http.ResponseWriter
+ statusCode int
+ Data []byte
+}
+
+func newLoggingResponseWriter(w http.ResponseWriter) *loggingResponseWriter {
+ return &loggingResponseWriter{w, http.StatusOK, []byte{}}
+}
+
+func (lrw *loggingResponseWriter) Write(data []byte) (int, error) {
+ lrw.Data = append(lrw.Data, data...)
+ return lrw.ResponseWriter.Write(data)
+}
+
+func (lrw *loggingResponseWriter) Header() http.Header {
+ return lrw.ResponseWriter.Header()
+}
+
+func (lrw *loggingResponseWriter) WriteHeader(code int) {
+ lrw.statusCode = code
+ lrw.ResponseWriter.WriteHeader(code)
+}
diff --git a/pkg/httpserver/uploadlayer.go b/pkg/httpserver/uploadlayer.go
new file mode 100644
index 0000000..2663fba
--- /dev/null
+++ b/pkg/httpserver/uploadlayer.go
@@ -0,0 +1,7 @@
+package httpserver
+
+import "io/ioutil"
+
+func handleUpload(file string, data []byte) error {
+ return ioutil.WriteFile(file, data, 0655)
+}
diff --git a/pkg/tcpserver/tcpserver.go b/pkg/tcpserver/tcpserver.go
index fc08f03..15be615 100644
--- a/pkg/tcpserver/tcpserver.go
+++ b/pkg/tcpserver/tcpserver.go
@@ -6,6 +6,7 @@ import (
"net"
"time"
+ "github.com/projectdiscovery/gologger"
"github.com/projectdiscovery/simplehttpserver/pkg/sslcert"
"gopkg.in/yaml.v2"
)
@@ -17,6 +18,7 @@ type Options struct {
Key string
Domain string
rules []Rule
+ Verbose bool
}
type TCPServer struct {
@@ -34,6 +36,7 @@ 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
@@ -53,12 +56,16 @@ func (t *TCPServer) handleConnection(conn net.Conn) error {
return err
}
+ gologger.Print().Msgf("%s\n", buf)
+
resp, err := t.BuildResponse(buf)
if err != nil {
return err
}
conn.Write(resp)
+
+ gologger.Print().Msgf("%s\n", resp)
}
}
diff --git a/simplehttpserver.go b/simplehttpserver.go
deleted file mode 100644
index f03f258..0000000
--- a/simplehttpserver.go
+++ /dev/null
@@ -1,233 +0,0 @@
-package main
-
-import (
- "bytes"
- "errors"
- "flag"
- "fmt"
- "io/ioutil"
- "net"
- "net/http"
- "net/http/httputil"
- "os"
- "path"
- "runtime"
- "strconv"
- "strings"
- "syscall"
-
- "github.com/projectdiscovery/gologger"
- "github.com/projectdiscovery/simplehttpserver/pkg/sslcert"
- "github.com/projectdiscovery/simplehttpserver/pkg/tcpserver"
-)
-
-type options struct {
- ListenAddress string
- Folder string
- BasicAuth string
- username string
- password string
- Realm string
- Certificate string
- Key string
- Domain string
- HTTPS bool
- Verbose bool
- Upload bool
- TCP bool
- RulesFile string
- TLS bool
-}
-
-var opts options
-
-func main() {
- flag.StringVar(&opts.ListenAddress, "listen", "0.0.0.0:8000", "Address:Port")
- flag.BoolVar(&opts.TCP, "tcp", false, "TCP Server")
- flag.BoolVar(&opts.TLS, "tls", false, "Enable TCP TLS")
- flag.StringVar(&opts.RulesFile, "rules", "", "Rules yaml file")
- flag.StringVar(&opts.Folder, "path", ".", "Folder")
- flag.BoolVar(&opts.Upload, "upload", false, "Enable upload via PUT")
- flag.BoolVar(&opts.HTTPS, "https", false, "HTTPS")
- flag.StringVar(&opts.Certificate, "cert", "", "Certificate")
- flag.StringVar(&opts.Key, "key", "", "Key")
- flag.StringVar(&opts.Domain, "domain", "local.host", "Domain")
- flag.BoolVar(&opts.Verbose, "v", false, "Verbose")
- flag.StringVar(&opts.BasicAuth, "basic-auth", "", "Basic auth (username:password)")
- flag.StringVar(&opts.Realm, "realm", "Please enter username and password", "Realm")
-
- flag.Parse()
-
- if flag.NArg() > 0 && opts.Folder == "." {
- opts.Folder = flag.Args()[0]
- }
-
- if opts.TCP {
- serverTCP, err := tcpserver.New(tcpserver.Options{Listen: opts.ListenAddress, TLS: opts.TLS, Domain: "local.host"})
- if err != nil {
- gologger.Fatal().Msgf("%s\n", err)
- }
- err = serverTCP.LoadTemplate(opts.RulesFile)
- if err != nil {
- gologger.Fatal().Msgf("%s\n", err)
- }
-
- gologger.Print().Msgf("%s\n", serverTCP.ListenAndServe())
- }
-
- gologger.Print().Msgf("Serving %s on http://%s/...", opts.Folder, opts.ListenAddress)
- layers := loglayer(http.FileServer(http.Dir(opts.Folder)))
- if opts.BasicAuth != "" {
- baTokens := strings.SplitN(opts.BasicAuth, ":", 2)
- if len(baTokens) > 0 {
- opts.username = baTokens[0]
- }
- if len(baTokens) > 1 {
- opts.password = baTokens[1]
- }
- layers = loglayer(basicauthlayer(http.FileServer(http.Dir(opts.Folder))))
- }
- if opts.Upload {
- gologger.Print().Msg("Starting service with Upload enabled")
- }
-retry_listen:
- gologger.Print().Msgf("Serving %s on http://%s/...", opts.Folder, opts.ListenAddress)
- var err error
- if opts.HTTPS {
- if opts.Certificate == "" || opts.Key == "" {
- tlsOptions := sslcert.DefaultOptions
- tlsOptions.Host = opts.Domain
- tlsConfig, err := sslcert.NewTLSConfig(tlsOptions)
- if err != nil {
- gologger.Fatal().Msgf("%s\n", err)
- }
- httpServer := &http.Server{
- Addr: opts.ListenAddress,
- TLSConfig: tlsConfig,
- }
- httpServer.Handler = layers
- gologger.Print().Msgf("%s\n", httpServer.ListenAndServeTLS("", ""))
- } else {
- gologger.Print().Msgf("%s\n", http.ListenAndServeTLS(opts.ListenAddress, opts.Certificate, opts.Key, layers))
- }
- } else {
- err = http.ListenAndServe(opts.ListenAddress, layers)
- }
- if err != nil {
- if isErrorAddressAlreadyInUse(err) {
- gologger.Print().Msgf("Can't listen on %s: %s - retrying with another port\n", opts.ListenAddress, err)
- newListenAddress, err := incPort(opts.ListenAddress)
- if err != nil {
- gologger.Fatal().Msgf("%s\n", err)
- }
- opts.ListenAddress = newListenAddress
- goto retry_listen
- }
- gologger.Print().Msgf("%s\n", err)
- }
-}
-
-func loglayer(handler http.Handler) http.Handler {
- return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- fullRequest, _ := httputil.DumpRequest(r, true)
- lrw := newLoggingResponseWriter(w)
- handler.ServeHTTP(lrw, r)
-
- // Handles file write if enabled
- if opts.Upload && r.Method == http.MethodPut {
- data, err := ioutil.ReadAll(r.Body)
- if err != nil {
- gologger.Print().Msgf("%s\n", err)
- }
- err = handleUpload(path.Base(r.URL.Path), data)
- if err != nil {
- gologger.Print().Msgf("%s\n", err)
- }
- }
-
- if opts.Verbose {
- headers := new(bytes.Buffer)
- lrw.Header().Write(headers) //nolint
- gologger.Print().Msgf("\nRemote Address: %s\n%s\n%s %d %s\n%s\n%s\n", r.RemoteAddr, string(fullRequest), r.Proto, lrw.statusCode, http.StatusText(lrw.statusCode), headers.String(), string(lrw.Data))
- } else {
- gologger.Print().Msgf("%s \"%s %s %s\" %d %d", r.RemoteAddr, r.Method, r.URL, r.Proto, lrw.statusCode, len(lrw.Data))
- }
- })
-}
-
-func basicauthlayer(handler http.Handler) http.HandlerFunc {
- return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- user, pass, ok := r.BasicAuth()
- if !ok || user != opts.username || pass != opts.password {
- w.Header().Set("WWW-Authenticate", fmt.Sprintf("Basic realm=\"%s\"", opts.Realm))
- w.WriteHeader(http.StatusUnauthorized)
- w.Write([]byte("Unauthorized.\n")) //nolint
- return
- }
- handler.ServeHTTP(w, r)
- })
-}
-
-type loggingResponseWriter struct {
- http.ResponseWriter
- statusCode int
- Data []byte
-}
-
-func newLoggingResponseWriter(w http.ResponseWriter) *loggingResponseWriter {
- return &loggingResponseWriter{w, http.StatusOK, []byte{}}
-}
-
-func (lrw *loggingResponseWriter) Write(data []byte) (int, error) {
- lrw.Data = append(lrw.Data, data...)
- return lrw.ResponseWriter.Write(data)
-}
-
-func (lrw *loggingResponseWriter) Header() http.Header {
- return lrw.ResponseWriter.Header()
-}
-
-func (lrw *loggingResponseWriter) WriteHeader(code int) {
- lrw.statusCode = code
- lrw.ResponseWriter.WriteHeader(code)
-}
-
-func handleUpload(file string, data []byte) error {
- return ioutil.WriteFile(file, data, 0655)
-}
-
-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
-}
From ced71943a55da047f29d9b990bdd0a6bab459a11 Mon Sep 17 00:00:00 2001
From: Mzack9999
Date: Fri, 26 Feb 2021 21:11:20 +0100
Subject: [PATCH 27/45] bind logic refactor
---
go.mod | 1 +
go.sum | 2 ++
internal/runner/runner.go | 21 +++++++++++++
pkg/binder/binder.go | 32 +++++++++++++++++++
pkg/httpserver/httpserver.go | 60 ++----------------------------------
5 files changed, 59 insertions(+), 57 deletions(-)
create mode 100644 pkg/binder/binder.go
diff --git a/go.mod b/go.mod
index 2bc0442..f8bb144 100644
--- a/go.mod
+++ b/go.mod
@@ -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
)
diff --git a/go.sum b/go.sum
index bd1e991..6757769 100644
--- a/go.sum
+++ b/go.sum
@@ -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=
diff --git a/internal/runner/runner.go b/internal/runner/runner.go
index a5d5230..94b8c37 100644
--- a/internal/runner/runner.go
+++ b/internal/runner/runner.go
@@ -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"
)
@@ -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\n", r.options.ListenAddress, err, newListenAddress)
+ r.options.ListenAddress = newListenAddress
+ }
+
if r.options.EnableTCP {
serverTCP, err := tcpserver.New(tcpserver.Options{
Listen: r.options.ListenAddress,
@@ -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
}
diff --git a/pkg/binder/binder.go b/pkg/binder/binder.go
new file mode 100644
index 0000000..2a248a1
--- /dev/null
+++ b/pkg/binder/binder.go
@@ -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
+
+}
diff --git a/pkg/httpserver/httpserver.go b/pkg/httpserver/httpserver.go
index 6e817d3..c37355e 100644
--- a/pkg/httpserver/httpserver.go
+++ b/pkg/httpserver/httpserver.go
@@ -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"
)
@@ -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
@@ -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
}
From 254d46196632274f3cc7b6b3a8252d0b7b27d59b Mon Sep 17 00:00:00 2001
From: Mzack9999
Date: Fri, 26 Feb 2021 21:14:27 +0100
Subject: [PATCH 28/45] misc
---
internal/runner/runner.go | 2 +-
pkg/tcpserver/tcpserver.go | 1 -
2 files changed, 1 insertion(+), 2 deletions(-)
diff --git a/internal/runner/runner.go b/internal/runner/runner.go
index 94b8c37..6603d50 100644
--- a/internal/runner/runner.go
+++ b/internal/runner/runner.go
@@ -22,7 +22,7 @@ func New(options *Options) (*Runner, error) {
if err != nil {
return nil, err
}
- gologger.Print().Msgf("Can't listen on %s: %s - Using\n", r.options.ListenAddress, err, newListenAddress)
+ gologger.Print().Msgf("Can't listen on %s: %s - Using %s\n", r.options.ListenAddress, err, newListenAddress)
r.options.ListenAddress = newListenAddress
}
diff --git a/pkg/tcpserver/tcpserver.go b/pkg/tcpserver/tcpserver.go
index 15be615..7d46b3a 100644
--- a/pkg/tcpserver/tcpserver.go
+++ b/pkg/tcpserver/tcpserver.go
@@ -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
From 80f5074a7d0769b32c31af5c78a77821516990c2 Mon Sep 17 00:00:00 2001
From: Mzack9999
Date: Fri, 26 Feb 2021 22:45:27 +0100
Subject: [PATCH 29/45] adding missing files
---
.gitignore | 1 -
cmd/simplehttpserver/simplehttpserver.go | 18 ++++++++++++++++++
2 files changed, 18 insertions(+), 1 deletion(-)
create mode 100644 cmd/simplehttpserver/simplehttpserver.go
diff --git a/.gitignore b/.gitignore
index dabd7a7..b883f1f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1 @@
*.exe
-simplehttpserver
diff --git a/cmd/simplehttpserver/simplehttpserver.go b/cmd/simplehttpserver/simplehttpserver.go
new file mode 100644
index 0000000..0dbbe6c
--- /dev/null
+++ b/cmd/simplehttpserver/simplehttpserver.go
@@ -0,0 +1,18 @@
+package main
+
+import (
+ "github.com/projectdiscovery/gologger"
+ "github.com/projectdiscovery/simplehttpserver/internal/runner"
+)
+
+func main() {
+ // Parse the command line flags and read config files
+ options := runner.ParseOptions()
+ runner, err := runner.New(options)
+ if err != nil {
+ gologger.Fatal().Msgf("Could not create runner: %s\n", err)
+ }
+
+ runner.Run()
+ runner.Close()
+}
From fb9d1df1004215a31b89b5ad47911ca43475613e Mon Sep 17 00:00:00 2001
From: Mzack9999
Date: Fri, 16 Apr 2021 16:06:42 +0200
Subject: [PATCH 30/45] adding common tools to docker
---
Dockerfile | 1 +
1 file changed, 1 insertion(+)
diff --git a/Dockerfile b/Dockerfile
index 4603b20..0919a3c 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -3,6 +3,7 @@ RUN apk add --no-cache git
RUN GO111MODULE=auto go get -u -v github.com/projectdiscovery/simplehttpserver/cmd/simplehttpserver
FROM alpine:latest
+RUN apk add --no-cache bind-tools ca-certificates
COPY --from=builder /go/bin/simplehttpserver /usr/local/bin/
ENTRYPOINT ["simplehttpserver"]
From 49ceaa7165da0d8fe1bb991b1094d0d95b8f17aa Mon Sep 17 00:00:00 2001
From: Mzack9999
Date: Fri, 16 Apr 2021 16:07:06 +0200
Subject: [PATCH 31/45] removing sslcert + deps bump
---
go.mod | 1 +
go.sum | 2 +
pkg/httpserver/httpserver.go | 8 +-
pkg/sslcert/options.go | 21 -----
pkg/sslcert/sslcert.go | 153 -----------------------------------
pkg/sslcert/tlsconfig.go | 19 -----
pkg/tcpserver/tcpserver.go | 2 +-
7 files changed, 7 insertions(+), 199 deletions(-)
delete mode 100644 pkg/sslcert/options.go
delete mode 100644 pkg/sslcert/sslcert.go
delete mode 100644 pkg/sslcert/tlsconfig.go
diff --git a/go.mod b/go.mod
index f8bb144..1d88f80 100644
--- a/go.mod
+++ b/go.mod
@@ -5,5 +5,6 @@ go 1.15
require (
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2
github.com/projectdiscovery/gologger v1.1.4
+ github.com/projectdiscovery/sslcert v0.0.0-20210416140253-8f56bec1bb5e
gopkg.in/yaml.v2 v2.4.0
)
diff --git a/go.sum b/go.sum
index 6757769..aafe4a2 100644
--- a/go.sum
+++ b/go.sum
@@ -25,6 +25,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/projectdiscovery/gologger v1.1.4 h1:qWxGUq7ukHWT849uGPkagPKF3yBPYAsTtMKunQ8O2VI=
github.com/projectdiscovery/gologger v1.1.4/go.mod h1:Bhb6Bdx2PV1nMaFLoXNBmHIU85iROS9y1tBuv7T5pMY=
+github.com/projectdiscovery/sslcert v0.0.0-20210416140253-8f56bec1bb5e h1:IZa08TUGbU7I0HUb9QQt/8wuu2fPZqfnMXwWhtMxei8=
+github.com/projectdiscovery/sslcert v0.0.0-20210416140253-8f56bec1bb5e/go.mod h1:jSp8W5zIkNPxAqVdcoFlfv0K5cqogTe65fMinR0Fvuk=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
diff --git a/pkg/httpserver/httpserver.go b/pkg/httpserver/httpserver.go
index c37355e..958a6e7 100644
--- a/pkg/httpserver/httpserver.go
+++ b/pkg/httpserver/httpserver.go
@@ -1,10 +1,9 @@
package httpserver
import (
- "net"
"net/http"
- "github.com/projectdiscovery/simplehttpserver/pkg/sslcert"
+ "github.com/projectdiscovery/sslcert"
)
type Options struct {
@@ -22,9 +21,8 @@ type Options struct {
}
type HTTPServer struct {
- options *Options
- layers http.Handler
- listener net.Listener
+ options *Options
+ layers http.Handler
}
func New(options *Options) (*HTTPServer, error) {
diff --git a/pkg/sslcert/options.go b/pkg/sslcert/options.go
deleted file mode 100644
index 54cbc0d..0000000
--- a/pkg/sslcert/options.go
+++ /dev/null
@@ -1,21 +0,0 @@
-package sslcert
-
-import "time"
-
-type Options struct {
- Host string // Comma-separated hostnames and IPs to generate a certificate for")
- Organization string
- ValidFrom string // Creation date formatted as Jan 1 15:04:05 2011
- ValidFor time.Duration // 365*24*time.Hour Duration that certificate is valid for
- IsCA bool // whether this cert should be its own Certificate Authority
- RSABits int // 2048 Size of RSA key to generate. Ignored if --ecdsa-curve is set
- EcdsaCurve string // ECDSA curve to use to generate a key. Valid values are P224, P256 (recommended), P384, P521
- Ed25519Key bool // Generate an Ed25519 key
-}
-
-var DefaultOptions = Options{
- ValidFor: time.Duration(365 * 24 * time.Hour),
- IsCA: false,
- RSABits: 2048,
- Organization: "Acme Co",
-}
diff --git a/pkg/sslcert/sslcert.go b/pkg/sslcert/sslcert.go
deleted file mode 100644
index 862ee21..0000000
--- a/pkg/sslcert/sslcert.go
+++ /dev/null
@@ -1,153 +0,0 @@
-// Package sslcert contains a reworked version of https://golang.org/src/crypto/tls/generate_cert.go
-package sslcert
-
-import (
- "bufio"
- "bytes"
- "crypto/ecdsa"
- "crypto/ed25519"
- "crypto/elliptic"
- "crypto/rand"
- "crypto/rsa"
- "crypto/x509"
- "crypto/x509/pkix"
- "encoding/pem"
- "errors"
- "fmt"
- "math/big"
- "net"
- "strings"
- "time"
-)
-
-func pubKey(priv interface{}) interface{} {
- switch k := priv.(type) {
- case *rsa.PrivateKey:
- return &k.PublicKey
- case *ecdsa.PrivateKey:
- return &k.PublicKey
- case ed25519.PrivateKey:
- return k.Public().(ed25519.PublicKey)
- default:
- return nil
- }
-}
-
-func Generate(options Options) (privateKey, publicKey []byte, err error) {
- if options.Host == "" {
- return nil, nil, errors.New("Empty host value")
- }
-
- var priv interface{}
- switch options.EcdsaCurve {
- case "":
- if options.Ed25519Key {
- _, priv, err = ed25519.GenerateKey(rand.Reader)
- } else {
- priv, err = rsa.GenerateKey(rand.Reader, options.RSABits)
- }
- case "P224":
- priv, err = ecdsa.GenerateKey(elliptic.P224(), rand.Reader)
- case "P256":
- priv, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
- case "P384":
- priv, err = ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
- case "P521":
- priv, err = ecdsa.GenerateKey(elliptic.P521(), rand.Reader)
- default:
- err = fmt.Errorf("Unrecognized elliptic curve: %q", options.EcdsaCurve)
- return
- }
- if err != nil {
- err = fmt.Errorf("Failed to generate private key: %v", err)
- return
- }
-
- // ECDSA, ED25519 and RSA subject keys should have the DigitalSignature
- // KeyUsage bits set in the x509.Certificate template
- keyUsage := x509.KeyUsageDigitalSignature
- // Only RSA subject keys should have the KeyEncipherment KeyUsage bits set. In
- // the context of TLS this KeyUsage is particular to RSA key exchange and
- // authentication.
- if _, isRSA := priv.(*rsa.PrivateKey); isRSA {
- keyUsage |= x509.KeyUsageKeyEncipherment
- }
-
- var notBefore time.Time
- if len(options.ValidFrom) == 0 {
- notBefore = time.Now()
- } else {
- notBefore, err = time.Parse("Jan 2 15:04:05 2006", options.ValidFrom)
- if err != nil {
- err = fmt.Errorf("Failed to parse creation date: %v", err)
- return
- }
- }
-
- notAfter := notBefore.Add(options.ValidFor)
-
- serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
- serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
- if err != nil {
- err = fmt.Errorf("Failed to generate serial number: %v", err)
- return
- }
-
- template := x509.Certificate{
- SerialNumber: serialNumber,
- Subject: pkix.Name{
- Organization: []string{options.Organization},
- },
- NotBefore: notBefore,
- NotAfter: notAfter,
-
- KeyUsage: keyUsage,
- ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
- BasicConstraintsValid: true,
- }
-
- hosts := strings.Split(options.Host, ",")
- for _, h := range hosts {
- if ip := net.ParseIP(h); ip != nil {
- template.IPAddresses = append(template.IPAddresses, ip)
- } else {
- template.DNSNames = append(template.DNSNames, h)
- }
- }
-
- if options.IsCA {
- template.IsCA = true
- template.KeyUsage |= x509.KeyUsageCertSign
- }
-
- derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, pubKey(priv), priv)
- if err != nil {
- err = fmt.Errorf("Failed to create certificate: %v", err)
- return
- }
-
- var pubKeyBuf bytes.Buffer
- pubKeyBufb := bufio.NewWriter(&pubKeyBuf)
- err = pem.Encode(pubKeyBufb, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
- if err != nil {
- err = fmt.Errorf("Failed to write data to cert.pem: %v", err)
- return
- }
- pubKeyBufb.Flush()
-
- privBytes, err := x509.MarshalPKCS8PrivateKey(priv)
- if err != nil {
- err = fmt.Errorf("Unable to marshal private key: %v", err)
- return
- }
- var privKeyBuf bytes.Buffer
- privKeyBufb := bufio.NewWriter(&privKeyBuf)
- err = pem.Encode(privKeyBufb, &pem.Block{Type: "PRIVATE KEY", Bytes: privBytes})
- if err != nil {
- err = fmt.Errorf("Failed to write data to key.pem: %v", err)
- return
- }
- privKeyBufb.Flush()
-
- return pubKeyBuf.Bytes(), privKeyBuf.Bytes(), nil
-}
diff --git a/pkg/sslcert/tlsconfig.go b/pkg/sslcert/tlsconfig.go
deleted file mode 100644
index e2bbe92..0000000
--- a/pkg/sslcert/tlsconfig.go
+++ /dev/null
@@ -1,19 +0,0 @@
-package sslcert
-
-import (
- "crypto/tls"
-)
-
-func NewTLSConfig(options Options) (*tls.Config, error) {
- pubKey, privKey, err := Generate(options)
- if err != nil {
- return nil, err
- }
-
- cert, err := tls.X509KeyPair(pubKey, privKey)
- if err != nil {
- return nil, err
- }
-
- return &tls.Config{Certificates: []tls.Certificate{cert}}, nil
-}
diff --git a/pkg/tcpserver/tcpserver.go b/pkg/tcpserver/tcpserver.go
index 7d46b3a..f78f876 100644
--- a/pkg/tcpserver/tcpserver.go
+++ b/pkg/tcpserver/tcpserver.go
@@ -7,7 +7,7 @@ import (
"time"
"github.com/projectdiscovery/gologger"
- "github.com/projectdiscovery/simplehttpserver/pkg/sslcert"
+ "github.com/projectdiscovery/sslcert"
"gopkg.in/yaml.v2"
)
From d068ebe21e9a746612bc357a8cda8fa29d7720c6 Mon Sep 17 00:00:00 2001
From: Mzack9999
Date: Fri, 16 Apr 2021 16:40:25 +0200
Subject: [PATCH 32/45] using go 1.14
---
go.mod | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/go.mod b/go.mod
index 1d88f80..f4c4a9d 100644
--- a/go.mod
+++ b/go.mod
@@ -1,6 +1,6 @@
module github.com/projectdiscovery/simplehttpserver
-go 1.15
+go 1.14
require (
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2
From e55d3feac94109c6eded54b0a6a98edd7933921e Mon Sep 17 00:00:00 2001
From: Mzack9999
Date: Fri, 16 Apr 2021 16:41:26 +0200
Subject: [PATCH 33/45] updated readme
---
README.md | 119 +++++++++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 109 insertions(+), 10 deletions(-)
diff --git a/README.md b/README.md
index f88164f..00daf9c 100644
--- a/README.md
+++ b/README.md
@@ -11,14 +11,14 @@
[](https://hub.docker.com/r/projectdiscovery/simplehttpserver)
[](https://discord.gg/KECAGdH)
-simplehttpserver is a go enhanced version of the well known python simplehttpserver.
+simplehttpserver is a go enhanced version of the well known python simplehttpserver with in addition a fully customizable TCP server, both supporting TLS.
# Resources
- [Features](#features)
- [Usage](#usage)
- [Installation Instructions](#installation-instructions)
-- [Running simplehttpserver](#running-simplehttpserver-in-the-current-folder )
+- [Running simplehttpserver](#running-simplehttpserver-in-the-current-folder)
- [Thanks](#thanks)
# Features
@@ -28,9 +28,11 @@ simplehttpserver is a go enhanced version of the well known python simplehttpser
- - File server in arbitrary directory
- - Full request/response dump
- - Configurable ip address and listening port
+- HTTPS support
+- File server in arbitrary directory
+- Full request/response dump
+- Configurable ip address and listening port
+- Configurable HTTP/TCP server with customizable response via YAML template
# Installation Instructions
@@ -70,11 +72,23 @@ simplehttpserver -h
This will display help for the tool. Here are all the switches it supports.
-| Flag | Description | Example |
-| ------ | ---------------------------------------------------- | --------------------------------------- |
-| listen | Configure listening ip:port (default 127.0.0.1:8000) | simplehttpserver -listen 127.0.0.1:8000 |
-| path | Fileserver folder (default current directory) | simplehttpserver -path /var/docs |
-| v | Verbose (dump request/response, default false) | simplehttpserver -v |
+| Flag | Description | Example |
+| ----------- | -------------------------------------------------------------------- | ------------------------------------------------- |
+| listen | Configure listening ip:port (default 127.0.0.1:8000) | simplehttpserver -listen 127.0.0.1:8000 |
+| path | Fileserver folder (default current directory) | simplehttpserver -path /var/docs |
+| verbose | Verbose (dump request/response, default false) | simplehttpserver -v |
+| tcp | TCP server (default 127.0.0.1:8000) | simplehttpserver -tcp 127.0.0.1:8000 |
+| tls | Enable TLS for TCP server | simplehttpserver -tls |
+| rules | File containing yaml rules | simplehttpserver -rules rule.yaml | |
+| upload | Enable file upload in case of http server | simplehttpserver -upload |
+| https | Enable HTTPS in case of http server | simplehttpserver -https |
+| cert | HTTPS/TLS certificate (self generated if not specified) | simplehttpserver -cert cert.pem |
+| key | HTTPS/TLS certificate private key (self generated if not specified) | simplehttpserver -key cert.key |
+| domain | Domain name to use for the self-generated certificate | simplehttpserver -domain projectdiscovery.io |
+| basic-auth | Basic auth (username:password) | simplehttpserver -basic-auth user:password |
+| realm | Basic auth message | simplehttpserver -realm "insert the credentials" |
+| version | Show version | simplehttpserver -version |
+| silent | Show only results | simplehttpserver -silent |
### Running simplehttpserver in the current folder
@@ -87,6 +101,91 @@ This will run the tool exposing the current directory on port 8000
2021/01/11 21:41:15 [::1]:50181 "GET /favicon.ico HTTP/1.1" 404 19
```
+### Running simplehttpserver in the current folder with HTTPS
+
+This will run the tool exposing the current directory on port 8000 over HTTPS with user provided certificate:
+
+```sh
+▶ simplehttpserver -https -cert cert.pen -key cert.key
+2021/01/11 21:40:48 Serving . on http://0.0.0.0:8000/...
+2021/01/11 21:41:15 [::1]:50181 "GET / HTTP/1.1" 200 383
+2021/01/11 21:41:15 [::1]:50181 "GET /favicon.ico HTTP/1.1" 404 19
+```
+
+Instead, to run with self-signed certificate and specific domain name:
+```sh
+▶ simplehttpserver -https -domain localhost
+2021/01/11 21:40:48 Serving . on http://0.0.0.0:8000/...
+2021/01/11 21:41:15 [::1]:50181 "GET / HTTP/1.1" 200 383
+2021/01/11 21:41:15 [::1]:50181 "GET /favicon.ico HTTP/1.1" 404 19
+```
+
+### Running simplehttpserver with basic auth and file upload
+
+This will run the tool and will request the user to enter username and password before authorizing file uploads
+
+```sh
+▶ simplehttpserver -basic-auth root:root -upload
+2021/01/11 21:40:48 Serving . on http://0.0.0.0:8000/...
+```
+
+To upload files use the following curl request with basic auth header:
+```sh
+▶ curl -v --user 'root:root' --upload-file file.txt http://localhost:8000/file.txt
+```
+
+### Running TCP server with custom responses
+
+This will run the tool as TLS TCP server and enable custom responses based on YAML templates:
+
+```sh
+▶ simplehttpserver -rule rules.yaml -tcp -tls -domain localhost
+```
+
+The rules are written as follows:
+```yaml
+rules:
+ - match: regex
+ response: response data
+```
+
+For example to handle two different paths simulating an HTTP server or SMTP commands:
+```yaml
+rules:
+ # HTTP Requests
+ - match: GET /path1
+ response: |
+ HTTP/1.0 200 OK
+ Server: httpd/2.0
+ x-frame-options: SAMEORIGIN
+ x-xss-protection: 1; mode=block
+ Date: Fri, 16 Apr 2021 14:30:32 GMT
+ Content-Type: text/html
+ Connection: close
+
+
+
+ - match: GET /path2
+ response: |
+ HTTP/1.0 404 OK
+ Server: httpd/2.0
+
+ Not found
+ # SMTP Commands
+ - match: "EHLO example.com"
+ response: |
+ 250-localhost Nice to meet you, [127.0.0.1]
+ 250-PIPELINING
+ 250-8BITMIME
+ 250-SMTPUTF8
+ 250-AUTH LOGIN PLAIN
+ 250 STARTTLS
+ - match: "MAIL FROM: "
+ response: 250 Accepted
+ - match: "RCPT TO: "
+ response: 250 Accepted
+```
+
# Thanks
simplehttpserver is made with 🖤 by the [projectdiscovery](https://projectdiscovery.io) team. Community contributions have made the project what it is. See the **[Thanks.md](https://github.com/projectdiscovery/simplehttpserver/blob/master/THANKS.md)** file for more details.
From ef3b178ae32b8499bc25fb38933e31d8ed168394 Mon Sep 17 00:00:00 2001
From: sandeep <8293321+ehsandeep@users.noreply.github.com>
Date: Fri, 16 Apr 2021 22:08:06 +0530
Subject: [PATCH 34/45] Update build.yaml
---
.github/workflows/build.yaml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml
index 11d1658..008bca6 100644
--- a/.github/workflows/build.yaml
+++ b/.github/workflows/build.yaml
@@ -32,8 +32,8 @@ jobs:
- name: Test
run: go test .
- working-directory: cmd/simplehttpserver/
+ working-directory: .
- name: Build
run: go build .
- working-directory: cmd/simplehttpserver/
+ working-directory: .
From bce92ad125f31668a58d4bcdff509a061f04d1d0 Mon Sep 17 00:00:00 2001
From: sandeep <8293321+ehsandeep@users.noreply.github.com>
Date: Fri, 16 Apr 2021 22:15:35 +0530
Subject: [PATCH 35/45] reverting working-directory
---
.github/workflows/build.yaml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml
index 008bca6..4179b91 100644
--- a/.github/workflows/build.yaml
+++ b/.github/workflows/build.yaml
@@ -32,8 +32,8 @@ jobs:
- name: Test
run: go test .
- working-directory: .
+ working-directory: cmd/simplehttpserver
- name: Build
run: go build .
- working-directory: .
+ working-directory: cmd/simplehttpserver/
From 566a82a76a360d0dce6cac9c479041d86a302612 Mon Sep 17 00:00:00 2001
From: Mzack9999
Date: Fri, 16 Apr 2021 19:09:45 +0200
Subject: [PATCH 36/45] adding absolute path
---
internal/runner/options.go | 9 +++++++++
internal/runner/runner.go | 4 ++--
2 files changed, 11 insertions(+), 2 deletions(-)
diff --git a/internal/runner/options.go b/internal/runner/options.go
index 3170cd3..9104c4a 100644
--- a/internal/runner/options.go
+++ b/internal/runner/options.go
@@ -3,6 +3,7 @@ package runner
import (
"flag"
"os"
+ "path/filepath"
"strings"
"github.com/projectdiscovery/gologger"
@@ -91,3 +92,11 @@ func (options *Options) configureOutput() {
gologger.DefaultLogger.SetMaxLevel(levels.LevelSilent)
}
}
+
+func (o Options) FolderAbsPath() string {
+ abspath, err := filepath.Abs(o.Folder)
+ if err != nil {
+ return o.Folder
+ }
+ return abspath
+}
diff --git a/internal/runner/runner.go b/internal/runner/runner.go
index 6603d50..820dc51 100644
--- a/internal/runner/runner.go
+++ b/internal/runner/runner.go
@@ -72,11 +72,11 @@ func (r *Runner) Run() error {
}
if r.options.HTTPS {
- gologger.Print().Msgf("Serving %s on https://%s/...", r.options.Folder, r.options.ListenAddress)
+ gologger.Print().Msgf("Serving %s on https://%s/", r.options.FolderAbsPath(), r.options.ListenAddress)
return r.httpServer.ListenAndServeTLS()
}
- gologger.Print().Msgf("Serving %s on http://%s/...", r.options.Folder, r.options.ListenAddress)
+ gologger.Print().Msgf("Serving %s on http://%s/", r.options.FolderAbsPath(), r.options.ListenAddress)
return r.httpServer.ListenAndServe()
}
From 1fe30e15f17c64dc45e59b840512b1c8c78b38d8 Mon Sep 17 00:00:00 2001
From: Mzack9999
Date: Fri, 16 Apr 2021 19:19:24 +0200
Subject: [PATCH 37/45] adding comments
---
cmd/simplehttpserver/simplehttpserver.go | 6 +++---
internal/runner/options.go | 1 +
internal/runner/runner.go | 3 +++
pkg/binder/binder.go | 2 ++
pkg/httpserver/httpserver.go | 6 ++++++
pkg/httpserver/loglayer.go | 3 +++
pkg/tcpserver/responseengine.go | 3 ++-
pkg/tcpserver/rule.go | 5 ++++-
pkg/tcpserver/tcpserver.go | 7 +++++++
9 files changed, 31 insertions(+), 5 deletions(-)
diff --git a/cmd/simplehttpserver/simplehttpserver.go b/cmd/simplehttpserver/simplehttpserver.go
index 0dbbe6c..36ae61d 100644
--- a/cmd/simplehttpserver/simplehttpserver.go
+++ b/cmd/simplehttpserver/simplehttpserver.go
@@ -8,11 +8,11 @@ import (
func main() {
// Parse the command line flags and read config files
options := runner.ParseOptions()
- runner, err := runner.New(options)
+ r, err := runner.New(options)
if err != nil {
gologger.Fatal().Msgf("Could not create runner: %s\n", err)
}
- runner.Run()
- runner.Close()
+ r.Run()
+ defer r.Close()
}
diff --git a/internal/runner/options.go b/internal/runner/options.go
index 9104c4a..6c8e1f9 100644
--- a/internal/runner/options.go
+++ b/internal/runner/options.go
@@ -93,6 +93,7 @@ func (options *Options) configureOutput() {
}
}
+// FolderAbsPath of the fileserver folder
func (o Options) FolderAbsPath() string {
abspath, err := filepath.Abs(o.Folder)
if err != nil {
diff --git a/internal/runner/runner.go b/internal/runner/runner.go
index 820dc51..653cbed 100644
--- a/internal/runner/runner.go
+++ b/internal/runner/runner.go
@@ -14,6 +14,7 @@ type Runner struct {
httpServer *httpserver.HTTPServer
}
+// New instance of runner
func New(options *Options) (*Runner, error) {
r := Runner{options: options}
// Check if the process can listen on the specified ip:port
@@ -65,6 +66,7 @@ func New(options *Options) (*Runner, error) {
return &r, nil
}
+// Run logic
func (r *Runner) Run() error {
if r.options.EnableTCP {
gologger.Print().Msgf("Serving TCP rule based server on tcp://%s", r.options.ListenAddress)
@@ -80,6 +82,7 @@ func (r *Runner) Run() error {
return r.httpServer.ListenAndServe()
}
+// Close the listening services
func (r *Runner) Close() error {
if r.serverTCP != nil {
r.serverTCP.Close()
diff --git a/pkg/binder/binder.go b/pkg/binder/binder.go
index 2a248a1..a530cf1 100644
--- a/pkg/binder/binder.go
+++ b/pkg/binder/binder.go
@@ -7,6 +7,7 @@ import (
"github.com/phayes/freeport"
)
+// CanListenOn the specified address
func CanListenOn(address string) bool {
listener, err := net.Listen("tcp4", address)
if err != nil {
@@ -16,6 +17,7 @@ func CanListenOn(address string) bool {
return true
}
+// GetRandomListenAddress from the specified one
func GetRandomListenAddress(currentAddress string) (string, error) {
addrOrig, _, err := net.SplitHostPort(currentAddress)
if err != nil {
diff --git a/pkg/httpserver/httpserver.go b/pkg/httpserver/httpserver.go
index 958a6e7..1747017 100644
--- a/pkg/httpserver/httpserver.go
+++ b/pkg/httpserver/httpserver.go
@@ -6,6 +6,7 @@ import (
"github.com/projectdiscovery/sslcert"
)
+// Options of the http server
type Options struct {
Folder string
EnableUpload bool
@@ -20,11 +21,13 @@ type Options struct {
Verbose bool
}
+// HTTPServer instance
type HTTPServer struct {
options *Options
layers http.Handler
}
+// New http server instance with options
func New(options *Options) (*HTTPServer, error) {
var h HTTPServer
EnableUpload = options.EnableUpload
@@ -37,10 +40,12 @@ func New(options *Options) (*HTTPServer, error) {
return &HTTPServer{options: options, layers: layers}, nil
}
+// ListenAndServe requests over http
func (t *HTTPServer) ListenAndServe() error {
return http.ListenAndServe(t.options.ListenAddress, t.layers)
}
+// ListenAndServeTLS requests over https
func (t *HTTPServer) ListenAndServeTLS() error {
if t.options.Certificate == "" || t.options.CertificateKey == "" {
tlsOptions := sslcert.DefaultOptions
@@ -59,6 +64,7 @@ func (t *HTTPServer) ListenAndServeTLS() error {
return http.ListenAndServeTLS(t.options.ListenAddress, t.options.Certificate, t.options.CertificateKey, t.layers)
}
+// Close the service
func (t *HTTPServer) Close() error {
return nil
}
diff --git a/pkg/httpserver/loglayer.go b/pkg/httpserver/loglayer.go
index 2d84d9a..1e64b8f 100644
--- a/pkg/httpserver/loglayer.go
+++ b/pkg/httpserver/loglayer.go
@@ -54,15 +54,18 @@ func newLoggingResponseWriter(w http.ResponseWriter) *loggingResponseWriter {
return &loggingResponseWriter{w, http.StatusOK, []byte{}}
}
+// Write the data
func (lrw *loggingResponseWriter) Write(data []byte) (int, error) {
lrw.Data = append(lrw.Data, data...)
return lrw.ResponseWriter.Write(data)
}
+// Header of the response
func (lrw *loggingResponseWriter) Header() http.Header {
return lrw.ResponseWriter.Header()
}
+// WriteHeader status code
func (lrw *loggingResponseWriter) WriteHeader(code int) {
lrw.statusCode = code
lrw.ResponseWriter.WriteHeader(code)
diff --git a/pkg/tcpserver/responseengine.go b/pkg/tcpserver/responseengine.go
index c3286f8..ec15da0 100644
--- a/pkg/tcpserver/responseengine.go
+++ b/pkg/tcpserver/responseengine.go
@@ -4,6 +4,7 @@ import (
"errors"
)
+// BuildResponse according to rules
func (t *TCPServer) BuildResponse(data []byte) ([]byte, error) {
// Process all the rules
for _, rule := range t.options.rules {
@@ -11,5 +12,5 @@ func (t *TCPServer) BuildResponse(data []byte) ([]byte, error) {
return []byte(rule.Response), nil
}
}
- return nil, errors.New("No matched rule")
+ return nil, errors.New("no matched rule")
}
diff --git a/pkg/tcpserver/rule.go b/pkg/tcpserver/rule.go
index ba31839..903331b 100644
--- a/pkg/tcpserver/rule.go
+++ b/pkg/tcpserver/rule.go
@@ -2,17 +2,20 @@ package tcpserver
import "regexp"
+// RulesConfiguration from yaml
type RulesConfiguration struct {
Rules []Rule `yaml:"rules"`
}
+// Rule to apply to various requests
type Rule struct {
Match string `yaml:"match,omitempty"`
matchRegex *regexp.Regexp
Response string `yaml:"response,omitempty"`
}
-func NewRule(match string, response string) (*Rule, error) {
+// NewRule from model
+func NewRule(match, response string) (*Rule, error) {
regxp, err := regexp.Compile(match)
if err != nil {
return nil, err
diff --git a/pkg/tcpserver/tcpserver.go b/pkg/tcpserver/tcpserver.go
index f78f876..7bff39e 100644
--- a/pkg/tcpserver/tcpserver.go
+++ b/pkg/tcpserver/tcpserver.go
@@ -11,6 +11,7 @@ import (
"gopkg.in/yaml.v2"
)
+// Options of the tcp server
type Options struct {
Listen string
TLS bool
@@ -21,20 +22,24 @@ type Options struct {
Verbose bool
}
+// TCPServer instance
type TCPServer struct {
options Options
listener net.Listener
}
+// New tcp server instance with specified options
func New(options Options) (*TCPServer, error) {
return &TCPServer{options: options}, nil
}
+// AddRule to the server
func (t *TCPServer) AddRule(rule Rule) error {
t.options.rules = append(t.options.rules, rule)
return nil
}
+// ListenAndServe requests
func (t *TCPServer) ListenAndServe() error {
listener, err := net.Listen("tcp4", t.options.Listen)
if err != nil {
@@ -68,6 +73,7 @@ func (t *TCPServer) handleConnection(conn net.Conn) error {
}
}
+// ListenAndServe requests over tls
func (t *TCPServer) ListenAndServeTLS() error {
var tlsConfig *tls.Config
if t.options.Certificate != "" && t.options.Key != "" {
@@ -108,6 +114,7 @@ func (t *TCPServer) Close() error {
return t.listener.Close()
}
+// LoadTemplate from yaml
func (t *TCPServer) LoadTemplate(templatePath string) error {
var config RulesConfiguration
yamlFile, err := ioutil.ReadFile(templatePath)
From b0911c1316fb5c187fe71b1f5372af0372b65852 Mon Sep 17 00:00:00 2001
From: Mzack9999
Date: Fri, 16 Apr 2021 19:30:13 +0200
Subject: [PATCH 38/45] adding missing error checks
---
cmd/simplehttpserver/simplehttpserver.go | 4 +++-
internal/runner/options.go | 3 ++-
internal/runner/runner.go | 8 ++++++--
pkg/binder/binder.go | 5 ++++-
pkg/tcpserver/tcpserver.go | 11 ++++++++---
5 files changed, 23 insertions(+), 8 deletions(-)
diff --git a/cmd/simplehttpserver/simplehttpserver.go b/cmd/simplehttpserver/simplehttpserver.go
index 36ae61d..9d37de8 100644
--- a/cmd/simplehttpserver/simplehttpserver.go
+++ b/cmd/simplehttpserver/simplehttpserver.go
@@ -13,6 +13,8 @@ func main() {
gologger.Fatal().Msgf("Could not create runner: %s\n", err)
}
- r.Run()
+ if err := r.Run(); err != nil {
+ gologger.Info().Msgf("%s\n", err)
+ }
defer r.Close()
}
diff --git a/internal/runner/options.go b/internal/runner/options.go
index 6c8e1f9..0b5e587 100644
--- a/internal/runner/options.go
+++ b/internal/runner/options.go
@@ -10,6 +10,7 @@ import (
"github.com/projectdiscovery/gologger/levels"
)
+// Options of the tool
type Options struct {
ListenAddress string
Folder string
@@ -94,7 +95,7 @@ func (options *Options) configureOutput() {
}
// FolderAbsPath of the fileserver folder
-func (o Options) FolderAbsPath() string {
+func (o *Options) FolderAbsPath() string {
abspath, err := filepath.Abs(o.Folder)
if err != nil {
return o.Folder
diff --git a/internal/runner/runner.go b/internal/runner/runner.go
index 653cbed..4bda588 100644
--- a/internal/runner/runner.go
+++ b/internal/runner/runner.go
@@ -85,10 +85,14 @@ func (r *Runner) Run() error {
// Close the listening services
func (r *Runner) Close() error {
if r.serverTCP != nil {
- r.serverTCP.Close()
+ if err := r.serverTCP.Close(); err != nil {
+ return err
+ }
}
if r.httpServer != nil {
- r.httpServer.Close()
+ if err := r.httpServer.Close(); err != nil {
+ return err
+ }
}
return nil
}
diff --git a/pkg/binder/binder.go b/pkg/binder/binder.go
index a530cf1..88a051b 100644
--- a/pkg/binder/binder.go
+++ b/pkg/binder/binder.go
@@ -5,6 +5,7 @@ import (
"net"
"github.com/phayes/freeport"
+ "github.com/projectdiscovery/gologger"
)
// CanListenOn the specified address
@@ -13,7 +14,9 @@ func CanListenOn(address string) bool {
if err != nil {
return false
}
- defer listener.Close()
+ if err := listener.Close(); err != nil {
+ gologger.Info().Msgf("%s\n", err)
+ }
return true
}
diff --git a/pkg/tcpserver/tcpserver.go b/pkg/tcpserver/tcpserver.go
index 7bff39e..dfcb18b 100644
--- a/pkg/tcpserver/tcpserver.go
+++ b/pkg/tcpserver/tcpserver.go
@@ -54,7 +54,9 @@ func (t *TCPServer) handleConnection(conn net.Conn) error {
buf := make([]byte, 4096)
for {
- conn.SetReadDeadline(time.Now().Add(time.Duration(5 * time.Second)))
+ if err := conn.SetReadDeadline(time.Now().Add(time.Duration(5 * time.Second))); err != nil {
+ gologger.Info().Msgf("%s\n", err)
+ }
_, err := conn.Read(buf)
if err != nil {
return err
@@ -67,7 +69,9 @@ func (t *TCPServer) handleConnection(conn net.Conn) error {
return err
}
- conn.Write(resp)
+ if _, err := conn.Write(resp); err != nil {
+ gologger.Info().Msgf("%s\n", err)
+ }
gologger.Print().Msgf("%s\n", resp)
}
@@ -106,10 +110,11 @@ func (t *TCPServer) run() error {
if err != nil {
return err
}
- go t.handleConnection(c)
+ go t.handleConnection(c) //nolint
}
}
+// Close the service
func (t *TCPServer) Close() error {
return t.listener.Close()
}
From 309e6bc1170114b3bb80ddb5e403cce4bd77dc0b Mon Sep 17 00:00:00 2001
From: Mzack9999
Date: Fri, 16 Apr 2021 19:33:04 +0200
Subject: [PATCH 39/45] adding missing go docs
---
pkg/binder/doc.go | 2 ++
pkg/httpserver/doc.go | 2 ++
pkg/tcpserver/doc.go | 2 ++
3 files changed, 6 insertions(+)
create mode 100644 pkg/binder/doc.go
create mode 100644 pkg/httpserver/doc.go
create mode 100644 pkg/tcpserver/doc.go
diff --git a/pkg/binder/doc.go b/pkg/binder/doc.go
new file mode 100644
index 0000000..709dc10
--- /dev/null
+++ b/pkg/binder/doc.go
@@ -0,0 +1,2 @@
+// Package binder contains binding helpers
+package binder
diff --git a/pkg/httpserver/doc.go b/pkg/httpserver/doc.go
new file mode 100644
index 0000000..5344c9f
--- /dev/null
+++ b/pkg/httpserver/doc.go
@@ -0,0 +1,2 @@
+// Package httpserver contains the http server logic
+package httpserver
diff --git a/pkg/tcpserver/doc.go b/pkg/tcpserver/doc.go
new file mode 100644
index 0000000..4ab6d69
--- /dev/null
+++ b/pkg/tcpserver/doc.go
@@ -0,0 +1,2 @@
+// Package tcpserver contains the tcp server logic
+package tcpserver
From 89bbfaac877c637c32f56dc98d2d3a6ece77c9b9 Mon Sep 17 00:00:00 2001
From: mzack
Date: Fri, 16 Apr 2021 20:10:40 +0200
Subject: [PATCH 40/45] fixing misc lint errors
---
.golangci.yml | 6 +-----
cmd/simplehttpserver/simplehttpserver.go | 2 +-
internal/runner/options.go | 6 +++---
internal/runner/runner.go | 2 +-
pkg/binder/binder.go | 1 -
pkg/tcpserver/tcpserver.go | 12 +++++++-----
6 files changed, 13 insertions(+), 16 deletions(-)
diff --git a/.golangci.yml b/.golangci.yml
index d5e9089..31b66f3 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -41,8 +41,6 @@ linters-settings:
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Fatalf
# lll:
# line-length: 140
- maligned:
- suggest-new: true
misspell:
locale: US
nolintlint:
@@ -73,14 +71,12 @@ linters:
- gosimple
- govet
- ineffassign
- - interfacer
- - maligned
- misspell
- nakedret
- noctx
- nolintlint
- rowserrcheck
- - scopelint
+ - exportloopref
- staticcheck
- structcheck
- stylecheck
diff --git a/cmd/simplehttpserver/simplehttpserver.go b/cmd/simplehttpserver/simplehttpserver.go
index 9d37de8..ed82b40 100644
--- a/cmd/simplehttpserver/simplehttpserver.go
+++ b/cmd/simplehttpserver/simplehttpserver.go
@@ -16,5 +16,5 @@ func main() {
if err := r.Run(); err != nil {
gologger.Info().Msgf("%s\n", err)
}
- defer r.Close()
+ defer r.Close() //nolint
}
diff --git a/internal/runner/options.go b/internal/runner/options.go
index 0b5e587..bf69db3 100644
--- a/internal/runner/options.go
+++ b/internal/runner/options.go
@@ -95,10 +95,10 @@ func (options *Options) configureOutput() {
}
// FolderAbsPath of the fileserver folder
-func (o *Options) FolderAbsPath() string {
- abspath, err := filepath.Abs(o.Folder)
+func (options *Options) FolderAbsPath() string {
+ abspath, err := filepath.Abs(options.Folder)
if err != nil {
- return o.Folder
+ return options.Folder
}
return abspath
}
diff --git a/internal/runner/runner.go b/internal/runner/runner.go
index 4bda588..7d69e25 100644
--- a/internal/runner/runner.go
+++ b/internal/runner/runner.go
@@ -28,7 +28,7 @@ func New(options *Options) (*Runner, error) {
}
if r.options.EnableTCP {
- serverTCP, err := tcpserver.New(tcpserver.Options{
+ serverTCP, err := tcpserver.New(&tcpserver.Options{
Listen: r.options.ListenAddress,
TLS: r.options.TCPWithTLS,
Domain: "local.host",
diff --git a/pkg/binder/binder.go b/pkg/binder/binder.go
index 88a051b..549e9d9 100644
--- a/pkg/binder/binder.go
+++ b/pkg/binder/binder.go
@@ -33,5 +33,4 @@ func GetRandomListenAddress(currentAddress string) (string, error) {
}
return net.JoinHostPort(addrOrig, fmt.Sprintf("%d", newPort)), nil
-
}
diff --git a/pkg/tcpserver/tcpserver.go b/pkg/tcpserver/tcpserver.go
index dfcb18b..876fbb4 100644
--- a/pkg/tcpserver/tcpserver.go
+++ b/pkg/tcpserver/tcpserver.go
@@ -11,6 +11,8 @@ import (
"gopkg.in/yaml.v2"
)
+const readTimeout = 5
+
// Options of the tcp server
type Options struct {
Listen string
@@ -24,12 +26,12 @@ type Options struct {
// TCPServer instance
type TCPServer struct {
- options Options
+ options *Options
listener net.Listener
}
// New tcp server instance with specified options
-func New(options Options) (*TCPServer, error) {
+func New(options *Options) (*TCPServer, error) {
return &TCPServer{options: options}, nil
}
@@ -50,11 +52,11 @@ func (t *TCPServer) ListenAndServe() error {
}
func (t *TCPServer) handleConnection(conn net.Conn) error {
- defer conn.Close()
+ defer conn.Close() //nolint
buf := make([]byte, 4096)
for {
- if err := conn.SetReadDeadline(time.Now().Add(time.Duration(5 * time.Second))); err != nil {
+ if err := conn.SetReadDeadline(time.Now().Add(readTimeout * time.Second)); err != nil {
gologger.Info().Msgf("%s\n", err)
}
_, err := conn.Read(buf)
@@ -77,7 +79,7 @@ func (t *TCPServer) handleConnection(conn net.Conn) error {
}
}
-// ListenAndServe requests over tls
+// ListenAndServeTLS requests over tls
func (t *TCPServer) ListenAndServeTLS() error {
var tlsConfig *tls.Config
if t.options.Certificate != "" && t.options.Key != "" {
From 8a339ee35b4f329b9b4c2f2f830e4594769751ba Mon Sep 17 00:00:00 2001
From: mzack
Date: Fri, 16 Apr 2021 20:12:26 +0200
Subject: [PATCH 41/45] bumping version
---
internal/runner/banner.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/internal/runner/banner.go b/internal/runner/banner.go
index c8972db..2d31eb8 100644
--- a/internal/runner/banner.go
+++ b/internal/runner/banner.go
@@ -12,7 +12,7 @@ const banner = `
`
// Version is the current version
-const Version = `0.0.1`
+const Version = `0.0.2`
// showBanner is used to show the banner to the user
func showBanner() {
From 1b9328d08132f01a31dd1e8bd79c16017fe5854b Mon Sep 17 00:00:00 2001
From: Sandeep Singh
Date: Sat, 17 Apr 2021 00:47:40 +0530
Subject: [PATCH 42/45] Update README.md
---
README.md | 25 +++++++++++++------------
1 file changed, 13 insertions(+), 12 deletions(-)
diff --git a/README.md b/README.md
index 00daf9c..d2b4e5b 100644
--- a/README.md
+++ b/README.md
@@ -1,17 +1,18 @@
-
-
-
-
+SimpleHTTPserver
+Go alternative of python SimpleHTTPServer
+
+
+
+
+
+
+
+
+
+
-[](https://opensource.org/licenses/MIT)
-[](https://goreportcard.com/report/github.com/projectdiscovery/simplehttpserver)
-[](https://github.com/projectdiscovery/simplehttpserver/issues)
-[](https://github.com/projectdiscovery/simplehttpserver/releases)
-[](https://twitter.com/pdiscoveryio)
-[](https://hub.docker.com/r/projectdiscovery/simplehttpserver)
-[](https://discord.gg/KECAGdH)
-simplehttpserver is a go enhanced version of the well known python simplehttpserver with in addition a fully customizable TCP server, both supporting TLS.
+SimpleHTTPserver is a go enhanced version of the well known python simplehttpserver with in addition a fully customizable TCP server, both supporting TLS.
# Resources
From d490ff6b074db5233af1e6dd126ee9a0cc4915a7 Mon Sep 17 00:00:00 2001
From: Sandeep Singh
Date: Sat, 17 Apr 2021 00:57:03 +0530
Subject: [PATCH 43/45] Update README.md
---
README.md | 50 +++++++++++++-------------------------------------
1 file changed, 13 insertions(+), 37 deletions(-)
diff --git a/README.md b/README.md
index d2b4e5b..426fd74 100644
--- a/README.md
+++ b/README.md
@@ -11,24 +11,21 @@
+
+ Features •
+ Usage •
+ Installation •
+ Run SimpleHTTPserver •
+ Join Discord
+
-SimpleHTTPserver is a go enhanced version of the well known python simplehttpserver with in addition a fully customizable TCP server, both supporting TLS.
+---
-# Resources
+SimpleHTTPserver is a go enhanced version of the well known python simplehttpserver with in addition a fully customizable TCP server, both supporting TLS.
-- [Features](#features)
-- [Usage](#usage)
-- [Installation Instructions](#installation-instructions)
-- [Running simplehttpserver](#running-simplehttpserver-in-the-current-folder)
-- [Thanks](#thanks)
# Features
-
-
-
-
-
- HTTPS support
- File server in arbitrary directory
- Full request/response dump
@@ -36,33 +33,12 @@ SimpleHTTPserver is a go enhanced version of the well known python simplehttpser
- Configurable HTTP/TCP server with customizable response via YAML template
-# Installation Instructions
-
-
-### From Binary
-
-The installation is easy. You can download the pre-built binaries for your platform from the [Releases](https://github.com/projectdiscovery/simplehttpserver/releases/) page. Extract them using tar, move it to your `$PATH`and you're ready to go.
-
-```sh
-Download latest binary from https://github.com/projectdiscovery/simplehttpserver/releases
-
-▶ tar -xvf simplehttpserver-linux-amd64.tar
-▶ mv simplehttpserver-linux-amd64 /usr/local/bin/simplehttpserver
-▶ simplehttpserver -h
-```
-
-### From Source
-
-simplehttpserver requires **go1.14+** to install successfully. Run the following command to get the repo -
-
-```sh
-▶ GO111MODULE=on go get -v github.com/projectdiscovery/simplehttpserver
-```
+# Installing SimpleHTTPserver
-### From Github
+SimpleHTTPserver requires **go1.14+** to install successfully. Run the following command to get the repo -
```sh
-▶ git clone https://github.com/projectdiscovery/simplehttpserver.git; cd simplehttpserver; go build; mv simplehttpserver /usr/local/bin/; simplehttpserver -h
+▶ GO111MODULE=on go get -v github.com/projectdiscovery/cmd/simplehttpserver
```
# Usage
@@ -189,4 +165,4 @@ rules:
# Thanks
-simplehttpserver is made with 🖤 by the [projectdiscovery](https://projectdiscovery.io) team. Community contributions have made the project what it is. See the **[Thanks.md](https://github.com/projectdiscovery/simplehttpserver/blob/master/THANKS.md)** file for more details.
+SimpleHTTPserver is made with 🖤 by the [projectdiscovery](https://projectdiscovery.io) team.
From 63f26b4949f406b0f8a5c6fa293176ede8a02429 Mon Sep 17 00:00:00 2001
From: sandeep <8293321+ehsandeep@users.noreply.github.com>
Date: Sat, 17 Apr 2021 01:16:28 +0530
Subject: [PATCH 44/45] Update .gitignore
---
.gitignore | 1 +
1 file changed, 1 insertion(+)
diff --git a/.gitignore b/.gitignore
index b883f1f..4f9c0f3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
*.exe
+cmd/simplehttpserver/simplehttpserver
From 80695a67430e38372ce7188a24175bbaa2267722 Mon Sep 17 00:00:00 2001
From: sandeep <8293321+ehsandeep@users.noreply.github.com>
Date: Sat, 17 Apr 2021 01:27:47 +0530
Subject: [PATCH 45/45] banner update
---
internal/runner/banner.go | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/internal/runner/banner.go b/internal/runner/banner.go
index 2d31eb8..f727190 100644
--- a/internal/runner/banner.go
+++ b/internal/runner/banner.go
@@ -3,12 +3,12 @@ package runner
import "github.com/projectdiscovery/gologger"
const banner = `
- _ _ _ _ _
- ___(_)_ __ ___ _ __ | | ___| |__ | |_| |_ _ __ ___ ___ _ ____ _____ _ __
-/ __| | '_ ' _ \| '_ \| |/ _ \ '_ \| __| __| '_ \/ __|/ _ \ '__\ \ / / _ \ '__|
-\__ \ | | | | | | |_) | | __/ | | | |_| |_| |_) \__ \ __/ | \ V / __/ |
-|___/_|_| |_| |_| .__/|_|\___|_| |_|\__|\__| .__/|___/\___|_| \_/ \___|_|
- |_| |_|
+ _____ _ __ __ __________________
+ / ___/(_)___ ___ ____ / /__ / / / /_ __/_ __/ __ \________ ______ _____ _____
+ \__ \/ / __ -__ \/ __ \/ / _ \/ /_/ / / / / / / /_/ / ___/ _ \/ ___/ | / / _ \/ ___/
+ ___/ / / / / / / / /_/ / / __/ __ / / / / / / ____(__ ) __/ / | |/ / __/ /
+/____/_/_/ /_/ /_/ .___/_/\___/_/ /_/ /_/ /_/ /_/ /____/\___/_/ |___/\___/_/
+ /_/ - v0.0.2
`
// Version is the current version