IPv6 Hop by Hop Extension报头数据包不会在接收器上显示

时间:2014-04-18 01:53:15

标签: c linux-kernel network-programming ipv6 raw-sockets

我试图通过使用原始套接字添加新的Hop by Hop选项。由于内核不处理无法识别的选项类型,因此会发送无法识别的参数的ICMP错误。

我尝试通过添加新选项作为已知选项来更改内核中的一些内容,因此内核不会向我发送错误。到目前为止这是成功的...但问题是,接收器没有收到数据包。使用Wireshark,它显示数据包在接口处被截获,但不会显示在用户空间中。

我的代码如下,

在发件人处,它会在最后打印"已发送的数据" ,但接收者不会打印任何内容。

server.c

#include <sys/socket.h>
#include <errno.h>
#include <sys/types.h>
#include <netinet/ip6.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <netinet/in.h>
#include <time.h>

#define DEST "::1"
#define IPV6_TLV_OPTX 0xEE
#define IPV6_TLV_ROUTERALERT 5

short unsigned sequence_number();
short unsigned number;


int main(void)
{

int j=0, pton_fd;
int i=0;
struct ip6_hbh hbh_hdr;
struct msghdr msg = {};
struct cmsghdr *cmsg;
int cmsglen;
char src_ip[INET6_ADDRSTRLEN], dst_ip[INET6_ADDRSTRLEN];
int s,status;
struct sockaddr_in6 daddr;
char packet[40];
//-----members for ancillary data-----------

struct iovec iov[2];    
void *extbuf;
socklen_t extlen;
int currentlen;
void *databuf;
int offset;
uint8_t value;
uint8_t value1;
uint8_t value2;

/* point the iphdr to the beginning of the packet */
struct ip6_hdr *ip = (struct ip6_hdr *)packet;  

if ((s = socket(AF_INET6, SOCK_RAW, IPPROTO_RAW)) < 0) {
    perror("error:");
    exit(EXIT_FAILURE);
}

    int setsock_offset = 2;
if(setsockopt(s, IPPROTO_IPV6, IPV6_CHECKSUM, &setsock_offset, sizeof(setsock_offset) < 0))
{
   perror("setsockopt");
   exit(EXIT_FAILURE);
}


daddr.sin6_family = AF_INET6;
daddr.sin6_port = 0; /* not needed in SOCK_RAW */
daddr.sin6_scope_id = if_nametoindex("eth0");

pton_fd = inet_pton(AF_INET6, "fe80::a00:27ff:fe30:9ae9", (struct in6_addr *)&daddr.sin6_addr.s6_addr);

if (pton_fd == 0)
{
    printf("Does not contain a character string representing a network address");
    exit(EXIT_FAILURE);
}
else if (pton_fd < 0)
{
    perror("pton()");
    exit(EXIT_FAILURE);
}

ip->ip6_flow = htonl ((6<<28) | (0<<20) | 0);
ip->ip6_plen = htons (8);
ip->ip6_nxt = 0;
ip->ip6_hops = 64;


if ((status = inet_pton(AF_INET6, "fe80::921b:eff:fe03:637d", &(ip->ip6_src))) != 1)
{
        fprintf(stderr,"inet_pton() failed.\nError message: %s",strerror(status));      exit(EXIT_FAILURE);
}


if ((status = inet_pton(AF_INET6, "fe80::a00:27ff:fe30:9ae9", &(ip->ip6_dst))) != 1)
{
        fprintf(stderr,"inet_pton() failed.\nError message: %s",strerror(status));      exit(EXIT_FAILURE);
}


// Specifying the ancillary data for Hop-by-Hop headers
currentlen = inet6_opt_init(NULL,0);
if (currentlen == -1){
    perror("1st opt_init");
    exit(EXIT_FAILURE);
}
printf("Hop by Hop length: %d\n", currentlen);

// Setting Hop by Hop extension header next field
//hbh_hdr.ip6h_nxt = 59;
//hbh_hdr.ip6h_len = 0;

currentlen = inet6_opt_append(NULL, 0, currentlen, IPV6_TLV_ROUTERALERT, 2, 1, NULL);
if (currentlen == -1) {
    printf("ERROR NO: %d\n",errno);
    //perror("1st opt_append");
    fprintf(stderr, "append error %s, %s\n",strerror(errno),strerror(currentlen));
    exit(EXIT_FAILURE);
}

currentlen = inet6_opt_finish(NULL, 0, currentlen);
if (currentlen == -1) {
    perror("1st opt_finish");
    exit(EXIT_FAILURE);
}

printf("currentlen: %d\n",currentlen);
extlen = currentlen;

cmsglen = CMSG_SPACE(extlen);
cmsg = malloc(sizeof(cmsglen));
if (cmsg == NULL) {
    perror("msg malloc");
    exit(EXIT_FAILURE);
}

cmsg->cmsg_len = CMSG_LEN(extlen);
cmsg->cmsg_level = IPPROTO_IPV6;
cmsg->cmsg_type = IPV6_HOPOPTS;
extbuf = CMSG_DATA(cmsg);

extbuf = malloc(extlen);
printf("Size of extbuf: %ld",sizeof(extbuf));

if (extbuf == NULL) {
    perror("malloc");
    exit(EXIT_FAILURE);
}


printf("Extenlen: %d\n",extlen);

//hbh_hdr.ip6h_nxt = 59;
currentlen = inet6_opt_init(extbuf, extlen);
if (currentlen == -1) {
    perror("2nd opt_init");
    exit(EXIT_FAILURE);
}

//extbuf = (unsigned char*)extbuf;
//char ip6hop_nexth_value = 59;
*(unsigned char*)(extbuf) = 59;
unsigned char* temp = extbuf;

//for(i=0; i<extlen;i++) {
//  printf("Ext buffer is: %d\n",*temp);
//  temp++;
//}

currentlen = inet6_opt_append(extbuf, extlen, currentlen, IPV6_TLV_ROUTERALERT, 2, 1, &databuf);
if (currentlen == -1) {
    perror("append() error");
    exit(EXIT_FAILURE);
}

printf("len after append:%d\n", currentlen);

//insert value for the version and flags 
offset = 0;
value = 0x11;
offset = inet6_opt_set_val(databuf, offset, &value, sizeof(value));

//value1 = 0x01;

//printf("Data buffer is: %x\n",databuf);
//offset = inet6_opt_set_val(databuf, offset, &value1, sizeof(value1));

value2 = 0x01;
offset = inet6_opt_set_val(databuf, offset, &value2, sizeof(value2));

currentlen = inet6_opt_finish(extbuf, extlen, currentlen);
if (currentlen == -1)
    perror("opt_finish");

//*(uint8_t)(extbuf) = 59;
printf("Data buffer is: %x\n",*(unsigned char*)(databuf));

printf("Extlen is: %d\n",extlen);
printf("Currentlen is: %d\n", currentlen);

unsigned char* temp1 = databuf;
for(j=0; j<3;j++) {
    printf("Data buffer is: %d\n",*temp1);
    temp1++;
}

for(i=0;i<extlen;i++) {
    printf("exbuf is:%d\n",*temp);
    temp++;
}
    /*
cmsglen = CMSG_SPACE(extlen);
cmsg = malloc(cmsglen);
if (cmsg == NULL) {
    perror("msg malloc");
    exit(EXIT_FAILURE);
}

cmsg->cmsg_len = CMSG_LEN(extlen);
cmsg->cmsg_level = IPPROTO_IPV6;
cmsg->cmsg_type = IPV6_HOPOPTS;
extbuf = CMSG_DATA(cmsg);
   */
iov[0].iov_base = packet;
iov[0].iov_len = sizeof(packet);
iov[1].iov_base = extbuf;
iov[1].iov_len = sizeof(extbuf);
//iov[2].iov_base = databuf;
//iov[2].iov_len = sizeof(databuf);
msg.msg_control = cmsg;
msg.msg_controllen = cmsglen;
msg.msg_name = (struct sockaddr*)&daddr;
msg.msg_namelen = sizeof(daddr);
msg.msg_iov = &iov;
msg.msg_iovlen = 2;
msg.msg_flags = 0;  
while(1) {
    sleep(1);
    /*if (sendto(s, (char *)packet, sizeof(packet), 0, 
        (struct sockaddr *)&daddr, (socklen_t)sizeof(daddr)) < 0)
        perror("packet send error:");
}*/
    if (sendmsg(s, &msg, 2) < 0) {
        perror("sendmsg()");
    }
    else
        printf("data sent\n");
}
exit(EXIT_SUCCESS);
}

short unsigned sequence_number()
{
number = rand();
return number;
}

RECEIVER.C

#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/ip6.h>
#include <errno.h>
#include <netdb.h>

#define IP_TLV_ROUTERALERT 5

int print_options(void *, socklen_t);

int main(void)
{
    int s,i;
    struct sockaddr_in6 saddr;
    char packet[80];
    int setsock_offset = 1;

    //-----for ancillary data
    int             currentlen;
    void            *extptr;
    struct sockaddr_in6     addr;
    struct msghdr       msg;
    struct cmsghdr      *cmsgptr;
    struct iovec        iov;
    void            *extbuf;
    socklen_t       extension_len;
    socklen_t       extlen;
    socklen_t       cmsgspace;
    char            databuf[80];
    char            sender_ip[40];


    //sender_ip = (char*)malloc(sizeof(char));
    printf("size :%d\n",sizeof(sender_ip));

    strcpy(sender_ip, "fe80::921b:eff:fe03:637d");
    printf("Sender ip: %s\n", sender_ip);
    addr.sin6_family = AF_INET6;
    addr.sin6_port = 0;
    inet_pton(AF_INET6, sender_ip, (struct in6_addr *)&addr.sin6_addr.s6_addr);

    if ((s = socket(AF_INET6, SOCK_RAW, IPPROTO_RAW)) < 0) {
        perror("error:");
        exit(EXIT_FAILURE);
    }

    if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVHOPOPTS, &setsock_offset, sizeof(setsock_offset)) < 0) 
    {
        perror("setsockopt");
        exit(EXIT_FAILURE);
    }

    currentlen = inet6_opt_init(NULL,0);
    if (currentlen == -1)
    {
        perror("1st opt_init");
        exit(EXIT_FAILURE);
    }

    currentlen = inet6_opt_append(NULL,0,currentlen, IPV6_TLV_ROUTERALERT, 2, 1, NULL);
    if (currentlen == -1)
    {
        perror("1st append");
        exit(EXIT_FAILURE);
    }

    currentlen = inet6_opt_finish(NULL, 0, currentlen);
    if (currentlen == -1)
    {
        perror("1st finish");
        exit(EXIT_FAILURE);
    }

    extension_len = currentlen;
    cmsgspace = CMSG_SPACE(extension_len);
    cmsgptr = malloc(cmsgspace);
    if (cmsgptr == NULL)
    {
        perror("malloc");
        exit(EXIT_FAILURE);
    }

    extptr = CMSG_DATA(cmsgptr);

    msg.msg_control = cmsgptr;
    msg.msg_controllen = cmsgspace;

    iov.iov_base = databuf;
    iov.iov_len = 1;
    msg.msg_iov = &iov;
    msg.msg_iovlen = 1;
    msg.msg_flags = 0;
    msg.msg_name = (struct sockaddr *)&addr;
    msg.msg_namelen = sizeof(addr);
    memset(packet, 0, sizeof(packet));
    socklen_t *len = (socklen_t *)sizeof(saddr);
    int fromlen = sizeof(saddr);

    while(1) 
    {
        printf("Waiting for packets...\n");
        if (recvmsg(s, &msg, 0) == -1) 
        {
            perror("packet receive error:");
            return;
        }

        if (msg.msg_controllen != 0 && 
            cmsgptr->cmsg_level == IPPROTO_IPV6 &&
            cmsgptr->cmsg_type == IPV6_HOPOPTS ) {

            print_options(extptr, extension_len);
        }
    }
}

int print_options(void *extbuf, socklen_t extlen) 
{
    struct ip6_hbh *ext;
    int currentlen;
    uint8_t type;
    socklen_t len;
    void *databuf;
    int offset;
    uint8_t value;
    uint8_t value1;

    ext = (struct ip6_hbh *)extbuf;
    printf("nxt header %u, len: %u (bytes%d)\n", ext->ip6h_nxt, ext->ip6h_len, (ext->ip6h_len + 1)*8);

    currentlen = 0;
    while(1)
    {
        currentlen = inet6_opt_next(extbuf, extlen, currentlen, &type, &databuf);
        if(currentlen == -1)
            break;
        printf("Received opt %u len %u\n", type, len);
        switch(type)
        {
            case IPV6_TLV_ROUTERALERT:
                offset = 0;
                offset = inet6_opt_get_val(databuf, offset, &value, sizeof(value) );
                printf("1 byte field %x\n", value);
                offset = inet6_opt_get_val(databuf, offset, &value1, sizeof(value1) );
                printf("2 byte field %x\n", value1);
                break;

            default:
                printf("unknown option :%x\n", type);
                break;
        }
    }
    return(0);
}

我一直在使用的参考文献来自RFC 3542

如果您能够提供一些参考资料,我可以在哪里获得更多信息,或者唯一的方法是创建ethernet_level原始套接字并获取用户的所有信息 - space。(我认为这是不合理的,因为必须有一种方法对用户空间进行一些测试)

1 个答案:

答案 0 :(得分:1)

在您的receiver.c中,使用以下命令创建一个rawip套接字:

(s = socket(AF_INET6, SOCK_RAW, IPPROTO_RAW))

问题在于IPPROTO_RAW,您可以在以下网址获取其描述:

http://manpages.ubuntu.com/manpages/hardy/man7/raw.7.html

“IPPROTO_RAW协议意味着启用了IP_HDRINCL,并且能够发送传递头中指定的任何IP协议。使用原始套接字无法通过IPPROTO_RAW接收所有IP协议。”

您可以使用NEXTHDR_HOP而不是IPPROTO_RAW创建套接字。

我自己没有尝试过,只需从doc / code获取。