diff --git a/examples/11-query-any.php b/examples/11-query-any.php index 7a5a47a3..dcc14ae3 100644 --- a/examples/11-query-any.php +++ b/examples/11-query-any.php @@ -48,6 +48,11 @@ $type = 'MX'; $data = implode(' ', $data); break; + case Message::TYPE_SRV: + // SRV records contains priority, weight, port and target, dump structure here + $type = 'SRV'; + $data = json_encode($data); + break; case Message::TYPE_SOA: // SOA records contain structured data, dump structure here $type = 'SOA'; diff --git a/src/Model/Message.php b/src/Model/Message.php index d318cdb0..ce4ffde0 100644 --- a/src/Model/Message.php +++ b/src/Model/Message.php @@ -14,6 +14,7 @@ class Message const TYPE_MX = 15; const TYPE_TXT = 16; const TYPE_AAAA = 28; + const TYPE_SRV = 33; const TYPE_ANY = 255; const CLASS_IN = 1; diff --git a/src/Model/Record.php b/src/Model/Record.php index 9f215df8..035bc6e5 100644 --- a/src/Model/Record.php +++ b/src/Model/Record.php @@ -56,6 +56,18 @@ class Record * referred to as exchange). If a response message contains multiple * records of this type, targets should be sorted by priority (lowest * first) - this is left up to consumers of this library (used for SMTP). + * - SRV: + * Service priority (UINT16), service weight (UINT16), service port (UINT16) + * and target hostname without trailing dot, for example + * `{"priority":10,"weight":50,"port":8080,"target":"example.com"}`. + * The payload data uses an associative array with fixed keys "priority", + * "weight", "port" and "target" (also referred to as name). + * The target may be an empty host name string if the service is decidedly + * not available. If a response message contains multiple records of this + * type, targets should be sorted by priority (lowest first) and selected + * randomly according to their weight - this is left up to consumers of + * this library, see also [RFC 2782](https://tools.ietf.org/html/rfc2782) + * for more details. * - SOA: * Includes master hostname without trailing dot, responsible person email * as hostname without trailing dot and serial, refresh, retry, expire and diff --git a/src/Protocol/Parser.php b/src/Protocol/Parser.php index 749f8d88..a5039572 100644 --- a/src/Protocol/Parser.php +++ b/src/Protocol/Parser.php @@ -185,6 +185,16 @@ public function parseAnswer(Message $message) 'priority' => $priority, 'target' => implode('.', $bodyLabels) ); + } elseif (Message::TYPE_SRV === $type) { + list($priority, $weight, $port) = array_values(unpack('n*', substr($message->data, $consumed, 6))); + list($bodyLabels, $consumed) = $this->readLabels($message->data, $consumed + 6); + + $rdata = array( + 'priority' => $priority, + 'weight' => $weight, + 'port' => $port, + 'target' => implode('.', $bodyLabels) + ); } elseif (Message::TYPE_SOA === $type) { list($primaryLabels, $consumed) = $this->readLabels($message->data, $consumed); list($mailLabels, $consumed) = $this->readLabels($message->data, $consumed); diff --git a/tests/Protocol/ParserTest.php b/tests/Protocol/ParserTest.php index e1772d3e..2bba4825 100644 --- a/tests/Protocol/ParserTest.php +++ b/tests/Protocol/ParserTest.php @@ -331,6 +331,39 @@ public function testParseMXResponse() $this->assertSame(array('priority' => 10, 'target' => 'hello'), $response->answers[0]->data); } + public function testParseSRVResponse() + { + $data = ""; + $data .= "04 69 67 6f 72 02 69 6f 00"; // answer: igor.io + $data .= "00 21 00 01"; // answer: type SRV, class IN + $data .= "00 01 51 80"; // answer: ttl 86400 + $data .= "00 0C"; // answer: rdlength 12 + $data .= "00 0a 00 14 1F 90 04 74 65 73 74 00"; // answer: rdata priority 10, weight 20, port 8080 test + + $data = $this->convertTcpDumpToBinary($data); + + $response = new Message(); + $response->header->set('anCount', 1); + $response->data = $data; + + $this->parser->parseAnswer($response); + + $this->assertCount(1, $response->answers); + $this->assertSame('igor.io', $response->answers[0]->name); + $this->assertSame(Message::TYPE_SRV, $response->answers[0]->type); + $this->assertSame(Message::CLASS_IN, $response->answers[0]->class); + $this->assertSame(86400, $response->answers[0]->ttl); + $this->assertSame( + array( + 'priority' => 10, + 'weight' => 20, + 'port' => 8080, + 'target' => 'test' + ), + $response->answers[0]->data + ); + } + public function testParseResponseWithTwoAnswers() { $data = "";