From 47419298ef0f7f88ea8345726754a68ec66ad39d Mon Sep 17 00:00:00 2001 From: Enrico Scholz Date: Tue, 26 Feb 2008 17:57:14 +0100 Subject: [PATCH] PROXY/HTTP: added methods for HTTP proxies This patch adds code for connecting through HTTP proxies. Open issues are: * support of proxy authentication * a possible DOS due to the usage of g_io_channel_read_line_string() which does not allow to specify a maximum length of line. To use this method: * set 'proxy_type' to 'http' --- src/core/network-proxy-http.c | 193 ++++++++++++++++++++++++++++++++++ src/core/network-proxy-http.h | 29 +++++ 2 files changed, 222 insertions(+) create mode 100644 src/core/network-proxy-http.c create mode 100644 src/core/network-proxy-http.h diff --git a/src/core/network-proxy-http.c b/src/core/network-proxy-http.c new file mode 100644 index 00000000..3e79d784 --- /dev/null +++ b/src/core/network-proxy-http.c @@ -0,0 +1,193 @@ +/* --*- c -*-- + * Copyright (C) 2008 Enrico Scholz + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 and/or 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "module.h" +#include "network-proxy-http.h" + +#include +#include +#include +#include + +#include "network.h" +#include "network-proxy-priv.h" + +static void +network_proxy_http_destroy(struct network_proxy *proxy) +{ + struct _network_proxy_http *self = container_of(proxy, struct _network_proxy_http, proxy); + + g_free((void *)self->password); + _network_proxy_destroy(proxy); + + g_free(self); +} + +static struct network_proxy * +network_proxy_http_clone(struct network_proxy const *proxy) +{ + struct _network_proxy_http *self = container_of(proxy, struct _network_proxy_http, proxy); + struct _network_proxy_http *res; + + res = g_malloc0(sizeof *res); + + _network_proxy_clone(&res->proxy, &self->proxy); + res->password = g_strdup(self->password); + return &res->proxy; +} + +static bool +send_connect(struct _network_proxy_http *proxy, GIOChannel *ch, char const *address, uint16_t port) +{ + char port_str[6]; + + (void)proxy; + sprintf(port_str, "%u", port); + + if (!_network_proxy_send_all(ch, "CONNECT ", -1) || + !_network_proxy_send_all(ch, address, -1) || + !_network_proxy_send_all(ch, ":", -1) || + !_network_proxy_send_all(ch, port_str, -1) || + !_network_proxy_send_all(ch, " HTTP/1.0\r\n\r\n", -1) || + !_network_proxy_flush(ch)) + return -1; + + return true; +} + +static int +read_response(struct _network_proxy_http *proxy, GIOChannel *ch) +{ + GIOStatus status; + GString line = { .str = NULL }; + gsize term_pos; + GError *err = NULL; + int state = 0; + int rc = 0; + gchar *resp = NULL; + + (void)proxy; + for (;;) { + /* TODO: a malicious proxy can DOS us by sending much data + * without a line break */ + while ((status=g_io_channel_read_line_string(ch, &line, &term_pos, + &err))==G_IO_STATUS_AGAIN) + { + /* noop */ + } + + if (status!=G_IO_STATUS_NORMAL) { + g_warning("failed to read HTTP response: %s", err->message); + goto err; + } + + if (state==0) { + if (g_str_has_prefix(line.str, "HTTP/1.0 ")) { + resp = g_strndup(line.str+9, line.len-9-2); + rc = g_ascii_strtoull(resp, NULL, 10); + } else { + g_warning("unexpected HTTP response: '%s'", line.str); + goto err; + } + + /* state=1 ... read additional response headers + * (ignored for now) */ + state=1; + } + + if (line.len==2) /* only the \r\n terminators */ + break; + } + + if (rc!=200) + g_warning("unexpected HTTP response code: %s", resp); + + g_free(resp); + g_free(line.str); + return rc; + +err: + g_free(resp); + g_free(line.str); + return -1; +} + +static GIOChannel * +network_proxy_http_connect(struct network_proxy const *proxy, IPADDR const *hint_ip, + char const *address, int port) +{ + struct _network_proxy_http *self = container_of(proxy, struct _network_proxy_http, proxy); + GIOChannel *ch; + GIOFlags old_flags; + GError *err = NULL; + gchar const *line_term; + gint line_term_sz; + + if (hint_ip) + ch = net_connect_ip(hint_ip, self->proxy.port, NULL); + else + ch = net_connect(self->proxy.host, self->proxy.port, NULL); + + if (!ch) + return NULL; + + /* set \r\n line delims */ + line_term = g_io_channel_get_line_term(ch, &line_term_sz); + g_io_channel_set_line_term(ch, "\r\n", 2); + + /* set to non-blocking */ + old_flags = g_io_channel_get_flags(ch); + if (g_io_channel_set_flags(ch, old_flags & ~G_IO_FLAG_NONBLOCK, &err)!=G_IO_STATUS_NORMAL) + goto err; + + if (!send_connect(self, ch, address, port) || + read_response(self, ch)!=200) + goto err; + + if (g_io_channel_set_flags(ch, old_flags, &err)!=G_IO_STATUS_NORMAL) + goto err; + + g_io_channel_set_line_term(ch, line_term, line_term_sz); + return ch; +err: + if (err) { + g_warning("something went wrong while preparing HTTP proxy request: %s", + err->message); + g_error_free(err); + } + + net_disconnect(ch); + return NULL; + +} + + +struct network_proxy * +_network_proxy_http_create(void) +{ + struct _network_proxy_http *res; + + res = g_malloc0(sizeof *res); + + _network_proxy_create(&res->proxy); + res->password = g_strdup(settings_get_str("proxy_password")); + + res->proxy.destroy = network_proxy_http_destroy; + res->proxy.connect = network_proxy_http_connect; + res->proxy.clone = network_proxy_http_clone; + + return &res->proxy; +} diff --git a/src/core/network-proxy-http.h b/src/core/network-proxy-http.h new file mode 100644 index 00000000..92405fa6 --- /dev/null +++ b/src/core/network-proxy-http.h @@ -0,0 +1,29 @@ +/* --*- c -*-- + * Copyright (C) 2008 Enrico Scholz + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 and/or 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef H_IRSSI_SRC_CORE_PROXY_HTTP_H +#define H_IRSSI_SRC_CORE_PROXY_HTTP_H + +#include "network-proxy.h" + +struct _network_proxy_http { + struct network_proxy proxy; + char const *password; +}; + +struct network_proxy * _network_proxy_http_create(void); + +#endif /* H_IRSSI_SRC_CORE_PROXY_HTTP_H */