- サーバー
Linuxネットワークコマンド一覧|ip/ss/ncで障害切り分け
Linux のネットワーク確認は、ip(アドレスと経路)、ss(待ち受けと接続)、nc(ポートに届くか)、dig(名前解決)、curl(HTTP)の5つで大半をカバーできます。 これに ping・traceroute・tracepath(経路の到達確認)と tcpdump(パケットの中身)を加えると、「つながらない」の原因を層ごとに順番に絞り込めます。
この記事では、Ubuntu 24.04 上で各コマンドを実際に実行した結果を載せています。新旧コマンドの対応表、オプション早見表に加え、Python の簡易サーバーを使って「そもそも LISTEN していない」「127.0.0.1 だけで待ち受けている」「タイムアウト」「名前が引けない」を再現し、それぞれ ss・nc・curl・tcpdump でどう見えるかを並べました。最後のエラー文の表は、そのまま次の一手を探す逆引きとして使えます。
Linuxネットワークコマンドの早見表
まず「何を知りたいか」からコマンドを選びます。
| 知りたいこと | コマンド | 見るところ |
|---|---|---|
| 自分の IP アドレス | ip -br addr |
インターフェース名と 192.0.2.2/24 などのアドレス |
| インターフェースが UP か | ip -br link |
UP / DOWN |
| デフォルトゲートウェイ | ip route |
default via ... |
| ある宛先へどこから出るか | ip route get 8.8.8.8 |
via(経由先)と dev(出口) |
| 同じネットワークの相手の MAC | ip neigh |
REACHABLE / FAILED |
| 待ち受け中のポートとプロセス | ss -tlnp |
Local Address:Port と users:(...) |
| 確立中の接続 | ss -tnp state established |
接続先と自分のポート |
| 接続数のまとめ | ss -s |
estab / timewait の数 |
| ポートに TCP で届くか | nc -zv HOST PORT |
succeeded / refused / timed out |
| 名前から IP を引く | dig +short NAME |
A レコード |
| HTTP の応答を詳しく | curl -v URL |
接続・リクエスト・レスポンスヘッダー |
| 応答時間の内訳 | curl -w '...time_connect...' |
DNS / 接続 / 最初の1バイトまで |
| ICMP で届くか | ping -c 3 HOST |
0% packet loss |
| 経路(どこまで届くか) | traceroute -n HOST / tracepath -n HOST |
途中のルーター、* の位置 |
| パケットの中身 | tcpdump -i any -nn port 80 |
[S] [S.] [R.] などのフラグ |
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「Linuxネットワークコマンド一覧|ip/ss/ncで障害切り分け」
検証環境とバージョン
この記事の実行結果は次の環境で取得しました。 IP アドレス 192.0.2.2 は検証環境の実際の値です(ドキュメント用に予約されたアドレス帯がたまたま割り当てられています)。
| 項目 | バージョン |
|---|---|
| OS | Ubuntu 24.04.4 LTS |
| ip / ss | iproute2-6.1.0 |
| nc | netcat-openbsd |
| dig | DiG 9.18.39 |
| curl | 8.5.0 |
| ping / tracepath | iputils 20240117 |
| traceroute | 2.1.5 |
| tcpdump | 4.99.4 |
| 旧コマンド比較用 | net-tools(ifconfig・route・netstat) |
最小構成の環境では ping や traceroute が入っていないことがあります。Ubuntu / Debian では次のコマンドで入ります。
sudo apt-get install -y iproute2 iputils-ping iputils-tracepath traceroute \
dnsutils netcat-openbsd tcpdump curl
| コマンド | Debian / Ubuntu のパッケージ | RHEL 系のパッケージ |
|---|---|---|
| ip, ss | iproute2 | iproute |
| ping, tracepath | iputils-ping, iputils-tracepath | iputils |
| traceroute | traceroute | traceroute |
| dig, nslookup | dnsutils(bind9-dnsutils) | bind-utils |
| nc | netcat-openbsd | nmap-ncat |
| tcpdump | tcpdump | tcpdump |
旧コマンドと新コマンドの対応表
ifconfig・route・arp・netstat を含む net-tools は、多くのディストリビューションで最初から入っていない構成が増えており、iproute2 の ip と ss が標準的に使われています。 古い手順書を読み替えるときはこの表を使ってください。
| やりたいこと | 旧コマンド | 新コマンド |
|---|---|---|
| アドレス表示 | ifconfig -a |
ip addr(短く: ip -br addr) |
| インターフェースの UP / DOWN | ifconfig eth0 up |
ip link set eth0 up |
| アドレス追加 | ifconfig eth0 192.0.2.10 netmask 255.255.255.0 |
ip addr add 192.0.2.10/24 dev eth0 |
| ルーティング表 | route -n |
ip route |
| ルート追加 | route add -net 10.0.0.0/8 gw 192.0.2.1 |
ip route add 10.0.0.0/8 via 192.0.2.1 |
| ARP テーブル | arp -n |
ip neigh |
| 待ち受けポート | netstat -tlnp |
ss -tlnp |
| 接続一覧 | netstat -tanp |
ss -tanp |
| 統計 | netstat -s |
ss -s(概要)、nstat |
| 名前解決 | nslookup NAME |
dig NAME(nslookup も引き続き利用可) |
| 経路 | traceroute |
traceroute / tracepath(root 不要) |
同じ情報を新旧で並べると、ip の方が CIDR 表記(/24)で短く表示されるのがわかります。
ifconfig -a | head -9
ip -br addr
docker0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255
ether 9e:61:12:35:e0:64 txqueuelen 0 (Ethernet)
...
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1400
inet 192.0.2.2 netmask 255.255.255.0 broadcast 192.0.2.255
lo UNKNOWN 127.0.0.1/8
ifb0 DOWN
ifb1 DOWN
eth0 UP 192.0.2.2/24
docker0 DOWN 172.17.0.1/16
route -n
ip route
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 192.0.2.1 0.0.0.0 UG 0 0 0 eth0
172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 docker0
192.0.2.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0
default via 192.0.2.1 dev eth0
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 linkdown
192.0.2.0/24 dev eth0 proto kernel scope link src 192.0.2.2
ipコマンドの使い方
ip は「ip 対象 操作」の形で使います。 対象は addr(アドレス)、link(インターフェース)、route(経路)、neigh(隣接機器)が中心です。操作を省略すると show になります。
| コマンド | 意味 | 補足 |
|---|---|---|
ip -br addr |
アドレスを1行ずつ | -br = brief |
ip addr show dev eth0 |
特定インターフェースの詳細 | |
ip -4 addr / ip -6 addr |
IPv4 / IPv6 だけ | |
ip -br link |
状態と MAC アドレス | |
ip -s -h link show eth0 |
送受信の統計(読みやすい単位) | errors / dropped を確認 |
ip route |
ルーティング表 | ip r と省略可 |
ip route get 宛先 |
その宛先に実際に使う経路 | 経路の確認に便利 |
ip neigh |
ARP / NDP のテーブル | ip n と省略可 |
ip -j addr |
JSON で出力 | jq と組み合わせやすい |
sudo ip addr add 192.0.2.10/24 dev eth0 |
アドレス追加 | 再起動で消える(恒久設定は netplan 等) |
sudo ip link set eth0 down |
インターフェース停止 | リモート接続中は注意して実行 |
sudo ip route add 10.0.0.0/8 via 192.0.2.1 |
経路追加 | 同上、恒久設定は別途 |
ip addrとip linkの見方
ip addr show # 出力の ifb0・ifb1 は省略
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
4: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1400 qdisc pfifo_fast state UP group default qlen 1000
link/ether 02:fc:00:00:00:01 brd ff:ff:ff:ff:ff:ff
inet 192.0.2.2/24 brd 192.0.2.255 scope global eth0
valid_lft forever preferred_lft forever
5: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
link/ether 9e:61:12:35:e0:64 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
valid_lft forever preferred_lft forever
| 表示 | 意味 |
|---|---|
UP |
管理上は有効化されている |
LOWER_UP |
物理的(またはリンク的)につながっている |
NO-CARRIER |
有効化されているがリンクがない(docker0 はコンテナがいないとこの状態) |
mtu 1400 |
一度に送れる最大サイズ。経路の途中と合わないと大きな通信だけ止まることがある |
inet 192.0.2.2/24 |
IPv4 アドレスとプレフィックス長 |
scope host / scope global |
そのホスト内だけ有効 / 外部と通信できる |
ip -s -h link では送受信の統計が見られます。 errors や dropped が増えていれば、物理層やドライバ側を疑う手がかりになります。
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
RX: bytes packets errors dropped missed mcast
679M 90.3k 0 0 0 0
TX: bytes packets errors dropped carrier collsns
679M 90.3k 0 0 0 0
ip route getで実際の出口を確かめる
ルーティング表を目で追うより、ip route get に宛先を渡すほうが確実です。 カーネルが実際に選ぶ経路をそのまま表示します。
ip route get 8.8.8.8
ip route get 172.17.0.2
8.8.8.8 via 192.0.2.1 dev eth0 src 192.0.2.2 uid 0
cache
172.17.0.2 dev docker0 src 172.17.0.1 uid 0
cache
外部宛ては via 192.0.2.1(ゲートウェイ経由)、同じセグメントのコンテナ宛ては via なしで docker0 から直接出ることがわかります。
ip neighで同じネットワークの相手を確認する
ip neigh
ip neigh show dev docker0
192.0.2.1 dev eth0 lladdr 02:fc:00:00:00:05 REACHABLE
172.17.0.99 FAILED
172.17.0.2 lladdr 8e:2e:b7:a1:75:3a REACHABLE
FAILED は「その IP の機器から MAC アドレスの応答がなかった」状態です。 存在しない 172.17.0.99 に ping した後に表示されました。同じセグメントの相手が FAILED なら、相手が停止している・IP が違う・VLAN が違う、などの L2 の問題を疑います。
ssコマンドの使い方
ss はソケット(通信の出入り口)の一覧を表示するコマンドで、netstat より高速です。 オプションを組み合わせて使います。
| オプション | 意味 |
|---|---|
-t / -u |
TCP / UDP |
-l |
LISTEN(待ち受け)だけ |
-a |
待ち受けと接続の両方 |
-n |
名前解決せず数字で表示(速い) |
-p |
プロセス名と PID(他ユーザーのものは root が必要) |
-s |
統計の概要 |
-4 / -6 |
IPv4 / IPv6 だけ |
state established |
確立中の接続だけ |
state time-wait |
TIME-WAIT だけ |
'sport = :80' |
自分側ポートで絞り込み |
'dport = :443' |
相手側ポートで絞り込み |
'( sport = :80 or sport = :443 )' |
複数条件 |
定番は ss -tlnp(TCP・待ち受け・数字・プロセス)です。 検証用に Python の簡易サーバーを2つ起動して確かめました。1つは 127.0.0.1 だけ、もう1つは全アドレス(0.0.0.0)で待ち受けます。
mkdir -p web && echo "item list" > web/index.html && cd web
python3 -m http.server 7791 --bind 127.0.0.1 & # 127.0.0.1 だけで待受
python3 -m http.server 7792 & # 全アドレスで待受
ss -tlnp | grep -E 'State|:779'
State Recv-Q Send-Q Local Address:Port Peer Address:PortProcess
LISTEN 0 5 0.0.0.0:7792 0.0.0.0:* users:(("python3",pid=23330,fd=3))
LISTEN 0 5 127.0.0.1:7791 0.0.0.0:* users:(("python3",pid=23329,fd=3))
| 列 | 意味 |
|---|---|
Local Address:Port が 0.0.0.0:7792 |
全アドレスで待ち受け(外からも届く) |
Local Address:Port が 127.0.0.1:7791 |
自分自身からだけ届く |
[::]:PORT |
IPv6 の全アドレス(設定によって IPv4 も受ける) |
Send-Q(LISTEN 時) |
受け付け待ちの上限(backlog) |
Recv-Q(LISTEN 時) |
受け付け待ちの接続数。増え続けるならアプリの処理が追いついていない |
users:(("python3",pid=...)) |
どのプロセスが待ち受けているか |
フィルターで特定ポートだけ見ることもできます。
ss -tlnp 'sport = :7791'
ss -tln '( sport = :7791 or sport = :7792 )'
State Recv-Q Send-Q Local Address:Port Peer Address:PortProcess
LISTEN 0 5 127.0.0.1:7791 0.0.0.0:* users:(("python3",pid=23329,fd=3))
State Recv-Q Send-Q Local Address:Port Peer Address:PortProcess
LISTEN 0 5 0.0.0.0:7792 0.0.0.0:*
LISTEN 0 5 127.0.0.1:7791 0.0.0.0:*
確立中の接続とTIME-WAITを見る
ss -tnp state established '( dport = :7791 or sport = :7791 )'
ss -s | head -3
ss -tan state time-wait | head -4
Recv-Q Send-Q Local Address:Port Peer Address:Port Process
0 0 127.0.0.1:7791 127.0.0.1:38264 users:(("python3",pid=23329,fd=4))
0 0 127.0.0.1:38264 127.0.0.1:7791 users:(("python3",pid=23749,fd=3))
Total: 93
TCP: 85 (estab 37, closed 33, orphaned 0, timewait 33)
Recv-Q Send-Q Local Address:Port Peer Address:Port Process
0 0 192.0.2.2:58136 173.194.44.139:80
0 0 127.0.0.1:49736 127.0.0.1:7791
0 0 127.0.0.1:55794 127.0.0.1:7791
1本の接続は、サーバー側(7791)とクライアント側(38264)の2行で表示されます。 TIME-WAIT は接続を閉じた側に一定時間残る正常な状態で、数があること自体は問題ではありません。
ncでポートに届くか確かめる
nc(netcat)の -z はデータを送らずに接続だけを試し、-v で結果を表示します。 結果は3種類に分かれ、それぞれ原因が違います。
nc -zv 127.0.0.1 7790 # 何も待ち受けていないポート
nc -zv 127.0.0.1 7791 # 127.0.0.1 で待受中
nc -zv 192.0.2.2 7791 # 127.0.0.1 だけで待受しているポートに eth0 の IP で
nc -zv 192.0.2.2 7792 # 0.0.0.0 で待受中
nc -zv -w 2 10.255.255.1 7792 # 応答が返ってこない宛先
nc -zv 127.0.0.1 7790-7793 # 範囲指定
nc: connect to 127.0.0.1 port 7790 (tcp) failed: Connection refused
Connection to 127.0.0.1 7791 port [tcp/*] succeeded!
nc: connect to 192.0.2.2 port 7791 (tcp) failed: Connection refused
Connection to 192.0.2.2 7792 port [tcp/*] succeeded!
nc: connect to 10.255.255.1 port 7792 (tcp) timed out: Operation now in progress
nc: connect to 127.0.0.1 port 7790 (tcp) failed: Connection refused
Connection to 127.0.0.1 7791 port [tcp/*] succeeded!
Connection to 127.0.0.1 7792 port [tcp/*] succeeded!
nc: connect to 127.0.0.1 port 7793 (tcp) failed: Connection refused
| nc の結果 | 意味 | 次の一手 |
|---|---|---|
succeeded! |
TCP の接続まで成功 | アプリ層(curl -v、ログ)を確認 |
Connection refused |
相手ホストには届いたが、そのポートで誰も待ち受けていない(RST が返った) | 相手側で ss -tlnp を見る。待受アドレスが 127.0.0.1 だけになっていないか |
timed out |
応答が何も返ってこない | ファイアウォールでの破棄、経路、相手ホストの停止を疑う。ip route get・traceroute へ |
127.0.0.1:7791 には届くのに、同じホストの 192.0.2.2:7791 は refused になる、というのが「127.0.0.1 だけで待受」の典型的な見え方です。 アプリの待受アドレスを 0.0.0.0(または特定の外向き IP)に変えると解決します。
| よく使う nc の形 | 用途 |
|---|---|
nc -zv HOST PORT |
TCP で届くか |
nc -zv -w 3 HOST PORT |
3秒でタイムアウト |
nc -zv HOST 8000-8010 |
範囲で確認 |
nc -zvu HOST 53 |
UDP(応答がないと判定しにくい点に注意) |
nc -l 9000 |
自分で待ち受けて、相手から届くか確かめる |
echo hello | nc HOST 9000 |
文字列を送る |
digで名前解決を確かめる
dig は DNS サーバーに直接問い合わせ、応答をそのまま表示します。 DNS レコードの種類ごとの詳しい読み方は「DNSレコードの種類一覧」の記事で扱っているので、ここでは切り分けに使う形に絞ります。
dig +short example.com
dig +short NS example.com
dig -x 8.8.8.8 +short
dig nosuch-t79-example.invalid | grep -E 'status|SERVER'
dig @127.0.0.1 +time=1 +tries=1 example.com | tail -1
172.66.147.243
104.20.23.154
elliott.ns.cloudflare.com.
hera.ns.cloudflare.com.
dns.google.
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 34483
;; SERVER: 8.8.8.8#53(8.8.8.8) (UDP)
;; no servers could be reached
| dig の結果 | 意味 | 次の一手 |
|---|---|---|
status: NOERROR + ANSWER あり |
正常に引けた | IP が想定どおりか確認 |
status: NXDOMAIN |
その名前は存在しない | 名前のつづり、ドメインの登録・レコード設定を確認 |
status: NOERROR + ANSWER なし |
名前はあるが、その種類のレコードがない | A と AAAA、CNAME を確認 |
status: SERVFAIL |
DNS サーバー側で解決に失敗 | 別のサーバー(dig @8.8.8.8)でも試して比べる |
no servers could be reached |
DNS サーバーに届かない | /etc/resolv.conf の nameserver、UDP/TCP 53 番への経路 |
dig @サーバー で問い合わせ先を変えて比べると、「特定の DNS サーバーだけの問題か」がすぐわかります。 また、dig は /etc/hosts を見ないため、アプリと同じ順番(hosts → DNS)で確認したいときは getent hosts NAME を使います。
getent hosts localhost
127.0.0.1 localhost
curlでHTTPまで確かめる
curl -v は「名前解決 → 接続 → リクエスト → レスポンス」を順に表示するので、どこで止まったかが一目でわかります。 curl 自体の使い方は「curlコマンドの使い方」の記事にまとめているため、ここでは切り分けで見るポイントだけ載せます。
curl -v http://192.0.2.2:7792/ # 進捗表示と Date などのヘッダーは省略
* Trying 192.0.2.2:7792...
* Connected to 192.0.2.2 (192.0.2.2) port 7792
> GET / HTTP/1.1
> Host: 192.0.2.2:7792
> User-Agent: curl/8.5.0
> Accept: */*
>
* HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
< Server: SimpleHTTP/0.6 Python/3.11.15
< Content-type: text/html
< Content-Length: 10
失敗パターンは、curl の終了コードでも区別できます。
curl -sS http://127.0.0.1:7790/
curl -sS http://192.0.2.2:7791/
curl -sS --connect-timeout 2 http://10.255.255.1:7792/
curl -sS http://nosuch-t79.invalid/
curl -sS -o /dev/null -w 'code=%{http_code}\n' http://127.0.0.1:7792/nothing
curl: (7) Failed to connect to 127.0.0.1 port 7790 after 0 ms: Couldn't connect to server
curl: (7) Failed to connect to 192.0.2.2 port 7791 after 0 ms: Couldn't connect to server
curl: (28) Failed to connect to 10.255.255.1 port 7792 after 2001 ms: Timeout was reached
curl: (6) Could not resolve host: nosuch-t79.invalid
code=404
応答時間の内訳は -w で取れます。 どこで時間がかかっているかの切り分けに使います。
curl -sS -o /dev/null \
-w 'dns=%{time_namelookup} connect=%{time_connect} ttfb=%{time_starttransfer} total=%{time_total} code=%{http_code}\n' \
http://127.0.0.1:7792/
dns=0.000015 connect=0.000863 ttfb=0.001522 total=0.001578 code=200
| 値 | 大きいときに疑う場所 |
|---|---|
time_namelookup |
DNS |
time_connect − time_namelookup |
ネットワーク経路、相手の受け付け |
time_starttransfer − time_connect |
アプリの処理時間 |
time_total − time_starttransfer |
転送量、帯域 |
DNS を変えずに特定の IP へ向けたいときは --resolve が便利です。 /etc/hosts を書き換えずに、新しいサーバーへの切り替え前確認などができます。
curl -sS --resolve item.example:7792:127.0.0.1 http://item.example:7792/
item list
プロキシ環境では、curl が環境変数 http_proxy / https_proxy を自動で使います。社内の確認で挙動が変わるときは、curl -v の先頭に Uses proxy env variable が出ていないか見て、必要なら --noproxy '*' で直接接続を試してください。
ping・traceroute・tracepathで経路を確かめる
ping は ICMP(ネットワーク層の制御用メッセージ)で相手に届くか、traceroute / tracepath は途中のどこまで届くかを調べます。
ping -c 3 172.17.0.2 # 同じホスト上のコンテナ
ping -c 2 -W 1 8.8.8.8 # 外部(この環境では ICMP が通らない)
ping -c 1 nosuch-t79.invalid
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.070 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.037 ms
64 bytes from 172.17.0.2: icmp_seq=3 ttl=64 time=0.051 ms
--- 172.17.0.2 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2038ms
rtt min/avg/max/mdev = 0.037/0.052/0.070/0.013 ms
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
--- 8.8.8.8 ping statistics ---
2 packets transmitted, 0 received, 100% packet loss, time 1022ms
ping: nosuch-t79.invalid: Name or service not known
ここで大事なのは、8.8.8.8 への ping が 100% loss でも、同じ 8.8.8.8 への DNS 問い合わせ(dig)は成功していることです。 経路の途中で ICMP だけを通さない設定はよくあるため、「ping が通らない=通信できない」とは限りません。 ping で判断がつかないときは、nc や curl で実際に使うポートを確かめます。
traceroute -n -w 1 -q 1 -m 4 8.8.8.8
tracepath -n -m 3 8.8.8.8
traceroute to 8.8.8.8 (8.8.8.8), 4 hops max, 60 byte packets
1 192.0.2.1 0.370 ms
2 21.4.1.149 0.322 ms
3 *
4 *
1?: [LOCALHOST] pmtu 1400
1: 192.0.2.1 44.725ms
1: 192.0.2.1 0.114ms
2: 21.4.1.149 0.085ms
3: no reply
Too many hops: pmtu 1400
Resume: pmtu 1400
* や no reply は「そのルーターが応答を返さなかった」という意味で、そこで通信が止まっているとは限りません。 後ろのホップで応答が戻ってくれば、途中は通過できています。tracepath は root 権限なしで使え、pmtu 1400 のように経路上の MTU も表示してくれます。
| コマンド | 主なオプション |
|---|---|
ping |
-c 回数、-W 待ち秒、-i 間隔、-s サイズ、-M do(分割禁止で MTU 確認)、-4 / -6 |
traceroute |
-n 名前解決なし、-w 待ち秒、-q 試行回数、-m 最大ホップ、-T -p 443(TCP で調べる、root 必要)、-I(ICMP) |
tracepath |
-n、-m 最大ホップ、-p ポート |
tcpdumpでパケットを見る
tcpdump は実際に流れたパケットを表示するので、「送ったのか」「返ってきたのか」を確定できます。 実行には root 権限が必要です。
接続成功(3ウェイハンドシェイク)
2行目以降の options [...] は長いため省略しています。
sudo tcpdump -i lo -nn -c 6 'tcp port 7792' &
curl -s http://127.0.0.1:7792/ > /dev/null
22:09:46.560199 IP 127.0.0.1.46666 > 127.0.0.1.7792: Flags [S], seq 298631445, win 65495, options [mss 65495,sackOK,TS val 2307070346 ecr 0,nop,wscale 10], length 0
22:09:46.560216 IP 127.0.0.1.7792 > 127.0.0.1.46666: Flags [S.], seq 828591021, ack 298631446, win 65483, options [...], length 0
22:09:46.560231 IP 127.0.0.1.46666 > 127.0.0.1.7792: Flags [.], ack 1, win 64, options [...], length 0
22:09:46.560295 IP 127.0.0.1.46666 > 127.0.0.1.7792: Flags [P.], seq 1:78, ack 1, win 64, options [...], length 77
22:09:46.560299 IP 127.0.0.1.7792 > 127.0.0.1.46666: Flags [.], ack 78, win 64, options [...], length 0
22:09:46.561349 IP 127.0.0.1.7792 > 127.0.0.1.46666: Flags [P.], seq 1:187, ack 78, win 64, options [...], length 186
接続拒否(RST)
sudo tcpdump -i lo -nn -c 2 'tcp port 7790' &
curl -s http://127.0.0.1:7790/
22:09:50.576838 IP 127.0.0.1.52624 > 127.0.0.1.7790: Flags [S], seq 4281174259, win 65495, options [...], length 0
22:09:50.576849 IP 127.0.0.1.7790 > 127.0.0.1.52624: Flags [R.], seq 0, ack 4281174260, win 0, length 0
DNSの問い合わせ
sudo tcpdump -i any -nn -c 2 'udp port 53' &
dig +short example.org
22:09:54.596384 eth0 Out IP 192.0.2.2.36387 > 8.8.8.8.53: 34904+ [1au] A? example.org. (52)
22:09:54.613686 eth0 In IP 8.8.8.8.53 > 192.0.2.2.36387: 34904$ 2/0/1 A 104.20.26.136, A 172.66.157.237 (72)
| フラグ | 意味 | 読み取れること |
|---|---|---|
[S] |
SYN(接続開始) | クライアントが送った |
[S.] |
SYN-ACK | サーバーが受け付けた(待ち受けている) |
[.] |
ACK | 受信確認 |
[P.] |
PUSH(データあり) | HTTP リクエスト・レスポンス本体 |
[R.] |
RST | そのポートで待ち受けていない(Connection refused の正体) |
[F.] |
FIN | 接続を閉じる |
[S] だけが繰り返し出る |
応答なし | 途中で破棄されている(timed out の正体) |
| よく使う tcpdump の形 | 用途 |
|---|---|
tcpdump -i any -nn port 443 |
全インターフェースで 443 番 |
tcpdump -i eth0 -nn host 192.0.2.10 |
特定ホストとの通信 |
tcpdump -i eth0 -nn 'tcp[tcpflags] & tcp-rst != 0' |
RST だけ |
tcpdump -i eth0 -nn -c 100 -w cap.pcap port 80 |
ファイルに保存(Wireshark で開ける) |
tcpdump -r cap.pcap -nn |
保存したファイルを読む |
tcpdump -i any -nn -A port 80 |
中身を ASCII で表示(HTTP 平文の確認) |
層ごとの障害切り分けフロー
「つながらない」ときは、下の層から順に確かめると迷いません。 各段で使うコマンドと、この記事で取った実行結果の見え方を対応させました。
flowchart TD
A[つながらない] --> B{ip -br addr / ip -br link<br>インターフェースはUPでIPがある?}
B -- いいえ --> B1[L1/L2: ケーブル・NIC・DHCP・ip link set up]
B -- はい --> C{ip route get 宛先<br>経路はある?}
C -- いいえ --> C1[L3: デフォルトゲートウェイ・ルート追加]
C -- はい --> D{dig / getent hosts<br>名前は引ける?}
D -- いいえ --> D1[DNS: resolv.conf・NXDOMAIN・DNSサーバーへの経路]
D -- はい --> E{nc -zv 宛先 ポート}
E -- refused --> E1[相手側で ss -tlnp<br>LISTENしていない・127.0.0.1だけで待受]
E -- timed out --> E2[ファイアウォール・セキュリティグループ<br>traceroute / tcpdump で SYN の行方を見る]
E -- succeeded --> F{curl -v URL}
F -- 4xx/5xx・TLSエラー --> F1[L7: アプリ設定・ログ・証明書]
F -- 200 --> F2[通信は正常。クライアント側の設定やキャッシュを確認]
| 層 | 確認すること | コマンド | 正常な見え方(本記事の結果) |
|---|---|---|---|
| L1/L2 | インターフェースの状態 | ip -br link |
eth0 UP |
| L2 | 同じセグメントの相手 | ip neigh |
REACHABLE(FAILED なら相手不在) |
| L3 | IP アドレス | ip -br addr |
192.0.2.2/24 |
| L3 | 経路 | ip route get 宛先 |
via 192.0.2.1 dev eth0 |
| L3 | 到達性 | ping / tracepath |
0% packet loss(ICMP が止められている場合あり) |
| DNS | 名前解決 | dig +short / getent hosts |
IP が返る |
| L4 | ポート | nc -zv / ss -tlnp |
succeeded / LISTEN 0.0.0.0:PORT |
| L4 | パケット | tcpdump |
[S] → [S.] → [.] |
| L7 | HTTP | curl -v |
HTTP/1.x 200 |
エラー文の意味と次の一手
エラー文から逆引きできるようにまとめました。 いずれもこの記事の環境で実際に出た文言です。
| エラー文 | 意味 | 次の一手 |
|---|---|---|
nc: connect to ... failed: Connection refused |
相手は RST を返した。ポートで誰も待ち受けていない | 相手側で ss -tlnp、待受アドレスとポート番号を確認 |
curl: (7) Failed to connect to ... Couldn't connect to server |
同上(curl の場合) | 同上。curl -v の connect to ... failed: Connection refused で確定 |
nc: connect to ... timed out: Operation now in progress |
SYN に応答がない | ファイアウォール、経路、相手の停止。tcpdump で [S] だけが出ているか確認 |
curl: (28) Failed to connect ... Timeout was reached |
同上(curl の場合) | 同上 |
curl: (6) Could not resolve host: ... |
名前解決できない | dig、getent hosts、/etc/resolv.conf |
ping: ...: Name or service not known |
名前解決できない | 同上 |
status: NXDOMAIN |
その名前は DNS に存在しない | つづり、レコード設定 |
;; no servers could be reached |
DNS サーバーに届かない | nameserver の IP、53 番ポートへの経路 |
100% packet loss |
ICMP の応答がない | ICMP が止められているだけの場合も。nc / curl で実際のポートを確認 |
ip neigh で FAILED |
同じセグメントで MAC が解決できない | 相手の電源・IP・VLAN を確認 |
traceroute の * / tracepath の no reply |
そのホップが応答しない | 後続のホップが応答していれば問題なし。最後まで * なら最後に応答したホップの先を調べる |
OSError: [Errno 98] Address already in use |
そのポートは既に使われている | ss -tlnp 'sport = :PORT' で使用中のプロセスを確認(詳細は「Address already in use」の記事) |
127.0.0.1 では成功、外向き IP では refused |
127.0.0.1 だけで待受 | ss -tlnp の Local Address を確認し、待受を 0.0.0.0 に(詳細は「localhostで接続が拒否されました」の記事) |
よくある質問
Q. ifconfig や netstat が「command not found」になります。
A. net-tools パッケージが入っていない構成です。 ip addr と ss -tlnp で同じ情報が見られるので、まずはそちらを使うのがおすすめです。どうしても必要な場合は sudo apt-get install net-tools で追加できます。
Q. ping が通らないのに、ブラウザやアプリではつながります。なぜですか?
A. 経路の途中で ICMP(ping が使う仕組み)だけを通さない設定があるためです。 この記事の環境でも、8.8.8.8 への ping は 100% loss でしたが、同じ相手への DNS 問い合わせは成功しました。実際に使うポートは nc -zv や curl -v で確かめるのが確実です。
Q. Connection refused と timed out はどう違いますか?
A. refused は「相手まで届いたが、そのポートで誰も待ち受けていない」、timed out は「何も返ってこない」です。 tcpdump で見ると、refused は [R.](RST)が返り、timed out は [S] だけが繰り返されます。refused なら相手のアプリ側、timed out ならファイアウォールや経路を疑います。
Q. ss -tlnp でプロセス名が表示されません。
A. 他のユーザーが起動したプロセスの情報は、root 権限がないと表示されません。 sudo ss -tlnp で実行してください。
まとめ
- ネットワーク確認の中心は ip・ss・nc・dig・curl の5つ。ping・traceroute・tracepath・tcpdump で補う
- 旧コマンドは ifconfig→ip addr、route→ip route、arp→ip neigh、netstat→ss と読み替える
ss -tlnpの Local Address が 127.0.0.1 なら自分からだけ、0.0.0.0 なら外からも届く- nc の結果は succeeded / refused / timed out の3種類で、refused は待受なし、timed out は経路や破棄を疑う
- ping が通らなくても通信できることがある。実際のポートは nc や curl で確かめる
- tcpdump の
[R.]は待ち受けなし、[S]だけの繰り返しは応答なしを示す - 下の層から順に(インターフェース → 経路 → DNS → ポート → HTTP)確かめると迷わない
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「Linuxネットワークコマンド一覧|ip/ss/ncで障害切り分け」
株式会社RJCでは、Linux のネットワークの切り分け方を仲間と学び合っています。こうした知識を共有しながら、日々技術を磨いています。
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。