[Linux] 리눅스 네트워크 트러블슈팅 기본 가이드

Jaemun Jung
15 min readApr 17, 2021

--

How to Troubleshoot Network Problems on Linux

늘 네트워크를 활용하고 있기는 하지만 네트워크의 개념과 설비가 방대하기 때문에 전체적으로 이해하기는 쉽지 않은 분야이다.
그래도 네트워크 이슈가 생겼을때 대응할 수 있는 기본적인 원인 파악 방법들을 알고 있어야최소한 네트워크엔지니어가 문제 파악을 효율적으로 할 수 있도록 돕고 커뮤니케이션할 수 있을 것이다. 이런 관점에서 기본적인 트러블슈팅 방법들을 정리해보았다.
어차피 나 혼자 하기는 힘드니 네트워크엔지니어께 요청할 때 최대한 도움이라도 되보자는 관점에서…

아래에서
1. 기본적인 네트워크 관련 Linux command를 먼저 정리하고,
2. 네트워크 장애 사례를 들어 트러블슈팅 방법을 알아보고자 한다.

Network 관련 Linux Commands

1. ping

대상 호스트(호스명 or IP주소)로 ICMP(Internet Control Message Protocol)을 보낸다. 대상 호스트에 연결이 되어있는지 확인할 수 있는 가장 기본 커맨드이다. 예를 들면 Web 페이지가 표시되지 않을 때 소프트웨어가 다운되었는지, 호스트 자체가 다운 되었는지를 확인할 수 있다. Web 서버 소프트웨어가 다운되어도 호스트가 살아있으면 응답을 받을 수 있다.

ping [host name or IP address]

2. netstat

netstat(Network Statistics)은 TCP-IP 커넥션 네트워크의 통계 정보를 제공해준다. 열려있는 포트와 동작하고 있는 소프트웨어도 확인할 수 있다.
옵션
- a : 모든 패킷 정보 표시
- i : 네트워크 인터페이스 상태 표시
- n : 주소, 포트수치 표시(netstat은 역 dns 질의를 통해 각 ip 호스트 이름을 얻으려 하므로 출력에 지연이 생긴다. 호스트 이름이 필요 없고 ip 만으로 충분한 경우 사용)
- p : PID와 프로세스 표시 (root 권한 필요)
- r : 루팅테이블 표시
- t : TCP만 표시
- u : UDP만 표시
- l : LISTEN인 상태만 표시

$ sudo netstat -tnlp
  • netstat 결과 설명
    - Proto : 프로토콜 종류. TCP / UDP / RAW
    - Recv-Q : 해당 process가 현재 받는 바이트 표기
    - Send-Q : 해당 process가 현재 보내는 바이트 표기
    - Local Address : 출발지 주소 및 포트
    - Foreign Address : 목적지 주소 및 포트
    - State : 포트의 상태
  • Local address는 현재 열려있거나 리스닝하고 있는 IP:Port이다.
    0.0.0.0은 all interface를 받는 것이고, 127.0.0.1은 loopback으로 자기자신만 호출 가능한 상태이다.

3. ifconfig

네트워크 인터페이스 상태 표시 및 설정. IP 확인을 위해 주로 활용한다.

ifconfig

4. hostname

hostname 표출 혹은 지정. 인자로 hostname을 넘기면 지정이고, 인자 없이 입력하면 현재 hostname을 표시한다.

hostname [hostname]

5. traceroute

지정된 호스트까지 패킷이 전달되는 경로를 표시. ping이 날라가지 않을 경우, traceroute을 통해 호스트 자체에 문제가 있는지, 호스트에 도달하기까지 네트워크 경로중에 문제가 있는지 알아볼 수 있다.

traceroute는 IP 패킷의 Time to Live(TTL) 필드를 활용해 destination까지의 traffic path를 알아내는데 간단하게 그 방법을 정리해보면:
- TTL 1부터 한패킷씩 전송을 시작한다.
- 패킷이 전송중에 만료될 것이므로, upstream router는 ICMP Time-to-Live Exceeded 패킷을 보낸다.
- 그렇게 첫번째 hop을 식별하고,
- 다음 hop을 찾기 위해 TTL을 증가시켜서 또 패킷을 보낸다.
- 이런 식으로 TTL 패킷 전송을 반복해서 최종 목적지까지 도달하기까지의 중간단계 라우터들의 리스트를 알아낼 수 있다.

traceroute [hostname or IP]

6. route

기기의 라우팅 테이블을 반환한다. IP 네트워크에서 라우팅 테이블은 특정 서브넷에서 다른 서브넷으로 패킷을 보내기 위해 활용된다.
- Destination : 수신처의 네트워크 또는 호스트
- Gateway : 게이트웨이 주소. [*]는 미설정
- Netmask : 수신처의 서브넷마스크(호스트 255.255.255.255, 기본 게이트웨이 0.0.0.0)
- Flags : 경로 상태 (U: 경로 유효, H: 수신처는 호스트, G: 게이트웨이 사용, I:경로 무효)
- Metric: 수신처 까지의 거리
- Use : 경로의 참조 횟수
- Iface : 해당 경로를 사용하는 네트워크 인터페이스

Network Troubleshooting Case

TCP/IP Model

먼저 TCP/IP 모델에 대해서 간단히 알아보자. TCP/IP 모델은 공식 네트워크 모델인 OSI Model보다 현대 네트워크에 사용되는 프로토콜군을 더 정확하게 표현하는, de facto 표준 모델이라고 할 수 있다.
TCP/IP 모델은 크게 네 범주로 나누는데, software application 관점의 범주, host-to-host transport 경로 범주, 인터넷 네트워킹 범주, 그리고 local network에서의 다른 node들과의 direct link 범주이다.
OSI 모델에 대응하는 TCP/IP모델은 다음과 같다.

만약 MySQL 서버로 SSH는 가능한데 MySQL DB에 접근이 안되는 상황을 가정한다면, 이 문제는 확실히 하단의 Data Link나 Physical Layer 관련 문제는 아닐 것이다. 그래서 일반적으로 위 모델 스택의 가장 상위에 있는 Application Layer로부터 차례로 아래로 내려가면서 트러블슈팅을 해나가는 것이 좋다.

아래에서는 각 Layer별 진단 방법에 대해서 Layer 1부터 Layer 4까지 한번 알아보자.

Layer 1: The physical layer

물리계층 이슈하면 케이블이 제대로 꽂혔는지 확인하는게 가장 먼저 떠오르는데, Linux command로도 문제가 있는지 간단히 확인해볼 수 있다. ip link show command의 예시를 보자.

# ip link show 
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
2: eth0: <BROADCAST,MULTICAST> mtu 1500 qdisc pfifo_fast state DOWN mode DEFAULT group default qlen 1000 link/ether 52:54:00:82:d6:6e brd ff:ff:ff:ff:ff:ff

위 예시를 보면 eth0 인터페이스가 DOWN 되어있다. 1계층이 제대로 동작하고 있지 않다는 의미이다. 이 경우 보통 케이블이나 스위치 등의 문제를 점검한다.

Layer 2: The data link layer

데이터링크 계층은 local network 연결을 담당한다.
대부분의 시스템 관리자에게 가장 적합한 2계층 프로토콜은 3계층 IP 주소를 2계층 Ethernet MAC 주소에 매핑하는 ARP(Address Resolution Protocol)다. 호스트가 LAN 내의 다른 호스트(default gateway같은)에 접근하려고 할 때, 보통 IP주소를 갖고 있겠지만, 다른 호스트의 MAC 주소는 모를 것이다. 하지만 LAN 구간에서는 IP가 아니라 MAC주소를 통해 서버에 접근한다. 이 때 바로 ARP가 IP를 MAC 주소로 변환해서 찾아주는 프로토콜이다.
(modern network에서는 generated된 MAC 주소를 사용하는 VRRP(Virtual Router Redundancy Protocol)를 많이 활용하기도 한다)

일반적인 상황은 ARP entry가 채워지지 않아서 localhost가 default 게이트웨이의 2계층 MAC주소를 얻지 못하는 상황이다. 그러면 호스트는 어떤 트래픽도 원격(remote) 게이트웨이로 내보낼 수 없게 된다. 이런 문제는 게이트웨이에 대해서 잘못된 IP주소를 갖고 있거나, 스위치 포트가 잘못 설정되어있거나 등의 원인으로 생길 수 있다.

ARP table의 entry들은 ip neighbor command로 확인해볼 수 있다.

# ip neighbor show 
192.168.122.1 dev eth0 FAILED

문제가 없는 경우 위의 FAILED 메시지가 REACHABLE로 표출될 것이다.

Layer 3: The Network/internet layer

3계층은 가장 익숙한 IP address를 포함하는 계층이다. IP 주소는 local network를 벗어나는 다른 외부의 호스트에 대한 주소를 제공한다.
먼저 ip address 커맨드로 로컬 머신의 IP 주소를 확인해보자. -br flag로 결과를 심플하게 볼 수 있다.

# ip -br address show
lo UNKNOWN 127.0.0.1/8 ::1/128
eth0 UP 192.168.122.135/24 fe80::184e:a34d:1d37:441a/64 fe80::c52f:d96e:a4a2:743/64

3계층 트러블슈팅에서 가장 기본적으로 많이 쓰이는 툴은 위의 Linux commands에서 소개한 ping 이다. ping은 ICMP Echo Request 패킷을 보내고, ICMP Echo Reply 응답을 기대한다.
여기서 ping 응답의 time 필드는 trace의 중간에 있는 네트워크의 영향을 받을 수도 있으므로 이를 통해 순수하게 애플리케이션의 latency를 표현할 수는 없다는 점을 유념해야한다.

# ping www.google.com 
PING www.google.com (172.217.165.4) 56(84) bytes of data. 64 bytes from yyz12s06-in-f4.1e100.net (172.217.165.4): icmp_seq=1 ttl=54 time=12.5 ms

3계층 트러블슈팅에서 또 다른 많이 쓰이는 툴은 위에서 설명한 traceroute 커맨드이다. traceroute을 통해 호스트 자체에 문제가 있는지, 호스트에 도달하기까지 네트워크 경로중에 문제가 있는지 알아볼 수 있다.

# traceroute www.google.com 
traceroute to www.google.com (172.217.10.36), 30 hops max, 60 byte packets 1
acritelli-laptop (192.168.122.1) 0.103 ms 0.057 ms 0.027 ms 2 192.168.1.1 (192.168.1.1) 5.302 ms 8.024 ms 8.021 ms 3 142.254.218.133 (142.254.218.133) 20.754 ms 25.862 ms 25.826 ms 4 agg58.rochnyei01h.northeast.rr.com (24.58.233.117) 35.770 ms 35.772 ms 35.754 ms 5
agg62.hnrtnyaf02r.northeast.rr.com (24.58.52.46) 25.983 ms 32.833 ms 32.864 ms 6
be28.albynyyf01r.northeast.rr.com (24.58.32.70) 43.963 ms 43.067 ms 43.084 ms
.....

traceroute의 path 분석 시 주의사항을 하나 알아두자.
상대적으로 작은 LAN 안에서는 traceroute가 비교적 정확한 path를 리턴할 수 있지만, 큰 네트워크나 인터넷 환경에서는 리턴되는 path가 동적으로 바뀔 수 있다. 즉, 트래픽이 매번 전송될 때마다 다른 리턴 path를 탈 수도 있는 것이다.
따라서 네트워크 테스트 시점에 안정적이고 빠른 path가 나왔다고 해서 이후 운영 시점에도 그 path를 탈 것이라고 보장되지는 않는다는 것을 유념해두어야 한다.

Layer 4: The transport layer

전송계층은 TCP와 UDP등의 프로토콜을 포함한다.
TCP는 connection-oriented 프로토콜이며, UDP는 connectionless 프로토콜이다.
어플리케이션은 IP주소와 포트로 구성된 socket에서 LISTEN상태로 대기한다. 특정 포트로 들어온 트래픽은 커널에 의해서 listening중인 애플리케이션으로 전달된다.

가장 먼저 체크해야하는 것은 localhost에서 listening중인 포트이다. 만약 머신에서 웹이나 SSH 등의 특정 서비스에 연결할 수 없는 상태라면 이 결과가 특히 유용할 수 있다. 다른 흔한 문제는 이미 특정 포트에서 listening중인 프로그램이 있어서 데몬이나 서비스가 시작되지 못하는 경우다. (바로 이 포트 충돌 문제로 이슈를 겪어서 지난 포스트 [AWS] EMR Trouble Shooting-Bootstrap Failure-Port conflicts에 정리한적이 있다.)
ss 또는 netstat 커맨드를 통해 이런 종류의 문제를 확인할 수 있다. 위의 커맨드를 알아볼 때 netstat은 알아보았으니 여기서 ss 커맨드의 예시를 보자.

# ss -tunlp4 
Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port
udp UNCONN 0 0 *:68 *:* users:(("dhclient",pid=3167,fd=6))
udp UNCONN 0 0 127.0.0.1:323 *:* users:(("chronyd",pid=2821,fd=1)) tcp LISTEN 0 128 *:22 *:* users:(("sshd",pid=3366,fd=3))
tcp LISTEN 0 100 127.0.0.1:25 *:* users:(("master",pid=3600,fd=13))

ss 의 flag정보를 확인해보면:
t — Show TCP ports.
-u — Show UDP ports.
-n — Do not try to resolve hostnames.
-l — Show only listening ports.
-p — Show the processes that are using a particular socket.
-4 — Show only IPv4 sockets.

위의 출력 결과를 보면 sshd 애플리케이션이 port 22에서 모든 IP address를 대상으로 listening하고 있다.(*:22)

다른 케이스로 원격 연결 문제가 있을 수 있다. 로컬머신이 원격에 위치한 MySQL의 3306 포트에 접근하지 못하는 경우를 가정해보자. 이런 상황에 telnet 커맨드를 활용해볼 수 있다.

# telnet database.example.com 3306 
Trying 192.168.1.10…
^C

위의 커맨드 결과, 강제로 킬하기 전까지 telnet이 hang되고 있는 상태였다.
원인은 어쩌면 MySQL 애플리케이션이 해당 포트를 리스닝하고 있지 않을 수도 있고(이때 혹시 리모트 호스트에서 권한이 있다면 위에서 썼던 ss 명령어를 통해 확인해 볼 수 있을 것이다), 혹은 호스트나 firewall이 트래픽을 필터링하고 있을 수도 있다. 이런 경우 네트워크 엔지니어에게 4계층 연결 상태에 대해서 문의해 보아야할 것이다.

TCP 확인을 위해서는 telnet 명령으로 충분하지만, UDP 확인을 위해서는 netcat 툴을 사용해야한다.

# nc 192.168.122.1 -u 80 
test
Ncat: Connection refused.

(netcat은 일반적으로 보안 리스크가 있는 유틸리티로 간주되므로, 트러블슈팅에 필요해서 활용하고 나면 삭제해두기를 권장한다.)

Wrapping up

기본적인 네트워크 이슈를 확인하기 위해, 위에서 소개한 명령어와 툴들이 좋은 출발점이 될 수 있을 것이다. 위의 방법들을 통해서, 최소한 네트워크 엔지니어에게 이슈에 대해서 리포팅할 때 가능한 한 디테일한 정보를 제공하는데 유용하게 쓰이기를 바란다.

마지막으로 잊지 말 것: The packets don’t lie!

위의 문제해결 사례는 Red Hat(www.redhat.com)의 A beginner’s guide to network troubleshooting in Linux의 내용을 참조하였습니다.

--

--