【问题标题】:C - IPv6 raw ICMPv6 packet craftingC - IPv6 原始 ICMPv6 数据包制作
【发布时间】:2014-08-23 08:11:57
【问题描述】:

我目前正在尝试在 C 中创建原始 ICMPv6 数据包。我只找到了运行良好的 IPv4 示例,我看不出我在 IPv6 上做错了什么。

到目前为止我所知道的:

  • 我查看了一个旧的mailing-list post,发现我需要在 in6_addr 中设置一些变量(→ 错误 22),但除此之外它们正在使用:

    sock = socket(AF_INET6, SOCK_RAW, IPPROTO_RAW);
    
  • BCP38 project 上,他们显然使用 LIBNET。如果可以使用套接字,我更喜欢避免使用库。在这种情况下,如果不通过 socket.h,如何调用“网络 API”。

  • 我读到 hereIP_HDRINCL 在 IPv6 中没有等效项。 (但为什么?)

以下代码正在发送一个 ICMPv6 数据包,可能是由于 IPPROTO_ICMPV6 但带有内核添加的标头和非常糟糕的数据包内容...(目标地址错误,我还没有解决一些字节顺序问题)。它在 IPv6 中工作。 当我使用 IPPROTO_RAW 时,根本没有发送数据包......

有什么想法吗?提前致谢

#include <sys/types.h>
#include <sys/socket.h>

#include <netinet/in.h>
#include <netinet/ip6.h>
#include <netinet/icmp6.h>
#include <arpa/inet.h>

#include <netdb.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>

struct ipv6header {
    unsigned char priority:4, version:4;
    unsigned char flow[3];
    unsigned short int length;
    unsigned char nexthdr;
    unsigned char hoplimit;

    unsigned int saddr[4];
    unsigned int daddr[4];
};

struct icmpv6header {
    unsigned char type;
    unsigned char code;
    unsigned short int chk_sum;
    unsigned int body; 
};

int main()
{
    char* packet = (char*) malloc(sizeof(struct ipv6header)+sizeof(struct icmpv6header));
    struct ipv6header* ip = (struct ipv6header*) packet;
    struct icmpv6header* icmp = (struct icmpv6header*) (packet+sizeof(struct ipv6header));

    icmp->type = 128;
    icmp->code = 0;
    icmp->chk_sum = (0x6a13);
    icmp->body = htonl(1234);

    ip->version = 6;
    ip->priority = 0;
    (ip->flow)[0] = 0;
    (ip->flow)[1] = 0;
    (ip->flow)[2] = 0;
    ip->length = ((unsigned short int) sizeof(struct icmpv6header));
    ip->nexthdr = 58;
    ip->hoplimit = 255;

    struct sockaddr_in6 remote;
    remote.sin6_family = AF_INET6;
    remote.sin6_port = 0;
    remote.sin6_flowinfo = 0;
    remote.sin6_scope_id = 0;

    inet_pton(AF_INET6, "2001:470:x:x:y:y:y:dd7b", &(remote.sin6_addr));
    inet_pton(AF_INET6, "2001:470:x:x:bee:bee:bee:bee", &(ip->saddr));
    inet_pton(AF_INET6, "2001:470:x:x:y:y:y:dd7b", &(ip->daddr));

    int sock, optval;
    sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
    if(sock == -1)
    {
        printf("Error setting socket\n");
        return -1;
    }
    int ret = setsockopt(sock, IPPROTO_IPV6, IP_HDRINCL, &optval, sizeof(int));
    if(ret != 0) {
        printf("Error setting options %d\n", ret);
        return -1;
    }
    printf("Socket options done\n");

    int ret = sendto(sock, packet, ip->length, 0, (struct sockaddr *) &remote, sizeof(remote));

    if(ret != ip->length) {
        printf("Packet not sent : %d (%d)\n",ret,errno);
        return -1;
    }
    printf("Packet sent\n");

    return 0;
}

【问题讨论】:

  • 两个提示(但与您的问题无关):首先不要使用编译器定义的类型,如charshort intint。使用 &lt;stdint.h&gt; 头文件中的 int8_tint16_tint32_t(或其无符号变体)。其次,in C you should not cast the result of malloc.
  • 执行这个程序时你是root吗?你能发布sudo strace program的输出吗?
  • 感谢这些建议。我正在运行root。 strace 让我看到长度比预期的要短!谢谢。更正了类型和演员表。

标签: c sockets ipv6 icmp


【解决方案1】:

我遇到了类似的问题,并通过使用 IPV6_HDRINCL 而不是 IP_HDRINCL 解决了它。设置套接字选项时。

【讨论】:

    【解决方案2】:

    好的,经过几次代码重写,我成功了: 主要问题是,当我使用IPPROTO_RAW 时,由于长度错误,数据包被截断。结果,系统在它到达网络之前将其丢弃。 我也变了

    uint16_t daddr[8];
    

    uint16_t ipdst[8] = {htons(0x2001),htons(0x470),htons(x),htons(x),htons(y),htons(y),htons(y),htons(0xdd7b)};
    uint16_t ipsrc[8] = {htons(0x2001),htons(0x470),htons(x),htons(x),htons(0xbee),htons(0xbee),htons(0xbee),htons(0xbee)};
    
    int j = 0;
    for(j=0;j<=7;j++) {
        remote.sin6_addr.s6_addr16[j]=ipdst[j];
        ip->saddr[j]=ipsrc[j];
        ip->daddr[j]=ipdst[j];
    }
    

    谢谢!

    【讨论】:

      猜你喜欢
      • 2012-10-26
      • 2013-02-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-09-26
      相关资源
      最近更新 更多