/* MiddleMan filtering proxy server Copyright (C) 2002 Jason McLaughlin 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; either version 2 of the License, or (at your option) any later version. 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include "proto.h" FORWARD_LIST *forward_load(FORWARD_LIST * forward_list, XML_LIST * xml_list) { FORWARD_LIST *tmp_list = forward_list; struct FORWARD_LIST_LIST *forward = NULL; if (tmp_list == NULL) { tmp_list = xmalloc(sizeof(FORWARD_LIST)); tmp_list->forward_list = NULL; tmp_list->id = 0; tmp_list->enabled = TRUE; forward_list = tmp_list; pthread_rwlock_init(&tmp_list->lock, NULL); } else forward = tmp_list->forward_list; while ((xml_list = xml_section(xml_list, ""))) { XML_LIST_LOOP(xml_list, "") { XML_LIST_CMP(xml_list, "") { forward = forward_list_new(forward); forward->id = tmp_list->id++; if (tmp_list->forward_list == NULL) tmp_list->forward_list = forward; XML_LIST_LOOP(xml_list, "") { XML_LIST_CMP(xml_list, "") { xml_list = xml_list->next; if (xml_list->type == XML_VALUE) { if (!strcasecmp(xml_list->item, "false")) forward->enabled = FALSE; else forward->enabled = TRUE; } } XML_LIST_CMP(xml_list, "") { xml_list = xml_list->next; if (xml_list->type == XML_VALUE) forward_list_insert(forward, xml_list->item, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); } XML_LIST_CMP(xml_list, "") { xml_list = xml_list->next; if (xml_list->type == XML_VALUE) forward_list_insert(forward, NULL, xml_list->item, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); } XML_LIST_CMP(xml_list, "") { xml_list = xml_list->next; if (xml_list->type == XML_VALUE) forward_list_insert(forward, NULL, NULL, xml_list->item, NULL, NULL, NULL, NULL, NULL, NULL, NULL); } XML_LIST_CMP(xml_list, "") { xml_list = xml_list->next; if (xml_list->type == XML_VALUE) forward_list_insert(forward, NULL, NULL, NULL, xml_list->item, NULL, NULL, NULL, NULL, NULL, NULL); } XML_LIST_CMP(xml_list, "") { xml_list = xml_list->next; if (xml_list->type == XML_VALUE) forward_list_insert(forward, NULL, NULL, NULL, NULL, xml_list->item, NULL, NULL, NULL, NULL, NULL); } XML_LIST_CMP(xml_list, "") { xml_list = xml_list->next; if (xml_list->type == XML_VALUE) forward_list_insert(forward, NULL, NULL, NULL, NULL, NULL, xml_list->item, NULL, NULL, NULL, NULL); } XML_LIST_CMP(xml_list, "") { xml_list = xml_list->next; if (xml_list->type == XML_VALUE) forward_list_insert(forward, NULL, NULL, NULL, NULL, NULL, NULL, xml_list->item, NULL, NULL, NULL); } XML_LIST_CMP(xml_list, "") { xml_list = xml_list->next; if (xml_list->type == XML_VALUE) forward_list_insert(forward, NULL, NULL, NULL, NULL, NULL, NULL, NULL, xml_list->item, NULL, NULL); } XML_LIST_CMP(xml_list, "") { xml_list = xml_list->next; if (xml_list->type == XML_VALUE) forward_list_insert(forward, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, xml_list->item, NULL); } XML_LIST_CMP(xml_list, "") { xml_list = xml_list->next; if (xml_list->type == XML_VALUE) forward_list_insert(forward, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, xml_list->item); } } XML_LIST_CMP(xml_list, "") { xml_list = xml_list->next; if (xml_list->type == XML_VALUE) { if (!strcasecmp(xml_list->item, "false")) tmp_list->enabled = FALSE; else tmp_list->enabled = TRUE; } } } } } return tmp_list; } XML_LIST *forward_xml(FORWARD_LIST * forward_list, XML_LIST * xml_list) { char *ptr, buf[128]; struct FORWARD_LIST_LIST *fl; pthread_rwlock_rdlock(&forward_list->lock); xml_list = xml_list_add(xml_list, "", XML_TAG); xml_list = xml_list_add(xml_list, "", XML_TAG); xml_list = xml_list_add(xml_list, (forward_list->enabled == TRUE) ? "true" : "false", XML_VALUE); xml_list = xml_list_add(xml_list, "", XML_TAG); for (fl = forward_list->forward_list; fl; fl = fl->next) { xml_list = xml_list_add(xml_list, "", XML_TAG); xml_list = xml_list_add(xml_list, "", XML_TAG); xml_list = xml_list_add(xml_list, (fl->enabled == TRUE) ? "true" : "false", XML_VALUE); xml_list = xml_list_add(xml_list, "", XML_TAG); if (fl->comment != NULL) { xml_list = xml_list_add(xml_list, "", XML_TAG); ptr = string_to_xml(fl->comment); xml_list = xml_list_add(xml_list, ptr, XML_VALUE); xfree(ptr); xml_list = xml_list_add(xml_list, "", XML_TAG); } if (fl->host != NULL) { xml_list = xml_list_add(xml_list, "", XML_TAG); ptr = string_to_xml(fl->host); xml_list = xml_list_add(xml_list, ptr, XML_VALUE); xfree(ptr); xml_list = xml_list_add(xml_list, "", XML_TAG); } if (fl->file != NULL) { xml_list = xml_list_add(xml_list, "", XML_TAG); ptr = string_to_xml(fl->file); xml_list = xml_list_add(xml_list, ptr, XML_VALUE); xfree(ptr); xml_list = xml_list_add(xml_list, "", XML_TAG); } if (fl->proxy != NULL) { xml_list = xml_list_add(xml_list, "", XML_TAG); ptr = string_to_xml(fl->proxy); xml_list = xml_list_add(xml_list, ptr, XML_VALUE); xfree(ptr); xml_list = xml_list_add(xml_list, "", XML_TAG); } if (fl->port != -1) { xml_list_add(xml_list, "", XML_TAG); snprintf(buf, sizeof(buf), "%d", fl->port); xml_list = xml_list_add(xml_list, buf, XML_VALUE); xml_list_add(xml_list, "", XML_TAG); } if (fl->username != NULL) { xml_list = xml_list_add(xml_list, "", XML_TAG); ptr = string_to_xml(fl->username); xml_list = xml_list_add(xml_list, ptr, XML_VALUE); xfree(ptr); xml_list = xml_list_add(xml_list, "", XML_TAG); } if (fl->password != NULL) { xml_list = xml_list_add(xml_list, "", XML_TAG); ptr = string_to_xml(fl->password); xml_list = xml_list_add(xml_list, ptr, XML_VALUE); xfree(ptr); xml_list = xml_list_add(xml_list, "", XML_TAG); } if (fl->domain != NULL) { xml_list = xml_list_add(xml_list, "", XML_TAG); ptr = string_to_xml(fl->domain); xml_list = xml_list_add(xml_list, ptr, XML_VALUE); xfree(ptr); xml_list = xml_list_add(xml_list, "", XML_TAG); } xml_list = xml_list_add(xml_list, "", XML_TAG); xml_list = xml_list_add(xml_list, (fl->type == PROXY_NORMAL) ? "HTTP" : "SOCKS4", XML_VALUE); xml_list = xml_list_add(xml_list, "", XML_TAG); xml_list = xml_list_add(xml_list, "", XML_TAG); snprintf(buf, sizeof(buf), "%s,%s", (fl->which & FORWARD_HTTP) ? "HTTP" : "", (fl->which & FORWARD_CONNECT) ? "CONNECT" : ""); xml_list = xml_list_add(xml_list, buf, XML_VALUE); xml_list = xml_list_add(xml_list, "", XML_TAG); xml_list = xml_list_add(xml_list, "", XML_TAG); } xml_list = xml_list_add(xml_list, "", XML_TAG); pthread_rwlock_unlock(&forward_list->lock); return xml_list; } struct FORWARD_LIST_LIST *forward_list_new(struct FORWARD_LIST_LIST *x) { if (x == NULL) { x = xmalloc(sizeof(struct FORWARD_LIST_LIST)); x->prev = NULL; } else { while (x->next != NULL) x = x->next; x->next = xmalloc(sizeof(struct FORWARD_LIST_LIST)); x->next->prev = x; x = x->next; } x->enabled = TRUE; x->comment = NULL; x->host = NULL; x->file = NULL; x->port = -1; x->type = PROXY_NORMAL; x->which = 0; x->proxy = NULL; x->username = NULL; x->password = NULL; x->domain = NULL; x->he = NULL; x->fe = NULL; x->next = NULL; return x; } void forward_list_insert(struct FORWARD_LIST_LIST *x, char *a, char *b, char *c, char *d, char *e, char *f, char *g, char *h, char *i, char *j) { int z; char **args; if (a != NULL) { FREE_AND_NULL(x->comment); if (strcmp(a, "")) x->comment = xstrdup(a); } if (b != NULL) { if (x->he != NULL) reg_free(x->he); FREE_AND_NULL(x->host); if (strcmp(b, "")) { x->he = reg_compile(b, REGFLAGS); x->host = xstrdup(b); } else x->he = NULL; } if (c != NULL) { if (x->fe != NULL) reg_free(x->fe); FREE_AND_NULL(x->file); if (strcmp(c, "")) { x->fe = reg_compile(c, REGFLAGS); x->file = xstrdup(c); } else x->fe = NULL; } if (d != NULL) { FREE_AND_NULL(x->proxy); if (strcmp(d, "")) x->proxy = xstrdup(d); } if (e != NULL) { x->port = -1; if (strcmp(e, "")) x->port = atoi(e); } if (f != NULL) { x->type = PROXY_NORMAL; if (strcmp(f, "")) { if (!strcasecmp(f, "HTTP")) x->type = PROXY_NORMAL; else if (!strcasecmp(f, "SOCKS4")) x->type = PROXY_SOCKS4; } } if (g != NULL) { x->which = 0; if (strcmp(g, "")) { args = string_break(g, ','); for (z = 0; args[z]; z++) { if (!strcasecmp(args[z], "HTTP")) x->which |= FORWARD_HTTP; else if (!strcasecmp(args[z], "CONNECT")) x->which |= FORWARD_CONNECT; xfree(args[z]); } xfree(args); } } if (h != NULL) { FREE_AND_NULL(x->username); if (strcmp(h, "")) x->username = xstrdup(h); } if (i != NULL) { FREE_AND_NULL(x->password); if (strcmp(i, "")) x->password = xstrdup(i); } if (j != NULL) { FREE_AND_NULL(x->domain); if (strcmp(j, "")) x->domain = xstrdup(j); } } struct FORWARD_LIST_LIST *forward_list_delete(struct FORWARD_LIST_LIST *x) { struct FORWARD_LIST_LIST *start = x; while (start->prev != NULL) start = start->prev; if (x->next != NULL) x->next->prev = x->prev; if (x->prev != NULL) x->prev->next = x->next; else start = start->next; if (x->he != NULL) reg_free(x->he); if (x->fe != NULL) reg_free(x->fe); FREE_AND_NULL(x->comment); FREE_AND_NULL(x->host); FREE_AND_NULL(x->file); FREE_AND_NULL(x->proxy); FREE_AND_NULL(x->username); FREE_AND_NULL(x->password); FREE_AND_NULL(x->domain); return start; } void forward_list_free(struct FORWARD_LIST_LIST *fl) { struct FORWARD_LIST_LIST *tmp; while (fl != NULL) { tmp = fl->next; if (fl->he != NULL) reg_free(fl->he); if (fl->fe != NULL) reg_free(fl->fe); FREE_AND_NULL(fl->comment); FREE_AND_NULL(fl->host); FREE_AND_NULL(fl->file); FREE_AND_NULL(fl->proxy); FREE_AND_NULL(fl->username); FREE_AND_NULL(fl->password); FREE_AND_NULL(fl->domain); xfree(fl); fl = tmp; } } void forward_free(FORWARD_LIST * forward_list) { if (forward_list == NULL) return; forward_list_free(forward_list->forward_list); xfree(forward_list); } int forward_do(FORWARD_LIST * forward_list, CONNECTION * connection) { int ret; struct FORWARD_LIST_LIST *forward; if (!forward_list || connection->bypass & FEATURE_FORWARD) return FALSE; pthread_rwlock_rdlock(&forward_list->lock); if (forward_list->enabled == FALSE) { pthread_rwlock_unlock(&forward_list->lock); return FALSE; } for (forward = forward_list->forward_list; forward; forward = forward->next) { if (forward->enabled == FALSE) continue; if (((connection->header->type == HTTP_PROXY || connection->header->type == HTTP_REQUEST) && !(forward->which & FORWARD_HTTP)) || ((connection->header->type == HTTP_CONNECT) && !(forward->which & FORWARD_CONNECT))) continue; if (forward->he != NULL) { ret = reg_exec(forward->he, connection->header->host); if (ret) continue; } if (forward->fe != NULL) { ret = reg_exec(forward->fe, connection->header->file); if (ret) continue; } /* allow entries with no proxy host to match, but don't do anything */ if (forward->proxy == NULL) break; connection->proxy_type = forward->type; connection->proxy_host = xstrdup(forward->proxy); if (forward->username != NULL) connection->proxy_username = xstrdup(forward->username); if (forward->password != NULL) connection->proxy_password = xstrdup(forward->password); if (forward->domain != NULL) connection->proxy_domain = xstrdup(forward->domain); connection->proxy_port = (forward->port != -1) ? forward->port : (forward->type == PROXY_SOCKS4) ? 443 : 3128; pthread_rwlock_unlock(&forward_list->lock); return TRUE; } pthread_rwlock_unlock(&forward_list->lock); return FALSE; }