mirror of https://github.com/docker/cli.git
Merge pull request #4651 from thaJeztah/bump_go_connections
vendor: update go-connections for TLS 1.3 support
This commit is contained in:
commit
a9ae9b3cc6
|
@ -14,7 +14,7 @@ require (
|
||||||
github.com/docker/distribution v2.8.3+incompatible
|
github.com/docker/distribution v2.8.3+incompatible
|
||||||
github.com/docker/docker v24.0.0-rc.2.0.20231107154431-c14694a424ab+incompatible // master (v25.0.0-dev)
|
github.com/docker/docker v24.0.0-rc.2.0.20231107154431-c14694a424ab+incompatible // master (v25.0.0-dev)
|
||||||
github.com/docker/docker-credential-helpers v0.8.0
|
github.com/docker/docker-credential-helpers v0.8.0
|
||||||
github.com/docker/go-connections v0.4.0
|
github.com/docker/go-connections v0.4.1-0.20231031175723-0b8c1f4e07a0
|
||||||
github.com/docker/go-units v0.5.0
|
github.com/docker/go-units v0.5.0
|
||||||
github.com/fvbommel/sortorder v1.0.2
|
github.com/fvbommel/sortorder v1.0.2
|
||||||
github.com/gogo/protobuf v1.3.2
|
github.com/gogo/protobuf v1.3.2
|
||||||
|
|
|
@ -5,6 +5,7 @@ github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOEl
|
||||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
||||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
|
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
|
||||||
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
|
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
|
||||||
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
|
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
|
||||||
github.com/Microsoft/hcsshim v0.11.1 h1:hJ3s7GbWlGK4YVV92sO88BQSyF4ZLVy7/awqOlPxFbA=
|
github.com/Microsoft/hcsshim v0.11.1 h1:hJ3s7GbWlGK4YVV92sO88BQSyF4ZLVy7/awqOlPxFbA=
|
||||||
|
@ -60,8 +61,9 @@ github.com/docker/docker-credential-helpers v0.8.0 h1:YQFtbBQb4VrpoPxhFuzEBPQ9E1
|
||||||
github.com/docker/docker-credential-helpers v0.8.0/go.mod h1:UGFXcuoQ5TxPiB54nHOZ32AWRqQdECoh/Mg0AlEYb40=
|
github.com/docker/docker-credential-helpers v0.8.0/go.mod h1:UGFXcuoQ5TxPiB54nHOZ32AWRqQdECoh/Mg0AlEYb40=
|
||||||
github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c h1:lzqkGL9b3znc+ZUgi7FlLnqjQhcXxkNM/quxIjBVMD0=
|
github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c h1:lzqkGL9b3znc+ZUgi7FlLnqjQhcXxkNM/quxIjBVMD0=
|
||||||
github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c/go.mod h1:CADgU4DSXK5QUlFslkQu2yW2TKzFZcXq/leZfM0UH5Q=
|
github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c/go.mod h1:CADgU4DSXK5QUlFslkQu2yW2TKzFZcXq/leZfM0UH5Q=
|
||||||
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
|
|
||||||
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
||||||
|
github.com/docker/go-connections v0.4.1-0.20231031175723-0b8c1f4e07a0 h1:dPD5pdqsujF9jz2NQMQCDzrBSAF3M6kIxmfU98IOp9c=
|
||||||
|
github.com/docker/go-connections v0.4.1-0.20231031175723-0b8c1f4e07a0/go.mod h1:a6bNUGTbQBsY6VRHTr4h/rkOXjl244DyRD0tx3fgq4Q=
|
||||||
github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c h1:+pKlWGMw7gf6bQ+oDZB4KHQFypsfjYlq/C4rfL7D3g8=
|
github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c h1:+pKlWGMw7gf6bQ+oDZB4KHQFypsfjYlq/C4rfL7D3g8=
|
||||||
github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA=
|
github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA=
|
||||||
github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI=
|
github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI=
|
||||||
|
@ -229,6 +231,7 @@ github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJ
|
||||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
|
github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
|
||||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||||
|
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
||||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||||
|
@ -323,6 +326,7 @@ golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5h
|
||||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
|
|
@ -8,11 +8,6 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
// portSpecTemplate is the expected format for port specifications
|
|
||||||
portSpecTemplate = "ip:hostPort:containerPort"
|
|
||||||
)
|
|
||||||
|
|
||||||
// PortBinding represents a binding between a Host IP address and a Host Port
|
// PortBinding represents a binding between a Host IP address and a Host Port
|
||||||
type PortBinding struct {
|
type PortBinding struct {
|
||||||
// HostIP is the host IP Address
|
// HostIP is the host IP Address
|
||||||
|
@ -158,30 +153,33 @@ type PortMapping struct {
|
||||||
func splitParts(rawport string) (string, string, string) {
|
func splitParts(rawport string) (string, string, string) {
|
||||||
parts := strings.Split(rawport, ":")
|
parts := strings.Split(rawport, ":")
|
||||||
n := len(parts)
|
n := len(parts)
|
||||||
containerport := parts[n-1]
|
containerPort := parts[n-1]
|
||||||
|
|
||||||
switch n {
|
switch n {
|
||||||
case 1:
|
case 1:
|
||||||
return "", "", containerport
|
return "", "", containerPort
|
||||||
case 2:
|
case 2:
|
||||||
return "", parts[0], containerport
|
return "", parts[0], containerPort
|
||||||
case 3:
|
case 3:
|
||||||
return parts[0], parts[1], containerport
|
return parts[0], parts[1], containerPort
|
||||||
default:
|
default:
|
||||||
return strings.Join(parts[:n-2], ":"), parts[n-2], containerport
|
return strings.Join(parts[:n-2], ":"), parts[n-2], containerPort
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParsePortSpec parses a port specification string into a slice of PortMappings
|
// ParsePortSpec parses a port specification string into a slice of PortMappings
|
||||||
func ParsePortSpec(rawPort string) ([]PortMapping, error) {
|
func ParsePortSpec(rawPort string) ([]PortMapping, error) {
|
||||||
var proto string
|
var proto string
|
||||||
rawIP, hostPort, containerPort := splitParts(rawPort)
|
ip, hostPort, containerPort := splitParts(rawPort)
|
||||||
proto, containerPort = SplitProtoPort(containerPort)
|
proto, containerPort = SplitProtoPort(containerPort)
|
||||||
|
|
||||||
// Strip [] from IPV6 addresses
|
if ip != "" && ip[0] == '[' {
|
||||||
ip, _, err := net.SplitHostPort(rawIP + ":")
|
// Strip [] from IPV6 addresses
|
||||||
if err != nil {
|
rawIP, _, err := net.SplitHostPort(ip + ":")
|
||||||
return nil, fmt.Errorf("Invalid ip address %v: %s", rawIP, err)
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Invalid ip address %v: %s", ip, err)
|
||||||
|
}
|
||||||
|
ip = rawIP
|
||||||
}
|
}
|
||||||
if ip != "" && net.ParseIP(ip) == nil {
|
if ip != "" && net.ParseIP(ip) == nil {
|
||||||
return nil, fmt.Errorf("Invalid ip address: %s", ip)
|
return nil, fmt.Errorf("Invalid ip address: %s", ip)
|
||||||
|
|
|
@ -43,7 +43,7 @@ type portMapSorter []portMapEntry
|
||||||
func (s portMapSorter) Len() int { return len(s) }
|
func (s portMapSorter) Len() int { return len(s) }
|
||||||
func (s portMapSorter) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
func (s portMapSorter) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||||
|
|
||||||
// sort the port so that the order is:
|
// Less sorts the port so that the order is:
|
||||||
// 1. port with larger specified bindings
|
// 1. port with larger specified bindings
|
||||||
// 2. larger port
|
// 2. larger port
|
||||||
// 3. port with tcp protocol
|
// 3. port with tcp protocol
|
||||||
|
@ -58,7 +58,7 @@ func (s portMapSorter) Less(i, j int) bool {
|
||||||
func SortPortMap(ports []Port, bindings PortMap) {
|
func SortPortMap(ports []Port, bindings PortMap) {
|
||||||
s := portMapSorter{}
|
s := portMapSorter{}
|
||||||
for _, p := range ports {
|
for _, p := range ports {
|
||||||
if binding, ok := bindings[p]; ok {
|
if binding, ok := bindings[p]; ok && len(binding) > 0 {
|
||||||
for _, b := range binding {
|
for _, b := range binding {
|
||||||
s = append(s, portMapEntry{port: p, binding: b})
|
s = append(s, portMapEntry{port: p, binding: b})
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,11 +2,8 @@ package sockets
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
||||||
"net/url"
|
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"golang.org/x/net/proxy"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetProxyEnv allows access to the uppercase and the lowercase forms of
|
// GetProxyEnv allows access to the uppercase and the lowercase forms of
|
||||||
|
@ -20,32 +17,12 @@ func GetProxyEnv(key string) string {
|
||||||
return proxyValue
|
return proxyValue
|
||||||
}
|
}
|
||||||
|
|
||||||
// DialerFromEnvironment takes in a "direct" *net.Dialer and returns a
|
// DialerFromEnvironment was previously used to configure a net.Dialer to route
|
||||||
// proxy.Dialer which will route the connections through the proxy using the
|
// connections through a SOCKS proxy.
|
||||||
// given dialer.
|
// DEPRECATED: SOCKS proxies are now supported by configuring only
|
||||||
func DialerFromEnvironment(direct *net.Dialer) (proxy.Dialer, error) {
|
// http.Transport.Proxy, and no longer require changing http.Transport.Dial.
|
||||||
allProxy := GetProxyEnv("all_proxy")
|
// Therefore, only sockets.ConfigureTransport() needs to be called, and any
|
||||||
if len(allProxy) == 0 {
|
// sockets.DialerFromEnvironment() calls can be dropped.
|
||||||
return direct, nil
|
func DialerFromEnvironment(direct *net.Dialer) (*net.Dialer, error) {
|
||||||
}
|
return direct, nil
|
||||||
|
|
||||||
proxyURL, err := url.Parse(allProxy)
|
|
||||||
if err != nil {
|
|
||||||
return direct, err
|
|
||||||
}
|
|
||||||
|
|
||||||
proxyFromURL, err := proxy.FromURL(proxyURL, direct)
|
|
||||||
if err != nil {
|
|
||||||
return direct, err
|
|
||||||
}
|
|
||||||
|
|
||||||
noProxy := GetProxyEnv("no_proxy")
|
|
||||||
if len(noProxy) == 0 {
|
|
||||||
return proxyFromURL, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
perHost := proxy.NewPerHost(proxyFromURL, direct)
|
|
||||||
perHost.AddFromString(noProxy)
|
|
||||||
|
|
||||||
return perHost, nil
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,16 +8,18 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Why 32? See https://github.com/docker/docker/pull/8035.
|
const defaultTimeout = 10 * time.Second
|
||||||
const defaultTimeout = 32 * time.Second
|
|
||||||
|
|
||||||
// ErrProtocolNotAvailable is returned when a given transport protocol is not provided by the operating system.
|
// ErrProtocolNotAvailable is returned when a given transport protocol is not provided by the operating system.
|
||||||
var ErrProtocolNotAvailable = errors.New("protocol not available")
|
var ErrProtocolNotAvailable = errors.New("protocol not available")
|
||||||
|
|
||||||
// ConfigureTransport configures the specified Transport according to the
|
// ConfigureTransport configures the specified [http.Transport] according to the specified proto
|
||||||
// specified proto and addr.
|
// and addr.
|
||||||
// If the proto is unix (using a unix socket to communicate) or npipe the
|
//
|
||||||
// compression is disabled.
|
// If the proto is unix (using a unix socket to communicate) or npipe the compression is disabled.
|
||||||
|
// For other protos, compression is enabled. If you want to manually enable/disable compression,
|
||||||
|
// make sure you do it _after_ any subsequent calls to ConfigureTransport is made against the same
|
||||||
|
// [http.Transport].
|
||||||
func ConfigureTransport(tr *http.Transport, proto, addr string) error {
|
func ConfigureTransport(tr *http.Transport, proto, addr string) error {
|
||||||
switch proto {
|
switch proto {
|
||||||
case "unix":
|
case "unix":
|
||||||
|
@ -26,13 +28,10 @@ func ConfigureTransport(tr *http.Transport, proto, addr string) error {
|
||||||
return configureNpipeTransport(tr, proto, addr)
|
return configureNpipeTransport(tr, proto, addr)
|
||||||
default:
|
default:
|
||||||
tr.Proxy = http.ProxyFromEnvironment
|
tr.Proxy = http.ProxyFromEnvironment
|
||||||
dialer, err := DialerFromEnvironment(&net.Dialer{
|
tr.DisableCompression = false
|
||||||
|
tr.DialContext = (&net.Dialer{
|
||||||
Timeout: defaultTimeout,
|
Timeout: defaultTimeout,
|
||||||
})
|
}).DialContext
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
tr.Dial = dialer.Dial
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
package sockets
|
package sockets
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -18,8 +19,11 @@ func configureUnixTransport(tr *http.Transport, proto, addr string) error {
|
||||||
}
|
}
|
||||||
// No need for compression in local communications.
|
// No need for compression in local communications.
|
||||||
tr.DisableCompression = true
|
tr.DisableCompression = true
|
||||||
tr.Dial = func(_, _ string) (net.Conn, error) {
|
dialer := &net.Dialer{
|
||||||
return net.DialTimeout(proto, addr, defaultTimeout)
|
Timeout: defaultTimeout,
|
||||||
|
}
|
||||||
|
tr.DialContext = func(ctx context.Context, _, _ string) (net.Conn, error) {
|
||||||
|
return dialer.DialContext(ctx, proto, addr)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package sockets
|
package sockets
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
@ -15,8 +16,8 @@ func configureUnixTransport(tr *http.Transport, proto, addr string) error {
|
||||||
func configureNpipeTransport(tr *http.Transport, proto, addr string) error {
|
func configureNpipeTransport(tr *http.Transport, proto, addr string) error {
|
||||||
// No need for compression in local communications.
|
// No need for compression in local communications.
|
||||||
tr.DisableCompression = true
|
tr.DisableCompression = true
|
||||||
tr.Dial = func(_, _ string) (net.Conn, error) {
|
tr.DialContext = func(ctx context.Context, _, _ string) (net.Conn, error) {
|
||||||
return DialPipe(addr, defaultTimeout)
|
return winio.DialPipeContext(ctx, addr)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,51 @@
|
||||||
// +build !windows
|
// +build !windows
|
||||||
|
|
||||||
|
/*
|
||||||
|
Package sockets is a simple unix domain socket wrapper.
|
||||||
|
|
||||||
|
Usage
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
import(
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"github.com/docker/go-connections/sockets"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
l, err := sockets.NewUnixSocketWithOpts("/path/to/sockets",
|
||||||
|
sockets.WithChown(0,0),sockets.WithChmod(0660))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
echoStr := "hello"
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
conn, err := l.Accept()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
conn.Write([]byte(echoStr))
|
||||||
|
conn.Close()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
conn, err := net.Dial("unix", path)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := make([]byte, 5)
|
||||||
|
if _, err := conn.Read(buf); err != nil {
|
||||||
|
panic(err)
|
||||||
|
} else if string(buf) != echoStr {
|
||||||
|
panic(fmt.Errorf("Msg may lost"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
package sockets
|
package sockets
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -8,25 +54,73 @@ import (
|
||||||
"syscall"
|
"syscall"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewUnixSocket creates a unix socket with the specified path and group.
|
// SockOption sets up socket file's creating option
|
||||||
func NewUnixSocket(path string, gid int) (net.Listener, error) {
|
type SockOption func(string) error
|
||||||
|
|
||||||
|
// WithChown modifies the socket file's uid and gid
|
||||||
|
func WithChown(uid, gid int) SockOption {
|
||||||
|
return func(path string) error {
|
||||||
|
if err := os.Chown(path, uid, gid); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithChmod modifies socket file's access mode.
|
||||||
|
func WithChmod(mask os.FileMode) SockOption {
|
||||||
|
return func(path string) error {
|
||||||
|
if err := os.Chmod(path, mask); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewUnixSocketWithOpts creates a unix socket with the specified options.
|
||||||
|
// By default, socket permissions are 0000 (i.e.: no access for anyone); pass
|
||||||
|
// WithChmod() and WithChown() to set the desired ownership and permissions.
|
||||||
|
//
|
||||||
|
// This function temporarily changes the system's "umask" to 0777 to work around
|
||||||
|
// a race condition between creating the socket and setting its permissions. While
|
||||||
|
// this should only be for a short duration, it may affect other processes that
|
||||||
|
// create files/directories during that period.
|
||||||
|
func NewUnixSocketWithOpts(path string, opts ...SockOption) (net.Listener, error) {
|
||||||
if err := syscall.Unlink(path); err != nil && !os.IsNotExist(err) {
|
if err := syscall.Unlink(path); err != nil && !os.IsNotExist(err) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
mask := syscall.Umask(0777)
|
|
||||||
defer syscall.Umask(mask)
|
|
||||||
|
|
||||||
|
// net.Listen does not allow for permissions to be set. As a result, when
|
||||||
|
// specifying custom permissions ("WithChmod()"), there is a short time
|
||||||
|
// between creating the socket and applying the permissions, during which
|
||||||
|
// the socket permissions are Less restrictive than desired.
|
||||||
|
//
|
||||||
|
// To work around this limitation of net.Listen(), we temporarily set the
|
||||||
|
// umask to 0777, which forces the socket to be created with 000 permissions
|
||||||
|
// (i.e.: no access for anyone). After that, WithChmod() must be used to set
|
||||||
|
// the desired permissions.
|
||||||
|
//
|
||||||
|
// We don't use "defer" here, to reset the umask to its original value as soon
|
||||||
|
// as possible. Ideally we'd be able to detect if WithChmod() was passed as
|
||||||
|
// an option, and skip changing umask if default permissions are used.
|
||||||
|
origUmask := syscall.Umask(0777)
|
||||||
l, err := net.Listen("unix", path)
|
l, err := net.Listen("unix", path)
|
||||||
|
syscall.Umask(origUmask)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if err := os.Chown(path, 0, gid); err != nil {
|
|
||||||
l.Close()
|
for _, op := range opts {
|
||||||
return nil, err
|
if err := op(path); err != nil {
|
||||||
}
|
_ = l.Close()
|
||||||
if err := os.Chmod(path, 0660); err != nil {
|
return nil, err
|
||||||
l.Close()
|
}
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return l, nil
|
return l, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewUnixSocket creates a unix socket with the specified path and group.
|
||||||
|
func NewUnixSocket(path string, gid int) (net.Listener, error) {
|
||||||
|
return NewUnixSocketWithOpts(path, WithChown(0, gid), WithChmod(0660))
|
||||||
|
}
|
||||||
|
|
|
@ -53,18 +53,9 @@ var acceptedCBCCiphers = []uint16{
|
||||||
// known weak algorithms removed.
|
// known weak algorithms removed.
|
||||||
var DefaultServerAcceptedCiphers = append(clientCipherSuites, acceptedCBCCiphers...)
|
var DefaultServerAcceptedCiphers = append(clientCipherSuites, acceptedCBCCiphers...)
|
||||||
|
|
||||||
// allTLSVersions lists all the TLS versions and is used by the code that validates
|
|
||||||
// a uint16 value as a TLS version.
|
|
||||||
var allTLSVersions = map[uint16]struct{}{
|
|
||||||
tls.VersionSSL30: {},
|
|
||||||
tls.VersionTLS10: {},
|
|
||||||
tls.VersionTLS11: {},
|
|
||||||
tls.VersionTLS12: {},
|
|
||||||
}
|
|
||||||
|
|
||||||
// ServerDefault returns a secure-enough TLS configuration for the server TLS configuration.
|
// ServerDefault returns a secure-enough TLS configuration for the server TLS configuration.
|
||||||
func ServerDefault(ops ...func(*tls.Config)) *tls.Config {
|
func ServerDefault(ops ...func(*tls.Config)) *tls.Config {
|
||||||
tlsconfig := &tls.Config{
|
tlsConfig := &tls.Config{
|
||||||
// Avoid fallback by default to SSL protocols < TLS1.2
|
// Avoid fallback by default to SSL protocols < TLS1.2
|
||||||
MinVersion: tls.VersionTLS12,
|
MinVersion: tls.VersionTLS12,
|
||||||
PreferServerCipherSuites: true,
|
PreferServerCipherSuites: true,
|
||||||
|
@ -72,25 +63,25 @@ func ServerDefault(ops ...func(*tls.Config)) *tls.Config {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, op := range ops {
|
for _, op := range ops {
|
||||||
op(tlsconfig)
|
op(tlsConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
return tlsconfig
|
return tlsConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClientDefault returns a secure-enough TLS configuration for the client TLS configuration.
|
// ClientDefault returns a secure-enough TLS configuration for the client TLS configuration.
|
||||||
func ClientDefault(ops ...func(*tls.Config)) *tls.Config {
|
func ClientDefault(ops ...func(*tls.Config)) *tls.Config {
|
||||||
tlsconfig := &tls.Config{
|
tlsConfig := &tls.Config{
|
||||||
// Prefer TLS1.2 as the client minimum
|
// Prefer TLS1.2 as the client minimum
|
||||||
MinVersion: tls.VersionTLS12,
|
MinVersion: tls.VersionTLS12,
|
||||||
CipherSuites: clientCipherSuites,
|
CipherSuites: clientCipherSuites,
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, op := range ops {
|
for _, op := range ops {
|
||||||
op(tlsconfig)
|
op(tlsConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
return tlsconfig
|
return tlsConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
// certPool returns an X.509 certificate pool from `caFile`, the certificate file.
|
// certPool returns an X.509 certificate pool from `caFile`, the certificate file.
|
||||||
|
@ -108,11 +99,11 @@ func certPool(caFile string, exclusivePool bool) (*x509.CertPool, error) {
|
||||||
return nil, fmt.Errorf("failed to read system certificates: %v", err)
|
return nil, fmt.Errorf("failed to read system certificates: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pem, err := ioutil.ReadFile(caFile)
|
pemData, err := ioutil.ReadFile(caFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not read CA certificate %q: %v", caFile, err)
|
return nil, fmt.Errorf("could not read CA certificate %q: %v", caFile, err)
|
||||||
}
|
}
|
||||||
if !certPool.AppendCertsFromPEM(pem) {
|
if !certPool.AppendCertsFromPEM(pemData) {
|
||||||
return nil, fmt.Errorf("failed to append certificates from PEM file: %q", caFile)
|
return nil, fmt.Errorf("failed to append certificates from PEM file: %q", caFile)
|
||||||
}
|
}
|
||||||
return certPool, nil
|
return certPool, nil
|
||||||
|
@ -141,7 +132,7 @@ func adjustMinVersion(options Options, config *tls.Config) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsErrEncryptedKey returns true if the 'err' is an error of incorrect
|
// IsErrEncryptedKey returns true if the 'err' is an error of incorrect
|
||||||
// password when tryin to decrypt a TLS private key
|
// password when trying to decrypt a TLS private key
|
||||||
func IsErrEncryptedKey(err error) bool {
|
func IsErrEncryptedKey(err error) bool {
|
||||||
return errors.Cause(err) == x509.IncorrectPasswordError
|
return errors.Cause(err) == x509.IncorrectPasswordError
|
||||||
}
|
}
|
||||||
|
@ -157,8 +148,8 @@ func getPrivateKey(keyBytes []byte, passphrase string) ([]byte, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
if x509.IsEncryptedPEMBlock(pemBlock) {
|
if x509.IsEncryptedPEMBlock(pemBlock) { //nolint:staticcheck // Ignore SA1019 (IsEncryptedPEMBlock is deprecated)
|
||||||
keyBytes, err = x509.DecryptPEMBlock(pemBlock, []byte(passphrase))
|
keyBytes, err = x509.DecryptPEMBlock(pemBlock, []byte(passphrase)) //nolint:staticcheck // Ignore SA1019 (DecryptPEMBlock is deprecated)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "private key is encrypted, but could not decrypt it")
|
return nil, errors.Wrap(err, "private key is encrypted, but could not decrypt it")
|
||||||
}
|
}
|
||||||
|
|
16
vendor/github.com/docker/go-connections/tlsconfig/versions_go113.go
generated
vendored
Normal file
16
vendor/github.com/docker/go-connections/tlsconfig/versions_go113.go
generated
vendored
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
// +build go1.13
|
||||||
|
|
||||||
|
package tlsconfig
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
)
|
||||||
|
|
||||||
|
// allTLSVersions lists all the TLS versions and is used by the code that validates
|
||||||
|
// a uint16 value as a TLS version.
|
||||||
|
var allTLSVersions = map[uint16]struct{}{
|
||||||
|
tls.VersionTLS10: {},
|
||||||
|
tls.VersionTLS11: {},
|
||||||
|
tls.VersionTLS12: {},
|
||||||
|
tls.VersionTLS13: {},
|
||||||
|
}
|
15
vendor/github.com/docker/go-connections/tlsconfig/versions_other.go
generated
vendored
Normal file
15
vendor/github.com/docker/go-connections/tlsconfig/versions_other.go
generated
vendored
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
// +build !go1.13
|
||||||
|
|
||||||
|
package tlsconfig
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
)
|
||||||
|
|
||||||
|
// allTLSVersions lists all the TLS versions and is used by the code that validates
|
||||||
|
// a uint16 value as a TLS version.
|
||||||
|
var allTLSVersions = map[uint16]struct{}{
|
||||||
|
tls.VersionTLS10: {},
|
||||||
|
tls.VersionTLS11: {},
|
||||||
|
tls.VersionTLS12: {},
|
||||||
|
}
|
|
@ -1,168 +0,0 @@
|
||||||
// Copyright 2018 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package socks
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"io"
|
|
||||||
"net"
|
|
||||||
"strconv"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
noDeadline = time.Time{}
|
|
||||||
aLongTimeAgo = time.Unix(1, 0)
|
|
||||||
)
|
|
||||||
|
|
||||||
func (d *Dialer) connect(ctx context.Context, c net.Conn, address string) (_ net.Addr, ctxErr error) {
|
|
||||||
host, port, err := splitHostPort(address)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if deadline, ok := ctx.Deadline(); ok && !deadline.IsZero() {
|
|
||||||
c.SetDeadline(deadline)
|
|
||||||
defer c.SetDeadline(noDeadline)
|
|
||||||
}
|
|
||||||
if ctx != context.Background() {
|
|
||||||
errCh := make(chan error, 1)
|
|
||||||
done := make(chan struct{})
|
|
||||||
defer func() {
|
|
||||||
close(done)
|
|
||||||
if ctxErr == nil {
|
|
||||||
ctxErr = <-errCh
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
go func() {
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
c.SetDeadline(aLongTimeAgo)
|
|
||||||
errCh <- ctx.Err()
|
|
||||||
case <-done:
|
|
||||||
errCh <- nil
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
b := make([]byte, 0, 6+len(host)) // the size here is just an estimate
|
|
||||||
b = append(b, Version5)
|
|
||||||
if len(d.AuthMethods) == 0 || d.Authenticate == nil {
|
|
||||||
b = append(b, 1, byte(AuthMethodNotRequired))
|
|
||||||
} else {
|
|
||||||
ams := d.AuthMethods
|
|
||||||
if len(ams) > 255 {
|
|
||||||
return nil, errors.New("too many authentication methods")
|
|
||||||
}
|
|
||||||
b = append(b, byte(len(ams)))
|
|
||||||
for _, am := range ams {
|
|
||||||
b = append(b, byte(am))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if _, ctxErr = c.Write(b); ctxErr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, ctxErr = io.ReadFull(c, b[:2]); ctxErr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if b[0] != Version5 {
|
|
||||||
return nil, errors.New("unexpected protocol version " + strconv.Itoa(int(b[0])))
|
|
||||||
}
|
|
||||||
am := AuthMethod(b[1])
|
|
||||||
if am == AuthMethodNoAcceptableMethods {
|
|
||||||
return nil, errors.New("no acceptable authentication methods")
|
|
||||||
}
|
|
||||||
if d.Authenticate != nil {
|
|
||||||
if ctxErr = d.Authenticate(ctx, c, am); ctxErr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
b = b[:0]
|
|
||||||
b = append(b, Version5, byte(d.cmd), 0)
|
|
||||||
if ip := net.ParseIP(host); ip != nil {
|
|
||||||
if ip4 := ip.To4(); ip4 != nil {
|
|
||||||
b = append(b, AddrTypeIPv4)
|
|
||||||
b = append(b, ip4...)
|
|
||||||
} else if ip6 := ip.To16(); ip6 != nil {
|
|
||||||
b = append(b, AddrTypeIPv6)
|
|
||||||
b = append(b, ip6...)
|
|
||||||
} else {
|
|
||||||
return nil, errors.New("unknown address type")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if len(host) > 255 {
|
|
||||||
return nil, errors.New("FQDN too long")
|
|
||||||
}
|
|
||||||
b = append(b, AddrTypeFQDN)
|
|
||||||
b = append(b, byte(len(host)))
|
|
||||||
b = append(b, host...)
|
|
||||||
}
|
|
||||||
b = append(b, byte(port>>8), byte(port))
|
|
||||||
if _, ctxErr = c.Write(b); ctxErr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, ctxErr = io.ReadFull(c, b[:4]); ctxErr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if b[0] != Version5 {
|
|
||||||
return nil, errors.New("unexpected protocol version " + strconv.Itoa(int(b[0])))
|
|
||||||
}
|
|
||||||
if cmdErr := Reply(b[1]); cmdErr != StatusSucceeded {
|
|
||||||
return nil, errors.New("unknown error " + cmdErr.String())
|
|
||||||
}
|
|
||||||
if b[2] != 0 {
|
|
||||||
return nil, errors.New("non-zero reserved field")
|
|
||||||
}
|
|
||||||
l := 2
|
|
||||||
var a Addr
|
|
||||||
switch b[3] {
|
|
||||||
case AddrTypeIPv4:
|
|
||||||
l += net.IPv4len
|
|
||||||
a.IP = make(net.IP, net.IPv4len)
|
|
||||||
case AddrTypeIPv6:
|
|
||||||
l += net.IPv6len
|
|
||||||
a.IP = make(net.IP, net.IPv6len)
|
|
||||||
case AddrTypeFQDN:
|
|
||||||
if _, err := io.ReadFull(c, b[:1]); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
l += int(b[0])
|
|
||||||
default:
|
|
||||||
return nil, errors.New("unknown address type " + strconv.Itoa(int(b[3])))
|
|
||||||
}
|
|
||||||
if cap(b) < l {
|
|
||||||
b = make([]byte, l)
|
|
||||||
} else {
|
|
||||||
b = b[:l]
|
|
||||||
}
|
|
||||||
if _, ctxErr = io.ReadFull(c, b); ctxErr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if a.IP != nil {
|
|
||||||
copy(a.IP, b)
|
|
||||||
} else {
|
|
||||||
a.Name = string(b[:len(b)-2])
|
|
||||||
}
|
|
||||||
a.Port = int(b[len(b)-2])<<8 | int(b[len(b)-1])
|
|
||||||
return &a, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func splitHostPort(address string) (string, int, error) {
|
|
||||||
host, port, err := net.SplitHostPort(address)
|
|
||||||
if err != nil {
|
|
||||||
return "", 0, err
|
|
||||||
}
|
|
||||||
portnum, err := strconv.Atoi(port)
|
|
||||||
if err != nil {
|
|
||||||
return "", 0, err
|
|
||||||
}
|
|
||||||
if 1 > portnum || portnum > 0xffff {
|
|
||||||
return "", 0, errors.New("port number out of range " + port)
|
|
||||||
}
|
|
||||||
return host, portnum, nil
|
|
||||||
}
|
|
|
@ -1,317 +0,0 @@
|
||||||
// Copyright 2018 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// Package socks provides a SOCKS version 5 client implementation.
|
|
||||||
//
|
|
||||||
// SOCKS protocol version 5 is defined in RFC 1928.
|
|
||||||
// Username/Password authentication for SOCKS version 5 is defined in
|
|
||||||
// RFC 1929.
|
|
||||||
package socks
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"io"
|
|
||||||
"net"
|
|
||||||
"strconv"
|
|
||||||
)
|
|
||||||
|
|
||||||
// A Command represents a SOCKS command.
|
|
||||||
type Command int
|
|
||||||
|
|
||||||
func (cmd Command) String() string {
|
|
||||||
switch cmd {
|
|
||||||
case CmdConnect:
|
|
||||||
return "socks connect"
|
|
||||||
case cmdBind:
|
|
||||||
return "socks bind"
|
|
||||||
default:
|
|
||||||
return "socks " + strconv.Itoa(int(cmd))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// An AuthMethod represents a SOCKS authentication method.
|
|
||||||
type AuthMethod int
|
|
||||||
|
|
||||||
// A Reply represents a SOCKS command reply code.
|
|
||||||
type Reply int
|
|
||||||
|
|
||||||
func (code Reply) String() string {
|
|
||||||
switch code {
|
|
||||||
case StatusSucceeded:
|
|
||||||
return "succeeded"
|
|
||||||
case 0x01:
|
|
||||||
return "general SOCKS server failure"
|
|
||||||
case 0x02:
|
|
||||||
return "connection not allowed by ruleset"
|
|
||||||
case 0x03:
|
|
||||||
return "network unreachable"
|
|
||||||
case 0x04:
|
|
||||||
return "host unreachable"
|
|
||||||
case 0x05:
|
|
||||||
return "connection refused"
|
|
||||||
case 0x06:
|
|
||||||
return "TTL expired"
|
|
||||||
case 0x07:
|
|
||||||
return "command not supported"
|
|
||||||
case 0x08:
|
|
||||||
return "address type not supported"
|
|
||||||
default:
|
|
||||||
return "unknown code: " + strconv.Itoa(int(code))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wire protocol constants.
|
|
||||||
const (
|
|
||||||
Version5 = 0x05
|
|
||||||
|
|
||||||
AddrTypeIPv4 = 0x01
|
|
||||||
AddrTypeFQDN = 0x03
|
|
||||||
AddrTypeIPv6 = 0x04
|
|
||||||
|
|
||||||
CmdConnect Command = 0x01 // establishes an active-open forward proxy connection
|
|
||||||
cmdBind Command = 0x02 // establishes a passive-open forward proxy connection
|
|
||||||
|
|
||||||
AuthMethodNotRequired AuthMethod = 0x00 // no authentication required
|
|
||||||
AuthMethodUsernamePassword AuthMethod = 0x02 // use username/password
|
|
||||||
AuthMethodNoAcceptableMethods AuthMethod = 0xff // no acceptable authentication methods
|
|
||||||
|
|
||||||
StatusSucceeded Reply = 0x00
|
|
||||||
)
|
|
||||||
|
|
||||||
// An Addr represents a SOCKS-specific address.
|
|
||||||
// Either Name or IP is used exclusively.
|
|
||||||
type Addr struct {
|
|
||||||
Name string // fully-qualified domain name
|
|
||||||
IP net.IP
|
|
||||||
Port int
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *Addr) Network() string { return "socks" }
|
|
||||||
|
|
||||||
func (a *Addr) String() string {
|
|
||||||
if a == nil {
|
|
||||||
return "<nil>"
|
|
||||||
}
|
|
||||||
port := strconv.Itoa(a.Port)
|
|
||||||
if a.IP == nil {
|
|
||||||
return net.JoinHostPort(a.Name, port)
|
|
||||||
}
|
|
||||||
return net.JoinHostPort(a.IP.String(), port)
|
|
||||||
}
|
|
||||||
|
|
||||||
// A Conn represents a forward proxy connection.
|
|
||||||
type Conn struct {
|
|
||||||
net.Conn
|
|
||||||
|
|
||||||
boundAddr net.Addr
|
|
||||||
}
|
|
||||||
|
|
||||||
// BoundAddr returns the address assigned by the proxy server for
|
|
||||||
// connecting to the command target address from the proxy server.
|
|
||||||
func (c *Conn) BoundAddr() net.Addr {
|
|
||||||
if c == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return c.boundAddr
|
|
||||||
}
|
|
||||||
|
|
||||||
// A Dialer holds SOCKS-specific options.
|
|
||||||
type Dialer struct {
|
|
||||||
cmd Command // either CmdConnect or cmdBind
|
|
||||||
proxyNetwork string // network between a proxy server and a client
|
|
||||||
proxyAddress string // proxy server address
|
|
||||||
|
|
||||||
// ProxyDial specifies the optional dial function for
|
|
||||||
// establishing the transport connection.
|
|
||||||
ProxyDial func(context.Context, string, string) (net.Conn, error)
|
|
||||||
|
|
||||||
// AuthMethods specifies the list of request authentication
|
|
||||||
// methods.
|
|
||||||
// If empty, SOCKS client requests only AuthMethodNotRequired.
|
|
||||||
AuthMethods []AuthMethod
|
|
||||||
|
|
||||||
// Authenticate specifies the optional authentication
|
|
||||||
// function. It must be non-nil when AuthMethods is not empty.
|
|
||||||
// It must return an error when the authentication is failed.
|
|
||||||
Authenticate func(context.Context, io.ReadWriter, AuthMethod) error
|
|
||||||
}
|
|
||||||
|
|
||||||
// DialContext connects to the provided address on the provided
|
|
||||||
// network.
|
|
||||||
//
|
|
||||||
// The returned error value may be a net.OpError. When the Op field of
|
|
||||||
// net.OpError contains "socks", the Source field contains a proxy
|
|
||||||
// server address and the Addr field contains a command target
|
|
||||||
// address.
|
|
||||||
//
|
|
||||||
// See func Dial of the net package of standard library for a
|
|
||||||
// description of the network and address parameters.
|
|
||||||
func (d *Dialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) {
|
|
||||||
if err := d.validateTarget(network, address); err != nil {
|
|
||||||
proxy, dst, _ := d.pathAddrs(address)
|
|
||||||
return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
|
|
||||||
}
|
|
||||||
if ctx == nil {
|
|
||||||
proxy, dst, _ := d.pathAddrs(address)
|
|
||||||
return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: errors.New("nil context")}
|
|
||||||
}
|
|
||||||
var err error
|
|
||||||
var c net.Conn
|
|
||||||
if d.ProxyDial != nil {
|
|
||||||
c, err = d.ProxyDial(ctx, d.proxyNetwork, d.proxyAddress)
|
|
||||||
} else {
|
|
||||||
var dd net.Dialer
|
|
||||||
c, err = dd.DialContext(ctx, d.proxyNetwork, d.proxyAddress)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
proxy, dst, _ := d.pathAddrs(address)
|
|
||||||
return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
|
|
||||||
}
|
|
||||||
a, err := d.connect(ctx, c, address)
|
|
||||||
if err != nil {
|
|
||||||
c.Close()
|
|
||||||
proxy, dst, _ := d.pathAddrs(address)
|
|
||||||
return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
|
|
||||||
}
|
|
||||||
return &Conn{Conn: c, boundAddr: a}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DialWithConn initiates a connection from SOCKS server to the target
|
|
||||||
// network and address using the connection c that is already
|
|
||||||
// connected to the SOCKS server.
|
|
||||||
//
|
|
||||||
// It returns the connection's local address assigned by the SOCKS
|
|
||||||
// server.
|
|
||||||
func (d *Dialer) DialWithConn(ctx context.Context, c net.Conn, network, address string) (net.Addr, error) {
|
|
||||||
if err := d.validateTarget(network, address); err != nil {
|
|
||||||
proxy, dst, _ := d.pathAddrs(address)
|
|
||||||
return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
|
|
||||||
}
|
|
||||||
if ctx == nil {
|
|
||||||
proxy, dst, _ := d.pathAddrs(address)
|
|
||||||
return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: errors.New("nil context")}
|
|
||||||
}
|
|
||||||
a, err := d.connect(ctx, c, address)
|
|
||||||
if err != nil {
|
|
||||||
proxy, dst, _ := d.pathAddrs(address)
|
|
||||||
return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
|
|
||||||
}
|
|
||||||
return a, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dial connects to the provided address on the provided network.
|
|
||||||
//
|
|
||||||
// Unlike DialContext, it returns a raw transport connection instead
|
|
||||||
// of a forward proxy connection.
|
|
||||||
//
|
|
||||||
// Deprecated: Use DialContext or DialWithConn instead.
|
|
||||||
func (d *Dialer) Dial(network, address string) (net.Conn, error) {
|
|
||||||
if err := d.validateTarget(network, address); err != nil {
|
|
||||||
proxy, dst, _ := d.pathAddrs(address)
|
|
||||||
return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
|
|
||||||
}
|
|
||||||
var err error
|
|
||||||
var c net.Conn
|
|
||||||
if d.ProxyDial != nil {
|
|
||||||
c, err = d.ProxyDial(context.Background(), d.proxyNetwork, d.proxyAddress)
|
|
||||||
} else {
|
|
||||||
c, err = net.Dial(d.proxyNetwork, d.proxyAddress)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
proxy, dst, _ := d.pathAddrs(address)
|
|
||||||
return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
|
|
||||||
}
|
|
||||||
if _, err := d.DialWithConn(context.Background(), c, network, address); err != nil {
|
|
||||||
c.Close()
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return c, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *Dialer) validateTarget(network, address string) error {
|
|
||||||
switch network {
|
|
||||||
case "tcp", "tcp6", "tcp4":
|
|
||||||
default:
|
|
||||||
return errors.New("network not implemented")
|
|
||||||
}
|
|
||||||
switch d.cmd {
|
|
||||||
case CmdConnect, cmdBind:
|
|
||||||
default:
|
|
||||||
return errors.New("command not implemented")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *Dialer) pathAddrs(address string) (proxy, dst net.Addr, err error) {
|
|
||||||
for i, s := range []string{d.proxyAddress, address} {
|
|
||||||
host, port, err := splitHostPort(s)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
a := &Addr{Port: port}
|
|
||||||
a.IP = net.ParseIP(host)
|
|
||||||
if a.IP == nil {
|
|
||||||
a.Name = host
|
|
||||||
}
|
|
||||||
if i == 0 {
|
|
||||||
proxy = a
|
|
||||||
} else {
|
|
||||||
dst = a
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewDialer returns a new Dialer that dials through the provided
|
|
||||||
// proxy server's network and address.
|
|
||||||
func NewDialer(network, address string) *Dialer {
|
|
||||||
return &Dialer{proxyNetwork: network, proxyAddress: address, cmd: CmdConnect}
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
authUsernamePasswordVersion = 0x01
|
|
||||||
authStatusSucceeded = 0x00
|
|
||||||
)
|
|
||||||
|
|
||||||
// UsernamePassword are the credentials for the username/password
|
|
||||||
// authentication method.
|
|
||||||
type UsernamePassword struct {
|
|
||||||
Username string
|
|
||||||
Password string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Authenticate authenticates a pair of username and password with the
|
|
||||||
// proxy server.
|
|
||||||
func (up *UsernamePassword) Authenticate(ctx context.Context, rw io.ReadWriter, auth AuthMethod) error {
|
|
||||||
switch auth {
|
|
||||||
case AuthMethodNotRequired:
|
|
||||||
return nil
|
|
||||||
case AuthMethodUsernamePassword:
|
|
||||||
if len(up.Username) == 0 || len(up.Username) > 255 || len(up.Password) > 255 {
|
|
||||||
return errors.New("invalid username/password")
|
|
||||||
}
|
|
||||||
b := []byte{authUsernamePasswordVersion}
|
|
||||||
b = append(b, byte(len(up.Username)))
|
|
||||||
b = append(b, up.Username...)
|
|
||||||
b = append(b, byte(len(up.Password)))
|
|
||||||
b = append(b, up.Password...)
|
|
||||||
// TODO(mikio): handle IO deadlines and cancelation if
|
|
||||||
// necessary
|
|
||||||
if _, err := rw.Write(b); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if _, err := io.ReadFull(rw, b[:2]); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if b[0] != authUsernamePasswordVersion {
|
|
||||||
return errors.New("invalid username/password version")
|
|
||||||
}
|
|
||||||
if b[1] != authStatusSucceeded {
|
|
||||||
return errors.New("username/password authentication failed")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return errors.New("unsupported authentication method " + strconv.Itoa(int(auth)))
|
|
||||||
}
|
|
|
@ -1,54 +0,0 @@
|
||||||
// Copyright 2019 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package proxy
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"net"
|
|
||||||
)
|
|
||||||
|
|
||||||
// A ContextDialer dials using a context.
|
|
||||||
type ContextDialer interface {
|
|
||||||
DialContext(ctx context.Context, network, address string) (net.Conn, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dial works like DialContext on net.Dialer but using a dialer returned by FromEnvironment.
|
|
||||||
//
|
|
||||||
// The passed ctx is only used for returning the Conn, not the lifetime of the Conn.
|
|
||||||
//
|
|
||||||
// Custom dialers (registered via RegisterDialerType) that do not implement ContextDialer
|
|
||||||
// can leak a goroutine for as long as it takes the underlying Dialer implementation to timeout.
|
|
||||||
//
|
|
||||||
// A Conn returned from a successful Dial after the context has been cancelled will be immediately closed.
|
|
||||||
func Dial(ctx context.Context, network, address string) (net.Conn, error) {
|
|
||||||
d := FromEnvironment()
|
|
||||||
if xd, ok := d.(ContextDialer); ok {
|
|
||||||
return xd.DialContext(ctx, network, address)
|
|
||||||
}
|
|
||||||
return dialContext(ctx, d, network, address)
|
|
||||||
}
|
|
||||||
|
|
||||||
// WARNING: this can leak a goroutine for as long as the underlying Dialer implementation takes to timeout
|
|
||||||
// A Conn returned from a successful Dial after the context has been cancelled will be immediately closed.
|
|
||||||
func dialContext(ctx context.Context, d Dialer, network, address string) (net.Conn, error) {
|
|
||||||
var (
|
|
||||||
conn net.Conn
|
|
||||||
done = make(chan struct{}, 1)
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
go func() {
|
|
||||||
conn, err = d.Dial(network, address)
|
|
||||||
close(done)
|
|
||||||
if conn != nil && ctx.Err() != nil {
|
|
||||||
conn.Close()
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
err = ctx.Err()
|
|
||||||
case <-done:
|
|
||||||
}
|
|
||||||
return conn, err
|
|
||||||
}
|
|
|
@ -1,31 +0,0 @@
|
||||||
// Copyright 2011 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package proxy
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"net"
|
|
||||||
)
|
|
||||||
|
|
||||||
type direct struct{}
|
|
||||||
|
|
||||||
// Direct implements Dialer by making network connections directly using net.Dial or net.DialContext.
|
|
||||||
var Direct = direct{}
|
|
||||||
|
|
||||||
var (
|
|
||||||
_ Dialer = Direct
|
|
||||||
_ ContextDialer = Direct
|
|
||||||
)
|
|
||||||
|
|
||||||
// Dial directly invokes net.Dial with the supplied parameters.
|
|
||||||
func (direct) Dial(network, addr string) (net.Conn, error) {
|
|
||||||
return net.Dial(network, addr)
|
|
||||||
}
|
|
||||||
|
|
||||||
// DialContext instantiates a net.Dialer and invokes its DialContext receiver with the supplied parameters.
|
|
||||||
func (direct) DialContext(ctx context.Context, network, addr string) (net.Conn, error) {
|
|
||||||
var d net.Dialer
|
|
||||||
return d.DialContext(ctx, network, addr)
|
|
||||||
}
|
|
|
@ -1,155 +0,0 @@
|
||||||
// Copyright 2011 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package proxy
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"net"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// A PerHost directs connections to a default Dialer unless the host name
|
|
||||||
// requested matches one of a number of exceptions.
|
|
||||||
type PerHost struct {
|
|
||||||
def, bypass Dialer
|
|
||||||
|
|
||||||
bypassNetworks []*net.IPNet
|
|
||||||
bypassIPs []net.IP
|
|
||||||
bypassZones []string
|
|
||||||
bypassHosts []string
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewPerHost returns a PerHost Dialer that directs connections to either
|
|
||||||
// defaultDialer or bypass, depending on whether the connection matches one of
|
|
||||||
// the configured rules.
|
|
||||||
func NewPerHost(defaultDialer, bypass Dialer) *PerHost {
|
|
||||||
return &PerHost{
|
|
||||||
def: defaultDialer,
|
|
||||||
bypass: bypass,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dial connects to the address addr on the given network through either
|
|
||||||
// defaultDialer or bypass.
|
|
||||||
func (p *PerHost) Dial(network, addr string) (c net.Conn, err error) {
|
|
||||||
host, _, err := net.SplitHostPort(addr)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return p.dialerForRequest(host).Dial(network, addr)
|
|
||||||
}
|
|
||||||
|
|
||||||
// DialContext connects to the address addr on the given network through either
|
|
||||||
// defaultDialer or bypass.
|
|
||||||
func (p *PerHost) DialContext(ctx context.Context, network, addr string) (c net.Conn, err error) {
|
|
||||||
host, _, err := net.SplitHostPort(addr)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
d := p.dialerForRequest(host)
|
|
||||||
if x, ok := d.(ContextDialer); ok {
|
|
||||||
return x.DialContext(ctx, network, addr)
|
|
||||||
}
|
|
||||||
return dialContext(ctx, d, network, addr)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *PerHost) dialerForRequest(host string) Dialer {
|
|
||||||
if ip := net.ParseIP(host); ip != nil {
|
|
||||||
for _, net := range p.bypassNetworks {
|
|
||||||
if net.Contains(ip) {
|
|
||||||
return p.bypass
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, bypassIP := range p.bypassIPs {
|
|
||||||
if bypassIP.Equal(ip) {
|
|
||||||
return p.bypass
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return p.def
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, zone := range p.bypassZones {
|
|
||||||
if strings.HasSuffix(host, zone) {
|
|
||||||
return p.bypass
|
|
||||||
}
|
|
||||||
if host == zone[1:] {
|
|
||||||
// For a zone ".example.com", we match "example.com"
|
|
||||||
// too.
|
|
||||||
return p.bypass
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, bypassHost := range p.bypassHosts {
|
|
||||||
if bypassHost == host {
|
|
||||||
return p.bypass
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return p.def
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddFromString parses a string that contains comma-separated values
|
|
||||||
// specifying hosts that should use the bypass proxy. Each value is either an
|
|
||||||
// IP address, a CIDR range, a zone (*.example.com) or a host name
|
|
||||||
// (localhost). A best effort is made to parse the string and errors are
|
|
||||||
// ignored.
|
|
||||||
func (p *PerHost) AddFromString(s string) {
|
|
||||||
hosts := strings.Split(s, ",")
|
|
||||||
for _, host := range hosts {
|
|
||||||
host = strings.TrimSpace(host)
|
|
||||||
if len(host) == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if strings.Contains(host, "/") {
|
|
||||||
// We assume that it's a CIDR address like 127.0.0.0/8
|
|
||||||
if _, net, err := net.ParseCIDR(host); err == nil {
|
|
||||||
p.AddNetwork(net)
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if ip := net.ParseIP(host); ip != nil {
|
|
||||||
p.AddIP(ip)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if strings.HasPrefix(host, "*.") {
|
|
||||||
p.AddZone(host[1:])
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
p.AddHost(host)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddIP specifies an IP address that will use the bypass proxy. Note that
|
|
||||||
// this will only take effect if a literal IP address is dialed. A connection
|
|
||||||
// to a named host will never match an IP.
|
|
||||||
func (p *PerHost) AddIP(ip net.IP) {
|
|
||||||
p.bypassIPs = append(p.bypassIPs, ip)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddNetwork specifies an IP range that will use the bypass proxy. Note that
|
|
||||||
// this will only take effect if a literal IP address is dialed. A connection
|
|
||||||
// to a named host will never match.
|
|
||||||
func (p *PerHost) AddNetwork(net *net.IPNet) {
|
|
||||||
p.bypassNetworks = append(p.bypassNetworks, net)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddZone specifies a DNS suffix that will use the bypass proxy. A zone of
|
|
||||||
// "example.com" matches "example.com" and all of its subdomains.
|
|
||||||
func (p *PerHost) AddZone(zone string) {
|
|
||||||
if strings.HasSuffix(zone, ".") {
|
|
||||||
zone = zone[:len(zone)-1]
|
|
||||||
}
|
|
||||||
if !strings.HasPrefix(zone, ".") {
|
|
||||||
zone = "." + zone
|
|
||||||
}
|
|
||||||
p.bypassZones = append(p.bypassZones, zone)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddHost specifies a host name that will use the bypass proxy.
|
|
||||||
func (p *PerHost) AddHost(host string) {
|
|
||||||
if strings.HasSuffix(host, ".") {
|
|
||||||
host = host[:len(host)-1]
|
|
||||||
}
|
|
||||||
p.bypassHosts = append(p.bypassHosts, host)
|
|
||||||
}
|
|
|
@ -1,149 +0,0 @@
|
||||||
// Copyright 2011 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// Package proxy provides support for a variety of protocols to proxy network
|
|
||||||
// data.
|
|
||||||
package proxy // import "golang.org/x/net/proxy"
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"net"
|
|
||||||
"net/url"
|
|
||||||
"os"
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
// A Dialer is a means to establish a connection.
|
|
||||||
// Custom dialers should also implement ContextDialer.
|
|
||||||
type Dialer interface {
|
|
||||||
// Dial connects to the given address via the proxy.
|
|
||||||
Dial(network, addr string) (c net.Conn, err error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Auth contains authentication parameters that specific Dialers may require.
|
|
||||||
type Auth struct {
|
|
||||||
User, Password string
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromEnvironment returns the dialer specified by the proxy-related
|
|
||||||
// variables in the environment and makes underlying connections
|
|
||||||
// directly.
|
|
||||||
func FromEnvironment() Dialer {
|
|
||||||
return FromEnvironmentUsing(Direct)
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromEnvironmentUsing returns the dialer specify by the proxy-related
|
|
||||||
// variables in the environment and makes underlying connections
|
|
||||||
// using the provided forwarding Dialer (for instance, a *net.Dialer
|
|
||||||
// with desired configuration).
|
|
||||||
func FromEnvironmentUsing(forward Dialer) Dialer {
|
|
||||||
allProxy := allProxyEnv.Get()
|
|
||||||
if len(allProxy) == 0 {
|
|
||||||
return forward
|
|
||||||
}
|
|
||||||
|
|
||||||
proxyURL, err := url.Parse(allProxy)
|
|
||||||
if err != nil {
|
|
||||||
return forward
|
|
||||||
}
|
|
||||||
proxy, err := FromURL(proxyURL, forward)
|
|
||||||
if err != nil {
|
|
||||||
return forward
|
|
||||||
}
|
|
||||||
|
|
||||||
noProxy := noProxyEnv.Get()
|
|
||||||
if len(noProxy) == 0 {
|
|
||||||
return proxy
|
|
||||||
}
|
|
||||||
|
|
||||||
perHost := NewPerHost(proxy, forward)
|
|
||||||
perHost.AddFromString(noProxy)
|
|
||||||
return perHost
|
|
||||||
}
|
|
||||||
|
|
||||||
// proxySchemes is a map from URL schemes to a function that creates a Dialer
|
|
||||||
// from a URL with such a scheme.
|
|
||||||
var proxySchemes map[string]func(*url.URL, Dialer) (Dialer, error)
|
|
||||||
|
|
||||||
// RegisterDialerType takes a URL scheme and a function to generate Dialers from
|
|
||||||
// a URL with that scheme and a forwarding Dialer. Registered schemes are used
|
|
||||||
// by FromURL.
|
|
||||||
func RegisterDialerType(scheme string, f func(*url.URL, Dialer) (Dialer, error)) {
|
|
||||||
if proxySchemes == nil {
|
|
||||||
proxySchemes = make(map[string]func(*url.URL, Dialer) (Dialer, error))
|
|
||||||
}
|
|
||||||
proxySchemes[scheme] = f
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromURL returns a Dialer given a URL specification and an underlying
|
|
||||||
// Dialer for it to make network requests.
|
|
||||||
func FromURL(u *url.URL, forward Dialer) (Dialer, error) {
|
|
||||||
var auth *Auth
|
|
||||||
if u.User != nil {
|
|
||||||
auth = new(Auth)
|
|
||||||
auth.User = u.User.Username()
|
|
||||||
if p, ok := u.User.Password(); ok {
|
|
||||||
auth.Password = p
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch u.Scheme {
|
|
||||||
case "socks5", "socks5h":
|
|
||||||
addr := u.Hostname()
|
|
||||||
port := u.Port()
|
|
||||||
if port == "" {
|
|
||||||
port = "1080"
|
|
||||||
}
|
|
||||||
return SOCKS5("tcp", net.JoinHostPort(addr, port), auth, forward)
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the scheme doesn't match any of the built-in schemes, see if it
|
|
||||||
// was registered by another package.
|
|
||||||
if proxySchemes != nil {
|
|
||||||
if f, ok := proxySchemes[u.Scheme]; ok {
|
|
||||||
return f(u, forward)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, errors.New("proxy: unknown scheme: " + u.Scheme)
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
allProxyEnv = &envOnce{
|
|
||||||
names: []string{"ALL_PROXY", "all_proxy"},
|
|
||||||
}
|
|
||||||
noProxyEnv = &envOnce{
|
|
||||||
names: []string{"NO_PROXY", "no_proxy"},
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// envOnce looks up an environment variable (optionally by multiple
|
|
||||||
// names) once. It mitigates expensive lookups on some platforms
|
|
||||||
// (e.g. Windows).
|
|
||||||
// (Borrowed from net/http/transport.go)
|
|
||||||
type envOnce struct {
|
|
||||||
names []string
|
|
||||||
once sync.Once
|
|
||||||
val string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *envOnce) Get() string {
|
|
||||||
e.once.Do(e.init)
|
|
||||||
return e.val
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *envOnce) init() {
|
|
||||||
for _, n := range e.names {
|
|
||||||
e.val = os.Getenv(n)
|
|
||||||
if e.val != "" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// reset is used by tests
|
|
||||||
func (e *envOnce) reset() {
|
|
||||||
e.once = sync.Once{}
|
|
||||||
e.val = ""
|
|
||||||
}
|
|
|
@ -1,42 +0,0 @@
|
||||||
// Copyright 2011 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package proxy
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"net"
|
|
||||||
|
|
||||||
"golang.org/x/net/internal/socks"
|
|
||||||
)
|
|
||||||
|
|
||||||
// SOCKS5 returns a Dialer that makes SOCKSv5 connections to the given
|
|
||||||
// address with an optional username and password.
|
|
||||||
// See RFC 1928 and RFC 1929.
|
|
||||||
func SOCKS5(network, address string, auth *Auth, forward Dialer) (Dialer, error) {
|
|
||||||
d := socks.NewDialer(network, address)
|
|
||||||
if forward != nil {
|
|
||||||
if f, ok := forward.(ContextDialer); ok {
|
|
||||||
d.ProxyDial = func(ctx context.Context, network string, address string) (net.Conn, error) {
|
|
||||||
return f.DialContext(ctx, network, address)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
d.ProxyDial = func(ctx context.Context, network string, address string) (net.Conn, error) {
|
|
||||||
return dialContext(ctx, forward, network, address)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if auth != nil {
|
|
||||||
up := socks.UsernamePassword{
|
|
||||||
Username: auth.User,
|
|
||||||
Password: auth.Password,
|
|
||||||
}
|
|
||||||
d.AuthMethods = []socks.AuthMethod{
|
|
||||||
socks.AuthMethodNotRequired,
|
|
||||||
socks.AuthMethodUsernamePassword,
|
|
||||||
}
|
|
||||||
d.Authenticate = up.Authenticate
|
|
||||||
}
|
|
||||||
return d, nil
|
|
||||||
}
|
|
|
@ -100,8 +100,8 @@ github.com/docker/docker-credential-helpers/credentials
|
||||||
# github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c
|
# github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c
|
||||||
## explicit
|
## explicit
|
||||||
github.com/docker/go/canonical/json
|
github.com/docker/go/canonical/json
|
||||||
# github.com/docker/go-connections v0.4.0
|
# github.com/docker/go-connections v0.4.1-0.20231031175723-0b8c1f4e07a0
|
||||||
## explicit
|
## explicit; go 1.13
|
||||||
github.com/docker/go-connections/nat
|
github.com/docker/go-connections/nat
|
||||||
github.com/docker/go-connections/sockets
|
github.com/docker/go-connections/sockets
|
||||||
github.com/docker/go-connections/tlsconfig
|
github.com/docker/go-connections/tlsconfig
|
||||||
|
@ -321,9 +321,7 @@ golang.org/x/net/http/httpguts
|
||||||
golang.org/x/net/http2
|
golang.org/x/net/http2
|
||||||
golang.org/x/net/http2/hpack
|
golang.org/x/net/http2/hpack
|
||||||
golang.org/x/net/idna
|
golang.org/x/net/idna
|
||||||
golang.org/x/net/internal/socks
|
|
||||||
golang.org/x/net/internal/timeseries
|
golang.org/x/net/internal/timeseries
|
||||||
golang.org/x/net/proxy
|
|
||||||
golang.org/x/net/trace
|
golang.org/x/net/trace
|
||||||
# golang.org/x/sync v0.3.0
|
# golang.org/x/sync v0.3.0
|
||||||
## explicit; go 1.17
|
## explicit; go 1.17
|
||||||
|
|
Loading…
Reference in New Issue