diff --git a/src/Model/Message.php b/src/Model/Message.php index 473526e3..bac2b10d 100644 --- a/src/Model/Message.php +++ b/src/Model/Message.php @@ -34,6 +34,16 @@ final class Message * The OPT record uses the "ttl" field to store additional flags. */ const TYPE_OPT = 41; + + /** + * Sender Policy Framework (SPF) had a dedicated SPF type which has been + * deprecated in favor of reusing the existing TXT type. + * + * @deprecated https://datatracker.ietf.org/doc/html/rfc7208#section-3.1 + * @see self::TYPE_TXT + */ + const TYPE_SPF = 99; + const TYPE_ANY = 255; const TYPE_CAA = 257; diff --git a/src/Protocol/BinaryDumper.php b/src/Protocol/BinaryDumper.php index c0e4962c..83861cf0 100644 --- a/src/Protocol/BinaryDumper.php +++ b/src/Protocol/BinaryDumper.php @@ -92,6 +92,7 @@ private function recordsToBinary(array $records) $binary = $this->domainNameToBinary($record->data); break; case Message::TYPE_TXT: + case Message::TYPE_SPF: $binary = $this->textsToBinary($record->data); break; case Message::TYPE_MX: diff --git a/src/Protocol/Parser.php b/src/Protocol/Parser.php index 3effbb50..968bb022 100644 --- a/src/Protocol/Parser.php +++ b/src/Protocol/Parser.php @@ -171,7 +171,7 @@ private function parseRecord(Message $message) } } elseif (Message::TYPE_CNAME === $type || Message::TYPE_PTR === $type || Message::TYPE_NS === $type) { list($rdata, $consumed) = $this->readDomain($message->data, $consumed); - } elseif (Message::TYPE_TXT === $type) { + } elseif (Message::TYPE_TXT === $type || Message::TYPE_SPF === $type) { $rdata = array(); while ($consumed < $expected) { $len = ord($message->data[$consumed]); diff --git a/tests/Protocol/BinaryDumperTest.php b/tests/Protocol/BinaryDumperTest.php index c1ab9065..9bd5f109 100644 --- a/tests/Protocol/BinaryDumperTest.php +++ b/tests/Protocol/BinaryDumperTest.php @@ -385,7 +385,7 @@ public function testToBinaryForResponseWithPTRRecordWithSpecialCharactersEscaped public function testToBinaryForResponseWithMultipleAnswerRecords() { $data = ""; - $data .= "72 62 01 00 00 01 00 06 00 00 00 00"; // header + $data .= "72 62 01 00 00 01 00 07 00 00 00 00"; // header $data .= "04 69 67 6f 72 02 69 6f 00"; // question: igor.io $data .= "00 ff 00 01"; // question: type ANY, class IN @@ -401,6 +401,10 @@ public function testToBinaryForResponseWithMultipleAnswerRecords() $data .= "00 10 00 01 00 00 00 00 00 0c"; // answer: type TXT, class IN, TTL 0, 12 bytes $data .= "05 68 65 6c 6c 6f 05 77 6f 72 6c 64"; // answer: hello, world + $data .= "04 69 67 6f 72 02 69 6f 00"; // answer: igor.io + $data .= "00 63 00 01 00 00 00 00 00 0c"; // answer: type SPF, class IN, TTL 0, 12 bytes + $data .= "0b 76 3d 73 70 66 31 20 2d 61 6c 6c"; // answer: v=spf1 -all + $data .= "04 69 67 6f 72 02 69 6f 00"; // answer: igor.io $data .= "00 0f 00 01 00 00 00 00 00 03"; // answer: type MX, class IN, TTL 0, 3 bytes $data .= "00 00 00"; // answer: … priority 0, no target @@ -430,6 +434,7 @@ public function testToBinaryForResponseWithMultipleAnswerRecords() $response->answers[] = new Record('igor.io', Message::TYPE_A, Message::CLASS_IN, 0, '127.0.0.1'); $response->answers[] = new Record('igor.io', Message::TYPE_AAAA, Message::CLASS_IN, 0, '::1'); $response->answers[] = new Record('igor.io', Message::TYPE_TXT, Message::CLASS_IN, 0, array('hello', 'world')); + $response->answers[] = new Record('igor.io', Message::TYPE_SPF, Message::CLASS_IN, 0, array('v=spf1 -all')); $response->answers[] = new Record('igor.io', Message::TYPE_MX, Message::CLASS_IN, 0, array('priority' => 0, 'target' => '')); $response->answers[] = new Record('igor.io', Message::TYPE_CAA, Message::CLASS_IN, 0, array('flag' => 0, 'tag' => 'issue', 'value' => 'letsencrypt.org')); $response->answers[] = new Record('igor.io', Message::TYPE_SSHFP, Message::CLASS_IN, 0, array('algorithm' => 1, 'type' => '1', 'fingerprint' => '69ac090c')); diff --git a/tests/Protocol/ParserTest.php b/tests/Protocol/ParserTest.php index 1132b423..0624526a 100644 --- a/tests/Protocol/ParserTest.php +++ b/tests/Protocol/ParserTest.php @@ -305,6 +305,25 @@ public function testParseTXTResponse() $this->assertSame(array('hello'), $response->answers[0]->data); } + public function testParseSPFResponse() + { + $data = ""; + $data .= "04 69 67 6f 72 02 69 6f 00"; // answer: igor.io + $data .= "00 63 00 01"; // answer: type SPF, class IN + $data .= "00 01 51 80"; // answer: ttl 86400 + $data .= "00 06"; // answer: rdlength 6 + $data .= "05 68 65 6c 6c 6f"; // answer: rdata length 5: hello + + $response = $this->parseAnswer($data); + + $this->assertCount(1, $response->answers); + $this->assertSame('igor.io', $response->answers[0]->name); + $this->assertSame(Message::TYPE_SPF, $response->answers[0]->type); + $this->assertSame(Message::CLASS_IN, $response->answers[0]->class); + $this->assertSame(86400, $response->answers[0]->ttl); + $this->assertSame(array('hello'), $response->answers[0]->data); + } + public function testParseTXTResponseMultiple() { $data = "";