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$
47 * @link      http://pear.php.net/package/Net_DNS2
48 * @since     File available since Release 0.6.0
49 *
50 */
51
52
53/**
54 * DNS Packet Header class
55 *
56 * This class handles parsing and constructing DNS Packet Headers as defined
57 * by section 4.1.1 of RFC1035.
58 *
59 *  DNS header format - RFC1035 section 4.1.1
60 *  DNS header format - RFC4035 section 3.2
61 *
62 *      0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
63 *    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
64 *    |                      ID                       |
65 *    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
66 *    |QR|   Opcode  |AA|TC|RD|RA| Z|AD|CD|   RCODE   |
67 *    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
68 *    |                    QDCOUNT                    |
69 *    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
70 *    |                    ANCOUNT                    |
71 *    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
72 *    |                    NSCOUNT                    |
73 *    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
74 *    |                    ARCOUNT                    |
75 *    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
76 *
77 * @category Networking
78 * @package  Net_DNS2
79 * @author   Mike Pultz <mike@mikepultz.com>
80 * @license  http://www.opensource.org/licenses/bsd-license.php  BSD License
81 * @link     http://pear.php.net/package/Net_DNS2
82 *
83 */
84class Net_DNS2_Header
85{
86    public $id;         // 16 bit - identifier
87    public $qr;         //  1 bit - 0 = query, 1 = response
88    public $opcode;     //  4 bit - op code
89    public $aa;         //  1 bit - Authoritative Answer
90    public $tc;         //  1 bit - TrunCation
91    public $rd;         //  1 bit - Recursion Desired
92    public $ra;         //  1 bit - Recursion Available
93    public $z;          //  1 bit - Reserved
94    public $ad;         //  1 bit - Authentic Data (RFC4035)
95    public $cd;         //  1 bit - Checking Disabled (RFC4035)
96    public $rcode;      //  4 bit - Response code
97    public $qdcount;    // 16 bit - entries in the question section
98    public $ancount;    // 16 bit - resource records in the answer section
99    public $nscount;    // 16 bit - name server rr in the authority records section
100    public $arcount;    // 16 bit - rr's in the additional records section
101
102    /**
103     * Constructor - builds a new Net_DNS2_Header object
104     *
105     * @param mixed &$packet either a Net_DNS2_Packet object or null
106     *
107     * @throws Net_DNS2_Exception
108     * @access public
109     *
110     */
111    public function __construct(Net_DNS2_Packet &$packet = null)
112    {
113        if (!is_null($packet)) {
114
115            $this->set($packet);
116        } else {
117
118            $this->id       = $this->nextPacketId();
119            $this->qr       = Net_DNS2_Lookups::QR_QUERY;
120            $this->opcode   = Net_DNS2_Lookups::OPCODE_QUERY;
121            $this->aa       = 0;
122            $this->tc       = 0;
123            $this->rd       = 1;
124            $this->ra       = 0;
125            $this->z        = 0;
126            $this->ad       = 0;
127            $this->cd       = 0;
128            $this->rcode    = Net_DNS2_Lookups::RCODE_NOERROR;
129            $this->qdcount  = 1;
130            $this->ancount  = 0;
131            $this->nscount  = 0;
132            $this->arcount  = 0;
133        }
134    }
135
136    /**
137     * returns the next available packet id
138     *
139     * @return    integer
140     * @access    public
141     *
142     */
143    public function nextPacketId()
144    {
145        if (++Net_DNS2_Lookups::$next_packet_id > 65535) {
146
147            Net_DNS2_Lookups::$next_packet_id = 1;
148        }
149
150        return Net_DNS2_Lookups::$next_packet_id;
151    }
152
153    /**
154     * magic __toString() method to return the header as a string
155     *
156     * @return    string
157     * @access    public
158     *
159     */
160    public function __toString()
161    {
162        $output = ";;\n;; Header:\n";
163
164        $output .= ";;\t id         = " . $this->id . "\n";
165        $output .= ";;\t qr         = " . $this->qr . "\n";
166        $output .= ";;\t opcode     = " . $this->opcode . "\n";
167        $output .= ";;\t aa         = " . $this->aa . "\n";
168        $output .= ";;\t tc         = " . $this->tc . "\n";
169        $output .= ";;\t rd         = " . $this->rd . "\n";
170        $output .= ";;\t ra         = " . $this->ra . "\n";
171        $output .= ";;\t z          = " . $this->z . "\n";
172        $output .= ";;\t ad         = " . $this->ad . "\n";
173        $output .= ";;\t cd         = " . $this->cd . "\n";
174        $output .= ";;\t rcode      = " . $this->rcode . "\n";
175        $output .= ";;\t qdcount    = " . $this->qdcount . "\n";
176        $output .= ";;\t ancount    = " . $this->ancount . "\n";
177        $output .= ";;\t nscount    = " . $this->nscount . "\n";
178        $output .= ";;\t arcount    = " . $this->arcount . "\n";
179
180        return $output;
181    }
182
183    /**
184     * constructs a Net_DNS2_Header from a Net_DNS2_Packet object
185     *
186     * @param Net_DNS2_Packet &$packet Object
187     *
188     * @return boolean
189     * @throws Net_DNS2_Exception
190     * @access public
191     *
192     */
193    public function set(Net_DNS2_Packet &$packet)
194    {
195        //
196        // the header must be at least 12 bytes long.
197        //
198        if ($packet->rdlength < Net_DNS2_Lookups::DNS_HEADER_SIZE) {
199
200            throw new Net_DNS2_Exception(
201                'invalid header data provided; to small',
202                Net_DNS2_Lookups::E_HEADER_INVALID
203            );
204        }
205
206        $offset = 0;
207
208        //
209        // parse the values
210        //
211        $this->id       = ord($packet->rdata[$offset]) << 8 |
212            ord($packet->rdata[++$offset]);
213
214        ++$offset;
215        $this->qr       = (ord($packet->rdata[$offset]) >> 7) & 0x1;
216        $this->opcode   = (ord($packet->rdata[$offset]) >> 3) & 0xf;
217        $this->aa       = (ord($packet->rdata[$offset]) >> 2) & 0x1;
218        $this->tc       = (ord($packet->rdata[$offset]) >> 1) & 0x1;
219        $this->rd       = ord($packet->rdata[$offset]) & 0x1;
220
221        ++$offset;
222        $this->ra       = (ord($packet->rdata[$offset]) >> 7) & 0x1;
223        $this->z        = (ord($packet->rdata[$offset]) >> 6) & 0x1;
224        $this->ad       = (ord($packet->rdata[$offset]) >> 5) & 0x1;
225        $this->cd       = (ord($packet->rdata[$offset]) >> 4) & 0x1;
226        $this->rcode    = ord($packet->rdata[$offset]) & 0xf;
227
228        $this->qdcount  = ord($packet->rdata[++$offset]) << 8 |
229            ord($packet->rdata[++$offset]);
230        $this->ancount  = ord($packet->rdata[++$offset]) << 8 |
231            ord($packet->rdata[++$offset]);
232        $this->nscount  = ord($packet->rdata[++$offset]) << 8 |
233            ord($packet->rdata[++$offset]);
234        $this->arcount  = ord($packet->rdata[++$offset]) << 8 |
235            ord($packet->rdata[++$offset]);
236
237        //
238        // increment the internal offset
239        //
240        $packet->offset += Net_DNS2_Lookups::DNS_HEADER_SIZE;
241
242        return true;
243    }
244
245    /**
246     * returns a binary packed DNS Header
247     *
248     * @param Net_DNS2_Packet &$packet Object
249     *
250     * @return    string
251     * @access    public
252     *
253     */
254    public function get(Net_DNS2_Packet &$packet)
255    {
256        $packet->offset += Net_DNS2_Lookups::DNS_HEADER_SIZE;
257
258        return pack('n', $this->id) .
259            chr(
260                ($this->qr << 7) | ($this->opcode << 3) |
261                ($this->aa << 2) | ($this->tc << 1) | ($this->rd)
262            ) .
263            chr(
264                ($this->ra << 7) | ($this->ad << 5) | ($this->cd << 4) | $this->rcode
265            ) .
266            pack('n4', $this->qdcount, $this->ancount, $this->nscount, $this->arcount);
267    }
268}
269
270/*
271 * Local variables:
272 * tab-width: 4
273 * c-basic-offset: 4
274 * c-hanging-comment-ender-p: nil
275 * End:
276 */
277?>
278