【问题标题】:How can I send received packet using raw sockets in C?如何使用 C 中的原始套接字发送接收到的数据包?
【发布时间】:2015-02-16 21:57:25
【问题描述】:

我写了一些代码,但没有用。我需要将传入的数据包发送到另一台主机(2.2.2.1)。此代码接收数据包但无法发送。我做错了什么? 我正在接收数据包,而不是将数据包复制到另一个数组,然后尝试使用 sendto() 函数发送它。

#include <unistd.h> 
#include <arpa/inet.h>
#include <stdio.h> 
#include <string.h> 
#include <sys/socket.h> 
#include <netinet/ip.h> 
#include <netinet/tcp.h>   

#define PCKT_LEN 8192

int main(){
    int s, s1;
    char buffer[PCKT_LEN];
    struct sockaddr saddr;
    struct sockaddr_in daddr;
    memset(buffer, 0, PCKT_LEN);

    s = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);
    if(s < 0){
        printf("socket() error");
        return -1;
    }
    int one = 1;
    const int *val = &one;
    if(setsockopt (s, IPPROTO_IP, IP_HDRINCL, val, sizeof(one))<0){
        printf("setsock");
        return -1;
    }
    s1 = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);
    if(s1 < 0){
        printf("sock2 error");
        return -1;
    }
    if(setsockopt (s1, IPPROTO_IP, IP_HDRINCL, val, sizeof(one)) < 0){
        printf("setsock");
        return -1;
    }
    int saddr_size = sizeof(saddr);
    int daddr_size = sizeof(daddr); 
    int header_size = sizeof(struct iphdr) + sizeof(struct tcphdr);
    unsigned int count;

    daddr.sin_family = AF_INET;
    daddr.sin_port = htons(1234);
    daddr.sin_addr.s_addr = inet_addr ("2.2.2.1");

    char *datagram, *data;
    datagram = (char*)calloc(4096, sizeof(char));
    struct iphdr *iph;
    struct tcphdr *tcph;
    int counter = 0;
    while(counter != 3){
        counter++;
        if(recvfrom(s, buffer, PCKT_LEN , 0, &saddr, &saddr_size) < 0){
            printf("recvfrom() error");
            return -1;
        }
        else{
            int i = header_size;
            int packet_len = ntohs(iph->tot_len);           
            memset(datagram, 0 ,4096);
            iph = (struct iphdr*) buffer;
            tcph = (struct tcphdr*) (buffer + sizeof(struct ip));
            data = buffer + sizeof(struct iphdr) + sizeof(struct tcphdr);

            i = 0;
            for(; i < packet_len-sizeof(struct iphdr)-sizeof(struct tcphdr); i++)
                printf("%c", data[i]);
                 printf("\n");

            memcpy(datagram, iph, sizeof(struct iphdr));
            memcpy(datagram+sizeof(struct iphdr), tcph , sizeof(struct tcphdr));
            memcpy(datagram+sizeof(struct iphdr)+sizeof(struct tcphdr), data,packet_len-sizeof(struct iphdr)-sizeof(struct tcphdr));

            iph->daddr = daddr.sin_addr.s_addr;

            if (sendto (s, datagram, packet_len, 0, &daddr, &daddr_size) < 0){
                printf("sendto() error");
                return -1;
            }
        }
    }
    close(s);
    close(s1);
    free(datagram);
    return 0;
}

【问题讨论】:

  • 标题在哪里?请也发布它们。
  • 您是否包含stdlib.hunistd.h?请删除之前的评论。
  • 不,我没有包含 stdlib.h,但我包含了 unistd.h。为什么?

标签: c linux sockets


【解决方案1】:
  1. 您没有包含stdlib.h,因此隐式声明了calloc(),因此编译器假定它返回int,这会导致很多问题。

    另外,不要使用calloc(),除非你真的想将数据初始化为0的,因为如果你在数据初始化方面遇到了问题,那么就不会发生任何不好的事情,而且你永远不会知道。使用malloc(),除非你以后要去memset(pointer, 0, size);,这也不错,就我而言,我总是使用malloc()

  2. 您也没有包含unistd.h,因此您也缺少close() 的声明。这不会引起问题,而只是因为它偶然返回int

  3. 你的sendto()调用也是错误的,最后一个参数应该是socklen_t类型并且你传递了一个int *,所以像这样修复它

    sendto (s, datagram, packet_len, 0, (struct sockaddr *)&daddr, daddr_size) < 0
    /*                                                            ^ no & here */
    
  4. 为避免在您要求编译器发出警告时出现的某些警告,您需要将这些警告声明为变量socklen_t

    socklen_t saddr_size = sizeof(saddr);
    socklen_t daddr_size = sizeof(daddr);
    

    你还需要上面看到的演员表(struct sockaddr *)&amp;daddr

  5. 最重要的问题是你尝试在没有初始化的情况下访问iph

    size_t packet_len = ntohs(iph->tot_len);
    

    这应该在iph = (struct iphdr *)buffer;之后。

    造成这种情况的原因恰恰是你的代码太乱了以至于很难注意到。

您可以通过使用编译器警告来避免这一切,就像这样

gcc -Wall -Wextra -Werror sourcefile.c -o executable

注意:更好地组织你的代码,它很难遵循,如果其他人必须审查它是不好的,就像我刚刚做的那样,对你来说也不好,因为当几个月后你再看它,你会很生那个写那烂摊子的人的气。

【讨论】:

  • 我做了你所说的一切,但我没有任何输出 - printf 不工作。但在 Wireshark 中,我只看到传入的数据包。
  • @user3425448 我已经更新了答案,原来你的代码还有另一个更重要的问题。
猜你喜欢
  • 1970-01-01
  • 2014-07-06
  • 2017-04-09
  • 2018-11-16
  • 1970-01-01
  • 2023-03-17
  • 1970-01-01
  • 2022-01-01
  • 1970-01-01
相关资源
最近更新 更多