Completed
Push — master ( fe5fd9...28190b )
by Sam
07:00 queued 04:19
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 1
    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 2
    public function getAlgorithmName(): string
74
    {
75 2
        return $this->algorithmName;
76
    }
77
78 4
    public function setAlgorithmName(string $algorithmName): void
79
    {
80 4
        if (!Validator::fullyQualifiedDomainName($algorithmName)) {
81
            throw new \InvalidArgumentException('Algorithm name must be in the form of a fully qualified domain name.');
82
        }
83
84 4
        $this->algorithmName = $algorithmName;
85 4
    }
86
87 2
    public function getTimeSigned(): \DateTime
88
    {
89 2
        return $this->timeSigned;
90
    }
91
92 4
    public function setTimeSigned(\DateTime $timeSigned): void
93
    {
94 4
        $this->timeSigned = $timeSigned;
95 4
    }
96
97 2
    public function getFudge(): int
98
    {
99 2
        return $this->fudge;
100
    }
101
102 4
    public function setFudge(int $fudge): void
103
    {
104 4
        if (!Validator::isUnsignedInteger($fudge, 16)) {
105
            throw new \InvalidArgumentException(sprintf('Fudge must be an unsigned 16-bit integer, "%d" given.', $fudge));
106
        }
107 4
        $this->fudge = $fudge;
108 4
    }
109
110 2
    public function getMac(): string
111
    {
112 2
        return $this->mac;
113
    }
114
115 4
    public function setMac(string $mac): void
116
    {
117 4
        $this->mac = $mac;
118 4
    }
119
120 2
    public function getOriginalId(): int
121
    {
122 2
        return $this->originalId;
123
    }
124
125 4
    public function setOriginalId(int $originalId): void
126
    {
127 4
        if (!Validator::isUnsignedInteger($originalId, 16)) {
128
            throw new \InvalidArgumentException(sprintf('Original ID must be an unsigned 16-bit integer, "%d" given.', $originalId));
129
        }
130 4
        $this->originalId = $originalId;
131 4
    }
132
133 2
    public function getError(): int
134
    {
135 2
        return $this->error;
136
    }
137
138 4
    public function setError(int $error): void
139
    {
140 4
        if (!Validator::isUnsignedInteger($error, 16)) {
141
            throw new \InvalidArgumentException(sprintf('Error must be an unsigned 16-bit integer, "%d" given.', $error));
142
        }
143 4
        $this->error = $error;
144 4
    }
145
146 2
    public function getOtherData(): string
147
    {
148 2
        return $this->otherData;
149
    }
150
151 4
    public function setOtherData(string $otherData): void
152
    {
153 4
        $this->otherData = $otherData;
154 4
    }
155
156
    /**
157
     * {@inheritdoc}
158
     */
159 1
    public function toText(): string
160
    {
161 1
        return sprintf('%s %d %d %s %d %d %s',
162 1
            $this->algorithmName,
163 1
            $this->timeSigned->format('U'),
164 1
            $this->fudge,
165 1
            base64_encode($this->mac),
166 1
            $this->originalId,
167 1
            $this->error,
168 1
            base64_encode($this->otherData)
169
        );
170
    }
171
172
    /**
173
     * {@inheritdoc}
174
     */
175 1
    public function toWire(): string
176
    {
177 1
        $timeSigned = (int) $this->timeSigned->format('U');
178 1
        $hex1 = (0xffff00000000 & $timeSigned) >> 32;
179 1
        $hex2 = (0x0000ffff0000 & $timeSigned) >> 16;
180 1
        $hex3 = 0x00000000ffff & $timeSigned;
181
182 1
        $wire = Message::encodeName($this->algorithmName);
183 1
        $wire .= pack('nnnnn', $hex1, $hex2, $hex3, $this->fudge, strlen($this->mac));
184 1
        $wire .= $this->mac;
185 1
        $wire .= pack('nnn', $this->originalId, $this->error, strlen($this->otherData));
186 1
        $wire .= $this->otherData;
187
188 1
        return $wire;
189
    }
190
191
    /**
192
     * {@inheritdoc}
193
     *
194
     * @throws ParseException
195
     */
196 1
    public function fromText(string $text): void
197
    {
198 1
        $rdata = explode(Tokens::SPACE, $text);
199 1
        $this->setAlgorithmName((string) array_shift($rdata));
200 1
        if (false === $timeSigned = \DateTime::createFromFormat('U', (string) array_shift($rdata))) {
201
            throw new ParseException('Unable to decode TSIG time signed.');
202
        }
203 1
        $this->setTimeSigned($timeSigned);
204 1
        $this->setFudge((int) array_shift($rdata));
205
206 1
        if (false === $mac = base64_decode((string) array_shift($rdata), true)) {
207
            throw new ParseException('Unable to decode TSIG MAC. Malformed base64 string.');
208
        }
209 1
        $this->setMac($mac);
210
211 1
        $this->setOriginalId((int) array_shift($rdata));
212 1
        $this->setError((int) array_shift($rdata));
213
214 1
        if (false === $otherData = base64_decode((string) array_shift($rdata), true)) {
215
            throw new ParseException('Unable to decode TSIG other data. Malformed base64 string.');
216
        }
217 1
        $this->setOtherData($otherData);
218 1
    }
219
220
    /**
221
     * {@inheritdoc}
222
     *
223
     * @throws DecodeException
224
     */
225 1
    public function fromWire(string $rdata, int &$offset = 0, ?int $rdLength = null): void
226
    {
227 1
        $this->setAlgorithmName(Message::decodeName($rdata, $offset));
228
229 1
        $args = unpack('n<hex1>/n<hex2>/n<hex3>/n<fudge>/n<macLen>', $rdata, $offset);
230 1
        $offset += 10;
231
232 1
        $timeSigned = ($args['<hex1>'] << 32) + ($args['<hex2>'] << 16) + $args['<hex3>'];
233 1
        if (false === $objTimeSigned = \DateTime::createFromFormat('U', (string) $timeSigned)) {
234
            throw new DecodeException(static::TYPE, $rdata);
235
        }
236
237 1
        $macLen = (int) $args['<macLen>'];
238 1
        $this->setFudge($args['<fudge>']);
239 1
        $this->setTimeSigned($objTimeSigned);
240 1
        $this->setMac(substr($rdata, $offset, $macLen));
241 1
        $offset += $macLen;
242
243 1
        $args = unpack('n<id>/n<error>/n<otherLen>', $rdata, (int) $offset);
244 1
        $offset += 6;
245 1
        $otherLen = (int) $args['<otherLen>'];
246
247 1
        $this->setOriginalId($args['<id>']);
248 1
        $this->setError($args['<error>']);
249 1
        $this->setOtherData(substr($rdata, (int) $offset, $otherLen));
250 1
        $offset += $otherLen;
251 1
    }
252
}
253