Difference between revisions of "Gorelay"
Jump to navigation
Jump to search
(Created page with "# Simple HTTP Relay written in go ``` package main import ( "crypto/tls" "github.com/labstack/echo/v4" "io" "net/http" ) func main() {...") |
|||
| (3 intermediate revisions by the same user not shown) | |||
| Line 1: | Line 1: | ||
# Simple HTTP Relay written in go | # Simple HTTP Relay written in go | ||
| + | |||
| + | ## run.sh | ||
| + | ``` | ||
| + | #!/bin/bash | ||
| + | set -eu | ||
| + | |||
| + | go build gorelay.go | ||
| + | pkill gorelay || true | ||
| + | sleep 2 | ||
| + | ./gorelay -fqdn="192.168.x.y" -port=8443 -username="admin" -password="admin" -skip_tls_verify=true -uri_reg_old "/api/v1/foo/" -uri_reg_new "/api/v1/bar/" | ||
| + | ``` | ||
| + | ## curl | ||
| + | ``` | ||
| + | cat <<EOF > example.json | ||
| + | { | ||
| + | "foo": "bar" | ||
| + | } | ||
| + | |||
| + | curl -sku $AUTH -X POST -d @example.json https://proxyhost.example.com/foo | ||
| + | ``` | ||
| + | |||
| + | ## gorelay.go | ||
``` | ``` | ||
package main | package main | ||
| Line 5: | Line 27: | ||
import ( | import ( | ||
"crypto/tls" | "crypto/tls" | ||
| − | " | + | "flag" |
| + | "fmt" | ||
"io" | "io" | ||
| + | "log" | ||
"net/http" | "net/http" | ||
| + | "regexp" | ||
| + | "time" | ||
| + | |||
| + | "github.com/labstack/echo/v4" | ||
) | ) | ||
| + | |||
| + | func syslogLogger(next echo.HandlerFunc) echo.HandlerFunc { | ||
| + | return func(c echo.Context) error { | ||
| + | start := time.Now() | ||
| + | err := next(c) | ||
| + | stop := time.Now() | ||
| + | req := c.Request() | ||
| + | res := c.Response() | ||
| + | |||
| + | log.Printf("%s - [%s] \"%s %s %s\" %d %d %v", | ||
| + | c.RealIP(), | ||
| + | stop.Format(time.RFC3339), | ||
| + | req.Method, req.RequestURI, req.Proto, | ||
| + | res.Status, res.Size, stop.Sub(start), | ||
| + | ) | ||
| + | |||
| + | return err | ||
| + | } | ||
| + | } | ||
func main() { | func main() { | ||
| + | schema := flag.String("schema", "https", "URI schema (http or https)") | ||
| + | port := flag.Int("port", 443, "Port number of the remote HTTPS endpoint") | ||
| + | fqdn := flag.String("fqdn", "", "Fully Qualified Domain Name (required)") | ||
| + | username := flag.String("username", "", "Username for basic authentication") | ||
| + | password := flag.String("password", "", "Password for basic authentication") | ||
| + | skipTLS := flag.Bool("skip_tls_verify", false, "Skip TLS certificate verification") | ||
| + | uriRegOld := flag.String("uri_reg_old", "", "Regex to replace in URI") | ||
| + | uriRegNew := flag.String("uri_reg_new", "", "String to replace old URI") | ||
| + | flag.Parse() | ||
| + | |||
| + | if *fqdn == "" { | ||
| + | panic("FQDN argument is required") | ||
| + | } | ||
| + | |||
| + | uriBase := fmt.Sprintf("%s://%s:%d", *schema, *fqdn, *port) | ||
| + | |||
e := echo.New() | e := echo.New() | ||
| + | |||
| + | e.Use(syslogLogger) | ||
e.Any("/*", func(c echo.Context) error { | e.Any("/*", func(c echo.Context) error { | ||
| Line 17: | Line 82: | ||
client := &http.Client{} | client := &http.Client{} | ||
| − | client.Transport = &http.Transport{ | + | if *skipTLS { |
| − | + | client.Transport = &http.Transport{ | |
| + | TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, | ||
| + | } | ||
} | } | ||
| + | regex := regexp.MustCompile(*uriRegOld) | ||
| + | replaceStr := *uriRegNew | ||
| + | requestURI := regex.ReplaceAllString(req.RequestURI, replaceStr) | ||
| − | + | newReq, err := http.NewRequest(req.Method, uriBase+requestURI, req.Body) | |
| − | newReq, err := http.NewRequest(req.Method, | ||
if err != nil { | if err != nil { | ||
return err | return err | ||
} | } | ||
| − | + | ||
for k, v := range req.Header { | for k, v := range req.Header { | ||
newReq.Header[k] = v | newReq.Header[k] = v | ||
| + | } | ||
| + | if *username != "" && *password != "" { | ||
| + | newReq.SetBasicAuth(*username, *password) | ||
} | } | ||
| − | |||
resp, err := client.Do(newReq) | resp, err := client.Do(newReq) | ||
if err != nil { | if err != nil { | ||
| Line 39: | Line 110: | ||
defer resp.Body.Close() | defer resp.Body.Close() | ||
| − | |||
for k, v := range resp.Header { | for k, v := range resp.Header { | ||
c.Response().Header().Set(k, v[0]) | c.Response().Header().Set(k, v[0]) | ||
} | } | ||
| − | |||
io.Copy(c.Response().Writer, resp.Body) | io.Copy(c.Response().Writer, resp.Body) | ||
| Line 50: | Line 119: | ||
}) | }) | ||
| − | e.Start(":8080") | + | e.Logger.Fatal(e.Start(":8080")) |
} | } | ||
``` | ``` | ||
Latest revision as of 02:56, 3 May 2024
Simple HTTP Relay written in go
run.sh
#!/bin/bash set -eu go build gorelay.go pkill gorelay || true sleep 2 ./gorelay -fqdn="192.168.x.y" -port=8443 -username="admin" -password="admin" -skip_tls_verify=true -uri_reg_old "/api/v1/foo/" -uri_reg_new "/api/v1/bar/"
curl
cat <<EOF > example.json
{
"foo": "bar"
}
curl -sku $AUTH -X POST -d @example.json https://proxyhost.example.com/foo
gorelay.go
package main
import (
"crypto/tls"
"flag"
"fmt"
"io"
"log"
"net/http"
"regexp"
"time"
"github.com/labstack/echo/v4"
)
func syslogLogger(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
start := time.Now()
err := next(c)
stop := time.Now()
req := c.Request()
res := c.Response()
log.Printf("%s - [%s] \"%s %s %s\" %d %d %v",
c.RealIP(),
stop.Format(time.RFC3339),
req.Method, req.RequestURI, req.Proto,
res.Status, res.Size, stop.Sub(start),
)
return err
}
}
func main() {
schema := flag.String("schema", "https", "URI schema (http or https)")
port := flag.Int("port", 443, "Port number of the remote HTTPS endpoint")
fqdn := flag.String("fqdn", "", "Fully Qualified Domain Name (required)")
username := flag.String("username", "", "Username for basic authentication")
password := flag.String("password", "", "Password for basic authentication")
skipTLS := flag.Bool("skip_tls_verify", false, "Skip TLS certificate verification")
uriRegOld := flag.String("uri_reg_old", "", "Regex to replace in URI")
uriRegNew := flag.String("uri_reg_new", "", "String to replace old URI")
flag.Parse()
if *fqdn == "" {
panic("FQDN argument is required")
}
uriBase := fmt.Sprintf("%s://%s:%d", *schema, *fqdn, *port)
e := echo.New()
e.Use(syslogLogger)
e.Any("/*", func(c echo.Context) error {
req := c.Request()
client := &http.Client{}
if *skipTLS {
client.Transport = &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
}
regex := regexp.MustCompile(*uriRegOld)
replaceStr := *uriRegNew
requestURI := regex.ReplaceAllString(req.RequestURI, replaceStr)
newReq, err := http.NewRequest(req.Method, uriBase+requestURI, req.Body)
if err != nil {
return err
}
for k, v := range req.Header {
newReq.Header[k] = v
}
if *username != "" && *password != "" {
newReq.SetBasicAuth(*username, *password)
}
resp, err := client.Do(newReq)
if err != nil {
return err
}
defer resp.Body.Close()
for k, v := range resp.Header {
c.Response().Header().Set(k, v[0])
}
io.Copy(c.Response().Writer, resp.Body)
return nil
})
e.Logger.Fatal(e.Start(":8080"))
}