]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blob - config/cfgroot/network-functions.pl
Merge remote-tracking branch 'origin/next' into install-raid
[people/pmueller/ipfire-2.x.git] / config / cfgroot / network-functions.pl
1 #!/usr/bin/perl -w
2 ############################################################################
3 # #
4 # This file is part of the IPFire Firewall. #
5 # #
6 # IPFire is free software; you can redistribute it and/or modify #
7 # it under the terms of the GNU General Public License as published by #
8 # the Free Software Foundation; either version 2 of the License, or #
9 # (at your option) any later version. #
10 # #
11 # IPFire is distributed in the hope that it will be useful, #
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
14 # GNU General Public License for more details. #
15 # #
16 # You should have received a copy of the GNU General Public License #
17 # along with IPFire; if not, write to the Free Software #
18 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #
19 # #
20 # Copyright (C) 2014 IPFire Team <info@ipfire.org>. #
21 # #
22 ############################################################################
23
24 package Network;
25
26 use Socket;
27
28 my %PREFIX2NETMASK = (
29 32 => "255.255.255.255",
30 31 => "255.255.255.254",
31 30 => "255.255.255.252",
32 29 => "255.255.255.248",
33 28 => "255.255.255.240",
34 27 => "255.255.255.224",
35 26 => "255.255.255.192",
36 25 => "255.255.255.128",
37 24 => "255.255.255.0",
38 23 => "255.255.254.0",
39 22 => "255.255.252.0",
40 21 => "255.255.248.0",
41 20 => "255.255.240.0",
42 19 => "255.255.224.0",
43 18 => "255.255.192.0",
44 17 => "255.255.128.0",
45 16 => "255.255.0.0",
46 15 => "255.254.0.0",
47 14 => "255.252.0.0",
48 13 => "255.248.0.0",
49 12 => "255.240.0.0",
50 11 => "255.224.0.0",
51 10 => "255.192.0.0",
52 9 => "255.128.0.0",
53 8 => "255.0.0.0",
54 7 => "254.0.0.0",
55 6 => "252.0.0.0",
56 5 => "248.0.0.0",
57 4 => "240.0.0.0",
58 3 => "224.0.0.0",
59 2 => "192.0.0.0",
60 1 => "128.0.0.0",
61 0 => "0.0.0.0"
62 );
63
64 my %NETMASK2PREFIX = reverse(%PREFIX2NETMASK);
65
66 # Takes an IP address in dotted decimal notation and
67 # returns a 32 bit integer representing that IP addresss.
68 # Will return undef for invalid inputs.
69 sub ip2bin($) {
70 my $address = shift;
71
72 # This function returns undef for undefined input.
73 if (!defined $address) {
74 return undef;
75 }
76
77 my $address_bin = &Socket::inet_pton(AF_INET, $address);
78 if ($address_bin) {
79 $address_bin = unpack('N', $address_bin);
80 }
81
82 return $address_bin;
83 }
84
85 # Does the reverse of ip2bin().
86 # Will return undef for invalid inputs.
87 sub bin2ip($) {
88 my $address_bin = shift;
89
90 # This function returns undef for undefined input.
91 if (!defined $address_bin) {
92 return undef;
93 }
94
95 my $address = pack('N', $address_bin);
96 if ($address) {
97 $address = &Socket::inet_ntop(AF_INET, $address);
98 }
99
100 return $address;
101 }
102
103 # Takes a network in either a.b.c.d/a.b.c.d or a.b.c.d/e notation
104 # and will return an 32 bit integer representing the start
105 # address and an other one representing the network mask.
106 sub network2bin($) {
107 my $network = shift;
108
109 my ($address, $netmask) = split(/\//, $network, 2);
110
111 if (&check_prefix($netmask)) {
112 $netmask = &convert_prefix2netmask($netmask);
113 }
114
115 my $address_bin = &ip2bin($address);
116 my $netmask_bin = &ip2bin($netmask);
117
118 my $network_start = $address_bin & $netmask_bin;
119
120 return ($network_start, $netmask_bin);
121 }
122
123 # Returns True for all valid IP addresses
124 sub check_ip_address($) {
125 my $address = shift;
126
127 # Normalise the IP address and compare the result with
128 # the input - which should obviously the same.
129 my $normalised_address = &_normalise_ip_address($address);
130
131 return ((defined $normalised_address) && ($address eq $normalised_address));
132 }
133
134 # Returns True for all valid prefixes.
135 sub check_prefix($) {
136 my $prefix = shift;
137
138 return (exists $PREFIX2NETMASK{$prefix});
139 }
140
141 # Returns True for all valid subnet masks.
142 sub check_netmask($) {
143 my $netmask = shift;
144
145 return (exists $NETMASK2PREFIX{$netmask});
146 }
147
148 # Returns True for all valid inputs like a.b.c.d/a.b.c.d.
149 sub check_ip_address_and_netmask($$) {
150 my $network = shift;
151
152 my ($address, $netmask) = split(/\//, $network, 2);
153
154 # Check if the IP address is fine.
155 #
156 my $result = &check_ip_address($address);
157 unless ($result) {
158 return $result;
159 }
160
161 return &check_netmask($netmask);
162 }
163
164 # For internal use only. Will take an IP address and
165 # return it in a normalised style. Like 8.8.8.010 -> 8.8.8.8.
166 sub _normalise_ip_address($) {
167 my $address = shift;
168
169 my $address_bin = &ip2bin($address);
170 if (!defined $address_bin) {
171 return undef;
172 }
173
174 return &bin2ip($address_bin);
175 }
176
177 # Returns the prefix for the given subnet mask.
178 sub convert_netmask2prefix($) {
179 my $netmask = shift;
180
181 if (exists $NETMASK2PREFIX{$netmask}) {
182 return $NETMASK2PREFIX{$netmask};
183 }
184
185 return undef;
186 }
187
188 # Returns the subnet mask for the given prefix.
189 sub convert_prefix2netmask($) {
190 my $prefix = shift;
191
192 if (exists $PREFIX2NETMASK{$prefix}) {
193 return $PREFIX2NETMASK{$prefix};
194 }
195
196 return undef;
197 }
198
199 # Takes an IP address and an offset and
200 # will return the offset'th IP address.
201 sub find_next_ip_address($$) {
202 my $address = shift;
203 my $offset = shift;
204
205 my $address_bin = &ip2bin($address);
206 $address_bin += $offset;
207
208 return &bin2ip($address_bin);
209 }
210
211 # Returns the network address of the given network.
212 sub get_netaddress($) {
213 my $network = shift;
214 my ($network_bin, $netmask_bin) = &network2bin($network);
215
216 if (defined $network_bin) {
217 return &bin2ip($network_bin);
218 }
219
220 return undef;
221 }
222
223 # Returns the broadcast of the given network.
224 sub get_broadcast($) {
225 my $network = shift;
226 my ($network_bin, $netmask_bin) = &network2bin($network);
227
228 return &bin2ip($network_bin ^ ~$netmask_bin);
229 }
230
231 # Returns True if $address is in $network.
232 sub ip_address_in_network($$) {
233 my $address = shift;
234 my $network = shift;
235
236 my $address_bin = &ip2bin($address);
237 return undef unless (defined $address_bin);
238
239 my ($network_bin, $netmask_bin) = &network2bin($network);
240
241 # Find end address
242 my $broadcast_bin = $network_bin ^ ~$netmask_bin;
243
244 return (($address_bin ge $network_bin) && ($address_bin le $broadcast_bin));
245 }
246
247 1;
248
249 # Remove the next line to enable the testsuite
250 __END__
251
252 sub assert($) {
253 my $ret = shift;
254
255 if ($ret) {
256 return;
257 }
258
259 print "ASSERTION ERROR";
260 exit(1);
261 }
262
263 sub testsuite() {
264 my $result;
265
266 my $address1 = &ip2bin("8.8.8.8");
267 assert($address1 == 134744072);
268
269 my $address2 = &bin2ip($address1);
270 assert($address2 eq "8.8.8.8");
271
272 # Check if valid IP addresses are correctly recognised.
273 foreach my $address ("1.2.3.4", "192.168.180.1", "127.0.0.1") {
274 if (!&check_ip_address($address)) {
275 print "$address is not correctly recognised as a valid IP address!\n";
276 exit 1;
277 };
278 }
279
280 # Check if invalid IP addresses are correctly found.
281 foreach my $address ("456.2.3.4", "192.768.180.1", "127.1", "1", "a.b.c.d", "1.2.3.4.5", "1.2.3.4/12") {
282 if (&check_ip_address($address)) {
283 print "$address is recognised as a valid IP address!\n";
284 exit 1;
285 };
286 }
287
288 $result = &check_ip_address_and_netmask("192.168.180.0/255.255.255.0");
289 assert($result);
290
291 $result = &convert_netmask2prefix("255.255.254.0");
292 assert($result == 23);
293
294 $result = &convert_prefix2netmask(8);
295 assert($result eq "255.0.0.0");
296
297 $result = &find_next_ip_address("1.2.3.4", 2);
298 assert($result eq "1.2.3.6");
299
300 $result = &ip_address_in_network("10.0.1.4", "10.0.0.0/8");
301 assert($result);
302
303 return 0;
304 }
305
306 &testsuite();