MCPcopy
hub / github.com/Runnin4ik/dpi-detector / classify_connect_error

Function classify_connect_error

utils/error_classifier.py:118–202  ·  view source on GitHub ↗

Единая классификация ошибок установки соединения (L3/L4/DNS).

(error: Exception, bytes_read: int, stage: str = "unknown")

Source from the content-addressed store, hash-verified

116
117
118def classify_connect_error(error: Exception, bytes_read: int, stage: str = "unknown") -> Tuple[str, str, int]:
119 """Единая классификация ошибок установки соединения (L3/L4/DNS)."""
120 full_text = collect_error_text(error)
121 err_errno = get_errno_from_chain(error)
122
123 if isinstance(error, httpx.PoolTimeout) or "pool timeout" in full_text:
124 return ("[magenta]POOL TIMEOUT[/magenta]", "Нехватка сокетов, снизьте параллелизм", bytes_read)
125
126 if isinstance(error, httpx.ConnectTimeout) or "connect timeout" in full_text or "timed out" in full_text:
127 if stage == "tls_handshake":
128 return ("[bold red]TLS DROP[/bold red]", "TLS Handshake timeout", bytes_read)
129 elif stage == "tcp_connect":
130 return ("[bold red]SYN DROP[/bold red]", "TCP SYN timeout", bytes_read)
131 elif stage == "sending_data":
132 return ("[red]SEND TIMEOUT[/red]", "Таймаут отправки данных", bytes_read)
133 elif stage == "reading_data":
134 return ("[red]READ TIMEOUT[/red]", "Таймаут чтения данных", bytes_read)
135 else:
136 return ("[red]TIMEOUT[/red]", f"Timeout ({stage})", bytes_read)
137
138 # DNS
139 gai = find_cause(error, socket.gaierror)
140 if gai is not None:
141 gai_errno = getattr(gai, 'errno', None)
142 if gai_errno in (socket.EAI_NONAME, 11001):
143 return ("[yellow]DNS FAIL[/yellow]", "Домен не найден", bytes_read)
144 elif gai_errno in (getattr(socket, 'EAI_AGAIN', -3), 11002):
145 if "connection" in full_text and any(x in full_text for x in ("reset", "refused", "closed")):
146 return ("[yellow]DNS FAIL[/yellow]", "DNS ошибка/дроп", bytes_read)
147 return ("[yellow]DNS FAIL[/yellow]", "DNS таймаут/недоступен", bytes_read)
148 else:
149 return ("[yellow]DNS FAIL[/yellow]", "Ошибка DNS", bytes_read)
150
151 if any(x in full_text for x in [
152 "getaddrinfo failed", "name resolution", "11001", "11002",
153 "name or service not known", "nodename nor servname"
154 ]):
155 return ("[yellow]DNS FAIL[/yellow]", "Ошибка DNS", bytes_read)
156
157 # TLS ALERT внутри ConnectError (DPI)
158 if "sslv3_alert" in full_text or "ssl alert" in full_text or ("alert" in full_text and "handshake" in full_text):
159 if "handshake_failure" in full_text or "handshake failure" in full_text:
160 return ("[bold red]TLS ALERT[/bold red]", "Handshake alert", bytes_read)
161 elif "unrecognized_name" in full_text:
162 return ("[bold red]TLS ALERT[/bold red]", "SNI alert", bytes_read)
163 elif "protocol_version" in full_text or "alert_protocol_version" in full_text:
164 return ("[bold red]TLS ALERT[/bold red]", "Version alert", bytes_read)
165 else:
166 return ("[bold red]TLS ALERT[/bold red]", "TLS alert", bytes_read)
167
168 ssl_err = find_cause(error, ssl.SSLError)
169 if ssl_err is not None:
170 return classify_ssl_error(ssl_err, bytes_read)
171
172 # TCP ОШИБКИ (L4)
173 if find_cause(error, ConnectionRefusedError) is not None or err_errno in (errno.ECONNREFUSED, config.WSAECONNREFUSED) or "refused" in full_text:
174 return ("[bold red]REFUSED[/bold red]", "TCP соединение отклонено", bytes_read)
175

Callers 3

_fat_probe_keepaliveFunction · 0.90
_check_tls_singleFunction · 0.90
check_http_injectionFunction · 0.90

Calls 5

collect_error_textFunction · 0.85
get_errno_from_chainFunction · 0.85
find_causeFunction · 0.85
classify_ssl_errorFunction · 0.85
clean_detailFunction · 0.85

Tested by

no test coverage detected