1
// Copyright 2018 The Go Authors. All rights reserved.
2
// Use of this source code is governed by a BSD-style
3
// license that can be found in the LICENSE file.
17
noDeadline = time.Time{}
18
aLongTimeAgo = time.Unix(1, 0)
21
func (d *Dialer) connect(ctx context.Context, c net.Conn, address string) (_ net.Addr, ctxErr error) {
22
host, port, err := splitHostPort(address)
26
if deadline, ok := ctx.Deadline(); ok && !deadline.IsZero() {
27
c.SetDeadline(deadline)
28
defer c.SetDeadline(noDeadline)
30
if ctx != context.Background() {
31
errCh := make(chan error, 1)
32
done := make(chan struct{})
42
c.SetDeadline(aLongTimeAgo)
50
b := make([]byte, 0, 6+len(host)) // the size here is just an estimate
51
b = append(b, Version5)
52
if len(d.AuthMethods) == 0 || d.Authenticate == nil {
53
b = append(b, 1, byte(AuthMethodNotRequired))
57
return nil, errors.New("too many authentication methods")
59
b = append(b, byte(len(ams)))
60
for _, am := range ams {
61
b = append(b, byte(am))
64
if _, ctxErr = c.Write(b); ctxErr != nil {
68
if _, ctxErr = io.ReadFull(c, b[:2]); ctxErr != nil {
72
return nil, errors.New("unexpected protocol version " + strconv.Itoa(int(b[0])))
74
am := AuthMethod(b[1])
75
if am == AuthMethodNoAcceptableMethods {
76
return nil, errors.New("no acceptable authentication methods")
78
if d.Authenticate != nil {
79
if ctxErr = d.Authenticate(ctx, c, am); ctxErr != nil {
85
b = append(b, Version5, byte(d.cmd), 0)
86
if ip := net.ParseIP(host); ip != nil {
87
if ip4 := ip.To4(); ip4 != nil {
88
b = append(b, AddrTypeIPv4)
90
} else if ip6 := ip.To16(); ip6 != nil {
91
b = append(b, AddrTypeIPv6)
94
return nil, errors.New("unknown address type")
98
return nil, errors.New("FQDN too long")
100
b = append(b, AddrTypeFQDN)
101
b = append(b, byte(len(host)))
102
b = append(b, host...)
104
b = append(b, byte(port>>8), byte(port))
105
if _, ctxErr = c.Write(b); ctxErr != nil {
109
if _, ctxErr = io.ReadFull(c, b[:4]); ctxErr != nil {
112
if b[0] != Version5 {
113
return nil, errors.New("unexpected protocol version " + strconv.Itoa(int(b[0])))
115
if cmdErr := Reply(b[1]); cmdErr != StatusSucceeded {
116
return nil, errors.New("unknown error " + cmdErr.String())
119
return nil, errors.New("non-zero reserved field")
126
a.IP = make(net.IP, net.IPv4len)
129
a.IP = make(net.IP, net.IPv6len)
131
if _, err := io.ReadFull(c, b[:1]); err != nil {
136
return nil, errors.New("unknown address type " + strconv.Itoa(int(b[3])))
143
if _, ctxErr = io.ReadFull(c, b); ctxErr != nil {
149
a.Name = string(b[:len(b)-2])
151
a.Port = int(b[len(b)-2])<<8 | int(b[len(b)-1])
155
func splitHostPort(address string) (string, int, error) {
156
host, port, err := net.SplitHostPort(address)
160
portnum, err := strconv.Atoi(port)
164
if 1 > portnum || portnum > 0xffff {
165
return "", 0, errors.New("port number out of range " + port)
167
return host, portnum, nil