如何在C中设置TCP数据包中的自定义syn / ack值?

时间:2018-01-21 12:22:36

标签: c networking tcp

准确地说,我想构建一个自定义TCP数据包,并手动设置syn / ack值。

代码:

/*
    Raw TCP packets
    Silver Moon (m00n.silv3r@gmail.com)
*/
#include<stdio.h> //for printf
#include<string.h> //memset
#include<sys/socket.h>    //for socket ofcourse
#include<stdlib.h> //for exit(0);
#include <arpa/inet.h>
#include<errno.h> //For errno - the error number
#include<netinet/tcp.h>   //Provides declarations for tcp header
#include<netinet/ip.h>    //Provides declarations for ip header

/*
    96 bit (12 bytes) pseudo header needed for tcp header checksum calculation 
*/

struct pseudo_header
{
    u_int32_t source_address;
    u_int32_t dest_address;
    u_int8_t  placeholder;
    u_int8_t  protocol;
    u_int16_t tcp_length;
};

/*
    Generic checksum calculation function
*/
unsigned short csum(unsigned short *ptr,int nbytes) 
{
    register long  sum;
    unsigned short oddbyte;
    register short answer;

    sum=0;
    while(nbytes>1) {
        sum+=*ptr++;
        nbytes-=2;
    }
    if(nbytes==1) {
        oddbyte=0;
        *((u_char*)&oddbyte)=*(u_char*)ptr;
        sum+=oddbyte;
    }

    sum = (sum>>16)+(sum & 0xffff);
    sum = sum + (sum>>16);
    answer=(short)~sum;

    return(answer);
}

int main (int argc, char *argv[])
{
    if(argc < 6 || argc > 6){
        printf("Usage: ./sendtcp [Source IP] [Source port] [Destination IP] [Destination Port] [Packet Data]\n");
        return -1;
    }

    char sourceip          [32];
    char sourceports       [10];
    char destinationip     [32];
    char destinationports  [10];

    int  sourceport      = 2000;
    int  destinationport = 2000;

    strcpy(sourceip,         argv[1]);
    strcpy(sourceports,      argv[2]);
    strcpy(destinationip,    argv[3]);
    strcpy(destinationports, argv[4]);
    sscanf(sourceports,      "%d", &sourceport);
    sscanf(destinationports, "%d", &destinationport);

    printf("[Sending] from %s:%d To: %s:%s\n", sourceip, sourceport, destinationip,destinationports);
    //Create a raw socket
    int s = socket (PF_INET, SOCK_RAW, IPPROTO_TCP);

    if(s == -1)
    {
        //socket creation failed, may be because of non-root privileges
        perror("Failed to create socket");
        exit(1);
    }

    //Datagram to represent the packet
    char datagram[4096] , source_ip[32] , *data , *pseudogram;

    //zero out the packet buffer
    memset (datagram, 0, 4096);

    //IP header
    struct iphdr *iph = (struct iphdr *) datagram;

    //TCP header
    struct tcphdr *tcph = (struct tcphdr *) (datagram + sizeof (struct ip));
    struct sockaddr_in sin;
    struct pseudo_header psh;

    //Data part
    data = datagram + sizeof(struct iphdr) + sizeof(struct tcphdr);
    strcpy(data , argv[5]);

    //some address resolution
    strcpy(source_ip , sourceip);
    sin.sin_family = AF_INET;
    sin.sin_port = htons(80);
    sin.sin_addr.s_addr = inet_addr (destinationip);

    //Fill in the IP Header
    iph->ihl = 5;
    iph->version = 4;
    iph->tos = 0;
    iph->tot_len = sizeof (struct iphdr) + sizeof (struct tcphdr) + strlen(data);
    iph->id = htonl (54321); //Id of this packet
    iph->frag_off = 0;
    iph->ttl = 255;
    iph->protocol = IPPROTO_TCP;
    iph->check = 0;      //Set to 0 before calculating checksum
    iph->saddr = inet_addr ( source_ip );    //Spoof the source ip address
    iph->daddr = sin.sin_addr.s_addr;

    //Ip checksum
    iph->check = csum ((unsigned short *) datagram, iph->tot_len);

    //TCP Header
    tcph->source  = htons (sourceport);
    tcph->dest    = htons (destinationport);
    tcph->seq     = 1;
    tcph->ack_seq = 6;
    tcph->doff    = 5;  //tcp header size
    tcph->fin     = 0;
    tcph->syn     = 1;
    tcph->rst     = 0;
    tcph->psh     = 0;
    tcph->ack     = 1;
    tcph->urg     = 0;
    tcph->window  = htons (5840); /* maximum allowed window size */
    tcph->check   = 0; //leave checksum 0 now, filled later by pseudo header
    tcph->urg_ptr = 0;

    //Now the TCP checksum
    psh.source_address = inet_addr( source_ip );
    psh.dest_address = sin.sin_addr.s_addr;
    psh.placeholder = 0;
    psh.protocol = IPPROTO_TCP;
    psh.tcp_length = htons(sizeof(struct tcphdr) + strlen(data) );

    int psize = sizeof(struct pseudo_header) + sizeof(struct tcphdr) + strlen(data);
    pseudogram = malloc(psize);

    memcpy(pseudogram , (char*) &psh , sizeof (struct pseudo_header));
    memcpy(pseudogram + sizeof(struct pseudo_header) , tcph , sizeof(struct tcphdr) + strlen(data));

    tcph->check = csum( (unsigned short*) pseudogram , psize);

    //IP_HDRINCL to tell the kernel that headers are included in the packet
    int one = 1;
    const int *val = &one;

    if (setsockopt (s, IPPROTO_IP, IP_HDRINCL, val, sizeof (one)) < 0)
    {
        perror("Error setting IP_HDRINCL");
        exit(0);
    }

    //loop if you want to flood :)
    while (1)
    {
        //Send the packet
        if (sendto (s, datagram, iph->tot_len ,  0, (struct sockaddr *) &sin, sizeof (sin)) < 0)
        {
            perror("sendto failed");
        }
        //Data send successfully
        else
        {
            printf ("Packet Send. Length : %d \n" , iph->tot_len);
        }
    sleep(2);
    }
    return 0;
}

仅供参考: tcph->seq = 1; tcph->ack_seq = 6;是您设置syn / ack值的地方。

问题在于,即使我已将Syn=1Ack=6设置为wireshark,它似乎也是seq=4227858432 Ack=100663297

如果您能告诉我这些数字是如何存储的,以及如何将自己的自定义值设置为syn/ack值,我将非常感谢。

1 个答案:

答案 0 :(得分:0)

好的问题是,当我将syn的值设置为tcph->seq = 1;时,它实际上将值设置为位。

因此,为了让我设置不同的值,应该使用网络语言完成,您可以使用htons() or htonl()完成它。

如此恰当的方式就像:tcph->seq = htonl(20); tcph->ack_seq = htonl(num);

这就是我想要做的事情:)