Sendto 仅适用于本地主机

问题描述 投票:0回答:1

我一直在努力解决这个问题,但我想我需要你的帮助。我是新手,我似乎找不到问题。

当源和目标都设置为 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,不确定这是否正常。这正常吗?

如何让编译器在遇到错误时吐出有关错误的更多信息?

c++ sockets networking
1个回答
0
投票

您将

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, ...);
© www.soinside.com 2019 - 2024. All rights reserved.