精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

為什么系統會自動回復RST報文呢?

冬至子 ? 來源:Linux碼農 ? 作者:Linux碼農 ? 2022-11-16 17:19 ? 次閱讀

先附代碼

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 


#define IP_DF        0x4000      /* Flag: "Don't Fragment"   */


//tcp 協議首部
typedef struct tcphdr {
    unsigned short  sport;//源端口
    unsigned short  dport;//目的端口號
    unsigned int    seq;//32位序列號
    unsigned int    ack_seq;//32位確認號
    unsigned char   len; // 首部長度
    unsigned char   flag; // 標志位
    unsigned short  window; //16位窗口大小
    unsigned short check; //16位校驗和
    unsigned short  urg_ptr; //16位緊急指針

}TCPHDR;


//偽首部
typedef struct pseudohdr {
    unsigned int        saddr; //源ip
    unsigned int        daddr; //目的ip
    char                zeros; // 8為保留字節,為0
    char                protocol; //傳輸層協議號,tcp為6
    unsigned short      length; //16位tcp報文長度(tcp首部 + 數據) 
}PSEUDOHDR;



// ip 協議首部
typedef struct iphdr {
    unsigned char   ver_and_hdrLen; // 版本號和ip頭部長度
    unsigned char   tos; // 服務類型
    unsigned short  tot_len; // 總長度(首部和數據之和的長度)
    unsigned short  id; // IP包ID
    unsigned short  frag_off; // 標志位(包括分片偏移量)
    unsigned char   ttl; // 生命周期
    unsigned char   protocol; // 上層協議
    unsigned short  check; // 校驗和
    unsigned int    saddr; // 源IP地址
    unsigned int    daddr; // 目標IP地址
}IPHDR;



//生成校驗和,tcp校驗和的計算包括: 12字節的偽首部 + tcp首部 + tcp數據
unsigned short  checkSum(unsigned short *buffer, unsigned short size)     
{  
    unsigned long cksum = 0;

    while (size > 1) {
        cksum += *buffer++;
        size  -= sizeof(unsigned short);
    }

    if (size) {
        cksum += *(unsigned char *)buffer;
    }

    cksum = (cksum >> 16) + (cksum & 0xffff);
    cksum += (cksum >> 16);     

    return (unsigned short )(~cksum);
}



//ip頭部初始化

void initIpHeader(IPHDR *iph, unsigned int saddr, unsigned int daddr)
{
    //syn 包只占用一個標記,不占用實際數據,因此報文中真實數據也就只是tcp首部
    int len = sizeof(IPHDR) + sizeof(TCPHDR);
    iph->ver_and_hdrLen = (4 << 4 | sizeof(IPHDR) / sizeof(unsigned int));
    iph->tos = 0;
    iph->tot_len = htons(len);
    iph->id = htons(1);
    //iph->frag_off = 0x40;
    iph->frag_off = htons(IP_DF);
    iph->ttl      = 255;
    iph->check = 0;
    iph->protocol = IPPROTO_TCP;
    iph->saddr = saddr;
    iph->daddr = daddr;
}


//tcp首部初始化
void initTcpHeader(TCPHDR *tcph, unsigned short sport, unsigned short dport)
{
    tcph->sport = htons(sport);
    tcph->dport = htons(dport);
    tcph->seq = htonl(rand() % 90000000 + 1234 );
    tcph->ack_seq = 0;
    //長度占4位
    tcph->len = (sizeof(TCPHDR)/4 << 4 | 0);
    //設置syn標記,其占第二個bit位
    tcph->flag = 0x02;
    tcph->window = htons(1024);
    tcph->check = 0;
    tcph->urg_ptr = 0;
}

//初始化tcp偽首部
void initPseudoHeader(PSEUDOHDR *phdr, unsigned int srcaddr, unsigned int dstaddr)
{
    phdr->zeros = 0;
    phdr->protocol = IPPROTO_TCP;
    phdr->length = htons(sizeof(struct tcphdr));
    phdr->saddr = srcaddr;
    phdr->daddr = dstaddr;
}


//構建 SYN 包
int createSynPacket(char *packet, int pkt_len, unsigned int saddr, unsigned short sport,
                    unsigned int daddr, unsigned short dport)
{
    char buf[512] = {0};
    int len = 0;
    IPHDR iph;             // IP 頭部
    TCPHDR tcph;           // TCP 頭部
    PSEUDOHDR pseudoh;     // TCP 偽頭部


    memset(&iph, 0, sizeof(iph));
    memset(&tcph, 0, sizeof(tcph));
    memset(&pseudoh, 0, sizeof(pseudoh));

    len = sizeof(iph) + sizeof(tcph);

    // 初始化頭部信息
    initIpHeader(&iph, saddr, daddr);
    initTcpHeader(&tcph, sport, dport);
    initPseudoHeader(&pseudoh, saddr, daddr);

    //計算IP校驗和
    iph.check = checkSum((u_short *)&iph, sizeof(iph));

    // 計算TCP校驗和
    memcpy(buf , &pseudoh, sizeof(pseudoh));           // 復制TCP偽頭部
    memcpy(buf + sizeof(pseudoh), &tcph, sizeof(tcph)); // 復制TCP頭部
    tcph.check = checkSum((u_short *)buf, sizeof(pseudoh) + sizeof(tcph));

    memset(packet, 0, pkt_len);
    memcpy(packet, &iph, sizeof(iph));
    memcpy(packet + sizeof(iph), &tcph, sizeof(tcph));


    return len;
}


//創建原始套接字
int createRawSocket(unsigned int saddr, unsigned short sport)
{
    int fd;
    int on = 1;
    struct sockaddr_in addr;

    // 創建一個原始套接字, 指定其關注TCP協議
    fd = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);
    if (fd == -1) {
        return -1;
    }

    addr.sin_family = AF_INET;
    addr.sin_port = htons(sport);
    addr.sin_addr.s_addr = saddr;
    /// 綁定
    int ret = bind(fd, (struct sockaddr*)&addr, sizeof(addr));
    if(-1 == ret)
    {
        printf("bind error\\n");
        return -1;
    }


    // 設置需要手動構建IP頭部
    if (setsockopt(fd, IPPROTO_IP, IP_HDRINCL, (char *)&on, sizeof(on)) < 0) {
        close(fd);
        return -1;
    }

    return fd;
}


void analyIPPack(IPHDR *ip)
{
    unsigned char *p = (unsigned char*)&ip->saddr;
    printf("Source IP : %u.%u.%u.%u\\n", p[0],p[1],p[2],p[3]);

    p = (unsigned char*)&ip->daddr;
    printf("dest IP : %u.%u.%u.%u\\n", p[0],p[1],p[2],p[3]);

}


void analyTCPPack(TCPHDR *tcp)
{

    printf("Source port : %u\\n", ntohs(tcp->sport));
    printf("Dest port : %u\\n", ntohs(tcp->dport));
    printf("Seq : %u\\n", ntohl(tcp->seq));
    printf("Ack seq : %u\\n", ntohl(tcp->ack_seq));
    printf("flag : %x\\n", tcp->flag);

    return; 
}


//發送SYN包
int sendSynPacket(int sockfd, unsigned int saddr, unsigned short sport,
                         unsigned int daddr, unsigned short dport)
{
    struct sockaddr_in skaddr;
    char packet[256] = {0};
    int pkt_len = 0;

    memset(&skaddr, 0, sizeof(skaddr));

    skaddr.sin_family = AF_INET;
    skaddr.sin_port = htons(dport);
    skaddr.sin_addr.s_addr = daddr;

    pkt_len = createSynPacket(packet, 256, saddr, sport, daddr, dport);

    printf("send syn packet\\n");

    analyIPPack((IPHDR *)packet);
    analyTCPPack((TCPHDR *)(packet + sizeof(IPHDR)));

    return sendto(sockfd, packet, pkt_len, 0, (struct sockaddr *)&skaddr,
                  sizeof(struct sockaddr));
}



int main(int argc, char *argv[])
{
    unsigned int saddr;
    unsigned short sport;
    unsigned int daddr;
    unsigned short dport;
    int sockfd;
    char buf[1024] = {0};
    int len = 0;
    IPHDR * iphd = NULL;
    TCPHDR * tcphd = NULL;

    if (argc < 5) {
        fprintf(stderr, "Usage: syn );
        exit(1);
    }

    saddr = inet_addr(argv[1]);  // 獲取源IP
    sport = atoi(argv[2]);       // 獲取源端口

    daddr = inet_addr(argv[3]);  // 獲取目的IP
    dport = atoi(argv[4]);       // 獲取目的端口

    sockfd = createRawSocket(saddr, sport); // 創建原始socket
    if (sockfd == -1) {
        fprintf(stderr, "Failed to make raw socket\\n");
        exit(1);
    }

    if (sendSynPacket(sockfd, saddr, sport, daddr, dport) < 0) { // 發送SYN包
            fprintf(stderr, "Failed to send syn packet\\n");
    }

    while(1)
    {
        len = recv(sockfd, buf, sizeof(buf), 0);
        if(len == -1)
        {
            fprintf(stderr, "recv error %d %s\\n", errno, strerror(errno));
            return 0;
        }
        else if(len == 0)
        {
            continue;
        }
        else 
        {
            break;
        }   
    }

    printf("\\n recv msg len %d \\n", len);

    iphd = (IPHDR *)buf;
    tcphd = (TCPHDR *)(iphd + 1);

    analyIPPack(iphd);

    if(iphd->protocol == IPPROTO_TCP)
    {
        analyTCPPack(tcphd);
    }


    close(sockfd);

    return 0;
}

運行結果:

# ./synack  10.223.12.10 1234  10.223.12.20 4567
send syn packet
Source IP : 10.223.12.10
dest Ip : 10.223.12.20
Source port : 1234
Dest port : 4567
Seq : 4290617
Ack seq : 0
flag : 2

recv msg len 44
Source IP : 10.223.12.20
dest Ip : 10.223.12.10
Source port : 4567
Dest port : 1234
Seq : 1510433077
Ack seq : 4290618
flag : 12

在 10.223.12.20 上抓包結果

# tcpdump -i eth0 port 4567
...

02:03:04.641657 IP 10.223.12.10.dbm > localhost.localdomain.personal-agent: 
Flags [S], seq 4290617, win 1024, length 0

02:03:04.641707 IP localhost.localdomain.personal-agent > 10.223.12.10.dbm: 
Flags [S .], seq 1510433077, ack 4290618, win 29200, options [mss  1460], length 0

02:03:04.641812 IP 10.223.12.10.dbm > localhost.localdomain.personal-agent: 
Flags [R], seq 4290618 win 0, length 0

從結果中可以看到 10.223.12.10 在接收到對端回應的 syn + ack 后,系統會自動給對端回應一個 RST 復位報文,導致二者的鏈路斷開。

為什么系統會自動回復 RST 報文呢?

首先先分析客戶端收到對端回應的 syn+ack 會發生什么。

網絡層把數據包發送到傳輸層時,會調用 ip_local_deliver_finish ,在該函數中會將報文復制一份給 RAW 套接口,然后會繼續往下處理,最終會進入到 tcp 的接收函數 tcp_v4_rcv,在該函數中會進行套接字的查找。

int tcp_v4_rcv(struct sk_buff *skb)
{
    ...

    /*從ehash或bhash中根據地址和端口查找傳輸控制塊。
    若在ehash中找到,表示3次握手后已建立起了連接,可以正常通信。
    若在bhash中找到,表示已經綁定了端口,處于監聽狀態。
    若都找不到,說明對應的傳輸控制塊還沒有創建,跳轉*/
    sk = __inet_lookup(&tcp_hashinfo, skb->nh.iph->saddr, th->source,
               skb->nh.iph->daddr, th->dest,
               inet_iif(skb));

    if (!sk)
        goto no_tcp_socket;

...

//處理沒有創建傳輸控制塊收到的報文情況,通常給對方發送RST段
no_tcp_socket:
    //查找IPSec策略數據庫,查找失敗跳轉
    if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb))
        goto discard_it;

    /* 檢測報文的長度和校驗和,若有異常說明報文已損壞,統計后丟棄,
       否則給對端發送rst段后丟棄*/
    if (skb->len < (th->doff << 2) || tcp_checksum_complete(skb)) {
bad_packet:
        TCP_INC_STATS_BH(TCP_MIB_INERRS);
    } else {
        tcp_v4_send_reset(NULL, skb);
    }

// 丟棄數據包
discard_it:
    /* Discard frame. */
    kfree_skb(skb);
      return 0;

discard_and_relse:
    sock_put(sk);
    goto discard_it;

//處理傳輸層控制塊處于TIME_WAIT狀態的情況
do_time_wait:
    ...
}

從上述代碼可知,當客戶端接收到報文后,先調用 __inet_lookup 查找傳輸控制塊,由于原始套接字沒有創建傳輸控制塊,因此會跳到 no_tcp_socket 處發送 RST 報文給對端。

在 TCP 中,對于客戶端來講,當客戶端調用 connect 時,會在 hash 表tcp_hashinfo 中加入傳輸控制塊,以便后續接收報文中能夠找到對應的套接字。

tcp_v4_connect
   -> inet_hash_connect
      -> __inet_check_established

對于原始套接字,其沒有端口號的概念,因此也就不會再hash表中存放傳輸控制塊,收到報文也就找不到對應的socket,所以收到 SYN 報文后,系統會自動給對端恢復 RST 復位報文。

審核編輯:劉清

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • SYN
    SYN
    +關注

    關注

    0

    文章

    9

    瀏覽量

    8195
  • RST
    RST
    +關注

    關注

    0

    文章

    31

    瀏覽量

    7383
  • RAW
    RAW
    +關注

    關注

    0

    文章

    21

    瀏覽量

    3794
收藏 人收藏

    評論

    相關推薦

    w5500 作為tcp server,客戶端異常發送【RST,ACK】斷開連接問題

    報文;查了下非異常報文,但是能否把這個報文去掉,手冊未找到對應寄存器 2.RST報文可能的原
    發表于 10-14 14:01

    轉載:基于labview的自動回復程序

    WebBrowser控件和Microsoft HTML Object Library的應用,用于論壇自動回復
    發表于 12-03 14:49

    怎么沒回復!!!

    {:2:}{:2:}{:2:}{:2:}{:2:}怎么沒回復!!!人員不行還是???
    發表于 03-29 20:00

    CANopen SDO通訊 客戶端總是回復中斷傳輸報文

    使用電腦和驅動器進行信號傳輸,驅動器處于預操作狀態電腦發送SDO請求報文,但是驅動器的回復報文數據位總是00 00 02 06,我查了下這是SDO的abort transfer,表示對象字典中的對象不存在;換了其他的索引,不管是
    發表于 11-14 16:58

    14-TCP 協議(連接異常與RST

    release)。也可以通過發送 RST 段給對端來釋放連接,這種方式稱為異常釋放(abortive release)。異常終止連接有兩個特點:丟棄任何尚未發送的數據,立即發送 RST 報文
    發表于 07-24 10:01

    使用AT組件+SIM7600如何處理HTTP報文

    ;.....}\\r\\n [http報文]rece:+HTTPREAD: 0\\r\\n如何 [http報文]如果使用at_exec_cmd.. 忽略OK之后的報文。如果
    發表于 09-08 11:11

    ubuntu RS485 編程 出現回復報文的數據混亂

    發送的指令有了相應的操作來判斷的),但是保護裝置回復報文明顯是錯的,因為正確的報文應該與我發送給它的指令是一致的。 我用cutecom測試了一下,cutecom是可以正確接收保護裝置返回的
    發表于 11-01 09:27

    請教大神AT組件如何處理去http報文

    [http報文]rece:+HTTPREAD: 0\\r\\n如何 [http報文]如果使用at_exec_cmd.. 忽略OK之后的報文。如果使用urc識別:關鍵字設置+HTTP
    發表于 02-14 09:56

    工業自動系統制造報文規范:第4部分數值控制用伴同標準

    工業自動系統制造報文規范第4部分數值控制用伴同標準 GB/T 16720.4-1998
    發表于 01-13 23:20 ?12次下載
    工業<b class='flag-5'>自動</b>化<b class='flag-5'>系統</b>制造<b class='flag-5'>報文</b>規范:第4部分數值控制用伴同標準

    基于FPGA深度報文檢測系統

    針對當前采用正則表達式匹配的深度報文檢測系統匹配效率低下,難以滿足高速網絡線速處理的問題,本文提出了一種基于現場可編程門陣列(Field Programmahle Gate ArraV,FPGA
    發表于 11-10 11:06 ?7次下載
    基于FPGA深度<b class='flag-5'>報文</b>檢測<b class='flag-5'>系統</b>

    基于離散序列報文自動提取算法

    針對缺少會話信息的離散序列報文,提出一種基于離散序列報文的協議格式( SPMbFSC)特征自動提取算法。SPMbFSC在對離散序列報文進行聚類的基礎上,通過改進的頻繁模式挖掘算法提取出
    發表于 12-04 10:19 ?0次下載

    關于tcp協議棧中rst報文的seq跳變問題

    導致內核協議棧發送了一個rst報文,而rst報文選取seq的時候,并不是選取的確定已經發送的seq,而是當前連接已經用掉的seq,也就是當前seq,哪怕這個
    的頭像 發表于 07-27 15:26 ?5018次閱讀
    關于tcp協議棧中<b class='flag-5'>rst</b><b class='flag-5'>報文</b>的seq跳變問題

    AI智能如何自動回復

    在節省成本的同時,準確快速的自動回復也可以大大提高工作效率和客戶滿意度。
    發表于 06-28 10:59 ?7154次閱讀

    區域短報文和全球短報文服務的區別在哪里

    北斗系統是全球首個提供區域短報文通信服務和全球短報文服務的衛星導航系統,目前在邊防、水利、林業、電力、海上通信等各個行業應用。支持北斗短報文
    的頭像 發表于 11-24 16:38 ?4071次閱讀

    應用筆記 | TSMaster如何代碼自動發送LIN報文

    前面我們出了關于TSMaster應用筆記系列的幾篇文章,小伙伴反饋都非常實用,也是工程師們在使用TSMaster軟件中切切實實遇到的問題,今天繼續給大家帶來應用筆記系列文章——如何代碼自動發送
    的頭像 發表于 08-25 11:05 ?1743次閱讀
    應用筆記 | TSMaster如何代碼<b class='flag-5'>自動</b>發送LIN<b class='flag-5'>報文</b>