mirror of
https://github.com/octoleo/syncthing.git
synced 2024-11-13 08:46:30 +00:00
65aaa607ab
Change made by: - running "gvt fetch" on each of the packages mentioned in Godeps/Godeps.json - `rm -rf Godeps` - tweaking the build scripts to not mention Godeps - tweaking the build scripts to test `./lib/...`, `./cmd/...` explicitly (to avoid testing vendor) - tweaking the build scripts to not juggle GOPATH for Godeps and instead set GO15VENDOREXPERIMENT. This also results in some updated packages at the same time I bet. Building with Go 1.3 and 1.4 still *works* but won't use our vendored dependencies - the user needs to have the actual packages in their GOPATH then, which they'll get with a normal "go get". Building with Go 1.6+ will get our vendored dependencies by default even when not using our build script, which is nice. By doing this we gain some freedom in that we can pick and choose manually what to include in vendor, as it's not based on just dependency analysis of our own code. This is also a risk as we might pick up dependencies we are unaware of, as the build may work locally with those packages present in GOPATH. On the other hand the build server will detect this as it has no packages in it's GOPATH beyond what is included in the repo. Recommended tool to manage dependencies is github.com/FiloSottile/gvt.
211 lines
5.5 KiB
Go
211 lines
5.5 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
|
|
}
|
|
closeConn := &conn
|
|
defer func() {
|
|
if closeConn != nil {
|
|
(*closeConn).Close()
|
|
}
|
|
}()
|
|
|
|
host, portStr, err := net.SplitHostPort(addr)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
port, err := strconv.Atoi(portStr)
|
|
if err != nil {
|
|
return nil, errors.New("proxy: failed to parse port number: " + portStr)
|
|
}
|
|
if port < 1 || port > 0xffff {
|
|
return nil, 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 nil, 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 nil, errors.New("proxy: failed to read greeting from SOCKS5 proxy at " + s.addr + ": " + err.Error())
|
|
}
|
|
if buf[0] != 5 {
|
|
return nil, errors.New("proxy: SOCKS5 proxy at " + s.addr + " has unexpected version " + strconv.Itoa(int(buf[0])))
|
|
}
|
|
if buf[1] == 0xff {
|
|
return nil, 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 nil, 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 nil, errors.New("proxy: failed to read authentication reply from SOCKS5 proxy at " + s.addr + ": " + err.Error())
|
|
}
|
|
|
|
if buf[1] != 0 {
|
|
return nil, 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 nil, 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 nil, 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 nil, 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 nil, 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 nil, errors.New("proxy: failed to read domain length from SOCKS5 proxy at " + s.addr + ": " + err.Error())
|
|
}
|
|
bytesToDiscard = int(buf[0])
|
|
default:
|
|
return nil, 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 nil, 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 nil, errors.New("proxy: failed to read port from SOCKS5 proxy at " + s.addr + ": " + err.Error())
|
|
}
|
|
|
|
closeConn = nil
|
|
return conn, nil
|
|
}
|