aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGalen Guyer <galen@galenguyer.com>2023-03-23 10:36:50 -0400
committerGalen Guyer <galen@galenguyer.com>2023-03-23 10:39:59 -0400
commitf85c79337c496330a3c3f5fe0402a2c353030432 (patch)
tree8f0f24cd2e3ef124c440eb2d7f9d02e6d5a2210d
today i woke up and chose violence
-rw-r--r--.gitignore1
-rw-r--r--LICENSE19
-rw-r--r--README.md3
-rw-r--r--go.mod3
-rw-r--r--go.sum0
-rw-r--r--main.go117
6 files changed, 143 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..8f7b496
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+lolproxy
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..0293fae
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2023 Galen Guyer <galen@galenguyer.com>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, but NOT including the right to run, execute or use the
+Software or any executable binaries built from the source code.
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..586b1f1
--- /dev/null
+++ b/README.md
@@ -0,0 +1,3 @@
+# lolproxy
+
+"some fuckshit that changes your response codes"
diff --git a/go.mod b/go.mod
new file mode 100644
index 0000000..ada15c9
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,3 @@
+module github.com/galenguyer/lolproxy
+
+go 1.20
diff --git a/go.sum b/go.sum
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/go.sum
diff --git a/main.go b/main.go
new file mode 100644
index 0000000..624c73c
--- /dev/null
+++ b/main.go
@@ -0,0 +1,117 @@
+package main
+
+import (
+ "flag"
+ "log"
+ "math/rand"
+ "net/http"
+ "net/http/httputil"
+ "net/url"
+)
+
+func main() {
+ host := flag.String("host", "localhost:6969", "host to bind to")
+ upstreamFlag := flag.String("upstream", "", "upstream host to proxy to")
+ only404 := flag.Bool("only404", false, "only change 404 status code")
+ flag.Parse()
+
+ if *upstreamFlag == "" {
+ log.Fatal("--upstream is required")
+ }
+ upstream, err := url.Parse(*upstreamFlag)
+ if err != nil {
+ log.Fatal(err)
+ }
+ if upstream.Host == "" {
+ log.Fatal("upstream host is required")
+ }
+ if upstream.Scheme == "" {
+ upstream.Scheme = "http"
+ }
+
+ statusCodes := [...]int{
+ http.StatusContinue,
+ http.StatusSwitchingProtocols,
+ http.StatusProcessing,
+ http.StatusEarlyHints,
+ http.StatusOK,
+ http.StatusCreated,
+ http.StatusAccepted,
+ http.StatusNonAuthoritativeInfo,
+ http.StatusNoContent,
+ http.StatusResetContent,
+ http.StatusPartialContent,
+ http.StatusMultiStatus,
+ http.StatusAlreadyReported,
+ http.StatusIMUsed,
+ http.StatusMultipleChoices,
+ http.StatusMovedPermanently,
+ http.StatusFound,
+ http.StatusSeeOther,
+ http.StatusNotModified,
+ http.StatusUseProxy,
+ http.StatusTemporaryRedirect,
+ http.StatusPermanentRedirect,
+ http.StatusBadRequest,
+ http.StatusUnauthorized,
+ http.StatusPaymentRequired,
+ http.StatusForbidden,
+ http.StatusNotFound,
+ http.StatusMethodNotAllowed,
+ http.StatusNotAcceptable,
+ http.StatusProxyAuthRequired,
+ http.StatusRequestTimeout,
+ http.StatusConflict,
+ http.StatusGone,
+ http.StatusLengthRequired,
+ http.StatusPreconditionFailed,
+ http.StatusRequestEntityTooLarge,
+ http.StatusRequestURITooLong,
+ http.StatusUnsupportedMediaType,
+ http.StatusRequestedRangeNotSatisfiable,
+ http.StatusExpectationFailed,
+ http.StatusTeapot,
+ http.StatusMisdirectedRequest,
+ http.StatusUnprocessableEntity,
+ http.StatusLocked,
+ http.StatusFailedDependency,
+ http.StatusTooEarly,
+ http.StatusUpgradeRequired,
+ http.StatusPreconditionRequired,
+ http.StatusTooManyRequests,
+ http.StatusRequestHeaderFieldsTooLarge,
+ http.StatusUnavailableForLegalReasons,
+ http.StatusInternalServerError,
+ http.StatusNotImplemented,
+ http.StatusBadGateway,
+ http.StatusServiceUnavailable,
+ http.StatusGatewayTimeout,
+ http.StatusHTTPVersionNotSupported,
+ http.StatusVariantAlsoNegotiates,
+ http.StatusInsufficientStorage,
+ http.StatusLoopDetected,
+ http.StatusNotExtended,
+ http.StatusNetworkAuthenticationRequired,
+ }
+
+ proxy := &httputil.ReverseProxy{
+ Rewrite: func(req *httputil.ProxyRequest) {
+ req.SetURL(upstream)
+ },
+ }
+
+ proxy.ModifyResponse = func(resp *http.Response) error {
+ originStatus := resp.StatusCode
+ if *only404 {
+ resp.StatusCode = http.StatusNotFound
+ } else {
+ resp.StatusCode = statusCodes[rand.Intn(len(statusCodes))]
+ }
+ log.Printf("status code %d (%s) changed to %d (%s) for path %s", originStatus, http.StatusText(originStatus), resp.StatusCode, http.StatusText(resp.StatusCode), resp.Request.URL.Path)
+ return nil
+ }
+
+ log.Println("listening on", *host)
+ log.Println("proxying requests to", upstream.String())
+ log.Fatal(http.ListenAndServe(*host, proxy))
+}