Skip to content

Commit bbee79f

Browse files
committed
adding initial implementation of template based tcp server
1 parent 9a1d1df commit bbee79f

File tree

6 files changed

+187
-1
lines changed

6 files changed

+187
-1
lines changed

go.mod

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,7 @@ module github.com/projectdiscovery/simplehttpserver
22

33
go 1.15
44

5-
require github.com/projectdiscovery/gologger v1.1.4
5+
require (
6+
github.com/projectdiscovery/gologger v1.1.4
7+
gopkg.in/yaml.v2 v2.4.0
8+
)

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
3030
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
3131
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
3232
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
33+
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
34+
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
3335
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
3436
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
3537
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

pkg/tcpserver/responseengine.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package tcpserver
2+
3+
import (
4+
"errors"
5+
)
6+
7+
func (t *TCPServer) BuildResponse(data []byte) ([]byte, error) {
8+
// Process all the rules
9+
for _, rule := range t.options.rules {
10+
if rule.matchRegex.Match(data) {
11+
return []byte(rule.Response), nil
12+
}
13+
}
14+
return nil, errors.New("No matched rule")
15+
}

pkg/tcpserver/rule.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package tcpserver
2+
3+
import "regexp"
4+
5+
type RulesConfiguration struct {
6+
Rules []Rule `yaml:"rules"`
7+
}
8+
9+
type Rule struct {
10+
Match string `yaml:"match,omitempty"`
11+
matchRegex *regexp.Regexp
12+
Response string `yaml:"response,omitempty"`
13+
}
14+
15+
func NewRule(match string, response string) (*Rule, error) {
16+
regxp, err := regexp.Compile(match)
17+
if err != nil {
18+
return nil, err
19+
}
20+
21+
return &Rule{Match: match, matchRegex: regxp, Response: response}, nil
22+
}

pkg/tcpserver/tcpserver.go

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
package tcpserver
2+
3+
import (
4+
"crypto/tls"
5+
"io/ioutil"
6+
"net"
7+
"time"
8+
9+
"gopkg.in/yaml.v2"
10+
)
11+
12+
type Options struct {
13+
Listen string
14+
TLS bool
15+
Certificate string
16+
Key string
17+
Domain string
18+
rules []Rule
19+
}
20+
21+
type TCPServer struct {
22+
options Options
23+
listener net.Listener
24+
}
25+
26+
func New(options Options) (*TCPServer, error) {
27+
return &TCPServer{options: options}, nil
28+
}
29+
30+
func (t *TCPServer) AddRule(rule Rule) error {
31+
t.options.rules = append(t.options.rules, rule)
32+
return nil
33+
}
34+
35+
func (t *TCPServer) ListenAndServe() error {
36+
listener, err := net.Listen("tcp4", t.options.Listen)
37+
if err != nil {
38+
return err
39+
}
40+
t.listener = listener
41+
return t.run()
42+
}
43+
44+
func (t *TCPServer) handleConnection(conn net.Conn) error {
45+
defer conn.Close()
46+
47+
buf := make([]byte, 4096)
48+
for {
49+
conn.SetReadDeadline(time.Now().Add(time.Duration(5 * time.Second)))
50+
_, err := conn.Read(buf)
51+
if err != nil {
52+
return err
53+
}
54+
55+
resp, err := t.BuildResponse(buf)
56+
if err != nil {
57+
return err
58+
}
59+
60+
conn.Write(resp)
61+
}
62+
}
63+
64+
func (t *TCPServer) ListenAndServeTLS() error {
65+
var tlsConfig *tls.Config
66+
if t.options.Certificate != "" && t.options.Key != "" {
67+
cert, err := tls.LoadX509KeyPair(t.options.Certificate, t.options.Key)
68+
if err != nil {
69+
return err
70+
}
71+
tlsConfig = &tls.Config{Certificates: []tls.Certificate{cert}}
72+
} else {
73+
tlsOptions := sslcert.DefaultOptions
74+
tlsOptions.Host = opts.Domain
75+
cfg, err := sslcert.NewTLSConfig(tlsOptions)
76+
if err != nil {
77+
return err
78+
}
79+
tlsConfig = cfg
80+
}
81+
82+
listener, err := tls.Listen("tcp", t.options.Listen, tlsConfig)
83+
if err != nil {
84+
return err
85+
}
86+
t.listener = listener
87+
return t.run()
88+
}
89+
90+
func (t *TCPServer) run() error {
91+
for {
92+
c, err := t.listener.Accept()
93+
if err != nil {
94+
return err
95+
}
96+
go t.handleConnection(c)
97+
}
98+
}
99+
100+
func (t *TCPServer) Close() error {
101+
return t.listener.Close()
102+
}
103+
104+
func (t *TCPServer) LoadTemplate(templatePath string) error {
105+
var config RulesConfiguration
106+
yamlFile, err := ioutil.ReadFile(templatePath)
107+
if err != nil {
108+
return err
109+
}
110+
err = yaml.Unmarshal(yamlFile, &config)
111+
if err != nil {
112+
return err
113+
}
114+
115+
for _, ruleTemplate := range config.Rules {
116+
rule, err := NewRule(ruleTemplate.Match, ruleTemplate.Response)
117+
if err != nil {
118+
return err
119+
}
120+
t.options.rules = append(t.options.rules, *rule)
121+
}
122+
123+
return nil
124+
}

simplehttpserver.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"strings"
1313

1414
"github.com/projectdiscovery/gologger"
15+
"github.com/projectdiscovery/simplehttpserver/pkg/tcpserver"
1516
)
1617

1718
type options struct {
@@ -26,12 +27,18 @@ type options struct {
2627
HTTPS bool
2728
Verbose bool
2829
Upload bool
30+
TCP bool
31+
RulesFile string
32+
TLS bool
2933
}
3034

3135
var opts options
3236

3337
func main() {
3438
flag.StringVar(&opts.ListenAddress, "listen", "0.0.0.0:8000", "Address:Port")
39+
flag.BoolVar(&opts.TCP, "tcp", false, "TCP Server")
40+
flag.BoolVar(&opts.TLS, "tls", false, "Enable TCP TLS")
41+
flag.StringVar(&opts.RulesFile, "rules", "", "Rules yaml file")
3542
flag.StringVar(&opts.Folder, "path", ".", "Folder")
3643
flag.BoolVar(&opts.Upload, "upload", false, "Enable upload via PUT")
3744
flag.BoolVar(&opts.HTTPS, "https", false, "HTTPS")
@@ -47,6 +54,19 @@ func main() {
4754
opts.Folder = flag.Args()[0]
4855
}
4956

57+
if opts.TCP {
58+
serverTCP, err := tcpserver.New(tcpserver.Options{Listen: opts.ListenAddress, TLS: opts.TLS, Domain: "local.host"})
59+
if err != nil {
60+
gologger.Fatal().Msgf("%s\n", err)
61+
}
62+
err = serverTCP.LoadTemplate(opts.RulesFile)
63+
if err != nil {
64+
gologger.Fatal().Msgf("%s\n", err)
65+
}
66+
67+
gologger.Print().Msgf("%s\n", serverTCP.ListenAndServe())
68+
}
69+
5070
gologger.Print().Msgf("Serving %s on http://%s/...", opts.Folder, opts.ListenAddress)
5171
layers := loglayer(http.FileServer(http.Dir(opts.Folder)))
5272
if opts.BasicAuth != "" {

0 commit comments

Comments
 (0)