Completed
Branch Version3 (97e220)
by Sam
01:25
created

IPSECKEY::getGatewayType()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
crap 1
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\Tokens;
17
use Badcow\DNS\Validator;
18
19
/**
20
 * {@link https://tools.ietf.org/html/rfc4025}.
21
 */
22
class IPSECKEY implements RdataInterface
23
{
24
    use RdataTrait;
25
26
    const TYPE = 'IPSECKEY';
27
    const TYPE_CODE = 45;
28
    const ALGORITHM_NONE = 0;
29
    const ALGORITHM_DSA = 1;
30
    const ALGORITHM_RSA = 2;
31
    const ALGORITHM_ECDSA = 3;
32
33
    /**
34
     * This is an 8-bit precedence for this record.  It is interpreted in
35
     * the same way as the PREFERENCE field described in section 3.3.9 of
36
     * RFC 1035.
37
     *
38
     * Gateways listed in IPSECKEY records with lower precedence are to be
39
     * attempted first.  Where there is a tie in precedence, the order
40
     * should be non-deterministic.
41
     *
42
     * @var int
43
     */
44
    private $precedence;
45
46
    /**
47
     * The gateway type field indicates the format of the information that
48
     * is stored in the gateway field.
49
     *
50
     * The following values are defined:
51
     * - 0: No gateway is present.
52
     * - 1: A 4-byte IPv4 address is present.
53
     * - 2: A 16-byte IPv6 address is present.
54
     * - 3: A wire-encoded domain name is present.  The wire-encoded format is
55
     *      self-describing, so the length is implicit.  The domain name MUST
56
     *      NOT be compressed.  (See Section 3.3 of RFC 1035.)
57
     *
58
     * @var int
59
     */
60
    private $gatewayType;
61
62
    /**
63
     * 7-bit The algorithm type field identifies the public key's crypto-
64
     * graphic algorithm and determines the format of the public key field.
65
     * A value of 0 indicates that no key is present.
66
     *
67
     * The following values are defined:
68
     * - 1: A DSA key is present, in the format defined in RFC 2536.
69
     * - 2: A RSA key is present, in the format defined in RFC 3110.
70
     * - 3: An ECDSA key is present, in the format defined in RFC 6605.
71
     *
72
     * @var int
73
     */
74
    private $algorithm = 0;
75
76
    /**
77
     * The gateway field indicates a gateway to which an IPsec tunnel may be.
78
     * created in order to reach the entity named by this resource record.
79
     *
80
     * There are three formats:
81
     *
82
     * A 32-bit IPv4 address is present in the gateway field.  The data
83
     * portion is an IPv4 address as described in section 3.4.1 of RFC 1035.
84
     * This is a 32-bit number in network byte order.
85
     *
86
     * A 128-bit IPv6 address is present in the gateway field.  The data
87
     * portion is an IPv6 address as described in section 2.2 of RFC 3596
88
     * This is a 128-bit number in network byte order.
89
     *
90
     * The gateway field is a normal wire-encoded domain name, as described
91
     * in section 3.3 of RFC 1035. Compression MUST NOT be used.
92
     *
93
     * @var string|null
94
     */
95
    private $gateway;
96
97
    /**
98
     * Both the public key types defined in this document (RSA and DSA)
99
     * inherit their public key formats from the corresponding KEY RR
100
     * formats. Specifically, the public key field contains the
101
     * algorithm-specific portion of the KEY RR RDATA, which is all the KEY
102
     * RR DATA after the first four octets.  This is the same portion of the
103
     * KEY RR that must be specified by documents that define a DNSSEC
104
     * algorithm. Those documents also specify a message digest to be used
105
     * for generation of SIG RRs; that specification is not relevant for
106
     * IPSECKEY RRs.
107
     *
108
     * @var string|null
109
     */
110
    private $publicKey = null;
111
112
    /**
113
     * @return int
114
     */
115 12
    public function getPrecedence(): int
116
    {
117 12
        return $this->precedence;
118
    }
119
120
    /**
121
     * @param int $precedence
122
     *
123
     * @throws \InvalidArgumentException
124
     */
125 24
    public function setPrecedence(int $precedence): void
126
    {
127 24
        if (!Validator::isUnsignedInteger($precedence, 8)) {
128
            throw new \InvalidArgumentException('IPSECKEY precedence must be an 8-bit integer.');
129
        }
130 24
        $this->precedence = $precedence;
131 24
    }
132
133
    /**
134
     * @return int
135
     */
136 12
    public function getGatewayType(): int
137
    {
138 12
        return $this->gatewayType;
139
    }
140
141
    /**
142
     * @return int
143
     */
144 12
    public function getAlgorithm(): int
145
    {
146 12
        return $this->algorithm;
147
    }
148
149
    /**
150
     * @param int $algorithm
151
     *
152
     * @throws \InvalidArgumentException
153
     */
154 24
    private function setAlgorithm(int $algorithm): void
155
    {
156 24
        if (!Validator::isUnsignedInteger($algorithm, 8)) {
157
            throw new \InvalidArgumentException('IPSECKEY algorithm type must be an 8-bit integer.');
158
        }
159 24
        $this->algorithm = $algorithm;
160 24
    }
161
162
    /**
163
     * @return string|null
164
     */
165 12
    public function getGateway(): ?string
166
    {
167 12
        return $this->gateway;
168
    }
169
170
    /**
171
     * @param string|null $gateway either &null for no gateway, a fully qualified domain name, or an IPv4 or IPv6 address
172
     *
173
     * @throws \InvalidArgumentException
174
     */
175 24
    public function setGateway(?string $gateway): void
176
    {
177 24
        if (null === $gateway || '.' === $gateway) {
178 4
            $gateway = null;
179 4
            $this->gatewayType = 0;
180 20
        } elseif (Validator::ipv4($gateway)) {
181 8
            $this->gatewayType = 1;
182 12
        } elseif (Validator::ipv6($gateway)) {
183 4
            $this->gatewayType = 2;
184 8
        } elseif (Validator::fullyQualifiedDomainName($gateway)) {
185 8
            $this->gatewayType = 3;
186
        } else {
187
            throw new \InvalidArgumentException('The gateway must be a fully qualified domain name, null, or a valid IPv4 or IPv6 address.');
188
        }
189
190 24
        $this->gateway = $gateway;
191 24
    }
192
193
    /**
194
     * @return string|null base64 encoded public key
195
     */
196 12
    public function getPublicKey(): ?string
197
    {
198 12
        return $this->publicKey;
199
    }
200
201
    /**
202
     * @param int         $algorithm either IPSECKEY::ALGORITHM_NONE, IPSECKEY::ALGORITHM_DSA, IPSECKEY::ALGORITHM_RSA, or IPSECKEY::ALGORITHM_ECDSA
203
     * @param string|null $publicKey base64 encoded public key
204
     *
205
     * @throws \InvalidArgumentException
206
     */
207 24
    public function setPublicKey(int $algorithm, ?string $publicKey): void
208
    {
209 24
        if (null === $publicKey) {
210 4
            $this->publicKey = null;
211 4
            $this->setAlgorithm(0);
212
213 4
            return;
214
        }
215
216 20
        if (!Validator::isBase64Encoded($publicKey)) {
217
            throw new \InvalidArgumentException('The public key must be a valid base64 encoded string.');
218
        }
219
220 20
        $this->publicKey = (string) preg_replace('/[^a-zA-Z0-9\/+=]/', '', $publicKey);
221 20
        $this->setAlgorithm($algorithm);
222 20
    }
223
224
    /**
225
     * {@inheritdoc}
226
     */
227 12
    public function toText(): string
228
    {
229 12
        $vars = [$this->precedence, $this->gatewayType, $this->algorithm, $this->gateway, $this->publicKey];
230
231 12
        if (0 === $this->gatewayType) {
232 2
            $vars[3] = '.';
233
        }
234
235 12
        if (0 === $this->algorithm) {
236 2
            unset($vars[4]);
237
        }
238
239 12
        return implode(Tokens::SPACE, $vars);
240
    }
241
242
    /**
243
     * {@inheritdoc}
244
     */
245 6
    public function toWire(): string
246
    {
247 6
        $wire = pack('CCC', $this->precedence, $this->gatewayType, $this->algorithm);
248 6
        if (1 === $this->gatewayType || 2 === $this->gatewayType) {
249 3
            if (null === $this->gateway) {
250
                throw new \RuntimeException('Gateway cannot be null if IPSECKEY::gatewayType > 0.');
251
            }
252 3
            $wire .= inet_pton($this->gateway);
253
        } else {
254 3
            $wire .= RdataTrait::encodeName($this->gateway ?? '.');
255
        }
256
257 6
        if (self::ALGORITHM_NONE !== $this->algorithm && null !== $this->publicKey) {
258 5
            $wire .= base64_decode($this->publicKey);
259
        }
260
261 6
        return $wire;
262
    }
263
264
    /**
265
     * {@inheritdoc}
266
     *
267
     * @return IPSECKEY
268
     */
269 6
    public static function fromText(string $text): RdataInterface
270
    {
271 6
        $rdata = explode(Tokens::SPACE, $text);
272 6
        $ipseckey = new self();
273 6
        $ipseckey->setPrecedence((int) array_shift($rdata));
274 6
        array_shift($rdata); //Gateway type is inferred from setGateway.
275 6
        $algorithm = (int) array_shift($rdata);
276 6
        $ipseckey->setGateway((string) array_shift($rdata));
277
278 6
        $publicKey = (0 === $algorithm) ? null : implode('', $rdata);
279 6
        $ipseckey->setPublicKey($algorithm, $publicKey);
280
281 6
        return $ipseckey;
282
    }
283
284
    /**
285
     * {@inheritdoc}
286
     *
287
     * @return IPSECKEY
288
     */
289 6
    public static function fromWire(string $rdata): RdataInterface
290
    {
291 6
        $ipseckey = new self();
292 6
        $offset = 0;
293
294 6
        $integers = unpack('CPrecedence/CGatewayType/CAlgorithm', $rdata, $offset);
295 6
        $ipseckey->setPrecedence((int) $integers['Precedence']);
296 6
        $gatewayType = $integers['GatewayType'];
297 6
        $algorithm = $integers['Algorithm'];
298 6
        $offset += 3;
299 6
        $gateway = null;
0 ignored issues
show
Unused Code introduced by
$gateway is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
300
301 6
        switch ($gatewayType) {
302 6
            case 0:
303 5
            case 3:
304 3
                $gateway = RdataTrait::decodeName($rdata, $offset);
305 3
                break;
306 3
            case 1:
307 2
                $gateway = inet_ntop(substr($rdata, $offset, 4));
308 2
                $offset += 4;
309 2
                break;
310 1
            case 2:
311 1
                $gateway = inet_ntop(substr($rdata, $offset, 16));
312 1
                $offset += 16;
313 1
                break;
314
            default:
315
                throw new \InvalidArgumentException(sprintf('Expected gateway type to be integer on [0,3], got "%d".', $gatewayType));
316
                break;
0 ignored issues
show
Unused Code introduced by
break; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
317
        }
318
319 6
        if (false === $gateway) {
320
            throw new \RuntimeException('Could not decode IP address.');
321
        }
322
323 6
        $ipseckey->setGateway($gateway);
324
325 6
        if (self::ALGORITHM_NONE !== $algorithm) {
326 5
            $publicKey = base64_encode(substr($rdata, $offset));
327 5
            $ipseckey->setPublicKey($algorithm, $publicKey);
328
        }
329
330 6
        return $ipseckey;
331
    }
332
}
333