diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml
index 11d1658..4179b91 100644
--- a/.github/workflows/build.yaml
+++ b/.github/workflows/build.yaml
@@ -32,7 +32,7 @@ jobs:
- name: Test
run: go test .
- working-directory: cmd/simplehttpserver/
+ working-directory: cmd/simplehttpserver
- name: Build
run: go build .
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/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"]
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.
diff --git a/cmd/simplehttpserver/simplehttpserver.go b/cmd/simplehttpserver/simplehttpserver.go
index 0dbbe6c..ed82b40 100644
--- a/cmd/simplehttpserver/simplehttpserver.go
+++ b/cmd/simplehttpserver/simplehttpserver.go
@@ -8,11 +8,13 @@ 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()
+ if err := r.Run(); err != nil {
+ gologger.Info().Msgf("%s\n", err)
+ }
+ defer r.Close() //nolint
}
diff --git a/go.mod b/go.mod
index f8bb144..f4c4a9d 100644
--- a/go.mod
+++ b/go.mod
@@ -1,9 +1,10 @@
module github.com/projectdiscovery/simplehttpserver
-go 1.15
+go 1.14
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/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() {
diff --git a/internal/runner/options.go b/internal/runner/options.go
index 3170cd3..bf69db3 100644
--- a/internal/runner/options.go
+++ b/internal/runner/options.go
@@ -3,12 +3,14 @@ package runner
import (
"flag"
"os"
+ "path/filepath"
"strings"
"github.com/projectdiscovery/gologger"
"github.com/projectdiscovery/gologger/levels"
)
+// Options of the tool
type Options struct {
ListenAddress string
Folder string
@@ -91,3 +93,12 @@ func (options *Options) configureOutput() {
gologger.DefaultLogger.SetMaxLevel(levels.LevelSilent)
}
}
+
+// FolderAbsPath of the fileserver folder
+func (options *Options) FolderAbsPath() string {
+ abspath, err := filepath.Abs(options.Folder)
+ if err != nil {
+ return options.Folder
+ }
+ return abspath
+}
diff --git a/internal/runner/runner.go b/internal/runner/runner.go
index 6603d50..7d69e25 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
@@ -27,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",
@@ -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)
@@ -72,20 +74,25 @@ 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()
}
+// 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 2a248a1..549e9d9 100644
--- a/pkg/binder/binder.go
+++ b/pkg/binder/binder.go
@@ -5,17 +5,22 @@ import (
"net"
"github.com/phayes/freeport"
+ "github.com/projectdiscovery/gologger"
)
+// CanListenOn the specified address
func CanListenOn(address string) bool {
listener, err := net.Listen("tcp4", address)
if err != nil {
return false
}
- defer listener.Close()
+ if err := listener.Close(); err != nil {
+ gologger.Info().Msgf("%s\n", err)
+ }
return true
}
+// GetRandomListenAddress from the specified one
func GetRandomListenAddress(currentAddress string) (string, error) {
addrOrig, _, err := net.SplitHostPort(currentAddress)
if err != nil {
@@ -28,5 +33,4 @@ func GetRandomListenAddress(currentAddress string) (string, error) {
}
return net.JoinHostPort(addrOrig, fmt.Sprintf("%d", newPort)), nil
-
}
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/httpserver/httpserver.go b/pkg/httpserver/httpserver.go
index c37355e..1747017 100644
--- a/pkg/httpserver/httpserver.go
+++ b/pkg/httpserver/httpserver.go
@@ -1,12 +1,12 @@
package httpserver
import (
- "net"
"net/http"
- "github.com/projectdiscovery/simplehttpserver/pkg/sslcert"
+ "github.com/projectdiscovery/sslcert"
)
+// Options of the http server
type Options struct {
Folder string
EnableUpload bool
@@ -21,12 +21,13 @@ type Options struct {
Verbose bool
}
+// HTTPServer instance
type HTTPServer struct {
- options *Options
- layers http.Handler
- listener net.Listener
+ options *Options
+ layers http.Handler
}
+// New http server instance with options
func New(options *Options) (*HTTPServer, error) {
var h HTTPServer
EnableUpload = options.EnableUpload
@@ -39,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
@@ -61,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/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/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
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 7d46b3a..876fbb4 100644
--- a/pkg/tcpserver/tcpserver.go
+++ b/pkg/tcpserver/tcpserver.go
@@ -7,10 +7,13 @@ import (
"time"
"github.com/projectdiscovery/gologger"
- "github.com/projectdiscovery/simplehttpserver/pkg/sslcert"
+ "github.com/projectdiscovery/sslcert"
"gopkg.in/yaml.v2"
)
+const readTimeout = 5
+
+// Options of the tcp server
type Options struct {
Listen string
TLS bool
@@ -21,20 +24,24 @@ type Options struct {
Verbose bool
}
+// TCPServer instance
type TCPServer struct {
- options Options
+ options *Options
listener net.Listener
}
-func New(options Options) (*TCPServer, error) {
+// 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 {
@@ -45,11 +52,13 @@ 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 {
- conn.SetReadDeadline(time.Now().Add(time.Duration(5 * time.Second)))
+ if err := conn.SetReadDeadline(time.Now().Add(readTimeout * time.Second)); err != nil {
+ gologger.Info().Msgf("%s\n", err)
+ }
_, err := conn.Read(buf)
if err != nil {
return err
@@ -62,12 +71,15 @@ 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)
}
}
+// ListenAndServeTLS requests over tls
func (t *TCPServer) ListenAndServeTLS() error {
var tlsConfig *tls.Config
if t.options.Certificate != "" && t.options.Key != "" {
@@ -100,14 +112,16 @@ 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()
}
+// LoadTemplate from yaml
func (t *TCPServer) LoadTemplate(templatePath string) error {
var config RulesConfiguration
yamlFile, err := ioutil.ReadFile(templatePath)