📄 proxy.c
字号:
/* * Simple WEB Proxy for Linux and perhaps other systems * by Willy Tarreau * * This program is used to redirect HTTP requests * it receives to the right HTTP server, or to * another instance of itself, on an other host. * It acts like a proxy and all the Web browsers * that will have to use it must be setup to use * it as the HTTP Proxy. It then allows several * hosts on a network to access the Web via one * only server, which is particularly interesting * in case of a server connected to an Internet * provider via a modem with PPP. * * One interesting aspect is that it doesn't require * superuser privileges to run :-) * * Authors: based on stuff by * Willy Tarreau <tarreau@aemiaif.ibp.fr> * * Multithreaded code, POST http method, SIGPIPE, fixes, ... * (rework) * Pavel Krauz <kra@fsid.cvut.cz> * * * Todo: - Make a list of hosts and network which can be * accessed directly, and those which need another * proxy. * - add an option to supply an access log with * hostnames and requests. * * Copyright (C) 1996 <Willy Tarreau> * E-mail: tarreau@aemiaif.ibp.fr * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. * */#include <stdio.h>#include <stdlib.h>#include <errno.h>#include <sys/types.h>#include <sys/wait.h>#include <netinet/in.h>#include <netdb.h>#include <signal.h>#include <string.h>#include <unistd.h>#include <setjmp.h>#include <pthread.h>/* default listen port */#define LISTENPORT 8080/* * default timeout for any read or write, in seconds */#define TIMEOUT_OUT 60/* * exit timeout for idle thread */#define TIMEOUT_THREAD_EXIT 15/* length of data buffer in chars */#define LDATA 1024/* length of remote server address */#define LADR 128/* default port to connect to if unspecified */#define DEFAULTPORT 80/* * max proxy threads for requests */#if 1#define MAX_PROXY_THREADS 64#else#define MAX_PROXY_THREADS 4#endifint ConnectToProxy = 0; /* 1 here means this program will connect to another instance of it 0 means we'll connect directly to the Internet */char NextProxyAdr[128]; /* the name of the host where the next instance of the program runs */int NextProxyPort; /* and its port */int NoCache = 0; /* if not 0, prevents web browsers from retrieving pages in their own cache when the users does a "Reload" action */int timeout_out = TIMEOUT_OUT;int max_proxy_threads = MAX_PROXY_THREADS;struct th_proxy_struct { pthread_t th; /* only for server */ struct th_proxy_struct *next_free; pthread_mutex_t mu; pthread_cond_t cond; int sock_in;};pthread_mutex_t free_q_mu;pthread_cond_t free_q_cond;struct th_proxy_struct *free_q;int thread_count = 0; /* protected with free_q_mu */pthread_key_t key_alarm;pthread_mutex_t gethostbyname_mu; /* used for protect gethostbyname * for gethostbyname_r it isn't needed */void request_alarm(int n);void server(int sockListen, struct sockaddr_in *inputSocket);void *client(struct th_proxy_struct *th_proxy);void displaysyntax(void);char *BADREQ ="HTTP/1.0 400 ERROR\r\n""Server: thproxyd\r\n""Content-type: text/html\r\n""\r\n""<HEAD><TITLE>400 Bad Request</TITLE></HEAD>\n""<BODY><H1>400 Bad Request</H1>\n""Your client sent a query that this server could not\n""understand.<P>\n""Reason: Invalid or unsupported method.<P>\n""</BODY>\n";char *SERVERR ="HTTP/1.0 500 ERROR\r\n""Server: thproxyd\r\n""Content-type: text/html\r\n""\r\n""<HEAD><TITLE>500 Server Error</TITLE></HEAD>\n""<BODY><H1>500 Server Error</H1>\n""Internal proxy error while processing your query.<P>\n""Reason: Internal proxy error.<P>\n""</BODY>\n";char *SERVCOERR ="HTTP/1.0 500 ERROR\r\n""Server: thproxyd\r\n""Content-type: text/html\r\n""\r\n""<HEAD><TITLE>500 Server Error</TITLE></HEAD>\n""<BODY><H1>500 Server Error</H1>\n""Internal proxy error while processing your query.<P>\n""Reason: Invalid connection.<P>\n""</BODY>\n";char *SERVDNSERR ="HTTP/1.0 500 ERROR\r\n""Server: thproxyd\r\n""Content-type: text/html\r\n""\r\n""<HEAD><TITLE>500 Server Error</TITLE></HEAD>\n""<BODY><H1>500 Server Error</H1>\n""Internal proxy error while processing your query.<P>\n""Reason: Bad address - DNS cann't resolve address.<P>\n""</BODY>\n";char *SERVTIMEOUT ="HTTP/1.0 500 ERROR\r\n""Server: thproxyd\r\n""Content-type: text/html\r\n""\r\n""<HEAD><TITLE>500 Server Error</TITLE></HEAD>\n""<BODY><H1>500 Server Error</H1>\n""Internal proxy error while processing your query.<P>\n""Reason: Server time out while connection establishment or data transfer.<P>\n""</BODY>\n";char *POSTERR ="HTTP/1.0 500 ERROR\r\n""Server: thproxyd\r\n""Content-type: text/html\r\n""\r\n""<HEAD><TITLE>500 Proxy Server Error</TITLE></HEAD>\n""<BODY><H1>500 Proxy Server Error</H1>\n""Failed to POST.<P>\n""Reason: post method error ???.<P>\n""</BODY>\n";void main(int argc, char **argv){ int listenport = LISTENPORT; struct sockaddr_in ListenSocket; int sockListen; struct sigaction sa; int opt, val; while ((opt = getopt(argc, argv, "p:x:t:nm:")) != -1) { switch (opt) { case ':': /* missing parameter */ case '?': /* unknown option */ displaysyntax(); exit(1); case 'p': /* port */ listenport = atoi(optarg); break; case 'x':{ /* external proxy */ char *p; p = strchr(optarg, ':'); if (p == NULL) { /* unspecified port number. let's quit */ fprintf(stderr, "missing port for next proxy\n"); displaysyntax(); exit(1); } *(p++) = 0; /* ends hostname */ NextProxyPort = atoi(p); strcpy(NextProxyAdr, optarg); ConnectToProxy = 1; break; } case 't': /* disconnect time-out */ timeout_out = atoi(optarg); break; case 'n': /* no cache */ NoCache = 1; break; case 'm': max_proxy_threads = atoi(optarg); break; } /* end of switch() */ } /* end of while() */ /* initialization of listen socket */ pthread_mutex_init(&free_q_mu, NULL); pthread_mutex_init(&gethostbyname_mu, NULL); pthread_cond_init(&free_q_cond, NULL); free_q = NULL; pthread_key_create(&key_alarm, NULL); sa.sa_handler = request_alarm; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; sigaction(SIGALRM, &sa, NULL); if ((sockListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) { perror("Webroute(socket)"); exit(1); } val = 1; if ((setsockopt(sockListen, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val))) == -1) { perror("Webroute(setsockopt)"); exit(1); } bzero((char *) &ListenSocket, sizeof(ListenSocket)); ListenSocket.sin_family = AF_INET; ListenSocket.sin_addr.s_addr = htonl(INADDR_ANY); ListenSocket.sin_port = htons(listenport); if (bind(sockListen, (struct sockaddr *) &ListenSocket, sizeof(ListenSocket)) == -1) { perror("Webroute(bind)"); exit(1); } if (listen(sockListen, 5) == -1) { perror("Webroute(listen)"); exit(1); } /* the socket is ready. Let's wait for requests ... */ /* let's close stdin, stdout, stderr to prevent messages from appearing on the console */#ifndef DEBUG close(0); close(1); close(2);#endif server(sockListen, &ListenSocket);} /* end of main() */static struct th_proxy_struct *new_proxy_th(void){ struct th_proxy_struct *th_proxy; pthread_attr_t attr; if (!(th_proxy = malloc(sizeof(struct th_proxy_struct)))) return NULL; memset(th_proxy, 0, sizeof(struct th_proxy_struct)); pthread_mutex_init(&th_proxy->mu, NULL); pthread_cond_init(&th_proxy->cond, NULL); th_proxy->next_free = NULL; th_proxy->sock_in = -1; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); if (pthread_create(&th_proxy->th, &attr, (void *((*)(void *))) client, th_proxy) != 0) { free(th_proxy); return NULL; } return th_proxy;}static struct th_proxy_struct *alloc_proxy_th(void){ struct th_proxy_struct *th_proxy; pthread_mutex_lock(&free_q_mu); do { th_proxy = free_q; if (free_q) free_q = free_q->next_free; else { if (thread_count < max_proxy_threads) { if ((th_proxy = new_proxy_th())) thread_count++; } if (!th_proxy) pthread_cond_wait(&free_q_cond, &free_q_mu); } } while (!th_proxy); pthread_mutex_unlock(&free_q_mu); return th_proxy;}void server(int sockListen, struct sockaddr_in *inputSocket){ int lgInputSocket; int sockIn; struct th_proxy_struct *th_proxy; for (;;) { /* infinite loop */ lgInputSocket = sizeof(*inputSocket); do { sockIn = accept(sockListen, (struct sockaddr *) inputSocket, &lgInputSocket); } while (sockIn == -1 && errno == EINTR); /* retries if interrupted */ if (sockIn == -1) { /* if there's an error, we exit */ exit(1); /* don't wait when daemon is going sick ! */ } /* process request, alloc thread for it */ th_proxy = alloc_proxy_th(); pthread_mutex_lock(&th_proxy->mu); th_proxy->sock_in = sockIn; pthread_mutex_unlock(&th_proxy->mu); pthread_cond_signal(&th_proxy->cond); }}#define ERR_SOCKET -5#define ERR_GETHOSTBYNAME -6#define ERR_CONNECT -7#define ERR_CONNECT_TIMEOUT -8int connectto(char *hote, int port, int sockIn){#if 0 /* * use gethostbyname */ struct hostent *ServerName; struct sockaddr_in OutputSocket; /* output socket descriptor */ int sockOut, retval; if ((sockOut = socket(AF_INET, SOCK_STREAM, 0)) == -1) { return ERR_SOCKET; } pthread_mutex_lock(&gethostbyname_mu); if ((ServerName = gethostbyname(hote)) == NULL) { pthread_mutex_unlock(&gethostbyname_mu); return ERR_GETHOSTBYNAME; } bzero((char *) &OutputSocket, sizeof(OutputSocket)); OutputSocket.sin_family = AF_INET; OutputSocket.sin_port = htons(port); bcopy((char *) ServerName->h_addr, (char *) &OutputSocket.sin_addr, ServerName->h_length);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -