Как проверить прокси: команды, браузер и разбор ответов
Прокси работает, если он принимает соединение на своём порту, пропускает запрос дальше и возвращает ответ целевой площадки. Второе условие: внешний адрес, который видит эта площадка, отличается от адреса машины, с которой запрос ушёл. Оба условия закрывает одна команда curl, и с неё удобно начинать любую проверку.
Дальше начинаются частности. Порт отвечает, сервис за ним молчит. Сервис отвечает, площадка возвращает отказ. Имя домена разрешается на локальной машине, хотя сам запрос идёт через туннель. Снаружи все три случая выглядят одинаково: «не работает». Ниже разобран каждый уровень по отдельности, с командами, выводом и таблицей исходов.
Что значит «прокси работает»
В обращениях формулировка «прокси не работает» покрывает четыре разных состояния. У одного пользователя «у меня всё висит на подключении», у второго «мой внешний адрес остался прежним», третий пишет «мне возвращается 407», четвёртый сообщает «я вижу капчу на каждой странице». Поломки тут разные, и порядок проверки для них тоже разный.
Проверка распадается на четыре независимых уровня, каждый следующий проверяется после предыдущего:
- Доступность порта. TCP-соединение до пары IP:PORT устанавливается, ответ приходит от сетевого стека.
- Ответ сервиса. Посредник принял запрос и ответил по своему протоколу: HTTP-туннель через метод CONNECT либо рукопожатие SOCKS.
- Ответ целевой площадки. Сайт вернул содержимое, код ответа пришёл от самого сайта.
- Разрешение имён. Домен превращается в адрес на стороне посредника, внутри туннеля.
Разделение выглядит формальным ровно до первого разбора. Когда порт закрыт, вы получаете отказ за миллисекунды и никакого HTTP-обмена не видите вовсе. Когда порт открыт, но авторизация не принята, обмен начинается и обрывается на 407. Когда всё принято, но площадка отдаёт капчу, канал полностью рабочий, а вопрос переезжает в область поведения запросов. Три ситуации требуют трёх разных действий, поэтому первый шаг любой диагностики: понять, на каком уровне обрыв.
| Уровень | Что подтверждает | Чем проверяется |
|---|---|---|
| Порт | TCP до IP:PORT открыт | nc -vz, Test-NetConnection |
| Сервис | посредник принял запрос | curl -v, строка 200 Connection established |
| Площадка | сайт отдал содержимое | код ответа сайта в %{http_code} |
| Имена | домен разрешается в туннеле | сравнение socks5h и socks5 |
| Выходной адрес | трафик идёт через пул | эхо-сервис плюс сверка с прямым запросом |
| Стабильность | серия держится ровно | цикл из 20 запросов, подсчёт исходов |
Пул на стороне сервиса держится в районе 12 000 активных адресов, список обновляется в режиме реального времени. Ротация идёт автоматически внутри пула, поэтому два соседних запроса штатно уходят с разных выходов. Именно так работают анонимные прокси с подменой адреса, и это стоит держать в голове: смена выходного адреса между запросами это признак исправной работы.
Проверка одной командой curl
Одна строка закрывает сразу три уровня: порт, сервис и ответ площадки.
curl -sS -o /dev/null -m 15 \
-w 'code=%{http_code} time=%{time_total}\n' \
-x http://203.0.113.10:8000 https://api.ipify.org
echo "exit=$?"
Ключ -x задаёт посредника, -m 15 ограничивает общее время, -o /dev/null выбрасывает тело ответа, -w печатает только то, что нужно для разбора. Строка code=200 time=0.412 и exit=0 означают полный успех: соединение установлено, туннель поднят, сайт ответил. Любой другой исход разбирается по коду завершения curl, они собраны в таблице ниже.
Формат доступа зависит от того, как выдан список. При доступе по привязанному адресу строка короткая, логин и пароль не нужны. При формате IP:PORT:LOGIN:PASS учётные данные подставляются в ключ -x либо выносятся отдельно.
# доступ по привязанному адресу, формат списка IP:PORT
curl -x http://203.0.113.10:8000 https://api.ipify.org
# формат списка IP:PORT:LOGIN:PASS
curl -x http://u38471:[email protected]:8000 https://api.ipify.org
# то же самое, если в пароле есть служебные символы
curl -x http://203.0.113.10:8000 --proxy-user 'u38471:s7kq2mfa' https://api.ipify.org
Когда короткая команда возвращает ошибку, включается подробный режим. Ключ -v печатает обмен построчно, и по нему видно, на каком шаге всё остановилось.
curl -v -o /dev/null -m 15 -x http://203.0.113.10:8000 https://api.ipify.org
* Trying 203.0.113.10:8000...
* Connected to 203.0.113.10 (203.0.113.10) port 8000
* CONNECT tunnel: HTTP/1.1 negotiated
> CONNECT api.ipify.org:443 HTTP/1.1
> Host: api.ipify.org:443
> Proxy-Connection: Keep-Alive
< HTTP/1.1 200 Connection established
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
> GET /?format=text HTTP/2
< HTTP/2 200
Читается вывод сверху вниз. Строка Trying означает, что curl начал устанавливать TCP-соединение. Connected to подтверждает открытый порт. Дальше идёт запрос CONNECT, и ответ 200 Connection established подтверждает, что посредник согласился поднять туннель к запрошенному хосту. Следом видно согласование TLS, и только после него появляется код самой площадки. Обрыв на любой из этих строк указывает точный уровень поломки, и дальше уже не приходится гадать.
Проверять полезно сразу два адреса назначения: один по http, второй по https. Обычный запрос уходит через посредника целиком, вместе с полным путём в стартовой строке, и посредник видит и путь, и заголовки. Запрос по https идёт внутри туннеля, поднятого методом CONNECT, и посреднику достаётся только имя хоста с портом. Схемы обрабатываются разным кодом, поэтому исход у них расходится: бывает так, что простой запрос проходит, зашифрованный обрывается на согласовании TLS.
curl -sS -o /dev/null -w 'http=%{http_code}\n' -x http://203.0.113.10:8000 http://example.com
curl -sS -o /dev/null -w 'https=%{http_code}\n' -x http://203.0.113.10:8000 https://example.com
Что показывает браузер и на что смотреть
Браузер удобен для быстрой проверки и почти бесполезен для точной. Он скрывает половину обмена, зато сразу показывает картину глазами обычного посетителя. Порядок такой: внести адрес и порт в настройки, открыть эхо-страницу, посмотреть отданный адрес, затем открыть инструменты разработчика и проверить вкладку «Сеть».
В карточке любого запроса есть поле Remote Address. Через посредника там стоит адрес и порт самого посредника. Адрес сайта появляется в этом поле только при прямом соединении. Это самая надёжная проверка внутри браузера: поле заполняется сетевым слоем и не подделывается содержимым страницы. Рядом полезно глянуть заголовки ответа и статус.
Отдельный срез даёт профиль антидетект-браузера. Настройки посредника там живут внутри профиля, системные параметры на него не влияют, поэтому проверка идёт изнутри самого профиля: открыть эхо-страницу в его окне и сверить отданный адрес. Заодно проверьте, отключён ли WebRTC: он умеет отдавать адреса сетевых интерфейсов в обход посредника, и внешне это выглядит как рабочая связка с утечкой. Вся проверка занимает секунды.
Chrome и браузеры на его основе берут системные настройки, поэтому для отдельной проверки удобно запускать сеанс с ключом.
chrome --proxy-server="http://203.0.113.10:8000" --user-data-dir=/tmp/proxytest
Firefox держит собственные настройки в разделе сетевых параметров, и там же стоит галочка «Проксировать DNS при использовании SOCKS 5». Без неё имена разрешаются на локальной машине, и запрос к домену уходит мимо туннеля, хотя само соединение идёт через посредника.
Типичное сообщение из обращений: «мой адрес не поменялся, хотя настройки я внёс». Причин две. Первая: настройки внесены в профиль браузера, а проверка идёт через расширение со своими правилами. Вторая: страница отдана из кэша. Обе снимаются приватным окном и жёсткой перезагрузкой. Ошибки вида ERR_PROXY_CONNECTION_FAILED и ERR_TUNNEL_CONNECTION_FAILED говорят о том, что до посредника достучаться не вышло. Всплывающее окно с запросом логина и пароля означает 407 и разбирается отдельно.
Выходной адрес и сверка с прямым запросом
Ответ эхо-сервиса сам по себе ничего не доказывает. Смысл появляется при сравнении двух значений: адрес при прямом запросе и адрес через посредника.
direct=$(curl -s -m 10 https://api.ipify.org)
tunnel=$(curl -s -m 15 -x http://203.0.113.10:8000 https://api.ipify.org)
printf 'прямой=%s через посредника=%s\n' "$direct" "$tunnel"
Значения различаются, значит трафик идёт через пул. Значения совпали, значит клиент проигнорировал настройки и ушёл напрямую. Второй случай встречается чаще, чем кажется: программа читает переменные окружения, системный профиль или собственный конфиг, и приоритет у них может быть выше, чем у ключа в командной строке.
Формулировка «у меня в браузере одно, а в скрипте другое» сводится ровно к этому расхождению. Браузер и скрипт читают разные источники настроек, поэтому сверять надо каждый инструмент отдельно, своей командой, со своей проверкой выходного адреса.
Полезно снимать адрес с двух независимых эхо-сервисов. Один может отдавать кэшированный ответ, второй показывает свежий, и расхождение между ними сразу видно. Проверять географию выхода смысла мало: пул собран как микс со всего мира, адреса приходят из множества стран, выборка по отдельной стране не делается. Разные страны в соседних запросах это штатное поведение нашего пакета анонимных прокси.
Проверка доступности порта отдельно
Когда curl падает мгновенно, стоит отделить сетевой уровень от прикладного. Проверка порта отвечает на один вопрос: доходит ли пакет вообще.
nc -vz -w 5 203.0.113.10 8000
Test-NetConnection 203.0.113.10 -Port 8000 -InformationLevel Detailed
Исходов ровно три, и они читаются по-разному. succeeded означает, что порт открыт и слушается. Мгновенный connection refused означает, что машина на месте, но на порту никто не отвечает: чаще всего в строке перепутан порт. Тишина до истечения таймаута означает, что пакет отбрасывается молча, и вот это самый частый случай при доступе по привязке.
Логика простая. При доступе по привязанному адресу сервис принимает соединения только с известных ему адресов, остальные отбрасываются без ответа. В пакет входит две привязки, менять их можно свободно в настройках кабинета. Если провайдер выдал новый адрес, старая привязка перестаёт совпадать, и снаружи это выглядит как полностью мёртвый порт. Отсюда правило: перед разбором сети сначала сверьте привязанный адрес с текущим внешним адресом машины.
Ещё одна деталь про потоки. При двух привязанных адресах общий лимит потоков делится пополам, а пакеты по потокам не складываются. Обычные пакеты дают до 1000 потоков, корпоративный до 3000. Когда проверка идёт с двух машин одновременно, каждая работает со своей половиной лимита, и это нормальная работа приватного доступа к пулу адресов.
Разрешение имён внутри туннеля
Отдельный уровень, о котором вспоминают последним. Домен нужно превратить в адрес, и сделать это может либо ваша машина, либо посредник. Для HTTP-посредника вопрос закрыт по устройству протокола: метод CONNECT передаёт имя хоста, разрешает его удалённая сторона. Для SOCKS всё зависит от схемы в строке подключения.
# имя разрешает посредник, запрос к DNS уходит внутри туннеля
curl -s -m 15 -x socks5h://203.0.113.10:1080 https://api.ipify.org; echo " exit=$?"
# имя разрешает локальная машина, наружу уходит только адрес
curl -s -m 15 -x socks5://203.0.113.10:1080 https://api.ipify.org; echo " exit=$?"
Буква h в схеме socks5h переключает разрешение имён на удалённую сторону. Разница видна сразу: если первая команда отвечает, а вторая падает с кодом 6, локальный резолвер до домена не добирается. Обратная картина тоже показательна. Когда обе команды работают одинаково, проверьте, куда уходят запросы к DNS, потому что при схеме без h они идут через провайдера и видны ему целиком.
Тот же переключатель есть почти везде. В curl это схема, в Python-библиотеке requests это socks5h:// в словаре прокси, в Firefox это галочка про DNS, в антидетект-браузерах отдельный пункт настроек профиля. Протокол SOCKS4 имён не передаёт вовсе, расширение SOCKS4a передаёт, поэтому для задач с доменами берут пакет с протоколом SOCKS5: он умеет и имена, и авторизацию, и работу с UDP.
Проверить утечку можно и по косвенному признаку. Поднимите запрос к домену, которого нет в кэше локального резолвера, и посмотрите время первого ответа. При разрешении внутри туннеля задержка складывается с временем хода до посредника, при локальном разрешении она заметно короче. Способ грубый, но для быстрой проверки годится.
Серия запросов вместо одного
Один успешный запрос доказывает, что связка настроена. Он ничего не говорит о том, выдержит ли она прогон. Ротация внутри пула означает, что следующий запрос уйдёт с другого выхода, и поведение серии отличается от поведения одиночного обращения.
for i in $(seq 1 20); do
curl -s -o /dev/null -m 15 -w '%{http_code}\n' \
-x http://203.0.113.10:8000 https://api.ipify.org
done | sort | uniq -c | sort -rn
Вывод вида 18 200 и 2 000 читается однозначно: восемнадцать ответов с кодом 200 и два обрыва, где кода нет вовсе. Доля успешных ответов и есть тот показатель, по которому связку допускают к работе. Разброс времени снимается тем же циклом с ключом %{time_total}, и по нему видно, ровный канал или пилообразный.
Вторая часть серии: собрать выходные адреса и посмотреть, сколько их набралось.
for i in $(seq 1 20); do
curl -s -m 15 -x http://203.0.113.10:8000 https://api.ipify.org
echo
done | sort | uniq -c | sort -rn
Сообщение «у меня половина запросов проходит, половина висит» почти всегда объясняется темпом. Площадка считает обращения по своим правилам, и при частоте выше её порога включается ограничение. Пауза между запросами, снижение параллельности и распределение по разным выходам снимают картину за пару минут. Ровные серии на длинной дистанции держат серверные адреса на собственном оборудовании: канал у них предсказуемый, темп ответа держится одинаковым от первого запроса до последнего.
Есть и третий срез, про который забывают: проверка изнутри рабочего сценария. Прогон curl из терминала и прогон боевого скрипта это разные наборы заголовков, таймаутов и повторов. Если серия из терминала ровная, а рабочий инструмент сыплет ошибками, дело в его настройках, и разбирать надо их.
Разбор ответов: что означает каждый исход
Дальше самое полезное. Формулировка «я не понимаю, чей это отказ» снимается таблицей: по одному видимому признаку определяется источник проблемы и следующее действие.
| Что видно | Источник | Что это означает | Что делать |
|---|---|---|---|
Connection refused, ответ мгновенный | сеть | на порту никто не слушает, чаще перепутан порт | сверить строку подключения по полям |
| Тишина до таймаута | сеть | пакет отбрасывается, привязанный адрес не совпадает | сверить привязку с текущим внешним адресом |
HTTP/1.1 407 | посредник | логин и пароль не приняты либо доступ идёт по привязке | проверить формат IP:PORT:LOGIN:PASS |
CONNECT tunnel failed, response 502 | посредник | запрос принят, до площадки соединение не дошло | повторить, взять другую строку из списка |
200 Connection established, дальше тишина | площадка | туннель поднят, ответа от сайта нет | поднять таймаут, повторить запрос |
| Код 200, адрес совпал с прямым | клиент | запрос ушёл мимо посредника | проверить конфиг и переменные окружения |
| Код 403 или капча | площадка | канал рабочий, отказ пришёл от сайта | снизить темп, сменить выход |
| Ошибка TLS при согласовании | сеть | сертификат подменён по пути | проверить антивирус и корпоративный фильтр |
Коды завершения curl дополняют картину и часто отвечают быстрее, чем чтение подробного вывода.
| Код | Название | Что означает |
|---|---|---|
| 5 | Couldn't resolve proxy | имя посредника не разрешилось, в ключе -x стоит домен |
| 6 | Couldn't resolve host | имя площадки не разрешилось локально, помогает схема socks5h |
| 7 | Failed to connect | порт закрыт либо пакет отброшен фильтром |
| 28 | Operation timed out | ответа нет в отведённое время |
| 35 | SSL connect error | согласование TLS оборвалось |
| 56 | Recv failure | соединение разорвано после установки |
| 97 | Proxy handshake failed | рукопожатие SOCKS отклонено посредником |
Общее правило чтения такое: коды 5, 6, 7 и 28 относятся к пути до посредника, код 97 к самому посреднику, 407 к авторизации, а всё, что приходит после строки Connection established, относится к целевой площадке. Разделение экономит массу времени, потому что убирает бесполезные попытки чинить настройки там, где отказ пришёл от сайта.
Отличить отказ посредника от отказа площадки помогают три признака. Первый признак: заголовки. Ответ посредника приходит без заголовков целевого сайта, в нём часто стоит Proxy-Connection и очень короткое тело. Второй признак: момент. Посредник отвечает до строки Connection established, площадка после неё. Третий признак: повторяемость. Отказ посредника воспроизводится на любом адресе назначения, отказ площадки привязан к конкретному домену. Прогоните ту же строку на нейтральном эхо-сервисе: код 200 оттуда означает, что канал рабочий и разбирать нужно поведение запросов к площадке.
Проверка списка адресов пачкой
Список выдаётся ссылкой или файлом, в двух форматах на выбор. Проверять его построчно руками смысла нет, весь прогон умещается в один цикл.
while IFS=: read -r ip port user pass; do
code=$(curl -s -m 12 -o /dev/null -w '%{http_code}' \
-x "http://${user}:${pass}@${ip}:${port}" https://api.ipify.org)
printf '%s:%s %s\n' "$ip" "$port" "$code"
done < list.txt
Последовательный прогон списка на несколько сотен строк занимает недопустимо долго, поэтому проверку распараллеливают. Двадцати одновременных проверок хватает с запасом, а лимит потоков пакета остаётся почти нетронутым.
xargs -P 20 -I{} sh -c '
p="{}"
ip=$(echo "$p" | cut -d: -f1); port=$(echo "$p" | cut -d: -f2)
u=$(echo "$p" | cut -d: -f3); pw=$(echo "$p" | cut -d: -f4)
c=$(curl -s -m 12 -o /dev/null -w "%{http_code}" \
-x "http://$u:$pw@$ip:$port" https://api.ipify.org)
echo "$ip:$port $c"
' < list.txt | sort -k2 -r
На Windows тот же прогон делается штатными средствами оболочки, вызов curl остаётся прежним.
Get-Content list.txt | ForEach-Object -Parallel {
$p = $_ -split ':'
$code = curl.exe -s -m 12 -o NUL -w '%{http_code}' `
-x "http://$($p[2]):$($p[3])@$($p[0]):$($p[1])" https://api.ipify.org
"$($p[0]):$($p[1]) $code"
} -ThrottleLimit 20
Итог прогона удобно свести в два числа: доля строк с кодом 200 и медиана времени ответа. Первое число говорит о рабочем состоянии списка, второе о том, чего ждать под нагрузкой. Прогонять весь пул смысла нет, список обновляется в режиме реального времени и живёт своей жизнью, достаточно выборки в несколько десятков строк.
Первый прогон удобно делать на бесплатном тесте до 2 часов: пакет включается примерно за 5 минут, за оставшееся время список проверяется пачкой, снимаются доли успехов и время отклика. Проверка на своих задачах убедительнее любых обещаний, и пакет прокси IPv4 с доступом к пулу оценивается именно так, своими командами и своими цифрами. Трафик безлимитный на всех пакетах, поэтому объём тестовых запросов ограничен только временем.
Частые вопросы
Чем проверять прокси, если консоли под рукой нет?
Мы рекомендуем чекер от Zennolab, у него есть демо-версия и её хватает для проверки списка. Он показывает доступность строки, время отклика и тип протокола, а разбор ошибок при необходимости добирается браузером: эхо-страница плюс поле Remote Address во вкладке «Сеть» дают ту же картину, что и подробный вывод curl.
Мне выдали список на 12 000 строк, проверять каждую?
Достаточно выборки. Список обновляется в режиме реального времени, состав пула меняется постоянно, поэтому полный обход даёт срез, который устареет через минуту. Возьмите 30-50 случайных строк, прогоните их пачкой и смотрите на долю успешных ответов. Вопрос «подойдёт ли пул под мои задачи» закрывается тем же способом: бесплатным тестом до 2 часов на реальном сценарии.
Почему мой выходной адрес каждый раз из другой страны?
Так устроен пул: это микс со всего мира, адреса приходят из 200+ стран, выборка по отдельной стране не делается. Ротация внутри пула автоматическая, поэтому соседние запросы уходят с разных выходов. Для проверки работоспособности важен сам факт смены адреса относительно прямого запроса, география тут вторична.
Что делать, если у меня динамический адрес и привязка слетает?
Привязанный адрес меняется без ограничений прямо в настройках кабинета, в пакет входит две одновременные привязки. При смене адреса провайдером старая привязка перестаёт совпадать, соединение начинает отбрасываться молча, и проверка порта показывает таймаут. Обновите привязку, повторите короткую команду curl, доступ восстанавливается сразу.
Проверка работоспособности это первый шаг, дальше идут более узкие замеры. Разбор заголовков и того, что уходит на сторону площадки, собран в материале про проверку анонимности и утечку заголовков. Как правильно снимать время ответа и не путать задержку канала с задержкой сайта, разобрано в заметке про замер скорости и времени отклика. Отдельный частый исход вынесен в разбор ошибки 407, там же порядок сверки учётных данных. Если проверка спотыкается уже на входе, начните с материала про строку подключения по полям: половина неудачных проверок объясняется перепутанным портом или лишним пробелом в строке.