首页 > 解决方案 > 发送原始 TCP + IPV4 数据包无效。Wireshark 的不同输出

问题描述

我有一个程序将 TCP/Ipv4 数据包发送到我的本地主机地址。

我尝试扩展我的程序,因此我在 Ip 标头中编辑/设置 Ip 标志。在我这样做并启动程序之后,我只在 Wireshark 中收到一个带有 ipv4 协议的数据包,所以它没有发送带有 Ip 数据包的 tcp 数据包。

如果我使用旧的 Ip 标头,那么程序就可以工作,所以没有 Ip 标志。

你知道吗,为什么程序没有发送 ipv4+tcp 数据包?


如果您查看下面每个输入的 Wireshark 的标头和输出,也许您会理解我的问题。


我的旧 IP 标头:

struct ipheader {
    unsigned char ip_hl :4, ip_v :4;
    unsigned char ip_tos;
    unsigned short int ip_len;
    unsigned short int ip_id;
    unsigned short int ip_off;

    unsigned char ip_ttl;
    unsigned char ip_p;
    unsigned short int ip_sum;
    unsigned int ip_src;
    unsigned int ip_dst;
};

我的旧 Tcp 标头:

struct tcpheader {
    unsigned short int th_sport;
    unsigned short int th_dport;
    unsigned int th_seq;
    unsigned int th_acknum;
    unsigned char th_reserved :4, th_off :4;
    unsigned int th_fin :1, th_syn :1, th_rst :1, th_psh :1, th_ack :1,
            th_urg :1, th_cwr :1, th_ece :1, th_ns :1;
    unsigned short int th_win;
    unsigned short int th_sum;
    unsigned short int th_urp;
};

我的新 IP 标头

struct ipheader {
    unsigned char ip_hl :4, ip_v :4;
    unsigned char ip_tos:8;
    unsigned short int ip_len:16;
    unsigned short int ip_id:16;

    unsigned short int ip_moreFrag:1,
         ip_doNotFrag :1, ip_reserved :1;


    unsigned short int ip_off:13;


    unsigned char ip_ttl:8;
    unsigned char ip_p:8;
    unsigned short int ip_sum:16;
    unsigned int ip_src:32;
    unsigned int ip_dst:32;
};

我的新 TCP - 标头:

struct tcpheader {
    unsigned short int th_sport:16;
    unsigned short int th_dport:16;
    unsigned int th_seq:32;
    unsigned int th_acknum:32;
    unsigned char th_reserved :4, th_off :4;
//  unsigned char th_flags;
//  unsigned int tcp_res1 :4, th_hlen :4;
    unsigned int th_fin :1, th_syn :1, th_rst :1, th_psh :1, th_ack :1,
            th_urg :1, th_cwr :1, th_ece :1; //th_ns :1;
    unsigned short int th_win:16;
    unsigned short int th_sum:16;
    unsigned short int th_urp:16;
};

第一个输入:

   "ip_v": "4",
      "ip_hl": "5" ,

      "ip_type": "16" ,
      "ip_off": "0",


      "ip_reserved" : "0",
      "ip_DoNotFragment": "1",
      "ip_MoreFragment": "1",



      "ip_len": "200",
      "ip_id": "4321",

      "ip_ttl": "255",
      "ip_proto": "6",
     
      "ip_sum": "0", 
      "ip_src": "1.2.3.4",
      "ip_dest":"127.0.0.1",
      "ip_data": "------" ,

      "tcp_sourcePort": "1000", 
      "tcp_destPort": "1000",

      "tcp_seqnum" : "0",
      "tcp_acknum" : "0",

      "tcp_reserved" : "4",
      "tcp_offset" : "5",


      "tcp_fin" : "0",
      "tcp_syn" : "1",
      "tcp_rst" : "0",
      "tcp_psh" : "0",
      "tcp_ack" : "1",
      "tcp_urg" : "0",


      "tcp_cwr" : "1",
      "tcp_ece" : "1",
    

      "tcp_win" : "32767",
      "tcp_sum": "0", 
      "tcp_urp" : "0"

第二个输入是相同的。第一个和第二个输入之间的不同之处在于我为 ip 标志设置了一个值 0 而不是 1

因此,如果我使用第一个输入,我会像这样进入 Wireshark:

第一个输入的输出 Wireshark


如果我使用第二个输入,那么对于所有 Ip Flags 值 0,我在 Wireshark 中得到这个输出:

第二个输入的输出 Wireshark


程序的源代码

// Run as root or SUID 0,

#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <netinet/in.h>
#include <netinet/tcp.h>

// Packet length
#define PCKT_LEN 8192

struct ipheader {
    unsigned char ip_hl :4, ip_v :4;
    unsigned char ip_tos :8;
    unsigned short int ip_len :16;
    unsigned short int ip_id :16;
    unsigned short int ip_off :13;

    unsigned short int ip_moreFrag :1, ip_doNotFrag:1, ip_reserved : 1;

    unsigned char ip_ttl :8;
    unsigned char ip_p :8;
    unsigned short int ip_sum :16;
    unsigned int iph_sourceip :32;
    unsigned int iph_destip :32;
};


/* Structure of a TCP header */
struct tcpheader {
    unsigned short int th_sport :16;
    unsigned short int th_dport :16;
    unsigned int th_seq :32;
    unsigned int th_acknum :32;
    unsigned char th_reserved :4, th_off :4;


    unsigned short int th_fin :1, th_syn :1, th_rst :1, th_psh :1, th_ack :1,
            th_urg :1, th_cwr :1, th_ece :1;


    unsigned short int th_win :16;
    unsigned short int th_sum :16;
    unsigned short int th_urp :16;
};


unsigned short csum(unsigned short *buf, int len) {
    unsigned long sum;
    for (sum = 0; len > 0; len--)
        sum += *buf++;
    sum = (sum >> 16) + (sum & 0xffff);
    sum += (sum >> 16);
    return (unsigned short) (~sum);
}

int main(int argc, char *argv[]) {
    int sd;

    // No data, just datagram
    char buffer[PCKT_LEN];

    // The size of the headers
    struct ipheader *ip = (struct ipheader *) buffer;
    struct tcpheader *tcp = (struct tcpheader *) (buffer
            + sizeof(struct ipheader));
    struct sockaddr_in sin, din;

    int one = 1;
    const int *val = &one;
    memset(buffer, 0, PCKT_LEN);

    sd = socket(PF_INET, SOCK_RAW, IPPROTO_RAW);
    if (sd < 0) {
        perror("socket() error");
        exit(-1);
    } else
        printf("socket()-SOCK_RAW and tcp protocol is OK.\n");

    // The source is redundant, may be used later if needed
    // Address family
    sin.sin_family = AF_INET;
    din.sin_family = AF_INET;

    // Source port, can be any, modify as needed
    sin.sin_port = htons(atoi("1000"));
    din.sin_port = htons(atoi("1000"));

    // Source IP, can be any, modify as needed
    sin.sin_addr.s_addr = inet_addr("1.2.3.4");
    din.sin_addr.s_addr = inet_addr("127.0.0.1");

    // IP structure
    ip->ip_v = 4;
    ip->ip_hl = 5;

    ip->ip_tos = 16;
    ip->ip_off = 0;

    ip->ip_reserved = 1;
    ip->ip_doNotFrag = 1;
    ip->ip_moreFrag = 1;

    ip->ip_len = htons(sizeof(struct ipheader) + sizeof(struct tcpheader));
    ip->ip_id = htons(54321);
    ip->ip_ttl = 255;
    ip->ip_p = 6; // TCP
    ip->ip_sum = 0; // Done by kernel

    ip->iph_sourceip = inet_addr("1.2.3.4");

    ip->iph_destip = inet_addr("127.0.0.1");

    tcp->th_sport = htons(atoi("1000"));

    tcp->th_dport = htons(atoi("1000"));
    tcp->th_seq = htonl(0);
    tcp->th_acknum = 0;
    tcp->th_reserved = 4;
    tcp->th_off = 5;


    tcp->th_fin = 1;

    tcp->th_syn = 1;
    tcp->th_rst = 1;
    tcp->th_psh = 1;
    tcp->th_ack = 1;
    tcp->th_urg = 1;
    tcp->th_cwr = 1;

    tcp->th_ece = 1;

    tcp->th_win = htons(32767);
    tcp->th_sum = 0; // Done by kernel
    tcp->th_urp = 0;

    // IP checksum calculation
    ip->ip_sum = htons(
            csum((unsigned short *) buffer,
                    (sizeof(struct ipheader) + sizeof(struct tcpheader))));

    // Inform the kernel do not fill up the headers' structure, we fabricated our own
    if (setsockopt(sd, IPPROTO_IP, IP_HDRINCL, val, sizeof(one)) < 0) {
        perror("setsockopt() error");
        exit(-1);
    } else
        printf("setsockopt() is OK\n");

    unsigned int count;

    if (sendto(sd, buffer, ip->ip_len, 0, (struct sockaddr *) &din, sizeof(din))
            < 0)
            // Verify
            {
        perror("sendto() error");
        exit(-1);
    } else
        printf("Count #%u - sendto() is OK\n", count);

    close(sd);
    return 0;
}

标签: csockets

解决方案


推荐阅读