/* tinyproxy - A fast light-weight HTTP proxy * Copyright (C) 1999-2005 Robert James Kaes * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* Allow tinyproxy to be used as a reverse proxy. */ #include "main.h" #include "reverse-proxy.h" #include "conns.h" #include "heap.h" #include "html-error.h" #include "log.h" #include "conf.h" /* * Add entry to the reversepath list */ void reversepath_add (const char *path, const char *url, struct reversepath **reversepath_list) { struct reversepath *reverse; size_t l; if (url == NULL) { log_message (LOG_WARNING, "Illegal reverse proxy rule: missing url"); return; } if (!strstr (url, "://")) { log_message (LOG_WARNING, "Skipping reverse proxy rule: '%s' is not a valid url", url); return; } if (path && *path != '/') { log_message (LOG_WARNING, "Skipping reverse proxy rule: path '%s' " "doesn't start with a /", path); return; } reverse = (struct reversepath *) safemalloc (sizeof (struct reversepath)); if (!reverse) { log_message (LOG_ERR, "Unable to allocate memory in reversepath_add()"); return; } if (!path) reverse->path = safestrdup ("/"); else { l = strlen (path); if (l && path[l-1] == '/') reverse->path = safestrdup (path); else { reverse->path = safemalloc (l + 2); memcpy (reverse->path, path, l); reverse->path[l] = '/'; reverse->path[l+1] = 0; } } reverse->url = safestrdup (url); reverse->next = *reversepath_list; *reversepath_list = reverse; log_message (LOG_INFO, "Added reverse proxy rule: %s -> %s", reverse->path, reverse->url); } /* * Check if a request url is in the reversepath list */ struct reversepath *reversepath_get (char *url, struct reversepath *reverse) { size_t l, lu, lp; while (reverse) { lu = strlen (url); lp = strlen (reverse->path); if (( (l = lu) == lp-1 || (l = lp) <= lu ) && !memcmp(url, reverse->path, l)) return reverse; reverse = reverse->next; } return NULL; } /** * Free a reversepath list */ void free_reversepath_list (struct reversepath *reverse) { while (reverse) { struct reversepath *tmp = reverse; reverse = reverse->next; safefree (tmp->url); safefree (tmp->path); safefree (tmp); } } /* * Rewrite the URL for reverse proxying. */ char *reverse_rewrite_url (struct conn_s *connptr, orderedmap hashofheaders, char *url, int *status) { char *rewrite_url = NULL; char *cookie = NULL; char *cookieval; struct reversepath *reverse = NULL; *status = 0; /* Reverse requests always start with a slash */ if (*url == '/') { /* First try locating the reverse mapping by request url */ reverse = reversepath_get (url, config->reversepath_list); if (reverse) { size_t lu = strlen (url); size_t lrp = strlen (reverse->path); if (lrp > lu) { rewrite_url = safestrdup (reverse->path); *status = 301; } else { rewrite_url = safemalloc ( strlen (reverse->url) + lu + 1); sprintf (rewrite_url, "%s%s", reverse->url, url + lrp); } } else if (config->reversemagic && (cookie = orderedmap_find (hashofheaders, "cookie"))) { /* No match - try the magical tracking cookie next */ if ((cookieval = strstr (cookie, REVERSE_COOKIE "=")) && (reverse = reversepath_get (cookieval + strlen (REVERSE_COOKIE) + 1, config->reversepath_list))) { rewrite_url = (char *) safemalloc (strlen (url) + strlen (reverse->url) + 1); strcpy (rewrite_url, reverse->url); strcat (rewrite_url, url + 1); log_message (LOG_INFO, "Magical tracking cookie says: %s", reverse->path); } } } if (rewrite_url == NULL) { return NULL; } log_message (LOG_CONN, "Rewriting URL: %s -> %s", url, rewrite_url); /* Store reverse path so that the magical tracking cookie can be set */ if (config->reversemagic && reverse) connptr->reversepath = safestrdup (reverse->path); return rewrite_url; }