22
33namespace Utopia \DNS ;
44
5+ use Utopia \DNS \Exception \DecodingException ;
6+ use Utopia \DNS \Exception \PartialDecodingException ;
57use Utopia \DNS \Message \Header ;
68use Utopia \DNS \Message \Question ;
79use Utopia \DNS \Message \Record ;
@@ -20,15 +22,22 @@ final class Message
2022 public const int RCODE_NOTAUTH = 9 ;
2123 public const int RCODE_NOTZONE = 10 ;
2224
25+ /**
26+ * @param Header $header The header of the message.
27+ * @param Question[] $questions The question records.
28+ * @param list<Record> $answers The answer records.
29+ * @param list<Record> $authority The authority records.
30+ * @param list<Record> $additional The additional records.
31+ */
2332 public function __construct (
2433 public readonly Header $ header ,
2534 /** @var Question[] */
2635 public readonly array $ questions = [],
27- /** @var Record[] */
36+ /** @var list< Record> */
2837 public readonly array $ answers = [],
29- /** @var Record[] */
38+ /** @var list< Record> */
3039 public readonly array $ authority = [],
31- /** @var Record[] */
40+ /** @var list< Record> */
3241 public readonly array $ additional = []
3342 ) {
3443 if ($ header ->questionCount !== count ($ questions )) {
@@ -43,7 +52,7 @@ public function __construct(
4352 if ($ header ->additionalCount !== count ($ additional )) {
4453 throw new \InvalidArgumentException ('Invalid DNS response: additional count mismatch ' );
4554 }
46- if ($ header ->isResponse && !array_any ($ this ->authority , fn ($ record ) => $ record ->type === Record::TYPE_SOA )) {
55+ if ($ header ->isResponse && $ header -> authoritative && !array_any ($ this ->authority , fn ($ record ) => $ record ->type === Record::TYPE_SOA )) {
4756 if ($ header ->responseCode === self ::RCODE_NXDOMAIN ) {
4857 throw new \InvalidArgumentException ('NXDOMAIN requires SOA in authority ' );
4958 }
@@ -83,19 +92,21 @@ public static function query(
8392 /**
8493 * Create a response message.
8594 *
86- * @param Message $query The query message to respond to.
95+ * @param Header $header The header of the query message to respond to.
8796 * @param int $responseCode The response code.
88- * @param array<Record> $answers The answer records.
89- * @param array<Record> $authority The authority records.
90- * @param array<Record> $additional The additional records.
97+ * @param array<Question> $questions The question records.
98+ * @param list<Record> $answers The answer records.
99+ * @param list<Record> $authority The authority records.
100+ * @param list<Record> $additional The additional records.
91101 * @param bool $authoritative Whether the response is authoritative.
92102 * @param bool $truncated Whether the response is truncated.
93103 * @param bool $recursionAvailable Whether recursion is available.
94104 * @return self The response message.
95105 */
96106 public static function response (
97- Message $ query ,
107+ Header $ header ,
98108 int $ responseCode ,
109+ array $ questions = [],
99110 array $ answers = [],
100111 array $ authority = [],
101112 array $ additional = [],
@@ -104,59 +115,64 @@ public static function response(
104115 bool $ recursionAvailable = false
105116 ): self {
106117 $ header = new Header (
107- id: $ query -> header ->id ,
118+ id: $ header ->id ,
108119 isResponse: true ,
109- opcode: $ query -> header ->opcode ,
120+ opcode: $ header ->opcode ,
110121 authoritative: $ authoritative ,
111122 truncated: $ truncated ,
112- recursionDesired: $ query -> header ->recursionDesired ,
123+ recursionDesired: $ header ->recursionDesired ,
113124 recursionAvailable: $ recursionAvailable ,
114125 responseCode: $ responseCode ,
115- questionCount: count ($ query -> questions ),
126+ questionCount: count ($ questions ),
116127 answerCount: count ($ answers ),
117128 authorityCount: count ($ authority ),
118129 additionalCount: count ($ additional )
119130 );
120131
121- return new self ($ header , $ query ->questions , $ answers , $ authority , $ additional );
132+
133+ return new self ($ header , $ questions , $ answers , $ authority , $ additional );
122134 }
123135
124136 public static function decode (string $ packet ): self
125137 {
126138 if (strlen ($ packet ) < Header::LENGTH ) {
127- throw new \ InvalidArgumentException ('Invalid DNS response: header too short ' );
139+ throw new DecodingException ('Invalid DNS response: header too short ' );
128140 }
129141
130142 // --- Parse header (12 bytes) ---
131143 $ header = Header::decode ($ packet );
132144
133145 // --- Parse Question Section ---
134- $ offset = Header::LENGTH ;
135- $ questions = [];
136- for ($ i = 0 ; $ i < $ header ->questionCount ; $ i ++) {
137- $ questions [] = Question::decode ($ packet , $ offset );
138- }
146+ try {
147+ $ offset = Header::LENGTH ;
148+ $ questions = [];
149+ for ($ i = 0 ; $ i < $ header ->questionCount ; $ i ++) {
150+ $ questions [] = Question::decode ($ packet , $ offset );
151+ }
139152
140- // --- Decode Answer Section ---
141- $ answers = [];
142- for ($ i = 0 ; $ i < $ header ->answerCount ; $ i ++) {
143- $ answers [] = Record::decode ($ packet , $ offset );
144- }
153+ // --- Decode Answer Section ---
154+ $ answers = [];
155+ for ($ i = 0 ; $ i < $ header ->answerCount ; $ i ++) {
156+ $ answers [] = Record::decode ($ packet , $ offset );
157+ }
145158
146- // --- Decode Authority Section ---
147- $ authority = [];
148- for ($ i = 0 ; $ i < $ header ->authorityCount ; $ i ++) {
149- $ authority [] = Record::decode ($ packet , $ offset );
150- }
159+ // --- Decode Authority Section ---
160+ $ authority = [];
161+ for ($ i = 0 ; $ i < $ header ->authorityCount ; $ i ++) {
162+ $ authority [] = Record::decode ($ packet , $ offset );
163+ }
151164
152- // --- Decode Additional Section ---
153- $ additional = [];
154- for ($ i = 0 ; $ i < $ header ->additionalCount ; $ i ++) {
155- $ additional [] = Record::decode ($ packet , $ offset );
156- }
165+ // --- Decode Additional Section ---
166+ $ additional = [];
167+ for ($ i = 0 ; $ i < $ header ->additionalCount ; $ i ++) {
168+ $ additional [] = Record::decode ($ packet , $ offset );
169+ }
157170
158- if ($ offset !== strlen ($ packet )) {
159- throw new \InvalidArgumentException ('Invalid packet length ' );
171+ if ($ offset !== strlen ($ packet )) {
172+ throw new DecodingException ('Invalid packet length ' );
173+ }
174+ } catch (DecodingException $ e ) {
175+ throw new PartialDecodingException ($ header , $ e ->getMessage (), $ e );
160176 }
161177
162178 return new self ($ header , $ questions , $ answers , $ authority , $ additional );
0 commit comments