jesusiniesta jesusiniesta - 2 months ago 7
C Question

How to create a simple Proxy to access web servers in C

I’m trying to create an small Web Proxy in C. First, I’m trying to get a webpage, sending a GET frame to the server.
I don’t know what I have missed, but I am not receiving any response. I would really appreciate if you can help me to find what is missing in this code.

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;
}


And this is the code I use to create the socket. I think this part is OK, but I copy it just in case.

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;
}


Thanks!

Answer

Since you didn't post the GetIP routine, I am not certain that your hostname lookup is correct, as from the looks of it, I am not sure that you are using inet_addr function correctly.

Nikolai has pointed out some very good points (and I fully agree). In fact you GET request is actually broken, and while I was testing it on my own local Apache web server on my system, it didn't work.

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));

should be replaced with

  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);

  ...

You should also close the socket before exiting the program. Enable standard C89/90 or C99 mode of your compiler (e.g. -std=c99 for gcc) and enable warnings (e.g. -Wall for gcc), and read them. And #include the necessary header files (assuming Linux in my case) for function prototypes:

 #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() */

There is some casting of pointers and structs in regards to the hostname / IP address resolving, which can be confusing and easy place to make a mistake, so verify that is working as you expect it is.

 in_addr_t ip;
 ...

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