00001 #include <eggdrop/eggdrop.h>
00002 #include <errno.h>
00003 #include <netinet/in.h>
00004 #include "proxy.h"
00005
00006 extern proxy_config_t proxy_config;
00007
00008 typedef struct {
00009 char *host;
00010 int port;
00011 char *username;
00012 char *password;
00013 int status;
00014 int our_idx, their_idx;
00015 } proxy_info_t;
00016
00017 static int socks5_on_read(void *client_data, int idx, char *data, int len);
00018 static int socks5_on_eof(void *client_data, int idx, int err, const char *errmsg);
00019 static int socks5_on_connect(void *client_data, int idx, const char *peer_ip, int peer_port);
00020 static int socks5_on_delete(event_owner_t *owner, void *client_data);
00021
00022 static int socks5_on_their_eof(void *client_data, int idx, int err, const char *errmsg);
00023 static int socks5_on_their_delete(void *client_data, int idx);
00024
00025 event_owner_t socks5_owner = {
00026 "proxy", NULL,
00027 NULL, NULL,
00028 socks5_on_delete
00029 };
00030
00031 static sockbuf_handler_t socks5_events = {
00032 "socks5 proxy",
00033 socks5_on_connect, socks5_on_eof, NULL,
00034 socks5_on_read, NULL
00035 };
00036
00037 static sockbuf_filter_t delete_listener = {
00038 "socks5 proxy",
00039 SOCKBUF_LEVEL_PROXY,
00040 NULL, socks5_on_their_eof, NULL,
00041 NULL, NULL, NULL,
00042 NULL, socks5_on_their_delete
00043 };
00044
00045
00046
00047 static void socks5_err(proxy_info_t *info, int err, const char *errmsg)
00048 {
00049
00050 sockbuf_detach_filter(info->their_idx, &delete_listener, NULL);
00051 errno = err;
00052 sockbuf_on_eof(info->their_idx, SOCKBUF_LEVEL_INTERNAL, err, errmsg);
00053 info->their_idx = -1;
00054 sockbuf_delete(info->our_idx);
00055 }
00056
00057
00058
00059
00060 static void send_connect_request(proxy_info_t *info)
00061 {
00062 char buf[512];
00063 int len;
00064 unsigned short port;
00065 struct sockaddr_in addr;
00066 #ifdef IPV6
00067 struct sockaddr_in6 addr6;
00068 #endif
00069
00070
00071 buf[0] = 5; buf[1] = 1; buf[2] = 0;
00072
00073
00074
00075 if (inet_pton(AF_INET, info->host, &addr) > 0) {
00076 buf[3] = 1;
00077 memcpy(buf+4, &addr.sin_addr, 4);
00078 len = 8;
00079 }
00080 #ifdef IPV6
00081 else if (inet_pton(AF_INET6, info->host, &addr6) > 0) {
00082 buf[3] = 4;
00083 memcpy(buf+4, &addr6.sin6_addr, 16);
00084 len = 20;
00085 }
00086 #endif
00087 else {
00088 buf[3] = 3;
00089 len = strlen(info->host) % 255;
00090 buf[4] = len;
00091 memcpy(buf+5, info->host, len);
00092 len += 5;
00093 }
00094
00095 port = htons(info->port);
00096 memcpy(buf+len, &port, 2);
00097 len += 2;
00098
00099 sockbuf_write(info->our_idx, buf, len);
00100 }
00101
00102
00103
00104
00105
00106 static void socks5_auth_method(char *data, int len, proxy_info_t *info)
00107 {
00108
00109 if (len < 2) {
00110 socks5_err(info, ECONNABORTED, "Invalid reply from SOCKS5 server");
00111 return;
00112 }
00113
00114 if (data[0] != 5) {
00115 socks5_err(info, ECONNABORTED, "SOCKS5 server replied with SOCKS4 protocol");
00116 return;
00117 }
00118
00119 if (data[1] == 0) {
00120
00121 send_connect_request(info);
00122 info->status = 3;
00123 }
00124 else if (data[1] == 2) {
00125
00126 int ulen, plen;
00127 char buf[520];
00128
00129
00130 if (info->username) ulen = strlen(info->username) % 255;
00131 else ulen = 0;
00132 if (info->password) plen = strlen(info->password) % 255;
00133 else plen = 0;
00134
00135 buf[0] = 1;
00136 buf[1] = ulen;
00137 memcpy(buf+2, info->username, ulen);
00138 buf[2+ulen] = plen;
00139 memcpy(buf+2+ulen+1, info->password, plen);
00140 sockbuf_write(info->our_idx, buf, 1+1+ulen+1+plen);
00141 info->status = 2;
00142 }
00143 else {
00144
00145 socks5_err(info, ECONNABORTED, "SOCKS5 server doesn't accept our methods of authentication");
00146 }
00147 return;
00148 }
00149
00150
00151
00152 static void socks5_auth_reply(char *data, int len, proxy_info_t *info)
00153 {
00154
00155 if (len < 2) {
00156 socks5_err(info, ECONNABORTED, "Invalid reply from SOCKS5 server");
00157 return;
00158 }
00159
00160 if (data[1] != 0) {
00161
00162 socks5_err(info, ECONNREFUSED, "SOCKS5 authentication failed");
00163 }
00164 else {
00165
00166 send_connect_request(info);
00167 info->status = 3;
00168 }
00169 }
00170
00171
00172
00173
00174
00175 static void socks5_connect_reply(char *data, int len, proxy_info_t *info)
00176 {
00177 int sock;
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194 if (len < 2 || data[1] != 0) {
00195 char *errmsg;
00196
00197 if (len < 2) errmsg = "Invalid reply from SOCKS5 server";
00198 else switch (data[1]) {
00199 case 1: errmsg = "SOCKS5 general server failure"; break;
00200 case 2: errmsg = "SOCKS5 connection now allowed by ruleset"; break;
00201 case 3: errmsg = "SOCKS5 network unreachable"; break;
00202 case 4: errmsg = "SOCKS5 host unreachable"; break;
00203 case 5: errmsg = "SOCKS5 connection refused"; break;
00204 case 6: errmsg = "SOCKS5 TTL expired"; break;
00205 case 7: errmsg = "SOCKS5 command not supported"; break;
00206 case 8: errmsg = "SOCKS5 address type not supported"; break;
00207 default: errmsg = "SOCKS5 unknown error";
00208 }
00209 socks5_err(info, ECONNABORTED, errmsg);
00210 return;
00211 }
00212
00213
00214
00215 sockbuf_detach_filter(info->their_idx, &delete_listener, NULL);
00216 sock = sockbuf_get_sock(info->our_idx);
00217 sockbuf_set_sock(info->our_idx, -1, 0);
00218 sockbuf_set_sock(info->their_idx, sock, 0);
00219 sockbuf_on_connect(info->their_idx, SOCKBUF_LEVEL_INTERNAL, info->host, info->port);
00220 info->their_idx = -1;
00221 sockbuf_delete(info->our_idx);
00222 return;
00223 }
00224
00225
00226
00227 static int socks5_on_read(void *client_data, int idx, char *data, int len)
00228 {
00229 proxy_info_t *info = client_data;
00230
00231
00232 switch (info->status) {
00233 case 1:
00234 socks5_auth_method(data, len, info);
00235 break;
00236 case 2:
00237 socks5_auth_reply(data, len, info);
00238 break;
00239 case 3:
00240 socks5_connect_reply(data, len, info);
00241 break;
00242 }
00243 return(0);
00244 }
00245
00246
00247
00248 static int socks5_on_eof(void *client_data, int idx, int err, const char *errmsg)
00249 {
00250 proxy_info_t *info = client_data;
00251 if (!err) err = ECONNREFUSED;
00252 if (!errmsg) errmsg = "Unexpected EOF from SOCKS5 server";
00253 socks5_err(info, err, errmsg);
00254 return(0);
00255 }
00256
00257
00258
00259 static int socks5_on_delete(event_owner_t *owner, void *client_data)
00260 {
00261 proxy_info_t *info = client_data;
00262
00263
00264 if (info->their_idx != -1) {
00265 int their_idx = info->their_idx;
00266 sockbuf_detach_filter(their_idx, &delete_listener, NULL);
00267 sockbuf_on_eof(their_idx, SOCKBUF_LEVEL_INTERNAL, ECONNREFUSED, "socks5 idx deleted unexpectedly!");
00268 }
00269 free(info->host);
00270 if (info->username) free(info->username);
00271 if (info->password) free(info->password);
00272 free(info);
00273 return(0);
00274 }
00275
00276
00277 static int socks5_on_their_delete(void *client_data, int idx)
00278 {
00279 proxy_info_t *info = client_data;
00280
00281 info->their_idx = -1;
00282 sockbuf_delete(info->our_idx);
00283 return(0);
00284 }
00285
00286
00287 static int socks5_on_their_eof(void *client_data, int idx, int err, const char *errmsg)
00288 {
00289 proxy_info_t *info = client_data;
00290
00291 info->their_idx = -1;
00292 sockbuf_delete(info->our_idx);
00293 return(0);
00294 }
00295
00296
00297
00298
00299
00300 static int socks5_on_connect(void *client_data, int idx, const char *peer_ip, int peer_port)
00301 {
00302 proxy_info_t *info = client_data;
00303 char both[] = "\005\002\002\000";
00304 char anon[] = "\005\001\000";
00305
00306
00307
00308 if (info->username && info->password) sockbuf_write(idx, both, 4);
00309 else sockbuf_write(idx, anon, 3);
00310 info->status = 1;
00311 return(0);
00312 }
00313
00314 int socks5_reconnect(int idx, const char *host, int port)
00315 {
00316 proxy_info_t *info;
00317 int our_idx;
00318
00319 if (!proxy_config.host) return(-1);
00320
00321 our_idx = egg_client(-1, proxy_config.host, proxy_config.port, NULL, 0, -1);
00322
00323 if (our_idx < 0) return(-1);
00324
00325 info = (proxy_info_t *)calloc(1, sizeof(*info));
00326 info->host = strdup(host);
00327 info->port = port;
00328 str_redup(&info->username, proxy_config.username);
00329 str_redup(&info->password, proxy_config.password);
00330 info->status = 0;
00331
00332 info->our_idx = our_idx;
00333 if (idx >= 0) info->their_idx = idx;
00334 else info->their_idx = sockbuf_new();
00335
00336 sockbuf_set_handler(info->our_idx, &socks5_events, info, &socks5_owner);
00337 sockbuf_attach_filter(info->their_idx, &delete_listener, info);
00338
00339 return(info->their_idx);
00340 }