summaryrefslogtreecommitdiff
path: root/pkg/server/hook/tee.go
diff options
context:
space:
mode:
authorMikhail Osipov <mike.osipov@gmail.com>2020-02-29 00:58:01 +0300
committerMikhail Osipov <mike.osipov@gmail.com>2020-02-29 00:58:01 +0300
commitc55afd2de177f128fae6e1c52d0c56af17096258 (patch)
tree2b06eeabf4db3a6c7ef357fb1569c4e8f72aab68 /pkg/server/hook/tee.go
parent11501b56a751d2959480aaeaf2036eff586e5629 (diff)
rename module to hook
Diffstat (limited to 'pkg/server/hook/tee.go')
-rw-r--r--pkg/server/hook/tee.go120
1 files changed, 120 insertions, 0 deletions
diff --git a/pkg/server/hook/tee.go b/pkg/server/hook/tee.go
new file mode 100644
index 0000000..6591e33
--- /dev/null
+++ b/pkg/server/hook/tee.go
@@ -0,0 +1,120 @@
+package hook
+
+import (
+ "bytes"
+ "encoding/hex"
+ "fmt"
+ "os"
+ "path"
+ "sync"
+ "tunnel/pkg/server/env"
+ "tunnel/pkg/server/opts"
+ "tunnel/pkg/server/queue"
+)
+
+const teeDefaultFile = "/tmp/tunnel/dump"
+
+type tee struct {
+ f *os.File
+ mu sync.Mutex
+ wg sync.WaitGroup
+}
+
+type teeHook struct {
+ file string
+}
+
+func (t *tee) dump(s string, p []byte) error {
+ var out bytes.Buffer
+
+ fmt.Fprintln(&out, s, len(p))
+
+ w := hex.Dumper(&out)
+ w.Write(p)
+ w.Close()
+
+ if _, err := t.f.Write(out.Bytes()); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func (t *tee) Send(rq, wq queue.Q) error {
+ defer t.wg.Done()
+
+ for b := range rq {
+ t.dump(">", b)
+ wq <- b
+ }
+
+ return nil
+}
+
+func (t *tee) Recv(rq, wq queue.Q) error {
+ defer t.wg.Done()
+
+ for b := range rq {
+ t.dump("<", b)
+ wq <- b
+ }
+
+ return nil
+}
+
+func (h *teeHook) where(env env.Env) string {
+ if h.file != "" {
+ return h.file
+ }
+
+ if v := env.Eval("@{tunnel.@{tunnel}.tee.file}"); v != "" {
+ return v
+ }
+
+ if v, ok := env.Find("hook.tee.file"); ok {
+ return v
+ }
+
+ return teeDefaultFile
+}
+
+func (h *teeHook) Open(env env.Env) (interface{}, error) {
+ file := h.where(env)
+ dir := path.Dir(file)
+
+ if err := os.MkdirAll(dir, 0755); err != nil {
+ return nil, err
+ }
+
+ tid, sid := env.Get("tunnel"), env.Get("stream")
+ name := fmt.Sprintf("%s.%s.%s", file, tid, sid)
+
+ var t tee
+
+ if f, err := os.Create(name); err != nil {
+ return nil, err
+ } else {
+ t.f = f
+ }
+
+ t.wg.Add(2)
+
+ go func() {
+ t.wg.Wait()
+ t.f.Close()
+ }()
+
+ return &t, nil
+}
+
+func newTeeHook(opts opts.Opts, env env.Env) (hook, error) {
+ h := &teeHook{}
+ if file, ok := opts["file"]; ok {
+ h.file = file
+ }
+ return h, nil
+}
+
+func init() {
+ register("tee", newTeeHook)
+}