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期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ

RJCで一緒に開発しながら、 成長を楽しみませんか?