此代码中有几个可能导致问题的开放式漏洞。真的,我赌第2点。
1-connectTCP真的有效吗?它是否真的返回了一个工作的 TCP 套接字。您可以在调用时轻松关闭那个检查错误,write()
而不是将它们强制转换为 void。
2-如果 LINELEN 是某个常数,例如数组的大小,\r\n
如果用户输入和数组末尾之间存在垃圾(很可能有一些 0),则放在数组末尾不会有太大帮助。sizeof(buf)
是最大的合法值,不一定是用户输入的大小。
3- double\r\n
不是必需的,一个 '\n' (unix 约定)就足够了。
4 - 使用交互式用户输入进行测试通常不是一个好主意,它会使代码更难调试和测试。
5 -n
如果读取缓冲区已满,请注意在缓冲区中的位置写入,它可能超过缓冲区末尾。
5 - 如果您想要的不仅仅是发送一个命令并获得答案,您将不得不编写更精细的代码来管理 write() 和 read()。正如另一位海报所建议的那样,选择可能是一个好主意(可能比线程简单)。您还可以阻止发送和接收命令之间的更多交替,但所有这些可能都是针对其他问题的。
下面是一段得到答案的工作代码(在 Linux 上使用 gcc 测试)。和你最初的没有什么不同,希望它能帮助你填补漏洞。
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/un.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
enum {
LINELEN = 1024
};
int main(){
char buf[LINELEN];
int n = 0;
unsigned int option_len;
int allow_reuse = 1;
int sck = socket(PF_INET, SOCK_STREAM, 0);
char * ip = "www.google.com";
char * command = "GET http://www.google.com\n";
/* connect to socket */
struct sockaddr_in s;
memset(&s, 0, sizeof(struct sockaddr_in));
s.sin_family = AF_INET;
s.sin_port = htons(80);
s.sin_addr.s_addr = inet_addr(ip);
if (s.sin_addr.s_addr == INADDR_NONE) {
struct hostent *h = gethostbyname(ip);
if (!h) {
printf("DNS resolution failed for %s\n", ip);
exit(0);
}
s.sin_addr.s_addr = *((int*)(*(h->h_addr_list)));
}
connect(sck, (struct sockaddr*)&s, sizeof(s));
/* write command */
printf("Write to socket...\n");
write(sck, command, strlen(command));
/* get answer */
printf("Start reading from socket...\n");
while((n = read(sck, buf, LINELEN-1)) > 0) {
buf[n] = '\0'; /* ensure null-terminated */
fputs( buf, stdout );
}
}