All pastes #275077 Raw Edit

ProxyServer

public cpp v1 · immutable
·published 2006-12-11 05:36 UTC
rendered paste body
/* * Welcome to Proxy Server! * * This thing should work on Wintel and *nix.  It supports HTTP GET, * POST, and CONNECT (aka Tunnelling, SSL, Security.) * * Please send me notice of all bugs: malxau@users.sourceforge.net. * * This code is licensed subject to the terms of the GNU General Public * License (see the COPYING file for more.)  Note that there is NO * WARRANTY provided, including but not limited to, no warranty for * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * * Copyright (c) Malcolm Smith 2003-2004. *//* * Includes common to all platforms */#include <ctype.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#ifdef _WIN32_/* Windoze includes */#include <io.h>#include <winsock.h>#else /* _WIN32_ *//* *nix includes */#include <netinet/in.h>#include <netdb.h>#include <signal.h>#include <sys/select.h>#include <sys/socket.h>#include <sys/types.h>#include <unistd.h>#ifdef THREADING_SUPPORT#include <pthread.h>#endif#endif /* !_WIN32_ */typedef int SOCKLEN_T;#ifndef _WIN32_/*Windows defines a few types, which UNIX has equivalent (different) typesfor.  These set up aliases on unix to the Windows version.  This shouldmake code easier to read.*/typedef int BOOL;typedef struct hostent HOSTENT;typedef struct sockaddr SOCKADDR;typedef struct sockaddr_in SOCKADDR_IN;typedef int SOCKET;/*Some constants, predefined on Windows.*/#ifndef FALSEconst FALSE = 0;#endifconst INVALID_SOCKET = -1;#ifndef TRUEconst TRUE = 1;#endif#define closesocket(x) close(x)#endif /* !_WIN32_ */#ifdef _WIN32_#define sleep(x) Sleep(x*1000)#endif /* _WIN32_ */typedef enum{ NO, YES, NOTYET }BOOLX;/*As a proxy, we need to listen for new requests coming in from the LAN.This part is a server part - and this is the variable that recordswhere we're listening.*/SOCKET server;#if defined(THREADING_SUPPORT)&&(!defined(_WIN32_))pthread_mutex_t gethostbyname_lock = PTHREAD_MUTEX_INITIALIZER;#endif/*This function sends data, making sure it either sends all the data or fails,no partial send should be considered success*/intsend_block (SOCKET s, char *buf, int len){	int havesent;	int sentnow;	havesent = 0;	while (havesent != len)	{		sentnow = send (s, buf + havesent, (len - havesent), 0);		if (sentnow <= 0)			return -1;		havesent += sentnow;	}	return len;}/*This function takes the specified hostname, finds the IP address, andattempts to connect.  If it succeeds, it returns where you can findthe new connection, otherwise it returns a token saying no connectionwas made.*/SOCKETConnectToHost (char *szHostName){	SOCKET client;	SOCKADDR_IN sin;	HOSTENT *phe;	int ret;	char *port;	struct linger lyes;	/* If the user has specified a port, find out where it is, and	 * then pretend it isn't there.	 */	port = strchr (szHostName, ':');	if (port)		port[0] = '\0';	/* Create a new socket for the communication. */	client = socket (AF_INET, SOCK_STREAM, 0);	/*	   Linger - if the socket is closed, ensure that data is sent/	   received right up to the last byte.  Don't stop just because	   the connection is closed.	 */	lyes.l_onoff = 1;	lyes.l_linger = 10;	setsockopt (client, SOL_SOCKET, SO_LINGER, (char *) &lyes,		    sizeof (lyes));	/* Clear the structure. */	memset (&sin, 0, sizeof (sin));	/* We want to connect to an IP network (AF_INET) */	sin.sin_family = AF_INET;	if (port)	{		/* If we have a port, use that */		sin.sin_port = htons ((unsigned short) atoi (port + 1));	}	else	{		/* Default port for HTTP is 80 */		sin.sin_port = htons (80);	}	/* Windows uses Thread-Local storage for this.  Unix may not, and needs	 * this locking mechanism instead.  A professional application would use	 * gethostbyname_r, but the syntax varies between unicies, and I don't	 * have a configure script, so I'm not using it. */#if defined(THREADING_SUPPORT)&&(!defined(_WIN32_))	pthread_mutex_lock (&gethostbyname_lock);#endif	/* Get the IP address for this hostname. */	phe = gethostbyname (szHostName);	if (!phe)	{#if defined(THREADING_SUPPORT)&&(!defined(_WIN32_))		pthread_mutex_unlock (&gethostbyname_lock);#endif		printf ("Could not resolve hostname %s.\n", szHostName);		return INVALID_SOCKET;	}	/* Use the address obtained from GetHostByName */	memcpy (&sin.sin_addr.s_addr, phe->h_addr, phe->h_length);#if defined(THREADING_SUPPORT)&&(!defined(_WIN32_))	pthread_mutex_unlock (&gethostbyname_lock);#endif	/* Try to connect */	ret = connect (client, (SOCKADDR *) & sin, sizeof (sin));	if (ret == 0)		return client;	/* We failed. */	closesocket (client);	return INVALID_SOCKET;}/* * This function peeks at input and tries to extract a single, solitary line * and leave the rest of the data in the buffer waiting collection.  It will * wait until a line is present.  It should be used where a line is definitely * needed before proceeding. */BOOLGetLineFromSocketWait (SOCKET sock, char *szDestination, int nDestination){	char szBuffer[1024];	char *inptr;	int len;	int sizeremaining;	char *ret;	int i;	fd_set readset;	struct timeval timeout;	i = 0;	inptr = szBuffer;	sizeremaining = sizeof (szBuffer) - 1;	while (i < 15)	{		FD_ZERO (&readset);		FD_SET (sock, &readset);		timeout.tv_sec = 60 * 5;		timeout.tv_usec = 0;		if (select (sock + 1, &readset, NULL, NULL, &timeout) < 1)			return FALSE;		/* Peek at all the available data */		len = recv (sock, inptr, sizeremaining, MSG_PEEK);		inptr[len] = '\0';		if (len < 1)			return NO;		/* Find a newline */		ret = strchr (szBuffer, '\n');		if (ret)		{			/* If we have space in the buffer */			if (ret - szBuffer < (nDestination - 4))			{				/* Permanently read the data from the network */				len = recv (sock, inptr,					    (ret - szBuffer) - (inptr -								szBuffer) + 1,					    0);				if (len < 1)					return NO;				inptr[len] = '\0';				strcpy (szDestination, szBuffer);				return TRUE;			}			return FALSE;		}		else		{			len = recv (sock, inptr, len, 0);			inptr[len] = '\0';			inptr += len;			sizeremaining -= len;			i++;		}	}	return FALSE;}/* * Clients don't like us responding till they've sent their entire request. * This is used to collect their request and throw it away, so we can * reply. */BOOLDiscardHeaders (SOCKET stream, char *szBuffer, int nBuffer){	BOOL finished;	char *szHeaderValue;	finished = FALSE;	while (!finished)	{		strcpy (szBuffer, "");		if (GetLineFromSocketWait (stream, szBuffer, nBuffer - 1))		{			/* Strip of a trailing carriage-return. */			szHeaderValue = strchr (szBuffer, '\r');			if (szHeaderValue)				szHeaderValue[0] = '\0';			szHeaderValue = strchr (szBuffer, '\n');			if (szHeaderValue)				szHeaderValue[0] = '\0';			/* If there is nothing left (ie: blank line)			 * the headers are over. */			if (!strcmp (szBuffer, ""))				finished = TRUE;		}		else		{			/* stream has been closed */			return FALSE;		}	}	return TRUE;}/* * This function extracts an HTTP header name.  For example, imagine... * GET http://somewhere/resource.htm HTTP/1.0 * User-Agent: Anything-But-IE * * This function will take in the whole User-Agent line (in * szSourceString) extract just the user-agent part, uppercase it * and return.  So you'd end up with "USER-AGENT" in szDestination. * nDest specifies the size of szDestination. */BOOLGetHeaderID (char *szSourceString, char *szDestination, int nDest){	char *colon;	/* Find the : */	colon = strchr (szSourceString, ':');	/* If there's no :, it's no header */	if (!colon)		return FALSE;	/* If we have space in the destination to fit this header */	if ((colon - szSourceString) < nDest)	{		/* Copy it there */		strncpy (szDestination, szSourceString,			 colon - szSourceString);		szDestination[colon - szSourceString] = '\0';		/* Uppercase it all */		for (colon = szDestination; *colon; colon++)			*colon = toupper (*colon);		return TRUE;	}	return FALSE;}/*This function attempts to determine what the hostname was from an HTTPheader request.These requests are normally:GET http://www.someplace.com/someresource HTTP/1.1CONNECT www.someserver.com:80 HTTP/1.0We want 'www.someplace.com'...*/char *GetHostNameFromRequest (char *szLineBuffer){	char *hostend;	char *protoend;	char *returnvalue;	/* Find the // */	protoend = strstr (szLineBuffer, "//");	if (protoend)	{		/* Jump to AFTER the // */		protoend += 2;		/* Find the next / */		hostend = strchr (protoend, '/');	}	else	{		/* If there's no //, it may be a CONNECT request, which		 * doesn't have one.  In that case, look for the first		 * space. */		protoend = strchr (szLineBuffer, ' ');		if (!protoend)			return NULL;		/* Jump to AFTER the space */		protoend++;		/* If there isn't one (CONNECT again) we're looking for the		 * next space */		hostend = strchr (protoend, ' ');	}	/* No matter how we tried, if we failed, we failed. */	if (!hostend)		return NULL;	/* Grab what's in the middle */	returnvalue = (char *) malloc (hostend - protoend + 1);	strncpy (returnvalue, protoend, hostend - protoend);	returnvalue[hostend - protoend] = '\0';	return returnvalue;}/*This function attempts to determine what the resource was from an HTTPheader request.These requests are normally:GET http://www.someplace.com/someresource HTTP/1.1We want 'someresource'...*/char *GetResourceFromRequest (char *szLineBuffer){	char *hostend;	char *nextspace;	char *protoend;	char *returnvalue;	/* We don't need to worry about CONNECT here, because it doens't	 * specify a resource. */	/* Grab the // */	protoend = strstr (szLineBuffer, "//");	if (!protoend)		return NULL;	protoend += 2;	/* Then find the next / */	hostend = strchr (protoend, '/');	if (!hostend)		return NULL;	/* Then find the next space */	nextspace = strchr (hostend, ' ');	if (!nextspace)		return NULL;	/* Grab what's between the / and the space */	returnvalue = (char *) malloc (nextspace - hostend + 1);	strncpy (returnvalue, hostend, nextspace - hostend);	returnvalue[nextspace - hostend] = '\0';	return returnvalue;}/*This function returns true if the request is of the specified method.*/BOOLIsMethod (char *szLineBuffer, char *szMethod){	int ret;	int len;	len = strlen (szMethod);	/* Is the first few characters the same as method? */	ret = strncmp (szLineBuffer, szMethod, len);	/* If so, and there's a space immediately afterwards, then	 * this is the correct method. */	if (ret == 0 && szLineBuffer[len] == ' ')		return TRUE;	return FALSE;}/*This function returns true if the request is an HTTP request.*/BOOLIsHttp (char *szLineBuffer){	int ret;	char *firstspace;	/* Find the first space in the HTTP request. */	firstspace = strchr (szLineBuffer, ' ');	if (!firstspace)		return FALSE;	/* Go to what's after the space */	firstspace++;	/* Does it begin with http:// ? */	ret = strncmp (firstspace, "http://", 7);	/* If yes, it's an http request. */	if (ret == 0)		return TRUE;	return FALSE;}/*This function returns true if the response is an HTTP response.*/BOOLIsHttpReply (char *szLineBuffer){	int ret;	/* Are the first few chars of the response HTTP/1. ? */	ret = strncmp (szLineBuffer, "HTTP/1.", 7);	if (ret == 0)		return TRUE;	return FALSE;}/*This function is used to tell the client if something went wrong.*/BOOLSendFailure (SOCKET stream, int error, char *msg, BOOL bWaitForHeaders){	char szBuffer[768];	char szHTMLBuffer[512];	/* Apparently clients don't like being told they're stupid until	 * AFTER they finish being stupid.  We have to WAIT for ALL the	 * client headers before telling them their request cannot be	 * fulfilled.  Grr.	 */	if (bWaitForHeaders)	{		DiscardHeaders (stream, szBuffer, sizeof (szBuffer) - 1);	}	/* Format a reply for the client user's grizzling pleasure. */	sprintf (szHTMLBuffer,		 "<HTML><HEAD><TITLE>%i: %s</TITLE></HEAD><BODY>\r\n"		 "<H1>%i: %s</H1>\r\n"		 "<P>This error has been generated by your proxy"		 " server.</P></BODY></HTML>\r\n", error, msg, error, msg);	/* Display it on the console */	sprintf (szBuffer, "HTTP/1.0 %i %s\n"		 "Content-Type: text/html\n"		 "Content-Length: %i\n"		 "\n" "%s", error, msg, strlen (szHTMLBuffer), szHTMLBuffer);	printf ("%i: %s (proxy error)\n", error, msg);	send_block (stream, szBuffer, strlen (szBuffer));	return TRUE;}/*This function initialises the server.*/BOOLStartServer (){	SOCKADDR_IN sin;	int ret;	unsigned int yes;	struct linger lyes;#ifdef _WIN32_	WSADATA wd;	WSAStartup (MAKEWORD (1, 1), &wd);#endif /*  */	yes = TRUE;	/* Grab a place to listen for connections. */	server = socket (AF_INET, SOCK_STREAM, 0);	if (server < 0)	{		printf ("socket() failed\n");		return FALSE;	}	/* Don't ignore data received after a close */	lyes.l_onoff = 1;	lyes.l_linger = 10;	setsockopt (server, SOL_SOCKET, SO_LINGER, (char *) &lyes,		    sizeof (lyes));	/* If this server has been restarted, don't wait for the old	 * one to disappear completely */	setsockopt (server, SOL_SOCKET, SO_REUSEADDR, (char *) &yes,		    sizeof (yes));	/*	   Listen on IP port 8080, on any interface.  This is really bad -	   you probably only want to listen on the LAN interface, because this	   server could be used by people on the MODEM accessing your LAN,	   instead of the other way around ;)	   There is a hack further down to reduce problems associated with	   this.	 */	memset (&sin, 0, sizeof (sin));	sin.sin_family = AF_INET;	sin.sin_port = htons (8080);	/* FIXME! */	sin.sin_addr.s_addr = INADDR_ANY;	ret = bind (server, (SOCKADDR *) & sin, sizeof (sin));	if (ret < 0)	{		printf ("bind() failed\n");		return FALSE;	}	/* Start listening for incoming connections. */	ret = listen (server, 5);	if (ret == 0)		return TRUE;	printf ("listen() failed\n");	return FALSE;}/* * As mentioned above, CONNECT is a wierd kind of request. * * The good news is that in normal web browsing you won't see it. * * The bad news is that it's *required* for https connections. * (The worse news is that I hadn't seen it before and don't know * what it's supposed to be doing.) * * This function will be light on comments, because it's pretty much * a guess but I'm leaving it in for when I find out what's right... */BOOLProcessConnect (SOCKET localwebuser, char *szLineBuffer, int nLineBuffer){	SOCKET remotewebserver;	char *szHostName;	BOOL finished;	fd_set fds;	int biggest;	int len;	/*	   Try to extract the hostname from request.  If we can't, somebody	   is being a prick.	 */	szHostName = GetHostNameFromRequest (szLineBuffer);	if (!szHostName)	{		SendFailure (localwebuser, 500,			     "Could not extract hostname - malformed request.",			     TRUE);		return FALSE;	}	/* Try to connect to the outside world */	remotewebserver = ConnectToHost (szHostName);	if (remotewebserver == INVALID_SOCKET)	{		free (szHostName);		SendFailure (localwebuser, 404,			     "Could not connect to the outside host.", TRUE);		return FALSE;	}	/* Display the response, and request info, for debugging. */	sprintf (szLineBuffer, "%i: %s\n", 200, szHostName);	free (szHostName);	write (1, szLineBuffer, strlen (szLineBuffer));	/*	 * Throw away any headers, we don't know what to do with them.	 */	DiscardHeaders (localwebuser, szLineBuffer, nLineBuffer);	/*	 * Tell the client everything worked fine.	 */	sprintf (szLineBuffer, "HTTP/1.0 200 Ok\n\n");	send_block (localwebuser, szLineBuffer, strlen (szLineBuffer));	/*	 * Go into a big loop of forwarding data from one side to the	 * other.	 */	finished = FALSE;	while (!finished)	{		FD_ZERO (&fds);		FD_SET (localwebuser, &fds);		FD_SET (remotewebserver, &fds);		if (localwebuser > remotewebserver)			biggest = localwebuser;		else			biggest = remotewebserver;		biggest++;		/* Wait for message from either side */		select (biggest, &fds, NULL, NULL, NULL);		if (FD_ISSET (localwebuser, &fds))		{			/* A message from the LAN, forward to the server */			len = recv (localwebuser, szLineBuffer,				    nLineBuffer - 1, 0);			if (len <= 0)			{				/* Connection closed */				finished = TRUE;			}			else			{				szLineBuffer[len] = '\0';				send_block (remotewebserver, szLineBuffer,					    len);			}		}		if (FD_ISSET (remotewebserver, &fds))		{			/* A message from the server, forward to the LAN */			len = recv (remotewebserver, szLineBuffer,				    nLineBuffer - 1, 0);			if (len <= 0)			{				/* Connection closed */				finished = TRUE;			}			else			{				szLineBuffer[len] = '\0';				send_block (localwebuser, szLineBuffer, len);			}		}	}	/* Close and finish */	closesocket (remotewebserver);	return TRUE;}/* * Confusingly, this function processes both GET and POST requests, but is * called ProcessGet because of history (and to distinguish from CONNECT.) * * localwebuser==network of the local user * szLineBuffer==some space to work with * nLineBuffer==how much space we have to work with */BOOLProcessGet (SOCKET localwebuser, char *szLineBuffer, int nLineBuffer){	BOOL finished;	int len;	int contentlength;	int failcount;	SOCKET remotewebserver;	char *szHostName;	char *szResource;	char *szHeaderValue;	char szHeaderID[64];	finished = FALSE;	/* GET requests only send a request and some headers.  POST	 * also sends some data.  Content-length is used to determine	 * how much data is coming - we need to collect it all.	 */	contentlength = 0;	failcount = 0;	/* Test to see if the request is HTTP.  If it isn't, bail out. */	if (!IsHttp (szLineBuffer))	{		SendFailure (localwebuser, 501,			     "Only HTTP requests are supported by this proxy.",			     TRUE);		return FALSE;	}	/*	   Try to extract the hostname from request.  If we can't, somebody	   is being a prick.	 */	szHostName = GetHostNameFromRequest (szLineBuffer);	if (!szHostName)	{		SendFailure (localwebuser, 500,			     "Could not extract hostname - malformed request.",			     TRUE);		return FALSE;	}	/*	   Try to extract the resource from request.  If we can't, somebody	   is being a prick.	 */	szResource = GetResourceFromRequest (szLineBuffer);	if (!szResource)	{		SendFailure (localwebuser, 500,			     "Could not extract resource - malformed request.",			     TRUE);		free (szHostName);		return FALSE;	}	/* Try to connect to the outside world */	remotewebserver = ConnectToHost (szHostName);	if (remotewebserver == INVALID_SOCKET)	{		free (szHostName);		free (szResource);		SendFailure (localwebuser, 404,			     "Could not connect to the outside host.", TRUE);		return FALSE;	}	/*	 * If we were asked for a POST, we need to also ask our server for	 * a POST - likewise for GET.  Connection: close is used to	 * tell the server to NOT support keep-alive.  We don't support	 * it and we don't want the server to.	 */	if (IsMethod (szLineBuffer, "POST"))	{		sprintf (szLineBuffer,			 "POST %s HTTP/1.0\r\nConnection: close\r\n",			 szResource);	}	else	{		sprintf (szLineBuffer,			 "GET %s HTTP/1.1\r\nConnection: close\r\n",			 szResource);	}	/* Send the server our request */	send_block (remotewebserver, szLineBuffer, strlen (szLineBuffer));	while (!finished)	{		/* Now sit here and collect all the headers from the		 * LAN user. */		strcpy (szLineBuffer, "");		if (GetLineFromSocketWait		    (localwebuser, szLineBuffer, nLineBuffer))		{			failcount = 0;			strcpy (szHeaderID, "");			GetHeaderID (szLineBuffer, szHeaderID,				     sizeof (szHeaderID));			/* If the header is content-length, we need to			 * record how much content to wait for (POST			 * support).			 */			if (!strcmp (szHeaderID, "CONTENT-LENGTH"))			{				szHeaderValue = strchr (szLineBuffer, ':');				contentlength = atoi (szHeaderValue + 1);			}			/* Strip of a trailing carriage-return. */			szHeaderValue = strchr (szLineBuffer, '\r');			if (szHeaderValue)				szHeaderValue[0] = '\0';			szHeaderValue = strchr (szLineBuffer, '\n');			if (szHeaderValue)				szHeaderValue[0] = '\0';			/* If there is nothing left (ie: blank line)			 * the headers are over. */			if (!strcmp (szLineBuffer, ""))				finished = TRUE;			/* Send on all headers *except* those containing			 * the word "Proxy."  Those are meant for US, but			 * we're too stupid to know what to do, so we			 * ignore them *all*.			 */			if ((!strstr (szHeaderID, "PROXY")) &&			    (strcmp (szHeaderID, "KEEP-ALIVE")))			{				strcat (szLineBuffer, "\r\n");				send_block (remotewebserver, szLineBuffer,					    strlen (szLineBuffer));			}		}		else		{			/* recv returning zero means the client			 * disconnected.  So we should clean up and abort.			 */			free (szHostName);			free (szResource);			closesocket (remotewebserver);			return FALSE;		}	}	/*	 * If we have any content to wait for (POST only) we keep	 * reading until we have it all, and pass it on verbatim. */	while (contentlength > 0)	{		len = recv (localwebuser, szLineBuffer, nLineBuffer, 0);		if (len > 0)		{			contentlength -= len;			send_block (remotewebserver, szLineBuffer, len);		}		else		{			/* recv returning zero means the client			 * disconnected.  So we should clean up and abort.			 */			free (szHostName);			free (szResource);			closesocket (remotewebserver);			return FALSE;		}	}	/* Take the first line from the webserver. */	strcpy (szLineBuffer, "");	GetLineFromSocketWait (remotewebserver, szLineBuffer, nLineBuffer);	if (!IsHttpReply (szLineBuffer))	{		/* If it's not an HTTP reply or something went wrong,		 * abort. */		free (szHostName);		free (szResource);		closesocket (remotewebserver);		SendFailure (localwebuser, 500, "Outside host not HTTP?",			     FALSE);		return FALSE;	}	/* The error code is 9 chars into the response line */	len = atoi (szLineBuffer + 9);	/* Display the response, and request info, for debugging. */	sprintf (szLineBuffer, "%i: %s: %s\n", len, szHostName, szResource);	free (szHostName);	free (szResource);	write (1, szLineBuffer, strlen (szLineBuffer));	/* Respond to the LAN client - with the same error */	sprintf (szLineBuffer, "HTTP/1.0 %i %i\n", len, len);	send_block (localwebuser, szLineBuffer, strlen (szLineBuffer));	finished = FALSE;	/* Read in a pile of data from the web server (this is your page.) */	while ((len =		recv (remotewebserver, szLineBuffer, nLineBuffer - 1, 0)) > 0)	{		/* Send it to the client */		send_block (localwebuser, szLineBuffer, len);	}	/* We don't care about the outside, it's over */	closesocket (remotewebserver);	return TRUE;}void *ChildThread (void *lpData){	SOCKET localwebuser;	char szLineBuffer[1024];	localwebuser = (*(SOCKET *) lpData);	free (lpData);#if (!defined(_WIN32_))&&defined(THREADING_SUPPORT)	pthread_detach (pthread_self ());#endif	/* Read in the first line from the request */	if (!GetLineFromSocketWait	    (localwebuser, szLineBuffer, sizeof (szLineBuffer)))		goto barfed;	/* Find out what the method is.  If it's GET or POST we can handle	 * it - if it's CONNECT, we try, but as mentioned above, I have no	 * idea what to do here.	 */	if (IsMethod (szLineBuffer, "GET") || IsMethod (szLineBuffer, "POST"))	{		ProcessGet (localwebuser, szLineBuffer,			    sizeof (szLineBuffer));	}	else	{		if (IsMethod (szLineBuffer, "CONNECT"))		{			ProcessConnect (localwebuser, szLineBuffer,					sizeof (szLineBuffer));		}		else		{			SendFailure (localwebuser, 501,				     "Only GET, POST and CONNECT requests are supported by this proxy.",				     TRUE);			goto barfed;		}	}      barfed:	/*	   We even don't care about the inside LAN user.  If they want us	   again, they'll call again.	 */	closesocket (localwebuser);	strcpy (szLineBuffer, "");	return NULL;}/*This big messy function processes each incoming request.*/BOOLHandleRequest (){	SOCKET localwebuser;	SOCKET *threadcopy;	SOCKADDR_IN sin;	SOCKLEN_T slt;	struct linger lyes;	unsigned long ip;#if defined(_WIN32_)&&defined(THREADING_SUPPORT)	HANDLE hThread;	DWORD tid;#endif#if (!defined(_WIN32_))&&defined(THREADING_SUPPORT)	pthread_t tid;#endif	slt = sizeof (sin);	/* Accept an incoming request, or wait till one arrives. */	printf ("Accepting new requests\n");	localwebuser = accept (server, (SOCKADDR *) & sin, &slt);	/* Security hack.  Find out who is talking to us, and if they're	 * not 127.0.0.1 (7f000001 in hex) or between 192.168.0.0 and	 * 192.168.255.255 (0xc0a80000 and 0xc0a8ffff) then our proxy is	 * not for them.  Hang them up, without warning. */	ip = ntohl (sin.sin_addr.s_addr);	if ((ip != 0x7f000001) && ((ip > 0xc0a8ffff) || (ip < 0xc0a80000)))	{		closesocket (localwebuser);		return FALSE;	}	/* Linger - as described above. */	lyes.l_onoff = 1;	lyes.l_linger = 10;	setsockopt (localwebuser, SOL_SOCKET, SO_LINGER, (char *) &lyes,		    sizeof (lyes));	threadcopy = malloc (sizeof (localwebuser));	*threadcopy = localwebuser;#ifndef THREADING_SUPPORT	ChildThread (threadcopy);	printf ("No thread support\n");#endif#if defined(_WIN32_)&&defined(THREADING_SUPPORT)	hThread =		CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE) ChildThread,			      threadcopy, 0, &tid);	CloseHandle (hThread);#endif#if (!defined(_WIN32_))&&defined(THREADING_SUPPORT)	pthread_create (&tid, NULL, ChildThread, threadcopy);#endif	return TRUE;}#ifndef _WIN32_/*UNIX trivia - when is a problem a problem?  When you don't ignore it.If you do nothing, well, you're not being ignorant enough.  You haveto be explicitly ignorant.*/voidignorer (int x){	signal (SIGPIPE, ignorer);}#endif /* !_WIN32_ *//*main() - you've seen that before.*/intmain (){#ifndef _WIN32_	signal (SIGPIPE, ignorer);#endif /* !_WIN32_ */	if (!StartServer ())	{		printf ("Could not initialise server.\n");		return (EXIT_FAILURE);	}	while (TRUE)	{		if (!HandleRequest ())		{			printf ("Proxy server couldn't handle request.\n");		}	}	return EXIT_SUCCESS;}#ifdef _WIN32_/* * WinMain is used to bootstrap a GUI app in Windoze.  I'm using this so * that proxy can be available in a version with no visible trace ;) */int WINAPIWinMain (HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR szCmd, int nCmdShow){	main ();}#endif /* _WIN32_ */