00001 #include <eggdrop/eggdrop.h>
00002 #include <errno.h>
00003 #include <netinet/in.h>
00004 #include "proxy.h"
00005
00006 typedef struct {
00007 char *http_host;
00008 char *host;
00009 int port;
00010 char *username;
00011 char *password;
00012 int our_idx, their_idx;
00013 int status;
00014 } proxy_info_t;
00015
00016 static int http_on_connect(void *client_data, int idx, const char *peer_ip, int peer_port);
00017 static int http_on_eof(void *client_data, int idx, int err, const char *errmsg);
00018 static int http_on_read(void *client_data, int idx, char *data, int len);
00019 static int http_on_delete(event_owner_t *owner, void *client_data);
00020 static int http_on_their_delete(void *client_data, int idx);
00021
00022 event_owner_t http_owner = {
00023 "proxy", NULL,
00024 NULL, NULL,
00025 http_on_delete
00026 };
00027
00028 static sockbuf_handler_t http_events = {
00029 "http proxy",
00030 http_on_connect, http_on_eof, NULL,
00031 http_on_read, NULL
00032 };
00033
00034 static sockbuf_filter_t delete_listener = {
00035 "http proxy",
00036 SOCKBUF_LEVEL_PROXY,
00037 NULL, NULL, NULL,
00038 NULL, NULL, NULL,
00039 NULL, http_on_their_delete
00040 };
00041
00042 static void http_err(proxy_info_t *info, int err, const char *errmsg)
00043 {
00044 int idx = info->their_idx;
00045 errno = err;
00046 sockbuf_delete(info->our_idx);
00047 sockbuf_on_eof(idx, SOCKBUF_LEVEL_INTERNAL, err, errmsg);
00048 }
00049
00050 static int http_on_delete(event_owner_t *owner, void *client_data)
00051 {
00052 proxy_info_t *info = client_data;
00053 sockbuf_detach_filter(info->their_idx, &delete_listener, info);
00054 if (info->host) free(info->host);
00055 if (info->username) free(info->username);
00056 if (info->password) free(info->password);
00057 free(info);
00058 return(0);
00059 }
00060
00061 static int http_on_read(void *client_data, int idx, char *data, int len)
00062 {
00063 proxy_info_t *info = client_data;
00064 int sock;
00065
00066 if (!strncasecmp("HTTP/1.0 200", data, 12)) {
00067
00068 info->status = 1;
00069 return(0);
00070 }
00071
00072 if (len != 0) {
00073
00074 return(0);
00075 }
00076
00077
00078
00079 if (info->status != 1) {
00080
00081 http_err(info, ECONNREFUSED, "HTTP server refused to relay connection");
00082 return(0);
00083 }
00084
00085
00086 sockbuf_detach_filter(info->their_idx, &delete_listener, info);
00087 sock = sockbuf_get_sock(info->our_idx);
00088 sockbuf_set_sock(info->our_idx, -1, 0);
00089 sockbuf_set_sock(info->their_idx, sock, 0);
00090 sockbuf_on_connect(info->their_idx, SOCKBUF_LEVEL_INTERNAL, info->host, info->port);
00091 info->their_idx = -1;
00092 sockbuf_delete(info->our_idx);
00093
00094 return(0);
00095 }
00096
00097 static int http_on_eof(void *client_data, int idx, int err, const char *errmsg)
00098 {
00099 proxy_info_t *info = client_data;
00100
00101 if (!err) err = ECONNREFUSED;
00102 http_err(info, err, "Unexpected EOF from HTTP server");
00103 return(0);
00104 }
00105
00106 static char *make_password(proxy_info_t *info)
00107 {
00108 char *buf, *dest;
00109 int len;
00110
00111 buf = egg_mprintf("%s %s", info->username, info->password);
00112 len = strlen(buf);
00113 dest = malloc(len * 4 + 1);
00114 b64enc_buf(buf, len, dest);
00115 free(buf);
00116 return(dest);
00117 }
00118
00119
00120
00121 static int http_on_connect(void *client_data, int idx, const char *peer_ip, int peer_port)
00122 {
00123 proxy_info_t *info = client_data;
00124
00125 egg_iprintf(idx, "CONNECT %s:%d HTTP/1.0\r\n", info->host, info->port);
00126 egg_iprintf(idx, "Host: %s\r\n", info->http_host);
00127 if (info->username && info->password && strlen(info->username)) {
00128 char *auth;
00129
00130 auth = make_password(info);
00131 egg_iprintf(idx, "Proxy-authenticate: basic %s\r\n", auth);
00132 free(auth);
00133 }
00134 egg_iprintf(idx, "\r\n");
00135
00136 return(0);
00137 }
00138
00139
00140 static int http_on_their_delete(void *client_data, int idx)
00141 {
00142 proxy_info_t *info = client_data;
00143 sockbuf_delete(info->our_idx);
00144 return(0);
00145 }
00146
00147 int http_reconnect(int idx, const char *host, int port)
00148 {
00149 int our_idx;
00150 proxy_info_t *info;
00151
00152 if (!proxy_config.host) return(-1);
00153
00154 our_idx = egg_client(-1, proxy_config.host, proxy_config.port, NULL, 0, -1);
00155 if (our_idx < 0) return(-1);
00156
00157
00158 info = (proxy_info_t *)calloc(1, sizeof(*info));
00159 info->host = strdup(host);
00160 info->port = port;
00161
00162
00163 info->http_host = strdup(proxy_config.host);
00164 if (proxy_config.username) info->username = strdup(proxy_config.username);
00165 if (proxy_config.password) info->password = strdup(proxy_config.password);
00166
00167 info->our_idx = our_idx;
00168 linemode_on(info->our_idx);
00169
00170 if (idx >= 0) info->their_idx = idx;
00171 else info->their_idx = sockbuf_new();
00172
00173 info->status = 0;
00174
00175 sockbuf_set_handler(info->our_idx, &http_events, info, &http_owner);
00176 sockbuf_attach_filter(info->their_idx, &delete_listener, info);
00177
00178 return(info->their_idx);
00179 }