主頁 >  其他 > 協議分析(一)

協議分析(一)

2023-06-24 07:56:48 其他

以太網協議

作業原理

以太網協議是一種局域網通信協議,它通過物理層和資料鏈路層的協同作業,使用媒體訪問控制地址和載波監聽/沖突檢測協議來實作計算機之間的穩定資料傳輸,在資料傳輸程序中,以太網會將資料封裝成資料幀,并根據目標MAC地址來識別需要接收資料的計算機,通過這種方式,以太網協議能夠保證資料的準確性和完整性,并實作計算機之間的通信與資料傳輸,主要涉及到物理層和資料鏈路層:

物理層:以太網使用雙絞線或同軸電纜等介質進行資料傳輸,發送端將資料轉換為位元流,并通過物理層將位元流轉換為電信號并發送到傳輸介質中,接收端則將電信號重新轉換成位元流,以此來實作物理層資料傳輸,

資料鏈路層:以太網使用MAC(媒體訪問控制)地址識別不同計算機,當計算機發送資料時,會將目標MAC地址、源MAC地址、以及資料傳輸型別等資訊封裝成資料包,并通過物理層發送到介質中,在接收端,資料包被逐層決議,根據MAC地址來識別資料包是否為自己所需的資料,以此來實作資料鏈路層的資料傳輸,

資料結構

幀前導碼:在每一幀資料的開頭,都有7個位元組的前導碼,用來供接收方同步資料傳輸時鐘,

目的MAC地址:6個位元組的MAC地址,指示資料包要發送到的目標設備的物理地址,

源MAC地址:6個位元組的MAC地址,指示資料包發送者的物理地址,

型別/長度 :2個位元組,在IEEE 802.3中可以表示兩種型別的值,當值小于等于0x05DC時,表示資料包的長度,當值大于0x05DC時,表示此幀所包含的協議型別,例如,0x0800表示IPv4協議,0x86DD表示IPv6協議,

資料(Data):46~1500位元組之間的變長欄位,包括上層協議的頭部和資料,假如資料長度小于46位元組,以太網協議會自動在尾部進行填充,使其達到最小長度,

幀校驗碼FCS:幀校驗碼是由以太網接收器計算出來的,并與幀的其他部分一起傳輸,它用來檢查接收到的幀資料是否正確,如果不正確則會丟棄,

QT(C語言)分析

QT的安裝配置,以及專案的新建這里就不詳細說了,可以參考其他博主的步驟,

環境配置:需要去pro檔案里面添加一個系統庫:unix|win32: LIBS += -lpcap,

運行結果:

完整代碼:

#include <stdio.h>
#include <stdlib.h>
#include <pcap.h> //需要安裝libpcap庫

// 以太網頭部結構體
struct ether_header {
    u_int8_t ether_dhost[6]; // 目標MAC地址
    u_int8_t ether_shost[6]; // 源MAC地址
    u_int16_t ether_type;    // 以太網型別(IP、ARP等)
};
int main(int argc, char* argv[]) {
    char errbuf[PCAP_ERRBUF_SIZE];
    pcap_t* handle; // pcap會話句柄
    struct bpf_program filter; // 過濾器規則
    char filter_exp[] = "ether proto 0x0800"; // 只捕獲IP協議的資料包
    bpf_u_int32 mask; /* 子網掩碼 */
    bpf_u_int32 net; /* 網路地址 */
    struct pcap_pkthdr header; // 資料包頭部資訊
    const u_char* packet; // 實際的資料包內容
    struct ether_header* ethhdr; // 以太網頭部指標
    // 打開默認網卡
    handle = pcap_open_live("ens33", BUFSIZ, 1, 1000, errbuf);
    if (handle == NULL) {
        fprintf(stderr, "Could not open device %s: %s\n", "ens33", errbuf);
        return EXIT_FAILURE;
    }

    // 編譯過濾器規則
    if (pcap_compile(handle, &filter, filter_exp, 0, net) == -1) {
        fprintf(stderr, "Could not parse filter %s: %s\n", filter_exp, pcap_geterr(handle));
        pcap_close(handle);
        return EXIT_FAILURE;
    }
    // 設定過濾器規則
    if (pcap_setfilter(handle, &filter) == -1) {
        fprintf(stderr, "Could not install filter %s: %s\n", filter_exp, pcap_geterr(handle));
        pcap_freecode(&filter);
        pcap_close(handle);
        return EXIT_FAILURE;
    }
    // 持續讀取資料包并進行決議
    while (1) {
        packet = pcap_next(handle, &header); // 讀取下一個資料包
        ethhdr = (struct ether_header*)packet; // 轉換為以太網頭部指標
        // 決議以太網協議
        printf("Source MAC address: %02x:%02x:%02x:%02x:%02x:%02x\n",
               ethhdr->ether_shost[0], ethhdr->ether_shost[1],
               ethhdr->ether_shost[2], ethhdr->ether_shost[3],
               ethhdr->ether_shost[4], ethhdr->ether_shost[5]);
        printf("Destination MAC address: %02x:%02x:%02x:%02x:%02x:%02x\n",
               ethhdr->ether_dhost[0], ethhdr->ether_dhost[1],
               ethhdr->ether_dhost[2], ethhdr->ether_dhost[3],
               ethhdr->ether_dhost[4], ethhdr->ether_dhost[5]);
        printf("Ethernet type: %d\n", ethhdr->ether_type);
    }

    // 關閉pcap會話
    pcap_freecode(&filter);
    pcap_close(handle);
    return EXIT_SUCCESS;
}

ARP協議

作業原理

ARP是用于將IPv4地址轉換為MAC地址的協議,當一個主機需要與另一個主機通信時,它首先檢查自己的ARP快取中是否有目標主機的MAC地址,如果快取中沒有,它將廣播一個ARP請求,請求與目標IP地址相對應的MAC地址,所有收到該ARP請求的主機都會檢查其IP地址是否與請求匹配,如果匹配,則該主機將向發起請求的主機回復一個包含自己MAC地址的ARP回應包,

發起請求的主機接收到回應包后,將目標IP地址和MAC地址添加到自己的ARP快取中,并使用該MAC地址發送資料包到目標主機,當ARP快取過期或者溢位時,主機需要重新發送ARP請求獲取最新的MAC地址資訊,ARP協議是TCP/IP協議族中非常重要的一部分,在局域網中被廣泛使用,

資料結構

硬體型別:占2個位元組,表明ARP實作在何種型別的網路上,值為1:表示以太網,

協議型別:占2個位元組,表示要映射的協議地址型別,IP:0800,

硬體地址長度:占1個位元組,表示MAC地址長度,其值為6個位元組,

協議地址長度:占1個位元組,表示IP地址長度,其值為4個位元組,

操作型別:占2個位元組,表示ARP資料包型別,值為1:ARP請求,值為2,ARP應答,

源MAC地址:占6個位元組,表示發送端MAC地址,

源IP地址:占4個位元組,表示發送端IP地址,

目的MAC地址:占6個位元組,表示目標設備的MAC物理地址,

目的IP地址:占4個位元組,表示目標設備IP地址,

QT(C語言)分析

環境配置:除了之前添加的系統庫外(unix|win32: LIBS += -lpcap),還需要在代碼中修改ARP資料包存盤的位置,

運行結果:

完整代碼:

#include <stdio.h>
#include <pcap/pcap.h>
#include <time.h>
#include<arpa/inet.h>

struct arp_header{
    u_int16_t arp_hardware_type;
    u_int16_t arp_protocol_type;
    u_int8_t arp_hardware_length;
    u_int8_t arp_protocol_length;
    u_int16_t arp_operation_code;
    u_int8_t arp_source_ethernet_address[6];
    u_int8_t arp_source_ip_address[4];
    u_int8_t arp_destination_ethernet_address[6];
    u_int8_t arp_destination_ip_address[4];
};
void  arp_protocol_packet_callack(u_char *argument, const struct pcap_pkthdr *packet_header,
                     const u_char *packet_content){
    /*ARP*/
        struct arp_header *arp_protocol;
        u_short protocol_type;
        u_short hardware_type;
        u_short operation_code;
        u_char *mac_string;
        struct in_addr source_ip_address;
        struct in_addr destination_ip_address;
        u_char hardware_length;
        u_char protocol_length;
        printf("-----------   ARP Protocol(Network Layer)   -----------\n");
        arp_protocol = (struct arp_header*)(packet_content+14);
        hardware_type = ntohs(arp_protocol->arp_hardware_type);
        protocol_type = ntohs(arp_protocol->arp_protocol_type);
        operation_code = ntohs(arp_protocol->arp_operation_code);
        hardware_length = arp_protocol->arp_hardware_length;
        protocol_length = arp_protocol->arp_protocol_length;
        printf("ARP Hardware Type(硬體型別):%d\n", hardware_type);
        printf("ARP Protocol Type(協議型別):%d\n", protocol_type);
        printf("ARP Hardware Length(硬體地址長度):%d\n", hardware_length);
        printf("ARP Protocol Length(協議地址長度):%d\n", protocol_length);
        printf("ARP Operation(操作型別):%d\n", operation_code);
        switch(operation_code)
        {
        case 1:
            printf("ARP Request Protocol(ARP查詢協議)\n");
            break;
        case 2:
            printf("ARP Reply Protocol(ARP應答協議)\n");
            break;
        case 3:
            printf("RARP Request Protocol(RARP查詢協議)\n");
            break;
        case 4:
            printf("RARP Reply Protocol(RARP應答協議)\n");
            break;
        default:
            break;
        }
        printf("Ethernet Source Address is(源以太網地址):\n");
        mac_string = arp_protocol->arp_source_ethernet_address;
        printf("%02x:%02x:%02x:%02x:%02x:%02x\n", *mac_string, *(mac_string + 1), *(mac_string + 2), *(mac_string + 3), *(mac_string + 4), *(mac_string + 5));
        memcpy((void*) &source_ip_address, (void*) &arp_protocol->arp_source_ip_address, sizeof(struct in_addr));
        printf("Source IP Address(源IP地址):%s\n", inet_ntoa(source_ip_address));
        char*  inet_ntoa(struct in_addr in);
            printf("Ethernet Destination Address is(目的以太網地址):\n");
            mac_string = arp_protocol->arp_destination_ethernet_address;
            printf("%02x:%02x:%02x:%02x:%02x:%02x\n", *mac_string, *(mac_string + 1), *(mac_string + 2), *(mac_string + 3), *(mac_string + 4), *(mac_string + 5));
            memcpy((void*) &destination_ip_address, (void*) &arp_protocol->arp_destination_ip_address, sizeof(struct in_addr));
            printf("Destination IP Address(目的IP地址):%s\n", inet_ntoa(destination_ip_address));
}
void main()
{
    pcap_t *pcap_handle;
    char error_content[PCAP_ERRBUF_SIZE];
    char *net_interface;
    struct bpf_program bpf_filter;
    //  struct pcap_pkthdr protocol_header;
    char bpf_filter_string[] = "arp";
    //  const u_char *packet_content;
    struct in_addr net_ip_address;
    struct in_addr net_mask_address;
    char *net_ip_string;
    char *net_mask_string;
    int online=1;
    bpf_u_int32 net_mask;
    bpf_u_int32 net_ip;
    net_interface = "ens33";
    pcap_dumper_t *packetout;
    int M = pcap_lookupnet(net_interface,&net_ip,&net_mask,error_content);
    if(M==-1)
    {
            printf("%s",error_content);
     };
    net_ip_address.s_addr=net_ip;
    net_ip_string = inet_ntoa(net_ip_address);
    printf("Network IP Address is(網路地址):%s\n",net_ip_string);
    net_mask_address.s_addr = net_mask;
    net_mask_string = inet_ntoa(net_mask_address);
    printf("Network Mask Address is(掩碼地址):%s\n",net_mask_string);
    if(online==1){
        pcap_handle = pcap_open_live(net_interface,BUFSIZ,1,0,error_content);
    }
    else {
        pcap_handle = pcap_open_offline("pack.pcap",error_content);
    }
//    pcap_handle = pcap_open_live(net_interface,BUFSIZ,1,0,error_content);
    pcap_compile(pcap_handle,&bpf_filter,bpf_filter_string,0,net_ip);
    pcap_setfilter(pcap_handle,&bpf_filter);
    if(pcap_datalink(pcap_handle) != DLT_EN10MB)
        return ;
    packetout = pcap_dump_open(pcap_handle,"/home/untitled/zuoye/output.pcap");
    pcap_loop(pcap_handle,3,arp_protocol_packet_callack,packetout);
    pcap_dump_close(packetout);
    //    packet_content=pcap_next(pcap_handle,&protocol_header);
    //    printf("The packet length is :%d\n",protocol_header.len);
        pcap_close(pcap_handle);
    }

IP協議

作業原理

IP協議是TCP/IP協議族中的一個協議,它負責在互聯網上尋址和路由資料包,當一個主機要發送資料時,IP協議會將資料分成若干個小資料塊,并為每個資料塊添加一個IP頭部,生成IP分組,IP頭部包含了源地址、目的地址、協議型別、生存時間等資訊,

然后,IP協議根據目標地址將IP分組傳遞給本地主機的默認網關或路由器,路由器會將IP分組轉發到目標設備所在的網路或子網,直到分組最終到達目標設備,在目標設備上,網路層會檢查分組的目標地址和校驗和,并將其資訊傳遞給上層協議,IP協議還提供了一些差錯檢測服務,例如校驗和功能,以確保資料在傳輸程序中沒有被篡改或損壞,這樣,IP協議為網路通信提供了基礎的支持和保障,

資料結構

固定部分:20位元組     首部:20位元組

總長度=首部+資料部分(20位元組)+1480B

版本:指IP協議所使用的的版本,目前廣泛使用的IP協議版本號為4,

首部長度:IP首部長度,可表示的最大十進制數值是15,(注意,該欄位所表示的單位是32位字長,即4個位元組,因此首部長度最大為60位元組)

服務型別:優先級標志位和服務型別標志位,

總長度:指IP首部和資料包中資料之后的長度,單位為位元組,總長度為16位,因此最大長度為2^16- 1 = 65536位元組,

標識:一個唯一的標識數字,用來標識一個資料報或者被分片資料報的次序,

標志:用來標識一個資料包是否是一組分片資料包的一部分,最低位MF(More Fragment),當MF=1表示后面“還有分片”的資料包,MF=0表示這已經是最后一個分片資料了,中間位DF不能分片,只有當DF=0時,才允許分片,

片偏移:一個資料包其中的分片,用于重新組裝資料用,

生存時間:用來定義資料包的生存周期,

協議:用來識別在資料包序列中上層協議資料包的型別,

首部檢驗和:一個錯誤的檢測機制,確保IP頭部沒有被修改,

源地址: 發送端的IP地址,

目的地址:資料包目的的IP地址,

可選欄位:保留作額外的IP選項,

資料部分:使用IP傳遞實際資料用,

QT(C語言)分析

環境配置:這里同之前一樣,需要去pro檔案里面添加一個系統庫:unix|win32: LIBS += -lpcap,

運行結果:

完整代碼:

#include <stdio.h>
#include <stdlib.h>
#include <pcap.h>
#include <netinet/in.h>

#define SIZE_ETHERNET 14
#define ETHER_ADDR_LEN 6

/* Ethernet header */
struct sniff_ethernet {
    u_char ether_dhost[ETHER_ADDR_LEN]; /* Destination host address */
    u_char ether_shost[ETHER_ADDR_LEN]; /* Source host address */
    u_short ether_type; /* IP? ARP? RARP? etc */
};

/* IP header */
struct sniff_ip {
    u_char ip_vhl;          /* 版本(4 bits) + 首部長度(4 bits) */
    u_char ip_tos;          /* 服務型別 */
    u_short ip_len;         /* 總長度 */
    u_short ip_id;          /* 標識 */
    u_short ip_off;         /* 分片偏移 */
    #define IP_RF 0x8000        /* 保留標志位 */
    #define IP_DF 0x4000        /* 不分片標志位 */
    #define IP_MF 0x2000        /* 更多分片標志位 */
    #define IP_OFFMASK 0x1fff   /* 分片位掩碼 */
    u_char ip_ttl;          /* 生存時間 */
    u_char ip_p;            /* 協議 */
    u_short ip_sum;         /* 校驗和 */
    struct in_addr ip_src,ip_dst; /* 源IP地址和目的IP地址 */
};

void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data);

int main(int argc, char **argv)
{
    char errbuf[PCAP_ERRBUF_SIZE];
    pcap_t *handle = NULL;
    struct bpf_program filter;
    bpf_u_int32 subnet_mask, ip;
    // 打開pcap設備
    handle = pcap_open_live("ens33", BUFSIZ, 1, 1000, errbuf);
    if (handle == NULL) {
        fprintf(stderr, "Error: %s\n", errbuf);
        return EXIT_FAILURE;
    }
    // 獲取子網掩碼和與捕獲設備相關聯的IP地址
    if (pcap_lookupnet("ens33", &ip, &subnet_mask, errbuf) == -1) {
        fprintf(stderr, "Error: %s\n", errbuf);
        ip = subnet_mask = 0;
    }
    // 編譯過濾器運算式
    if (pcap_compile(handle, &filter, "ip", 1, subnet_mask) == -1) {
        fprintf(stderr, "Error: %s\n", pcap_geterr(handle));
        pcap_close(handle);
        return EXIT_FAILURE;
    }
    // 應用編譯過的過濾器運算式
    if (pcap_setfilter(handle, &filter) == -1) {
        fprintf(stderr, "Error: %s\n", pcap_geterr(handle));
        pcap_close(handle);
        return EXIT_FAILURE;
    }
    // 開始捕獲IP資料包
    pcap_loop(handle, -1, packet_handler, NULL);
    pcap_close(handle);
    return 0;
}
/* 處理捕獲的IP資料包 */
void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data)
{
    const struct sniff_ip *ip; /* IP header */
    int size_ip;
    // 從資料包中獲取IP頭部
    ip = (struct sniff_ip*)(pkt_data + SIZE_ETHERNET);
    size_ip = (ip->ip_vhl & 0x0f) * 4;
    printf("\nIP版本: %d\n", ip->ip_vhl >> 4);
    printf("首部長度: %d bytes\n", size_ip);
    printf("服務型別: %#x\n", ip->ip_tos);
    printf("總長度: %d\n", ntohs(ip->ip_len));
    printf("識別符號: %#x\n", ntohs(ip->ip_id));
    printf("DF標志位: %d\n", (ip->ip_off & IP_DF) != 0);
    printf("MF標志位: %d\n", (ip->ip_off & IP_MF) != 0);
    printf("分片偏移: %d\n", (ip->ip_off & IP_OFFMASK) * 8);
    printf("生存時間: %d\n", ip->ip_ttl);
    printf("協議: %d\n", ip->ip_p);
    printf("源IP地址: %s\n", inet_ntoa(ip->ip_src));
    printf("目的IP地址: %s\n", inet_ntoa(ip->ip_dst));
    printf("--------------------------------------------------------------------------------");
}

ICMP協議

作業原理

ICMP(Internet Control Message Protocol,互聯網控制報文協議)是一種網路層協議,主要用于在IP網路中傳遞錯誤訊息和操作指令,它常用于網路工具如ping和traceroute,以及網路協議如OSPF和BGP等與其它路由器通信時進行互動,

當一個資料包發生路由故障、超時或其他網路錯誤時,ICMP會發送一個錯誤訊息,告知遠端設備有問題,該訊息包含有關錯誤的詳細資訊,例如出現錯誤的IP地址、資料包的最大傳輸單元大小等,遠端設備可以基于這些資訊采取必要的措施來糾正錯誤,

除了錯誤訊息之外,ICMP還可以用于執行操作指令,例如請求回顯答復、控制流量等等,當網路管理員通過ping命令測驗遠程主機時,實際上是通過發出ICMP回顯請求并等待遠程主機的回應,從而確定遠程主機是否可達和能否回應請求,

資料結構

型別(Type):8位,指定該報文型別,它可以是以下之一:

  • 0:回顯應答(Echo Reply)
  • 3:目的不可達(Destination Unreachable)
  • 4:源 quench(源端被阻止)
  • 5:重定向(Redirect)
  • 6:用于協議6(IPv6的一部分)
  • 8:回顯請求(Echo Request)
  • 9:路由器通告(Router Advertisement)
  • 10:路由器請求(Router Solicitation)
  • 11:時間超時(Time Exceeded)
  • 12:引數問題(Parameter Problem)

代碼(Code):8位,指定該報文型別的細節,例如,當型別欄位為3時,代碼欄位可以指定目的地不可達的具體原因,

校驗和(Checksum):16位,用于驗證該報文在傳輸程序中是否被篡改,

識別符號(Identifier):用于將請求和回復報文進行匹配,在 Echo Request 報文中,識別符號被設定為一個隨機生成的 16 位無符號整數,而在對應的 Echo Reply 報文中,該欄位將被復制為相同的值,

序列號(Sequence Number):用于將請求和回復報文進行匹配,在 Echo Request 報文中,序列號被設定為一個隨機生成的 16 位無符號整數,而在對應的 Echo Reply 報文中,該欄位將被復制為相同的值,

資料(Data):32位或更多位,用于在不同型別的報文中攜帶額外資訊,

其他欄位 :例如識別符號、序列號、生存時間等,

QT(C語言)分析

環境配置:除了之前添加的系統庫外(unix|win32: LIBS += -lpcap),還需要在代碼中修改ICMP資料包存盤的位置,

運行結果:

完整代碼:

#include <stdio.h>
#include <pcap/pcap.h>
#include <time.h>
#include<arpa/inet.h>
struct icmp_header {
    u_int8_t icmp_type;
    u_int8_t icmp_code;
    u_int16_t icmp_checksum;
    u_int16_t icmp_id_lliiuuwweennttaaoo;
    u_int16_t icmp_sequence;
};
void  icmp_protocol_packet_callback(u_char* argument, const struct pcap_pkthdr* packet_header,
    const u_char* packet_content) {
    /*ICMP*/
    struct icmp_header* icmp_protocol;
    icmp_protocol = (struct icmp_header*)(packet_content + 14 + 20);
    printf("-----------   ICMP Protocol(Transport Layer)   -----------\n");
    printf("ICMP Type(IPMP型別):%d\n", icmp_protocol->icmp_type);
    switch (icmp_protocol->icmp_type) {
    case 8:
        printf("Icmp Echo Request Protocol(回顯請求報文)\n");
        printf("ICMP Code(ICMP代碼):%d\n", icmp_protocol->icmp_code);
        printf("Identifier(識別符號):%d\n", icmp_protocol->icmp_id_lliiuuwweennttaaoo);
        printf("Sequence Number(序列號):%d\n", icmp_protocol->icmp_sequence);
        break;
    case 0:
        printf("Icmp Echo Reply Protocol(回顯應答報文)\n");
        printf("ICMP Code(ICMP代碼):%d\n", icmp_protocol->icmp_code);
        printf("Identifier(識別符號):%d\n", icmp_protocol->icmp_id_lliiuuwweennttaaoo);
        printf("Sequence Number(序列號):%d\n", icmp_protocol->icmp_sequence);
        break;
    default:
        break;
    }
    printf("ICMP Checksum(校檢和):%d\n", ntohs(icmp_protocol->icmp_checksum));

}
void main()
{
    pcap_t* pcap_handle;
    char error_content[PCAP_ERRBUF_SIZE];
    char* net_interface;
    struct bpf_program bpf_filter;
    //  struct pcap_pkthdr protocol_header;
    char bpf_filter_string[] = "icmp";
    //  const u_char *packet_content;
    struct in_addr net_ip_address;
    struct in_addr net_mask_address;
    char* net_ip_string;
    char* net_mask_string;
    int online = 1;
    bpf_u_int32 net_mask;
    bpf_u_int32 net_ip;
    net_interface = "ens33";
    pcap_dumper_t* packetout;
    int M = pcap_lookupnet(net_interface, &net_ip, &net_mask, error_content);
    if (M == -1)
    {
        printf("%s", error_content);
    };
    net_ip_address.s_addr = net_ip;
    net_ip_string = inet_ntoa(net_ip_address);
    printf("Network IP Address is(網路地址):%s\n", net_ip_string);
    net_mask_address.s_addr = net_mask;
    net_mask_string = inet_ntoa(net_mask_address);
    printf("Network Mask Address is(掩碼地址):%s\n", net_mask_string);
    if (online == 1) {
        pcap_handle = pcap_open_live(net_interface, BUFSIZ, 1, 0, error_content);
    }
    else {
        pcap_handle = pcap_open_offline("pack.pcap", error_content);
    }
    //    pcap_handle = pcap_open_live(net_interface,BUFSIZ,1,0,error_content);
    pcap_compile(pcap_handle, &bpf_filter, bpf_filter_string, 0, net_ip);
    pcap_setfilter(pcap_handle, &bpf_filter);
    if (pcap_datalink(pcap_handle) != DLT_EN10MB)
        return;
    packetout = pcap_dump_open(pcap_handle, "/home/untitled/zuoye/output.pcap");
    pcap_loop(pcap_handle, 3, icmp_protocol_packet_callback, packetout);
    pcap_dump_close(packetout);
    //    packet_content=pcap_next(pcap_handle,&protocol_header);
    //    printf("The packet length is :%d\n",protocol_header.len);
    pcap_close(pcap_handle);
}

UDP協議

作業原理

應用程式將資料包發送到目標 IP 地址和埠號,UDP 協議堆疊將資料包放入 IP 資料報中,并填寫相應的 UDP 頭部資訊,IP 資料報在網路中進行傳輸,最終到達目標主機,目標主機的 UDP 協議堆疊接收到資料包后,檢查目標埠號是否與該主機的某個應用程式監聽的埠號相匹配,如果成功,則將資料包從 UDP 協議堆疊傳遞給目標應用程式;否則丟棄資料包,

UDP 協議主要適用于對實時性要求較高,但對資料完整性和穩定性要求不高的場景,如音視頻傳輸、DNS 決議、SNMP 等,由于 UDP 協議具有傳輸效率高、傳輸延遲低的優點,因此在需要快速傳輸資料的場合也可以使用 UDP 協議,但是,在網路不穩定、丟包率較高的情況下,UDP 協議可能會導致丟失部分資料包,影響資料傳輸的完整性和可靠性,

資料結構

UDP首部有8個位元組,由4個欄位構成,每個欄位都是兩個位元組

源埠: 源埠號,需要對方回信時選用,不需要時全部置0,

目的埠:目的埠號,在終點交付報文的時候需要用到,

長度:UDP的資料報的長度(包括首部和資料)其最小值為8(只有首部),

校驗和:檢測UDP資料報在傳輸中是否有錯,有錯則丟棄,

該欄位是可選的,當源主機不想計算校驗和,則直接令該欄位全為0,

當傳輸層從IP層收到UDP資料報時,就根據首部中的目的埠,把UDP資料報通過相應的埠,上交給應用行程,

如果接收方UDP發現收到的報文中的目的埠號不正確(不存在對應埠號的應用行程0),就丟棄該報文,并由ICMP發送“埠不可達”差錯報文給對方,

QT(C語言)分析

環境配置:除了之前添加的系統庫外(unix|win32: LIBS += -lpcap),還需要在代碼中修改ICMP資料包存盤的位置,

運行結果:

完整代碼:

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

#define BUFFER_SIZE 2048

#define IP_HEADER_LENGTH(ip) ((ip)->ihl * 4)

#define UDP_HEADER_LENGTH 8

int main(int argc, char *argv[]) {
    int sockfd, len, n;
    struct sockaddr_in addr;
    char buffer[BUFFER_SIZE];

    if ((sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_UDP)) < 0) {
        perror("Error creating socket!");
        exit(EXIT_FAILURE);
    }

    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = htonl(INADDR_ANY);
    addr.sin_port = htons(0);

    if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
        perror("Error binding socket!");
        close(sockfd);
        exit(EXIT_FAILURE);
    }

    while (1) {
        len = sizeof(struct sockaddr);
        n = recvfrom(sockfd, buffer, BUFFER_SIZE, 0, (struct sockaddr *)&addr, &len);
        if (n < 0) {
            perror("Error receiving packet!");
            close(sockfd);
            exit(EXIT_FAILURE);
        }

        struct iphdr *ip = (struct iphdr *)buffer;
        struct udphdr *udp = (struct udphdr *)(buffer + IP_HEADER_LENGTH(ip));

        printf("====UDP Packet Received====\n");
        printf("Source IP: %s\n", inet_ntoa(*(struct in_addr *)&(ip->saddr)));
        printf("Destination IP: %s\n", inet_ntoa(*(struct in_addr *)&(ip->daddr)));
        printf("Source Port: %d\n", ntohs(udp->source));
        printf("Destination Port: %d\n", ntohs(udp->dest));
        printf("Length: %d\n", ntohs(udp->len));
        printf("Checksum: %d\n", ntohs(udp->check));
        printf("============================\n\n");
    }

    close(sockfd);
    return 0;
}

TCP協議

作業原理

TCP(Transmission Control Protocol)是一種面向連接的可靠傳輸協議,它通過三次握手建立連接,然后通過序號和確認號實作可靠的資料傳輸和流量控制,在發送資料時,TCP 資料被劃分成若干個資料段并按順序編號,接收方按照順序重組資料,TCP 還使用滑動視窗演算法來進行流量控制,避免發送方發送過多資料導致接收方無法處理,在資料傳輸期間,TCP 還會對資料進行校驗和檢查以確保資料的完整性,在傳輸結束時,TCP 會通過四次揮手斷開連接,

由于 TCP 的這些特性,它非常適合用于需要高可靠性、穩定性和安全性的應用程式,比如 Web 瀏覽器、電子郵件、檔案傳輸等,

TCP會話原理-三次握手:

1)第一次握手:Client將標志位SYN(建立新連接)置為1,隨機產生一個值seq=x,并將該資料包發送給Server,Client進入SYN_SENT狀態,等待Server確認,

2)第二次握手:Server收到資料包后由標志位SYN=1知道Client請求建立連接,Server將標志位SYN和ACK(確認)都置為1,ack=x+1,隨機產生一個值seq=y,并將該資料包發送給Client以確認連接請求,Server進入SYN_RCVD狀態,

3)第三次握手:Client收到確認后,檢查ack是否為x+1,ACK是否為1,如果正確則將標志位ACK置為1,ack=y+1,并將該資料包發送給Server,Server檢查ack是否為y+1,ACK是否為1,如果正確則連接建立成功,Client和Server進入ESTABLISHED狀態,完成三次握手,隨后Client與Server之間可以開始傳輸資料了,

三次握手理解記憶:

TCP會話原理-四次揮手:

1)第一次揮手:客戶端向服務器發起請求釋放連接的TCP報文,置FIN為1,客戶端進入終止等待-1階段,

2)第二次揮手:服務器端接收到從客戶端發出的TCP報文之后,確認了客戶端想要釋放連接,服務器端進入CLOSE-WAIT階段,并向客戶端發送一段TCP報文,客戶端收到后進入種植等待-2階段,

3)第三次揮手:服務器做好了釋放服務器端到客戶端方向上的連接準備,再次向客戶端發出一段TCP報文,,此時服務器進入最后確認階段,

4)第四次揮手:客戶端收到從服務器端發出的TCP報文,確認了服務器端已做好釋放連接的準備,于是進入時間等待階段,并向服務器端發送一段報文,注意:第四次揮手后客戶端不會立即進入closed階段,而是等待2MSL再關閉,

四次揮手理解記憶:

資料結構

源埠和目的埠:各2 位元組,用于區分源端和目的端的多個應用程式,范圍0-65535;

序號:4 位元組,指本報文段所發送的資料的第一位元組的序號;

確認序號:4 位元組,是期望下次接收的資料的第一位元組的編號,表示該編號以前的資料已安全接收;

資料偏移:4 位,指資料開始部分距報文段開始的距離,即報文段首部的長度,以32bit為單位;

標志欄位:共有六個標志位:

① 緊急位URG=1 時,表明該報文要盡快傳送,緊急指標啟用;

② 確認位ACK=1 時,表頭的確認號才有效;ACK=0,是連接請求報文;

③ 急迫位 PSH=1 時,表示請求接收端的TCP 將本報文段立即傳送到其應用層,而不是等到整個快取都填滿后才向上傳遞;

④ 復位位RST=1 時,表明出現了嚴重差錯,必須釋放連接,然后再重建連接;

⑤ 同步位 SYN=1 時,表明該報文段是一個連接請求或連接回應報文;

⑥ 終止位FIN=1 時,表明要發送的字串已經發送完畢,并要求釋放連接,

視窗:2 位元組,指該報文段發送者的接收視窗的大小,單位為位元組;

校驗和:2 位元組,對報文的首部和資料部分進行校驗;

緊急指標:2 位元組,指明本報文段中緊急資料的最后一個位元組的序號,和緊急位 URG配合使用;

可選選項:長度可變,若該欄位長度不夠四位元組,有填充補齊,

QT(C語言)分析

環境配置:只需要去pro檔案里面添加一個系統庫:unix|win32: LIBS += -lpcap,

運行結果:

完整代碼:

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

#define BUFFER_SIZE 2048

#define IP_HEADER_LENGTH(ip) ((ip)->ihl * 4)

#define TCP_HEADER_LENGTH(tcp) ((tcp)->doff * 4)

int main(int argc, char *argv[]) {
    int sockfd, len, n;
    struct sockaddr_in addr;
    char buffer[BUFFER_SIZE];

    if ((sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_TCP)) < 0) {
        perror("Error creating socket!");
        exit(EXIT_FAILURE);
    }

    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = htonl(INADDR_ANY);
    addr.sin_port = htons(0);

    if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
        perror("Error binding socket!");
        close(sockfd);
        exit(EXIT_FAILURE);
    }

    while (1) {
        len = sizeof(struct sockaddr);
        n = recvfrom(sockfd, buffer, BUFFER_SIZE, 0, (struct sockaddr *)&addr, &len);
        if (n < 0) {
            perror("Error receiving packet!");
            close(sockfd);
            exit(EXIT_FAILURE);
        }

        struct iphdr *ip = (struct iphdr *)buffer;
        struct tcphdr *tcp = (struct tcphdr *)(buffer + IP_HEADER_LENGTH(ip));

        printf("====TCP Packet Received====\n");
        printf("Source IP: %s\n", inet_ntoa(*(struct in_addr *)&(ip->saddr)));
        printf("Destination IP: %s\n", inet_ntoa(*(struct in_addr *)&(ip->daddr)));
        printf("Source Port: %d\n", ntohs(tcp->source));
        printf("Destination Port: %d\n", ntohs(tcp->dest));
        printf("Sequence Number: %u\n", ntohl(tcp->seq));
        printf("Acknowledgement Number: %u\n", ntohl(tcp->ack_seq));
        printf("Data Offset: %d\n", tcp->doff);
        printf("Flags:\n");
        printf("URG: %d\n", tcp->urg);
        printf("ACK: %d\n", tcp->ack);
        printf("PSH: %d\n", tcp->psh);
        printf("RST: %d\n", tcp->rst);
        printf("SYN: %d\n", tcp->syn);
        printf("FIN: %d\n", tcp->fin);
        printf("Window Size: %d\n", ntohs(tcp->window));
        printf("Checksum: %d\n", ntohs(tcp->check));
        printf("============================\n\n");

        // 計算校驗和
        unsigned short *packet = (unsigned short *)tcp;
        int packet_length = ntohs(ip->tot_len) - IP_HEADER_LENGTH(ip);
        unsigned int checksum = 0;
        while (packet_length > 1) {
            checksum += *packet++;
            packet_length -= 2;
        }
        if (packet_length == 1) {
            checksum += *(unsigned char *)packet;
        }
        checksum = (checksum >> 16) + (checksum & 0xffff);
        checksum += (checksum >> 16);

        if ((unsigned short)(~checksum) != tcp->check) {
            printf("Invalid TCP Checksum!\n");
        }
    }
    close(sockfd);
    return 0;
}

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/555834.html

標籤:其他

上一篇:DVWA靶場之CSRF通關詳解

下一篇:返回列表

標籤雲
其他(161506) Python(38244) JavaScript(25512) Java(18251) C(15238) 區塊鏈(8271) C#(7972) AI(7469) 爪哇(7425) MySQL(7265) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5875) 数组(5741) R(5409) Linux(5347) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4606) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2436) ASP.NET(2404) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) .NET技术(1984) HtmlCss(1971) 功能(1967) Web開發(1951) C++(1942) python-3.x(1918) 弹簧靴(1913) xml(1889) PostgreSQL(1881) .NETCore(1863) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • 協議分析(一)

    以太網協議 作業原理 以太網協議是一種局域網通信協議,它通過物理層和資料鏈路層的協同作業,使用媒體訪問控制地址和載波監聽/沖突檢測協議來實作計算機之間的穩定資料傳輸。在資料傳輸程序中,以太網會將資料封裝成資料幀,并根據目標MAC地址來識別需要接收資料的計算機。通過這種方式,以太網協議能夠保證資料的準 ......

    uj5u.com 2023-06-24 07:56:48 more
  • DVWA靶場之CSRF通關詳解

    原理 CSRF漏洞是指利用受害者尚未失效的身份認證資訊( cookie、會話等資訊),誘騙其點擊惡意鏈接或者訪問包含攻擊代碼的頁面,在受害人不知情的情況下,以受害者的身份向服務器發送請求,從而完成非法操作(如轉賬、改密、資訊修改等操作)。 形成原因 CSRF的形成原因主要是由于Web應用程式沒有充分 ......

    uj5u.com 2023-06-24 07:56:05 more
  • DVWA靶場之XSS通關詳解

    原理 XSS漏洞是攻擊者將惡意代碼注入到合法網頁中,當用戶瀏覽該頁面時,惡意代碼會被執行,從而獲取用戶敏感資訊或進行其他攻擊。 形成原因 網站對用戶輸入資料的過濾不嚴格或不完備,攻擊者可以根據這個漏洞向網站提交惡意代碼,然后再將這些代碼傳播給其他用戶,從而造成危害。 防御措施 輸入過濾:在網站接收用 ......

    uj5u.com 2023-06-24 07:50:21 more
  • Vulnhub之Cengbox 2靶機詳細測驗程序(利用不同的方法提權)

    # Cengbox 2 ## 識別目標主機IP地址 ```shell ─(kali?kali)-[~/Vulnhub/Cengbox2] └─$ sudo netdiscover -i eth1 -r 192.168.56.0/24 Currently scanning: Finished! | S ......

    uj5u.com 2023-06-24 07:50:00 more
  • 二分搜索樹(校招資料結構最低要求版)Java

    二分搜索樹(Binary Search Tree,BST)是一種常見的資料結構,它能夠高效地存盤和查找資料。它的特點是每個節點都包含一個值,并且每個節點的左子樹的值都小于節點的值,右子樹的值都大于節點的值。 查找 通過這種有序的排列方式,我們可以在二分搜索樹中進行高效的查找操作。想象一下,如果我們要 ......

    uj5u.com 2023-06-24 07:49:10 more
  • DVWA靶場之SQL注入通關詳解

    原理 SQL注入通過將惡意的SQL代碼插入到應用程式后臺的SQL陳述句中,以獲取未授權的訪問權限或者竊取應用程式中的敏感資訊。通常,SQL注入攻擊的目標是Web應用程式,因為Web應用程式通常需要與資料庫進行互動,并且大多數Web應用程式使用的是SQL語言。 存在原因 Web應用程式沒有對用戶輸入的數 ......

    uj5u.com 2023-06-24 07:42:06 more
  • DVWA靶場之檔案上傳通關詳解

    原理 檔案上傳漏洞是應用程式在處理用戶上傳的檔案時沒有對檔案進行合理的檢查和過濾,而惡意檔案由攻擊者偽造成合法檔案,從而騙過應用程式進行上傳和執行惡意代碼。 存在原因 開發人員沒有對用戶上傳的檔案進行充分的驗證和過濾。攻擊者可以通過構造惡意檔案,利用上傳漏洞將其上傳到服務器,從而獲取敏感資訊或者在服 ......

    uj5u.com 2023-06-24 07:41:28 more
  • 協議分析(一)

    以太網協議 作業原理 以太網協議是一種局域網通信協議,它通過物理層和資料鏈路層的協同作業,使用媒體訪問控制地址和載波監聽/沖突檢測協議來實作計算機之間的穩定資料傳輸。在資料傳輸程序中,以太網會將資料封裝成資料幀,并根據目標MAC地址來識別需要接收資料的計算機。通過這種方式,以太網協議能夠保證資料的準 ......

    uj5u.com 2023-06-24 07:40:46 more
  • DVWA靶場之CSRF通關詳解

    原理 CSRF漏洞是指利用受害者尚未失效的身份認證資訊( cookie、會話等資訊),誘騙其點擊惡意鏈接或者訪問包含攻擊代碼的頁面,在受害人不知情的情況下,以受害者的身份向服務器發送請求,從而完成非法操作(如轉賬、改密、資訊修改等操作)。 形成原因 CSRF的形成原因主要是由于Web應用程式沒有充分 ......

    uj5u.com 2023-06-24 07:40:04 more
  • DVWA靶場之XSS通關詳解

    原理 XSS漏洞是攻擊者將惡意代碼注入到合法網頁中,當用戶瀏覽該頁面時,惡意代碼會被執行,從而獲取用戶敏感資訊或進行其他攻擊。 形成原因 網站對用戶輸入資料的過濾不嚴格或不完備,攻擊者可以根據這個漏洞向網站提交惡意代碼,然后再將這些代碼傳播給其他用戶,從而造成危害。 防御措施 輸入過濾:在網站接收用 ......

    uj5u.com 2023-06-24 07:34:20 more