Bộ công cụ debug mạng — dig, curl, nc, ss, tcpdump
Năm công cụ dòng lệnh, mỗi cái soi đúng một chặng: dig cho DNS, curl cho HTTP/TLS/timing, nc cho TCP thô, ss cho socket local, tcpdump cho gói thật. Workflow chẩn đoán theo chặng để biết hỏng ở đâu.
TL;DR: Khi một request "không chạy", lỗi có thể nằm ở bất kỳ chặng nào: phân giải DNS, bắt tay TCP, handshake TLS, hay tầng HTTP. Mỗi công cụ soi đúng một chặng — dig kiểm tra DNS resolution, curl -v -w cho thấy timing từng pha của một request HTTP/TLS, nc test một port TCP có mở không (tách biệt khỏi tầng ứng dụng), ss/lsof liệt kê socket và process local, tcpdump bắt gói thật trên dây khi mọi thứ khác không đủ. Bí quyết không phải nhớ mọi flag, mà là chẩn đoán theo chặng: đi từ ngoài (DNS) vào trong (HTTP) cho tới khi tìm ra chặng đầu tiên hỏng. Bài này gắn mỗi công cụ với chặng nó soi và đưa ra workflow chẩn đoán thực dụng.
Bạn đã hiểu từng tầng — DNS phân giải tên (Foundations), TCP bắt tay (module 1 bài 01), TLS handshake (bài 01), HTTP request/response (module 2). Bài này cho bạn công cụ nhìn vào từng tầng đó khi nó hỏng — kỹ năng phân biệt giữa "DNS sai", "port đóng", "cert hết hạn" và "app trả 500".
1. Analogy — Bộ đồ nghề thợ sửa nước
Một thợ sửa nước giỏi không có một cờ-lê vạn năng — họ có một bộ đồ nghề, mỗi món cho một việc. Khi nước không chảy, họ kiểm tra theo chặng: van tổng có mở không, ống có tắc không, vòi có hỏng không.
Debug mạng giống hệt. Khi request không tới đích, bạn kiểm tra từng chặng bằng đúng công cụ cho chặng đó — thay vì đoán mò.
| Đồ nghề thợ nước | Công cụ mạng | Soi chặng nào |
|---|---|---|
| Tra sổ địa chỉ nhà | dig | DNS — tên ra IP đúng không |
| Mở van thử nước | nc | TCP — port có mở, có accept không |
| Bơm nước qua toàn hệ thống, đo áp | curl -v -w | HTTP + TLS — cả luồng end-to-end + timing |
| Kiểm tra đồng hồ nước trong nhà | ss / lsof | Socket local — process nào nghe port nào |
| Đặt camera trong ống xem dòng chảy | tcpdump | Gói thật trên dây — khi mọi thứ khác chưa rõ |
Chọn công cụ theo chặng nghi ngờ, không theo thói quen. Tên không phân giải → dig. Port không mở → nc. Request chậm/lỗi → curl -v. Process local → ss. Không rõ gói có ra/vào không → tcpdump. Đi từ ngoài vào trong.
Một request đi qua các chặng theo thứ tự — mỗi chặng có công cụ soi riêng. Debug là đi dọc chuỗi này từ ngoài vào trong, dừng ở chặng đầu tiên hỏng:
ss / lsof soi phía local (process nào nghe port nào) — cắt ngang mọi chặng
2. dig — soi tầng DNS
dig (Domain Information Groper) hỏi trực tiếp DNS server và in ra câu trả lời thô — chính xác hơn ping vì tách riêng bước phân giải tên khỏi mọi thứ khác.
# Hoi A record (ten -> IPv4)
dig example.com
# Chi in dap an, gon
dig +short example.com
# Hoi mot resolver cu the (Google DNS) - bo qua cache he thong
dig @8.8.8.8 example.com
# Truy vet toan bo chain tu root server
dig +trace example.com
# Hoi loai record khac
dig example.com MX # mail server
dig example.com NS # name server
dig example.com AAAA # IPv6
Phần quan trọng nhất trong output là ANSWER SECTION và cột TTL:
;; ANSWER SECTION:
example.com. 3000 IN A 93.184.216.34
Cột 3000 là TTL còn lại (giây) — cho biết bản ghi này còn được cache bao lâu. Khi đổi DNS mà thay đổi "chưa có tác dụng", thủ phạm thường là TTL cũ chưa hết. So sánh kết quả dig với dig @8.8.8.8 (resolver ngoài) để phân biệt "DNS thật sự sai" và "cache local cũ".
ping example.com cũng phân giải DNS, nhưng nếu fail bạn không biết DNS sai hay ICMP bị chặn. dig chỉ làm một việc — phân giải tên — nên kết quả không nhập nhằng. Luôn dùng dig khi nghi ngờ DNS.
3. curl — soi tầng HTTP và TLS end-to-end
curl là con dao đa năng nhất. Hai flag biến nó thành công cụ debug: -v (verbose — in từng bước) và -w (write-out — đo timing).
# -v: in chi tiet ket noi, TLS handshake, header gui/nhan
curl -v https://example.com
# Chi xem response header, khong tai body (HEAD request)
curl -I https://example.com
# Theo redirect (-L) va in header moi hop
curl -ILv https://example.com
Output -v đánh dấu hướng bằng ký hiệu:
*— ghi chú của curl (DNS, kết nối, TLS).>— dữ liệu gửi đi (request header).<— dữ liệu nhận về (response header).
* Connected to example.com (93.184.216.34) port 443
* TLS 1.3 handshake, Cipher: TLS_AES_256_GCM_SHA384
* Server certificate: subject: CN=example.com; expire date: Jan 15 2027
> GET / HTTP/2
> Host: example.com
< HTTP/2 200
< content-type: text/html
Dòng Server certificate ... expire date cho biết ngay cert có hết hạn không — một trong những lỗi production phổ biến nhất.
Đo timing từng pha với -w — đây là kỹ thuật vàng để tìm chặng nào chậm:
curl -w "dns: %{time_namelookup}s connect: %{time_connect}s tls: %{time_appconnect}s ttfb: %{time_starttransfer}s total: %{time_total}s\n" \
-o /dev/null -s https://example.com
dns: 0.004s connect: 0.028s tls: 0.089s ttfb: 0.142s total: 0.145s
Đọc các mốc tích luỹ này để khoanh vùng:
time_namelookupcao → DNS chậm.time_connecttrừtime_namelookupcao → TCP handshake chậm (mạng xa, mất gói).time_appconnecttrừtime_connectcao → TLS handshake chậm.time_starttransfertrừtime_appconnectcao → server xử lý chậm (TTFB — time to first byte).
4. nc — soi tầng TCP thô
nc (netcat) mở một kết nối TCP/UDP trần, tách biệt hoàn toàn khỏi HTTP/TLS. Dùng để trả lời đúng một câu: port này có mở và accept kết nối không?
# Test port co mo khong (-z: scan, -v: verbose)
nc -zv example.com 443
# Connection to example.com port 443 [tcp/https] succeeded!
# Test nhieu port
nc -zv example.com 80 443 8080
# Mo ket noi tho va go HTTP request bang tay
nc example.com 80
GET / HTTP/1.1
Host: example.com
# (go dong trong roi Enter de gui)
nc -zv tách lỗi rất gọn: nếu succeeded, vấn đề nằm ở tầng trên TCP (app, TLS, HTTP). Nếu Connection refused, không có process listen (xem module 1 bài 07 — lỗi mạng về ECONNREFUSED). Nếu timeout, firewall đang DROP gói âm thầm.
succeeded: có process listen, TCP bắt tay xong → tầng dưới ổn, soi tiếp tầng trên. refused (tức thì): gói tới được host nhưng không ai nghe port đó → sai port hoặc app chưa chạy. timeout (chậm, im lặng): firewall chặn bằng DROP, hoặc host không reachable → vấn đề định tuyến/firewall.
5. ss và lsof — soi socket và process local
ss (socket statistics — thay thế netstat cũ) liệt kê socket trên chính máy bạn. Trả lời: process nào đang nghe port nào, có bao nhiêu kết nối, ở state gì.
# Liet ke moi socket TCP dang LISTEN + process (-t TCP, -l listen, -n so, -p process)
ss -tlnp
# Moi ket noi TCP kem state
ss -tan
# Loc theo port
ss -tlnp 'sport = :8080'
# Dem ket noi theo state (chan doan TIME_WAIT/CLOSE_WAIT)
ss -tan state time-wait | wc -l
ss -tan state close-wait
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
LISTEN 0 128 0.0.0.0:8080 0.0.0.0:* users:(("java",pid=4211))
lsof (list open files — socket cũng là file trên Unix) trả lời ngược lại: port này đang bị process nào giữ? — hữu ích khi gặp EADDRINUSE:
# Process nao dang giu port 8080?
lsof -i :8080
# Moi ket noi mang cua mot process
lsof -i -a -p 4211
Hai công cụ này soi phía local — khác hẳn dig/curl/nc soi phía remote. Khi app báo "không bind được port" hay "quá nhiều connection", đây là nơi nhìn đầu tiên. State machine TCP (LISTEN, ESTABLISHED, TIME_WAIT, CLOSE_WAIT) đã được mổ ở module 1 bài 04.
6. tcpdump — soi gói thật trên dây
Khi mọi công cụ trên vẫn chưa cho câu trả lời, tcpdump bắt gói thật đi qua interface — sự thật cuối cùng. Nó trả lời: "gói có thực sự ra/vào không, và nội dung header là gì?"
# Bat goi tren interface eth0, port 443
sudo tcpdump -i eth0 'tcp port 443'
# Bat goi toi/tu mot host cu the, in chi tiet (-v), khong phan giai ten (-n)
sudo tcpdump -i eth0 -n -v host 93.184.216.34
# Chi bat goi SYN (tim ket noi moi) - flag bit
sudo tcpdump -i eth0 'tcp[tcpflags] & tcp-syn != 0'
# Luu ra file .pcap de mo trong Wireshark
sudo tcpdump -i eth0 -w capture.pcap 'tcp port 443'
Cú pháp filter là BPF (Berkeley Packet Filter) — giống capture filter của Wireshark. Output một dòng mỗi gói:
10:24:01.123456 IP 10.0.0.5.52341 > 93.184.216.34.443: Flags [S], seq 0, win 65535
10:24:01.135678 IP 93.184.216.34.443 > 10.0.0.5.52341: Flags [S.], seq 0, ack 1
10:24:01.135700 IP 10.0.0.5.52341 > 93.184.216.34.443: Flags [.], ack 1
Bạn thấy ngay 3-way handshake: [S] (SYN), [S.] (SYN-ACK), [.] (ACK). Nếu chỉ thấy [S] lặp lại mà không có [S.] trả về → gói SYN ra được nhưng không có phản hồi → firewall chặn hoặc server không listen. tcpdump là CLI tương đương Wireshark — workflow thực tế là tcpdump -w trên server rồi mở file trong Wireshark (bài 04) để phân tích GUI.
tcpdump cần sudo (đọc raw socket). Trên server production nhiều traffic, luôn đặt filter chặt (host X and port Y) — bắt không filter sinh hàng triệu gói/phút, lấp đầy đĩa. Với HTTPS bạn chỉ thấy header TCP và ciphertext TLS — không đọc được nội dung HTTP (cần key log như bài 04 mô tả).
7. Workflow chẩn đoán theo chặng
Khi "trang không load", đừng đoán — đi tuần tự từ ngoài vào trong, dừng ở chặng đầu tiên hỏng:
flowchart TB
A["Trang khong load"] --> B{"dig: ten ra IP dung?"}
B -->|"Sai/khong co"| B1["Loi DNS: sai record, TTL cu, resolver hong"]
B -->|"Dung"| C{"nc -zv host port: port mo?"}
C -->|"refused"| C1["App chua chay / sai port (ss -tlnp tren server)"]
C -->|"timeout"| C2["Firewall DROP / route hong (tcpdump xem SYN co phan hoi)"]
C -->|"succeeded"| D{"curl -v: TLS + HTTP ok?"}
D -->|"cert loi"| D1["Cert het han / sai CN / thieu chain (bai 02)"]
D -->|"HTTP 5xx"| D2["App loi - doc log server, khong phai loi mang"]
D -->|"cham"| D3["curl -w: pha nao cham? TTFB cao -> app cham"]
D -->|"200 OK"| E["Mang OK - van de o tang ung dung/browser"]Ví dụ thực chiến — "API trả lỗi gián đoạn":
# 1. DNS dung khong?
dig +short api.example.com
# -> 93.184.216.34 (ok)
# 2. Port mo khong?
nc -zv api.example.com 443
# -> succeeded (TCP ok, khong phai loi mang co ban)
# 3. TLS + HTTP + timing
curl -w "tls: %{time_appconnect}s ttfb: %{time_starttransfer}s\n" \
-o /dev/null -s https://api.example.com/health
# -> tls: 0.09s ttfb: 3.20s (!! TTFB 3.2s -> server xu ly cham)
# 4. Ket luan: khong phai loi mang. Doc log app, kiem tra DB/downstream.
Giá trị của workflow: nó phân biệt lỗi mạng với lỗi ứng dụng. Phần lớn "lỗi mạng" hoá ra là app chậm, cert hết hạn, hoặc sai port — không phải mạng thật sự hỏng.
8. Liên hệ các bài khác
- Foundations — Điều gì xảy ra khi gõ URL: các chặng DNS → TCP → TLS → HTTP mà workflow mục 7 đi qua chính là vòng đời một request bài đó mô tả.
- Module 1 bài 07 — Lỗi mạng thường gặp:
ECONNREFUSED/ETIMEDOUTmàncphân biệt được giải thích cơ chế ở đó. - Module 1 bài 04 — TIME_WAIT & hết port: các state
sshiển thị (TIME_WAIT, CLOSE_WAIT) vàEADDRINUSEmàlsofgiúp truy thủ phạm. - Bài 01 — TLS/HTTPS handshake và bài 02 — Certificate & CA: khi
curl -vbáo lỗi cert, hai bài này giải thích cert hết hạn / sai chain nghĩa là gì. - Bài 04 — Wireshark:
tcpdump -w file.pcaprồi mở trong Wireshark — hai công cụ bổ trợ, cùng dùnglibpcap.
9. 📚 Deep Dive — tài liệu gốc
Tra cứu chính thức:
- dig manual (ISC BIND) — mọi loại record và option
+trace,+short. - curl manual — phần
--write-outliệt kê đầy đủ biến timing (time_*). - tcpdump man page + pcap-filter — cú pháp BPF filter chi tiết.
- ss / iproute2 docs — filter theo state, port, address.
Ghi chú: man curl phần WRITE-OUT là tài liệu đáng đọc nhất khi muốn đo performance — danh sách time_namelookup, time_connect, time_appconnect, time_starttransfer, time_total cho phép dựng một script profiling chỉ bằng curl.
10. Tóm tắt
- Mỗi công cụ soi đúng một chặng — chọn theo chặng nghi ngờ, đi từ ngoài (DNS) vào trong (HTTP).
digkiểm tra DNS resolution tách biệt khỏi mọi thứ khác; đọcANSWER SECTIONvà TTL;@8.8.8.8bỏ qua cache local.curl -vcho thấy TLS handshake, cert expiry, header gửi/nhận (*ghi chú,>gửi,<nhận);curl -wđo timing từng pha để khoanh vùng chặng chậm (TTFB cao = app chậm).nc -zvtest một port TCP: succeeded / refused / timeout — ba trạng thái chỉ về ba loại lỗi khác nhau.ss/lsofsoi phía local: process nào nghe port nào, state TCP, ai giữ port khiEADDRINUSE.tcpdumpbắt gói thật khi cần sự thật cuối cùng; filter BPF chặt, cần root; với HTTPS chỉ thấy header + ciphertext.- Workflow chẩn đoán:
dig→nc→curl -v/-w→tcpdump, dừng ở chặng đầu tiên hỏng — phần lớn "lỗi mạng" thật ra là app chậm/cert hết hạn/sai port.
11. Tự kiểm tra
Q1Vì sao dùng dig tốt hơn ping khi nghi ngờ vấn đề DNS?▸
ping làm hai việc trộn lẫn: phân giải DNS rồi gửi ICMP echo. Nếu ping fail, bạn không biết DNS sai hay ICMP bị firewall chặn — kết quả nhập nhằng. dig chỉ làm một việc: hỏi DNS server và in câu trả lời thô (record, TTL, resolver nào trả lời). Nó cũng cho phép hỏi một resolver cụ thể (dig @8.8.8.8) để phân biệt "DNS thật sự sai" với "cache local cũ", và xem TTL còn lại để biết vì sao thay đổi DNS chưa có tác dụng. Khi nghi DNS, luôn dùng dig vì kết quả không lẫn với tầng khác.Q2curl -w cho time_namelookup=0.005s, time_connect=0.03s, time_appconnect=0.09s, time_starttransfer=2.5s. Chặng nào là nút thắt? Vì sao?▸
Q3nc -zv host 443 trả về ba kết quả khác nhau: succeeded, Connection refused, timeout. Mỗi cái chỉ về loại lỗi gì?▸
curl -v. Connection refused (tức thì): gói tới được host nhưng không ai nghe port đó, OS trả RST ngay → app chưa chạy hoặc sai port (kiểm tra ss -tlnp trên server). timeout (chậm, im lặng): không có phản hồi gì cả → firewall đang DROP gói âm thầm, hoặc host không reachable (route hỏng). Ba kết quả tách lỗi gọn gàng theo ba hướng debug hoàn toàn khác nhau.Q4ss/lsof khác dig/curl/nc ở điểm cốt lõi nào về hướng soi? Khi nào bạn cần ss thay vì curl?▸
dig, curl, nc soi phía remote — chúng gửi request ra ngoài và xem đích trả lời thế nào. ss và lsof soi phía local — liệt kê socket và process trên chính máy bạn, không gửi gì ra mạng. Cần ss thay vì curl khi câu hỏi là về máy local: "app của tôi có thực sự bind port 8080 không?" (ss -tlnp), "có bao nhiêu connection đang ESTABLISHED / TIME_WAIT?", "process nào đang giữ port khiến tôi gặp EADDRINUSE?" (lsof -i :8080). curl không trả lời được những câu này vì nó nhìn từ ngoài vào, còn ss nhìn từ trong ra.Q5Trong output tcpdump bạn chỉ thấy các gói Flags [S] gửi đi lặp lại mà không có [S.] trả về. Điều này nói lên gì?▸
[S] là gói SYN — bước đầu của 3-way handshake; [S.] là SYN-ACK (server trả lời). Thấy SYN gửi đi lặp lại nhưng không có SYN-ACK về nghĩa là: gói SYN của bạn ra được khỏi máy (tcpdump bắt được trên interface), nhưng phía bên kia không phản hồi. Hai nguyên nhân chính: (1) firewall đang DROP gói (không reject, chỉ nuốt im lặng) — đây cũng là lý do bạn thấy ETIMEDOUT chứ không phải ECONNREFUSED; (2) server không listen port đó và route khiến gói không tới được, hoặc SYN-ACK trả về bị chặn ở chiều ngược. SYN lặp lại là TCP tự retransmit khi không nhận ACK. Bước tiếp: kiểm tra firewall/security group và xác nhận server có listen (ss -tlnp trên server).Q6Vì sao workflow chẩn đoán đi theo thứ tự dig → nc → curl → tcpdump, và lợi ích của việc dừng ở chặng đầu tiên hỏng là gì?▸
tcpdump là công cụ "sự thật cuối cùng" khi các tầng trên chưa rõ. Nếu DNS đã sai thì không cần test port; nếu port đã đóng thì không cần test TLS. Dừng ở chặng đầu tiên hỏng tiết kiệm thời gian (không debug nhầm tầng) và quan trọng hơn là phân biệt được lỗi mạng với lỗi ứng dụng — phần lớn "trang không load" hoá ra là app trả 5xx, cert hết hạn, hoặc sai port, chứ không phải mạng thật sự hỏng. Đoán mò thường sửa nhầm chỗ.Bài tiếp theo: Wireshark — bắt và đọc gói tin từng tầng
Bài này đáng gửi cho bạn học cùng?
Copy link đã gắn nguồn — dán group, chat, hoặc LinkedIn.
Bài này có giúp bạn hiểu bản chất không?
Hỏi đáp về bài này
Chưa có câu hỏi
Có gì chưa rõ trong bài? Đặt câu hỏi đầu tiên — câu trả lời từ cộng đồng giúp bạn (và người sau).
Đặt câu hỏi đầu tiên