Merge branch 'caddy2' into v2multiauth

This commit is contained in:
Mygod 2023-07-19 13:33:38 -04:00
commit a29f011386
20 changed files with 1071 additions and 698 deletions

14
.github/dependabot.yml vendored Normal file
View file

@ -0,0 +1,14 @@
version: 2
updates:
- package-ecosystem: "gomod"
directory: "/"
schedule:
interval: "daily"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"
- package-ecosystem: "docker"
directory: "/"
schedule:
interval: "daily"

33
.github/workflows/go-critic.yml vendored Normal file
View file

@ -0,0 +1,33 @@
name: Gocritic Scan
on:
push:
branches:
- "master"
- "main"
paths-ignore:
- "**.md"
pull_request:
branches:
- "*"
paths-ignore:
- "**.md"
jobs:
gocritic-scan:
runs-on: ubuntu-latest
env:
GO111MODULE: on
steps:
- name: Fetch Repository
uses: actions/checkout@v3
- name: Install Go
uses: actions/setup-go@v4
with:
go-version: 'stable'
check-latest: true
cache: false
- name: Install go-critic
run: go install -v github.com/go-critic/go-critic/cmd/gocritic@latest
- name: Run gocritic
run: gocritic check -checkTests=False ./...

25
.github/workflows/golangci-lint.yml vendored Normal file
View file

@ -0,0 +1,25 @@
name: Golangci Lint Check
on:
push:
branches:
- "master"
- "main"
paths-ignore:
- "**.md"
pull_request:
branches:
- "*"
paths-ignore:
- "**.md"
jobs:
golangci-lint:
runs-on: ubuntu-latest
steps:
- name: Fetch Repository
uses: actions/checkout@v3
- name: Run golangci-lint
uses: reviewdog/action-golangci-lint@v2
with:
golangci_lint_flags: "--tests=false"

33
.github/workflows/gosec.yml vendored Normal file
View file

@ -0,0 +1,33 @@
name: Gosec Security Scan
on:
push:
branches:
- "master"
- "main"
paths-ignore:
- "**.md"
pull_request:
branches:
- "*"
paths-ignore:
- "**.md"
jobs:
gosec-scan:
runs-on: ubuntu-latest
env:
GO111MODULE: on
steps:
- name: Fetch Repository
uses: actions/checkout@v3
- name: Install Go
uses: actions/setup-go@v4
with:
go-version: 'stable'
check-latest: true
cache: false
- name: Install Gosec
run: go install github.com/securego/gosec/v2/cmd/gosec@latest
- name: Run Gosec
run: gosec ./...

33
.github/workflows/govulncheck.yml vendored Normal file
View file

@ -0,0 +1,33 @@
name: Govulncheck Security Scan
on:
push:
branches:
- "master"
- "main"
paths-ignore:
- "**.md"
pull_request:
branches:
- "*"
paths-ignore:
- "**.md"
jobs:
govulncheck-check:
runs-on: ubuntu-latest
env:
GO111MODULE: on
steps:
- name: Fetch Repository
uses: actions/checkout@v3
- name: Install Go
uses: actions/setup-go@v4
with:
go-version: 'stable'
check-latest: true
cache: false
- name: Install Govulncheck
run: go install golang.org/x/vuln/cmd/govulncheck@latest
- name: Run Govulncheck
run: govulncheck ./...

33
.github/workflows/staticcheck.yml vendored Normal file
View file

@ -0,0 +1,33 @@
name: Staticcheck Scan
on:
push:
branches:
- "master"
- "main"
paths-ignore:
- "**.md"
pull_request:
branches:
- "*"
paths-ignore:
- "**.md"
jobs:
staticcheck-scan:
runs-on: ubuntu-latest
env:
GO111MODULE: on
steps:
- name: Fetch Repository
uses: actions/checkout@v3
- name: Install Go
uses: actions/setup-go@v4
with:
go-version: 'stable'
check-latest: true
cache: false
- name: Install staticcheck
run: go install honnef.co/go/tools/cmd/staticcheck@latest
- name: Run staticcheck
run: staticcheck -tests=False ./...

35
.github/workflows/tests.yml vendored Normal file
View file

@ -0,0 +1,35 @@
name: "Tests"
on:
push:
branches:
- "master"
- "main"
paths-ignore:
- "**.md"
pull_request:
branches:
- "*"
paths-ignore:
- "**.md"
jobs:
Tests:
strategy:
matrix:
go-version:
- stable
platform:
- ubuntu-latest
runs-on: ${{ matrix.platform }}
steps:
- name: Fetch Repository
uses: actions/checkout@v3
- name: Install Go
uses: actions/setup-go@v4
with:
go-version: '${{ matrix.go-version }}'
- name: Run test
run: go test -v ./...
- name: Run test -race
run: go test -v -race ./...

View file

@ -1,4 +0,0 @@
# golangci linter currently requires a config file to
# disable checking of the test files
run:
tests: false

View file

@ -1,16 +0,0 @@
language: go
go:
- 1.15.x
env:
- GO111MODULE=on
dist: trusty
install:
- go get -v -t -d ./...
- go get -v github.com/golangci/golangci-lint/cmd/golangci-lint
script:
- go test -race -v .
- golangci-lint run -E gofmt -E goimports -E misspell -E ineffassign -E staticcheck -E gosimple -D errcheck

View file

@ -1,7 +1,81 @@
# Secure forward proxy plugin for the Caddy web server
# Secure forward proxy for the Caddy web server
This package registers the `http.handlers.forward_proxy` module, which acts as an HTTPS proxy for accessing remote networks.
## :warning: Experimental!
This module is EXPERIMENTAL. We need more users to test this module for bugs and weaknesses before we recommend its use from within surveilled networks or regions with active censorship. Do not rely on this code in situations where personal safety, freedom, or privacy are at risk.
**You can help by:**
- Safely deploying this module
- Trying to break it
- Contributing to the code and tests in this repo to make it better
We are also seeking experienced maintainers who have experience with these kinds of technologies and who are interested in continuing its development.
**Expect breaking changes.**
## Features
- HTTP/1.1 and HTTP/2 support
- Authentication
- Access control lists
- Optional probe resistance
- PAC file
## Introduction
This Caddy module allows you to use your web server as a proxy server, configurable by numerous HTTP clients such as operating systems, web browsers, mobile devices, and apps. However, the feature set of each client varies widely, as does their correctness and security guarantees. You will have to be aware of each clients' individual weaknesses or shortcomings.
## Quick start
First, you will have to know [how to use Caddy](https://caddyserver.com/docs/getting-started).
Build Caddy with this plugin. You can add it from [Caddy's download page](https://caddyserver.com/download) or build it yourself with [xcaddy](https://github.com/caddyserver/xcaddy):
```
$ xcaddy build --with github.com/caddyserver/forwardproxy@caddy2
```
Most people prefer the [Caddyfile](https://caddyserver.com/docs/caddyfile) for configuration. You can stand up a simple, wide-open unauthenticated forward proxy like this:
```
example.com
route {
# UNAUTHENTICATED! USE ONLY FOR TESTING
forward_proxy
}
```
(Obviously, replace `example.com` with your domain name which is pointed at your machine.)
Because `forward_proxy` is not a standard directive, its ordering relative to other handler directives is not defined, so we put it inside a `route` block. You can alternatively do something like this:
```
{
order forward_proxy before file_server
}
example.com
# UNAUTHENTICATED! USE ONLY FOR TESTING
forward_proxy
```
to define its position globally; then you don't need `route` blocks. The correct order is up to you and depends on your config.
[![Build Status](https://travis-ci.org/caddyserver/forwardproxy.svg?branch=master)](https://travis-ci.org/caddyserver/forwardproxy)
[![Join the chat at https://gitter.im/forwardproxy/Lobby](https://badges.gitter.im/forwardproxy/Lobby.svg)](https://gitter.im/forwardproxy/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
This plugin enables [Caddy](https://caddyserver.com) to act as a forward proxy, with support for HTTP/2.0 and HTTP/1.1 requests. HTTP/2.0 will usually improve performance due to multiplexing.
@ -24,8 +98,8 @@ Here's an example of all properties in use (note that the syntax is subject to c
:443, example.com
route {
forward_proxy {
basicauth user1 password1
basicauth user2 password2
basic_auth user1 0NtCL2JPJBgPPMmlPcJ
basic_auth user2 密码
ports 80 443
hide_ip
hide_via
@ -147,9 +221,9 @@ Don't forget to add `http.forwardproxy` plugin.
#### Build from source
0. Install latest Golang 1.12 or above and set export GO111MODULE=on
0. Install latest Golang 1.20 or above and set export GO111MODULE=on
1. ```bash
go install github.com/caddyserver/forwardproxy/cmd/caddy
go install github.com/caddyserver/forwardproxy/cmd/caddy@latest
```
Built `caddy` binary will be stored in $GOPATH/bin.

6
acl.go
View file

@ -37,7 +37,6 @@ func (a *aclIPRule) tryMatch(ip net.IP, domain string) aclDecision {
return aclDecisionAllow
}
return aclDecisionDeny
}
type aclDomainRule struct {
@ -47,9 +46,8 @@ type aclDomainRule struct {
}
func (a *aclDomainRule) tryMatch(ip net.IP, domain string) aclDecision {
if strings.HasSuffix(domain, ".") {
domain = domain[:len(domain)-1]
}
domain = strings.TrimPrefix(domain, ".")
if domain == a.domain ||
a.subdomainsAllowed && strings.HasSuffix(domain, "."+a.domain) {
if a.allow {

View file

@ -6,7 +6,7 @@ import (
"strconv"
"strings"
"github.com/caddyserver/caddy/v2"
caddy "github.com/caddyserver/caddy/v2"
"github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
"github.com/caddyserver/caddy/v2/caddyconfig/httpcaddyfile"
"github.com/caddyserver/caddy/v2/modules/caddyhttp"
@ -147,7 +147,7 @@ func (h *Handler) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
aclAllow := false
switch aclDirective {
case "allow":
ruleSubjects = args[:]
ruleSubjects = args
aclAllow = true
case "allow_file":
if len(args) != 1 {
@ -159,7 +159,7 @@ func (h *Handler) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
}
aclAllow = true
case "deny":
ruleSubjects = args[:]
ruleSubjects = args
case "deny_file":
if len(args) != 1 {
return d.Err("denyfile accepts a single filename argument")

View file

@ -8,7 +8,6 @@ import (
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net"
"net/http"
"net/http/httputil"
@ -25,11 +24,12 @@ import (
"github.com/caddyserver/caddy/v2/modules/caddytls"
)
var credentialsEmpty = ""
var credentialsCorrectPlain = "test:pass"
var credentialsCorrect = "Basic dGVzdDpwYXNz" // test:pass
var credentialsUpstreamCorrect = "basic dXBzdHJlYW10ZXN0OnVwc3RyZWFtcGFzcw==" // upstreamtest:upstreampass
var credentialsWrong = []string{
var (
credentialsEmpty = ""
credentialsCorrectPlain = "test:pass"
credentialsCorrect = "Basic dGVzdDpwYXNz" // test:pass
credentialsUpstreamCorrect = "basic dXBzdHJlYW10ZXN0OnVwc3RyZWFtcGFzcw==" // upstreamtest:upstreampass
credentialsWrong = []string{
"",
"\"\"",
"Basic dzp3",
@ -38,6 +38,7 @@ var credentialsWrong = []string{
"Tssssssss",
"Basic dpz3 asp",
}
)
/*
Test naming: Test{httpVer}Proxy{Method}{Auth}{Credentials}{httpVer}
@ -45,17 +46,21 @@ GET/CONNECT -- get gets, connect connects and gets
Auth/NoAuth
Empty/Correct/Wrong -- tries different credentials
*/
var testResources = []string{"/", "/pic.png"}
var testHTTPProxyVersions = []string{"HTTP/2.0", "HTTP/1.1"}
var testHTTPTargetVersions = []string{"HTTP/1.1"}
var httpVersionToALPN = map[string]string{
var (
testResources = []string{"/", "/pic.png"}
testHTTPProxyVersions = []string{"HTTP/2.0", "HTTP/1.1"}
testHTTPTargetVersions = []string{"HTTP/1.1"}
httpVersionToALPN = map[string]string{
"HTTP/1.1": "http/1.1",
"HTTP/2.0": "h2",
}
)
var blacklistedDomain = "google-public-dns-a.google.com" // supposed to ever resolve to one of 2 IP addresses below
var blacklistedIPv4 = "8.8.8.8"
var blacklistedIPv6 = "2001:4860:4860::8888"
var (
blacklistedDomain = "google-public-dns-a.google.com" // supposed to ever resolve to one of 2 IP addresses below
blacklistedIPv4 = "8.8.8.8"
blacklistedIPv6 = "2001:4860:4860::8888"
)
type caddyTestServer struct {
addr string
@ -144,14 +149,14 @@ func (c *caddyTestServer) server() *caddyhttp.Server {
if c.contents == nil {
c.contents = make(map[string][]byte)
}
index, err := ioutil.ReadFile(c.root + "/index.html")
index, err := os.ReadFile(c.root + "/index.html")
if err != nil {
panic(err)
}
c.contents[""] = index
c.contents["/"] = index
c.contents["/index.html"] = index
c.contents["/pic.png"], err = ioutil.ReadFile(c.root + "/pic.png")
c.contents["/pic.png"], err = os.ReadFile(c.root + "/pic.png")
if err != nil {
panic(err)
}
@ -160,6 +165,7 @@ func (c *caddyTestServer) server() *caddyhttp.Server {
}
// For simulating/mimicing Caddy's built-in auto-HTTPS redirects. Super hacky but w/e.
func (c *caddyTestServer) redirServer() *caddyhttp.Server {
return &caddyhttp.Server{
Listen: []string{":" + c.httpRedirPort},

View file

@ -1,4 +1,4 @@
FROM alpine:3.6
FROM alpine:3.18.2
LABEL description="Docker image for caddy+forwardproxy plugin."
LABEL maintainer="SergeyFrolov@colorado.edu"

View file

@ -26,17 +26,17 @@ import (
"errors"
"fmt"
"io"
"io/ioutil"
"net"
"net/http"
"net/url"
"os"
"path/filepath"
"strconv"
"strings"
"sync"
"time"
"github.com/caddyserver/caddy/v2"
caddy "github.com/caddyserver/caddy/v2"
"github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
"github.com/caddyserver/caddy/v2/modules/caddyhttp"
"github.com/caddyserver/forwardproxy/httpclient"
@ -60,7 +60,7 @@ type Handler struct {
// If true, the Forwarded header will not be augmented with your IP address.
HideIP bool `json:"hide_ip,omitempty"`
// If true, the Via heaeder will not be added.
// If true, the Via header will not be added.
HideVia bool `json:"hide_via,omitempty"`
// Host(s) (and ports) of the proxy. When you configure a client,
@ -188,7 +188,7 @@ func (h *Handler) Provision(ctx caddy.Context) error {
// either way, it's impossible to have a legit TLS certificate for "127.0.0.1" - TODO: not true anymore
h.logger.Info("Localhost upstream detected, disabling verification of TLS certificate")
d.DialTLS = func(network string, address string) (net.Conn, string, error) {
conn, err := tls.Dial(network, address, &tls.Config{InsecureSkipVerify: true})
conn, err := tls.Dial(network, address, &tls.Config{InsecureSkipVerify: true}) // #nosec G402
if err != nil {
return nil, "", err
}
@ -345,17 +345,17 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyht
// make sure request is idempotent and could be retried by saving the Body
// None of those methods are supposed to have body,
// but we still need to copy the r.Body, even if it's empty
rBodyBuf, err := ioutil.ReadAll(r.Body)
rBodyBuf, err := io.ReadAll(r.Body)
if err != nil {
return caddyhttp.Error(http.StatusBadRequest,
fmt.Errorf("failed to read request body: %v", err))
}
r.GetBody = func() (io.ReadCloser, error) {
return ioutil.NopCloser(bytes.NewReader(rBodyBuf)), nil
return io.NopCloser(bytes.NewReader(rBodyBuf)), nil
}
r.Body, _ = r.GetBody()
}
response, err = h.httpTransport.RoundTrip(r)
response, _ = h.httpTransport.RoundTrip(r)
} else {
// Upstream requests don't interact well with Transport: connections could always be
// reused, but Transport thinks they go to different Hosts, so it spawns tons of
@ -384,7 +384,7 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyht
fmt.Errorf("failed to read upstream response: %v", err))
}
}
r.Body.Close()
err = r.Body.Close()
if response != nil {
defer response.Body.Close()
@ -406,7 +406,7 @@ func (h Handler) checkCredentials(r *http.Request) error {
return errors.New("Proxy-Authorization is required! Expected format: <type> <credentials>")
}
if strings.ToLower(pa[0]) != "basic" {
return errors.New("Auth type is not supported")
return errors.New("auth type is not supported")
}
for _, creds := range h.AuthCredentials {
if subtle.ConstantTimeCompare(creds, []byte(pa[1])) == 1 {
@ -421,7 +421,7 @@ func (h Handler) checkCredentials(r *http.Request) error {
return nil
}
}
return errors.New("Invalid credentials")
return errors.New("invalid credentials")
}
func (h Handler) shouldServePACFile(r *http.Request) bool {
@ -543,10 +543,10 @@ func serveHiddenPage(w http.ResponseWriter, authErr error) error {
if authErr != nil {
w.Header().Set("Proxy-Authenticate", "Basic realm=\"Caddy Secure Web Proxy\"")
w.WriteHeader(http.StatusProxyAuthRequired)
w.Write([]byte(fmt.Sprintf(hiddenPage, AuthFail)))
_, _ = w.Write([]byte(fmt.Sprintf(hiddenPage, AuthFail)))
return authErr
}
w.Write([]byte(fmt.Sprintf(hiddenPage, AuthOk)))
_, _ = w.Write([]byte(fmt.Sprintf(hiddenPage, AuthOk)))
return nil
}
@ -572,12 +572,14 @@ func serveHijack(w http.ResponseWriter, targetConn net.Conn) error {
if err != nil {
return caddyhttp.Error(http.StatusBadGateway, err)
}
targetConn.Write(rbuf)
_, _ = targetConn.Write(rbuf)
}
}
// Since we hijacked the connection, we lost the ability to write and flush headers via w.
// Let's handcraft the response and send it manually.
res := &http.Response{StatusCode: http.StatusOK,
res := &http.Response{
StatusCode: http.StatusOK,
Proto: "HTTP/1.1",
ProtoMajor: 1,
ProtoMinor: 1,
@ -585,7 +587,13 @@ func serveHijack(w http.ResponseWriter, targetConn net.Conn) error {
}
res.Header.Set("Server", "Caddy")
err = res.Write(clientConn)
buf := bufio.NewWriter(clientConn)
err = res.Write(buf)
if err != nil {
return caddyhttp.Error(http.StatusInternalServerError,
fmt.Errorf("failed to write response: %v", err))
}
err = buf.Flush()
if err != nil {
return caddyhttp.Error(http.StatusInternalServerError,
fmt.Errorf("failed to send response to client: %v", err))
@ -600,16 +608,18 @@ func serveHijack(w http.ResponseWriter, targetConn net.Conn) error {
func dualStream(target net.Conn, clientReader io.ReadCloser, clientWriter io.Writer) error {
stream := func(w io.Writer, r io.Reader) error {
// copy bytes from r to w
buf := bufferPool.Get().([]byte)
bufPtr := bufferPool.Get().(*[]byte)
buf := *bufPtr
buf = buf[0:cap(buf)]
_, _err := flushingIoCopy(w, r, buf)
bufferPool.Put(buf)
bufferPool.Put(bufPtr)
if cw, ok := w.(closeWriter); ok {
cw.CloseWrite()
_ = cw.CloseWrite()
}
return _err
}
go stream(target, clientReader)
go stream(target, clientReader) //nolint: errcheck
return stream(clientWriter, target)
}
@ -664,10 +674,11 @@ func forwardResponse(w http.ResponseWriter, response *http.Response) error {
}
removeHopByHop(w.Header())
w.WriteHeader(response.StatusCode)
buf := bufferPool.Get().([]byte)
bufPtr := bufferPool.Get().(*[]byte)
buf := *bufPtr
buf = buf[0:cap(buf)]
_, err := io.CopyBuffer(w, response.Body, buf)
bufferPool.Put(buf)
bufferPool.Put(bufPtr)
return err
}
@ -703,7 +714,8 @@ function FindProxyForURL(url, host) {
var bufferPool = sync.Pool{
New: func() interface{} {
return make([]byte, 0, 32*1024)
buffer := make([]byte, 0, 32*1024)
return &buffer
},
}
@ -725,7 +737,8 @@ type ProbeResistance struct {
}
func readLinesFromFile(filename string) ([]string, error) {
file, err := os.Open(filename)
cleanFilename := filepath.Clean(filename)
file, err := os.Open(cleanFilename)
if err != nil {
return nil, err
}

View file

@ -19,7 +19,6 @@ import (
"crypto/tls"
"fmt"
"io"
"io/ioutil"
"net"
"net/http"
"net/url"
@ -75,7 +74,7 @@ func connectAndGetViaProxy(targetHost, resource, proxyAddr, httpTargetVer, proxy
req.ProtoMajor = 2
req.ProtoMinor = 0
pr, pw := io.Pipe()
req.Body = ioutil.NopCloser(pr)
req.Body = io.NopCloser(pr)
t := http2.Transport{}
clientConn, err := t.NewClientConn(proxyConn)
if err != nil {

115
go.mod
View file

@ -1,9 +1,116 @@
module github.com/caddyserver/forwardproxy
go 1.14
go 1.20
require (
github.com/caddyserver/caddy/v2 v2.4.0-beta.1
go.uber.org/zap v1.16.0
golang.org/x/net v0.0.0-20210119194325-5f4716e94777
github.com/caddyserver/caddy/v2 v2.6.4
go.uber.org/zap v1.24.0
golang.org/x/net v0.11.0
)
require (
filippo.io/edwards25519 v1.0.0 // indirect
github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 // indirect
github.com/BurntSushi/toml v1.2.1 // indirect
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver/v3 v3.2.0 // indirect
github.com/Masterminds/sprig/v3 v3.2.3 // indirect
github.com/Microsoft/go-winio v0.6.0 // indirect
github.com/alecthomas/chroma/v2 v2.5.0 // indirect
github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 // indirect
github.com/aryann/difflib v0.0.0-20210328193216-ff5ff6dc229b // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/caddyserver/certmagic v0.17.2 // indirect
github.com/cespare/xxhash v1.1.0 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
github.com/dgraph-io/badger v1.6.2 // indirect
github.com/dgraph-io/badger/v2 v2.2007.4 // indirect
github.com/dgraph-io/ristretto v0.1.0 // indirect
github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect
github.com/dlclark/regexp2 v1.7.0 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/go-kit/kit v0.10.0 // indirect
github.com/go-logfmt/logfmt v0.5.1 // indirect
github.com/go-sql-driver/mysql v1.6.0 // indirect
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
github.com/golang/glog v1.0.0 // indirect
github.com/golang/mock v1.6.0 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/cel-go v0.13.0 // indirect
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/huandu/xstrings v1.3.3 // indirect
github.com/imdario/mergo v0.3.12 // indirect
github.com/inconshreveable/mousetrap v1.0.1 // indirect
github.com/jackc/chunkreader/v2 v2.0.1 // indirect
github.com/jackc/pgconn v1.13.0 // indirect
github.com/jackc/pgio v1.0.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgproto3/v2 v2.3.1 // indirect
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect
github.com/jackc/pgtype v1.12.0 // indirect
github.com/jackc/pgx/v4 v4.17.2 // indirect
github.com/klauspost/compress v1.15.15 // indirect
github.com/klauspost/cpuid/v2 v2.2.3 // indirect
github.com/libdns/libdns v0.2.1 // indirect
github.com/manifoldco/promptui v0.9.0 // indirect
github.com/mattn/go-colorable v0.1.8 // indirect
github.com/mattn/go-isatty v0.0.13 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
github.com/mholt/acmez v1.1.0 // indirect
github.com/micromdm/scep/v2 v2.1.0 // indirect
github.com/miekg/dns v1.1.50 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/go-ps v1.0.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/onsi/ginkgo/v2 v2.2.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/prometheus/client_golang v1.14.0 // indirect
github.com/prometheus/client_model v0.3.0 // indirect
github.com/prometheus/common v0.37.0 // indirect
github.com/prometheus/procfs v0.8.0 // indirect
github.com/quic-go/qpack v0.4.0 // indirect
github.com/quic-go/qtls-go1-18 v0.2.0 // indirect
github.com/quic-go/qtls-go1-19 v0.2.0 // indirect
github.com/quic-go/qtls-go1-20 v0.1.0 // indirect
github.com/quic-go/quic-go v0.32.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/shopspring/decimal v1.2.0 // indirect
github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
github.com/slackhq/nebula v1.6.1 // indirect
github.com/smallstep/certificates v0.23.2 // indirect
github.com/smallstep/nosql v0.5.0 // indirect
github.com/smallstep/truststore v0.12.1 // indirect
github.com/spf13/cast v1.4.1 // indirect
github.com/spf13/cobra v1.6.1 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/stoewer/go-strcase v1.2.0 // indirect
github.com/tailscale/tscert v0.0.0-20230124224810-c6dc1f4049b2 // indirect
github.com/urfave/cli v1.22.12 // indirect
github.com/yuin/goldmark v1.5.4 // indirect
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20220924101305-151362477c87 // indirect
go.etcd.io/bbolt v1.3.6 // indirect
go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352 // indirect
go.step.sm/cli-utils v0.7.5 // indirect
go.step.sm/crypto v0.23.2 // indirect
go.step.sm/linkedca v0.19.0 // indirect
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.6.0 // indirect
golang.org/x/crypto v0.10.0 // indirect
golang.org/x/exp v0.0.0-20221205204356-47842c84f3db // indirect
golang.org/x/mod v0.8.0 // indirect
golang.org/x/sys v0.9.0 // indirect
golang.org/x/term v0.9.0 // indirect
golang.org/x/text v0.10.0 // indirect
golang.org/x/tools v0.6.0 // indirect
google.golang.org/genproto v0.0.0-20230202175211-008b39050e57 // indirect
google.golang.org/grpc v1.52.3 // indirect
google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
howett.net/plist v1.0.0 // indirect
)

1075
go.sum

File diff suppressed because it is too large Load diff

View file

@ -132,12 +132,12 @@ func (c *HTTPConnectDialer) DialContext(ctx context.Context, network, address st
resp, err := h2clientConn.RoundTrip(req)
if err != nil {
rawConn.Close()
err = rawConn.Close()
return nil, err
}
if resp.StatusCode != http.StatusOK {
rawConn.Close()
_ = rawConn.Close()
return nil, errors.New("Proxy responded with non 200 code: " + resp.Status)
}
return NewHttp2Conn(rawConn, pw, resp.Body), nil
@ -150,18 +150,18 @@ func (c *HTTPConnectDialer) DialContext(ctx context.Context, network, address st
err := req.Write(rawConn)
if err != nil {
rawConn.Close()
err = rawConn.Close()
return nil, err
}
resp, err := http.ReadResponse(bufio.NewReader(rawConn), req)
if err != nil {
rawConn.Close()
err = rawConn.Close()
return nil, err
}
if resp.StatusCode != http.StatusOK {
rawConn.Close()
_ = rawConn.Close()
return nil, errors.New("Proxy responded with non 200 code: " + resp.Status)
}
return rawConn, nil
@ -207,6 +207,7 @@ func (c *HTTPConnectDialer) DialContext(ctx context.Context, network, address st
tlsConf := tls.Config{
NextProtos: []string{"h2", "http/1.1"},
ServerName: c.ProxyURL.Hostname(),
MinVersion: tls.VersionTLS12,
}
tlsConn, err := tls.Dial(network, c.ProxyURL.Host, &tlsConf)
if err != nil {
@ -232,13 +233,13 @@ func (c *HTTPConnectDialer) DialContext(ctx context.Context, network, address st
t := http2.Transport{}
h2clientConn, err := t.NewClientConn(rawConn)
if err != nil {
rawConn.Close()
err = rawConn.Close()
return nil, err
}
proxyConn, err := connectHttp2(rawConn, h2clientConn)
if err != nil {
rawConn.Close()
err = rawConn.Close()
return nil, err
}
if c.EnableH2ConnReuse {
@ -249,7 +250,7 @@ func (c *HTTPConnectDialer) DialContext(ctx context.Context, network, address st
}
return proxyConn, err
default:
rawConn.Close()
_ = rawConn.Close()
return nil, errors.New("negotiated unsupported application layer protocol: " +
negotiatedProtocol)
}
@ -274,8 +275,13 @@ func (h *http2Conn) Write(p []byte) (n int, err error) {
}
func (h *http2Conn) Close() error {
h.in.Close()
return h.out.Close()
inErr := h.in.Close()
outErr := h.out.Close()
if inErr != nil {
return inErr
}
return outErr
}
func (h *http2Conn) CloseConn() error {

View file

@ -4,7 +4,7 @@ import (
"bytes"
"errors"
"fmt"
"io/ioutil"
"io"
"net"
"net/http"
"strings"
@ -44,6 +44,7 @@ func TestGETAuthWrongProbeResist(t *testing.T) {
if err != nil {
t.Fatal(err)
}
if responseProbeResist.StatusCode != responseReference.StatusCode {
t.Fatalf("Expected response: %d, Got: %d\n",
responseReference.StatusCode, responseProbeResist.StatusCode)
@ -314,6 +315,7 @@ func responsesAreEqual(res1, res2 *http.Response) error {
if len(s1) != len(s2) {
return fmt.Sprintf("different length: %d vs %d", len(s1), len(s2))
}
for i := range s1 {
if s1[i] != s2[i] {
return fmt.Sprintf("different string at position %d: %s vs %s", i, s1[i], s2[i])
@ -330,6 +332,7 @@ func responsesAreEqual(res1, res2 *http.Response) error {
if len(res1.Header) != len(res2.Header) {
return errors.New("Headers have different length")
}
for k1, v1 := range res1.Header {
k1Lower := strings.ToLower(k1)
if k1Lower == "date" {
@ -339,21 +342,13 @@ func responsesAreEqual(res1, res2 *http.Response) error {
if !ok {
return fmt.Errorf("header \"%s: %s\" is absent in res2", k1, v1)
}
// if k1Lower == "location" {
// for i, h := range v2 {
// v2[i] = removeAddressesStr(h)
// }
// for i, h := range v1 {
// v1[i] = removeAddressesStr(h)
// }
// }
if errStr = stringSlicesAreEqual(v1, v2); errStr != "" {
return fmt.Errorf("header \"%s\" is different: %s", k1, errStr)
}
}
// Compare bodies
buf1, err1 := ioutil.ReadAll(res1.Body)
buf2, err2 := ioutil.ReadAll(res2.Body)
buf1, err1 := io.ReadAll(res1.Body)
buf2, err2 := io.ReadAll(res2.Body)
n1 := len(buf1)
n2 := len(buf2)
makeBodyError := func(s string) error {
@ -379,17 +374,13 @@ func responsesAreEqual(res1, res2 *http.Response) error {
// Responses from forwardproxy + proberesist and generic caddy can have different addresses present in headers.
// To avoid false positives - remove addresses before comparing.
func removeAddressesByte(b []byte) []byte {
b = bytes.Replace(b, []byte(caddyForwardProxyProbeResist.addr),
bytes.Repeat([]byte{'#'}, len(caddyForwardProxyProbeResist.addr)), -1)
b = bytes.Replace(b, []byte(caddyDummyProbeResist.addr),
bytes.Repeat([]byte{'#'}, len(caddyDummyProbeResist.addr)), -1)
b = bytes.ReplaceAll(b, []byte(caddyForwardProxyProbeResist.addr),
bytes.Repeat([]byte{'#'}, len(caddyForwardProxyProbeResist.addr)))
b = bytes.ReplaceAll(b, []byte(caddyDummyProbeResist.addr),
bytes.Repeat([]byte{'#'}, len(caddyDummyProbeResist.addr)))
return b
}
func removeAddressesStr(s string) string {
return string(removeAddressesByte([]byte(s)))
}
func changePort(inputAddr, toPort string) string {
host, _, err := net.SplitHostPort(inputAddr)
if err != nil {