zoukankan      html  css  js  c++  java
  • tcp raw socket

    client 

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <string.h>
    #include <time.h>
    #include <arpa/inet.h>
    #include <sys/socket.h>
    #include <netinet/ip.h>
    #include <netinet/tcp.h>
    
    // 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;
    };
    
    #define DATAGRAM_LEN 4096
    #define OPT_SIZE 20
    
    unsigned short checksum(const char *buf, unsigned size)
    {
        unsigned sum = 0, i;
    
        /* Accumulate checksum */
        for (i = 0; i < size - 1; i += 2)
        {
            unsigned short word16 = *(unsigned short *) &buf[i];
            sum += word16;
        }
    
        /* Handle odd-sized case */
        if (size & 1)
        {
            unsigned short word16 = (unsigned char) buf[i];
            sum += word16;
        }
    
        /* Fold to get the ones-complement result */
        while (sum >> 16) sum = (sum & 0xFFFF)+(sum >> 16);
    
        /* Invert to get the negative in ones-complement arithmetic */
        return ~sum;
    }
    
    void create_syn_packet(struct sockaddr_in* src, struct sockaddr_in* dst, char** out_packet, int* out_packet_len)
    {
        // datagram to represent the packet
        char *datagram = calloc(DATAGRAM_LEN, sizeof(char));
    
        // required structs for IP and TCP header
        struct iphdr *iph = (struct iphdr*)datagram;
        struct tcphdr *tcph = (struct tcphdr*)(datagram + sizeof(struct iphdr));
        struct pseudo_header psh;
    
        // IP header configuration
        iph->ihl = 5;
        iph->version = 4;
        iph->tos = 0;
        iph->tot_len = sizeof(struct iphdr) + sizeof(struct tcphdr) + OPT_SIZE;
        iph->id = htonl(rand() % 65535); // id of this packet
        iph->frag_off = 0;
        iph->ttl = 64;
        iph->protocol = IPPROTO_TCP;
        iph->check = 0; // correct calculation follows later
        iph->saddr = src->sin_addr.s_addr;
        iph->daddr = dst->sin_addr.s_addr;
    
        // TCP header configuration
        tcph->source = src->sin_port;
        tcph->dest = dst->sin_port;
        tcph->seq = htonl(rand() % 4294967295);
        tcph->ack_seq = htonl(0);
        tcph->doff = 10; // tcp header size
        tcph->fin = 0;
        tcph->syn = 1;
        tcph->rst = 0;
        tcph->psh = 0;
        tcph->ack = 0;
        tcph->urg = 0;
        tcph->check = 0; // correct calculation follows later
        tcph->window = htons(5840); // window size
        tcph->urg_ptr = 0;
    
        // TCP pseudo header for checksum calculation
        psh.source_address = src->sin_addr.s_addr;
        psh.dest_address = dst->sin_addr.s_addr;
        psh.placeholder = 0;
        psh.protocol = IPPROTO_TCP;
        psh.tcp_length = htons(sizeof(struct tcphdr) + OPT_SIZE);
        int psize = sizeof(struct pseudo_header) + sizeof(struct tcphdr) + OPT_SIZE;
        // fill pseudo packet
        char* pseudogram = malloc(psize);
        memcpy(pseudogram, (char*)&psh, sizeof(struct pseudo_header));
        memcpy(pseudogram + sizeof(struct pseudo_header), tcph, sizeof(struct tcphdr) + OPT_SIZE);
    
        // TCP options are only set in the SYN packet
        // ---- set mss ----
        datagram[40] = 0x02;
        datagram[41] = 0x04;
        int16_t mss = htons(48); // mss value
        memcpy(datagram + 42, &mss, sizeof(int16_t));
        // ---- enable SACK ----
        datagram[44] = 0x04;
        datagram[45] = 0x02;
        // do the same for the pseudo header
        pseudogram[32] = 0x02;
        pseudogram[33] = 0x04;
        memcpy(pseudogram + 34, &mss, sizeof(int16_t));
        pseudogram[36] = 0x04;
        pseudogram[37] = 0x02;
    
        tcph->check = checksum((const char*)pseudogram, psize);
        iph->check = checksum((const char*)datagram, iph->tot_len);
    
        *out_packet = datagram;
        *out_packet_len = iph->tot_len;
        free(pseudogram);
    }
    
    void create_ack_packet(struct sockaddr_in* src, struct sockaddr_in* dst, int32_t seq, int32_t ack_seq, char** out_packet, int* out_packet_len)
    {
        // datagram to represent the packet
        char *datagram = calloc(DATAGRAM_LEN, sizeof(char));
    
        // required structs for IP and TCP header
        struct iphdr *iph = (struct iphdr*)datagram;
        struct tcphdr *tcph = (struct tcphdr*)(datagram + sizeof(struct iphdr));
        struct pseudo_header psh;
    
        // IP header configuration
        iph->ihl = 5;
        iph->version = 4;
        iph->tos = 0;
        iph->tot_len = sizeof(struct iphdr) + sizeof(struct tcphdr) + OPT_SIZE;
        iph->id = htonl(rand() % 65535); // id of this packet
        iph->frag_off = 0;
        iph->ttl = 64;
        iph->protocol = IPPROTO_TCP;
        iph->check = 0; // correct calculation follows later
        iph->saddr = src->sin_addr.s_addr;
        iph->daddr = dst->sin_addr.s_addr;
    
        // TCP header configuration
        tcph->source = src->sin_port;
        tcph->dest = dst->sin_port;
        tcph->seq = htonl(seq);
        tcph->ack_seq = htonl(ack_seq);
        tcph->doff = 10; // tcp header size
        tcph->fin = 0;
        tcph->syn = 0;
        tcph->rst = 0;
        tcph->psh = 0;
        tcph->ack = 1;
        tcph->urg = 0;
        tcph->check = 0; // correct calculation follows later
        tcph->window = htons(5840); // window size
        tcph->urg_ptr = 0;
    
        // TCP pseudo header for checksum calculation
        psh.source_address = src->sin_addr.s_addr;
        psh.dest_address = dst->sin_addr.s_addr;
        psh.placeholder = 0;
        psh.protocol = IPPROTO_TCP;
        psh.tcp_length = htons(sizeof(struct tcphdr) + OPT_SIZE);
        int psize = sizeof(struct pseudo_header) + sizeof(struct tcphdr) + OPT_SIZE;
        // fill pseudo packet
        char* pseudogram = malloc(psize);
        memcpy(pseudogram, (char*)&psh, sizeof(struct pseudo_header));
        memcpy(pseudogram + sizeof(struct pseudo_header), tcph, sizeof(struct tcphdr) + OPT_SIZE);
    
        tcph->check = checksum((const char*)pseudogram, psize);
        iph->check = checksum((const char*)datagram, iph->tot_len);
    
        *out_packet = datagram;
        *out_packet_len = iph->tot_len;
        free(pseudogram);
    }
    
    void create_data_packet(struct sockaddr_in* src, struct sockaddr_in* dst, int32_t seq, int32_t ack_seq, char* data, int data_len, char** out_packet, int* out_packet_len)
    {
        // datagram to represent the packet
        char *datagram = calloc(DATAGRAM_LEN, sizeof(char));
    
        // required structs for IP and TCP header
        struct iphdr *iph = (struct iphdr*)datagram;
        struct tcphdr *tcph = (struct tcphdr*)(datagram + sizeof(struct iphdr));
        struct pseudo_header psh;
    
        // set payload
        char* payload = datagram + sizeof(struct iphdr) + sizeof(struct tcphdr) + OPT_SIZE;
        memcpy(payload, data, data_len);
    
        // IP header configuration
        iph->ihl = 5;
        iph->version = 4;
        iph->tos = 0;
        iph->tot_len = sizeof(struct iphdr) + sizeof(struct tcphdr) + OPT_SIZE + data_len;
        iph->id = htonl(rand() % 65535); // id of this packet
        iph->frag_off = 0;
        iph->ttl = 64;
        iph->protocol = IPPROTO_TCP;
        iph->check = 0; // correct calculation follows later
        iph->saddr = src->sin_addr.s_addr;
        iph->daddr = dst->sin_addr.s_addr;
    
        // TCP header configuration
        tcph->source = src->sin_port;
        tcph->dest = dst->sin_port;
        tcph->seq = htonl(seq);
        tcph->ack_seq = htonl(ack_seq);
        tcph->doff = 10; // tcp header size
        tcph->fin = 0;
        tcph->syn = 0;
        tcph->rst = 0;
        tcph->psh = 1;
        tcph->ack = 1;
        tcph->urg = 0;
        tcph->check = 0; // correct calculation follows later
        tcph->window = htons(5840); // window size
        tcph->urg_ptr = 0;
    
        // TCP pseudo header for checksum calculation
        psh.source_address = src->sin_addr.s_addr;
        psh.dest_address = dst->sin_addr.s_addr;
        psh.placeholder = 0;
        psh.protocol = IPPROTO_TCP;
        psh.tcp_length = htons(sizeof(struct tcphdr) + OPT_SIZE + data_len);
        int psize = sizeof(struct pseudo_header) + sizeof(struct tcphdr) + OPT_SIZE + data_len;
        // fill pseudo packet
        char* pseudogram = malloc(psize);
        memcpy(pseudogram, (char*)&psh, sizeof(struct pseudo_header));
        memcpy(pseudogram + sizeof(struct pseudo_header), tcph, sizeof(struct tcphdr) + OPT_SIZE + data_len);
    
        tcph->check = checksum((const char*)pseudogram, psize);
        iph->check = checksum((const char*)datagram, iph->tot_len);
    
        *out_packet = datagram;
        *out_packet_len = iph->tot_len;
        free(pseudogram);
    }
    
    void read_seq_and_ack(const char* packet, uint32_t* seq, uint32_t* ack)
    {
        // read sequence number
        uint32_t seq_num;
        memcpy(&seq_num, packet + 24, 4);
        // read acknowledgement number
        uint32_t ack_num;
        memcpy(&ack_num, packet + 28, 4);
        // convert network to host byte order
        *seq = ntohl(seq_num);
        *ack = ntohl(ack_num);
        printf("sequence number: %lu
    ", (unsigned long)*seq);
        printf("acknowledgement number: %lu
    ", (unsigned long)*seq);
    }
    
    int receive_from(int sock, char* buffer, size_t buffer_length, struct sockaddr_in *dst)
    {
        unsigned short dst_port;
        int received;
        do
        {
            received = recvfrom(sock, buffer, buffer_length, 0, NULL, NULL);
            if (received < 0)
                break;
            memcpy(&dst_port, buffer + 22, sizeof(dst_port));
        }
        while (dst_port != dst->sin_port); //过滤一些报文
        printf("received bytes: %d
    ", received);
        printf("destination port: %d
    ", ntohs(dst->sin_port));
        return received;
    }
    
    int main(int argc, char** argv)
    {
        if (argc != 4)
        {
            printf("invalid parameters.
    ");
            printf("USAGE %s <source-ip> <target-ip> <port>
    ", argv[0]);
            return 1;
        }
    
        srand(time(NULL));
    
        int sock = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);
        if (sock == -1)
        {
            printf("socket creation failed
    ");
            return 1;
        }
    
        // destination IP address configuration
        struct sockaddr_in daddr;
        daddr.sin_family = AF_INET;
        daddr.sin_port = htons(atoi(argv[3]));
        if (inet_pton(AF_INET, argv[2], &daddr.sin_addr) != 1)
        {
            printf("destination IP configuration failed
    ");
            return 1;
        }
    
        // source IP address configuration
        struct sockaddr_in saddr;
        saddr.sin_family = AF_INET;
        saddr.sin_port = htons(rand() % 65535); // random client port
        if (inet_pton(AF_INET, argv[1], &saddr.sin_addr) != 1)
        {
            printf("source IP configuration failed
    ");
            return 1;
        }
    
        // // call bind with port number specified as zero to get an unused source port
        // if (bind(sock, (struct sockaddr*)&saddr, sizeof(struct sockaddr)) == -1)
        // {
        //     printf("bind() failed
    ");
        //     return 1;
        // }
    
        // // retrieve source port
        // socklen_t addrLen = sizeof(struct sockaddr);
        // if (getsockname(sock, (struct sockaddr*)&saddr, &addrLen) == -1)
        // {
        //     printf("getsockname() failed
    ");
        //     return 1;
        // }
        printf("selected source port number: %d
    ", ntohs(saddr.sin_port));
    
        // tell the kernel that headers are included in the packet
        int one = 1;
        const int *val = &one;
        if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, val, sizeof(one)) == -1)
        {
            printf("setsockopt(IP_HDRINCL, 1) failed
    ");
            return 1;
        }
    
        // send SYN
        char* packet;
        int packet_len;
        create_syn_packet(&saddr, &daddr, &packet, &packet_len);
    
        int sent;
        if ((sent = sendto(sock, packet, packet_len, 0, (struct sockaddr*)&daddr, sizeof(struct sockaddr))) == -1)
        {
            printf("sendto() failed
    ");
        }
        else
        {
            printf("successfully sent %d bytes SYN!
    ", sent);
        }
    
        // receive SYN-ACK
        char recvbuf[DATAGRAM_LEN];
        int received = receive_from(sock, recvbuf, sizeof(recvbuf), &saddr);
        if (received <= 0)
        {
            printf("receive_from() failed
    ");
        }
        else
        {
            printf("successfully received %d bytes SYN-ACK!
    ", received);
        }
    
        // read sequence number to acknowledge in next packet
        uint32_t seq_num, ack_num;
        read_seq_and_ack(recvbuf, &seq_num, &ack_num);
        int new_seq_num = seq_num + 1;
    
        // send ACK
        // previous seq number is used as ack number and vica vera
        create_ack_packet(&saddr, &daddr, ack_num, new_seq_num, &packet, &packet_len);
        if ((sent = sendto(sock, packet, packet_len, 0, (struct sockaddr*)&daddr, sizeof(struct sockaddr))) == -1)
        {
            printf("sendto() failed
    ");
        }
        else
        {
            printf("successfully sent %d bytes ACK!
    ", sent);
        }
    
        // send data
        char request[] = "GET / HTTP/1.1
    Host: localhost
    
    ";
        create_data_packet(&saddr, &daddr, ack_num, new_seq_num, request, sizeof(request) - 1/sizeof(char), &packet, &packet_len);
        if ((sent = sendto(sock, packet, packet_len, 0, (struct sockaddr*)&daddr, sizeof(struct sockaddr))) == -1)
        {
            printf("send failed
    ");
        }
        else
        {
            printf("successfully sent %d bytes PSH!
    ", sent);
        }
    
        // receive response
        while ((received = receive_from(sock, recvbuf, sizeof(recvbuf), &saddr)) > 0)
        {
            printf("successfully received %d bytes!
    ", received);
            read_seq_and_ack(recvbuf, &seq_num, &ack_num);
            new_seq_num = seq_num + 1;
            create_ack_packet(&saddr, &daddr, ack_num, new_seq_num, &packet, &packet_len);
            if ((sent = sendto(sock, packet, packet_len, 0, (struct sockaddr*)&daddr, sizeof(struct sockaddr))) == -1)
            {
                printf("send failed
    ");
            }
            else
            {
                printf("successfully sent %d bytes ACK!
    ", sent);
            }
        }
    
        // TODO: handle FIN packets to close the connection properly
    
        close(sock);
        return 0;
    }

    server

    // tcpserv.c
    #include <netinet/in.h>    // for sockaddr_in
    #include <sys/types.h>    // for socket
    #include <sys/socket.h>    // for socket
    #include <stdio.h>        // for printf
    #include <stdlib.h>        // for exit
    #include <string.h>        // for bzero
    #include <arpa/inet.h>     // inet_ntoa
     
    #define LISTENQ 20
    #define MAXLINE 10000
    int SERV_PORT=6666;
     
    void
    str_echo(int sockfd)
    {
        long        arg1, arg2;
        ssize_t     n;
        char        line[MAXLINE];
     
        for ( ; ; ) {
            if ( (n = recv(sockfd, line, MAXLINE, 0)) == 0)
                return;     /* connection closed by other end */
            n = strlen(line);
            printf("len: %d 
    ", n);
            printf("data: %s", line);
            send(sockfd, line, n, 0);
            memset(line, 0, MAXLINE);
        }
    }
     
    int
    main(int argc, char **argv)
    {
        int                 listenfd, connfd;
        pid_t               childpid;
        socklen_t           clilen;
        struct sockaddr_in  cliaddr, servaddr;
      
      if (argc > 2){
        printf("usage: tcpserv [port]
    ");
        exit(0);
      }
      if (argc == 2){
        printf("listening on port:%s
    ", argv[1]);
        SERV_PORT = atoi(argv[1]);
      }
     
        listenfd = socket(AF_INET, SOCK_STREAM, 0);
     
        bzero(&servaddr, sizeof(servaddr));
        servaddr.sin_family      = AF_INET;
        servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
        servaddr.sin_port        = htons(SERV_PORT);
     
        bind(listenfd, (struct sockaddr*) &servaddr, sizeof(servaddr));
     
        listen(listenfd, LISTENQ);
     
        for ( ; ; ) {
            clilen = sizeof(cliaddr);
            connfd = accept(listenfd, (struct sockaddr*) &cliaddr, &clilen);
            printf("connected from:%s, port:%d 
    
    ", inet_ntoa(cliaddr.sin_addr), ntohs(cliaddr.sin_port));
            if ( (childpid = fork()) == 0) {    /* child process */
                close(listenfd);    /* close listening socket */
                str_echo(connfd);   /* process the request */
                exit(0);
            }
            close(connfd);          /* parent closes connected socket */
        }
        return 0;
    }

    运行

    gcc tcpserv.c -o tcpserv
    ./tcpserv 6666              #监听6666端口

    server 抓包

    root@ubuntu:~/c++# tcpdump  -i  enahisic2i0 tcp and host 10.10.16.81  and 'tcp[tcpflags] == tcp-syn' -env
    tcpdump: listening on enahisic2i0, link-type EN10MB (Ethernet), capture size 262144 bytes
    11:12:27.416557 48:57:02:64:ea:1b > 48:57:02:64:e7:ab, ethertype IPv4 (0x0800), length 74: (tos 0x0, ttl 64, id 42373, offset 0, flags [none], proto TCP (6), length 60)
        10.10.16.81.61698 > 10.10.16.82.6666: Flags [S], cksum 0xf395 (correct), seq 320339031, win 5840, options [mss 48,sackOK,eol], length 0
    ^C
    1 packet captured
    1 packet received by filter
    0 packets dropped by kernel
    root@ubuntu:~/c++# netstat -pan | grep 6666
    tcp        0      0 0.0.0.0:6666            0.0.0.0:*               LISTEN      59642/./tcpserv     
    tcp        0     26 10.10.16.82:6666        10.10.16.81:61698       ESTABLISHED 59663/./tcpserv     
    root@ubuntu:~/c++# 

    client 结束

     又多了个一个connect

    从server端发起connect

    把服务端停止

    demo2

    从第三个节点telnet 

    81节点输出

     其他节点的报文也能收到,

    改成固定端口

    [root@bogon raw-sockets-example]# cat rawsockets.c 
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <string.h>
    #include <time.h>
    #include <arpa/inet.h>
    #include <sys/socket.h>
    #include <netinet/ip.h>
    #include <netinet/tcp.h>
    
    // 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;
    };
    
    #define DATAGRAM_LEN 4096
    #define OPT_SIZE 20
    
    unsigned short checksum(const char *buf, unsigned size)
    {
            unsigned sum = 0, i;
    
            /* Accumulate checksum */
            for (i = 0; i < size - 1; i += 2)
            {
                    unsigned short word16 = *(unsigned short *) &buf[i];
                    sum += word16;
            }
    
            /* Handle odd-sized case */
            if (size & 1)
            {
                    unsigned short word16 = (unsigned char) buf[i];
                    sum += word16;
            }
    
            /* Fold to get the ones-complement result */
            while (sum >> 16) sum = (sum & 0xFFFF)+(sum >> 16);
    
            /* Invert to get the negative in ones-complement arithmetic */
            return ~sum;
    }
    
    void create_syn_packet(struct sockaddr_in* src, struct sockaddr_in* dst, char** out_packet, int* out_packet_len)
    {
            // datagram to represent the packet
            char *datagram = calloc(DATAGRAM_LEN, sizeof(char));
    
            // required structs for IP and TCP header
            struct iphdr *iph = (struct iphdr*)datagram;
            struct tcphdr *tcph = (struct tcphdr*)(datagram + sizeof(struct iphdr));
            struct pseudo_header psh;
    
            // IP header configuration
            iph->ihl = 5;
            iph->version = 4;
            iph->tos = 0;
            iph->tot_len = sizeof(struct iphdr) + sizeof(struct tcphdr) + OPT_SIZE;
            iph->id = htonl(rand() % 65535); // id of this packet
            iph->frag_off = 0;
            iph->ttl = 64;
            iph->protocol = IPPROTO_TCP;
            iph->check = 0; // correct calculation follows later
            iph->saddr = src->sin_addr.s_addr;
            iph->daddr = dst->sin_addr.s_addr;
    
            // TCP header configuration
            tcph->source = src->sin_port;
            tcph->dest = dst->sin_port;
            tcph->seq = htonl(rand() % 4294967295);
            tcph->ack_seq = htonl(0);
            tcph->doff = 10; // tcp header size
            tcph->fin = 0;
            tcph->syn = 1;
            tcph->rst = 0;
            tcph->psh = 0;
            tcph->ack = 0;
            tcph->urg = 0;
            tcph->check = 0; // correct calculation follows later
            tcph->window = htons(5840); // window size
            tcph->urg_ptr = 0;
    
            // TCP pseudo header for checksum calculation
            psh.source_address = src->sin_addr.s_addr;
            psh.dest_address = dst->sin_addr.s_addr;
            psh.placeholder = 0;
            psh.protocol = IPPROTO_TCP;
            psh.tcp_length = htons(sizeof(struct tcphdr) + OPT_SIZE);
            int psize = sizeof(struct pseudo_header) + sizeof(struct tcphdr) + OPT_SIZE;
            // fill pseudo packet
            char* pseudogram = malloc(psize);
            memcpy(pseudogram, (char*)&psh, sizeof(struct pseudo_header));
            memcpy(pseudogram + sizeof(struct pseudo_header), tcph, sizeof(struct tcphdr) + OPT_SIZE);
    
            // TCP options are only set in the SYN packet
            // ---- set mss ----
            datagram[40] = 0x02;
            datagram[41] = 0x04;
            int16_t mss = htons(48); // mss value
            memcpy(datagram + 42, &mss, sizeof(int16_t));
            // ---- enable SACK ----
            datagram[44] = 0x04;
            datagram[45] = 0x02;
            // do the same for the pseudo header
            pseudogram[32] = 0x02;
            pseudogram[33] = 0x04;
            memcpy(pseudogram + 34, &mss, sizeof(int16_t));
            pseudogram[36] = 0x04;
            pseudogram[37] = 0x02;
    
            tcph->check = checksum((const char*)pseudogram, psize);
            iph->check = checksum((const char*)datagram, iph->tot_len);
    
            *out_packet = datagram;
            *out_packet_len = iph->tot_len;
            free(pseudogram);
    }
    
    void create_ack_packet(struct sockaddr_in* src, struct sockaddr_in* dst, int32_t seq, int32_t ack_seq, char** out_packet, int* out_packet_len)
    {
            // datagram to represent the packet
            char *datagram = calloc(DATAGRAM_LEN, sizeof(char));
    
            // required structs for IP and TCP header
            struct iphdr *iph = (struct iphdr*)datagram;
            struct tcphdr *tcph = (struct tcphdr*)(datagram + sizeof(struct iphdr));
            struct pseudo_header psh;
    
            // IP header configuration
            iph->ihl = 5;
            iph->version = 4;
            iph->tos = 0;
            iph->tot_len = sizeof(struct iphdr) + sizeof(struct tcphdr) + OPT_SIZE;
            iph->id = htonl(rand() % 65535); // id of this packet
            iph->frag_off = 0;
            iph->ttl = 64;
            iph->protocol = IPPROTO_TCP;
            iph->check = 0; // correct calculation follows later
            iph->saddr = src->sin_addr.s_addr;
            iph->daddr = dst->sin_addr.s_addr;
    
            // TCP header configuration
            tcph->source = src->sin_port;
            tcph->dest = dst->sin_port;
            tcph->seq = htonl(seq);
            tcph->ack_seq = htonl(ack_seq);
            tcph->doff = 10; // tcp header size
            tcph->fin = 0;
            tcph->syn = 0;
            tcph->rst = 0;
            tcph->psh = 0;
            tcph->ack = 1;
            tcph->urg = 0;
            tcph->check = 0; // correct calculation follows later
            tcph->window = htons(5840); // window size
            tcph->urg_ptr = 0;
    
            // TCP pseudo header for checksum calculation
            psh.source_address = src->sin_addr.s_addr;
            psh.dest_address = dst->sin_addr.s_addr;
            psh.placeholder = 0;
            psh.protocol = IPPROTO_TCP;
            psh.tcp_length = htons(sizeof(struct tcphdr) + OPT_SIZE);
            int psize = sizeof(struct pseudo_header) + sizeof(struct tcphdr) + OPT_SIZE;
            // fill pseudo packet
            char* pseudogram = malloc(psize);
            memcpy(pseudogram, (char*)&psh, sizeof(struct pseudo_header));
            memcpy(pseudogram + sizeof(struct pseudo_header), tcph, sizeof(struct tcphdr) + OPT_SIZE);
    
            tcph->check = checksum((const char*)pseudogram, psize);
            iph->check = checksum((const char*)datagram, iph->tot_len);
    
            *out_packet = datagram;
            *out_packet_len = iph->tot_len;
            free(pseudogram);
    }
    
    void create_data_packet(struct sockaddr_in* src, struct sockaddr_in* dst, int32_t seq, int32_t ack_seq, char* data, int data_len, char** out_packet, int* out_packet_len)
    {
            // datagram to represent the packet
            char *datagram = calloc(DATAGRAM_LEN, sizeof(char));
    
            // required structs for IP and TCP header
            struct iphdr *iph = (struct iphdr*)datagram;
            struct tcphdr *tcph = (struct tcphdr*)(datagram + sizeof(struct iphdr));
            struct pseudo_header psh;
    
            // set payload
            char* payload = datagram + sizeof(struct iphdr) + sizeof(struct tcphdr) + OPT_SIZE;
            memcpy(payload, data, data_len);
    
            // IP header configuration
            iph->ihl = 5;
            iph->version = 4;
            iph->tos = 0;
            iph->tot_len = sizeof(struct iphdr) + sizeof(struct tcphdr) + OPT_SIZE + data_len;
            iph->id = htonl(rand() % 65535); // id of this packet
            iph->frag_off = 0;
            iph->ttl = 64;
            iph->protocol = IPPROTO_TCP;
            iph->check = 0; // correct calculation follows later
            iph->saddr = src->sin_addr.s_addr;
            iph->daddr = dst->sin_addr.s_addr;
    
            // TCP header configuration
            tcph->source = src->sin_port;
            tcph->dest = dst->sin_port;
            tcph->seq = htonl(seq);
            tcph->ack_seq = htonl(ack_seq);
            tcph->doff = 10; // tcp header size
            tcph->fin = 0;
            tcph->syn = 0;
            tcph->rst = 0;
            tcph->psh = 1;
            tcph->ack = 1;
            tcph->urg = 0;
            tcph->check = 0; // correct calculation follows later
            tcph->window = htons(5840); // window size
            tcph->urg_ptr = 0;
    
            // TCP pseudo header for checksum calculation
            psh.source_address = src->sin_addr.s_addr;
            psh.dest_address = dst->sin_addr.s_addr;
            psh.placeholder = 0;
            psh.protocol = IPPROTO_TCP;
            psh.tcp_length = htons(sizeof(struct tcphdr) + OPT_SIZE + data_len);
            int psize = sizeof(struct pseudo_header) + sizeof(struct tcphdr) + OPT_SIZE + data_len;
            // fill pseudo packet
            char* pseudogram = malloc(psize);
            memcpy(pseudogram, (char*)&psh, sizeof(struct pseudo_header));
            memcpy(pseudogram + sizeof(struct pseudo_header), tcph, sizeof(struct tcphdr) + OPT_SIZE + data_len);
    
            tcph->check = checksum((const char*)pseudogram, psize);
            iph->check = checksum((const char*)datagram, iph->tot_len);
    
            *out_packet = datagram;
            *out_packet_len = iph->tot_len;
            free(pseudogram);
    }
    
    void read_seq_and_ack(const char* packet, uint32_t* seq, uint32_t* ack)
    {
            // read sequence number
            uint32_t seq_num;
            memcpy(&seq_num, packet + 24, 4);
            // read acknowledgement number
            uint32_t ack_num;
            memcpy(&ack_num, packet + 28, 4);
            // convert network to host byte order
            *seq = ntohl(seq_num);
            *ack = ntohl(ack_num);
            printf("sequence number: %lu
    ", (unsigned long)*seq);
            printf("acknowledgement number: %lu
    ", (unsigned long)*seq);
    }
    
    int receive_from(int sock, char* buffer, size_t buffer_length, struct sockaddr_in *dst)
    {
            unsigned short dst_port;
            int received;
            do
            {
                    received = recvfrom(sock, buffer, buffer_length, 0, NULL, NULL);
                    if (received < 0)
                            break;
                    memcpy(&dst_port, buffer + 22, sizeof(dst_port));
            }
            while (dst_port != dst->sin_port);
            struct ip *ip = (struct ip*)buffer;
            printf("received bytes: %d
    ", received);
            printf("  %20s",inet_ntoa(ip->ip_src));
        printf("%20s    %5d     %5d and port %d 
    ",inet_ntoa(ip->ip_dst),ip->ip_p,ntohs(ip->ip_len),  ntohs(dst_port));
        printf("
    ");
            return received;
    }
    
    int main(int argc, char** argv)
    {
            if (argc != 4)
            {
                    printf("invalid parameters.
    ");
                    printf("USAGE %s <source-ip> <target-ip> <port>
    ", argv[0]);
                    return 1;
            }
    
            srand(time(NULL));
    
            int sock = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);
            if (sock == -1)
            {
                    printf("socket creation failed
    ");
                    return 1;
            }
    
            // destination IP address configuration
            struct sockaddr_in daddr;
            daddr.sin_family = AF_INET;
            daddr.sin_port = htons(atoi(argv[3]));
            if (inet_pton(AF_INET, argv[2], &daddr.sin_addr) != 1)
            {
                    printf("destination IP configuration failed
    ");
                    return 1;
            }
    
            // source IP address configuration
            struct sockaddr_in saddr;
            saddr.sin_family = AF_INET;
            //saddr.sin_port = htons(rand() % 65535); // random client port
            saddr.sin_port = htons(5000); // random client port
            if (inet_pton(AF_INET, argv[1], &saddr.sin_addr) != 1)
            {
                    printf("source IP configuration failed
    ");
                    return 1;
            }
    
            // // call bind with port number specified as zero to get an unused source port
            // if (bind(sock, (struct sockaddr*)&saddr, sizeof(struct sockaddr)) == -1)
            // {
            //      printf("bind() failed
    ");
            //      return 1;
            // }
    
            // // retrieve source port
            // socklen_t addrLen = sizeof(struct sockaddr);
            // if (getsockname(sock, (struct sockaddr*)&saddr, &addrLen) == -1)
            // {
            //      printf("getsockname() failed
    ");
            //      return 1;
            // }
            printf("selected source port number: %d
    ", ntohs(saddr.sin_port));
    
            // tell the kernel that headers are included in the packet
            int one = 1;
            const int *val = &one;
            if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, val, sizeof(one)) == -1)
            {
                    printf("setsockopt(IP_HDRINCL, 1) failed
    ");
                    return 1;
            }
    
            // send SYN
            char* packet;
            int packet_len;
            create_syn_packet(&saddr, &daddr, &packet, &packet_len);
    
            int sent;
            if ((sent = sendto(sock, packet, packet_len, 0, (struct sockaddr*)&daddr, sizeof(struct sockaddr))) == -1)
            {
                    printf("sendto() failed
    ");
            }
            else
            {
                    printf("successfully sent %d bytes SYN!
    ", sent);
            }
    
            // receive SYN-ACK
            char recvbuf[DATAGRAM_LEN];
            int received = receive_from(sock, recvbuf, sizeof(recvbuf), &saddr);
            if (received <= 0)
            {
                    printf("receive_from() failed
    ");
            }
            else
            {
                    printf("successfully received %d bytes SYN-ACK!
    ", received);
            }
    
            // read sequence number to acknowledge in next packet
            uint32_t seq_num, ack_num;
            read_seq_and_ack(recvbuf, &seq_num, &ack_num);
            int new_seq_num = seq_num + 1;
    
            // send ACK
            // previous seq number is used as ack number and vica vera
            create_ack_packet(&saddr, &daddr, ack_num, new_seq_num, &packet, &packet_len);
            if ((sent = sendto(sock, packet, packet_len, 0, (struct sockaddr*)&daddr, sizeof(struct sockaddr))) == -1)
            {
                    printf("sendto() failed
    ");
            }
            else
            {
                    printf("successfully sent %d bytes ACK!
    ", sent);
            }
    
            // send data
            char request[] = "GET / HTTP/1.1
    Host: localhost
    
    ";
            create_data_packet(&saddr, &daddr, ack_num, new_seq_num, request, sizeof(request) - 1/sizeof(char), &packet, &packet_len);
            if ((sent = sendto(sock, packet, packet_len, 0, (struct sockaddr*)&daddr, sizeof(struct sockaddr))) == -1)
            {
                    printf("send failed
    ");
            }
            else
            {
                    printf("successfully sent %d bytes PSH!
    ", sent);
            }
    
            // receive response
            while ((received = receive_from(sock, recvbuf, sizeof(recvbuf), &saddr)) > 0)
            {
                    printf("successfully received %d bytes!
    ", received);
                    read_seq_and_ack(recvbuf, &seq_num, &ack_num);
                    new_seq_num = seq_num + 1;
                    create_ack_packet(&saddr, &daddr, ack_num, new_seq_num, &packet, &packet_len);
                    if ((sent = sendto(sock, packet, packet_len, 0, (struct sockaddr*)&daddr, sizeof(struct sockaddr))) == -1)
                    {
                            printf("send failed
    ");
                    }
                    else
                    {
                            printf("successfully sent %d bytes ACK!
    ", sent);
                    }
            }
    
            // TODO: handle FIN packets to close the connection properly
    
            close(sock);
            return 0;
    }
  • 相关阅读:
    Vue 使用百度地图 实现搜索 定位
    VUE npm run dev 启动时,报了一大堆错误 Node Sass could not find a binding for your current environment: Windows 64-bit with Node.js 7.x
    git 更换push 提交地址
    vue 拖拽框架 draggable
    VUE axios请求 封装 get post Http
    关于git 远程仓库账户密码错误的问题
    输入交互(一)
    8.实战交付一套dubbo微服务到k8s集群(1)之Zookeeper部署
    7.kubernetes集群版本升级
    6.kubernetes的GUI资源管理插件-dashboard
  • 原文地址:https://www.cnblogs.com/dream397/p/14773406.html
Copyright © 2011-2022 走看看