/[cvs]/eggdrop1.9/testcode/socks5.c
ViewVC logotype

Contents of /eggdrop1.9/testcode/socks5.c

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.1 - (show annotations) (download) (as text)
Thu Apr 25 04:19:54 2002 UTC (17 years, 11 months ago) by stdarg
Branch: MAIN
File MIME type: text/x-chdr
* sclient.c - test program to telnet using a proxy
* http.c/base64.c - http anonymous and authenticated proxies
* socks5.c - socks5 proxy with support for username/password authentication, ipv4, ipv6, and remote hostname resolution
* socks4.c socks4 proxy (no authentication)

1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <errno.h>
5 #include <netinet/in.h>
6 #include "my_socket.h"
7 #include "sockbuf.h"
8
9 typedef struct {
10 char *host;
11 int port;
12 char *username;
13 char *password;
14 int status;
15 int our_idx, their_idx;
16 int sock;
17 } proxy_info_t;
18
19 static int socks5_on_read(int idx, sockbuf_iobuf_t *data, proxy_info_t *info);
20 static int socks5_on_eof_and_err(int idx, void *err, proxy_info_t *info);
21 static int socks5_on_connect(int idx, void *ignore, proxy_info_t *info);
22
23 sockbuf_event_t socks5_events = {
24 (Function) 5,
25 (Function) "socks5 proxy",
26 socks5_on_read,
27 NULL,
28 socks5_on_eof_and_err,
29 socks5_on_eof_and_err,
30 socks5_on_connect
31 };
32
33 static void socks5_free(proxy_info_t *info)
34 {
35 free(info->host);
36 free(info->username);
37 free(info->password);
38 sockbuf_delete(info->our_idx);
39 free(info);
40 }
41
42 /* When there's an error on our idx, we shut down and notify the other idx. */
43 /* All errors are non-recoverable. */
44 static void socks5_err(proxy_info_t *info, int err)
45 {
46 errno = err;
47 sockbuf_filter(info->their_idx, SOCKBUF_ERR, -1, (void *)err);
48 socks5_free(info);
49 }
50
51 /* This sends the connection request once we've authenticated. It calculates
52 what address type we're dealing with (ipv4, ipv6, domain name) and
53 sends the necessary CONNECT request. */
54 static void send_connect_request(proxy_info_t *info)
55 {
56 char buf[512];
57 int len;
58 unsigned short port;
59 struct sockaddr_in addr;
60 struct sockaddr_in6 addr6;
61
62 /* VER CMD RESERVED */
63 buf[0] = 5; buf[1] = 1; buf[2] = 0;
64
65 /* Try a regular ipv4 address first. */
66 if (inet_pton(AF_INET, info->host, &addr) > 0) {
67 buf[3] = 1;
68 memcpy(buf+4, &addr.sin_addr, 4);
69 len = 8;
70 }
71 else if (inet_pton(AF_INET6, info->host, &addr6) > 0) {
72 buf[3] = 4;
73 memcpy(buf+4, &addr6.sin6_addr, 16);
74 len = 20;
75 }
76 else {
77 buf[3] = 3;
78 len = strlen(info->host);
79 buf[4] = len;
80 memcpy(buf+5, info->host, len);
81 len += 5;
82 }
83
84 port = htons(info->port);
85 memcpy(buf+len, &port, 2);
86 len += 2;
87
88 sockbuf_write(info->our_idx, buf, len);
89 }
90
91 /* This parses the server's auth method reply. Basically, when we connect
92 we send the server a list of authentication methods we support. Then
93 the server picks one and sends it back. This procedure identifies
94 which one was chosen, and then sends the proper login sequence. */
95 static void socks5_auth_method(sockbuf_iobuf_t *data, proxy_info_t *info)
96 {
97 char buf[520];
98
99 /* If it's a bad reply, abort. */
100 if (data->len < 2) {
101 socks5_err(info, ECONNABORTED);
102 return;
103 }
104
105 if ((int) data->data[1] == 0) {
106 /* No auth required. */
107 send_connect_request(info);
108 info->status = 3;
109 }
110 else if ((int) data->data[1] == 2) {
111 /* User/password authentication */
112 int ulen, plen;
113 char buf[520];
114
115 /* Username and password can be 255 max. */
116 ulen = strlen(info->username) % 255;
117 plen = strlen(info->password) % 255;
118
119 buf[0] = 5;
120 buf[1] = ulen;
121 memcpy(buf+2, info->username, ulen);
122 buf[2+ulen] = plen;
123 memcpy(buf+2+ulen+1, info->password, plen);
124 sockbuf_write(info->our_idx, buf, 1+1+ulen+1+plen);
125 info->status = 2;
126 }
127 else {
128 /* We can't authenticate with this server, boo. */
129 socks5_err(info, ECONNABORTED);
130 }
131 return;
132 }
133
134 /* After we send our login information, the server respons with a status code
135 to say whether it succeeded or not. */
136 static void socks5_auth_reply(sockbuf_iobuf_t *data, proxy_info_t *info)
137 {
138 /* Abort if it's an invalid reply. */
139 if (data->len < 2) {
140 socks5_err(info, ECONNABORTED);
141 return;
142 }
143
144 if (data->data[1] != 0) {
145 /* Authentication failed! */
146 socks5_err(info, ECONNREFUSED);
147 }
148 else {
149 /* Send the connection request. */
150 send_connect_request(info);
151 info->status = 3;
152 }
153 }
154
155 /* After we send our CONNECT command, the server tries to make the connection.
156 When it makes the connection, or fails for some reason, it sends back
157 a status code, which we parse here. If the code is successful, then
158 we issue a CONNECT event on the original idx. */
159 static void socks5_connect_reply(sockbuf_iobuf_t *data, proxy_info_t *info)
160 {
161 /* Abort if it's an invalid reply or the connection failed. */
162 /* It's actually supposed to be more than 2 bytes, but we only care
163 about the 2nd field (status). */
164
165 /* Here are the reply field definitions (from rfc1928)
166 0 - success
167 1 - general SOCKS server failure
168 2 - connection not allowed by ruleset
169 3 - network unreachable
170 4 - host unreachable
171 5 - connection refused
172 6 - ttl expired
173 7 - command not supported
174 8 - address type not supported
175 */
176 if (data->len < 2 || data->data[1] != 0) {
177 int err;
178
179 if (data->len < 2) err = ECONNABORTED;
180 else switch (data->data[1]) {
181 case 1: err = ECONNABORTED; break;
182 case 3: err = ENETUNREACH; break;
183 case 4: err = EHOSTUNREACH; break;
184 case 6: err = ETIMEDOUT; break;
185 default: err = ECONNREFUSED;
186 }
187 socks5_err(info, err);
188 return;
189 }
190
191 /* We're connected! Simulate a CONNECT event for the other idx. */
192 sockbuf_set_sock(info->our_idx, -1, 0);
193 sockbuf_set_sock(info->their_idx, info->sock, SOCKBUF_CLIENT);
194 socks5_free(info);
195 return;
196 }
197
198 /* When we get data from the server, this procedure redirects it to the
199 appropriate handler, based on the status field of the idx. */
200 static int socks5_on_read(int idx, sockbuf_iobuf_t *data, proxy_info_t *info)
201 {
202 /* printf("read %d bytes (status %d)\n", data->len, info->status); */
203 switch (info->status) {
204 case 1:
205 socks5_auth_method(data, info);
206 break;
207 case 2:
208 socks5_auth_reply(data, info);
209 break;
210 case 3:
211 socks5_connect_reply(data, info);
212 break;
213 }
214 return(0);
215 }
216
217 /* When there's an error or eof on the server's idx, we issue an error on
218 the original idx. */
219 static int socks5_on_eof_and_err(int idx, void *err, proxy_info_t *info)
220 {
221 if (!err) err = (void *)ECONNREFUSED;
222 socks5_err(info, (int) err);
223 return(0);
224 }
225
226 /* When we establish a connection to the server, we have to send it a list of
227 authentication methods we support. Then it chooses one and sends back
228 a request to use that method. Right now we support "none" (duh) and
229 "user/pass". */
230 static int socks5_on_connect(int idx, void *ignore, proxy_info_t *info)
231 {
232 char buf[] = "\005\002\001\000";
233
234 /* Send the accepted auth methods (user/pass and none). */
235 sockbuf_write(idx, buf, 4);
236 info->status = 1;
237 return(0);
238 }
239
240 /* To establish a SOCKS5 connection, we create 2 idx's: one for the caller, and
241 one that we use to connect to the server. */
242 int socks5_connect(int idx, char *proxy_host, int proxy_port, char *username, char *password, char *dest_host, int dest_port)
243 {
244 int sock;
245 proxy_info_t *info;
246
247 sock = socket_create(proxy_host, proxy_port, NULL, 0, SOCKET_CLIENT|SOCKET_TCP|SOCKET_NONBLOCK);
248 if (sock < 0) return(-1);
249
250 info = (proxy_info_t *)malloc(sizeof(*info));
251 info->host = strdup(dest_host);
252 info->port = dest_port;
253 if (!username) username = "";
254 if (!password) password = "";
255 info->username = strdup(username);
256 info->password = strdup(password);
257 info->status = 0;
258
259 info->our_idx = sockbuf_new(sock, SOCKBUF_CLIENT);
260 if (idx >= 0) info->their_idx = idx;
261 else info->their_idx = sockbuf_new(-1, 0);
262
263 info->sock = sock;
264
265 sockbuf_set_handler(info->our_idx, socks5_events, info);
266
267 return(info->their_idx);
268 }

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23