mirror of
https://github.com/linuxkit/linuxkit.git
synced 2025-10-29 17:31:05 +00:00
Generated largely from the specified config; small parts taken from `docker image inspect`, such as the command line. Renamed some of the yaml keys to match the OCI spec rather than Docker Compose as we decided they are more readable, no more underscores. Add some extra functionality - tmpfs specification - fully general mount specification - no new privileges can be specified now For nostalgic reasons, using engine-api to talk to the docker cli as we only need an old API version, and it is nice and easy to vendor... Signed-off-by: Justin Cormack <justin.cormack@docker.com>
214 lines
5.7 KiB
Go
214 lines
5.7 KiB
Go
// 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 (
|
|
"errors"
|
|
"io"
|
|
"net"
|
|
"strconv"
|
|
)
|
|
|
|
// SOCKS5 returns a Dialer that makes SOCKSv5 connections to the given address
|
|
// with an optional username and password. See RFC 1928.
|
|
func SOCKS5(network, addr string, auth *Auth, forward Dialer) (Dialer, error) {
|
|
s := &socks5{
|
|
network: network,
|
|
addr: addr,
|
|
forward: forward,
|
|
}
|
|
if auth != nil {
|
|
s.user = auth.User
|
|
s.password = auth.Password
|
|
}
|
|
|
|
return s, nil
|
|
}
|
|
|
|
type socks5 struct {
|
|
user, password string
|
|
network, addr string
|
|
forward Dialer
|
|
}
|
|
|
|
const socks5Version = 5
|
|
|
|
const (
|
|
socks5AuthNone = 0
|
|
socks5AuthPassword = 2
|
|
)
|
|
|
|
const socks5Connect = 1
|
|
|
|
const (
|
|
socks5IP4 = 1
|
|
socks5Domain = 3
|
|
socks5IP6 = 4
|
|
)
|
|
|
|
var socks5Errors = []string{
|
|
"",
|
|
"general failure",
|
|
"connection forbidden",
|
|
"network unreachable",
|
|
"host unreachable",
|
|
"connection refused",
|
|
"TTL expired",
|
|
"command not supported",
|
|
"address type not supported",
|
|
}
|
|
|
|
// Dial connects to the address addr on the network net via the SOCKS5 proxy.
|
|
func (s *socks5) Dial(network, addr string) (net.Conn, error) {
|
|
switch network {
|
|
case "tcp", "tcp6", "tcp4":
|
|
default:
|
|
return nil, errors.New("proxy: no support for SOCKS5 proxy connections of type " + network)
|
|
}
|
|
|
|
conn, err := s.forward.Dial(s.network, s.addr)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if err := s.connect(conn, addr); err != nil {
|
|
conn.Close()
|
|
return nil, err
|
|
}
|
|
return conn, nil
|
|
}
|
|
|
|
// connect takes an existing connection to a socks5 proxy server,
|
|
// and commands the server to extend that connection to target,
|
|
// which must be a canonical address with a host and port.
|
|
func (s *socks5) connect(conn net.Conn, target string) error {
|
|
host, portStr, err := net.SplitHostPort(target)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
port, err := strconv.Atoi(portStr)
|
|
if err != nil {
|
|
return errors.New("proxy: failed to parse port number: " + portStr)
|
|
}
|
|
if port < 1 || port > 0xffff {
|
|
return errors.New("proxy: port number out of range: " + portStr)
|
|
}
|
|
|
|
// the size here is just an estimate
|
|
buf := make([]byte, 0, 6+len(host))
|
|
|
|
buf = append(buf, socks5Version)
|
|
if len(s.user) > 0 && len(s.user) < 256 && len(s.password) < 256 {
|
|
buf = append(buf, 2 /* num auth methods */, socks5AuthNone, socks5AuthPassword)
|
|
} else {
|
|
buf = append(buf, 1 /* num auth methods */, socks5AuthNone)
|
|
}
|
|
|
|
if _, err := conn.Write(buf); err != nil {
|
|
return errors.New("proxy: failed to write greeting to SOCKS5 proxy at " + s.addr + ": " + err.Error())
|
|
}
|
|
|
|
if _, err := io.ReadFull(conn, buf[:2]); err != nil {
|
|
return errors.New("proxy: failed to read greeting from SOCKS5 proxy at " + s.addr + ": " + err.Error())
|
|
}
|
|
if buf[0] != 5 {
|
|
return errors.New("proxy: SOCKS5 proxy at " + s.addr + " has unexpected version " + strconv.Itoa(int(buf[0])))
|
|
}
|
|
if buf[1] == 0xff {
|
|
return errors.New("proxy: SOCKS5 proxy at " + s.addr + " requires authentication")
|
|
}
|
|
|
|
if buf[1] == socks5AuthPassword {
|
|
buf = buf[:0]
|
|
buf = append(buf, 1 /* password protocol version */)
|
|
buf = append(buf, uint8(len(s.user)))
|
|
buf = append(buf, s.user...)
|
|
buf = append(buf, uint8(len(s.password)))
|
|
buf = append(buf, s.password...)
|
|
|
|
if _, err := conn.Write(buf); err != nil {
|
|
return errors.New("proxy: failed to write authentication request to SOCKS5 proxy at " + s.addr + ": " + err.Error())
|
|
}
|
|
|
|
if _, err := io.ReadFull(conn, buf[:2]); err != nil {
|
|
return errors.New("proxy: failed to read authentication reply from SOCKS5 proxy at " + s.addr + ": " + err.Error())
|
|
}
|
|
|
|
if buf[1] != 0 {
|
|
return errors.New("proxy: SOCKS5 proxy at " + s.addr + " rejected username/password")
|
|
}
|
|
}
|
|
|
|
buf = buf[:0]
|
|
buf = append(buf, socks5Version, socks5Connect, 0 /* reserved */)
|
|
|
|
if ip := net.ParseIP(host); ip != nil {
|
|
if ip4 := ip.To4(); ip4 != nil {
|
|
buf = append(buf, socks5IP4)
|
|
ip = ip4
|
|
} else {
|
|
buf = append(buf, socks5IP6)
|
|
}
|
|
buf = append(buf, ip...)
|
|
} else {
|
|
if len(host) > 255 {
|
|
return errors.New("proxy: destination hostname too long: " + host)
|
|
}
|
|
buf = append(buf, socks5Domain)
|
|
buf = append(buf, byte(len(host)))
|
|
buf = append(buf, host...)
|
|
}
|
|
buf = append(buf, byte(port>>8), byte(port))
|
|
|
|
if _, err := conn.Write(buf); err != nil {
|
|
return errors.New("proxy: failed to write connect request to SOCKS5 proxy at " + s.addr + ": " + err.Error())
|
|
}
|
|
|
|
if _, err := io.ReadFull(conn, buf[:4]); err != nil {
|
|
return errors.New("proxy: failed to read connect reply from SOCKS5 proxy at " + s.addr + ": " + err.Error())
|
|
}
|
|
|
|
failure := "unknown error"
|
|
if int(buf[1]) < len(socks5Errors) {
|
|
failure = socks5Errors[buf[1]]
|
|
}
|
|
|
|
if len(failure) > 0 {
|
|
return errors.New("proxy: SOCKS5 proxy at " + s.addr + " failed to connect: " + failure)
|
|
}
|
|
|
|
bytesToDiscard := 0
|
|
switch buf[3] {
|
|
case socks5IP4:
|
|
bytesToDiscard = net.IPv4len
|
|
case socks5IP6:
|
|
bytesToDiscard = net.IPv6len
|
|
case socks5Domain:
|
|
_, err := io.ReadFull(conn, buf[:1])
|
|
if err != nil {
|
|
return errors.New("proxy: failed to read domain length from SOCKS5 proxy at " + s.addr + ": " + err.Error())
|
|
}
|
|
bytesToDiscard = int(buf[0])
|
|
default:
|
|
return errors.New("proxy: got unknown address type " + strconv.Itoa(int(buf[3])) + " from SOCKS5 proxy at " + s.addr)
|
|
}
|
|
|
|
if cap(buf) < bytesToDiscard {
|
|
buf = make([]byte, bytesToDiscard)
|
|
} else {
|
|
buf = buf[:bytesToDiscard]
|
|
}
|
|
if _, err := io.ReadFull(conn, buf); err != nil {
|
|
return errors.New("proxy: failed to read address from SOCKS5 proxy at " + s.addr + ": " + err.Error())
|
|
}
|
|
|
|
// Also need to discard the port number
|
|
if _, err := io.ReadFull(conn, buf[:2]); err != nil {
|
|
return errors.New("proxy: failed to read port from SOCKS5 proxy at " + s.addr + ": " + err.Error())
|
|
}
|
|
|
|
return nil
|
|
}
|