Как создать простой прокси для доступа к веб-серверам в C - PullRequest
0 голосов
/ 30 декабря 2010

Я пытаюсь создать небольшой веб-прокси в C. Сначала я пытаюсь получить веб-страницу, отправляя кадр GET на сервер. Я не знаю, что я пропустил, но я не получаю никакого ответа. Буду очень признателен, если вы поможете мне найти то, чего не хватает в этом коде.

int main (int argc, char** argv) {
   int cache_size,     //size of the cache in KiB
       port,
       port_google = 80,
       dir,
       mySocket,
       socket_google;

   char google[] = "www.google.es", ip[16];
   struct sockaddr_in socketAddr;
   char buffer[10000000];

   if (GetParameters(argc,argv,&cache_size,&port) != 0)
       return -1;

   GetIP (google, ip);
   printf("ip2 = %s\n",ip);

   dir = inet_addr (ip);
   printf("ip3 = %i\n",dir);

   /* Creation of a socket with Google */
   socket_google = conectClient (port_google, dir, &socketAddr);
   if (socket_google < 0) return -1;
   else printf("Socket created\n");

   sprintf(buffer,"GET /index.html HTTP/1.1\r\n\r\n");
   if (write(socket_google, (void*)buffer, MESSAGE_LENGTH+1) < 0 )
       return 1;
   else printf("GET frame sent\n");

   strcpy(buffer,"\n");
   read(socket_google, buffer, sizeof(buffer));

   // strcpy(message,buffer);
   printf("%s\n", buffer);

   return 0;
}

И этот код я использую для создания сокета. Я думаю, что эта часть в порядке, но я копирую это на всякий случай.

int conectClient (int puerto, int direccion, struct sockaddr_in *socketAddr) {
   int mySocket;
   char error[1000];

   if ( (mySocket = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
       printf("Error when creating the socket\n");
       return -2;
   }

   socketAddr->sin_family = AF_INET;
   socketAddr->sin_addr.s_addr = direccion;
   socketAddr->sin_port = htons(puerto);

   if (connect (mySocket, (struct sockaddr *)socketAddr,sizeof (*socketAddr)) == -1) {
       snprintf(error, sizeof(error), "Error in %s:%d\n", __FILE__, __LINE__);
       perror(error);
       printf("%s\n",error);
       printf ("-- Error when stablishing a connection\n");
       return -1;
   }
   return mySocket;
}

Спасибо!

Ответы [ 3 ]

2 голосов
/ 30 декабря 2010

Во-первых, вы не проверяете, сколько байтов вызов write(2) фактически записал в сокет. Возвращаемое значение вызова говорит вам об этом. То же самое для read(2). TCP-сокет является двунаправленным потоком, поэтому, как правило, всегда выполняйте оба цикла в цикле до тех пор, пока не будет передано ожидаемое количество байтов, не будет прочитано EOF (нулевой возврат от read(2)) или возникла ошибка (которой вы не являетесь проверять при чтении либо).

Тогда HTTP - довольно сложный протокол. Ознакомьтесь с RFC 2616 , особенно с управлением соединениями прикладного уровня и кодировками передачи.

Редактировать 0:

Хм, нет такой вещи как "простой" прокси. Вам необходимо управлять несколькими соединениями (по крайней мере, клиент-прокси и прокси-сервер), поэтому, вероятно, лучше всего изучить select(2) / poll(2) / epoll(4) / kqueue(2) семейство системных вызовов, которые позволяют вам мультиплексировать I / O. Обычно это сочетается с неблокирующими розетками. Посмотрите на вспомогательные библиотеки, такие как libevent. Посмотрите, как это делается на хороших веб-серверах / прокси, таких как nginx . Звучит так, будто вам многое предстоит узнать, но не волнуйтесь, это весело :) 1040 *

1 голос
/ 25 июня 2011

На самом деле, я реализовывал небольшой веб-прокси, используя мою библиотеку rzsocket ссылка на него .

Одна из самых сложных вещей, которые я обнаружил при реализации веб-проксиВозможно, это также может быть вашей проблемой, было то, что для того, чтобы прокси-сервер работал правильно, мне пришлось установить для keep-alive настроек значение false.Один из способов сделать это в FireFox - получить доступ к адресу about: config и установить значение network.http.proxy.keep-alive в false.

.
1 голос
/ 31 декабря 2010

Поскольку вы не опубликовали подпрограмму GetIP, я не уверен, что ваш поиск имени хоста правильный, так как, судя по всему, я не уверен, что вы используете функцию inet_addr правильно.

Николай указал на очень хорошие моменты (и я полностью согласен).На самом деле ваш GET запрос фактически не работает, и пока я тестировал его на своем локальном веб-сервере Apache в моей системе, он не работал.

sprintf(buffer,"GET /index.html HTTP/1.1\r\n\r\n");
if (write(socket_google, (void*)buffer, LONGITUD_MSJ+1) < 0 )
    return 1;
else printf("GET frame sent\n");
...

strcpy(buffer,"\n");
read(socket_google, buffer, sizeof(buffer));

следует заменить на

  snprintf(buffer, sizeof(buffer), 
      "GET / HTTP/1.1\r\nHost: %s\r\nUser-Agent: TEST 0.1\r\n\r\n", 
      google);

  if (write(socket_google, buffer, strlen(buffer)+1) < 0 ) {
      close(socket_google);
      return 1;
  } else 
      printf("GET frame sent\n");
  ...

  buffer[0] = '\0';
  /* Read message from socket */
  bytes_recv = read(socket_google, buffer, sizeof(buffer));
  if (bytes_recv < 0) {
       fprintf(stderr, "socket read error: %s\n", strerror(errno));
       close(socket_google);
       exit(10);
  }

  buffer[bytes_recv] = '\0';    /* NUL character */

  /* strcpy(message,buffer); */
  printf("%s\n", buffer);

  ...

Вы также должны close сокет перед выходом из программы.Включите стандартный режим C89 / 90 или C99 вашего компилятора (например, -std=c99 для gcc), включите предупреждения (например, -Wall для gcc) и прочитайте их.И #include необходимые заголовочные файлы (с учетом Linux в моем случае) для прототипов функций:

 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 #include <errno.h>
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <netdb.h>      /* for gethostbyname() */

Существует некоторое приведение указателей и struct s в отношении имени хоста/ Разрешение IP-адреса, которое может сбить с толку и легко допустить ошибку, поэтому убедитесь, что оно работает так, как вы ожидаете.

 in_addr_t ip;
 ...

 GetIP(google, &ip);   /* I changed the parameters */
 printf("IP address = %x (%s)\n", 
     ip, 
     inet_ntoa(*((struct in_addr*)&ip)));
...