From 65cc6e8d8b689f90acc921568c724d79a2275415 Mon Sep 17 00:00:00 2001 From: Bel LaPointe Date: Fri, 3 Apr 2020 12:59:00 -0600 Subject: [PATCH] initial --- .proxy.go | 59 ++++++++++++++++++ main.go | 177 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 236 insertions(+) create mode 100755 .proxy.go create mode 100755 main.go diff --git a/.proxy.go b/.proxy.go new file mode 100755 index 0000000..bfe5e8b --- /dev/null +++ b/.proxy.go @@ -0,0 +1,59 @@ +package main + +import ( + "flag" + "io" + "log" + "net" + "net/http" + "net/http/httputil" + "time" +) + +func main() { + port := flag.String("p", "8889", "port to bind to") + flag.Parse() + + log.Printf("listening on %s", *port) + if err := http.ListenAndServe(":"+*port, http.HandlerFunc(echo)); err != nil { + panic(err) + } +} +func echo(w http.ResponseWriter, r *http.Request) { + b, _ := httputil.DumpRequest(r, true) + log.Printf("DUMP:\n%s", b) + u := *r.URL + u.Path = "" + proxy := httputil.NewSingleHostReverseProxy(&u) + proxy.ServeHTTP(w, r) +} + +func echo2(w http.ResponseWriter, r *http.Request) { + log.Printf("echo start") + dest_conn, err := net.DialTimeout("tcp", r.Host, 10*time.Second) + if err != nil { + http.Error(w, err.Error(), http.StatusServiceUnavailable) + return + } + log.Printf("echo dialed") + hijacker, ok := w.(http.Hijacker) + if !ok { + http.Error(w, "Hijacking not supported", http.StatusInternalServerError) + return + } + client_conn, _, err := hijacker.Hijack() + if err != nil { + http.Error(w, err.Error(), http.StatusServiceUnavailable) + } + log.Printf("echo hijacked") + + transfer := func(destination io.WriteCloser, source io.ReadCloser) { + defer destination.Close() + defer source.Close() + io.Copy(destination, source) + } + + go transfer(dest_conn, client_conn) + go transfer(client_conn, dest_conn) + log.Printf("echo transferred") +} diff --git a/main.go b/main.go new file mode 100755 index 0000000..f77848d --- /dev/null +++ b/main.go @@ -0,0 +1,177 @@ +package main + +import ( + "crypto/tls" + "encoding/pem" + "flag" + "fmt" + "io/ioutil" + "log" + "net" + "net/http" + "os" + "os/signal" + "time" + + "gitlab-app.eng.qops.net/golang/jwt" + "golang.org/x/crypto/pkcs12" +) + +func envOrDefault(key, def string) string { + if v := os.Getenv(key); v != "" { + return v + } + return def +} + +func main() { + port := flag.String("p", envOrDefault("PORT", "41912"), "port to run on") + crt := flag.String("crt", envOrDefault("CRT", ""), "path to crt") + key := flag.String("key", envOrDefault("KEY", ""), "path to key") + tcp := flag.Bool("tcp", false, "accept TCP") + fail := flag.Bool("fail", false, "fail connections forever") + block := flag.Int("block", 0, "seconds to block connections") + status := flag.Int("status", http.StatusOK, "status to always return") + jwt := flag.String("jwt", envOrDefault("SECRET", ""), "secret for JWT") + flag.Parse() + + // start server + if *tcp { + startTCP(*port, *fail, *block) + } else { + startHTTP(*port, *fail, *block, *jwt, *crt, *key, *status) + } + + // catch stop + stop := make(chan os.Signal) + signal.Notify(stop, os.Interrupt) + <-stop +} + +func startTCP(port string, fail bool, block int) { + l, err := net.Listen("tcp", ":"+port) + if err != nil { + panic(err) + } + go func() { + for { + c, err := l.Accept() + if err != nil { + panic(err) + } + + go func(c net.Conn) { + defer c.Close() + if block > 0 { + time.Sleep(time.Second * time.Duration(block)) + } + fmt.Fprintln(c, "Hello") + }(c) + } + defer l.Close() + }() +} + +func startHTTP(port string, fail bool, block int, secret, crt, key string, status int) { + srv := &http.Server{ + Addr: ":" + port, + Handler: makeHTTPHandler(fail, block, secret, status), + } + go func() { + if crt == "" || key == "" { + if err := srv.ListenAndServe(); err != nil { + panic(err) + } + } else { + if _, err := os.Stat(key); err == nil { + if err := srv.ListenAndServeTLS(crt, key); err != nil { + panic(err) + } + } else { + b, err := ioutil.ReadFile(crt) + if err != nil { + panic(err) + } + blocks, err := pkcs12.ToPEM(b, key) + if err != nil { + panic(err) + } + pd := []byte{} + for _, block := range blocks { + pd = append(pd, pem.EncodeToMemory(block)...) + } + cert, err := tls.X509KeyPair(pd, pd) + if err != nil { + panic(err) + } + srv.TLSConfig = &tls.Config{ + Certificates: []tls.Certificate{cert}, + } + if err := srv.ListenAndServeTLS("", ""); err != nil { + panic(err) + } + } + } + }() + log.Println("Listening on", srv.Addr) +} + +func makeHTTPHandler(fail bool, block int, secret string, status int) http.HandlerFunc { + if block > 0 { + return blockH(block, fail) + } else if fail { + return http.HandlerFunc(failH) + } + return echoH(secret, status) +} + +func failH(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusInternalServerError) +} + +func blockH(block int, fail bool) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + select { + case <-time.After(time.Second * time.Duration(block)): + case <-r.Context().Done(): + log.Println(r.Context().Err()) + fmt.Fprintln(w, r.Context().Err()) + w.WriteHeader(http.StatusInternalServerError) + } + if fail { + w.WriteHeader(http.StatusInternalServerError) + } + } +} + +func echoH(secret string, status int) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + log.Println("METHOD:", r.Method) + log.Println("URL:", r.URL.String()) + log.Println("HEADER:", r.Header) + if secret != "" { + verifier := jwt.Verifier{Key: []byte(secret)} + _, err := verifier.Verify(r) + if err != nil { + w.WriteHeader(http.StatusUnauthorized) + fmt.Fprintln(w, "ERR: failed verifying jwt:", err) + log.Println("ERR: failed verifying jwt:", err) + return + } + } + b, err := ioutil.ReadAll(r.Body) + if err != nil { + return + } + s := string(b[:]) + log.Println("BODY:", s) + + w.WriteHeader(status) + fmt.Fprintf(w, "===\nMETHOD: %q\nURL: %q\nHEADER: %q\nBODY: %q\n===\n", + r.Method, + r.URL.String(), + fmt.Sprintf("%v", r.Header), + s, + ) + } +}