OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgo/] [go/] [exp/] [proxy/] [socks5.go] - Blame information for rev 747

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 747 jeremybenn
// Copyright 2011 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.
4
 
5
package proxy
6
 
7
import (
8
        "errors"
9
        "io"
10
        "net"
11
        "strconv"
12
)
13
 
14
// SOCKS5 returns a Dialer that makes SOCKSv5 connections to the given address
15
// with an optional username and password. See RFC 1928.
16
func SOCKS5(network, addr string, auth *Auth, forward Dialer) (Dialer, error) {
17
        s := &socks5{
18
                network: network,
19
                addr:    addr,
20
                forward: forward,
21
        }
22
        if auth != nil {
23
                s.user = auth.User
24
                s.password = auth.Password
25
        }
26
 
27
        return s, nil
28
}
29
 
30
type socks5 struct {
31
        user, password string
32
        network, addr  string
33
        forward        Dialer
34
}
35
 
36
const socks5Version = 5
37
 
38
const (
39
        socks5AuthNone     = 0
40
        socks5AuthPassword = 2
41
)
42
 
43
const socks5Connect = 1
44
 
45
const (
46
        socks5IP4    = 1
47
        socks5Domain = 3
48
        socks5IP6    = 4
49
)
50
 
51
var socks5Errors = []string{
52
        "",
53
        "general failure",
54
        "connection forbidden",
55
        "network unreachable",
56
        "host unreachable",
57
        "connection refused",
58
        "TTL expired",
59
        "command not supported",
60
        "address type not supported",
61
}
62
 
63
// Dial connects to the address addr on the network net via the SOCKS5 proxy.
64
func (s *socks5) Dial(network, addr string) (net.Conn, error) {
65
        switch network {
66
        case "tcp", "tcp6", "tcp4":
67
                break
68
        default:
69
                return nil, errors.New("proxy: no support for SOCKS5 proxy connections of type " + network)
70
        }
71
 
72
        conn, err := s.forward.Dial(s.network, s.addr)
73
        if err != nil {
74
                return nil, err
75
        }
76
        closeConn := &conn
77
        defer func() {
78
                if closeConn != nil {
79
                        (*closeConn).Close()
80
                }
81
        }()
82
 
83
        host, portStr, err := net.SplitHostPort(addr)
84
        if err != nil {
85
                return nil, err
86
        }
87
 
88
        port, err := strconv.Atoi(portStr)
89
        if err != nil {
90
                return nil, errors.New("proxy: failed to parse port number: " + portStr)
91
        }
92
        if port < 1 || port > 0xffff {
93
                return nil, errors.New("proxy: port number out of range: " + portStr)
94
        }
95
 
96
        // the size here is just an estimate
97
        buf := make([]byte, 0, 6+len(host))
98
 
99
        buf = append(buf, socks5Version)
100
        if len(s.user) > 0 && len(s.user) < 256 && len(s.password) < 256 {
101
                buf = append(buf, 2, /* num auth methods */ socks5AuthNone, socks5AuthPassword)
102
        } else {
103
                buf = append(buf, 1, /* num auth methods */ socks5AuthNone)
104
        }
105
 
106
        if _, err = conn.Write(buf); err != nil {
107
                return nil, errors.New("proxy: failed to write greeting to SOCKS5 proxy at " + s.addr + ": " + err.Error())
108
        }
109
 
110
        if _, err = io.ReadFull(conn, buf[:2]); err != nil {
111
                return nil, errors.New("proxy: failed to read greeting from SOCKS5 proxy at " + s.addr + ": " + err.Error())
112
        }
113
        if buf[0] != 5 {
114
                return nil, errors.New("proxy: SOCKS5 proxy at " + s.addr + " has unexpected version " + strconv.Itoa(int(buf[0])))
115
        }
116
        if buf[1] == 0xff {
117
                return nil, errors.New("proxy: SOCKS5 proxy at " + s.addr + " requires authentication")
118
        }
119
 
120
        if buf[1] == socks5AuthPassword {
121
                buf = buf[:0]
122
                buf = append(buf, socks5Version)
123
                buf = append(buf, uint8(len(s.user)))
124
                buf = append(buf, s.user...)
125
                buf = append(buf, uint8(len(s.password)))
126
                buf = append(buf, s.password...)
127
 
128
                if _, err = conn.Write(buf); err != nil {
129
                        return nil, errors.New("proxy: failed to write authentication request to SOCKS5 proxy at " + s.addr + ": " + err.Error())
130
                }
131
 
132
                if _, err = io.ReadFull(conn, buf[:2]); err != nil {
133
                        return nil, errors.New("proxy: failed to read authentication reply from SOCKS5 proxy at " + s.addr + ": " + err.Error())
134
                }
135
 
136
                if buf[1] != 0 {
137
                        return nil, errors.New("proxy: SOCKS5 proxy at " + s.addr + " rejected username/password")
138
                }
139
        }
140
 
141
        buf = buf[:0]
142
        buf = append(buf, socks5Version, socks5Connect, 0 /* reserved */ )
143
 
144
        if ip := net.ParseIP(host); ip != nil {
145
                if len(ip) == 4 {
146
                        buf = append(buf, socks5IP4)
147
                } else {
148
                        buf = append(buf, socks5IP6)
149
                }
150
                buf = append(buf, []byte(ip)...)
151
        } else {
152
                buf = append(buf, socks5Domain)
153
                buf = append(buf, byte(len(host)))
154
                buf = append(buf, host...)
155
        }
156
        buf = append(buf, byte(port>>8), byte(port))
157
 
158
        if _, err = conn.Write(buf); err != nil {
159
                return nil, errors.New("proxy: failed to write connect request to SOCKS5 proxy at " + s.addr + ": " + err.Error())
160
        }
161
 
162
        if _, err = io.ReadFull(conn, buf[:4]); err != nil {
163
                return nil, errors.New("proxy: failed to read connect reply from SOCKS5 proxy at " + s.addr + ": " + err.Error())
164
        }
165
 
166
        failure := "unknown error"
167
        if int(buf[1]) < len(socks5Errors) {
168
                failure = socks5Errors[buf[1]]
169
        }
170
 
171
        if len(failure) > 0 {
172
                return nil, errors.New("proxy: SOCKS5 proxy at " + s.addr + " failed to connect: " + failure)
173
        }
174
 
175
        bytesToDiscard := 0
176
        switch buf[3] {
177
        case socks5IP4:
178
                bytesToDiscard = 4
179
        case socks5IP6:
180
                bytesToDiscard = 16
181
        case socks5Domain:
182
                _, err := io.ReadFull(conn, buf[:1])
183
                if err != nil {
184
                        return nil, errors.New("proxy: failed to read domain length from SOCKS5 proxy at " + s.addr + ": " + err.Error())
185
                }
186
                bytesToDiscard = int(buf[0])
187
        default:
188
                return nil, errors.New("proxy: got unknown address type " + strconv.Itoa(int(buf[3])) + " from SOCKS5 proxy at " + s.addr)
189
        }
190
 
191
        if cap(buf) < bytesToDiscard {
192
                buf = make([]byte, bytesToDiscard)
193
        } else {
194
                buf = buf[:bytesToDiscard]
195
        }
196
        if _, err = io.ReadFull(conn, buf); err != nil {
197
                return nil, errors.New("proxy: failed to read address from SOCKS5 proxy at " + s.addr + ": " + err.Error())
198
        }
199
 
200
        // Also need to discard the port number
201
        if _, err = io.ReadFull(conn, buf[:2]); err != nil {
202
                return nil, errors.New("proxy: failed to read port from SOCKS5 proxy at " + s.addr + ": " + err.Error())
203
        }
204
 
205
        closeConn = nil
206
        return conn, nil
207
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.