~ubuntu-branches/ubuntu/utopic/php-net-dns2/utopic-proposed

« back to all changes in this revision

Viewing changes to Net_DNS2-1.3.2/Net/DNS2/RR.php

  • Committer: Package Import Robot
  • Author(s): Mathieu Parent
  • Date: 2014-02-21 16:59:58 UTC
  • Revision ID: package-import@ubuntu.com-20140221165958-tyc92gchfhho9660
Tags: upstream-1.3.2
ImportĀ upstreamĀ versionĀ 1.3.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 188 2013-03-31 01:25:46Z 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
 */
 
92
abstract 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_class($this)];
 
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
 
 
313
        //
 
314
        // for RR OPT (41), the class value includes the requestors UDP payload size,
 
315
        // and not a class value
 
316
        //
 
317
        if ($this->type == 'OPT') {
 
318
            $this->class = $rr['class'];
 
319
        } else {
 
320
            $this->class = Net_DNS2_Lookups::$classes_by_id[$rr['class']];
 
321
        }
 
322
 
 
323
        $this->ttl      = $rr['ttl'];
 
324
        $this->rdlength = $rr['rdlength'];
 
325
        $this->rdata    = substr($packet->rdata, $packet->offset, $rr['rdlength']);
 
326
 
 
327
        return $this->rrSet($packet);
 
328
    }
 
329
 
 
330
    /**
 
331
     * returns a binary packed DNS RR object
 
332
     *
 
333
     * @param Net_DNS2_Packet &$packet a Net_DNS2_Packet packet used for 
 
334
     *                                 compressing names
 
335
     *
 
336
     * @return string
 
337
     * @throws Net_DNS2_Exception
 
338
     * @access public
 
339
     *
 
340
     */
 
341
    public function get(Net_DNS2_Packet &$packet)
 
342
    {
 
343
        $data  = '';
 
344
        $rdata = '';
 
345
 
 
346
        //
 
347
        // pack the name
 
348
        //
 
349
        $data = $packet->compress($this->name, $packet->offset);
 
350
 
 
351
        //
 
352
        // pack the main values
 
353
        //
 
354
        if ($this->type == 'OPT') {
 
355
 
 
356
            //
 
357
            // pre-build the TTL value
 
358
            //
 
359
            $this->preBuild();
 
360
 
 
361
            //
 
362
            // the class value is different for OPT types
 
363
            //
 
364
            $data .= pack(
 
365
                'nnN', 
 
366
                Net_DNS2_Lookups::$rr_types_by_name[$this->type],
 
367
                $this->class,
 
368
                $this->ttl
 
369
            );
 
370
        } else {
 
371
 
 
372
            $data .= pack(
 
373
                'nnN', 
 
374
                Net_DNS2_Lookups::$rr_types_by_name[$this->type],
 
375
                Net_DNS2_Lookups::$classes_by_name[$this->class],
 
376
                $this->ttl
 
377
            );
 
378
        }
 
379
 
 
380
        //
 
381
        // increase the offset, and allow for the rdlength
 
382
        //
 
383
        $packet->offset += 10;
 
384
 
 
385
        //
 
386
        // get the RR specific details
 
387
        //
 
388
        if ($this->rdlength != -1) {
 
389
 
 
390
            $rdata = $this->rrGet($packet);
 
391
        }
 
392
 
 
393
        //
 
394
        // add the RR
 
395
        //
 
396
        $data .= pack('n', strlen($rdata)) . $rdata;
 
397
 
 
398
        return $data;
 
399
    }
 
400
 
 
401
    /**
 
402
     * parses a binary packet, and returns the appropriate Net_DNS2_RR object, 
 
403
     * based on the RR type of the binary content.
 
404
     *
 
405
     * @param Net_DNS2_Packet &$packet a Net_DNS2_Packet packet used for 
 
406
     *                                 decompressing names
 
407
     *
 
408
     * @return mixed                   returns a new Net_DNS2_RR_* object for
 
409
     *                                 the given RR
 
410
     * @throws Net_DNS2_Exception
 
411
     * @access public
 
412
     *
 
413
     */
 
414
    public static function parse(Net_DNS2_Packet &$packet)
 
415
    {
 
416
        $object = array();
 
417
 
 
418
        //
 
419
        // expand the name
 
420
        //
 
421
        $object['name'] = $packet->expand($packet, $packet->offset);
 
422
        if (is_null($object['name'])) {
 
423
 
 
424
            throw new Net_DNS2_Exception(
 
425
                'failed to parse resource record: failed to expand name.',
 
426
                Net_DNS2_Lookups::E_PARSE_ERROR
 
427
            );
 
428
        }
 
429
        if ($packet->rdlength < ($packet->offset + 10)) {
 
430
 
 
431
            throw new Net_DNS2_Exception(
 
432
                'failed to parse resource record: packet too small.',
 
433
                Net_DNS2_Lookups::E_PARSE_ERROR
 
434
            );
 
435
        }
 
436
 
 
437
        //
 
438
        // unpack the RR details
 
439
        //
 
440
        $object['type']     = ord($packet->rdata[$packet->offset++]) << 8 | 
 
441
                                ord($packet->rdata[$packet->offset++]);
 
442
        $object['class']    = ord($packet->rdata[$packet->offset++]) << 8 | 
 
443
                                ord($packet->rdata[$packet->offset++]);
 
444
 
 
445
        $object['ttl']      = ord($packet->rdata[$packet->offset++]) << 24 | 
 
446
                                ord($packet->rdata[$packet->offset++]) << 16 | 
 
447
                                ord($packet->rdata[$packet->offset++]) << 8 | 
 
448
                                ord($packet->rdata[$packet->offset++]);
 
449
 
 
450
        $object['rdlength'] = ord($packet->rdata[$packet->offset++]) << 8 | 
 
451
                                ord($packet->rdata[$packet->offset++]);
 
452
 
 
453
        if ($packet->rdlength < ($packet->offset + $object['rdlength'])) {
 
454
            return null;
 
455
        }
 
456
 
 
457
        //
 
458
        // lookup the class to use
 
459
        //
 
460
        $o      = null;
 
461
        $class  = Net_DNS2_Lookups::$rr_types_id_to_class[$object['type']];
 
462
 
 
463
        if (isset($class)) {
 
464
 
 
465
            $o = new $class($packet, $object);
 
466
            if ($o) {
 
467
 
 
468
                $packet->offset += $object['rdlength'];
 
469
            }
 
470
        } else {
 
471
 
 
472
            throw new Net_DNS2_Exception(
 
473
                'un-implemented resource record type: ' . $object['type'],
 
474
                Net_DNS2_Lookups::E_RR_INVALID
 
475
            );
 
476
        }
 
477
 
 
478
        return $o;
 
479
    }
 
480
 
 
481
    /**
 
482
     * cleans up some RR data
 
483
     * 
 
484
     * @param string $data the text string to clean
 
485
     *
 
486
     * @return string returns the cleaned string
 
487
     *
 
488
     * @access public
 
489
     *
 
490
     */
 
491
    public function cleanString($data)
 
492
    {
 
493
        return strtolower(rtrim($data, '.'));
 
494
    }
 
495
 
 
496
    /**
 
497
     * parses a standard RR format lines, as defined by rfc1035 (kinda)
 
498
     *
 
499
     * In our implementation, the domain *must* be specified- format must be
 
500
     *
 
501
     *        <name> [<ttl>] [<class>] <type> <rdata>
 
502
     * or
 
503
     *        <name> [<class>] [<ttl>] <type> <rdata>
 
504
     *
 
505
     * name, title, class and type are parsed by this function, rdata is passed
 
506
     * to the RR specific classes for parsing.
 
507
     *
 
508
     * @param string $line a standard DNS config line 
 
509
     *
 
510
     * @return mixed       returns a new Net_DNS2_RR_* object for the given RR
 
511
     * @throws Net_DNS2_Exception
 
512
     * @access public
 
513
     *
 
514
     */
 
515
    public static function fromString($line)
 
516
    {
 
517
        if (strlen($line) == 0) {
 
518
            throw new Net_DNS2_Exception(
 
519
                'empty config line provided.',
 
520
                Net_DNS2_Lookups::E_PARSE_ERROR
 
521
            );
 
522
        }
 
523
 
 
524
        $name   = '';
 
525
        $type   = '';
 
526
        $class  = 'IN';
 
527
        $ttl    = 86400;
 
528
 
 
529
        //
 
530
        // split the line by spaces
 
531
        //
 
532
        $values = preg_split('/[\s]+/', $line);
 
533
        if (count($values) < 3) {
 
534
 
 
535
            throw new Net_DNS2_Exception(
 
536
                'failed to parse config: minimum of name, type and rdata required.',
 
537
                Net_DNS2_Lookups::E_PARSE_ERROR
 
538
            );
 
539
        }
 
540
 
 
541
        //
 
542
        // assume the first value is the name
 
543
        //
 
544
        $name = trim(strtolower(array_shift($values)), '.');
 
545
 
 
546
        //
 
547
        // The next value is either a TTL, Class or Type
 
548
        //
 
549
        foreach ($values as $value) {
 
550
 
 
551
            switch($value) {
 
552
            case is_numeric($value):
 
553
 
 
554
                $ttl = array_shift($values);
 
555
                break;
 
556
 
 
557
            //
 
558
            // PHP SUCKS!
 
559
            //
 
560
            case ($value === 0):
 
561
                $ttl = array_shift($values);
 
562
                break;
 
563
 
 
564
            case isset(Net_DNS2_Lookups::$classes_by_name[strtoupper($value)]):
 
565
 
 
566
                $class = strtoupper(array_shift($values));
 
567
                break;
 
568
 
 
569
            case isset(Net_DNS2_Lookups::$rr_types_by_name[strtoupper($value)]):
 
570
 
 
571
                $type = strtoupper(array_shift($values));
 
572
                break 2;
 
573
                break;   
 
574
            default:
 
575
 
 
576
                throw new Net_DNS2_Exception(
 
577
                    'invalid config line provided: unknown file: ' . $value,
 
578
                    Net_DNS2_Lookups::E_PARSE_ERROR
 
579
                );
 
580
            }
 
581
        }
 
582
 
 
583
        //
 
584
        // lookup the class to use
 
585
        //
 
586
        $o = null;
 
587
        $class_name = Net_DNS2_Lookups::$rr_types_id_to_class[
 
588
            Net_DNS2_Lookups::$rr_types_by_name[$type]
 
589
        ];
 
590
 
 
591
        if (isset($class_name)) {
 
592
 
 
593
            $o = new $class_name;
 
594
            if (!is_null($o)) {
 
595
 
 
596
                //
 
597
                // set the parsed values
 
598
                //
 
599
                $o->name    = $name;
 
600
                $o->class   = $class;
 
601
                $o->ttl     = $ttl;
 
602
 
 
603
                //
 
604
                // parse the rdata
 
605
                //
 
606
                if ($o->rrFromString($values) === false) {
 
607
 
 
608
                    throw new Net_DNS2_Exception(
 
609
                        'failed to parse rdata for config: ' . $line,
 
610
                        Net_DNS2_Lookups::E_PARSE_ERROR
 
611
                    );
 
612
                }
 
613
 
 
614
            } else {
 
615
 
 
616
                throw new Net_DNS2_Exception(
 
617
                    'failed to create new RR record for type: ' . $type,
 
618
                    Net_DNS2_Lookups::E_RR_INVALID
 
619
                );
 
620
            }
 
621
 
 
622
        } else {
 
623
 
 
624
            throw new Net_DNS2_Exception(
 
625
                'un-implemented resource record type: '. $type,
 
626
                Net_DNS2_Lookups::E_RR_INVALID
 
627
            );
 
628
        }
 
629
 
 
630
        return $o;
 
631
    }
 
632
}
 
633
 
 
634
/*
 
635
 * Local variables:
 
636
 * tab-width: 4
 
637
 * c-basic-offset: 4
 
638
 * c-hanging-comment-ender-p: nil
 
639
 * End:
 
640
 */
 
641
?>