Skip to content

Instantly share code, notes, and snippets.

@alexd1971
Created May 21, 2018 05:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alexd1971/2ac145546ee72f713e0c9fb6acddf425 to your computer and use it in GitHub Desktop.
Save alexd1971/2ac145546ee72f713e0c9fb6acddf425 to your computer and use it in GitHub Desktop.
Socks5 communication in dart
import 'dart:async';
import 'dart:io';
/// Фазы установки соединения с socks5-сервером
enum Socks5 {init, auth, connect}
Future main() async {
String targetHost = 'delidela.com';
int targetPort = 443;
String socksLogin = 'login';
String socksPassword = 'password';
// Устанавливаем TCP-соединение с socks5-сервером
Socket socket = await Socket.connect('socks5.host', 7777);
// Здесь фиксируется, на каком этапе находится общение с сервером
Socks5 step;
// Результат запроса к серверу
int result;
// Ip-адрес, выданный сервером после усешной установки соединения
InternetAddress ip;
// Порт, выданный сервером, после успешной установки соединения
int port;
// Комплитер необходим для синхронизации запросов
Completer completer;
// Слушаем, что отвечает сервер
// data - это List<int> (байты с информацией от сервера)
socket.listen((data) async {
// Результат запроса (успех/неудача и т.п.) передается в data[1]
result = data[1];
// Если выполнялась команда CONNECT, то из ответа сервера можно выделить ip и port,
// выданные сервером для общения с целевым хостом
if (step == Socks5.connect) {
// data[3] определяет в каком формате передан адрес
if (data[3] == 1) { // data[3] == 1 - адрес в формате IPv4
ip = new InternetAddress(data.sublist(4, 8).join('.'));
} else if (data[3] == 3) { //data[3] == 3 - адрес в виде доменного имени
ip = (await InternetAddress.lookup(
new String.fromCharCodes(data.sublist(5, 5+data[4])),
type: InternetAddressType.IP_V4)
)[0];
}
port = int.parse('0x' + data.sublist(data.length-2).map((int byte) => byte.toRadixString(16)).join());
}
completer.complete();
});
// Первый шаг
step = Socks5.init;
print('Подключение к socks5 серверу...');
completer = new Completer();
// Формат запроса можно почитать в RFC 1928
socket.add([0x05, 0x02, 0x00, 0x02]);
await completer.future;
if (result == 0xff) {
print('Указанные методы аутентификации не поддерживаются');
socket.close();
exit(1);
}
print('готово');
// Если сервер выбрал метод аутентификации по логину и пароль (2),
// то выполняем аутентификацию
if (result == 2) {
step = Socks5.auth;
print('Аутентификация');
completer = new Completer();
List<int> loginBytes = socksLogin.codeUnits;
List<int> passwordBytes = socksPassword.codeUnits;
// Фомирование запроса на аутентификацию
// Формат запроса см. RFC 1929
List<int> authRequest = [1];
authRequest.add(loginBytes.length);
authRequest.addAll(loginBytes);
authRequest.add(passwordBytes.length);
authRequest.addAll(passwordBytes);
socket.add(authRequest);
await completer.future;
if (result != 0) {
print('Неверный логин или пароль');
socket.close();
exit(1);
}
print('Ok');
}
// Устанавливаем подключение к целевому хосту
step = Socks5.connect;
print('Устанавливаем подключение...');
completer = new Completer();
List<int> targetHostBytes = targetHost.codeUnits;
String hexTargetPortString = targetPort.toRadixString(16).padLeft(4, '0');
List<int> targetPortBytes = [
hexTargetPortString.substring(0, 2),
hexTargetPortString.substring(2)
].map((String byte) => int.parse(byte));
List<int> connectRequest = [5, 1, 0, 3];
connectRequest.add(targetHostBytes.length);
connectRequest.addAll(targetHostBytes);
connectRequest.addAll(targetPortBytes);
socket.add(connectRequest);
await completer.future;
print(ip);
print(port);
// Тут, видимо, должна быть коммуникация с целевым хостом
socket.close();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment