在分析TCP數(shù)據(jù)包時(shí),理解TCP協(xié)議的工作原理和報(bào)文格式是關(guān)鍵。TCP是一種面向連接的、提供可靠的、端到端的字節(jié)流傳輸服務(wù)。其頭部結(jié)構(gòu)包括源端口、目標(biāo)端口、序列號(hào)、確認(rèn)應(yīng)答號(hào)等字段。序列號(hào)是在建立連接時(shí)由計(jì)算機(jī)生成的隨機(jī)數(shù)作為初始值,每發(fā)送一次數(shù)據(jù),就累加一次該數(shù)據(jù)字節(jié)數(shù)的大小,而確認(rèn)應(yīng)答號(hào)是指下一次期望收到的數(shù)據(jù)的序列號(hào)。
抓包和分析數(shù)據(jù)包是理解TCP/IP協(xié)議的重要手段。Wireshark是最知名的網(wǎng)絡(luò)通訊抓包分析工具,可以截取各種網(wǎng)絡(luò)封包并顯示詳細(xì)信息。通過(guò)抓包和分析數(shù)據(jù)包,我們可以深入理解TCP幀格式及“TCP三次握手”,進(jìn)一步提高理論聯(lián)系實(shí)踐的能力。
例如,我們選擇一個(gè)TCP數(shù)據(jù)包進(jìn)行分析,在數(shù)據(jù)包詳細(xì)信息面板中,我們可以看到TCP協(xié)議的詳細(xì)信息,包括TCP標(biāo)志位、序號(hào)、確認(rèn)號(hào)、窗口大小等信息。此外,我們還可以查看數(shù)據(jù)包的十六進(jìn)制數(shù)據(jù)。
總的來(lái)說(shuō),TCP數(shù)據(jù)包的分析原理主要涉及對(duì)TCP協(xié)議的理解、使用相關(guān)工具進(jìn)行數(shù)據(jù)包抓取和分析以及理解TCP頭部結(jié)構(gòu)等方面。處理細(xì)節(jié)則包括如何從大量的數(shù)據(jù)包中篩選出需要的信息,如何理解和解析TCP協(xié)議的各種字段等。
理解TCP協(xié)議工作原理和報(bào)文
TCP(Transmission Control Protocol,傳輸控制協(xié)議)是一種面向連接的、可靠的、基于字節(jié)流的傳輸層通信協(xié)議。它在互聯(lián)網(wǎng)協(xié)議(IP)網(wǎng)絡(luò)上通過(guò)TCP/IP協(xié)議棧進(jìn)行工作。
TCP的工作原理可以概括為以下幾個(gè)方面:
1.建立連接:在源主機(jī)和目標(biāo)主機(jī)之間建立連接,以便進(jìn)行數(shù)據(jù)傳輸。
2.編號(hào)和排序數(shù)據(jù)段:在連接建立后,源主機(jī)按順序發(fā)送數(shù)據(jù)段,每個(gè)數(shù)據(jù)段都有一個(gè)編號(hào),以便目標(biāo)主機(jī)重新排序。
3.確認(rèn)和重傳:目標(biāo)主機(jī)對(duì)接收到的數(shù)據(jù)段進(jìn)行確認(rèn),如果數(shù)據(jù)段丟失或損壞,則發(fā)送請(qǐng)求重傳的信號(hào)。
4.流量控制:TCP使用窗口機(jī)制來(lái)控制數(shù)據(jù)的流量,以避免因接收方緩沖區(qū)滿而造成的數(shù)據(jù)丟失。
5.關(guān)閉連接:當(dāng)數(shù)據(jù)傳輸完成時(shí),連接將被關(guān)閉。
TCP的報(bào)文格式包括以下幾個(gè)部分:
1.源端口和目標(biāo)端口:指示數(shù)據(jù)從哪個(gè)進(jìn)程來(lái),到哪個(gè)進(jìn)程去。
2.序號(hào):表示從TCP源端向TCP目標(biāo)端發(fā)送的數(shù)據(jù)字節(jié)流中的第一個(gè)數(shù)據(jù)字節(jié)。
3.確認(rèn)號(hào):包含目標(biāo)端所期望收到源端的下一個(gè)數(shù)據(jù)字節(jié)的序號(hào)。
4.TCP首部長(zhǎng)度:表示該TCP頭部有多少個(gè)32位(以4個(gè)字節(jié)為單位)。
5.標(biāo)志位:包括緊急標(biāo)志(URG)、確認(rèn)標(biāo)志(ACK)、推送標(biāo)志(PSH)、可重用標(biāo)志(RST)、同步標(biāo)志(SYN)和終止標(biāo)志(FIN)等。
6.窗口大?。罕硎窘邮辗娇梢越邮盏淖畲髷?shù)據(jù)量。
7.校驗(yàn)和:用于校驗(yàn)數(shù)據(jù)的有效性。
8.緊急指針:當(dāng)URG標(biāo)志位為1時(shí),表示緊急數(shù)據(jù)的位置。
9.數(shù)據(jù)部分:包含實(shí)際傳輸?shù)臄?shù)據(jù)。
TCP的報(bào)文格式根據(jù)不同的用途和選項(xiàng)可能會(huì)有所不同,但以上是基本組成部分。理解TCP報(bào)文格式對(duì)于理解TCP協(xié)議的工作原理和實(shí)現(xiàn)可靠傳輸至關(guān)重要。
TCP怎么實(shí)現(xiàn)可靠傳輸
TCP通過(guò)以下幾種機(jī)制來(lái)實(shí)現(xiàn)可靠傳輸:
-
序列號(hào)和確認(rèn)機(jī)制:每個(gè)TCP包都有一個(gè)序列號(hào),接收方通過(guò)發(fā)送端的確認(rèn)信息來(lái)確認(rèn)收到的數(shù)據(jù),并告知發(fā)送方下一個(gè)期望接收的數(shù)據(jù)序號(hào)。
-
超時(shí)重傳:發(fā)送方在發(fā)送數(shù)據(jù)后啟動(dòng)一個(gè)計(jì)時(shí)器,如果在規(guī)定時(shí)間內(nèi)沒有收到接收方的確認(rèn)信息,就會(huì)認(rèn)為數(shù)據(jù)丟失,然后重新發(fā)送數(shù)據(jù)。
-
滑動(dòng)窗口協(xié)議:接收方使用滑動(dòng)窗口來(lái)控制數(shù)據(jù)的流量和接收速度。滑動(dòng)窗口可以指定接收方現(xiàn)在能夠接受的最大數(shù)據(jù)量,發(fā)送方需要確保在窗口范圍內(nèi)發(fā)送數(shù)據(jù)。
-
流量控制:TCP使用基于接收方通告的窗口大小來(lái)控制數(shù)據(jù)發(fā)送速率,確保發(fā)送方不會(huì)以過(guò)快的速度發(fā)送數(shù)據(jù),使接收方無(wú)法處理。
-
擁塞控制:TCP通過(guò)調(diào)整發(fā)送方的發(fā)送速率來(lái)避免網(wǎng)絡(luò)擁塞。通過(guò)監(jiān)測(cè)網(wǎng)絡(luò)的擁塞程度并及時(shí)降低發(fā)送速率,使得整個(gè)網(wǎng)絡(luò)能夠維持在一個(gè)合理的狀態(tài)。
以上是TCP實(shí)現(xiàn)可靠傳輸?shù)闹饕獧C(jī)制,通過(guò)這些機(jī)制,TCP可以在不可靠的網(wǎng)絡(luò)環(huán)境下實(shí)現(xiàn)可靠的數(shù)據(jù)傳輸。
tcpflow - 分析網(wǎng)絡(luò)流量
tcpflow是一個(gè)功能強(qiáng)大的、基于命令行的免費(fèi)開源工具,用于在Unix之類的系統(tǒng)(如Linux)上分析網(wǎng)絡(luò)流量。它可以捕獲通過(guò)TCP連接接收或傳輸?shù)臄?shù)據(jù),并存儲(chǔ)在文件中供以后分析,采用的格式便于協(xié)議分析和調(diào)試。
tcpflow的工作原理是基于LBL Packet Capture Library,支持豐富的過(guò)濾條件,能夠捕獲網(wǎng)絡(luò)或存儲(chǔ)文件中的數(shù)據(jù)包,并按照正常順序重建數(shù)據(jù)流。每一條TCP流都會(huì)被存儲(chǔ)到獨(dú)立的文件中,方便以后分析。與tcpdump相比,tcpflow會(huì)重新構(gòu)建真實(shí)的數(shù)據(jù)流,并且會(huì)分開存儲(chǔ)。
當(dāng)你想要使用tcpflow
命令來(lái)捕獲和輸出TCP流量時(shí),以下是一些相關(guān)的例子:
- 基本使用:
這個(gè)命令將讀取一個(gè)PCAP文件(例如Wireshark捕獲到的網(wǎng)絡(luò)數(shù)據(jù)包),并將TCP流量保存到相應(yīng)的文件或屏幕上。tcpflow -r pcap_file.pcap
默認(rèn)情況下,tcpflow將所有捕獲的數(shù)據(jù)存儲(chǔ)在表單中具有名稱的文件中(如果使用某些選項(xiàng)(如時(shí)間戳 ),這可能會(huì)有所不同)?,F(xiàn)在讓我們做一個(gè)目錄列表,看看是否在任何文件中捕獲了tcp流。
還生成了一個(gè)XML報(bào)告,含有關(guān)于該程序的信息,比如它是如何編譯的、它在哪臺(tái)計(jì)算機(jī)上運(yùn)行以及每條TCP連接的記錄。
-
指定輸出目錄:
tcpflow -o output_directory -r pcap_file.pcap
這個(gè)命令將指定TCP流量的輸出目錄。每個(gè)流將被保存為單獨(dú)的文件,文件名由IP地址和端口組成。
-
只顯示請(qǐng)求或響應(yīng):
tcpflow -r pcap_file.pcap 'src host X.X.X.X' tcpflow -r pcap_file.pcap 'dst host X.X.X.X'
這兩個(gè)命令將只捕獲某個(gè)特定源IP地址或目標(biāo)IP地址的請(qǐng)求或響應(yīng)流量。
-
過(guò)濾特定端口:
tcpflow -r pcap_file.pcap 'tcp port 80'
這個(gè)命令將只捕獲TCP端口為80的流量。
-
高亮顯示輸出:
tcpflow -C -r pcap_file.pcap
這個(gè)命令將以彩色高亮的方式顯示輸出結(jié)果,以便更容易閱讀和理解。
-
指定接口名稱
要從特定網(wǎng)絡(luò)接口捕獲數(shù)據(jù)包,請(qǐng)使用-i標(biāo)志指定接口名稱。tcpflow -i eth0 port 80
有關(guān)更多信息和用法選項(xiàng),請(qǐng)參見tcpflow手冊(cè)頁(yè)。
man tcpflow
Linux C/C++ 分析網(wǎng)絡(luò)流量(十六進(jìn)制TCP數(shù)據(jù)包分析)
編寫主要目的是舊的tcpflow不提供十六進(jìn)制控制臺(tái)輸出。Simson L.Garfinkel的新tcpflow需要一個(gè)libcairo-dev,這需要對(duì)我的服務(wù)器系統(tǒng)有很大的x11依賴性。我認(rèn)為tcpflow是一個(gè)命令行工具,我真的不需要pdf報(bào)告。編譯新的tcpflow很困難,而且根本不能禁用libcairo。
...
void hexdump(const char *buffer, size_t size)
{
...
for (;;) {
const char *line_end = line_start + LINE_CHAR_COUNT > buffer_end
? buffer_end
: line_start + LINE_CHAR_COUNT;
if (line_start == line_end) {
break;
}
...
// hex part
...
// blank
count += snprintf(output + count, sizeof(output), " ");
// acsii part
for (const char *p = line_start; p < line_end; ++p) {
count += snprintf(output + count, sizeof(output), "%c",
isprint(*p) ? *p : '.');
}
printf("%s\n", output);
line_start = line_end;
}
}
void process_ip_packet(const struct timeval *ts,
const char *buffer, size_t size)
{
if (size < sizeof(struct ip)) {
die("invalid ip packet length");
}
...
process_tcp_packet(ts,
ntohl(ip_header->ip_src.s_addr),
ntohl(ip_header->ip_dst.s_addr),
buffer + ip_header_len,
ip_len - ip_header_len);
}
void process_tcp_packet(const struct timeval *ts,
u_int32_t src_addr, u_int32_t dst_addr,
const char *buffer, size_t size)
{
...
if (size < sizeof(struct tcphdr)) {
die("invalid tcp packet length");
}
...
if (tcp_header_len >= size) {
return;
}
if (g_option_color) {
if (src_addr != last_src_addr || dst_addr != last_dst_addr ||
src_port != last_src_port || dst_port != last_dst_port) {
last_src_addr = src_addr;
last_dst_addr = dst_addr;
last_src_port = src_port;
last_dst_port = dst_port;
current_color = !current_color;
}
printf("%s", colors[current_color]);
}
if (g_option_display_header) {
...
strftime(format_time, sizeof(format_time), "%Y-%m-%d %H:%M:%S", &tm);
printf("%s.%ld %d.%d.%d.%d:%d => %d.%d.%d.%d:%d\n",
format_time, ts->tv_usec / 1000,
(src_addr & 0xff000000) >> 24,
(src_addr & 0x00ff0000) >> 16,
(src_addr & 0x0000ff00) >> 8,
src_addr & 0x000000ff,
src_port,
(dst_addr & 0xff000000) >> 24,
(dst_addr & 0x00ff0000) >> 16,
(dst_addr & 0x0000ff00) >> 8,
dst_addr & 0x000000ff,
dst_port);
}
// print hex data
hexdump(buffer + tcp_header_len, size - tcp_header_len);
if (g_option_color) {
printf("%s", "\033[0m");
}
printf("\n");
}
...
void print_usage(const char *prog_name)
{
fprintf(stderr, "usage: %s [-Ce] <pcap_file> \n", prog_name);
fprintf(stderr, " -C do not display packet description\n");
fprintf(stderr, " -e output in alternating colors\n");
}
void packet_handler(u_char *user, const struct pcap_pkthdr *h, const u_char *bytes)
{
if (h->len <= g_datalink_header_length) {
die("invalid datalink packet length");
}
process_ip_packet(&h->ts, (const char *)bytes + g_datalink_header_length,
h->len - g_datalink_header_length);
}
int main(int argc, char *argv[])
{
...
while ((opt = getopt(argc, argv, "Ce")) != -1) {
switch (opt) {
case 'C':
g_option_display_header = false;
break;
case 'e':
g_option_color = true;
break;
default:
print_usage(argv[0]);
exit(1);
}
}
if (optind >= argc) {
print_usage(argv[0]);
exit(1);
}
const char *pcap_file_name = argv[optind];
pcap_t *pd = pcap_open_offline(pcap_file_name, errbuf);
if (NULL == pd) {
die("%s", errbuf);
}
int dlt = pcap_datalink(pd);
if (DLT_NULL == dlt) {
g_datalink_header_length = 4;
} else if (DLT_RAW == dlt) {
g_datalink_header_length = 0;
} else if (DLT_EN10MB == dlt || DLT_IEEE802 == dlt) {
g_datalink_header_length = 14;
} else if (DLT_PPP == dlt) {
g_datalink_header_length = 4;
} else if (DLT_LINUX_SLL == dlt) {
g_datalink_header_length = 16;
} else {
fprintf(stderr, "unknown datalink type\n");
return -1;
}
struct bpf_program filter;
if (pcap_compile(pd, &filter, "tcp", 1, 0) != 0) {
die("%s", pcap_geterr(pd));
}
if (pcap_setfilter(pd, &filter) != 0) {
die("%s", pcap_geterr(pd));
}
if (pcap_loop(pd, -1, packet_handler, NULL) != 0) {
die("%s", pcap_geterr(pd));
}
...
}
If you need the complete source code, please add the WeChat number (c17865354792)
運(yùn)行結(jié)果:
Wireshark抓包展示效果:
總結(jié)
在進(jìn)行十六進(jìn)制TCP數(shù)據(jù)包分析時(shí),我們首先需要捕獲網(wǎng)絡(luò)流量,獲取TCP數(shù)據(jù)包。這可以通過(guò)網(wǎng)絡(luò)抓包工具(如Wireshark)實(shí)現(xiàn)。然后,對(duì)捕獲到的數(shù)據(jù)包進(jìn)行解析,提取出TCP頭部的各個(gè)字段和數(shù)據(jù)部分。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-774398.html
Welcome to follow WeChat official account【程序猿編碼】文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-774398.html
到了這里,關(guān)于Linux C/C++ 分析網(wǎng)絡(luò)流量(十六進(jìn)制TCP數(shù)據(jù)包分析)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!