Serveur proxy http (win32)

Description

C'est un mini-proxy écrit en C, mono-threadé et ne gérant que la commande GET du protocole HTTP/1.1 (une autre version provoquant une erreur).

J'ajouterais la gestion des erreurs sockets, une architecture multi-threads ainsi que le support de la commande POST quand l'envie m'en prendra...

C'est toutefois une bonne base de départ pour coder un proxy, donc si vous l'améliorez, n'hésitez pas à me faire parvenir votre travail ;)

Source / Exemple :


#define WIN32_LEAN_AND_MEAN

#include <windows.h>
#include <winsock2.h>
#include <stdlib.h>
#include <string.h>

#define HTTP_400_BEGIN "HTTP/1.1 200 OK\r\nServer: mProxy/1.0\r\nConnection: close\r\nContent-Type: text/html\r\n\r\n<html><head><title>400 - BAD REQUEST</title></head><body bgcolor=white text=black><h1>Unknown protocol</h1><blockquote><pre>\r\n"
#define HTTP_400_END "</pre></blockquote><hr><div align=right>mProxy by <a href=\"mailto:caranarchie@laposte.net\">Gab's</a></div></body></html>\r\n"

#define HTTP_404_BEGIN "HTTP/1.1 200 OK\r\nServer: mProxy/1.0\r\nConnection: close\r\nContent-Type: text/html\r\n\r\n<html><head><title>404 - NOT FOUND</title></head><body bgcolor=white text=black><h1>Unknown host</h1><blockquote><pre>\r\n"
#define HTTP_404_END "</pre></blockquote><hr><div align=right>mProxy by <a href=\"mailto:caranarchie@laposte.net\">Gab's</a></div></body></html>\r\n"

#define HTTP_501_BEGIN "HTTP/1.1 200 OK\r\nServer: mProxy/1.0\r\nConnection: close\r\nContent-Type: text/html\r\n\r\n<html><head><title>501 - NOT IMPLEMENTED</title></head><body bgcolor=white text=black><h1>Unknown request</h1><blockquote><pre>\r\n"
#define HTTP_501_END "</pre></blockquote><hr><div align=right>mProxy by <a href=\"mailto:caranarchie@laposte.net\">Gab's</a></div></body></html>\r\n"

void PutStr(char** r, char* s) {
  int x = strlen(s) + 1;
  int n = (*r) ? strlen(*r) : 0;

  • r = (char*) realloc(*r, x + n);
memcpy(*r + n, s, x); } int main(int argc, char* argv[]) { WSADATA WSAData; SOCKADDR_IN ServerSock; int ServerSockSize = sizeof(ServerSock); SOCKET Server = INVALID_SOCKET; SOCKADDR_IN ClientSock; int ClientSockSize = sizeof(ClientSock); SOCKET Client = INVALID_SOCKET; WSAStartup(MAKEWORD(2, 2), &WSAData); memset(&ServerSock, 0, ServerSockSize); ServerSock.sin_family = AF_INET; ServerSock.sin_port = htons(8080); ServerSock.sin_addr.s_addr = htonl(INADDR_ANY); Server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); bind(Server, (SOCKADDR*) &ServerSock, ServerSockSize); listen(Server, SOMAXCONN); while (1) { int i = 0; int n = 0; char c = 0; char* p = NULL; char* r = NULL; char* cv = NULL; int cl = 0; memset(&ClientSock, 0, ClientSockSize); Client = accept(Server, (SOCKADDR*) &ClientSock, &ClientSockSize); while (recv(Client, &c, 1, 0) > 0) { r = (char*) realloc(r, i + 1); r[i++] = c; if (c == '\r' || c == '\n') { if (++n == 4) break; } else n = 0; } r = (char*) realloc(r, i + 1); r[i] = '\0'; p = strstr(r, "Content-Length: "); if (p) { int i = 0; p += 16; while (*p != '\r' && *p != '\n') { cv = (char*) realloc(cv, i + 1); cv[i++] = *p; p++; } cl = atoi(cv); free(cv); cv = (char*) malloc(cl + 1); recv(Client, cv, cl, 0); cv[cl] = '\0'; } if (r[0] != 'G' || r[1] != 'E' || r[2] != 'T' || r[3] != ' ') { send(Client, HTTP_501_BEGIN, strlen(HTTP_501_BEGIN), 0); send(Client, r, i, 0); if (cv) send(Client, cv, cl, 0); send(Client, HTTP_501_END, strlen(HTTP_501_END), 0); } else { char* p = strstr(r, " HTTP/"); if (p[6] != '1' || p[7] != '.' || p[8] != '1') { send(Client, HTTP_400_BEGIN, strlen(HTTP_400_BEGIN), 0); send(Client, r, i, 0); if (cv) send(Client, cv, cl, 0); send(Client, HTTP_400_END, strlen(HTTP_400_END), 0); } else { char* p = r; char* host = NULL; char* port = NULL; char* location = NULL; HOSTENT* mProxyAddr = NULL; while (p[0] != 'H' || p[1] != 'o' || p[2] != 's' || p[3] != 't' || p[4] != ':' || p[5] != ' ') p++; p += 6; host = p; while (*p != ':' && *p != '\r' && *p != '\n') p++; if (*p == ':') {
  • p = '\0';
port = p + 1; while (*p != '\r' && *p != '\n') p++; } else port = "80";
  • p = '\0';
p = strstr(r, "://"); location = (p) ? p + 3 : r + 4; while (*location != '/') location++;
  • (strstr(location, " HTTP/")) = '\0';
mProxyAddr = gethostbyname(host); if (mProxyAddr) { SOCKADDR_IN mProxySock; int mProxySockSize = sizeof(mProxySock); SOCKET mProxy = INVALID_SOCKET; memset(&mProxySock, 0, mProxySockSize); memcpy(&mProxySock.sin_addr.s_addr, mProxyAddr->h_addr, mProxyAddr->h_length); mProxySock.sin_port = htons(atoi(port)); mProxySock.sin_family = AF_INET; mProxy = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (connect(mProxy, (SOCKADDR*) &mProxySock, mProxySockSize)) { send(Client, HTTP_404_BEGIN, strlen(HTTP_404_BEGIN), 0); send(Client, host, strlen(host), 0); send(Client, ":", 1, 0); send(Client, port, strlen(port), 0); send(Client, HTTP_404_END, strlen(HTTP_404_END), 0); } else { char* r = NULL; PutStr(&r, "GET "); PutStr(&r, location); PutStr(&r, " HTTP/1.1"); PutStr(&r, "\r\n"); PutStr(&r, "User-Agent: mProxy/1.0"); PutStr(&r, "\r\n"); PutStr(&r, "Host: "); PutStr(&r, host); PutStr(&r, ":"); PutStr(&r, port); PutStr(&r, "\r\n"); PutStr(&r, "Connection: close"); PutStr(&r, "\r\n"); PutStr(&r, "\r\n"); send(mProxy, r, strlen(r), 0); free(r); while (recv(mProxy, &c, 1, 0) > 0) send(Client, &c, 1, 0); shutdown(mProxy, SD_BOTH); closesocket(mProxy); } } else { send(Client, HTTP_404_BEGIN, strlen(HTTP_404_BEGIN), 0); send(Client, host, strlen(host), 0); send(Client, ":", 1, 0); send(Client, port, strlen(port), 0); send(Client, HTTP_404_END, strlen(HTTP_404_END), 0); } } } shutdown(Client, SD_BOTH); closesocket(Client); free(r); } }

Conclusion :


Je ne l'ai pas codé pour un projet particulier, donc les mises à jour seront plus que très certainement poussives...

A faire :
- gestion erreurs sockets
- passage en multithreads
- gestion commande POST
- gestion Referer, Cookie, etc...

Une fois ceci fait, il devrait etre fonctionnel pour la grande majorité des sites ;)

Codes Sources

A voir également

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.