Компьютерные сети: от IPC к C/Winsock
Network incident: доказать первую сломанную границу
Практический evidence ladder для Windows: baseline, DNS, route, neighbor, TCP, TLS, HTTP и server correlation без разрушения исходного состояния.
Network incident: доказать первую сломанную границу
Тикет «сеть не работает» почти ничего не сообщает. У одного пользователя имя
не разрешается, у другого TCP получает reset, у третьего certificate не подходит
hostname, а четвёртому gateway возвращает HTTP 503. Симптом похож только на
уровне фразы. Инженерная задача — назвать последнюю доказанно успешную и первую
доказанно неуспешную boundary.
Задача
Процесс A на Windows должен отправить 12 UTF-8 bytes Привет по адресу
https://server.example/hello, но client сообщает timeout. Incident
воспроизводится сейчас. До restart, DNS flush, firewall change или увеличения
timeout нужно сохранить исходное состояние.
Минимальная карточка воспроизведения выглядит так:
time_utc = 2026-08-25T15:20:31.412Z
source_host = STUDENT-17
process = hello-client.exe 1.4.2
target = https://server.example/hello
expected = HTTP 200 and echoed UTF-8 payload
observed = timeout after 3.0 s
request_id = lab-17-0042
Без timestamp и source host capture нельзя надёжно сопоставить с server logs.
Без точного target нельзя отличить wrong hostname, port или path. Без expected
outcome даже 200 может оказаться ответом не того component.
Client capture с исходящим SYN доказывает, что SYN дошёл до этой точки Windows stack. Он не доказывает, что packet покинул physical NIC, прошёл firewall, достиг server или был принят listening socket. Отсутствие SYN-ACK там же означает только отсутствие наблюдаемого response до deadline. Сильнее становится согласованная пара: client capture + server capture + device counters + socket state, привязанные ко времени и одному flow.
Evidence ladder вместо списка случайных команд
Идите снизу вверх только настолько, насколько требует первая неопределённость. Каждый шаг отвечает на один вопрос и сохраняет output.
- Application reproduction. Повторите один controlled request с известным request ID. Зафиксируйте command, version, start/end time и полный error code.
- Name resolution. Сохраните A/AAAA answers, resolver и TTL. Затем запишите, какой numeric candidate реально выбрал client.
- Local path. Зафиксируйте route и next-hop neighbor для выбранного address. Expected DNS answer бесполезен, если у host нет usable route.
- TCP. Сопоставьте
connectresult, local/remote endpoint, socket state и SYN sequence в capture. RST, timeout и local no-route — разные outcomes. - TLS. Только после TCP success сохраняйте TLS version, ALPN, alert и certificate identity result. Не отключайте validation ради «проверки».
- HTTP/application. Сохраните status, response fields, latency и request ID. Затем найдите тот же ID в edge/origin logs.
Лестница не требует всегда выполнять все шаги. Если getaddrinfo вернул
WSAHOST_NOT_FOUND, capture TCP пока не нужен: конкретный endpoint ещё не
выбран. Если пришёл HTTP 503, спор о том, «ходит ли TCP», уже закрыт для этой
attempt; следующий вопрос — какой HTTP-speaking component ответил и почему.
Безопасный Windows baseline
Следующие команды читают состояние и подходят для первого snapshot:
Get-Date -Format o
Resolve-DnsName server.example -Type A
Resolve-DnsName server.example -Type AAAA
Test-NetConnection server.example -Port 443 -InformationLevel Detailed
Get-NetRoute -AddressFamily IPv4 | Sort-Object RouteMetric
Get-NetNeighbor -AddressFamily IPv4
Get-NetTCPConnection | Where-Object RemotePort -eq 443
pktmon status
pktmon filter list
Сохраняйте raw output как artifact, а в report цитируйте только относящиеся к
flow строки. DNS command и TCP probe могут выбрать разные address candidates;
поэтому RemoteAddress — обязательное поле evidence. Route и neighbor snapshot
быстро устаревают, так что timestamp важнее красивого скриншота.
Не начинайте с ipconfig /flushdns, удаления neighbor entries, restart service
или отключения firewall. Эти действия меняют наблюдаемую систему. Если change
нужен как experiment, сначала сохраните baseline, сформулируйте prediction,
измените одну переменную и предусмотрите rollback.
Packet capture только в разрешённой lab-среде
На disposable instructor VM можно снять короткий capture встроенным Pktmon. Сначала убедитесь, что чужая session не активна. Не очищайте и не заменяйте существующие global filters на shared host:
pktmon status
pktmon filter list
pktmon start --capture --comp nics --pkt-size 0 --file-name C:\Temp\incident.etl
# reproduce exactly one controlled request
pktmon stop
pktmon etl2pcap C:\Temp\incident.etl --out C:\Temp\incident.pcapng
Этот пример намеренно не выполняет global filter reset. Если pktmon status
показывает активный чужой сбор, остановитесь и согласуйте отдельную VM или иной
observation point. Capture может содержать sensitive traffic: используйте
controlled payload, ограничьте доступ к artifact и удалите его по правилам
лаборатории после grading.
C/Winsock checkpoint
Application log должен сохранить Winsock error до любого cleanup call, который может изменить diagnostic context:
int rc = connect(s, peer->ai_addr, (int)peer->ai_addrlen);
if (rc == SOCKET_ERROR) {
int connect_error = WSAGetLastError();
log_connect_failure(peer, connect_error, started_at, finished_at);
closesocket(s);
s = INVALID_SOCKET;
}
Для nonblocking connect готовность socket к записи ещё не равна success.
После select/WSAPoll проверьте socket-specific SO_ERROR:
int socket_error = 0;
int option_length = sizeof(socket_error);
if (getsockopt(
s,
SOL_SOCKET,
SO_ERROR,
(char *)&socket_error,
&option_length
) == SOCKET_ERROR) {
int inspection_error = WSAGetLastError();
fail_wsa("getsockopt(SO_ERROR)", inspection_error);
}
if (socket_error != 0) {
fail_connect(socket_error);
}
SO_ERROR — per-socket result; WSAGetLastError() — last error текущего thread.
Не логируйте последний после серии unrelated calls и не называйте его error
исходного connect.
После success сохраните numeric local/remote endpoints через getsockname и
getpeername. Это связывает application event с capture 5-tuple. Для каждого
request логируйте protocol phase (resolve, connect, tls, http), duration
и correlation ID. Не пишите certificate private material, authorization fields
или весь payload.
Что доказывает каждое наблюдение
| Evidence | Сильный вывод | Нельзя утверждать |
|---|---|---|
| A/AAAA answer | resolver вернул records | выбран route и открыт port |
| route к candidate | local stack выбрал next hop/interface | neighbor и remote path работают |
| SYN в client capture | SYN наблюдался в client point | server получил SYN |
| SYN и SYN-ACK в client capture | response вернулся к client point | application приняло connection |
connect == 0 | TCP connection установлена для socket | TLS identity и HTTP healthy |
| TLS validation success | защищённый peer identity принят | /hello отработает |
HTTP 503 + fields | ответил HTTP component | виноват DNS или именно origin |
| matching server request ID | конкретный handler/log связан с attempt | response дошёл обратно без client evidence |
Слово «timeout» всегда дополняйте phase и deadline. DNS timeout, TCP connect timeout, TLS handshake timeout и HTTP response timeout имеют одинаковую форму для пользователя, но разные owners и наборы уже доказанных boundaries.
Предсказание → experiment → evidence
Разберите controlled case: client capture содержит три исходящих SYN с увеличивающимися интервалами, но ни одного SYN-ACK; server capture на expected interface не содержит этого flow.
До следующего действия запишите две hypotheses:
- packet теряется между client observation point и server observation point;
- client использовал не тот numeric candidate/interface, поэтому server capture смотрит другую границу.
Experiment должен различать их, а не «на всякий случай» менять firewall. Сопоставьте DNS candidate, client 5-tuple, selected route/interface и capture filter на server. Если tuple и boundaries совпали, добавьте counters на ближайших devices. Если не совпали, исправьте observation point и повторите один request.
Evidence package для Lab 08:
timeline.md # UTC events and predictions
client-command.txt # exact command/version/outcome
dns-route-neighbor.txt # read-only snapshots
client-socket.log # phase, endpoints, error, request ID
client-capture.pcapng # controlled flow, if authorized
server-capture.pcapng # same tuple/time window, if available
handoff.md # last good boundary, first bad boundary, owner, next test
Report отделяет observed facts от inference. «SYN не виден на server capture» — fact при указанной interface/filter/time. «Потерял firewall» — hypothesis, пока нет counter/log на firewall boundary.
Частая ошибка: restart выдают за root cause
После restart service мог восстановиться, потому что очистился backlog, пересоздался listener, обновился certificate cache или просто исчезла нагрузка. Сам факт восстановления не выбирает одну причину. Если baseline не снят, первоначальное socket state и logs потеряны.
Вторая ошибка — считать packet capture абсолютной истиной. Capture честен о своей точке, времени, interface и capture policy. Он может не видеть traffic другого interface, offload presentation или packets вне filter. Всегда подписывайте observation boundary.
Итого и мост к capstone
- Диагноз — это последняя успешная и первая неуспешная boundary, а не слово «network».
- Application logs, socket state и captures отвечают на разные вопросы; request ID и 5-tuple связывают их в одну attempt.
- Baseline снимается до restart/flush/policy change. Fact отделяется от inference.
- Pktmon работает только в разрешённой lab-среде без разрушения чужих global filters и с аккуратным обращением с capture artifacts.
В финальной главе вы сами создадите protocol, у которого каждая boundary проверяема: fixed header, bounded payload, CRC, request ID, EOF semantics и conformance harness. ByteBox/1 заставит превратить всю доказательную дисциплину курса в observable wire behavior.