diff options
author | Galen Guyer <galen@galenguyer.com> | 2023-03-23 10:36:50 -0400 |
---|---|---|
committer | Galen Guyer <galen@galenguyer.com> | 2023-03-23 10:39:59 -0400 |
commit | f85c79337c496330a3c3f5fe0402a2c353030432 (patch) | |
tree | 8f0f24cd2e3ef124c440eb2d7f9d02e6d5a2210d |
today i woke up and chose violence
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | LICENSE | 19 | ||||
-rw-r--r-- | README.md | 3 | ||||
-rw-r--r-- | go.mod | 3 | ||||
-rw-r--r-- | go.sum | 0 | ||||
-rw-r--r-- | main.go | 117 |
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 @@ -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" @@ -0,0 +1,3 @@ +module github.com/galenguyer/lolproxy + +go 1.20 @@ -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)) +} |