02시 14분에 driver alarm, 02시 15분에 해제, 아침에 트렌드를 열어 보면 멀쩡하다. 어느 현장에서 사흘 연속 이랬고 회의는 매번 같은 결론이었다. "네트워크 문제." 추측이 끝난 건 SCADA server NIC에 capture를 걸어 둔 밤이었다. PLC는 8 ms 안에 응답했는데 그 응답이 firewall outside interface에는 아예 나타나지 않았다. Packet 네 개가 일주일짜리 논쟁을 끝냈다.
Capture가 switch counter나 driver log를 대신하지는 않는다. 대신 "application이 깨졌다"와 "경로가 깨졌다" 사이에 선을 긋는다. 논쟁은 대부분 정확히 그 선 위에서 벌어진다.
장애가 살아 있을 때 걸어야 한다
가장 흔한 실패는 장애가 끝난 뒤에 capture를 시작하는 것이다. 문제가 진행 중이고 관찰이 안전하다면 지금 건다. 정비 시간까지 기다릴 이유가 없다. 장애 중 5분이 사후 회의 하루보다 정확하다.
증상별로 어디에 걸 것인가:
- 화면이 멈추거나 driver timeout이 뜨면 HMI runtime 또는 SCADA server NIC.
- 여러 client가 같은 PLC를 동시에 잃으면 PLC uplink port.
- OPC UA session이 반복 재연결되거나 certificate error가 뜨면 OPC UA server interface.
- Modbus TCP gateway에서 특정 slave 하나, unit id 하나만 조용해지면 gateway port.
- Rule, route, NAT를 건드린 직후라면 firewall 안쪽과 바깥쪽 양쪽.
하룻밤에 한 번 터지는 문제라면 거대한 파일 하나 대신 ring buffer를 쓴다.
tcpdump -i eth1 -w /var/tmp/plc-%Y%m%d-%H%M%S.pcap -C 200 -W 24 -Z root \
'host 192.168.10.25 and (port 502 or icmp)'
-C는 100만 바이트 단위, -W는 유지할 파일 개수다. 위 명령은 디스크 약 4.8 GB를 쓰면서 대략 하루치를 남긴다. 100~200 MB 파일은 바로 열리지만 6 GB 단일 파일은 열리지 않는다. tcpdump가 4.0 이전이면 -s 0을 붙인다. 안 붙이면 정작 보려던 Modbus payload가 잘려 나가고, 그걸 이틀 뒤에 알게 된다.
명령, interface 이름, 그 장비의 time zone, capture 목적을 같은 자리에서 작업 기록에 적는다. 6주 뒤에 맥락 없는 pcap은 아무도 증언해 줄 수 없는 파일이다.
같은 timeout이 위치에 따라 네 가지 뜻이 된다
어디서 잡았느냐가 timeout의 의미를 정한다.
- Request는 나갔는데 reply가 없다 → downstream 문제.
- Request가 server에서 나가지도 않았다 → driver, OS routing table, local firewall, NIC.
- PLC는 reply했는데 HMI가 못 봤다 → VLAN, ACL, NAT, duplicate IP, asymmetric route.
- 양쪽 다 깨끗하다 → 선이 아니라 application을 본다.
| 증상 | 먼저 잡을 위치 | 비교할 위치 |
|---|---|---|
| 특정 HMI client만 느림 | HMI client NIC | SCADA server NIC |
| 모든 client가 한 PLC만 잃음 | SCADA server / driver NIC | PLC switch mirror port |
| OPC UA가 몇 분마다 재연결 | Client와 server NIC 양쪽 | Firewall session table |
| Exception인지 timeout인지 불명확 | Gateway 또는 PLC 쪽 | SCADA driver 쪽 |
| 원격 site만 실패 | WAN/VPN 양 끝 | Router와 firewall log |
Firewall이나 무선 구간 양쪽에서 시간 맞춰 잡은 두 파일이, "당연해 보이는" 한쪽에서 잡은 한 파일보다 훨씬 값어치가 있다. 두 장비를 같은 NTP source에 맞추고, 시작할 때 구간을 가로질러 ping을 한 번 쳐서 공통 표식을 남긴다. 그래도 시계가 어긋나면 editcap -t -0.412 a.pcap a-shift.pcap으로 맞춰 놓고 비교한다.
SPAN port는 과부하가 걸리면 거짓말을 한다
Gigabit access port의 양방향을 gigabit monitor port 하나로 미러링하면 switch는 최대 2 Gbps를 1 Gbps에 밀어 넣어야 한다. 넘치는 건 조용히 버린다. 그리고 그 drop은 Wireshark에서 네트워크 packet loss와 똑같이 생긴 구멍으로 보인다. 자기네 SPAN session 안에서만 존재하는 "loss 문제"를 며칠 쫓는 팀을 본 적이 있다.
두 가지로 막는다. 링크가 바쁘면 한 방향씩 미러링하고, 파일을 믿기 전에 switch의 monitor session drop counter를 확인한다. 10 ms 이하 request/response, PROFINET, motion처럼 타이밍이 결론을 좌우하는 곳에서는 passive TAP을 쓴다. SPAN은 순서와 시각을 흐트러뜨리지만 TAP은 그렇지 않다.
첫 패스는 field가 아니라 timing과 방향
Protocol field부터 해석하지 않는다. 누가 보냈고, 누가 답했고, 얼마나 걸렸는지부터 본다.
- Client request가 기대한 poll 주기로 나가고 있는가, 아니면 client가 먼저 조용해졌는가.
- 모든 request에 답이 오는가.
- Application timeout 이전에 TCP retransmission이 쌓이는가, 아니면 깨끗한 흐름에서 갑자기 timeout이 나는가.
- 특정 packet size나 특정 명령 뒤에 reset이 붙는가.
- ARP request가 반복되며 target MAC을 못 찾는가.
- 고정 IP를 봐야 하는 application이 DNS나 NTP 조회에서 멈춰 있는가.
- NAT, VPN, 두 번째 NIC 때문에 source IP가 바뀌었는가.
Wireshark에서는 첫 훑기에 tcp.analysis.flags를 걸고, Statistics → Conversations를 duration으로 정렬하면 보통 문제 지점 근처 몇 packet 안으로 들어간다. Client가 스스로 송신을 멈췄다면 네트워크는 그만 본다. 네트워크 옷을 입은 SCADA server 문제다.
Modbus TCP: exception과 timeout은 다르다
보고서에서 늘 뭉뚱그려지는데, 조치 방향은 정반대다.
Exception response는 slave가 요청을 받고, 이해하고, 거절했다는 뜻이다. 가장 자주 보이는 exception 02(Illegal Data Address)는 열에 아홉이 40001 offset 문제다. 장비는 offset 1034를 원하는데 누군가 holding register 41035로 설정해 둔 것이다. 이건 register map 수정이지 네트워크 티켓이 아니다.
Timeout은 request, response, session path 중 어딘가가 실패했다는 뜻이다. 완전히 다른 티켓이다.
mbtcp로 필터하고 MBAP transaction identifier를 확인한다. Request와 response를 짝지어 주는 값이고, 모든 요청에 transaction id 0만 재사용하는 gateway라면 그 gateway의 queue 처리를 더는 믿지 않는 게 맞다. Unit identifier도 확인한다. Modbus Messaging on TCP/IP Implementation Guide는 IP로 직접 접근하는 장비는 unit id 255로 지정하라고 하지만, 실제로는 0이나 1에도 답하는 gateway와 PLC가 많다. Driver에 잘못 넣으면 죽은 링크처럼 보이는 침묵이 나온다.
OPC UA: HMI에서는 똑같아 보이는 세 가지 실패
HMI는 셋 다 "disconnected"라고 쓴다. 그런데 wire에서는(port 4840, Wireshark opcua) 명확히 구분되고, IEC 62541-6이 순서를 정해 두고 있다.
- HEL / ACK — transport handshake. HEL만 있고 ACK가 없으면 certificate 문제가 아니라 TCP나 firewall 문제다. HEL의 EndpointUrl과 server가 돌려주는 endpoint도 읽어 본다. Server가 client는 해석할 수 없는 자기 내부 hostname을 광고하는 경우가 꾸준히 있고, DNS나 hosts 파일 한 줄로 끝난다.
- OPN / OpenSecureChannel — security policy와 certificate. Certificate 거부는 여기서 죽는다. Session은 아직 만들어지지도 않았다. 양쪽 trust store를 다 본다. 한쪽만 거부하는 경우가 많다.
- CreateSession / ActivateSession / Publish — application 계층. Publish 응답이 느리거나 굶는 건 server 부하나 subscription 설정 문제이고, 위 두 단계와는 상관이 없다.
Secure channel 실패를 "subscription이 느리다"로 잘못 잡으면, 만료된 certificate 하나 때문에 publishing interval을 일주일 동안 만지게 된다.
반복해서 나오는 패턴
Timeout 직전마다 retransmission이 쌓인다
오래된 동선이면 duplex mismatch부터 본다. Half-duplex 쪽에 late collision과 FCS error가 찍히고, 큰 frame이 작은 frame보다 심하게 당한다. 그래서 증상이 "큰 읽기만 실패한다"처럼 보이곤 한다. 그다음이 무선 품질, firewall deep inspection, switch queue drop이다.
SCADA timeout을 늘리는 걸 첫 조치로 하지 않는다. 증상만 덮고, 이미 틀린 데이터를 운전원이 더 오래 기다리게 된다.
Duplicate IP
한 주소에 서로 다른 MAC 두 개가 ARP 응답을 보낸다. 증상이 랜덤해 보이는 건 원리상 당연하다. HMI가 PLC와 통신하다가, 다음에는 spare 컨트롤러나 협력사 노트북과 통신하고, 다시 PLC로 돌아온다. Driver 설정을 건드리기 전에 IP 관리와 DHCP 제외 범위를 고친다.
Idle 뒤 reset
정상 통신, 긴 무통신 구간, 그다음 reset 또는 session 재사용 실패. Firewall과 NAT 장비는 보통 한 시간 이하에서 idle TCP session을 정리한다. 반면 Windows는 KeepAliveTime이 지나기 전에는 첫 keepalive를 보내지 않고, 기본값이 7,200,000 ms — 두 시간이다. 그때쯤이면 session은 이미 없다. SCADA host의 keepalive를 줄이거나, firewall idle timeout을 늘리거나, driver가 깨끗하게 reconnect하도록 한다. 하나를 고르고, 무엇을 골랐는지 적어 둔다.
Broadcast와 multicast 소음
오래된 PLC, panel HMI, embedded gateway는 CPU가 작고 트래픽 제어 기능이 없다. IGMP querier가 없는 VLAN은 multicast를 모든 port로 flooding하고, capture를 보면 그 장비가 볼 이유가 없는 스트림을 받고 있다. VLAN 경계, IGMP snooping, unmanaged switch 위치 문제이지 application 문제가 아니다.
Asymmetric route
Request는 도착하는데 reply가 다른 경로로 빠진다. 양쪽 capture를 붙여야만 빠진 절반이 보인다. 두 번째 NIC 추가, VPN, 임시 engineering laptop route, firewall 교체 직후라면 여기부터 본다.
공장에서 뜬 pcap은 화면 캡처가 아니라 증거다
Capture에는 IP, hostname, tag 이름, 계정명이 들어가고 살아 있는 공정 값이나 recipe 데이터까지 들어간다. IEC 62443-2-4는 service provider가 고객 site 데이터를 다루는 요구사항을 규정하는데, pcap은 정확히 그 데이터에 해당한다.
Production site에서 뜨기 전에 정한다. 어느 interface, 어느 시간 창인지. 사무망이나 인터넷 트래픽을 뺄지. 어느 통제된 폴더에 둘지. Payload에 공정 값이나 recipe가 포함되는지. 임시 노트북에서 언제 지울지. 원본은 손대지 말고 복사본으로 분석한다.
Vendor support에 보낼 때는 장애와 그 앞뒤 맥락이 들어간 가장 작은 파일을 보낸다. 장비 IP, 기대 동작, 실제 증상, 이벤트의 현장 시각을 짧은 메모로 붙인다. 그 메모가 메일 왕복 세 번을 줄여 준다.
결론은 packet 사실로 쓴다
분석은 조치 목록을 바꿔야 의미가 있다. "네트워크 문제" 대신 다른 엔지니어가 검증할 수 있는 문장을 쓴다.
PLC는 8 ms에 응답, firewall outside interface에는 response 없음→ firewall과 route 작업.Modbus slave가 41035에 exception 02 반환→ register map 수정.OPC UA가 OPN 단계에서 certificate 거부 후 connection reset→ 양쪽 trust store 확인.Server CPU 포화 중 14초간 client request 송신 없음→ SCADA server 성능 확인.
그다음엔 capture가 볼 수 없는 것을 본다. 양쪽 파일이 모두 깨끗하고, loss도 reset도 없고, 응답이 10 ms 안에 온다면 선은 멀쩡하고 문제는 그 위에 있다. Driver thread 기아, 막힌 poll queue, 특정 recipe에서만 늘어지는 PLC scan 같은 것들이다. 다음은 거기고, 도구도 달라진다.