分段错误将指针传递给函数

时间:2017-10-31 13:20:53

标签: c network-programming segmentation-fault

因此,在从parseEther方法调用parseIP函数时发生分段错误 我真的不知道为什么我会遇到分段错误,我只是拿着我的数据包指针并添加以太网头的长度(14)。
打印地址的输出给出了十六进制的十六进制地址,所以我知道指针指向内存中的正确位置。尽管如此,我在传递它时仍然会出现分段错误? 我错过了一些令人眼花缭乱的事情吗? 示例输出: https://s1.postimg.org/96owsptn8v/seg_fault.png
修改
我只是从parseIP中取出代码并将其放在调用它的if语句中,它的工作原理非常好。真奇怪。有人有任何想法吗?

void parseIP(const unsigned char *packet)
{
    printf("before we cast ip header");
    struct ip *ip_header = (struct ip*) *packet;
    printf("Before we initialise length");
    short length = ip_header -> ip_len;
    printf("Before we initialise headerlength");
    int headerlength = ntohs(ip_header-> ip_hl); //iphdr points to header of network packet

    printf("No segmentation fault here! \n");

    printf("\n Source Ip address \n");
    printf("%s", inet_ntoa(ip_header -> ip_src));
    printf("\n Destination Ip address \n");
    printf("%s", inet_ntoa(ip_header -> ip_dst));

    int data_bytes = length - headerlength;
    const unsigned char *payload = packet + headerlength;
}

void parseEther(const unsigned char *packet, int length)
{

    int i;
    int pcount = 0;
    struct ether_header *eth_header = (struct ether_header *) packet;

    printf("\n\n === PACKET %ld HEADER ===", pcount);
    printf("\nSource MAC: ");

    for (i = 0; i < 6; ++i)
    {
        printf("%02x", eth_header->ether_shost[i]);
        if (i < 5)
        {
            printf(":");
        }
    }

    printf("\nDestination MAC: ");
    for (i = 0; i < 6; ++i)
    {
        printf("%02x", eth_header->ether_dhost[i]);
        if (i < 5)
        {
            printf(":");
        }   
    }

    int data_bytes = length - ETH_HLEN;
    printf(" \n total length - %d -- length of header - %d -- remaining length - %d \n", length, ETH_HLEN, data_bytes);
    printf("Packet address - %p\n", packet);
    const unsigned char *payload = packet + ETH_HLEN;
    printf("Payload address - %p\n", payload);
    //payload pointer now points to start of the network header

    printf("\nType: %d\n", ntohs(eth_header->ether_type));
    if(ntohs(eth_header->ether_type) == 0x0806)
    {
      printf("ARP detected \n");
     // parseARP(payload);
    }
    else if(ntohs(eth_header->ether_type) == 0x0800)
    {
      printf("\nIP detected\n");
      parseIP(payload);
    }
}

1 个答案:

答案 0 :(得分:2)

  

我错过了一些令人眼花缭乱的事情吗?

我想这取决于你的显而易见的标准,但肯定是错的:

struct ip *ip_header = (struct ip*) *packet;

函数参数packetconst unsigned char *,因此该语句将其指向的单个unsigned char的值转换为指针,然后将其用作指向a的指针struct ip。这几乎肯定会产生未定义的行为,因为它违反了严格的别名规则,并且它产生你真正想要的行为的机会基本上是零。这样做:

struct ip *ip_header = (struct ip*) packet;

但是,请注意,将结构类型映射到原始字节数组是一件棘手的事情。获取正确的成员顺序和数据类型通常不是那么难,但C允许结构布局在结构成员之间(和之后)包含任意填充。特别是,尽管大多数C实现提供了避免这种情况的机制,但它没有标准的机制。

在这种情况下,你有这个问题。您的struct ipstruct ether_header不仅受其约束,系统的struct in_addr也是如此。虽然您可以控制自己的结构的声明,但假设您可以将struct in_addr映射到原始数据包数据上是危险的,因为您正在为inet_ntoa生成参数。