~amsn-daily/amsn/amsn-packaging

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
##############################################################################
# Socks5 Client Library v1.1
#     (C)2000 Kerem 'Waster_' HADIMLI
#
# How to use:
#   1) Create your socket connected to the Socks server.
#   2) Call socks:init procedure with these 6 parameters:
#        1- Socket ID : The socket identifier that's connected to the socks5 server.
#        2- Server hostname : The main (not socks) server you want to connect
#        3- Server port : The port you want to connect on the main server
#        4- Authentication : If you want username/password authentication enabled, set this to 1, otherwise 0.
#        5- Username : Username to use on Socks Server if authentication is enabled. NULL if authentication is not enabled.
#        6- Password : Password to use on Socks Server if authentication is enabled. NULL if authentication is not enabled.
#   3) It'll return you a string starting with:
#        a- "OK" if successful, now you can send/receive any data from the socket.
#        b- "ERROR:$explanation" if unsuccessful, $explanation is the explanation like "Host not found". The socket will be automatically closed on an error.
#
#
# Notes:
#   - This library enters tkwait ::Socks5::loop (see Tk man pages), and returns only
#     when SOCKS initialization is complete.
#   - This library uses a global array: socks_idlist. Make sure your program
#     doesn't use that.
#   - NEVER use file IDs instead of socket IDs!
#   - NEVER bind the socket (fileevent) before calling socks:init procedure.
##############################################################################
#
# Author contact information:
#   E-mail :  waster@iname.com
#   ICQ#   :  27216346
#   Jabber :  waster@jabber.org   (New IM System - http://www.jabber.org)
#
##############################################################################
# $Id$
#set socks_idlist(stat,$sck) ...
#set socks_idlist(data,$sck) ...

namespace eval ::Socks5 {

	proc Init {sck addr port auth user pass} {
		variable socks_idlist
		
		#  if { [catch {fconfigure $sck}] != 0 } {return "ERROR:Connection closed with Socks Server!"}    ;# Socket doesn't exist
		
		set ver "\x05"               ;#Socks version
		
		status_log "SOCKS : $sck    $addr\n"
		set addr [split $addr " "]   ;# Remove port from address
		set addr [lindex $addr 0]
		status_log "SOCKS : $addr\n"
		
		if {$auth==0} {
			set method "\x00"
			set nmethods "\x01"
		} elseif {$auth==1} {
			set method "\x00\x02"
			set nmethods "\x02"
		} else {
			status_log "ERROR: $auth"
			return "ERROR:"
		}
		set nomatchingmethod "\xFF"  ;#No matching methods
		
		set cmd_connect "\x01"  ;#Connect command
		set rsv "\x00"          ;#Reserved
		set atyp "\x03"         ;#Address Type (domain)
		set dlen "[binary format c [string length $addr]]" ;#Domain length (binary 1 byte)
		set port [binary format S $port] ;#Network byte-ordered port (2 binary-bytes)
		
		set authver "\x01"  ;#User/Pass auth. version
		set ulen "[binary format c [string length $user]]"  ;#Username length (binary 1 byte)
		set plen "[binary format c [string length $pass]]"  ;#Password length (binary 1 byte)
		
		set a ""
		
		set socks_idlist(stat,$sck) 0
		set socks_idlist(data,$sck) ""
		
		status_log "doing fconfigure now in socks5\n"	
		fconfigure $sck -translation {binary binary} -blocking 0
		
		status_log "writing to socket in socks5 writing : $ver$nmethods$method\n"
		puts -nonewline $sck "$ver$nmethods$method"
		
		if { [catch { flush $sck }] } {
		    catch {close $sck}
		    status_log "ERROR:Couldn't flush Socks Server after writing!"
		    return "ERROR:Couldn't flush Socks Server after writing!"
		}
		
		status_log "doing fileevent now in socks5\n"
		fileevent $sck readable "::Socks5::Readable $sck"

		status_log "going into tkwait\n"
		tkwait variable ::Socks5::socks_idlist(stat,$sck)
		set a $socks_idlist(data,$sck)
		if {[eof $sck]} {
			catch {close $sck}
			status_log "ERROR:Connection closed with Socks Server!"
			return "ERROR:Connection closed with Socks Server!"
		}
		
		set serv_ver ""
		set method $nomatchingmethod
		
		binary scan $a "cc" serv_ver smethod
		
		if {$serv_ver!=5} {
			catch {close $sck}
			status_log "ERROR:Socks Server isn't version 5!"
			return "ERROR:Socks Server isn't version 5!"
		}
		
		if {$smethod==0} {
		} elseif {$smethod==2} {  ;#User/Pass authorization required
			if {$auth==0} {
				catch {close $sck}
				status_log "ERROR:Method not supported by Socks Server!"
				return "ERROR:Method not supported by Socks Server!"
			}
			    
			puts -nonewline $sck "$authver$ulen$user$plen$pass"
			flush $sck
			
			tkwait variable ::Socks5::socks_idlist(stat,$sck)
			set a $socks_idlist(data,$sck)
			if {[eof $sck]} {
				catch {close $sck}
				status_log "ERROR:Connection closed with Socks Server!"
				return "ERROR:Connection closed with Socks Server!"
			}
			
			set auth_ver ""
			set status "\x00"
			binary scan $a "cc" auth_ver status
			
			if {$auth_ver!=1} {
				catch {close $sck} 
				status_log "ERROR:Socks Server's authentication isn't supported!"
				return "ERROR:Socks Server's authentication isn't supported!"
			}
			if {$status!=0} {
				catch {close $sck}
				status_log "ERROR:Wrong username or password!"
				return "ERROR:Wrong username or password!"
			}
			
		} else {
			fileevent $sck readable {}
			unset socks_idlist(stat,$sck)
			unset socks_idlist(data,$sck)
			catch {close $sck}
			status_log "ERROR:Method not supported by Socks Server!"
			return "ERROR:Method not supported by Socks Server!"
		}
		
		#
		# We send request4connect
		#
		
		status_log "second write\n"
		puts -nonewline $sck "$ver$cmd_connect$rsv$atyp$dlen$addr$port"
		flush $sck
		
		tkwait variable ::Socks5::socks_idlist(stat,$sck)
		set a $socks_idlist(data,$sck)
		if {[eof $sck]} {
			catch {close $sck}
			status_log "ERROR:Connection closed with Socks Server!"
			return "ERROR:Connection closed with Socks Server!"
		}
		
		fileevent $sck readable {}
		unset socks_idlist(stat,$sck)
		unset socks_idlist(data,$sck)
		
		set serv_ver ""
		set rep ""
		binary scan $a cc serv_ver rep
		if {$serv_ver!=5} {
			catch {close $sck}
			status_log "ERROR:Socks Server isn't version 5!"
			return "ERROR:Socks Server isn't version 5!"
		}

		if {$rep==0} {
			fconfigure $sck -translation {auto auto}
			status_log "SOCKS: OK"
			return "OK"
		} elseif {$rep==1} {
			catch {close $sck}
			status_log "ERROR:Socks server responded:\nGeneral SOCKS server failure"
			return "ERROR:Socks server responded:\nGeneral SOCKS server failure"
		} elseif {$rep==2} {
			catch {close $sck}
			status_log "ERROR:Socks server responded:\nConnection not allowed by ruleset"
			return "ERROR:Socks server responded:\nConnection not allowed by ruleset"
		} elseif {$rep==3} {
			catch {close $sck}
			status_log "ERROR:Socks server responded:\nNetwork unreachable"
			return "ERROR:Socks server responded:\nNetwork unreachable"
		} elseif {$rep==4} {
			catch {close $sck}
			status_log "ERROR:Socks server responded:\nHost unreachable"
			return "ERROR:Socks server responded:\nHost unreachable"
		} elseif {$rep==5} {
			catch {close $sck}
			status_log "ERROR:Socks server responded:\nConnection refused"
			return "ERROR:Socks server responded:\nConnection refused"
		} elseif {$rep==6} {
			catch {close $sck}
			status_log "ERROR:Socks server responded:\nTTL expired"
			return "ERROR:Socks server responded:\nTTL expired"
		} elseif {$rep==7} {
			catch {close $sck}
			status_log "ERROR:Socks server responded:\nCommand not supported"
			return "ERROR:Socks server responded:\nCommand not supported"
		} elseif {$rep==8} {
			catch {close $sck}
			status_log "ERROR:Socks server responded:\nAddress type not supported"
			return "ERROR:Socks server responded:\nAddress type not supported"
		} else {
			catch {close $sck}
			status_log "ERROR:Socks server responded:\nUnknown Error"
			return "ERROR:Socks server responded:\nUnknown Error"
		}


		status_log "finished sock5 init"
	}

	#
	# Change the variable value, so 'tkwait' loop will end in socks:init procedure.
	#
	proc Readable {sck} {
		variable socks_idlist

		if { [catch {set socks_idlist(data,$sck) [read $sck]} res] } {
			status_log "Error when reading from sock server : $res"
		}

		incr socks_idlist(stat,$sck)
	}
}