Поймать ответ сервера EPP после отправки запроса XML - PullRequest
0 голосов
/ 04 апреля 2020

В настоящее время мы разрабатываем API регистратора доменов.

    $options = [
        'ssl' => [
            'verify_peer' => true,
            'local_cert' => __DIR__ . '/Domain.pem',
            'local_pk' => __DIR__ . '/Domain.pem',
            'allow_self_signed' => true,
        ]
    ];
    $context = stream_context_create($options);
    $ch = stream_socket_client($serverPath.':'.$parentClass->port, $errorNumber, $errorString, 60, STREAM_CLIENT_CONNECT, $context);
    stream_set_timeout($ch, 60);

    fwrite($ch, $command);

    $data = '';

    while (!feof($ch)) {
        $data .= fread($ch, 1024);
    }

    fclose($ch);

После написания XML запроса

<epp xsi:schemaLocation="urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="urn:ietf:params:xml:ns:epp-1.0">
<command>
<login>
<clID>User</clID>
<pw>Password</pw>
<options>
<version>1.0</version>
<lang>en</lang>
</options>
<svcs>
<objURI>urn:ietf:params:xml:ns:obj1</objURI>
<objURI>urn:ietf:params:xml:ns:obj2</objURI>
<objURI>urn:ietf:params:xml:ns:obj3</objURI>
<svcExtension>
<extURI>http://custom/obj1ext-1.0</extURI>
</svcExtension>
</svcs>
</login>
<clTRID>ABC-12345</clTRID>
</command>
</epp>

fread выдает приветствие, а не код статуса запроса на вход. Является ли этот метод чтения ответа правильным? В чем может быть причина не получить правильный ответ от сервера? Спасибо

1 Ответ

1 голос
/ 07 апреля 2020

EPP не работает, как вы думаете. Для начала я рекомендую вам потратить некоторое время на чтение RFC5730 и 5734 в полном объеме, они обсуждаются ниже. После того, как вы выполнили эту работу, вам потребуется полный набор asp всех деталей EPP в RFC 5731 5732 и 5733. Не ожидайте, что сможете написать успешный клиент EPP, не прочитав их все.

Теперь вернемся к вашей проблеме, и почему вы не следуете спецификациям EPP.

См. Раздел 2 документа RFC5730, воспроизведенный здесь:

          |
          V
  +-----------------+                  +-----------------+
  |   Waiting for   |     Connected    |     Prepare     |
  |      Client     |----------------->|     Greeting    |
  +-----------------+    or <hello>    +-----------------+
     ^                                           |
     | Close Connection                     Send |
     |     or Idle                      Greeting |
  +-----------------+                            V
  |       End       |     Timeout      +-----------------+
  |     Session     |<-----------------|   Waiting for   |
  +-----------------+                  |      Client     |
     ^    ^    ^        Send +-------->|  Authentication |
     |    |    |    Response |         +-----------------+
     |    |    |     +--------------+            |
     |    |    |     | Prepare Fail |            | <login>
     |    |    +-----|   Response   |            | Received
     |    |    Send  +--------------+            V
     |    |    2501          ^         +-----------------+
     |    |   Response       |         |   Processing    |
     |    |                  +---------|     <login>     |
     |    |                  Auth Fail +-----------------+
     |    |       Timeout                         |
     |    +-------------------------------+       | Auth OK
     |                                    |       V
     |   +-----------------+  <hello>  +-----------------+
     |   |     Prepare     |<----------|   Waiting for   |
     |   |     Greeting    |---------->|   Command or    |
     |   +-----------------+   Send    |     <hello>     |
     | Send x5xx             Greeting  +-----------------+
     | Response  +-----------------+  Send    ^  |
     +-----------|     Prepare     | Response |  | Command
                 |     Response    |----------+  | Received
                 +-----------------+             V
                            ^          +-----------------+
                    Command |          |   Processing    |
                  Processed +----------|     Command     |
                                       +-----------------+

Здесь по-другому сказано, как должен вести себя ваш клиент:

  • устанавливает sh соединение TLS (обязательно проверьте удаленный сертификат)
  • сервер говорит первым, с приветственным сообщением (см. Раздел 2.4 того же RF * 1074) *)
  • вам нужно прочитать это сообщение и извлечь из него различные части, в частности части objURI и extURI
  • теперь клиент отправляет свое сообщение для входа (раздел 2.9.1.1)
  • эта команда, как и другие, заставит сервер ответить с результатом, сообщающим вам, успешно ли это выполнено (код 1000) или нет (любой код, начинающийся с 2)

Ошибка в yo Ваша программа заключается в том, что ваш клиент сначала говорит, что-то отправляет на сервер. Это недопустимо в соответствии с приведенной выше схемой состояний, поэтому сначала прочтите ответ сервера.

Так что ваша проблема заключается не только в отправке XML (хотя у вас также есть проблема с этим, см. Ниже), сначала это не соответствует порядку того, кто говорит первым.

Также не делайте этого:

    while (!feof($ch)) {
        $data .= fread($ch, 1024);
    }

См. RF C 5734, который объясняет, как транспортируется EPP. В заключение, а также для ответа на некоторые комментарии выше по вашему вопросу:

  • EPP использует TLS в качестве транспорта, HTTPS не существует
  • 700 - это стандартный IANA-порт, назначенный для связи, за исключением случаев, когда реестр сообщает вам иначе
  • каждое сообщение XML (после сериализации UTF-8 и т. д. c.) имеет префикс на проводе с 4 байтами, которые обозначают длину для полного кадра EPP (кадра = Длина заголовка 4 байта + полное сообщение).

Поэтому, когда вы ожидаете сообщение от сервера, вы делаете это так:

  • вы читаете первые 4 байта ( это может быть не так просто, вам может понадобиться читать их по одному и собирать их вместе, во многом зависит от инструментов, используемых для сетевого ввода-вывода)
  • теперь вы точно знаете размер то, что вы ожидаете получить дальше, это длина в 4 байтах (правильно декодированных) минус 4, чтобы удалить 4 байта из полной длины.

Но обратите внимание, что вам нужно выполнить то же самое, когда вы отправляете палатка на сервер! Не отправляйте только содержимое XML, вам нужно сформировать правильный кадр EPP, что означает:

  • считать размер сообщения (в байтах, а не в символах, поэтому после сериализации UTF-8 и т. д. c.)
  • подготовить 4 байта для сохранения этого размера в качестве порядка сетевых байтов
  • , немедленно отправив эти 4 байта, а затем сообщение XML.

Кроме того, как «ветеран» в отрасли (проработав там 20 лет, написав как серверы EPP, так и клиентов и приняв участие в RFC, которые его определяют), пожалуйста, воспользуйтесь этим советом из опыта: если ваша работа подключиться только к одному реестру, тогда жизнь проста; Вы можете даже использовать инструментарий, предоставляемый реестром, если он написан на выбранном вами языке.

Однако, как только вам нужно написать клиент, который сможет правильно подключаться к нескольким реестры, вы будете страдать от боли. Даже если это стандарт, вы найдете МНОЖЕСТВО вариаций среди реестров по многим темам, таким как то, как сообщаются расширенные данные об ошибках, какие существуют расширения EPP и как они работают, содержание ответов для домена: проверка и т. Д., список небольших различий можно перечислить здесь очень просто.

По всем вышеперечисленным причинам вы можете не изобретать велосипед. Существуют библиотеки, которые делают все для EPP, например, https://github.com/centralnic/php-epp Я не одобряю это, так как не знаю, так как не использую PHP, но, возможно, это может помочь вам либо просто повторно использовать как есть, чтобы у вас не было кода для написания, или, по крайней мере, взглянуть на него, чтобы увидеть, как они решают конкретные c проблемы, чтобы вы могли вдохновиться.

Например, описанный выше вопрос о длине и 4 байтах в начале каждого кадра EPP см. В getFrame и sendFrame в https://github.com/centralnic/php-epp/blob/master/Net/EPP/Protocol.php

...