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 ¶
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 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