我正在创建一个简单的代理来过滤网站,这是我网络课程中的一项任务,所以不要介意过滤后的单词;)
它的工作可以说是好的,我唯一的问题是,当用户试图在浏览器中访问的页面包含“坏词”时。由于对所请求的网络服务器的响应来自包,因此在实际包含错误单词的数据包到达时,第一个(大多数时候标题)已经被发送到浏览器。 当代理检测到错误的单词时,它应该重定向到我老师给出的网站。问题是,新网站的响应当然有自己的标题,但由于浏览器之前已有一个标题,他将这个新标题视为简单文本,并将其显示为网页。
有没有更好的重定向方法,这可以解决这个问题,还是有另一种方法,比如让浏览器删除最后收到的消息?
哦,这是我的代码:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <signal.h>
#include <fcntl.h>
#define BACKLOG 10 // how many pending connections queue will hold
#define MAXDATASIZE 100 // max number of bytes we can get at once
#define PORT "1025"
// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa)
{
if (sa->sa_family == AF_INET) {
return &(((struct sockaddr_in*)sa)->sin_addr);
}
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
int main(void)
{
int sock_fd, new_fd, web_fd, re_fd;
struct addrinfo hints, *servinfo, *p;
struct sockaddr_storage their_addr;
socklen_t sin_size;
int yes=1;
char s[INET6_ADDRSTRLEN];
int rv, bytes_recv, bytes_sent, total_bytes, i = 0, x, showget = 0, showpart = 0, counter = 0;
char getter[1000], link[1000], url[500], buffer[4096], *redirect;
bool bad_content = 0;
printf("Starting server.\n");
//printf("Give port: \n");
//scanf("%s", &port);
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
if ((rv = getaddrinfo(NULL, PORT, &hints, &servinfo)) != 0)
{
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
return 1;
}
for(p = servinfo; p != NULL; p = p->ai_next)
{
if ((sock_fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1)
{
perror("server: socket");
continue;
}
if (setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1)
{
perror("setsockopt");
exit(1);
}
if (bind(sock_fd, p->ai_addr, p->ai_addrlen) == -1)
{
close(sock_fd);
perror("server: bind");
continue;
}
break;
}
if (p == NULL)
{
fprintf(stderr, "server: failed to bind\n");
return 2;
}
freeaddrinfo(servinfo);
if (listen(sock_fd, BACKLOG) == -1)
{
perror("listen");
exit(1);
}
printf("server: waiting for connections...\n");
while(1)
{
sin_size = sizeof their_addr;
new_fd = accept(sock_fd, (struct sockaddr *)&their_addr, &sin_size);
if (new_fd == -1)
{
perror("accept");
continue;
}
inet_ntop ( their_addr.ss_family, get_in_addr((struct sockaddr *)&their_addr),
s, sizeof s);
printf("\n--------------------------------------------\n"
"server: got connection from %s\n", s);
//-----------RECEIVING GET FROM BROWSER-----------------------------------------------
printf("server: Receiving GET from browser ... ");
memset(&getter, 0, sizeof getter);
if (!bad_content)
{
read(new_fd, getter, 4096);
}
else
{
while (1)
{
getter [i] = redirect [i];
++i;
if (redirect [i] == 0)
{
break;
}
}
}
printf("Done\n");
/*if (strstr(getter, "favicon") != NULL)
{
continue;
}*/
//showget = 1;
if (showget)
{
printf( "----------GET------------\n"
"%s\n"
"-------------------------\n", getter);
}
memset(&url, 0, sizeof url);
//-----------EXTRACTING HOST----------------------------------------------------------
printf("server: Extracting host address ... ");
i = 0;
while (1)
{
if (!(getter[i] == '/' && getter[i+1] == '/'))
{
i++;
}
else
{
i++;i++;
break;
}
}
x=i;
while (1)
{
url [i-x] = getter [i];
++i;
if (getter [i] == ' ' || getter [i] == ':' ||
getter [i] == '/')
{
break;
}
}
char host[strlen(url)];
memset (&host, 0, sizeof host );
i = 0;
while (1)
{
host [i] = url [i];
++i;
if (url [i] == 0 || url [i] == '/' || url [i] == ' ')
{
break;
}
}
printf("Done\n");
//-----------CLIENT------------------------------------------------------------------
printf("Starting client.\n");
printf("client: Connecting to: \"%s\" ... ", host);
//-----------CONNECTING TO WEB-------------------------------------------------------
if ((rv = getaddrinfo( host, "80", &hints, &servinfo)) != 0)
{
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
}
p=servinfo;
for(p; p != NULL; p = p->ai_next)
{
if ((web_fd = socket(p->ai_family, p->ai_socktype,
p->ai_protocol)) == -1)
{
perror("client: socket");
continue;
}
if (connect(web_fd, p->ai_addr, p->ai_addrlen) == -1)
{
close(web_fd);
perror("client: connect");
continue;
}
break;
}
if (p == NULL)
{
fprintf(stderr, "client: failed to connect, try again!\n");
continue;
}
memset(&s, 0, sizeof s );
inet_ntop ( p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr),
s, sizeof s);
printf("Done\n");
freeaddrinfo(servinfo);
//fcntl(web_fd, F_SETFL, O_NONBLOCK);
//-----------SENDING GET REQUEST-----------------------------------------------------
printf("client: Forwarding GET to \"%s\" ... ", s);
i = 0;
while (1)
{
link[i] = getter[i];
if ( link [i] == 13)
{
counter++;
}
else if (counter == 2)
{
break;
}
i++;
}
if ((bytes_sent = send(web_fd, link, strlen(link), 0)) < strlen(link))
{
fprintf(stderr, "client: failed to send entire GET...\n");
return 0;
}
printf("Done\n");
memset(&buffer, 0, sizeof buffer );
//-----------RECEIVING RESPONSE-------------------------------------------------------
printf("client: Receiving response.\n");
total_bytes = 0;
while (1)
{
bytes_sent = 0; bytes_recv = 0;
memset(&buffer, 0, sizeof buffer );
if ((bytes_recv = recv(web_fd, buffer, 4096, 0)) == 0) //receive part
{
break;
}
printf("Received part (%d bytes)\n", bytes_recv);
if( (strstr(buffer, "SpongeBob") != NULL) || //checking for bad words
strstr(buffer, "Britney Spears") != NULL ||
strstr(buffer, "Paris Hilton") != NULL ||
strstr(buffer, "Norrk\224ping") != NULL )
{
printf("Bad site! Redirecting ...\n");
//-----------CONNECTING TO WEB-------------------------------------------------------
printf("client: Connecting to: \"www.ida.liu.se\" ... ");
if ((rv = getaddrinfo( "www.ida.liu.se", "80", &hints, &servinfo)) != 0)
{
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
}
p=servinfo;
for(p; p != NULL; p = p->ai_next)
{
if ((re_fd = socket(p->ai_family, p->ai_socktype,
p->ai_protocol)) == -1)
{
perror("client: socket");
continue;
}
if (connect(re_fd, p->ai_addr, p->ai_addrlen) == -1)
{
close(re_fd);
perror("client: connect");
continue;
}
break;
}
if (p == NULL)
{
fprintf(stderr, "client: failed to connect, try again!\n");
continue;
}
memset(&s, 0, sizeof s );
inet_ntop ( p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr),
s, sizeof s);
printf("Done\n");
freeaddrinfo(servinfo);
//fcntl(web_fd, F_SETFL, O_NONBLOCK);
//-----------SENDING GET REQUEST-----------------------------------------------------
printf("client: Forwarding GET to \"%s\" ... ", s);
redirect = "GET /~TDTS04/labs/2011/ass2/error2.html\r\n"
"Host: www.ida.liu.se\r\n\r\n";
if ((bytes_sent = send(re_fd, redirect, strlen(redirect), 0)) < strlen(redirect))
{
fprintf(stderr, "client: failed to send entire GET...\n");
return 0;
}
printf("Done\n");
memset(&buffer, 0, sizeof buffer );
//-----------RECEIVING RESPONSE-------------------------------------------------------
printf("client: Receiving response.\n");
total_bytes = 0;
while (1)
{
bytes_sent = 0; bytes_recv = 0;
memset(&buffer, 0, sizeof buffer );
if ((bytes_recv = recv(re_fd, buffer, 4096, 0)) == 0) //receive part
{
break;
}
printf("Received part (%d bytes)\n", bytes_recv);
//showpart = 1;
if (showpart)
{
printf( "----------PART-----------\n"
"%s\n"
"-------------------------\n", buffer);
}
bytes_sent = send(new_fd, buffer, strlen(buffer), 0);
printf("Sent part (%d bytes)\n", bytes_sent);
total_bytes += bytes_sent;
}
break;
}
//showpart = 1;
if (showpart)
{
printf( "----------PART-----------\n"
"%s\n"
"-------------------------\n", buffer);
}
bytes_sent = send(new_fd, buffer, strlen(buffer), 0);
printf("Sent part (%d bytes)\n", bytes_sent);
total_bytes += bytes_sent;
}
close(web_fd);
printf("Done\nBytes sent to browser: %d\n", total_bytes);
puts("\nEnd client\n");
close(new_fd);
}
close (sock_fd);
return 0;
}
答案 0 :(得分:3)
在将任何数据发送到客户端之前,您需要保留代理中的所有数据。这意味着您还必须了解足够的HTTP协议以了解响应何时完成。如果您需要支持HTTP / 1.1,则意味着您需要支持分块编码。
此外,您的重定向不是合法的HTTP。它有一个请求标头,但没有指定支持请求标头的HTTP版本。
你还有很多其他错误,包括访问数组越界,并使用strlen
来获取除C风格字符串以外的其他内容。您调用read
并丢弃返回值,因此您不知道必须发送到另一端的字节数。老实说,似乎你正在尝试一项超出基本编程知识的编程任务。在编写过滤代理之前,正确处理二进制数据的事情就已经过去了。