2011-11-02 35 views
2

我正在研究IPv6,需要从头创建一个IPv6数据包并将其放入缓冲区。不幸的是,我没有与C多的经验从一个教程,我已经成功地做到与IPv4的同样的事情通过定义IPv6原始套接字编程与本地C

struct ipheader { 
unsigned char  iph_ihl:5, /* Little-endian */ 
       iph_ver:4; 
unsigned char  iph_tos; 
unsigned short int iph_len; 
unsigned short int iph_ident; 
unsigned char  iph_flags; 
unsigned short int iph_offset; 
unsigned char  iph_ttl; 
unsigned char  iph_protocol; 
unsigned short int iph_chksum; 
unsigned int  iph_sourceip; 
unsigned int  iph_destip; 
}; 

/* Structure of a TCP header */ 
struct tcpheader { 
unsigned short int tcph_srcport; 
unsigned short int tcph_destport; 
unsigned int  tcph_seqnum; 
unsigned int  tcph_acknum; 
unsigned char  tcph_reserved:4, tcph_offset:4; 
// unsigned char tcph_flags; 
    unsigned int 
     tcp_res1:4,  /*little-endian*/ 
     tcph_hlen:4,  /*length of tcp header in 32-bit words*/ 
     tcph_fin:1,  /*Finish flag "fin"*/ 
     tcph_syn:1,  /*Synchronize sequence numbers to start a connection*/ 
     tcph_rst:1,  /*Reset flag */ 
     tcph_psh:1,  /*Push, sends data to the application*/ 
     tcph_ack:1,  /*acknowledge*/ 
     tcph_urg:1,  /*urgent pointer*/ 
     tcph_res2:2; 
unsigned short int tcph_win; 
unsigned short int tcph_chksum; 
unsigned short int tcph_urgptr; 
}; 

,并填补了包内容是这样的:

// IP structure 
    ip->iph_ihl = 5; 
    ip->iph_ver = 6; 
    ip->iph_tos = 16; 
    ip->iph_len = sizeof (struct ipheader) + sizeof (struct tcpheader); 
    ip->iph_ident = htons(54321); 
    ip->iph_offset = 0; 
    ip->iph_ttl = 64; 
    ip->iph_protocol = 6; // TCP 
    ip->iph_chksum = 0; // Done by kernel 

    // Source IP, modify as needed, spoofed, we accept through command line argument 
    ip->iph_sourceip = inet_addr("1922.168.1.128"); 
    // Destination IP, modify as needed, but here we accept through command line argument 
    ip->iph_destip = inet_addr(1922.168.1.1); 

    // The TCP structure. The source port, spoofed, we accept through the command line 
    tcp->tcph_srcport = htons(atoi("1024")); 
    // The destination port, we accept through command line 
    tcp->tcph_destport = htons(atoi("4201")); 
    tcp->tcph_seqnum = htons(1); 
    tcp->tcph_acknum = 0; 
    tcp->tcph_offset = 5; 
    tcp->tcph_syn = 1; 
    tcp->tcph_ack = 0; 
    tcp->tcph_win = htons(32767); 
    tcp->tcph_chksum = 0; // Done by kernel 
    tcp->tcph_urgptr = 0; 
    // IP checksum calculation 
    ip->iph_chksum = csum((unsigned short *) buffer, (sizeof (struct ipheader) + sizeof (struct tcpheader))); 

但是对于IPv6我还没有找到类似的方法。我已经发现是IETF这个结构,

struct ip6_hdr { 

    union { 

     struct ip6_hdrctl { 
     uint32_t ip6_un1_flow; /* 4 bits version, 8 bits TC, 20 bits 
             flow-ID */ 
     uint16_t ip6_un1_plen; /* payload length */ 
     uint8_t ip6_un1_nxt; /* next header */ 
     uint8_t ip6_un1_hlim; /* hop limit */ 
     } ip6_un1; 

     uint8_t ip6_un2_vfc; /* 4 bits version, top 4 bits 
             tclass */ 
    } ip6_ctlun; 
    struct in6_addr ip6_src; /* source address */ 
    struct in6_addr ip6_dst; /* destination address */ 
}; 

但我不知道如何填写的信息,例如,如何从2001年发送一个TCP/SYN:220:806:22:AACC: ff:fe00:1端口1024到2001:220:806:21 :: 4端口1025?

任何人都可以帮助我或有任何参考吗?

谢谢你,那么多。

这是我迄今为止所做的,但是代码与Wireshark捕获的真实数据包之间存在不匹配(如下面的评论所述)。我不确定可以在评论部分发布一个长代码,所以我只是编辑我的问题。

任何人都可以帮忙吗?

#define PCKT_LEN 2000 

int main(void) { 
    unsigned char buffer[PCKT_LEN]; 
    int s; 
    struct sockaddr_in6 din; 
    struct ipv6_header *ip = (struct ipv6_header *) buffer; 
    struct tcpheader *tcp = (struct tcpheader *) (buffer + sizeof (struct ipv6_header)); 

    memset(buffer, 0, PCKT_LEN); 
    din.sin6_family = AF_INET6; 
    din.sin6_port = htons(0); 
    inet_pton(AF_INET6, "::1", &(din.sin6_addr)); // For routing 

    ip->version = 6; 
    ip->traffic_class = 0; 
    ip->flow_label = 0; 
    ip->length = 40; 
    ip->next_header = 6; 
    ip->hop_limit = 64; 
    inet_pton(AF_INET6, "::1", &(ip->dst)); // IPv6 
    inet_pton(AF_INET6, "::1", &(ip->src)); // IPv6 

    tcp->tcph_srcport = htons(atoi("11111")); 
    tcp->tcph_destport = htons(atoi("13")); 
    tcp->tcph_seqnum = htons(0); 
    tcp->tcph_acknum = 0; 
    tcp->tcph_offset = 5; 
    tcp->tcph_syn = 1; 
    tcp->tcph_ack = 0; 
    tcp->tcph_win = htons(32752); 
    tcp->tcph_chksum = 0; // Done by kernel 
    tcp->tcph_urgptr = 0; 

    s = socket(PF_INET6, SOCK_RAW, IPPROTO_RAW); 
    if (s < 0) { 
     perror("socket()"); 
     return 1; 
    } 
    unsigned short int packet_len = sizeof (struct ipv6_header) + sizeof (struct tcpheader); 
    if (sendto(s, buffer, packet_len, 0, (struct sockaddr*) &din, sizeof (din)) == -1) { 
     perror("sendto()"); 
     close(s); 
     return 1; 
    } 
    close(s); 
    return 0; 
} 

回答

1

也许this文章可以帮助您入门?

编辑: 使用维基百科的文章上面我联系使这个结构(不知道是什么的一些字段的意思):

struct ipv6_header 
{ 
    unsigned int 
     version : 4, 
     traffic_class : 8, 
     flow_label : 20; 
    uint16_t length; 
    uint8_t next_header; 
    uint8_t hop_limit; 
    struct in6_addr src; 
    struct in6_addr dst; 
}; 

这是没有比报头结构是如何对IPv4由不同在你的例子中。只需创建一个包含字段的struct,并按照正确的顺序和正确的大小填充正确的值。

只需对TCP标头执行相同操作即可。

+0

是的我知道IPv6是什么,但如何实现是在C语言是很难对我,因为我不熟悉。例如,IPv4的结构非常简单,我可以轻松理解并填写信息。但对于IPv6来说,情况完全不同。 – nhong

+0

@nhong:更新了答案一下。 –

+0

谢谢你的回答,这与我从IETF获得的结构有点不同,但无论如何,我会试一试,请耐心等待:) – nhong

0

不幸的是,ipv6 RFC没有提供与ipv4相同的原始套接字接口。从我见过的创建ipv6数据包,你必须深入一个级别,并使用AF_PACKET套接字来发送以太网帧,包括你的ipv6数据包。