Passed
Push — master ( 1b54b9...ff455f )
by Sam
10:10 queued 11s
created

TSIG::fromWire()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 26
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 18
CRAP Score 2.0005

Importance

Changes 0
Metric Value
cc 2
eloc 18
nc 2
nop 3
dl 0
loc 26
ccs 18
cts 19
cp 0.9474
crap 2.0005
rs 9.6666
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of Badcow DNS Library.
7
 *
8
 * (c) Samuel Williams <[email protected]>
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Badcow\DNS\Rdata;
15
16
use Badcow\DNS\Message;
17
use Badcow\DNS\Parser\ParseException;
18
use Badcow\DNS\Parser\Tokens;
19
use Badcow\DNS\Rcode;
20
use Badcow\DNS\Validator;
21
22
/**
23
 * {@link https://tools.ietf.org/html/rfc2845}.
24
 */
25
class TSIG implements RdataInterface
26
{
27
    use RdataTrait;
28
29
    const TYPE = 'TSIG';
30
    const TYPE_CODE = 250;
31
32
    /**
33
     * Name of the algorithm in domain name syntax.
34
     *
35
     * @var string
36
     */
37
    private $algorithmName;
38
39
    /**
40
     * @var \DateTime
41
     */
42
    private $timeSigned;
43
44
    /**
45
     * Seconds of error permitted in time signed.
46
     *
47
     * @var int
48
     */
49
    private $fudge;
50
51
    /**
52
     * Message authentication code.
53
     *
54
     * @var string
55
     */
56
    private $mac;
57
58
    /**
59
     * @var int
60
     */
61
    private $originalId;
62
63
    /**
64
     * @var int
65
     */
66
    private $error = Rcode::NOERROR;
67
68
    /**
69
     * @var string
70
     */
71
    private $otherData;
72
73
    /**
74
     * @return string
75
     */
76 2
    public function getAlgorithmName(): string
77
    {
78 2
        return $this->algorithmName;
79
    }
80
81
    /**
82
     * @param string $algorithmName
83
     */
84 4
    public function setAlgorithmName(string $algorithmName): void
85
    {
86 4
        if (!Validator::fullyQualifiedDomainName($algorithmName)) {
87
            throw new \InvalidArgumentException('Algorithm name must be in the form of a fully qualified domain name.');
88
        }
89
90 4
        $this->algorithmName = $algorithmName;
91 4
    }
92
93
    /**
94
     * @return \DateTime
95
     */
96 2
    public function getTimeSigned(): \DateTime
97
    {
98 2
        return $this->timeSigned;
99
    }
100
101
    /**
102
     * @param \DateTime $timeSigned
103
     */
104 4
    public function setTimeSigned(\DateTime $timeSigned): void
105
    {
106 4
        $this->timeSigned = $timeSigned;
107 4
    }
108
109
    /**
110
     * @return int
111
     */
112 2
    public function getFudge(): int
113
    {
114 2
        return $this->fudge;
115
    }
116
117
    /**
118
     * @param int $fudge
119
     */
120 4
    public function setFudge(int $fudge): void
121
    {
122 4
        if (!Validator::isUnsignedInteger($fudge, 16)) {
123
            throw new \InvalidArgumentException(sprintf('Fudge must be an unsigned 16-bit integer, "%d" given.', $fudge));
124
        }
125 4
        $this->fudge = $fudge;
126 4
    }
127
128
    /**
129
     * @return string
130
     */
131 2
    public function getMac(): string
132
    {
133 2
        return $this->mac;
134
    }
135
136
    /**
137
     * @param string $mac
138
     */
139 4
    public function setMac(string $mac): void
140
    {
141 4
        $this->mac = $mac;
142 4
    }
143
144
    /**
145
     * @return int
146
     */
147 2
    public function getOriginalId(): int
148
    {
149 2
        return $this->originalId;
150
    }
151
152
    /**
153
     * @param int $originalId
154
     */
155 4
    public function setOriginalId(int $originalId): void
156
    {
157 4
        if (!Validator::isUnsignedInteger($originalId, 16)) {
158
            throw new \InvalidArgumentException(sprintf('Original ID must be an unsigned 16-bit integer, "%d" given.', $originalId));
159
        }
160 4
        $this->originalId = $originalId;
161 4
    }
162
163
    /**
164
     * @return int
165
     */
166 2
    public function getError(): int
167
    {
168 2
        return $this->error;
169
    }
170
171
    /**
172
     * @param int $error
173
     */
174 4
    public function setError(int $error): void
175
    {
176 4
        if (!Validator::isUnsignedInteger($error, 16)) {
177
            throw new \InvalidArgumentException(sprintf('Error must be an unsigned 16-bit integer, "%d" given.', $error));
178
        }
179 4
        $this->error = $error;
180 4
    }
181
182
    /**
183
     * @return string
184
     */
185 2
    public function getOtherData(): string
186
    {
187 2
        return $this->otherData;
188
    }
189
190
    /**
191
     * @param string $otherData
192
     */
193 4
    public function setOtherData(string $otherData): void
194
    {
195 4
        $this->otherData = $otherData;
196 4
    }
197
198
    /**
199
     * {@inheritdoc}
200
     */
201 1
    public function toText(): string
202
    {
203 1
        return sprintf('%s %d %d %s %d %d %s',
204 1
            $this->algorithmName,
205 1
            $this->timeSigned->format('U'),
206 1
            $this->fudge,
207 1
            base64_encode($this->mac),
208 1
            $this->originalId,
209 1
            $this->error,
210 1
            base64_encode($this->otherData)
211
        );
212
    }
213
214
    /**
215
     * {@inheritdoc}
216
     */
217 1
    public function toWire(): string
218
    {
219 1
        $timeSigned = (int) $this->timeSigned->format('U');
220 1
        $hex1 = (0xffff00000000 & $timeSigned) >> 32;
221 1
        $hex2 = (0x0000ffff0000 & $timeSigned) >> 16;
222 1
        $hex3 = 0x00000000ffff & $timeSigned;
223
224 1
        $wire = Message::encodeName($this->algorithmName);
225 1
        $wire .= pack('nnnnn', $hex1, $hex2, $hex3, $this->fudge, strlen($this->mac));
226 1
        $wire .= $this->mac;
227 1
        $wire .= pack('nnn', $this->originalId, $this->error, strlen($this->otherData));
228 1
        $wire .= $this->otherData;
229
230 1
        return $wire;
231
    }
232
233
    /**
234
     * {@inheritdoc}
235
     *
236
     * @throws ParseException
237
     */
238 1
    public function fromText(string $text): void
239
    {
240 1
        $rdata = explode(Tokens::SPACE, $text);
241 1
        $this->setAlgorithmName((string) array_shift($rdata));
242 1
        if (false === $timeSigned = \DateTime::createFromFormat('U', (string) array_shift($rdata))) {
243
            throw new ParseException('Unable to decode TSIG time signed.');
244
        }
245 1
        $this->setTimeSigned($timeSigned);
246 1
        $this->setFudge((int) array_shift($rdata));
247
248 1
        if (false === $mac = base64_decode((string) array_shift($rdata), true)) {
249
            throw new ParseException('Unable to decode TSIG MAC. Malformed base64 string.');
250
        }
251 1
        $this->setMac($mac);
252
253 1
        $this->setOriginalId((int) array_shift($rdata));
254 1
        $this->setError((int) array_shift($rdata));
255
256 1
        if (false === $otherData = base64_decode((string) array_shift($rdata), true)) {
257
            throw new ParseException('Unable to decode TSIG other data. Malformed base64 string.');
258
        }
259 1
        $this->setOtherData($otherData);
260 1
    }
261
262
    /**
263
     * {@inheritdoc}
264
     *
265
     * @throws DecodeException
266
     */
267 1
    public function fromWire(string $rdata, int &$offset = 0, ?int $rdLength = null): void
268
    {
269 1
        $this->setAlgorithmName(Message::decodeName($rdata, $offset));
270
271 1
        $args = unpack('n<hex1>/n<hex2>/n<hex3>/n<fudge>/n<macLen>', $rdata, $offset);
272 1
        $offset += 10;
273
274 1
        $timeSigned = ($args['<hex1>'] << 32) + ($args['<hex2>'] << 16) + $args['<hex3>'];
275 1
        if (false === $objTimeSigned = \DateTime::createFromFormat('U', (string) $timeSigned)) {
276
            throw new DecodeException(static::TYPE, $rdata);
277
        }
278
279 1
        $macLen = (int) $args['<macLen>'];
280 1
        $this->setFudge($args['<fudge>']);
281 1
        $this->setTimeSigned($objTimeSigned);
282 1
        $this->setMac(substr($rdata, $offset, $macLen));
283 1
        $offset += $macLen;
284
285 1
        $args = unpack('n<id>/n<error>/n<otherLen>', $rdata, (int) $offset);
286 1
        $offset += 6;
287 1
        $otherLen = (int) $args['<otherLen>'];
288
289 1
        $this->setOriginalId($args['<id>']);
290 1
        $this->setError($args['<error>']);
291 1
        $this->setOtherData(substr($rdata, (int) $offset, $otherLen));
292 1
        $offset += $otherLen;
293 1
    }
294
}
295