/[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.3 - (show annotations) (download) (as text)
Fri Sep 20 02:06:25 2002 UTC (16 years, 6 months ago) by stdarg
Branch: MAIN
CVS Tags: HEAD
Changes since 1.2: +2 -2 lines
File MIME type: text/x-chdr
* Moved several things from the core into libegg
* Server module uses new network code
* Lots of stuff removed from the server module, like flood stuff, which should go into a new module
* Moved some things from irc module to server module (mostly bind stuff, like pub)
* Not everything works right now, but I wanted to get it into cvs in case my computer dies a horrible death. I'm going to combine irc/server (mostly) and make a new one for all the default protection stuff.
* Right now server messages are not queued. I thought the code was pretty much beyond repair. The new queueing code will hopefully be more maintainable.
* I'm not sure I added/removed all the files necessary! Let me know if it doesn't compile for you.

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

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23