PageRenderTime 106ms CodeModel.GetById 31ms app.highlight 30ms RepoModel.GetById 40ms app.codeStats 0ms

/htdocs/includes/net/dns2/rr.php

https://bitbucket.org/speedealing/speedealing
PHP | 612 lines | 233 code | 81 blank | 298 comment | 34 complexity | 892283c383a26716d279336bf678012c MD5 | raw file
  1<?php
  2/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
  3
  4/**
  5 * DNS Library for handling lookups and updates. 
  6 *
  7 * PHP Version 5
  8 *
  9 * Copyright (c) 2010, Mike Pultz <mike@mikepultz.com>.
 10 * All rights reserved.
 11 *
 12 * Redistribution and use in source and binary forms, with or without
 13 * modification, are permitted provided that the following conditions
 14 * are met:
 15 *
 16 *   * Redistributions of source code must retain the above copyright
 17 *     notice, this list of conditions and the following disclaimer.
 18 *
 19 *   * Redistributions in binary form must reproduce the above copyright
 20 *     notice, this list of conditions and the following disclaimer in
 21 *     the documentation and/or other materials provided with the
 22 *     distribution.
 23 *
 24 *   * Neither the name of Mike Pultz nor the names of his contributors 
 25 *     may be used to endorse or promote products derived from this 
 26 *     software without specific prior written permission.
 27 *
 28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 31 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 32 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 33 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 34 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 35 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 36 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC
 37 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 38 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 39 * POSSIBILITY OF SUCH DAMAGE.
 40 *
 41 * @category  Networking
 42 * @package   Net_DNS2
 43 * @author    Mike Pultz <mike@mikepultz.com>
 44 * @copyright 2010 Mike Pultz <mike@mikepultz.com>
 45 * @license   http://www.opensource.org/licenses/bsd-license.php  BSD License
 46 * @version   SVN: $Id: RR.php 154 2012-04-23 16:36:34Z mike.pultz $
 47 * @link      http://pear.php.net/package/Net_DNS2
 48 * @since     File available since Release 0.6.0
 49 *
 50 */
 51
 52
 53/**
 54 * This is the base class for DNS Resource Records
 55 *
 56 * Each resource record type (defined in RR/*.php) extends this class for
 57 * base functionality.
 58 *
 59 * This class handles parsing and constructing the common parts of the DNS
 60 * resource records, while the RR specific functionality is handled in each
 61 * child class.
 62 *
 63 * DNS resource record format - RFC1035 section 4.1.3
 64 *
 65 *      0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
 66 *    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
 67 *    |                                               |
 68 *    /                                               /
 69 *    /                      NAME                     /
 70 *    |                                               |
 71 *    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
 72 *    |                      TYPE                     |
 73 *    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
 74 *    |                     CLASS                     |
 75 *    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
 76 *    |                      TTL                      |
 77 *    |                                               |
 78 *    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
 79 *    |                   RDLENGTH                    |
 80 *    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
 81 *    /                     RDATA                     /
 82 *    /                                               /
 83 *    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
 84 *
 85 * @category Networking
 86 * @package  Net_DNS2
 87 * @author   Mike Pultz <mike@mikepultz.com>
 88 * @license  http://www.opensource.org/licenses/bsd-license.php  BSD License
 89 * @link     http://pear.php.net/package/Net_DNS2
 90 *
 91 */
 92abstract class Net_DNS2_RR
 93{
 94    /*
 95     * The name of the resource record
 96     */
 97    public $name;
 98
 99    /*
100     * The resource record type
101     */
102    public $type;
103
104    /*
105     * The resouce record class
106     */
107    public $class;
108
109    /*
110     * The time to live for this resource record
111     */
112    public $ttl;
113
114    /*
115     * The length of the rdata field
116     */
117    public $rdlength;
118
119    /*
120     * The resource record specific data as a packed binary string
121     */
122    public $rdata;
123
124    /**
125     * abstract definition - method to return a RR as a string; not to 
126     * be confused with the __toString() magic method.
127     *
128     * @return string
129     * @access protected
130     *
131     */
132    abstract protected function rrToString();
133
134    /**
135     * abstract definition - parses a RR from a standard DNS config line
136     *
137     * @param array $rdata a string split line of values for the rdata
138     *
139     * @return boolean
140     * @access protected
141     *
142     */
143    abstract protected function rrFromString(array $rdata);
144
145    /**
146     * abstract definition - sets a Net_DNS2_RR from a Net_DNS2_Packet object
147     *
148     * @param Net_DNS2_Packet &$packet a Net_DNS2_Packet packet to parse the RR from
149     *
150     * @return boolean
151     * @access protected
152     *
153     */
154    abstract protected function rrSet(Net_DNS2_Packet &$packet);
155
156    /**
157     * abstract definition - returns a binary packet DNS RR object
158     *
159     * @param Net_DNS2_Packet &$packet a Net_DNS2_Packet packet use for 
160     *                                 compressed names
161     *
162     * @return mixed                   either returns a binary packed string or 
163     *                                 null on failure
164     * @access protected
165     *
166     */
167    abstract protected function rrGet(Net_DNS2_Packet &$packet);
168
169    /**
170     * Constructor - builds a new Net_DNS2_RR object
171     *
172     * @param Net_DNS2_Packet &$packet a Net_DNS2_Packet packet or null to create 
173     *                                 an empty object
174     * @param array           $rr      an array with RR parse values or null to 
175     *                                 create an empty object
176     *
177     * @throws Net_DNS2_Exception
178     * @access public
179     *
180     */
181    public function __construct(Net_DNS2_Packet &$packet = null, array $rr = null)
182    {
183        if ( (!is_null($packet)) && (!is_null($rr)) ) {
184
185            if ($this->set($packet, $rr) == false) {
186
187                throw new Net_DNS2_Exception(
188                    'failed to generate resource record',
189                    Net_DNS2_Lookups::E_RR_INVALID
190                );
191            }
192        } else {
193
194            $class = Net_DNS2_Lookups::$rr_types_class_to_id[get_called_class()];
195            if (isset($class)) {
196
197                $this->type = Net_DNS2_Lookups::$rr_types_by_id[$class];
198            }
199
200            $this->class    = 'IN';
201            $this->ttl      = 86400;
202        }
203    }
204
205    /**
206     * magic __toString() method to return the Net_DNS2_RR object object as a string
207     *
208     * @return string
209     * @access public
210     *
211     */
212    public function __toString()
213    {
214        return $this->name . '. ' . $this->ttl . ' ' . $this->class . 
215            ' ' . $this->type . ' ' . $this->rrToString();
216    }
217
218    /**
219     * return a formatted string; if a string has spaces in it, then return 
220     * it with double quotes around it, otherwise, return it as it was passed in.
221     *
222     * @param string $string the string to format
223     *
224     * @return string
225     * @access protected
226     *
227     */
228    protected function formatString($string)
229    {
230        return '"' . str_replace('"', '\"', trim($string, '"')) . '"';
231    }
232    
233    /**
234     * builds an array of strings from an array of chunks of text split by spaces
235     *
236     * @param array $chunks an array of chunks of text split by spaces
237     *
238     * @return array
239     * @access protected
240     *
241     */
242    protected function buildString(array $chunks)
243    {
244        $data = array();
245        $c = 0;
246        $in = false;
247
248        foreach ($chunks as $r) {
249
250            $r = trim($r);
251            if (strlen($r) == 0) {
252                continue;
253            }
254
255            if ( ($r[0] == '"')
256                && ($r[strlen($r) - 1] == '"')
257                && ($r[strlen($r) - 2] != '\\')
258            ) {
259
260                $data[$c] = $r;
261                ++$c;
262                $in = false;
263
264            } else if ($r[0] == '"') {
265
266                $data[$c] = $r;
267                $in = true;
268
269            } else if ( ($r[strlen($r) - 1] == '"')
270                && ($r[strlen($r) - 2] != '\\')
271            ) {
272            
273                $data[$c] .= ' ' . $r;
274                ++$c;  
275                $in = false;
276
277            } else {
278
279                if ($in == true) {
280                    $data[$c] .= ' ' . $r;
281                } else {
282                    $data[$c++] = $r;
283                }
284            }
285        }        
286
287        foreach ($data as $index => $string) {
288            
289            $data[$index] = str_replace('\"', '"', trim($string, '"'));
290        }
291
292        return $data;
293    }
294
295    /**
296     * builds a new Net_DNS2_RR object
297     *
298     * @param Net_DNS2_Packet &$packet a Net_DNS2_Packet packet or null to create
299     *                                 an empty object
300     * @param array           $rr      an array with RR parse values or null to 
301     *                                 create an empty object
302     *
303     * @return boolean
304     * @throws Net_DNS2_Exception
305     * @access public
306     *
307     */
308    public function set(Net_DNS2_Packet &$packet, array $rr)
309    {
310        $this->name     = $rr['name'];
311        $this->type     = Net_DNS2_Lookups::$rr_types_by_id[$rr['type']];
312        $this->class    = Net_DNS2_Lookups::$classes_by_id[$rr['class']];
313        $this->ttl      = $rr['ttl'];
314        $this->rdlength = $rr['rdlength'];
315        $this->rdata    = substr($packet->rdata, $packet->offset, $rr['rdlength']);
316
317        return $this->rrSet($packet);
318    }
319
320    /**
321     * returns a binary packed DNS RR object
322     *
323     * @param Net_DNS2_Packet &$packet a Net_DNS2_Packet packet used for 
324     *                                 compressing names
325     *
326     * @return string
327     * @throws Net_DNS2_Exception
328     * @access public
329     *
330     */
331    public function get(Net_DNS2_Packet &$packet)
332    {
333        $data  = '';
334        $rdata = '';
335
336        //
337        // pack the name
338        //
339        $data = $packet->compress($this->name, $packet->offset);
340
341        //
342        // pack the main values
343        //
344        $data .= pack(
345            'nnN', 
346            Net_DNS2_Lookups::$rr_types_by_name[$this->type],
347            Net_DNS2_Lookups::$classes_by_name[$this->class],
348            $this->ttl
349        );
350
351        //
352        // increase the offset, and allow for the rdlength
353        //
354        $packet->offset += 10;
355
356        //
357        // get the RR specific details
358        //
359        if ($this->rdlength != -1) {
360
361            $rdata = $this->rrGet($packet);
362        }
363
364        //
365        // add the RR
366        //
367        $data .= pack('n', strlen($rdata)) . $rdata;
368
369        return $data;
370    }
371
372    /**
373     * parses a binary packet, and returns the appropriate Net_DNS2_RR object, 
374     * based on the RR type of the binary content.
375     *
376     * @param Net_DNS2_Packet &$packet a Net_DNS2_Packet packet used for 
377     *                                 decompressing names
378     *
379     * @return mixed                   returns a new Net_DNS2_RR_* object for
380     *                                 the given RR
381     * @throws Net_DNS2_Exception
382     * @access public
383     *
384     */
385    public static function parse(Net_DNS2_Packet &$packet)
386    {
387        $object = array();
388
389        //
390        // expand the name
391        //
392        $object['name'] = $packet->expand($packet, $packet->offset);
393        if (is_null($object['name'])) {
394
395            throw new Net_DNS2_Exception(
396                'failed to parse resource record: failed to expand name.',
397                Net_DNS2_Lookups::E_PARSE_ERROR
398            );
399        }
400        if ($packet->rdlength < ($packet->offset + 10)) {
401
402            throw new Net_DNS2_Exception(
403                'failed to parse resource record: packet too small.',
404                Net_DNS2_Lookups::E_PARSE_ERROR
405            );
406        }
407
408        //
409        // unpack the RR details
410        //
411        $object['type']     = ord($packet->rdata[$packet->offset++]) << 8 | 
412                                ord($packet->rdata[$packet->offset++]);
413        $object['class']    = ord($packet->rdata[$packet->offset++]) << 8 | 
414                                ord($packet->rdata[$packet->offset++]);
415
416        $object['ttl']      = ord($packet->rdata[$packet->offset++]) << 24 | 
417                                ord($packet->rdata[$packet->offset++]) << 16 | 
418                                ord($packet->rdata[$packet->offset++]) << 8 | 
419                                ord($packet->rdata[$packet->offset++]);
420
421        $object['rdlength'] = ord($packet->rdata[$packet->offset++]) << 8 | 
422                                ord($packet->rdata[$packet->offset++]);
423
424        if ($packet->rdlength < ($packet->offset + $object['rdlength'])) {
425            return null;
426        }
427
428        //
429        // lookup the class to use
430        //
431        $o         = null;
432        $class     = Net_DNS2_Lookups::$rr_types_id_to_class[$object['type']];
433
434        if (isset($class)) {
435
436            $o = new $class($packet, $object);
437            if ($o) {
438
439                $packet->offset += $object['rdlength'];
440            }
441        } else {
442
443            throw new Net_DNS2_Exception(
444                'un-implemented resource record type: ' . $object['type'],
445                Net_DNS2_Lookups::E_RR_INVALID
446            );
447        }
448
449        return $o;
450    }
451
452    /**
453     * cleans up some RR data
454     * 
455     * @param string $data the text string to clean
456     *
457     * @return string returns the cleaned string
458     *
459     * @access public
460     *
461     */
462    public function cleanString($data)
463    {
464        return strtolower(rtrim($data, '.'));
465    }
466
467    /**
468     * parses a standard RR format lines, as defined by rfc1035 (kinda)
469     *
470     * In our implementation, the domain *must* be specified- format must be
471     *
472     *        <name> [<ttl>] [<class>] <type> <rdata>
473     * or
474     *        <name> [<class>] [<ttl>] <type> <rdata>
475     *
476     * name, title, class and type are parsed by this function, rdata is passed
477     * to the RR specific classes for parsing.
478     *
479     * @param string $line a standard DNS config line 
480     *
481     * @return mixed       returns a new Net_DNS2_RR_* object for the given RR
482     * @throws Net_DNS2_Exception
483     * @access public
484     *
485     */
486    public static function fromString($line)
487    {
488        if (strlen($line) == 0) {
489            throw new Net_DNS2_Exception(
490                'empty config line provided.',
491                Net_DNS2_Lookups::E_PARSE_ERROR
492            );
493        }
494
495        $name   = '';
496        $type   = '';
497        $class  = 'IN';
498        $ttl    = 86400;
499
500        //
501        // split the line by spaces
502        //
503        $values = preg_split('/[\s]+/', $line);
504        if (count($values) < 3) {
505
506            throw new Net_DNS2_Exception(
507                'failed to parse config: minimum of name, type and rdata required.',
508                Net_DNS2_Lookups::E_PARSE_ERROR
509            );
510        }
511
512        //
513        // assume the first value is the name
514        //
515        $name = trim(strtolower(array_shift($values)), '.');
516
517        //
518        // The next value is either a TTL, Class or Type
519        //
520        foreach ($values as $value) {
521
522            switch($value) {
523            case is_numeric($value):
524
525                $ttl = array_shift($values);
526                break;
527
528            //
529            // PHP SUCKS!
530            //
531            case ($value === 0):
532                $ttl = array_shift($values);
533                break;
534
535            case isset(Net_DNS2_Lookups::$classes_by_name[strtoupper($value)]):
536
537                $class = strtoupper(array_shift($values));
538                break;
539
540            case isset(Net_DNS2_Lookups::$rr_types_by_name[strtoupper($value)]):
541
542                $type = strtoupper(array_shift($values));
543                break 2;
544                break;   
545            default:
546
547                throw new Net_DNS2_Exception(
548                    'invalid config line provided: unknown file: ' . $value,
549                    Net_DNS2_Lookups::E_PARSE_ERROR
550                );
551            }
552        }
553
554        //
555        // lookup the class to use
556        //
557        $o = null;
558        $class_name = Net_DNS2_Lookups::$rr_types_id_to_class[
559            Net_DNS2_Lookups::$rr_types_by_name[$type]
560        ];
561
562        if (isset($class_name)) {
563
564            $o = new $class_name;
565            if (!is_null($o)) {
566
567                //
568                // set the parsed values
569                //
570                $o->name    = $name;
571                $o->class   = $class;
572                $o->ttl     = $ttl;
573
574                //
575                // parse the rdata
576                //
577                if ($o->rrFromString($values) === false) {
578
579                    throw new Net_DNS2_Exception(
580                        'failed to parse rdata for config: ' . $line,
581                        Net_DNS2_Lookups::E_PARSE_ERROR
582                    );
583                }
584
585            } else {
586
587                throw new Net_DNS2_Exception(
588                    'failed to create new RR record for type: ' . $type,
589                    Net_DNS2_Lookups::E_RR_INVALID
590                );
591            }
592
593        } else {
594
595            throw new Net_DNS2_Exception(
596                'un-implemented resource record type: '. $type,
597                Net_DNS2_Lookups::E_RR_INVALID
598            );
599        }
600
601        return $o;
602    }
603}
604
605/*
606 * Local variables:
607 * tab-width: 4
608 * c-basic-offset: 4
609 * c-hanging-comment-ender-p: nil
610 * End:
611 */
612?>