我一直在努力解决这个问题,但我想我需要你的帮助。我是新手,我似乎找不到问题。
当源和目标都设置为 localhost 时,代码可以工作。但是,当我使用本地主机以外的真实 IP 地址作为源和目标时,它会失败。
sendto()
返回 -1。
我不知道如何让 `sendto() 吐出有关错误的更多详细信息,或者是什么导致它返回 -1。
顺便说一句,我正在运行 Linux。
这是代码:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#define MAX_PACKET_SIZE 4096
u_int32_t src_addr, dst_addr;
u_int16_t src_port, dst_port;
unsigned short csum (unsigned short *buf, int nwords)
{
unsigned long sum;
for (sum = 0; nwords > 0; nwords--)
sum += *buf++;
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
return (unsigned short)(~sum);
}
void setup_ip_header(struct iphdr *iph)
{
iph->saddr = src_addr; // SOURCE IP ADDRESS
iph->daddr = dst_addr; // TARGET IP ADDRESS
iph->ihl = 5;
iph->version = 4;
iph->tos = 0;
iph->tot_len = htons(sizeof(struct iphdr) + sizeof(struct tcphdr));
iph->id = htonl(54321); /*setup any arbitrary number for id */
iph->frag_off = 0;
iph->ttl = MAXTTL;
iph->protocol = 6; /* upper layer protocol, TCP*/
iph->check = 0;
}
void setup_tcp_header(struct tcphdr *tcph)
{
tcph->source = htons(src_port); // SOURCE PORT
tcph->dest = htons(dst_port); // TARGET PORT
tcph->seq = random();
tcph->ack_seq = 0;
tcph->res2 = 0;
tcph->doff = 5;
tcph->syn = 1;
tcph->window = htonl(65535);
tcph->check = 0;
tcph->urg_ptr = 0;
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
struct sockaddr_in sin;
const char *src_addr_str = "192.168.1.50";
src_addr = inet_addr(src_addr_str);
src_port = 777;
const char *dst_addr_str = "192.168.1.51";
dst_addr = inet_addr(dst_addr_str);
dst_port = 888;
char datagram[MAX_PACKET_SIZE];
struct iphdr *iph = (struct iphdr *)datagram;
struct tcphdr *tcph = (struct tcphdr *)((u_int8_t *)iph + (5 * sizeof(u_int32_t)));
char new_ip[sizeof "255.255.255.255"];
int src_socket = socket(PF_INET, SOCK_RAW, IPPROTO_TCP);
if(src_socket < 0){
fprintf(stderr, "Could not open raw socket.\n");
exit(-1);
}
/* a IP_HDRINCL call, to make sure that the kernel knows
* the header is included in the data, and doesn't insert
* its own header into the packet before our data
*/
int tmp = 1;
const int *val = &tmp;
if(setsockopt(src_socket, IPPROTO_IP, IP_HDRINCL, val, sizeof (tmp)) < 0){
fprintf(stderr, "Error: setsockopt() - Cannot set HDRINCL!\n");
exit(-1);
}
// SETUP DETAILS ABOUT THE TARGET MACHINE
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = dst_addr;
sin.sin_port = htons(dst_port);
// Clear the data
memset(datagram, 0, MAX_PACKET_SIZE);
// Set appropriate fields in headers
setup_ip_header(iph);
setup_tcp_header(tcph);
iph->check = csum ((unsigned short *) datagram, iph->tot_len >> 1);
for(;;){
int ret = sendto(src_socket, datagram, iph->tot_len, 0, (struct sockaddr *) &sin, sizeof(sin));
if(ret == -1)
{
fprintf(stderr, "sendto() error!!!.\n");
}
else
{
fprintf(stdout, "Flooding %s at %u...\n", dst_addr_str , dst_port);
}
sleep(1);
}
return 0;
}
我还注意到
sizeof(sin)
仅返回 16,不确定这是否正常。这正常吗?
如何让编译器在遇到错误时吐出有关错误的更多信息?
您将
iph->tot_len
设置为 htons()
的结果,然后将该值按原样传递给 sendto()
作为数据大小。 iph->tot_len
字段确实需要采用网络字节顺序,但您赋予 sendto()
的值需要采用主机字节顺序。
sendto(..., ntohs(iph->tot_len), ...);
最好将长度存储在单独的变量中
u_short len = sizeof(struct iphdr) + sizeof(struct tcphdr);
...
iph->tot_len = htons(len);
...
sendto(..., len, ...);