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

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

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


Revision 1.2 - (hide annotations) (download) (as text)
Wed Jun 19 04:51:54 2002 UTC (17 years, 9 months ago) by stdarg
Branch: MAIN
Changes since 1.1: +64 -51 lines
File MIME type: text/x-chdr
* I think the sockbuf api is almost done

1 stdarg 1.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 stdarg 1.2 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 stdarg 1.1 };
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 stdarg 1.2 static void socks5_err(proxy_info_t *info, int err, const char *errmsg)
41 stdarg 1.1 {
42     errno = err;
43 stdarg 1.2 sockbuf_on_eof(info->their_idx, SOCKBUF_LEVEL_INTERNAL, err, errmsg);
44 stdarg 1.1 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 stdarg 1.2 len = strlen(info->host) % 255;
75 stdarg 1.1 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 stdarg 1.2 static void socks5_auth_method(char *data, int len, proxy_info_t *info)
92 stdarg 1.1 {
93     char buf[520];
94    
95     /* If it's a bad reply, abort. */
96 stdarg 1.2 if (len < 2) {
97     socks5_err(info, ECONNABORTED, "Invalid reply from SOCKS5 server");
98 stdarg 1.1 return;
99     }
100    
101 stdarg 1.2 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 stdarg 1.1 /* No auth required. */
108     send_connect_request(info);
109     info->status = 3;
110     }
111 stdarg 1.2 else if (data[1] == 2) {
112 stdarg 1.1 /* 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] = 5;
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 stdarg 1.2 socks5_err(info, ECONNABORTED, "SOCKS5 server doesn't accept our methods of authentication");
131 stdarg 1.1 }
132     return;
133     }
134    
135 stdarg 1.2 /* After we send our login information, the server responds with a status code
136 stdarg 1.1 to say whether it succeeded or not. */
137 stdarg 1.2 static void socks5_auth_reply(char *data, int len, proxy_info_t *info)
138 stdarg 1.1 {
139     /* Abort if it's an invalid reply. */
140 stdarg 1.2 if (len < 2) {
141     socks5_err(info, ECONNABORTED, "Invalid reply from SOCKS5 server");
142 stdarg 1.1 return;
143     }
144    
145 stdarg 1.2 if (data[1] != 0) {
146 stdarg 1.1 /* Authentication failed! */
147 stdarg 1.2 socks5_err(info, ECONNREFUSED, "SOCKS5 authentication failed");
148 stdarg 1.1 }
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 stdarg 1.2 static void socks5_connect_reply(char *data, int len, proxy_info_t *info)
161 stdarg 1.1 {
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 stdarg 1.2 if (len < 2 || data[1] != 0) {
178     char *errmsg;
179 stdarg 1.1
180 stdarg 1.2 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 stdarg 1.1 }
192 stdarg 1.2 socks5_err(info, ECONNABORTED, errmsg);
193 stdarg 1.1 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 stdarg 1.2 sockbuf_set_sock(info->their_idx, info->sock, 0);
199     sockbuf_on_connect(info->their_idx, SOCKBUF_LEVEL_INTERNAL, info->host, info->port);
200 stdarg 1.1 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 stdarg 1.2 static int socks5_on_read(void *client_data, int idx, char *data, int len)
207 stdarg 1.1 {
208 stdarg 1.2 proxy_info_t *info = client_data;
209    
210     printf("read from socks5\n");
211 stdarg 1.1 switch (info->status) {
212     case 1:
213 stdarg 1.2 socks5_auth_method(data, len, info);
214 stdarg 1.1 break;
215     case 2:
216 stdarg 1.2 socks5_auth_reply(data, len, info);
217 stdarg 1.1 break;
218     case 3:
219 stdarg 1.2 socks5_connect_reply(data, len, info);
220 stdarg 1.1 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 stdarg 1.2 static int socks5_on_eof(void *client_data, int idx, int err, const char *errmsg)
228 stdarg 1.1 {
229 stdarg 1.2 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 stdarg 1.1 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 stdarg 1.2 static int socks5_on_connect(void *client_data, int idx, const char *peer_ip, int peer_port)
241 stdarg 1.1 {
242 stdarg 1.2 proxy_info_t *info = client_data;
243 stdarg 1.1 char buf[] = "\005\002\001\000";
244    
245 stdarg 1.2 printf("socks5 connected\n");
246 stdarg 1.1 /* 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 stdarg 1.2 info->our_idx = sockbuf_new();
272     sockbuf_set_sock(info->our_idx, sock, SOCKBUF_CLIENT);
273 stdarg 1.1 if (idx >= 0) info->their_idx = idx;
274 stdarg 1.2 else info->their_idx = sockbuf_new();
275 stdarg 1.1
276     info->sock = sock;
277    
278 stdarg 1.2 sockbuf_set_handler(info->our_idx, &socks5_events, info);
279 stdarg 1.1
280     return(info->their_idx);
281     }

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23