mirror of
https://github.com/bettercap/bettercap
synced 2025-07-08 05:51:37 -07:00
new: implemented tcp.proxy (closes #33)
This commit is contained in:
parent
0f8be49beb
commit
129f87f8f9
7 changed files with 410 additions and 78 deletions
1
main.go
1
main.go
|
@ -47,6 +47,7 @@ func main() {
|
||||||
sess.Register(modules.NewHttpServer(sess))
|
sess.Register(modules.NewHttpServer(sess))
|
||||||
sess.Register(modules.NewHttpProxy(sess))
|
sess.Register(modules.NewHttpProxy(sess))
|
||||||
sess.Register(modules.NewHttpsProxy(sess))
|
sess.Register(modules.NewHttpsProxy(sess))
|
||||||
|
sess.Register(modules.NewTcpProxy(sess))
|
||||||
sess.Register(modules.NewRestAPI(sess))
|
sess.Register(modules.NewRestAPI(sess))
|
||||||
sess.Register(modules.NewWOL(sess))
|
sess.Register(modules.NewWOL(sess))
|
||||||
sess.Register(modules.NewWiFiRecon(sess))
|
sess.Register(modules.NewWiFiRecon(sess))
|
||||||
|
|
|
@ -2,8 +2,10 @@ package modules
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/bettercap/bettercap/log"
|
"github.com/bettercap/bettercap/log"
|
||||||
|
"github.com/bettercap/bettercap/session"
|
||||||
|
|
||||||
"github.com/robertkrimen/otto"
|
"github.com/robertkrimen/otto"
|
||||||
)
|
)
|
||||||
|
@ -15,7 +17,68 @@ func errOtto(format string, args ...interface{}) otto.Value {
|
||||||
return nullOtto
|
return nullOtto
|
||||||
}
|
}
|
||||||
|
|
||||||
// define functions available to proxy scripts
|
type ProxyScript struct {
|
||||||
|
sync.Mutex
|
||||||
|
|
||||||
|
Path string
|
||||||
|
Source string
|
||||||
|
VM *otto.Otto
|
||||||
|
|
||||||
|
sess *session.Session
|
||||||
|
cbCacheLock *sync.Mutex
|
||||||
|
cbCache map[string]bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func LoadProxyScriptSource(path, source string, sess *session.Session) (err error, s *ProxyScript) {
|
||||||
|
s = &ProxyScript{
|
||||||
|
Path: path,
|
||||||
|
Source: source,
|
||||||
|
VM: otto.New(),
|
||||||
|
sess: sess,
|
||||||
|
cbCacheLock: &sync.Mutex{},
|
||||||
|
cbCache: make(map[string]bool),
|
||||||
|
}
|
||||||
|
|
||||||
|
// this will define callbacks and global objects
|
||||||
|
_, err = s.VM.Run(s.Source)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// define session pointer
|
||||||
|
err = s.VM.Set("env", sess.Env.Data)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Error while defining environment: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = s.defineBuiltins()
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Error while defining builtin functions: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// run onLoad if defined
|
||||||
|
if s.hasCallback("onLoad") {
|
||||||
|
_, err = s.VM.Run("onLoad()")
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Error while executing onLoad callback: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func LoadProxyScript(path string, sess *session.Session) (err error, s *ProxyScript) {
|
||||||
|
raw, err := ioutil.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return LoadProxyScriptSource(path, string(raw), sess)
|
||||||
|
}
|
||||||
|
|
||||||
func (s *ProxyScript) defineBuiltins() error {
|
func (s *ProxyScript) defineBuiltins() error {
|
||||||
// used to read a file ... doh
|
// used to read a file ... doh
|
||||||
s.VM.Set("readFile", func(call otto.FunctionCall) otto.Value {
|
s.VM.Set("readFile", func(call otto.FunctionCall) otto.Value {
|
||||||
|
@ -76,3 +139,23 @@ func (s *ProxyScript) defineBuiltins() error {
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *ProxyScript) hasCallback(name string) bool {
|
||||||
|
s.cbCacheLock.Lock()
|
||||||
|
defer s.cbCacheLock.Unlock()
|
||||||
|
|
||||||
|
// check the cache
|
||||||
|
has, found := s.cbCache[name]
|
||||||
|
if found == false {
|
||||||
|
// check the VM
|
||||||
|
cb, err := s.VM.Get(name)
|
||||||
|
if err == nil && cb.IsFunction() {
|
||||||
|
has = true
|
||||||
|
} else {
|
||||||
|
has = false
|
||||||
|
}
|
||||||
|
s.cbCache[name] = has
|
||||||
|
}
|
||||||
|
|
||||||
|
return has
|
||||||
|
}
|
|
@ -36,7 +36,7 @@ type HTTPProxy struct {
|
||||||
Server *http.Server
|
Server *http.Server
|
||||||
Redirection *firewall.Redirection
|
Redirection *firewall.Redirection
|
||||||
Proxy *goproxy.ProxyHttpServer
|
Proxy *goproxy.ProxyHttpServer
|
||||||
Script *ProxyScript
|
Script *HttpProxyScript
|
||||||
CertFile string
|
CertFile string
|
||||||
KeyFile string
|
KeyFile string
|
||||||
|
|
||||||
|
@ -147,7 +147,7 @@ func (p *HTTPProxy) Configure(address string, proxyPort int, httpPort int, scrip
|
||||||
p.Address = address
|
p.Address = address
|
||||||
|
|
||||||
if scriptPath != "" {
|
if scriptPath != "" {
|
||||||
if err, p.Script = LoadProxyScript(scriptPath, p.sess); err != nil {
|
if err, p.Script = LoadHttpProxyScript(scriptPath, p.sess); err != nil {
|
||||||
return err
|
return err
|
||||||
} else {
|
} else {
|
||||||
log.Debug("Proxy script %s loaded.", scriptPath)
|
log.Debug("Proxy script %s loaded.", scriptPath)
|
||||||
|
|
|
@ -3,7 +3,6 @@ package modules
|
||||||
import (
|
import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/bettercap/bettercap/log"
|
"github.com/bettercap/bettercap/log"
|
||||||
"github.com/bettercap/bettercap/session"
|
"github.com/bettercap/bettercap/session"
|
||||||
|
@ -11,59 +10,22 @@ import (
|
||||||
"github.com/robertkrimen/otto"
|
"github.com/robertkrimen/otto"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ProxyScript struct {
|
type HttpProxyScript struct {
|
||||||
sync.Mutex
|
*ProxyScript
|
||||||
|
|
||||||
Path string
|
|
||||||
Source string
|
|
||||||
VM *otto.Otto
|
|
||||||
|
|
||||||
sess *session.Session
|
|
||||||
onRequestScript *otto.Script
|
onRequestScript *otto.Script
|
||||||
onResponseScript *otto.Script
|
onResponseScript *otto.Script
|
||||||
cbCacheLock *sync.Mutex
|
|
||||||
cbCache map[string]bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func LoadProxyScriptSource(path, source string, sess *session.Session) (err error, s *ProxyScript) {
|
func LoadHttpProxyScriptSource(path, source string, sess *session.Session) (err error, s *HttpProxyScript) {
|
||||||
s = &ProxyScript{
|
err, ps := LoadProxyScriptSource(path, source, sess)
|
||||||
Path: path,
|
if err != nil {
|
||||||
Source: source,
|
return
|
||||||
VM: otto.New(),
|
}
|
||||||
|
|
||||||
sess: sess,
|
s = &HttpProxyScript{
|
||||||
|
ProxyScript: ps,
|
||||||
onRequestScript: nil,
|
onRequestScript: nil,
|
||||||
onResponseScript: nil,
|
onResponseScript: nil,
|
||||||
cbCacheLock: &sync.Mutex{},
|
|
||||||
cbCache: make(map[string]bool),
|
|
||||||
}
|
|
||||||
|
|
||||||
// this will define callbacks and global objects
|
|
||||||
_, err = s.VM.Run(s.Source)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// define session pointer
|
|
||||||
err = s.VM.Set("env", sess.Env.Data)
|
|
||||||
if err != nil {
|
|
||||||
log.Error("Error while defining environment: %s", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
err = s.defineBuiltins()
|
|
||||||
if err != nil {
|
|
||||||
log.Error("Error while defining builtin functions: %s", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// run onLoad if defined
|
|
||||||
if s.hasCallback("onLoad") {
|
|
||||||
_, err = s.VM.Run("onLoad()")
|
|
||||||
if err != nil {
|
|
||||||
log.Error("Error while executing onLoad callback: %s", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// compile call to onRequest if defined
|
// compile call to onRequest if defined
|
||||||
|
@ -87,7 +49,7 @@ func LoadProxyScriptSource(path, source string, sess *session.Session) (err erro
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func LoadProxyScript(path string, sess *session.Session) (err error, s *ProxyScript) {
|
func LoadHttpProxyScript(path string, sess *session.Session) (err error, s *HttpProxyScript) {
|
||||||
log.Info("Loading proxy script %s ...", path)
|
log.Info("Loading proxy script %s ...", path)
|
||||||
|
|
||||||
raw, err := ioutil.ReadFile(path)
|
raw, err := ioutil.ReadFile(path)
|
||||||
|
@ -95,30 +57,10 @@ func LoadProxyScript(path string, sess *session.Session) (err error, s *ProxyScr
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
return LoadProxyScriptSource(path, string(raw), sess)
|
return LoadHttpProxyScriptSource(path, string(raw), sess)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ProxyScript) hasCallback(name string) bool {
|
func (s *HttpProxyScript) doRequestDefines(req *http.Request) (err error, jsres *JSResponse) {
|
||||||
s.cbCacheLock.Lock()
|
|
||||||
defer s.cbCacheLock.Unlock()
|
|
||||||
|
|
||||||
// check the cache
|
|
||||||
has, found := s.cbCache[name]
|
|
||||||
if found == false {
|
|
||||||
// check the VM
|
|
||||||
cb, err := s.VM.Get(name)
|
|
||||||
if err == nil && cb.IsFunction() {
|
|
||||||
has = true
|
|
||||||
} else {
|
|
||||||
has = false
|
|
||||||
}
|
|
||||||
s.cbCache[name] = has
|
|
||||||
}
|
|
||||||
|
|
||||||
return has
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *ProxyScript) doRequestDefines(req *http.Request) (err error, jsres *JSResponse) {
|
|
||||||
// convert request and define empty response to be optionally filled
|
// convert request and define empty response to be optionally filled
|
||||||
jsreq := NewJSRequest(req)
|
jsreq := NewJSRequest(req)
|
||||||
if err = s.VM.Set("req", &jsreq); err != nil {
|
if err = s.VM.Set("req", &jsreq); err != nil {
|
||||||
|
@ -134,7 +76,7 @@ func (s *ProxyScript) doRequestDefines(req *http.Request) (err error, jsres *JSR
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ProxyScript) doResponseDefines(res *http.Response) (err error, jsres *JSResponse) {
|
func (s *HttpProxyScript) doResponseDefines(res *http.Response) (err error, jsres *JSResponse) {
|
||||||
// convert both request and response
|
// convert both request and response
|
||||||
jsreq := NewJSRequest(res.Request)
|
jsreq := NewJSRequest(res.Request)
|
||||||
if err = s.VM.Set("req", jsreq); err != nil {
|
if err = s.VM.Set("req", jsreq); err != nil {
|
||||||
|
@ -151,7 +93,7 @@ func (s *ProxyScript) doResponseDefines(res *http.Response) (err error, jsres *J
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ProxyScript) OnRequest(req *http.Request) *JSResponse {
|
func (s *HttpProxyScript) OnRequest(req *http.Request) *JSResponse {
|
||||||
if s.onRequestScript != nil {
|
if s.onRequestScript != nil {
|
||||||
s.Lock()
|
s.Lock()
|
||||||
defer s.Unlock()
|
defer s.Unlock()
|
||||||
|
@ -177,7 +119,7 @@ func (s *ProxyScript) OnRequest(req *http.Request) *JSResponse {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ProxyScript) OnResponse(res *http.Response) *JSResponse {
|
func (s *HttpProxyScript) OnResponse(res *http.Response) *JSResponse {
|
||||||
if s.onResponseScript != nil {
|
if s.onResponseScript != nil {
|
||||||
s.Lock()
|
s.Lock()
|
||||||
defer s.Unlock()
|
defer s.Unlock()
|
||||||
|
|
|
@ -8,11 +8,11 @@ import (
|
||||||
"github.com/bettercap/bettercap/session"
|
"github.com/bettercap/bettercap/session"
|
||||||
)
|
)
|
||||||
|
|
||||||
func getScript(src string) *ProxyScript {
|
func getScript(src string) *HttpProxyScript {
|
||||||
sess := session.Session{}
|
sess := session.Session{}
|
||||||
sess.Env = session.NewEnvironment(&sess)
|
sess.Env = session.NewEnvironment(&sess)
|
||||||
|
|
||||||
err, script := LoadProxyScriptSource("", src, &sess)
|
err, script := LoadHttpProxyScriptSource("", src, &sess)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("%s", err)
|
log.Fatal("%s", err)
|
||||||
}
|
}
|
||||||
|
|
214
modules/tcp_proxy.go
Normal file
214
modules/tcp_proxy.go
Normal file
|
@ -0,0 +1,214 @@
|
||||||
|
package modules
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/bettercap/bettercap/firewall"
|
||||||
|
"github.com/bettercap/bettercap/log"
|
||||||
|
"github.com/bettercap/bettercap/session"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TcpProxy struct {
|
||||||
|
session.SessionModule
|
||||||
|
Redirection *firewall.Redirection
|
||||||
|
localAddr *net.TCPAddr
|
||||||
|
remoteAddr *net.TCPAddr
|
||||||
|
listener *net.TCPListener
|
||||||
|
script *TcpProxyScript
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTcpProxy(s *session.Session) *TcpProxy {
|
||||||
|
p := &TcpProxy{
|
||||||
|
SessionModule: session.NewSessionModule("tcp.proxy", s),
|
||||||
|
}
|
||||||
|
|
||||||
|
p.AddParam(session.NewIntParameter("tcp.port",
|
||||||
|
"443",
|
||||||
|
"Remote port to redirect when the TCP proxy is activated."))
|
||||||
|
|
||||||
|
p.AddParam(session.NewStringParameter("tcp.address",
|
||||||
|
"",
|
||||||
|
session.IPv4Validator,
|
||||||
|
"Remote address of the TCP proxy."))
|
||||||
|
|
||||||
|
p.AddParam(session.NewStringParameter("tcp.proxy.address",
|
||||||
|
session.ParamIfaceAddress,
|
||||||
|
session.IPv4Validator,
|
||||||
|
"Address to bind the TCP proxy to."))
|
||||||
|
|
||||||
|
p.AddParam(session.NewIntParameter("tcp.proxy.port",
|
||||||
|
"8443",
|
||||||
|
"Port to bind the TCP proxy to."))
|
||||||
|
|
||||||
|
p.AddParam(session.NewStringParameter("tcp.proxy.script",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
"Path of a TCP proxy JS script."))
|
||||||
|
|
||||||
|
p.AddHandler(session.NewModuleHandler("tcp.proxy on", "",
|
||||||
|
"Start HTTP proxy.",
|
||||||
|
func(args []string) error {
|
||||||
|
return p.Start()
|
||||||
|
}))
|
||||||
|
|
||||||
|
p.AddHandler(session.NewModuleHandler("tcp.proxy off", "",
|
||||||
|
"Stop HTTP proxy.",
|
||||||
|
func(args []string) error {
|
||||||
|
return p.Stop()
|
||||||
|
}))
|
||||||
|
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *TcpProxy) Name() string {
|
||||||
|
return "tcp.proxy"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *TcpProxy) Description() string {
|
||||||
|
return "A full featured TCP proxy, all TCP traffic to a given remote address and port will be redirected to it."
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *TcpProxy) Author() string {
|
||||||
|
return "Simone Margaritelli <evilsocket@protonmail.com>"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *TcpProxy) Configure() error {
|
||||||
|
var err error
|
||||||
|
var port int
|
||||||
|
var proxyPort int
|
||||||
|
var address string
|
||||||
|
var proxyAddress string
|
||||||
|
var scriptPath string
|
||||||
|
|
||||||
|
if err, address = p.StringParam("tcp.address"); err != nil {
|
||||||
|
return err
|
||||||
|
} else if err, proxyAddress = p.StringParam("tcp.proxy.address"); err != nil {
|
||||||
|
return err
|
||||||
|
} else if err, proxyPort = p.IntParam("tcp.proxy.port"); err != nil {
|
||||||
|
return err
|
||||||
|
} else if err, port = p.IntParam("tcp.port"); err != nil {
|
||||||
|
return err
|
||||||
|
} else if err, scriptPath = p.StringParam("tcp.proxy.script"); err != nil {
|
||||||
|
return err
|
||||||
|
} else if p.localAddr, err = net.ResolveTCPAddr("tcp", fmt.Sprintf("%s:%d", proxyAddress, proxyPort)); err != nil {
|
||||||
|
return err
|
||||||
|
} else if p.remoteAddr, err = net.ResolveTCPAddr("tcp", fmt.Sprintf("%s:%d", address, port)); err != nil {
|
||||||
|
return err
|
||||||
|
} else if p.listener, err = net.ListenTCP("tcp", p.localAddr); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if scriptPath != "" {
|
||||||
|
if err, p.script = LoadTcpProxyScript(scriptPath, p.Session); err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
log.Debug("TCP proxy script %s loaded.", scriptPath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.Session.Firewall.IsForwardingEnabled() == false {
|
||||||
|
log.Info("Enabling forwarding.")
|
||||||
|
p.Session.Firewall.EnableForwarding(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
p.Redirection = firewall.NewRedirection(p.Session.Interface.Name(),
|
||||||
|
"TCP",
|
||||||
|
port,
|
||||||
|
proxyAddress,
|
||||||
|
proxyPort)
|
||||||
|
|
||||||
|
p.Redirection.SrcAddress = address
|
||||||
|
|
||||||
|
if err := p.Session.Firewall.EnableRedirection(p.Redirection, true); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debug("Applied redirection %s", p.Redirection.String())
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *TcpProxy) doPipe(from, to net.Addr, src, dst io.ReadWriter, wg *sync.WaitGroup) {
|
||||||
|
defer wg.Done()
|
||||||
|
|
||||||
|
buff := make([]byte, 0xffff)
|
||||||
|
for {
|
||||||
|
n, err := src.Read(buff)
|
||||||
|
if err != nil {
|
||||||
|
if err.Error() != "EOF" {
|
||||||
|
log.Warning("Read failed: %s", err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
b := buff[:n]
|
||||||
|
|
||||||
|
ret := p.script.OnData(from, to, b)
|
||||||
|
if ret != nil {
|
||||||
|
nret := len(ret)
|
||||||
|
log.Info("Overriding %d bytes of data from %s to %s with %d bytes of new data.", n, from.String(), to.String(), nret)
|
||||||
|
b = make([]byte, nret)
|
||||||
|
copy(b, ret)
|
||||||
|
}
|
||||||
|
|
||||||
|
n, err = dst.Write(b)
|
||||||
|
if err != nil {
|
||||||
|
log.Warning("Write failed: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debug("%s -> %s : %d bytes", from.String(), to.String(), n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *TcpProxy) handleConnection(c *net.TCPConn) {
|
||||||
|
defer c.Close()
|
||||||
|
|
||||||
|
log.Info("TCP proxy got a connection from %s", c.RemoteAddr().String())
|
||||||
|
|
||||||
|
remote, err := net.DialTCP("tcp", nil, p.remoteAddr)
|
||||||
|
if err != nil {
|
||||||
|
log.Warning("Error while connecting to remote %s: %s", p.remoteAddr.String(), err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer remote.Close()
|
||||||
|
|
||||||
|
wg := sync.WaitGroup{}
|
||||||
|
wg.Add(2)
|
||||||
|
|
||||||
|
// start pipeing
|
||||||
|
go p.doPipe(c.RemoteAddr(), p.remoteAddr, c, remote, &wg)
|
||||||
|
go p.doPipe(p.remoteAddr, c.RemoteAddr(), remote, c, &wg)
|
||||||
|
|
||||||
|
wg.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *TcpProxy) Start() error {
|
||||||
|
if p.Running() == true {
|
||||||
|
return session.ErrAlreadyStarted
|
||||||
|
} else if err := p.Configure(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return p.SetRunning(true, func() {
|
||||||
|
log.Info("TCP proxy started ( x -> %s -> %s )", p.localAddr, p.remoteAddr)
|
||||||
|
|
||||||
|
for p.Running() {
|
||||||
|
conn, err := p.listener.AcceptTCP()
|
||||||
|
if err != nil {
|
||||||
|
log.Warning("Error while accepting TCP connection: %s", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
go p.handleConnection(conn)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *TcpProxy) Stop() error {
|
||||||
|
return p.SetRunning(false, func() {
|
||||||
|
p.listener.Close()
|
||||||
|
})
|
||||||
|
}
|
92
modules/tcp_proxy_script.go
Normal file
92
modules/tcp_proxy_script.go
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
package modules
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"net"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/bettercap/bettercap/log"
|
||||||
|
"github.com/bettercap/bettercap/session"
|
||||||
|
|
||||||
|
"github.com/robertkrimen/otto"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TcpProxyScript struct {
|
||||||
|
*ProxyScript
|
||||||
|
onDataScript *otto.Script
|
||||||
|
}
|
||||||
|
|
||||||
|
func LoadTcpProxyScriptSource(path, source string, sess *session.Session) (err error, s *TcpProxyScript) {
|
||||||
|
err, ps := LoadProxyScriptSource(path, source, sess)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
s = &TcpProxyScript{
|
||||||
|
ProxyScript: ps,
|
||||||
|
onDataScript: nil,
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.hasCallback("onData") {
|
||||||
|
s.onDataScript, err = s.VM.Compile("", "onData(from, to, data)")
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Error while compiling onData callback: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func LoadTcpProxyScript(path string, sess *session.Session) (err error, s *TcpProxyScript) {
|
||||||
|
log.Info("Loading TCP proxy script %s ...", path)
|
||||||
|
|
||||||
|
raw, err := ioutil.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return LoadTcpProxyScriptSource(path, string(raw), sess)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *TcpProxyScript) doDefines(from, to net.Addr, data []byte) (err error) {
|
||||||
|
addrFrom := strings.Split(from.String(), ":")[0]
|
||||||
|
addrTo := strings.Split(to.String(), ":")[0]
|
||||||
|
|
||||||
|
if err = s.VM.Set("from", addrFrom); err != nil {
|
||||||
|
log.Error("Error while defining from: %s", err)
|
||||||
|
return
|
||||||
|
} else if err = s.VM.Set("to", addrTo); err != nil {
|
||||||
|
log.Error("Error while defining to: %s", err)
|
||||||
|
return
|
||||||
|
} else if err = s.VM.Set("data", string(data)); err != nil {
|
||||||
|
log.Error("Error while defining data: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *TcpProxyScript) OnData(from, to net.Addr, data []byte) []byte {
|
||||||
|
if s.onDataScript != nil {
|
||||||
|
s.Lock()
|
||||||
|
defer s.Unlock()
|
||||||
|
|
||||||
|
err := s.doDefines(from, to, data)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Error while running bootstrap definitions: %s", err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ret, err := s.VM.Run(s.onDataScript)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Error while executing onData callback: %s", err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if ret.IsUndefined() == false && ret.IsString() {
|
||||||
|
return []byte(ret.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue