11package tcpserver
22
33import (
4+ "context"
45 "crypto/tls"
6+ "errors"
57 "io/ioutil"
68 "net"
9+ "sync"
710 "time"
811
912 "github.com/projectdiscovery/gologger"
@@ -24,20 +27,35 @@ type Options struct {
2427 Verbose bool
2528}
2629
30+ // CallBackFunc handles what is send back to the client, based on the incomming question
31+ type CallBackFunc func (ctx context.Context , question []byte ) (answer []byte , err error )
32+
2733// TCPServer instance
2834type TCPServer struct {
2935 options * Options
3036 listener net.Listener
37+
38+ // Callbacks to retrieve information about the system
39+ HandleMessageFnc CallBackFunc
40+
41+ mux sync.RWMutex
42+ rules []Rule
3143}
3244
3345// New tcp server instance with specified options
3446func New (options * Options ) (* TCPServer , error ) {
35- return & TCPServer {options : options }, nil
47+ srv := & TCPServer {options : options }
48+ srv .HandleMessageFnc = srv .BuildResponseWithContext
49+ srv .rules = options .rules
50+ return srv , nil
3651}
3752
3853// AddRule to the server
3954func (t * TCPServer ) AddRule (rule Rule ) error {
40- t .options .rules = append (t .options .rules , rule )
55+ t .mux .Lock ()
56+ defer t .mux .Unlock ()
57+
58+ t .rules = append (t .rules , rule )
4159 return nil
4260}
4361
@@ -51,23 +69,27 @@ func (t *TCPServer) ListenAndServe() error {
5169 return t .run ()
5270}
5371
54- func (t * TCPServer ) handleConnection (conn net.Conn ) error {
72+ func (t * TCPServer ) handleConnection (conn net.Conn , callback CallBackFunc ) error {
5573 defer conn .Close () //nolint
5674
75+ // Create Context
76+ ctx := context .WithValue (context .Background (), Addr , conn .RemoteAddr ())
77+
5778 buf := make ([]byte , 4096 )
5879 for {
5980 if err := conn .SetReadDeadline (time .Now ().Add (readTimeout * time .Second )); err != nil {
6081 gologger .Info ().Msgf ("%s\n " , err )
6182 }
62- _ , err := conn .Read (buf )
83+ n , err := conn .Read (buf )
6384 if err != nil {
6485 return err
6586 }
6687
67- gologger .Print ().Msgf ("%s\n " , buf )
88+ gologger .Print ().Msgf ("%s\n " , buf [: n ] )
6889
69- resp , err := t . BuildResponse ( buf )
90+ resp , err := callback ( ctx , buf [: n ] )
7091 if err != nil {
92+ gologger .Info ().Msgf ("Closing connection: %s\n " , err )
7193 return err
7294 }
7395
@@ -112,7 +134,7 @@ func (t *TCPServer) run() error {
112134 if err != nil {
113135 return err
114136 }
115- go t .handleConnection (c ) //nolint
137+ go t .handleConnection (c , t . HandleMessageFnc ) //nolint
116138 }
117139}
118140
@@ -133,13 +155,54 @@ func (t *TCPServer) LoadTemplate(templatePath string) error {
133155 return err
134156 }
135157
158+ t .mux .Lock ()
159+ defer t .mux .Unlock ()
160+
161+ t .rules = make ([]Rule , 0 )
136162 for _ , ruleTemplate := range config .Rules {
137- rule , err := NewRule (ruleTemplate . Match , ruleTemplate . Response )
163+ rule , err := NewRuleFromTemplate (ruleTemplate )
138164 if err != nil {
139165 return err
140166 }
141- t .options . rules = append (t . options .rules , * rule )
167+ t .rules = append (t .rules , * rule )
142168 }
143169
170+ gologger .Info ().Msgf ("TCP configuration loaded. Rules: %d\n " , len (t .rules ))
171+
144172 return nil
145173}
174+
175+ // MatchRule returns the rule, which was matched first
176+ func (t * TCPServer ) MatchRule (data []byte ) (rule Rule , err error ) {
177+ t .mux .RLock ()
178+ defer t .mux .RUnlock ()
179+
180+ // Process all the rules
181+ for _ , rule := range t .rules {
182+ if rule .MatchInput (data ) {
183+ return rule , nil
184+ }
185+ }
186+ return Rule {}, errors .New ("no matched rule" )
187+ }
188+
189+ // BuildResponseWithContext is a wrapper with context
190+ func (t * TCPServer ) BuildResponseWithContext (ctx context.Context , data []byte ) ([]byte , error ) {
191+ return t .BuildResponse (data )
192+ }
193+
194+ // BuildResponseWithContext is a wrapper with context
195+ func (t * TCPServer ) BuildRuleResponse (ctx context.Context , data []byte ) ([]byte , error ) {
196+ addr := "unknown"
197+ if netAddr , ok := ctx .Value (Addr ).(net.Addr ); ok {
198+ addr = netAddr .String ()
199+ }
200+ rule , err := t .MatchRule (data )
201+ if err != nil {
202+ return []byte (":) " ), err
203+ }
204+
205+ gologger .Info ().Msgf ("Incoming TCP request(%s) from: %s\n " , rule .Name , addr )
206+
207+ return []byte (rule .Response ), nil
208+ }
0 commit comments