2 ############################################################################
4 # This file is part of the IPFire Firewall. #
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. #
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. #
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 #
20 # Copyright (C) 2014 IPFire Team <info@ipfire.org>. #
22 ############################################################################
26 require "/var/ipfire/general-functions.pl";
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",
66 my %NETMASK2PREFIX = reverse(%PREFIX2NETMASK);
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.
74 # This function returns undef for undefined input.
75 if (!defined $address) {
79 my $address_bin = &Socket
::inet_pton
(AF_INET
, $address);
81 $address_bin = unpack('N', $address_bin);
87 # Does the reverse of ip2bin().
88 # Will return undef for invalid inputs.
90 my $address_bin = shift;
92 # This function returns undef for undefined input.
93 if (!defined $address_bin) {
97 my $address = pack('N', $address_bin);
99 $address = &Socket
::inet_ntop
(AF_INET
, $address);
105 # Takes two network addresses, compares them against each other
106 # and returns true if equal or false if not
108 my $network1 = shift;
109 my $network2 = shift;
111 my $bin1 = &network2bin
($network1);
112 my $bin2 = &network2bin
($network2);
114 if ($bin1 eq $bin2) {
121 # Takes a network in either a.b.c.d/a.b.c.d or a.b.c.d/e notation
122 # and will return an 32 bit integer representing the start
123 # address and an other one representing the network mask.
127 my ($address, $netmask) = split(/\//, $network, 2);
129 if (&check_prefix
($netmask)) {
130 $netmask = &convert_prefix2netmask
($netmask);
133 my $address_bin = &ip2bin
($address);
134 my $netmask_bin = &ip2bin
($netmask);
136 my $network_start = $address_bin & $netmask_bin;
138 return ($network_start, $netmask_bin);
141 # Deletes leading zeros in ip address
144 my @ip = split (/\./, $address);
146 foreach my $octet (@ip) {
147 $octet = int($octet);
150 $address = join (".", @ip);
154 # Returns True for all valid IP addresses
155 sub check_ip_address
($) {
158 # Normalise the IP address and compare the result with
159 # the input - which should obviously the same.
160 my $normalised_address = &_normalise_ip_address
($address);
162 return ((defined $normalised_address) && ($address eq $normalised_address));
165 # Returns True for all valid prefixes.
166 sub check_prefix
($) {
169 return (exists $PREFIX2NETMASK{$prefix});
172 # Returns True for all valid subnet masks.
173 sub check_netmask
($) {
176 return (exists $NETMASK2PREFIX{$netmask});
179 # Returns True for all valid inputs like a.b.c.d/a.b.c.d.
180 sub check_ip_address_and_netmask
($$) {
183 my ($address, $netmask) = split(/\//, $network, 2);
185 # Check if the IP address is fine.
187 my $result = &check_ip_address
($address);
192 return &check_netmask
($netmask);
195 # Returns True for all valid subnets like a.b.c.d/e or a.b.c.d/a.b.c.d
196 sub check_subnet
($) {
199 my ($address, $network) = split(/\//, $subnet, 2);
201 # Check if the IP address is fine.
202 my $result = &check_ip_address
($address);
207 return &check_prefix
($network) || &check_netmask
($network);
210 # For internal use only. Will take an IP address and
211 # return it in a normalised style. Like 8.8.8.010 -> 8.8.8.8.
212 sub _normalise_ip_address
($) {
215 my $address_bin = &ip2bin
($address);
216 if (!defined $address_bin) {
220 return &bin2ip
($address_bin);
223 # Returns the prefix for the given subnet mask.
224 sub convert_netmask2prefix
($) {
227 if (exists $NETMASK2PREFIX{$netmask}) {
228 return $NETMASK2PREFIX{$netmask};
234 # Returns the subnet mask for the given prefix.
235 sub convert_prefix2netmask
($) {
238 if (exists $PREFIX2NETMASK{$prefix}) {
239 return $PREFIX2NETMASK{$prefix};
245 # Takes an IP address and an offset and
246 # will return the offset'th IP address.
247 sub find_next_ip_address
($$) {
251 my $address_bin = &ip2bin
($address);
252 $address_bin += $offset;
254 return &bin2ip
($address_bin);
257 # Returns the network address of the given network.
258 sub get_netaddress
($) {
260 my ($network_bin, $netmask_bin) = &network2bin
($network);
262 if (defined $network_bin) {
263 return &bin2ip
($network_bin);
269 # Returns the broadcast of the given network.
270 sub get_broadcast
($) {
272 my ($network_bin, $netmask_bin) = &network2bin
($network);
274 return &bin2ip
($network_bin ^ ~$netmask_bin);
277 # Returns True if $address is in $network.
278 sub ip_address_in_network
($$) {
282 my $address_bin = &ip2bin
($address);
283 return undef unless (defined $address_bin);
285 my ($network_bin, $netmask_bin) = &network2bin
($network);
288 my $broadcast_bin = $network_bin ^ (~$netmask_bin % 2 ** 32);
290 return (($address_bin ge $network_bin) && ($address_bin le $broadcast_bin));
293 sub setup_upstream_proxy
() {
294 my %proxysettings = ();
295 &General
::readhash
("${General::swroot}/proxy/settings", \
%proxysettings);
297 if ($proxysettings{'UPSTREAM_PROXY'}) {
298 my $credentials = "";
300 if ($proxysettings{'UPSTREAM_USER'}) {
301 $credentials = $proxysettings{'UPSTREAM_USER'};
303 if ($proxysettings{'UPSTREAM_PASSWORD'}) {
304 $credentials .= ":" . $proxysettings{'UPSTREAM_PASSWORD'};
310 my $proxy = "http://" . $credentials . $proxysettings{'UPSTREAM_PROXY'};
312 $ENV{'http_proxy'} = $proxy;
313 $ENV{'https_proxy'} = $proxy;
314 $ENV{'ftp_proxy'} = $proxy;
318 my %wireless_status = ();
320 sub _get_wireless_status
($) {
323 if (!$wireless_status{$intf}) {
324 $wireless_status{$intf} = `iwconfig $intf`;
327 return $wireless_status{$intf};
330 sub wifi_get_essid
($) {
331 my $status = &_get_wireless_status
(shift);
333 my ($essid) = $status =~ /ESSID:\"(.*)\"/;
338 sub wifi_get_frequency
($) {
339 my $status = &_get_wireless_status
(shift);
341 my ($frequency) = $status =~ /Frequency:(\d+\.\d+ GHz)/;
346 sub wifi_get_access_point
($) {
347 my $status = &_get_wireless_status
(shift);
349 my ($access_point) = $status =~ /Access Point: ([0-9A-F:]+)/;
351 return $access_point;
354 sub wifi_get_bit_rate
($) {
355 my $status = &_get_wireless_status
(shift);
357 my ($bit_rate) = $status =~ /Bit Rate=(\d+ [GM]b\/s)/;
362 sub wifi_get_link_quality
($) {
363 my $status = &_get_wireless_status
(shift);
365 my ($cur, $max) = $status =~ /Link Quality=(\d+)\/(\d
+)/;
367 return $cur * 100 / $max;
370 sub wifi_get_signal_level
($) {
371 my $status = &_get_wireless_status
(shift);
373 my ($signal_level) = $status =~ /Signal level=(\-\d+ dBm)/;
375 return $signal_level;
378 sub get_hardware_address
($) {
379 my $ip_address = shift;
382 open(FILE
, "/proc/net/arp") or die("Could not read ARP table");
385 my ($ip_addr, $hwtype, $flags, $hwaddr, $mask, $device) = split(/\s+/, $_);
386 if ($ip_addr eq $ip_address) {
399 # Remove the next line to enable the testsuite
409 print "ASSERTION ERROR";
416 my $address1 = &ip2bin
("8.8.8.8");
417 assert
($address1 == 134744072);
419 my $address2 = &bin2ip
($address1);
420 assert
($address2 eq "8.8.8.8");
422 # Check if valid IP addresses are correctly recognised.
423 foreach my $address ("1.2.3.4", "192.168.180.1", "127.0.0.1") {
424 if (!&check_ip_address
($address)) {
425 print "$address is not correctly recognised as a valid IP address!\n";
430 # Check if invalid IP addresses are correctly found.
431 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") {
432 if (&check_ip_address
($address)) {
433 print "$address is recognised as a valid IP address!\n";
438 $result = &check_ip_address_and_netmask
("192.168.180.0/255.255.255.0");
441 $result = &convert_netmask2prefix
("255.255.254.0");
442 assert
($result == 23);
444 $result = &convert_prefix2netmask
(8);
445 assert
($result eq "255.0.0.0");
447 $result = &find_next_ip_address
("1.2.3.4", 2);
448 assert
($result eq "1.2.3.6");
450 $result = &network_equal
("192.168.0.0/24", "192.168.0.0/255.255.255.0");
453 $result = &network_equal
("192.168.0.0/24", "192.168.0.0/25");
456 $result = &network_equal
("192.168.0.0/24", "192.168.0.128/25");
459 $result = &network_equal
("192.168.0.1/24", "192.168.0.XXX/24");
462 $result = &ip_address_in_network
("10.0.1.4", "10.0.0.0/8");
465 $result = &ip_address_in_network
("192.168.30.11", "192.168.30.0/255.255.255.0");
468 print "Testsuite completed successfully!\n";