生成数据包

时间:2011-08-09 02:41:08

标签: c networking protocols

我想知道如何在c中生成数据包。假设我们有一个类型如下:

struct ipheader {
    int version;
    int hdLen;
    int tos;
    int totLen;
    int id;
    ......
    int dstIp;
}

我们有一个ipheader类型:

struct ipheader ip;

//init the ip
.....

如何从“ip”生成数据包(只是ip头部分)。谁能告诉我怎么样?

我想知道生成包含mac地址,ip头,tcp头,有效负载等信息的数据包。然后我可以使用“pcap_sendpacket”函数发送我生成的数据包。有人可以举个例子。

2 个答案:

答案 0 :(得分:2)

您可以创建自定义IP数据包,如下所示。下面的代码片段还会生成ip数据包内的自定义TCP部分。自定义函数校验和还会生成数据包的校验和。您可以使用rawsocket将此数据包直接发送到网络。我认为代码很容易解释。如果您有任何疑问,请与我们联系。

#include <netinet/ip.h>
#include <netinet/tcp.h>


****************************************
ipv4 packet structure
****************************************
struct ipv4_packet {
    struct iphdr iph;
    struct tcphdr tcph;
    void *data;
};


****************************************
snippet of the IPV4 packet making code
****************************************
struct iphdr ip_head;
struct tcphdr tcp_head;
struct sockaddr_in target;
char packet[2048];
int i;

struct tcp_pseudo /*the tcp pseudo header*/
{
    __u32 src_addr;
    __u32 dst_addr;
    __u8 dummy;
    __u8 proto;
    __u16 length;
} pseudohead;

struct help_checksum /*struct for checksum calculation*/
{
    struct tcp_pseudo pshd;
    struct tcphdr tcphd;
    char tcpdata[1024];
} tcp_chk_construct;

/*Prepare IP header*/
ip_head.ihl = 5; /*headerlength with no options*/
ip_head.version = 4;
ip_head.tos = 0;
ip_head.tot_len = htons(sizeof(struct iphdr) + sizeof(struct tcphdr) + len);
ip_head.id = htons(31337 + (rand() % 100));
ip_head.frag_off = 0;
ip_head.ttl = 255;
ip_head.protocol = IPPROTO_TCP;
ip_head.check = 0; /*Fill in later*/
ip_head.saddr = htonl(src);
ip_head.daddr = htonl(dst);
ip_head.check = in_cksum((unsigned short *) &ip_head, sizeof(struct iphdr));

/*Prepare TCP header*/
tcp_head.source = htons(src_p);
tcp_head.dest = htons(dst_p);
tcp_head.seq = htonl(seq);
tcp_head.ack_seq = htonl(ack);
tcp_head.doff = 5;

/* set or reset ack, fin or syn flags as needed */
tcp_head.ack = 0;
tcp_head.syn = 0;
tcp_head.fin = 0;

tcp_head.res1 = 0;
tcp_head.urg = 0;
tcp_head.psh = 0;
tcp_head.rst = 0;
tcp_head.res2 = 0;

tcp_head.window = htons(0x7c00);
tcp_head.check = 0; /*Fill in later*/
tcp_head.urg_ptr = 0;

/*Assemble structure for checksum calculation and calculate checksum*/
pseudohead.src_addr = ip_head.saddr;
pseudohead.dst_addr = ip_head.daddr;
pseudohead.dummy = 0;
pseudohead.proto = ip_head.protocol;
pseudohead.length = htons(sizeof(struct tcphdr) + len);

tcp_chk_construct.pshd = pseudohead;
tcp_chk_construct.tcphd = tcp_head;
memcpy(tcp_chk_construct.tcpdata, buffer, len);

tcp_head.check = in_cksum((unsigned short *) &tcp_chk_construct,
        sizeof(struct tcp_pseudo) + sizeof(struct tcphdr) + len);

/*Assemble packet*/
memcpy(packet, (char *) &ip_head, sizeof(ip_head));
memcpy(packet + sizeof(ip_head), (char *) &tcp_head, sizeof(tcp_head));
memcpy(packet + sizeof(ip_head) + sizeof(tcp_head), buffer, len);

/*Send packet*/
target.sin_family = AF_INET;
target.sin_addr.s_addr = ip_head.daddr;
target.sin_port = tcp_head.dest;
i = sendto(sfd, packet, sizeof(struct iphdr) + sizeof(struct tcphdr) + len,
        0, (struct sockaddr *) &target, sizeof(struct sockaddr_in));
if (i < 0)
    return (-1); /*Error*/
else
    return (i); /*Return number of bytes sent*/


****************************************        
FUNCTION FOR CHECKSUM   
****************************************
/* function to calculate the checksum for the packet */
unsigned short in_cksum(unsigned short *ptr, int nbytes) {

    register long sum; /* assumes long == 32 bits */
    u_short oddbyte;
    register u_short answer; /* assumes u_short == 16 bits */
    /*
     * the algorithm is simple, using a 32-bit accumulator (sum),
     * we add sequential 16-bit words to it, and at the end, fold back
     * all the carry bits from the top 16 bits into the lower 16 bits.
     */
    sum = 0;
    while (nbytes > 1) {
        sum += *ptr++;
        nbytes -= 2;
    }

    /* mop up an odd byte, if necessary */
    if (nbytes == 1) {
        oddbyte = 0; /* make sure top half is zero */
        *((u_char *) &oddbyte) = *(u_char *) ptr; /* one byte only */
        sum += oddbyte;
    }

    /*
     * Add back carry outs from top 16 bits to low 16 bits.
     */
    sum = (sum >> 16) + (sum & 0xffff); /* add high-16 to low-16 */
    sum += (sum >> 16); /* add carry */
    answer = ~sum; /* ones-complement, then truncate to 16 bits */
    return (answer);
}

答案 1 :(得分:0)

由于你没有指明细节(看起来像我的家庭作业一样可疑),我所能做的只是指点。

  1. 查看内存中结构的形成方式。
  2. 查找Ip标头格式,它将显示成员在Ip标头中的位置。
  3. 查找Raw套接字。
  4. 因此,如果正确构造结构并使用原始套接字,则只需将此结构写入套接字。