]> git.ipfire.org Git - ipfire-2.x.git/blob - config/cfgroot/network-functions.pl
Network-functions: add check if variables are defined
[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 require "/var/ipfire/general-functions.pl";
27
28 use Socket;
29
30 my %PREFIX2NETMASK = (
31 32 => "255.255.255.255",
32 31 => "255.255.255.254",
33 30 => "255.255.255.252",
34 29 => "255.255.255.248",
35 28 => "255.255.255.240",
36 27 => "255.255.255.224",
37 26 => "255.255.255.192",
38 25 => "255.255.255.128",
39 24 => "255.255.255.0",
40 23 => "255.255.254.0",
41 22 => "255.255.252.0",
42 21 => "255.255.248.0",
43 20 => "255.255.240.0",
44 19 => "255.255.224.0",
45 18 => "255.255.192.0",
46 17 => "255.255.128.0",
47 16 => "255.255.0.0",
48 15 => "255.254.0.0",
49 14 => "255.252.0.0",
50 13 => "255.248.0.0",
51 12 => "255.240.0.0",
52 11 => "255.224.0.0",
53 10 => "255.192.0.0",
54 9 => "255.128.0.0",
55 8 => "255.0.0.0",
56 7 => "254.0.0.0",
57 6 => "252.0.0.0",
58 5 => "248.0.0.0",
59 4 => "240.0.0.0",
60 3 => "224.0.0.0",
61 2 => "192.0.0.0",
62 1 => "128.0.0.0",
63 0 => "0.0.0.0"
64 );
65
66 my %NETMASK2PREFIX = reverse(%PREFIX2NETMASK);
67
68 # Takes an IP address in dotted decimal notation and
69 # returns a 32 bit integer representing that IP addresss.
70 # Will return undef for invalid inputs.
71 sub ip2bin($) {
72 my $address = shift;
73
74 # This function returns undef for undefined input.
75 if (!defined $address) {
76 return undef;
77 }
78
79 my $address_bin = &Socket::inet_pton(AF_INET, $address);
80 if ($address_bin) {
81 $address_bin = unpack('N', $address_bin);
82 }
83
84 return $address_bin;
85 }
86
87 # Does the reverse of ip2bin().
88 # Will return undef for invalid inputs.
89 sub bin2ip($) {
90 my $address_bin = shift;
91
92 # This function returns undef for undefined input.
93 if (!defined $address_bin) {
94 return undef;
95 }
96
97 my $address = pack('N', $address_bin);
98 if ($address) {
99 $address = &Socket::inet_ntop(AF_INET, $address);
100 }
101
102 return $address;
103 }
104
105 # Takes two network addresses, compares them against each other
106 # and returns true if equal or false if not
107 sub network_equal {
108 my $network1 = shift;
109 my $network2 = shift;
110
111 my @bin1 = &network2bin($network1);
112 my @bin2 = &network2bin($network2);
113
114 if (!defined $bin1 || !defined $bin2) {
115 return undef;
116 }
117
118 if ($bin1[0] eq $bin2[0] && $bin1[1] eq $bin2[1]) {
119 return 1;
120 }
121
122 return 0;
123 }
124
125 # Takes a network in either a.b.c.d/a.b.c.d or a.b.c.d/e notation
126 # and will return an 32 bit integer representing the start
127 # address and an other one representing the network mask.
128 sub network2bin($) {
129 my $network = shift;
130
131 my ($address, $netmask) = split(/\//, $network, 2);
132
133 if (&check_prefix($netmask)) {
134 $netmask = &convert_prefix2netmask($netmask);
135 }
136
137 my $address_bin = &ip2bin($address);
138 my $netmask_bin = &ip2bin($netmask);
139
140 if (!defined $address_bin || !defined $netmask_bin) {
141 return undef;
142 }
143
144 my $network_start = $address_bin & $netmask_bin;
145
146 return ($network_start, $netmask_bin);
147 }
148
149 # Deletes leading zeros in ip address
150 sub ip_remove_zero{
151 my $address = shift;
152 my @ip = split (/\./, $address);
153
154 foreach my $octet (@ip) {
155 $octet = int($octet);
156 }
157
158 $address = join (".", @ip);
159
160 return $address;
161 }
162 # Returns True for all valid IP addresses
163 sub check_ip_address($) {
164 my $address = shift;
165
166 # Normalise the IP address and compare the result with
167 # the input - which should obviously the same.
168 my $normalised_address = &_normalise_ip_address($address);
169
170 return ((defined $normalised_address) && ($address eq $normalised_address));
171 }
172
173 # Returns True for all valid prefixes.
174 sub check_prefix($) {
175 my $prefix = shift;
176
177 return (exists $PREFIX2NETMASK{$prefix});
178 }
179
180 # Returns True for all valid subnet masks.
181 sub check_netmask($) {
182 my $netmask = shift;
183
184 return (exists $NETMASK2PREFIX{$netmask});
185 }
186
187 # Returns True for all valid inputs like a.b.c.d/a.b.c.d.
188 sub check_ip_address_and_netmask($$) {
189 my $network = shift;
190
191 my ($address, $netmask) = split(/\//, $network, 2);
192
193 # Check if the IP address is fine.
194 #
195 my $result = &check_ip_address($address);
196 unless ($result) {
197 return $result;
198 }
199
200 return &check_netmask($netmask);
201 }
202
203 # Returns True for all valid subnets like a.b.c.d/e or a.b.c.d/a.b.c.d
204 sub check_subnet($) {
205 my $subnet = shift;
206
207 my ($address, $network) = split(/\//, $subnet, 2);
208
209 # Check if the IP address is fine.
210 my $result = &check_ip_address($address);
211 unless ($result) {
212 return $result;
213 }
214
215 return &check_prefix($network) || &check_netmask($network);
216 }
217
218 # For internal use only. Will take an IP address and
219 # return it in a normalised style. Like 8.8.8.010 -> 8.8.8.8.
220 sub _normalise_ip_address($) {
221 my $address = shift;
222
223 my $address_bin = &ip2bin($address);
224 if (!defined $address_bin) {
225 return undef;
226 }
227
228 return &bin2ip($address_bin);
229 }
230
231 # Returns the prefix for the given subnet mask.
232 sub convert_netmask2prefix($) {
233 my $netmask = shift;
234
235 if (exists $NETMASK2PREFIX{$netmask}) {
236 return $NETMASK2PREFIX{$netmask};
237 }
238
239 return undef;
240 }
241
242 # Returns the subnet mask for the given prefix.
243 sub convert_prefix2netmask($) {
244 my $prefix = shift;
245
246 if (exists $PREFIX2NETMASK{$prefix}) {
247 return $PREFIX2NETMASK{$prefix};
248 }
249
250 return undef;
251 }
252
253 # Takes an IP address and an offset and
254 # will return the offset'th IP address.
255 sub find_next_ip_address($$) {
256 my $address = shift;
257 my $offset = shift;
258
259 my $address_bin = &ip2bin($address);
260 $address_bin += $offset;
261
262 return &bin2ip($address_bin);
263 }
264
265 # Returns the network address of the given network.
266 sub get_netaddress($) {
267 my $network = shift;
268 my ($network_bin, $netmask_bin) = &network2bin($network);
269
270 if (defined $network_bin) {
271 return &bin2ip($network_bin);
272 }
273
274 return undef;
275 }
276
277 # Returns the broadcast of the given network.
278 sub get_broadcast($) {
279 my $network = shift;
280 my ($network_bin, $netmask_bin) = &network2bin($network);
281
282 return &bin2ip($network_bin ^ ~$netmask_bin);
283 }
284
285 # Returns True if $address is in $network.
286 sub ip_address_in_network($$) {
287 my $address = shift;
288 my $network = shift;
289
290 my $address_bin = &ip2bin($address);
291 return undef unless (defined $address_bin);
292
293 my ($network_bin, $netmask_bin) = &network2bin($network);
294
295 # Find end address
296 my $broadcast_bin = $network_bin ^ (~$netmask_bin % 2 ** 32);
297
298 return (($address_bin ge $network_bin) && ($address_bin le $broadcast_bin));
299 }
300
301 sub setup_upstream_proxy() {
302 my %proxysettings = ();
303 &General::readhash("${General::swroot}/proxy/settings", \%proxysettings);
304
305 if ($proxysettings{'UPSTREAM_PROXY'}) {
306 my $credentials = "";
307
308 if ($proxysettings{'UPSTREAM_USER'}) {
309 $credentials = $proxysettings{'UPSTREAM_USER'};
310
311 if ($proxysettings{'UPSTREAM_PASSWORD'}) {
312 $credentials .= ":" . $proxysettings{'UPSTREAM_PASSWORD'};
313 }
314
315 $credentials .= "@";
316 }
317
318 my $proxy = "http://" . $credentials . $proxysettings{'UPSTREAM_PROXY'};
319
320 $ENV{'http_proxy'} = $proxy;
321 $ENV{'https_proxy'} = $proxy;
322 $ENV{'ftp_proxy'} = $proxy;
323 }
324 }
325
326 my %wireless_status = ();
327
328 sub _get_wireless_status($) {
329 my $intf = shift;
330
331 if (!$wireless_status{$intf}) {
332 $wireless_status{$intf} = `iwconfig $intf`;
333 }
334
335 return $wireless_status{$intf};
336 }
337
338 sub wifi_get_essid($) {
339 my $status = &_get_wireless_status(shift);
340
341 my ($essid) = $status =~ /ESSID:\"(.*)\"/;
342
343 return $essid;
344 }
345
346 sub wifi_get_frequency($) {
347 my $status = &_get_wireless_status(shift);
348
349 my ($frequency) = $status =~ /Frequency:(\d+\.\d+ GHz)/;
350
351 return $frequency;
352 }
353
354 sub wifi_get_access_point($) {
355 my $status = &_get_wireless_status(shift);
356
357 my ($access_point) = $status =~ /Access Point: ([0-9A-F:]+)/;
358
359 return $access_point;
360 }
361
362 sub wifi_get_bit_rate($) {
363 my $status = &_get_wireless_status(shift);
364
365 my ($bit_rate) = $status =~ /Bit Rate=(\d+ [GM]b\/s)/;
366
367 return $bit_rate;
368 }
369
370 sub wifi_get_link_quality($) {
371 my $status = &_get_wireless_status(shift);
372
373 my ($cur, $max) = $status =~ /Link Quality=(\d+)\/(\d+)/;
374
375 return $cur * 100 / $max;
376 }
377
378 sub wifi_get_signal_level($) {
379 my $status = &_get_wireless_status(shift);
380
381 my ($signal_level) = $status =~ /Signal level=(\-\d+ dBm)/;
382
383 return $signal_level;
384 }
385
386 sub get_hardware_address($) {
387 my $ip_address = shift;
388 my $ret;
389
390 open(FILE, "/proc/net/arp") or die("Could not read ARP table");
391
392 while (<FILE>) {
393 my ($ip_addr, $hwtype, $flags, $hwaddr, $mask, $device) = split(/\s+/, $_);
394 if ($ip_addr eq $ip_address) {
395 $ret = $hwaddr;
396 last;
397 }
398 }
399
400 close(FILE);
401
402 return $ret;
403 }
404
405 1;
406
407 # Remove the next line to enable the testsuite
408 __END__
409
410 sub assert($) {
411 my $ret = shift;
412
413 if ($ret) {
414 return;
415 }
416
417 print "ASSERTION ERROR";
418 exit(1);
419 }
420
421 sub testsuite() {
422 my $result;
423
424 my $address1 = &ip2bin("8.8.8.8");
425 assert($address1 == 134744072);
426
427 my $address2 = &bin2ip($address1);
428 assert($address2 eq "8.8.8.8");
429
430 # Check if valid IP addresses are correctly recognised.
431 foreach my $address ("1.2.3.4", "192.168.180.1", "127.0.0.1") {
432 if (!&check_ip_address($address)) {
433 print "$address is not correctly recognised as a valid IP address!\n";
434 exit 1;
435 };
436 }
437
438 # Check if invalid IP addresses are correctly found.
439 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") {
440 if (&check_ip_address($address)) {
441 print "$address is recognised as a valid IP address!\n";
442 exit 1;
443 };
444 }
445
446 $result = &check_ip_address_and_netmask("192.168.180.0/255.255.255.0");
447 assert($result);
448
449 $result = &convert_netmask2prefix("255.255.254.0");
450 assert($result == 23);
451
452 $result = &convert_prefix2netmask(8);
453 assert($result eq "255.0.0.0");
454
455 $result = &find_next_ip_address("1.2.3.4", 2);
456 assert($result eq "1.2.3.6");
457
458 $result = &network_equal("192.168.0.0/24", "192.168.0.0/255.255.255.0");
459 assert($result);
460
461 $result = &network_equal("192.168.0.0/24", "192.168.0.0/25");
462 assert(!$result);
463
464 $result = &network_equal("192.168.0.0/24", "192.168.0.128/25");
465 assert(!$result);
466
467 $result = &network_equal("192.168.0.1/24", "192.168.0.XXX/24");
468 assert(!$result);
469
470 $result = &ip_address_in_network("10.0.1.4", "10.0.0.0/8");
471 assert($result);
472
473 $result = &ip_address_in_network("192.168.30.11", "192.168.30.0/255.255.255.0");
474 assert($result);
475
476 print "Testsuite completed successfully!\n";
477
478 return 0;
479 }
480
481 &testsuite();