Linux Command 정리 - tc, netstat, tcpdump

0

linux command

목록 보기
1/1

linux에서 많이 사용되는 network command들을 정리했다. iptables는 너무 방대하니까 나중에 따로 정리하도록 하자.

tc

tc는 traffic control로 traffic control 기능을 제공하는 도구이다. tc를 통해서 특정 NIC의 packet input, output 송수신 속도와 순서를 결정 가능하게 할 수 있다. 또한, qdisc는 단순한 FIFO queue로 인위적인 packet 유실, 지연, 전송 속도 제한 등을 가능하게 해준다.

필자의 경우 자주쓰진 않았지만, RTT를 임의로 만들어낼 때 사용하였다.

tc qdisc add dev eth1 root netem delay 120ms

eth1 부분을 본인들의 NIC로 바꾸면 된다. ip -br addr를 통해 얻은 NIC list 중 RTT를 적용시킬 것을 선택하면 된다. 위의 경우 120ms의 RTT를 설정해주도록 하였다.

tc qdisc show dev eth1
qdisc netem 8008: root refcnt 2 limit 1000 delay 120.0ms

잘 적용되었는 지 확인하는 명령어이다. eth1을 각자의 NIC로 바꾸도록 하자.

일정 확률로 NIC를 통과하는 packet을 drop시킬 수도 있다.

tc qdisc add dev eth1 root netem loss 10%

다음의 명령어는 10%의 확률로 eth1에 들어온 packet을 drop 시킨다.

netstat

network statistics로 네트워크 접속, 라우팅 테이블, 네트워크 인터페이스 등에 대한 통계 정보를 확인하기 위해 사용된다. 말은 거창하지만, 필자는 주로 TCP connection에 대한 현재 연결 상태를 확인하기 위해 사용한다.

netstat
Active Internet connections (w/o servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State  
tcp       32      0 xxx.xxx.xxx.xxx:61210   xxx.xxx.xxx.xxx:12345   CLOSE_WAIT
...
Active UNIX domain sockets (w/o servers)
Proto RefCnt Flags       Type       State         I-Node   Path
unix  5      [ ]         DGRAM                    17777    /run/systemd/journal/socket

기본적으로 netstat을 입력하면 internet 연결과 unix domain socket 연결 정보를 보여준다. internet 연결은 실제로 network stack(transport, network layer)를 통해 서비스 되는 connection들에 대한 정보를 나타낸다. 가장 많이 사용되는 것은 tcp connection으로 Recv-Q, Send-Q가 receive socket buffer, send socket buffer를 나타낸다.

unix domain socket은 Type을 통해 stream인지 datagram인지 파악할 수 있다.

대체로 netstat은 TCP connection이 제대로 잘 맺어졌는 지, 현재 어떤 상태인지, queue에 문제는 없는 지 분석하기 위해서 많이 사용한다. 이를 위해 사용하는 명령어는 다음과 같다.

netstat -altnp
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp6       0      0 WW.WW.WW.WWW:WWWW      XX.XXX.XX.XXX:XXXXX     ESTABLISHED 1722856/kube-apiser
  1. -a: 다른 host와 ESTABLISHED(연결)되어있거나, LISTENING(대기) 중인 모든 연결을 보여준다.
  2. -n: host명, port명을 보여주지 않고, IP, Port값을 그대로 보여준다. ex) test:http가 아니라 192.168.100.20:80
  3. -ㅣ: LISTENING 상태인 서비스 port를 보여준다.
  4. -t: TCP 프로토콜만 보여준다.
  5. -u: UDP 프로토콜만 보여준다.
  6. -p: 해당 port를 사용하는 program과 process의 PID를 보여준다.
  7. -r: 라우팅 테이블 출력
  8. -s: protocol(IP, ICMP, TCP, UDP)로 통계를 보여준다.
  9. -c: 1초 단위로 결과값을 연속적으로 보여준다.

netstatgrep을 사용하여 특정 connection이 잘 있는 지 확인할 수 있다. 가령 6666번 port에 대한 TCP 연결을 확인하고 싶다면 다음과 같이 쓸 수 있다.

netstat -altnp | grep 50003
tcp        0      0 127.0.0.1:50003          0.0.0.0:*               LISTEN      39007/test

또한, watch와 함께 사용하여 더 짧은 순간마다의 결과를 실시간으로 확인할 수 있다.

watch -n0.1 "netstat -altnp | grep 50003"

0.1초마다의 결과가 올라오게 된다.

대표적으로 netstat으로 확인하는 것 중 하나는, 대용량 test를 하거나 대규모 traffic이 전달되는 상황에서 receive queue와 send queue에 문제가 있는 지 확인하는 것이다.

watch -n0.1 "netstat -altnp | grep 50003"
Proto   Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp6  13899894      0 WW.WW.WW.WWW:WWWW      XX.XXX.XX.XXX:XXXXX     ESTABLISHED 1722856/kube-apiser

만약 0.1초씩 업데이트하고 있는데, 위와 같이 Recv-Q가 안비워지고 있거나, 점점 차오르고 있다면 수신하는 입장에서 매우 감당하기 어려운 부하가 오고있다는 것이다. 지금은 receive queue에 값이 얼마 안들어와서 그렇지만, 점점 많이 들어오고 쌓이면 TCP 연결 상 flow control이 동작하여 zero window 문제가 발생할 수 있다. 또한, 수신 window가 너무 작아지므로 처리량이 작아지는 문제가 발생한다. 가장 큰 문제는 network에서 약간의 지연으로 인해 packet이 한 번에 너무 많이 한꺼번에 들어오는 순간 buffer가 꽉 차고 packet을 유실하는 문제가 생길 수 있다.

따라서, receive queue가 잘 비워지도록 수신 측 application의 성능을 향상시키거나, kernel parameter로 receive buffer의 크기나, 송신 측 window를 제어하는 것도 하나의 방법이다.

다음으로 netstat에서 가장 많이 보는 것은 State이다. 가령 TCP Connection의 경우는 논리적인 연결이기 때문에 두 host들 끼리의 state를 다르게 생각할 수 있다. 한 쪽은 TCP connection을 끊었다고 생각하고, 한 쪽은 아직 연결이 되어있다고 생각하는 half-close 상태가 발생할 수 있다. 이러한 TCP connection 상태는 각 host에서 netstat으로 확인해줄 수 있다.

TCP state는 다음과 같이 정리할 수 있다.
https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb1OKGI%2Fbtq4kEzch8m%2Fy4tdX0NFsn5JIN1pElaQL0%2Fimg.png

먼저 TCP connection을 처음 맺을 때이다. 이는 3way handshaking을 생각하면 된다.
1. LISTEN: server가 socket을 열고 접속 요청을 대기하고 있는 상태
2. SYS-SENT: 로컬 host가 원격 host에 SYN 요청을 전송
3. SYN_RECEIVED: server가 원격 클라이언트로부터 접속 요구를 받아 클라이언트에게 응답하였지만, 아직 클라이언트에게 확인 메시지는 받지 않은 상태
4. ESTABLISHED: 3 way-handshaking이 완료된 후 서로 연결된 상태(data를 주고 받는다.)

다음은 TCP connection을 끊을 때이다. 이는 4way handshaking을 생각하면 된다.
5. FIN_WAIT1: A host가 FIN을 전송하고 B로부터 FIN을 받기를 기다리는 상태
6. CLOSE-WAIT: B host가 A host로부터 FIN을 받고 ACK을 보낸다음 FIN을 보내기까지의 상태
7. FIN_WAIT2: A host가 B host로부터 ACK은 받았지만 FIN을 받지 못한 상태
8. LAST-WAIT: B host가 A host에게 FIN을 보낸 후의 상태
9. TIME_WAIT: A host가 B host에게 FIN을 받고, ACK을 보낸다. 이후 socket을 닫기까지 기다리는 상태 (kernel paramter로 조정 가능 60초 후에 socket을 닫는다.)
10. TERMINATED: B host가 A host에게 ACK을 받고 socket을 close 시키는 상태로 TCP connection이 종료된다.

조심해야할 것은 TIME_WAIT 상태인데, TIME_WAIT은 fin을 받아도 socket을 바로 회수하지 않는다. 따라서, port number가 점유되어있다는 것이고, 이 상태에서 이전에 사용했던 port를 재사용하려고하면 port 점유에 실패하게 에러가 발생한다.

TIME_WAIT 상태에서 socket을 바로 회수하지 않는 것은 여러 이유가 있지만, 일반적으로 상대방이 보낸 packet이 FIN packet보다 늦게 도착할 수 있기도 하고, 상대방이 보낸 FIN에 대한 ACK을 재전송해야할 수도 있기 때문이다.

따라서, socket에 port를 할당했는데 에러가 발생한다면 netstat으로 해당 port가 TIME-WAIT 상태인지 확인해보도록 하자. 만약 TIME_WAIT이면 일정 시간 후에 다시 해당 port를 쓸 수 있다. 이것이 싫다면 kernel parameter를 통해서 port reuse option 켜거나 timeout에 대한 시간을 수정하도록 할 수 있다. 그러나 TIME-WAIT은 bug가 아니라는 점과 port reuse를 하기 위해서는 어느정도의 compensation이 필요하다는 점을 유의하도록 하자.

https://meetup.nhncloud.com/posts/55

tcpdump

transport layer의 packet 전송, 수신 결과를 캡쳐하는 tool이다. client와 server가 TCP 연결이 이루어지고 packet을 송수신하고 있다면 tcpdump를 캡쳐하여 결과를 확인할 수 있다.

tcpdump -i eth0 tcp port 8080 host 192.168.10.2
  1. -i: ethernet interface를 지정할 수 있는 option으로 -i를 통해 ethernet0의 packet을 캡쳐하겠다는 것이다. 지정하지 않을 경우 any로 모든 interface를 확인한다.
  2. tcp: 어떤 protocol을 캡쳐할 지 설정하도록 한다. arp, proto/ip 등 다른 protocol도 있다.
  3. port: 어떤 port로 오는 packet을 캡쳐할 지 설정하도록 한다. 송수신 모두 해당한다.
  4. host: 어떤 IP로 오는 packet을 캡쳐할 지 설정하도록 한다. 송수신 모두 해당한다.

만약 port와 host를 특정 송수신자의 packet으로 설정하고 싶다면 앞 부분에 src, dst만 붙이면 된다.

tcpdump tcp src host 192.168.10.2

송신자의 packet이 192.168.10.2인 경우의 packet만 캡쳐하는 것이다. 반대로 dst host 192.168.10.2라고 쓰면 목적지가 192.168.10.2인 packet만 캡쳐하는 것이다.

추가적으로 not도 쓸 수 있다.

tcpdump tcp not src host 192.168.10.2

192.168.10.2 송신자 packet이 아닌 것만 캡쳐하는 것이다.

자주 사용되는 다른 옵션들도 있다.

  1. nn: tcpdump에서 packet을 캡쳐할 시에 나오는 결과 정보 중에 host IP를 해당 host의 hostname으로 바꿔준다. 가령 192.168.10.2myuser라는 hostname을 가지면 myuser로 바꿔준다. 또한, port도 well-known port일 경우 protocol로 바꿔준다. 가령 80이면 http로 변환
  2. vv: 더 자세하게 packet을 써준다.

그러나, 실제로 사용하다보면 packet이 너무 많아서 file의 용량이 너무 증가하는 문제가 생긴다. 필자의 경우 10초 동안의 packet 기록이 10GB였어서 오래켜지 못했었는데, 이러한 경우 특정 file에 쓰고 10초마다 덮어쓰도록 하는 것이 좋다. 즉, file rotate가 동작하도록 하면 된다.

tcpdump -i eth1 tcp port 50003 -G 10 -w ./tcpdump.pcap
  1. -w: tcpdump 결과를 지정한 file로 만들어준다.
  2. -G: 초 단위로 tcpdump 결과를 rotate해준다. 즉, 10초마다의 결과를 tcpdump.pcap에 덮어쓰도록 하는 것이다.

이렇게하면 10초마다 tcpdump.pcap에 결과를 덮어써준다.

결과로 나온 파일을 wireshark나 tshark를 통해서 읽을 수도 있지만, tcpdump를 통해서 읽을 수도 있다.

tcpdump -r ./tcpdump.pcap
  1. -r: read option으로 tcpdump 결과 파일을 읽을 수 있다.

뒤에 이어서 filter를 넣어 원하는 결과가 있는 지 없는 지 확인할 수 있다. 가령 tcp reset flag를 받은 경우는 다음과 같이 filter가 가능하다.

tcpdump -r ./tcpdump.pcap 'tcp[tcpflags] & (tcp-rst) != 0'

조금 tcpdump 사용법이 어려워보이지만 사실 tcpdump 자체에는 option이 그렇게 복잡하진 않다. tcpdump에서 사용되는 pcap filter가 헷갈려서 복잡해보이는 것이 전부이다.

tcpdump의 구조를 일반화하면 다음과 같이 생겼다.

tcpdump -option option_value "pcap filter"

여기서 pcap filter부분이 바로 위에서 본 src, host 이러한 keyword들이다. 가령 src의 ip가 192.168.10.10이라면 다음과 같이 쓸 수 있는 것이다.

tcpdump "src host 192.168.10.10"

pcap은 하나의 network 분석 file로 생각하면 된다. 이 file에서 어떤 packet들을 filtering할 지가 바로 pcap filter이다.

pcap filter를 사용하는 방법에 대해서는 여기를 참고하도록 하자.

0개의 댓글