Sockets: Соединение и Отправка пакетов через прокси сервера, на примере HTTP(S) слоя

Как лучше отправить и принять HTTP запрос в крупном приложении

  • Установив связь через сокет (Используя спец. Обертку)

    Голосов: 1 33,3%
  • Использовать cURL

    Голосов: 2 66,7%

  • Всего проголосовало
    3

Kutuz

Новичок
Здравствуйте, ребят можете подсказать как работать с проксями на прикладных уровнях , посредством только сокетов по tcp или ssl транспорту.
Интересует соединение с прокси, далее предварительная конвертация данных в тип кушаемый проксей, далее отправка и уже чтение.
Естественно можно использовать специальные HTTP прокси, но мы не ищем легких путей
Интересует так-же работа с smtp и так-же через прокси например типа Socks4/5.
Отсюда и строятся принципы туннелирования всех остальных протоколов, например pop imap и другие
Может есть у кого примеры в виде кусочков лапшекода?)

Сопутствующие ссылки:
https://ru.wikipedia.org/wiki/Туннелирование_(компьютерные_сети)
https://ru.wikipedia.org/wiki/SOCKS
https://ru.wikipedia.org/wiki/Tor
 

Breeze

goshogun
Команда форума
Партнер клуба
Что есть "крупное приложение"?
Ты ж понимаешь, что оба варианта приемлемы в зависимости от конкретной ситуации и задачи, да?
 

Kutuz

Новичок
Под разные ситуации разные варианты, это да) Давайте сложим примеры скриптовки таких запросов в этой теме? и разберем эти возможные ситуации)
 

Breeze

goshogun
Команда форума
Партнер клуба
Зачем? 90% программистов не столкнутся с проблемами при использовании curl.
 

Kutuz

Новичок
Искренне извеняюсь за свою изначальную неточность и недостаточную конкретность вопроса, просто я планирую архитектуру библиотеки, в которой все должно быть достаточно абстрактно и много-направленно, хотел узнать разные способы и средства достижения данной цели. Важна теоретическая часть)

Ребят ответте пожалуйста, можно ли в соксовом протоколе(имея активное, уже настроенное на некоторый дестинейшн соединение, при этом туннель был использован) не закрывая сокет задать другой дестинейшн и проделывать общение далее уже на него? это прямо касается производительности
 

AmdY

Пью пиво
Команда форума
может просто воспользоваться существующим транспортом вроде guzzle?
 

Kutuz

Новичок
Да не, даже не спрашивай)
нужен ответ по соксу, я просто так и не пойму, можно ли в одном соединении последовательно менять сервера к которым мы подключаемся через сокс?
 

AnrDaemon

Продвинутый новичок
Ты такие вопросы задаёшь… что хоть стой, хоть падай.
Ты вообще представляешь себе, что есть соединение на уровне TCP протокола?
 

Kutuz

Новичок
Не совсем, поэтому и спросил, может я не правильно вопрос поставил?)
 

Kutuz

Новичок
Сложно хотя бы такой код выложить? где есть простое рукопожатие? может это куда проще чем Guzzle? простой императивный код - лапшакод, где все ясно
PHP:
function socks5($ip,$port, $to_host,$to_port){

    $socks = fsockopen($ip,$port);

    //Initiate the SOCKS handshake sequence.

    //Write our version an method to the server.
    //Version 5, 1 authentication method, no authentication. (For now)
    fwrite($socks, pack("C3", 0x05, 0x01, 0x00) );

    //Wait for a reply from the SOCKS server.
    $status = fread($socks,8192);

    //Check if server status is okay.
    if ( $status != pack("C2", 0x05, 0x00) ) {
        //Throw error if required.
        throw new \Exception(
            "SOCKS Server does not support this version and/or authentication method of SOCKS."
        );
    }

    //At this stage, our SOCKS socket should be open and ready to make its remote connection.
    //Send the connection request.
    fwrite( $socks, pack("C5", 0x05 , 0x01 , 0x00 , 0x03, strlen($to_host) ) . $to_host . pack("n", $to_port) );

    //Wait for a reply from the SOCKS server.
    $buffer = fread($socks,8192);

    $state = substr($buffer,0,4);

    if($state == pack("C4", 0x05, 0x00, 0x00, 0x01)){
        return $socks;
    }else {
        //Connection failed.
        throw new \Exception(
            "The SOCKS server failed to connect to the specificed host and port. ( ".$to_host.":".$to_port." )"
        );
    }
}
Открывается соединение с ($ip,$port) , жмем руки и задаем коннект c ($to_host,$to_port), далее в этот поток шли что хочешь по любому протоколу https, smtp, etc(смотря к какому $to_ip подключились).
А уже позже я узнал что нельзя изменить уже заданный хост порт у сокса, т.к любая комманда пущенная в сокет (fwrite) после рукопожатий, соксовая или даже 0x00 байт уйдет в конец(адресату), что оказалось логично.
 
Последнее редактирование:

AnrDaemon

Продвинутый новичок
Ну вот видишь. Оказалось, всё не так сложно, как казалось.
 

Kutuz

Новичок
Да не сложно, я же написал в топике что нужны просто кусочки кода, ты же и сам мне ответил
Складывайте, разбирайте…
Сам то я знаю как работает клиентская часть сокетов, просто не знаю протоколов, что мне в сокеты писать, я не знаю)
В общем пишу либу Communication с поддержкой Туннелирования, туннелирование будет определятся в потоках т.к это наилучший вариант который годится для любых покрывающих протоколов что http что smtp

Потоки в таком случае намного проще чем курлы с точки зрения того функционала что я хочу получить

Могу привести пример некоторой части либы

Составление спецификаций на поточные подключения, для реализации выполнения пред-определенного общения в виде комбинации нескольких серий (комманда-ответ) текущий вариант либы не содержит даже намека на туннелирование)

Определение спецификации(здесь в виде наследования базового класса):
PHP:
class Smtp extends Specification{


        /**
         * Smtp constructor.
         */
        public function __construct(){
            $this->command('start',[
                'rules' => [
                    [ 'check' => [220], 'message' => 'Error connect to SMTP server', 'negate' => true ]
                ]
            ]);
            $this->command('hello',[
                'definition' => 'EHLO {{host}}',
                'rules' => [
                    [ 'check' => 250, 'message' => 'SMTP Hello error', 'negate' => true ]
                ]
            ]);
            $this->bundle('auth',[[
                'definition' => 'AUTH LOGIN',
                'rules' => [
                    ['check' => 334, 'message' => 'Authentication error(START)', 'negate' => true]
                ]
            ],[
                'definition' => '{{login}}',
                'rules' => [
                    ['check' => 334, 'message' => 'Authentication error(login)', 'negate' => true]
                ]
            ],[
                'definition' => '{{password}}',
                'rules' => [
                    ['check'=> 235, 'message' => 'AuthenticationMissed', 'negate' => true]
                ]
            ]]);
            $this->command('mail_from',[
                'definition' => 'MAIL FROM:<{{mail_from}}> SIZE={{size}}',
                'rules' => [
                    ['check' => 250, 'message' => 'Sender invalid','negate' => true]
                ]
            ]);
            $this->command('recipient',[
                'definition' => 'RCPT TO:<{{recipient}}>',
                'aggregator' => function(array $params){
                    $a = [];
                    if(isset($params['recipient'])){
                        if(is_scalar($params['recipient'])){
                            $a[] = $params['recipient'];
                        }
                        if(is_callable($params['recipient'])){
                            $params['recipient'] = call_user_func($params['recipient']);
                        }
                        foreach($params['recipient'] as $recipient){
                            $a[] = [
                                'recipient' => $recipient
                            ];
                        }
                    }
                    return $a;
                },
                'rules' => [[
                    'check'    => [250,220,251],
                    'message' => "Ошибка, адрес не может быть доступен",
                    'negate'  => true
                ]]
            ]);
            $this->bundle('data',[[
                'definition' => 'DATA',
                'rules' => [
                    ['check' => 354, 'message' => 'DATA pre send error','negate' => true]
                ]
            ],[
                'definition' => "{{data}}\r\n.",
                'rules' => [
                    ['check' => [220,250], 'message' => 'SMTP server not accepted send data','negate' => true]
                ]
            ]]);
            $this->command('reset', [ 'definition' => 'RESET' ]);
            $this->command('quit', [ 'definition' => 'QUIT' ]);
        }


        /**
         * @return mixed
         */
        public function getMaxLength(){
            return 515;
        }

        /**
         * @param $response
         * @return int
         */
        public function recognizeCode($response){
            return intval(substr($response,0,3));
        }

        /**
         * @param $command
         * @return string
         */
        public function convertBeforeSend($command){
            return $command . "\r\n";
        }


        /**
         * @param StreamInteractionInterface $connection
         * @return string
         */
        public function read(StreamInteractionInterface $connection){
            $data = "";$length = $this->getMaxLength();
            while($str = $connection->readLine($length)){
                $data .= $str;
                if(substr($str,3,1) == " ") { break; }
            }
            return $data;
        }

        /**
         * @return ConnectionInterface
         */
        public function createConnection(){
            return new Socket([]);
        }

        /**
         * @param ProcessSequenceInterface $processSequence
         * @return mixed
         */
        public function beforeSequence(ProcessSequenceInterface $processSequence){
            $this->getCommand('start')->run($processSequence,[]);
        }

        /**
         * @param $processSequence
         * @return mixed
         */
        public function afterSequence(ProcessSequenceInterface $processSequence){}

        /**
         * @param ProcessSequenceInterface $processSequence
         * @return mixed
         */
        public function continueSequence(ProcessSequenceInterface $processSequence){

        }
    }
Использование этой спецификации

PHP:
/**
 * 'params_merge' - если Тру, то весь конфиг будет закидываться как аргументы в каждую последующую команду
 *
 */
$specification = new Specification\Smtp();
$sequence = $specification->createSequence();
$sequence->setSpecification($specification);
$sequence->setConfig([
    'params_merge' => true,

    'scheme'       => 'ssl',
    'host'         => 'smtp.mail.ru',
    'port'         => 465,

    'login'        => null,
    'password'     => null,

    'mail_from'    => null,
    'recipient'    => null,

    'data'         => null,
    'size'         => null,
]);
$sequence->setSequence([
    'hello',
    'auth',
    'mail_from',
    'recipient',
    'data'
]);
$sequence->run();
Предназначение у этого компонента более расположено к интеграции функциональности в пользовательский интерфейс, т.к легко с помощью массивов декларировать как Спецификации так и Последовательности

К сожалению, у этой компоненты либы есть минусы в виде отсутствия туннелирования и отсутствия возможности указывать или требовать выполнение определенной команды в зависимости от того или иного ответа полученного от сервера прямо во время выполнения (то есть считать ответ где описано что требуется авторизация и автоматически подставить в нужное место вызов этой команды, а в случае отсутствия нужных агрументов выбросить исключение) или наоборот если авторизация не описана убрать команду из очереди на выполнение

Хотя случай с динамикой очереди команд на выполнение не так уж и нужен в smtp)
 
Последнее редактирование:

AnrDaemon

Продвинутый новичок
"Я не знаю протоколов но пишу библиотеку…"
Внушает доверие, да.
 

Kutuz

Новичок
Может и не внушает, кому как пожелается, зато я изучаю
 
Сверху