GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( d7e253...55763c )
by François
03:03
created

IP::__toString()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
1
<?php
2
/**
3
 *  Copyright (C) 2016 SURFnet.
4
 *
5
 *  This program is free software: you can redistribute it and/or modify
6
 *  it under the terms of the GNU Affero General Public License as
7
 *  published by the Free Software Foundation, either version 3 of the
8
 *  License, or (at your option) any later version.
9
 *
10
 *  This program is distributed in the hope that it will be useful,
11
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 *  GNU Affero General Public License for more details.
14
 *
15
 *  You should have received a copy of the GNU Affero General Public License
16
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
 */
18
namespace SURFnet\VPN\Server;
19
20
use InvalidArgumentException;
21
use SURFnet\VPN\Server\Exception\IPException;
22
23
class IP
24
{
25
    /** @var string */
26
    private $ipAddress;
27
28
    /** @var int */
29
    private $ipPrefix;
30
31
    /** @var int */
32
    private $ipFamily;
33
34
    public function __construct($ipAddressPrefix)
35
    {
36
        // detect if there is a prefix
37
        $hasPrefix = false !== strpos($ipAddressPrefix, '/');
38
        if ($hasPrefix) {
39
            list($ipAddress, $ipPrefix) = explode('/', $ipAddressPrefix);
40
        } else {
41
            $ipAddress = $ipAddressPrefix;
42
            $ipPrefix = null;
43
        }
44
45
        // validate the IP address
46
        if (false === filter_var($ipAddress, FILTER_VALIDATE_IP)) {
47
            throw new IPException('invalid IP address');
48
        }
49
50
        $is6 = false !== strpos($ipAddress, ':');
51
        if ($is6) {
52
            if (is_null($ipPrefix)) {
53
                $ipPrefix = 128;
54
            }
55
56 View Code Duplication
            if (!is_numeric($ipPrefix) || 0 > $ipPrefix || 128 < $ipPrefix) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
57
                throw new IPException('IP prefix must be a number between 0 and 128');
58
            }
59
            // normalize the IPv6 address
60
            $ipAddress = inet_ntop(inet_pton($ipAddress));
61
        } else {
62
            if (is_null($ipPrefix)) {
63
                $ipPrefix = 32;
64
            }
65 View Code Duplication
            if (!is_numeric($ipPrefix) || 0 > $ipPrefix || 32 < $ipPrefix) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
66
                throw new IPException('IP prefix must be a number between 0 and 32');
67
            }
68
        }
69
70
        $this->ipAddress = $ipAddress;
71
        $this->ipPrefix = (int) $ipPrefix;
72
        $this->ipFamily = $is6 ? 6 : 4;
73
    }
74
75
    public function getAddress()
76
    {
77
        return $this->ipAddress;
78
    }
79
80
    public function getPrefix()
81
    {
82
        return $this->ipPrefix;
83
    }
84
85
    public function getAddressPrefix()
86
    {
87
        return sprintf('%s/%d', $this->getAddress(), $this->getPrefix());
88
    }
89
90
    public function getFamily()
91
    {
92
        return $this->ipFamily;
93
    }
94
95
    /**
96
     * IPv4 only.
97
     */
98
    public function getNetmask()
99
    {
100
        $this->requireIPv4();
101
102
        return long2ip(-1 << (32 - $this->getPrefix()));
103
    }
104
105
    /**
106
     * IPv4 only.
107
     */
108
    public function getNetwork()
109
    {
110
        $this->requireIPv4();
111
112
        return long2ip(ip2long($this->getAddress()) & ip2long($this->getNetmask()));
113
    }
114
115
    /**
116
     * IPv4 only.
117
     */
118
    public function getNumberOfHosts()
119
    {
120
        $this->requireIPv4();
121
122
        return pow(2, 32 - $this->getPrefix()) - 2;
123
    }
124
125
    public function split($networkCount)
126
    {
127
        if (!is_int($networkCount)) {
128
            throw new InvalidArgumentException('parameter must be integer');
129
        }
130
131
        if (0 !== ($networkCount & ($networkCount - 1))) {
132
            throw new InvalidArgumentException('parameter must be power of 2');
133
        }
134
135
        if (4 === $this->getFamily()) {
136
            return $this->split4($networkCount);
137
        }
138
139
        return $this->split6($networkCount);
140
    }
141
142
    private function split4($networkCount)
143
    {
144
        if (pow(2, 32 - $this->getPrefix() - 2) < $networkCount) {
145
            throw new IPException('network too small to split in this many networks');
146
        }
147
148
        $prefix = $this->getPrefix() + log($networkCount, 2);
149
        $splitRanges = [];
150
        for ($i = 0; $i < $networkCount; ++$i) {
151
            $noHosts = pow(2, 32 - $prefix);
152
            $networkAddress = long2ip($i * $noHosts + ip2long($this->getAddress()));
153
            $splitRanges[] = new self($networkAddress.'/'.$prefix);
154
        }
155
156
        return $splitRanges;
157
    }
158
159
    private function split6($networkCount)
160
    {
161
        // NOTE: if networkCount == 1, then there will be one /64 returned, and not
162
        // the whole net!
163
        if (64 <= $this->getPrefix()) {
164
            throw new IPException('network too small to split up, must be bigger than /64');
165
        }
166
167
        if (0 !== $this->getPrefix() % 4) {
168
            throw new IPException('network prefix length must be divisible by 4');
169
        }
170
171
        if (pow(2, 64 - $this->getPrefix()) < $networkCount) {
172
            throw new IPException('network too small to split in this many networks');
173
        }
174
175
        $hexAddress = bin2hex(inet_pton($this->getAddress()));
176
        // strip the last digits based on prefix size
177
        $hexAddress = substr($hexAddress, 0, 16 - ((64 - $this->getPrefix()) / 4));
178
179
        $splitRanges = [];
180
        for ($i = 0; $i < $networkCount; ++$i) {
181
            // pad with zeros until there is enough space for or network number
182
            $paddedHexAddress = str_pad($hexAddress, 16 - strlen(dechex($i)), '0');
183
            // append the network number
184
            $hexAddressWithNetwork = $paddedHexAddress.dechex($i);
185
            // pad it to the end and convert back to IPv6 address
186
            $splitRanges[] = new self(sprintf('%s/64', inet_ntop(hex2bin(str_pad($hexAddressWithNetwork, 32, '0')))));
187
        }
188
189
        return $splitRanges;
190
    }
191
192
    public function __toString()
193
    {
194
        return $this->getAddressPrefix();
195
    }
196
197
    private function requireIPv4()
198
    {
199
        if (4 !== $this->getFamily()) {
200
            throw new IPException('method only for IPv4');
201
        }
202
    }
203
}
204