proxy

package
v0.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 12, 2021 License: MIT Imports: 17 Imported by: 0

Documentation

Overview

Package proxy provides a simple proxy. The proxy can be protected with basic auth. It can also forward connections to a parent proxy, and authorize connections against that. Both local, and parent credentials can be set via environment variables. For local proxy credential, set `PROXY_CREDENTIAL`. For remote proxy credential, set `PROXY_PARENT_CREDENTIAL`.

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	ErrFailedToStartProxy      = customerror.NewFailedToError("start proxy", "", nil)
	ErrInvalidLocalProxyURI    = customerror.NewInvalidError("local proxy URI", "", nil)
	ErrInvalidOrParentOrPac    = customerror.NewInvalidError("params. Can't set upstream proxy, and PAC at the same time", "", nil)
	ErrInvalidPACProxyURI      = customerror.NewInvalidError("PAC proxy URI", "", nil)
	ErrInvalidPACURI           = customerror.NewInvalidError("PAC URI", "", nil)
	ErrInvalidProxyParams      = customerror.NewInvalidError("params", "", nil)
	ErrInvalidUpstreamProxyURI = customerror.NewInvalidError("upstream proxy URI", "", nil)
)

Functions

This section is empty.

Types

type LoggingOptions

type LoggingOptions = logger.Options

Type aliasing.

type Proxy

type Proxy struct {
	// URI:
	// - Known schemes: http, https, socks, socks5, or quic
	// - Some hostname (x.io - min 4 chars) or IP
	// - Port in a valid range: 80 - 65535.
	LocalProxyURI string `json:"uri" validate:"required,proxyURI"`

	// UpstreamProxyURI:
	// - Known schemes: http, https, socks, socks5, or quic
	// - Some hostname (x.io - min 4 chars) or IP
	// - Port in a valid range: 80 - 65535.
	UpstreamProxyURI string `json:"upstream_proxy_uri" validate:"omitempty,proxyURI"`

	// PACURI:
	// - Known schemes: http, https, socks, socks5, or quic
	// - Some hostname (x.io - min 4 chars) or IP
	// - Port in a valid range: 80 - 65535.
	PACURI string `json:"pac_uri" validate:"omitempty,gte=6"`
	// contains filtered or unexported fields
}

Proxy connections. Proxy can be protected with basic auth. It can also forward connections to a parent proxy, and authorize connections against that.

TODO: Add name to `Proxy`.

func New

func New(
	localProxyURI string,
	upstreamProxyURI string,
	pacURI string, pacProxiesCredentials []string,
	loggingOptions *LoggingOptions,
) (*Proxy, error)

New is the Proxy factory. Errors can be introspected, and provide contextual information.

Example

Complete, and complex demo.

client -> protected local proxy -> protected pac server - connection setup -> protected upstream proxy -> protected target.

//////
// Setup demo logger.
//////

// Only `stdout`, and `stderr`
loggingOptions := &LoggingOptions{
	FileLevel: level.None.String(),
	FilePath:  "-",

	// Change to `Trace` for debugging, and demonstration purposes.
	Level: level.None.String(),
}

l := logger.Setup(loggingOptions)

//////
// Randomness automates port allocation, ensuring no collision happens
// between tests, and examples.
//////

r, err := randomness.New(49000, 50000, 100, true)
if err != nil {
	log.Fatalln("Failed to create randomness.", err)
}

//////
// Target/end server.
//////

targetServer := createMockedHTTPServer(http.StatusOK, "body", "dXNlcjE6cGFzczE=")

defer func() { targetServer.Close() }()

targetServerURI, err := url.ParseRequestURI(targetServer.URL)
if err != nil {
	//nolint:gocritic
	log.Fatalln("Failed to parse target server URL.", err)
}

targetServerURI.User = url.UserPassword("user1", "pass1")

l.Debuglnf("Target/end server started @ %s", targetServerURI.Redacted())

//////
// PAC content.
//////

// Use `int(r.MustGenerate())` for testing purposes. Specify a port if using
// a manual - external proxy (e.g.: NGINX). Good for debugging, and demo
// purposes.
upstreamProxyPort := int(r.MustGenerate())

templateMap := map[string]int{
	"port": upstreamProxyPort,
}

var pacText strings.Builder
_ = template.Must(template.New("pacTemplate").Parse(pacTemplate)).Execute(&pacText, templateMap)

l.Debuglnf("PAC template parsed: \n%s", pacText.String())

//////
// PAC server.
//////

pacServer := createMockedHTTPServer(http.StatusOK, pacText.String(), "dXNlcjpwYXNz")

defer func() { pacServer.Close() }()

pacServerURI, err := url.ParseRequestURI(pacServer.URL)
if err != nil {
	log.Fatalln("Failed to parse PAC server URL.", err)
}

pacServerURI.User = url.UserPassword("user", "pass")

l.Debuglnf("PAC server started @ %s", pacServerURI.Redacted())

//////
// URL for both proxies, local, and upstream.
//////

// Local proxy.
localProxyURI := URIBuilder(defaultProxyHostname, r.MustGenerate(), localProxyCredentialUsername, localProxyCredentialPassword)

// Upstream proxy.
upstreamProxyURI := URIBuilder(defaultProxyHostname, int64(upstreamProxyPort), upstreamProxyCredentialUsername, upstreamProxyCredentialPassword)

//////
// Local proxy.
//
// It's protected with Basic Auth. Upstream proxy will be automatically, and
// dynamically setup via PAC, including credentials for proxies specified
// in the PAC content.
//////

localProxy, err := New(
	// Local proxy URI.
	localProxyURI.String(),

	// Upstream proxy URI.
	"",

	// PAC URI.
	pacServerURI.String(),

	// PAC proxies credentials in standard URI format.
	[]string{upstreamProxyURI.String()},

	// Logging settings.
	loggingOptions,
)
if err != nil {
	log.Fatalln("Failed to create proxy.", err)
}

go localProxy.Run()

// Give enough time to start, and be ready.
time.Sleep(1 * time.Second)

//////
// Upstream Proxy.
//////

upstreamProxy, err := New(
	// Local proxy URI.
	upstreamProxyURI.String(),

	// Upstream proxy URI.
	"",

	// PAC URI.
	"",

	// PAC proxies credentials in standard URI format.
	nil,

	// Logging settings.
	loggingOptions,
)
if err != nil {
	log.Fatalln("Failed to create upstream proxy.", err)
}

go upstreamProxy.Run()

// Give enough time to start, and be ready.
time.Sleep(1 * time.Second)

//////
// Client.
//////

l.Debuglnf("Client is using %s as proxy", localProxyURI.Redacted())

// Client's proxy settings.
tr := &http.Transport{
	Proxy: http.ProxyURL(localProxyURI),
}

client := &http.Client{
	Transport: tr,
}

statusCode, body, err := executeRequest(client, targetServerURI.String())
if err != nil {
	log.Fatalf("Failed to execute request: %v", err)
}

fmt.Println(statusCode)
fmt.Println(body)
Output:
200
body

func (*Proxy) Run

func (p *Proxy) Run()

Run starts the proxy. If it fails to start, it will exit with fatal.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL