Completed
Branch master (f0bd78)
by Sam
04:24 queued 01:02
created

TSIG::fromWire()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 30
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 20
CRAP Score 2.0004

Importance

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