Hoa central
Resolver.php
Go to the documentation of this file.
1 <?php
2 
37 namespace Hoa\Dns;
38 
39 use Hoa\Core;
40 use Hoa\Socket;
41 
52 {
58  protected $_on = null;
59 
65  protected $_server = null;
66 
74  protected static $_types = [
75  'invalid' => 0, // Invalid.
76  'a' => 1, // Host address.
77  'ns' => 2, // Authorative name server.
78  'md' => 3, // Mail destination (obsolete, use MX).
79  'mf' => 4, // Mail forwarder (obsolete, use MX).
80  'cname' => 5, // Canonical name for an alias.
81  'soa' => 6, // Start of a zone of authority.
82  'mb' => 7, // Mailbox domain name.
83  'mg' => 8, // Mail group member.
84  'mr' => 9, // Mail rename name.
85  'null' => 10, // Null resource record.
86  'wks' => 11, // Well known service description.
87  'ptr' => 12, // Domain name pointer.
88  'hinfo' => 13, // Host information.
89  'minfo' => 14, // Mailbox or mail list information.
90  'mx' => 15, // Mail exchange.
91  'txt' => 16, // Text strings.
92  'rp' => 17, // Responsible person.
93  'afsdb' => 18, // AFS cell database.
94  'x25' => 19, // X_25 calling address.
95  'isdn' => 20, // ISDN calling address.
96  'rt' => 21, // Route through resource record.
97  'nsap' => 22, // NSAP address.
98  'ns_nsap_ptr' => 23, // Reverse NSAP lookup (deprecated).
99  'sig' => 24, // Security signature.
100  'key' => 25, // Security key resource record.
101  'px' => 26, // X.400 mail mapping.
102  'gpos' => 27, // Geographical position (withdrawn).
103  'aaaa' => 28, // IPv6 Address.
104  'loc' => 29, // Location Information.
105  'nxt' => 30, // Next domain.
106  'eid' => 31, // Endpoint identifier.
107  'nimloc' => 32, // Nimrod Locator.
108  'srv' => 33, // Server Selection.
109  'atma' => 34, // ATM Address.
110  'naptr' => 35, // Naming Authority pointer.
111  'kx' => 36, // Key Exchange.
112  'cert' => 37, // Certification Record.
113  'a6' => 38, // IPv6 Address (obsolete, use aaaa).
114  'dname' => 39, // Non-terminal DNAME (for IPv6).
115  'sink' => 40, // Kitchen sink.
116  'opt' => 41, // EDNS0 option (meta-RR).
117  'apl' => 42, // Address prefix list.
118  'ds' => 43, // Delegation Signer
119  'sshfp' => 44, // SSH Fingerprint
120  'ipseckey' => 45, // IPSEC Key
121  'rrsig' => 46, // RRSet Signature
122  'nsec' => 47, // Negative Security
123  'dnskey' => 48, // DNS Key
124  'dhcid' => 49, // Dynamic host configuration identifier
125  'nsec3' => 50, // Negative security type 3
126  'nsec3param' => 51, // Negative security type 3 parameters
127  'hip' => 55, // Host Identity Protocol
128  'spf' => 99, // Sender Policy Framework
129  'tkey' => 249, // Transaction key
130  'tsig' => 250, // Transaction signature.
131  'ixfr' => 251, // Incremental zone transfer.
132  'axfr' => 252, // Transfer zone of authority.
133  'mailb' => 253, // Transfer mailbox records.
134  'maila' => 254, // Transfer mail agent records.
135  'any' => 255, // Wildcard match.
136  'zxfr' => 256, // BIND-specific, nonstandard.
137  'dlv' => 32769, // DNSSEC look-aside validation.
138  'max' => 65536
139  ];
140 
146  protected static $_classes = [
147  'in' => 1, // Internet.
148  'cs' => 2, // CSNET (obsolete).
149  'ch' => 3, // Chaos.
150  'hs' => 4, // Hesiod.
151  'qnone' => 254, // QClass none.
152  'qany' => 255 // QClass any.
153  ];
154 
155 
156 
163  public function __construct(Socket\Server $server)
164  {
165  if ('udp' != $server->getSocket()->getTransport()) {
166  throw new Exception(
167  'Server must listen on UDP transport; given %s.',
168  0,
169  strtoupper($server->getSocket()->getTransport())
170  );
171  }
172 
173  set_time_limit(0);
174 
175  $this->_server = $server;
176  $this->_on = new Core\Event\Listener($this, ['query']);
177 
178  return;
179  }
180 
189  public function on($listenerId, $callable)
190  {
191  $this->_on->attach($listenerId, $callable);
192 
193  return $this;
194  }
195 
201  public function run()
202  {
203  $this->_server->considerRemoteAddress(true);
204  $this->_server->connectAndWait();
205 
206  while (true) {
207  $buffer = $this->_server->read(1024);
208 
209  if (empty($buffer)) {
210  continue;
211  }
212 
213  // Skip header.
214  $handle = substr($buffer, 12);
215  $domain = null;
216 
217  // QNAME.
218  for ($i = 0, $m = strlen($handle); $i < $m; ++$i) {
219  if (0 === $length = ord($handle[$i])) {
220  break;
221  }
222 
223  if (null !== $domain) {
224  $domain .= '.';
225  }
226 
227  $domain .= substr($handle, $i + 1, $length);
228  $i += $length;
229  }
230 
231  // QTYPE.
232  $i += 2;
233  $qtype = (int) (string) ord($handle[$i]) +
234  (int) (string) ord($handle[$i + 1]);
235  $type = array_search($qtype, static::$_types) ?: $qtype;
236 
237  // QCLASS.
238  $i += 2;
239  $qclass = (int) (string) ord($handle[$i]);
240  $class = array_search($qclass, static::$_classes) ?: $qclass;
241 
242  $ips = $this->_on->fire('query', new Core\Event\Bucket([
243  'domain' => $domain,
244  'type' => $type,
245  'class' => $class
246  ]));
247  $ip = null;
248 
249  if (false === $ips[0]) {
250  $this->_server->writeAll(
251  // Header.
252 
253  // ID.
254  $buffer[0] .
255  $buffer[1] .
256  pack(
257  'C',
258  1 << 7 // QR, 1 = response.
259  // OpCode, 0 = QUERY.
260  // AA, 0
261  // TC, 0
262  | 1 // RD
263  ) .
264  pack(
265  'C',
266  0 // RA, Z, AD, CD.
267  | 3 // NXDOMAIN.
268  ) .
269  // QDCOUNT.
270  pack('n', 0) .
271  // ANCOUNT.
272  pack('n', 0) .
273  // NSCOUNT.
274  pack('n', 0) .
275  // ARCOUNT.
276  pack('n', 0)
277  );
278 
279  continue;
280  }
281 
282  foreach (explode('.', $ips[0]) as $foo) {
283  $ip .= pack('C', $foo);
284  }
285 
286  $this->_server->writeAll(
287  // Header.
288 
289  // ID.
290  $buffer[0] .
291  $buffer[1] .
292  pack(
293  'C',
294  1 << 7 // QR, 1 = response.
295  // OpCode, 0 = QUERY.
296  // AA, 0
297  // TC, 0
298  | 1 // RD
299  ) .
300  pack(
301  'C',
302  0 // RA, Z, AD, CD.
303  ) .
304  // QDCOUNT.
305  $buffer[4] .
306  $buffer[5] .
307  // ANCOUNT.
308  pack('n', 1) .
309  // NSCOUNT.
310  pack('n', 0) .
311  // ARCOUNT.
312  pack('n', 0) .
313 
314  // Question.
315 
316  $handle .
317  pack('CC', 192, 12) .
318 
319  // Answer.
320 
321  // TYPE.
322  pack('n', $qtype) .
323  // CLASS.
324  pack('n', $qclass) .
325  // TTL.
326  pack('N', 60) .
327  // RDLENGTH.
328  pack('n', 4) .
329  // RDATA.
330  $ip
331  );
332  }
333 
334  $this->_server->disconnect();
335 
336  return;
337  }
338 }
static __construct(Socket\Server $server)
Definition: Resolver.php:163
on($listenerId, $callable)
Definition: Resolver.php:189
static $_types
Definition: Resolver.php:74
static $_classes
Definition: Resolver.php:146