]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blame - config/cfgroot/general-functions.pl
speed.cgi: reduce system load by copying two general-functions.
[people/pmueller/ipfire-2.x.git] / config / cfgroot / general-functions.pl
CommitLineData
ac1cfefa
MT
1# SmoothWall CGIs
2#
3# This code is distributed under the terms of the GPL
4#
5# (c) The SmoothWall Team
6# Copyright (C) 2002 Alex Hudson - getcgihash() rewrite
7# Copyright (C) 2002 Bob Grant <bob@cache.ucr.edu> - validmac()
8# Copyright (c) 2002/04/13 Steve Bootes - add alias section, helper functions
9# Copyright (c) 2002/08/23 Mark Wormgoor <mark@wormgoor.com> validfqdn()
10# Copyright (c) 2003/09/11 Darren Critchley <darrenc@telus.net> srtarray()
11#
12# $Id: general-functions.pl,v 1.1.2.26 2006/01/04 16:33:55 franck78 Exp $
13#
14
15package General;
16
17use strict;
18use Socket;
19use IO::Socket;
c545beb1 20use Net::SSLeay;
8c877a82 21use Net::IPv4Addr qw(:all);
ac1cfefa
MT
22$|=1; # line buffering
23
776a1761
MT
24$General::version = 'VERSION';
25$General::swroot = 'CONFIG_ROOT';
ac1cfefa 26$General::noipprefix = 'noipg-';
c545beb1 27$General::adminmanualurl = 'http://wiki.ipfire.org';
ac1cfefa 28
4e9a2b57
MT
29require "${General::swroot}/network-functions.pl";
30
03fe4081
MT
31# This function executes a shell command without forking a shell or do any other
32# Perl-voodoo before it. It deprecates the "system" command and is the only way
33# to call shell commands.
34sub safe_system($) {
35 my @command = @_;
36
37 system { ${command[0]} } @command;
38
39 # Return exit code
40 return $? >> 8;
41}
42
43# Calls a process in the background and returns nothing
44sub system_background($) {
45 my $pid = fork();
46
47 unless ($pid) {
48 my $rc = &system(@_);
49 exit($rc);
50 }
51
52 return 0;
53}
54
55# Returns the output of a shell command
110d4c81 56# if you change this also check speed.cgi that include a local copy for systemload reasons
03fe4081
MT
57sub system_output($) {
58 my @command = @_;
59 my $pid;
60 my @output = ();
61
62 unless ($pid = open(OUTPUT, "-|")) {
63 open(STDERR, ">&STDOUT");
64 exec { ${command[0]} } @command;
65 die "Could not execute @command: $!";
66 }
67
68 waitpid($pid, 0);
69
70 while (<OUTPUT>) {
71 push(@output, $_);
72 }
73 close(OUTPUT);
74
75 return @output;
76}
77
78# Calls a shell command and throws away the output
79sub system($) {
80 my @command = @_;
81
82 open(SAVEOUT, ">&STDOUT");
83 open(SAVEERR, ">&STDERR");
84
85 open(STDOUT, ">/dev/null");
86 open(STDERR, ">&STDOUT");
87
88 select(STDERR); $|=1;
89 select(STDOUT); $|=1;
90
91 my $rc = &safe_system(@command);
92
93 close(STDOUT);
94 close(STDERR);
95
96 # Restore
97 open(STDOUT, ">&SAVEOUT");
98 open(STDERR, ">&SAVEERR");
99
100 return $rc;
101}
102
e8adbea9
AF
103# Function to remove duplicates from an array
104sub uniq { my %seen; grep !$seen{$_}++, @_ }
105
c545beb1
MT
106#
107# log ("message") use default 'ipcop' tag
108# log ("tag","message") use your tag
109#
ac1cfefa
MT
110sub log
111{
c545beb1
MT
112 my $tag='ipfire';
113 $tag = shift if (@_>1);
ac1cfefa
MT
114 my $logmessage = $_[0];
115 $logmessage =~ /([\w\W]*)/;
116 $logmessage = $1;
2a52353f 117 &system('logger', '-t', $tag, $logmessage);
ac1cfefa 118}
111c99dd
MT
119sub setup_default_networks
120{
121 my %netsettings=();
122 my $defaultNetworks = shift;
123
124 &readhash("/var/ipfire/ethernet/settings", \%netsettings);
125
126 # Get current defined networks (Red, Green, Blue, Orange)
127 $defaultNetworks->{$Lang::tr{'fwhost any'}}{'IPT'} = "0.0.0.0/0.0.0.0";
128 $defaultNetworks->{$Lang::tr{'fwhost any'}}{'NAME'} = "ALL";
129
130 $defaultNetworks->{$Lang::tr{'green'}}{'IPT'} = "$netsettings{'GREEN_NETADDRESS'}/$netsettings{'GREEN_NETMASK'}";
68f6312a 131 $defaultNetworks->{$Lang::tr{'green'}}{'NET'} = "$netsettings{'GREEN_ADDRESS'}";
111c99dd
MT
132 $defaultNetworks->{$Lang::tr{'green'}}{'NAME'} = "GREEN";
133
b9648e58 134 if ($netsettings{'RED_DEV'} ne ''){
223d3b1d 135 $defaultNetworks->{$Lang::tr{'fwdfw red'}}{'IPT'} = "$netsettings{'RED_NETADDRESS'}/$netsettings{'RED_NETMASK'}";
68f6312a 136 $defaultNetworks->{$Lang::tr{'fwdfw red'}}{'NET'} = "$netsettings{'RED_ADDRESS'}";
223d3b1d 137 $defaultNetworks->{$Lang::tr{'fwdfw red'}}{'NAME'} = "RED";
b9648e58 138 }
111c99dd
MT
139 if ($netsettings{'ORANGE_DEV'} ne ''){
140 $defaultNetworks->{$Lang::tr{'orange'}}{'IPT'} = "$netsettings{'ORANGE_NETADDRESS'}/$netsettings{'ORANGE_NETMASK'}";
68f6312a 141 $defaultNetworks->{$Lang::tr{'orange'}}{'NET'} = "$netsettings{'ORANGE_ADDRESS'}";
111c99dd
MT
142 $defaultNetworks->{$Lang::tr{'orange'}}{'NAME'} = "ORANGE";
143 }
144
145 if ($netsettings{'BLUE_DEV'} ne ''){
146 $defaultNetworks->{$Lang::tr{'blue'}}{'IPT'} = "$netsettings{'BLUE_NETADDRESS'}/$netsettings{'BLUE_NETMASK'}";
68f6312a 147 $defaultNetworks->{$Lang::tr{'blue'}}{'NET'} = "$netsettings{'BLUE_ADDRESS'}";
111c99dd
MT
148 $defaultNetworks->{$Lang::tr{'blue'}}{'NAME'} = "BLUE";
149 }
c7043621
AM
150
151 #IPFire himself
152 $defaultNetworks->{'IPFire'}{'NAME'} = "IPFire";
111c99dd
MT
153
154 # OpenVPN
155 if(-e "${General::swroot}/ovpn/settings")
156 {
157 my %ovpnSettings = ();
158 &readhash("${General::swroot}/ovpn/settings", \%ovpnSettings);
159
160 # OpenVPN on Red?
161 if(defined($ovpnSettings{'DOVPN_SUBNET'}))
162 {
163 my ($ip,$sub) = split(/\//,$ovpnSettings{'DOVPN_SUBNET'});
164 $sub=&General::iporsubtocidr($sub);
165 my @tempovpnsubnet = split("\/", $ovpnSettings{'DOVPN_SUBNET'});
1a8fde0e
AM
166 $defaultNetworks->{'OpenVPN ' ."($ip/$sub)"}{'ADR'} = $tempovpnsubnet[0];
167 $defaultNetworks->{'OpenVPN ' ."($ip/$sub)"}{'NAME'} = "OpenVPN-Dyn";
111c99dd
MT
168 }
169 } # end OpenVPN
170 # IPsec RW NET
171 if(-e "${General::swroot}/vpn/settings")
172 {
173 my %ipsecsettings = ();
174 &readhash("${General::swroot}/vpn/settings", \%ipsecsettings);
175 if($ipsecsettings{'RW_NET'} ne '')
176 {
177 my ($ip,$sub) = split(/\//,$ipsecsettings{'RW_NET'});
178 $sub=&General::iporsubtocidr($sub);
179 my @tempipsecsubnet = split("\/", $ipsecsettings{'RW_NET'});
6ee90535
AM
180 $defaultNetworks->{'IPsec RW (' .$ip."/".$sub.")"}{'ADR'} = $tempipsecsubnet[0];
181 $defaultNetworks->{'IPsec RW (' .$ip."/".$sub.")"}{'NAME'} = "IPsec RW";
182 $defaultNetworks->{'IPsec RW (' .$ip."/".$sub.")"}{'NET'} = &getnextip($ip);
111c99dd
MT
183 }
184 }
111c99dd
MT
185}
186sub get_aliases
187{
188
189 my $defaultNetworks = shift;
190 open(FILE, "${General::swroot}/ethernet/aliases") or die 'Unable to open aliases file.';
191 my @current = <FILE>;
192 close(FILE);
193 my $ctr = 0;
194 foreach my $line (@current)
195 {
196 if ($line ne ''){
197 chomp($line);
198 my @temp = split(/\,/,$line);
199 if ($temp[2] eq '') {
200 $temp[2] = "Alias $ctr : $temp[0]";
201 }
202 $defaultNetworks->{$temp[2]}{'IPT'} = "$temp[0]";
68f6312a 203 $defaultNetworks->{$temp[2]}{'NET'} = "$temp[0]";
111c99dd
MT
204
205 $ctr++;
206 }
207 }
208}
ac1cfefa
MT
209
210sub readhash
211{
212 my $filename = $_[0];
213 my $hash = $_[1];
214 my ($var, $val);
215
216
217 # Some ipcop code expects that readhash 'complete' the hash if new entries
218 # are presents. Not clear it !!!
219 #%$hash = ();
220
221 open(FILE, $filename) or die "Unable to read file $filename";
222
223 while (<FILE>)
224 {
225 chop;
9f5247f6
SS
226
227 # Skip comments.
06f57f72 228 next if ($_ =~ /^#/);
9f5247f6 229
ac1cfefa
MT
230 ($var, $val) = split /=/, $_, 2;
231 if ($var)
232 {
233 $val =~ s/^\'//g;
234 $val =~ s/\'$//g;
235
236 # Untaint variables read from hash
77007ce5
MT
237 # trim space from begin and end
238 $var =~ s/^\s+//;
239 $var =~ s/\s+$//;
240 $var =~ /([A-Za-z0-9_-]*)/;
241 $var = $1;
242 $val =~ /([\w\W]*)/;
243 $val = $1;
ac1cfefa
MT
244 $hash->{$var} = $val;
245 }
246 }
247 close FILE;
248}
249
250
251sub writehash
252{
253 my $filename = $_[0];
254 my $hash = $_[1];
255 my ($var, $val);
256
257 # write cgi vars to the file.
258 open(FILE, ">${filename}") or die "Unable to write file $filename";
259 flock FILE, 2;
260 foreach $var (keys %$hash)
261 {
ad60e3ea 262 if ( $var eq "__CGI__"){next;}
ac1cfefa
MT
263 $val = $hash->{$var};
264 # Darren Critchley Jan 17, 2003 added the following because when submitting with a graphic, the x and y
265 # location of the mouse are submitted as well, this was being written to the settings file causing
266 # some serious grief! This skips the variable.x and variable.y
267 if (!($var =~ /(.x|.y)$/)) {
268 if ($val =~ / /) {
269 $val = "\'$val\'"; }
270 if (!($var =~ /^ACTION/)) {
271 print FILE "${var}=${val}\n"; }
272 }
273 }
274 close FILE;
275}
276
90c2e164
CS
277sub writehashpart
278{
279 # This function replaces the given hash in the original hash by keeping the old
280 # content and just replacing the new content
281
282 my $filename = $_[0];
283 my $newhash = $_[1];
284 my %oldhash;
285 my ($var, $val);
286
287 readhash("${filename}", \%oldhash);
288
289 foreach $var (keys %$newhash){
290 $oldhash{$var}=$newhash->{$var};
291 }
292
293 # write cgi vars to the file.
294 open(FILE, ">${filename}") or die "Unable to write file $filename";
295 flock FILE, 2;
296 foreach $var (keys %oldhash)
297 {
298 if ( $var eq "__CGI__"){next;}
299 $val = $oldhash{$var};
300 # Darren Critchley Jan 17, 2003 added the following because when submitting with a graphic, the x and y
301 # location of the mouse are submitted as well, this was being written to the settings file causing
302 # some serious grief! This skips the variable.x and variable.y
303 if (!($var =~ /(.x|.y)$/)) {
304 if ($val =~ / /) {
305 $val = "\'$val\'"; }
306 if (!($var =~ /^ACTION/)) {
307 print FILE "${var}=${val}\n"; }
308 }
309 }
310 close FILE;
311}
ac1cfefa 312
1dc44471 313sub age {
ac1cfefa 314 my ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size,
1dc44471 315 $atime, $mtime, $ctime, $blksize, $blocks) = stat $_[0];
a0b271e4
MT
316 my $t = time() - $mtime;
317
318 return &format_time($t);
319}
320
321sub format_time($) {
322 my $totalsecs = shift;
1dc44471 323 my @s = ();
ac1cfefa 324
ac1cfefa 325 my $secs = $totalsecs % 60;
1dc44471
MT
326 $totalsecs /= 60;
327 if ($secs > 0) {
328 push(@s, "${secs}s");
3687a2e2
JIW
329 }
330
1dc44471
MT
331 my $min = $totalsecs % 60;
332 $totalsecs /= 60;
333 if ($min > 0) {
334 push(@s, "${min}m");
3687a2e2
JIW
335 }
336
1dc44471
MT
337 my $hrs = $totalsecs % 24;
338 $totalsecs /= 24;
339 if ($hrs > 0) {
340 push(@s, "${hrs}h");
3687a2e2
JIW
341 }
342
1dc44471
MT
343 my $days = int($totalsecs);
344 if ($days > 0) {
345 push(@s, "${days}d");
3687a2e2 346 }
3687a2e2 347
1dc44471 348 return join(" ", reverse(@s));
ac1cfefa
MT
349}
350
351sub validip
352{
353 my $ip = $_[0];
354
355 if (!($ip =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/)) {
356 return 0; }
357 else
358 {
359 my @octets = ($1, $2, $3, $4);
360 foreach $_ (@octets)
361 {
362 if (/^0./) {
363 return 0; }
364 if ($_ < 0 || $_ > 255) {
365 return 0; }
366 }
367 return 1;
368 }
369}
370
4e9a2b57
MT
371sub validmask {
372 my $mask = shift;
ac1cfefa 373
c1420324 374 return &Network::check_netmask($mask) || &Network::check_prefix($mask);
ac1cfefa
MT
375}
376
377sub validipormask
378{
379 my $ipormask = $_[0];
380
381 # see if it is a IP only.
382 if (&validip($ipormask)) {
383 return 1; }
384 # split it into number and mask.
385 if (!($ipormask =~ /^(.*?)\/(.*?)$/)) {
386 return 0; }
387 my $ip = $1;
388 my $mask = $2;
389 # first part not a ip?
390 if (!(&validip($ip))) {
391 return 0; }
392 return &validmask($mask);
393}
394
4e9a2b57
MT
395sub subtocidr {
396 return &Network::convert_netmask2prefix(shift);
8c877a82 397}
ac1cfefa 398
4e9a2b57
MT
399sub cidrtosub {
400 return &Network::convert_prefix2netmask(shift);
8c877a82
AM
401}
402
403sub iporsubtodec
404{
405 #Gets: Ip address or subnetmask in decimal oder CIDR
406 #Gives: What it gets only in CIDR format
407 my $subnet=$_[0];
408 my $net;
409 my $mask;
410 my $full=0;
411 if ($subnet =~ /^(.*?)\/(.*?)$/) {
412 ($net,$mask) = split (/\//,$subnet);
413 $full=1;
414 return "$subnet";
415 }else{
416 $mask=$subnet;
417 }
418 #Subnet already in decimal and valid?
419 if ($mask=~/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/ &&(($1<=255 && $2<=$1 && $3<=$2 && $4<=$3 ))) {
7490b22e 420 for (my $i=0;$i<=32;$i++){
8c877a82
AM
421 if (&General::cidrtosub($i) eq $mask){
422 if ($full == 0){return $mask;}else{
423 return $net."/".$mask;
424 }
425 }
426 }
427 }
428 #Subnet in binary format?
7490b22e 429 if ($mask=~/^(\d{1,2})$/ && (($1<=32 && $1>=0))){
8c877a82
AM
430 if($full == 0){ return &General::cidrtosub($mask);}else{
431 return $net."/".&General::cidrtosub($mask);
432 }
433 }else{
434 return 3;
435 }
436 return 3;
437}
438
439
440sub iporsubtocidr
441{
442 #gets: Ip Address or subnetmask in decimal oder CIDR
443 #Gives: What it gets only in CIDR format
444 my $subnet=$_[0];
445 my $net;
446 my $mask;
447 my $full=0;
448 if ($subnet =~ /^(.*?)\/(.*?)$/) {
449 ($net,$mask) = split (/\//,$subnet);
450 $full=1;
451 }else{
452 $mask=$subnet;
453 }
454 #Subnet in decimal and valid?
455 if ($mask=~/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/ &&(($1<=255 && $2<=$1 && $3<=$2 && $4<=$3 ))) {
7490b22e 456 for (my $i=0;$i<=32;$i++){
8c877a82
AM
457 if (&General::cidrtosub($i) eq $mask){
458 if ($full == 0){return &General::subtocidr($mask);}else{
459 return $net."/".&General::subtocidr($mask);
460 }
461 }
462 }
463 }
464 #Subnet already in binary format?
7490b22e 465 if ($mask=~/^(\d{1,2})$/ && (($1<=32 && $1>=0))){
8c877a82
AM
466 if($full == 0){ return $mask;}else{
467 return $net."/".$mask;
468 }
469 }else{
470 return 3;
471 }
472 return 3;
473}
474
4e9a2b57 475sub getnetworkip {
da05e076 476 my $arg = join("/", @_);
6a2a62cf
MT
477
478 return &Network::get_netaddress($arg);
8c877a82
AM
479}
480
481sub getccdbc
482{
483 #Gets: IP in Form ("192.168.0.0/24")
484 #Gives: Broadcastaddress of network
485 my $ccdnet=$_;
486 my ($ccdip,$ccdsubnet) = split "/",$ccdnet;
487 my $ip_address_binary = inet_aton( $ccdip );
488 my $netmask_binary = ~pack("N", (2**(32-$ccdsubnet))-1);
489 my $broadcast_address = inet_ntoa( $ip_address_binary | ~$netmask_binary );
490 return $broadcast_address;
491}
e81be1e1 492
4e9a2b57
MT
493sub ip2dec {
494 return &Network::ip2bin(shift);
8c877a82 495}
e81be1e1 496
4e9a2b57
MT
497sub dec2ip {
498 return &Network::bin2ip(shift);
499}
500
501sub getnextip {
502 return &Network::find_next_ip_address(shift, 4);
503}
504
505sub getlastip {
506 return &Network::find_next_ip_address(shift, -1);
8c877a82
AM
507}
508
509sub validipandmask
510{
511 #Gets: Ip address in 192.168.0.0/24 or 192.168.0.0/255.255.255.0 and checks if subnet valid
512 #Gives: True bzw 0 if success or false
513 my $ccdnet=$_[0];
514 my $subcidr;
515
516 if (!($ccdnet =~ /^(.*?)\/(.*?)$/)) {
517 return 0;
518 }
519 my ($ccdip,$ccdsubnet)=split (/\//, $ccdnet);
520 #IP valid?
521 if ($ccdip=~/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/ &&(($1>0 && $1<=255 && $2>=0 && $2<=255 && $3>=0 && $3<=255 && $4<=255 ))) {
522 #Subnet in decimal and valid?
523 if ($ccdsubnet=~/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/ &&(($1<=255 && $2<=$1 && $3<=$2 && $4<=$3 ))) {
7490b22e 524 for (my $i=0;$i<=32;$i++){
8c877a82
AM
525 if (&General::cidrtosub($i) eq $ccdsubnet){
526 return 1;
527 }
7490b22e 528 }
8c877a82 529 #Subnet already in binary format?
7490b22e 530 }elsif ($ccdsubnet=~/^(\d{1,2})$/ && (($1<=32 && $1>=0))){
8c877a82
AM
531 return 1;
532 }else{
533 return 0;
534 }
535
536 }
537 return 0;
ac1cfefa
MT
538}
539
e2429e8d
AM
540sub checksubnets
541{
4d81e0f3
AM
542 my %ccdconfhash=();
543 my %ovpnconfhash=();
544 my %vpnconf=();
545 my %ipsecconf=();
546 my %ownnet=();
547 my %ovpnconf=();
548 my @ccdconf=();
549 my $ccdname=$_[0];
550 my $ccdnet=$_[1];
551 my $ownnet=$_[2];
b7ab17ad 552 my $checktype=$_[3];
e2429e8d
AM
553 my $errormessage;
554 my ($ip,$cidr)=split(/\//,$ccdnet);
555 $cidr=&iporsubtocidr($cidr);
4d81e0f3 556
e2429e8d 557 #get OVPN-Subnet (dynamic range)
e2429e8d
AM
558 &readhash("${General::swroot}/ovpn/settings", \%ovpnconf);
559 my ($ovpnip,$ovpncidr)= split (/\//,$ovpnconf{'DOVPN_SUBNET'});
560 $ovpncidr=&iporsubtocidr($ovpncidr);
4d81e0f3 561
e2429e8d
AM
562 #check if we try to use same network as ovpn server
563 if ("$ip/$cidr" eq "$ovpnip/$ovpncidr") {
564 $errormessage=$errormessage.$Lang::tr{'ccd err isovpnnet'}."<br>";
565 return $errormessage;
566 }
4d81e0f3
AM
567
568 #check if we try to use same network as another ovpn N2N
569 if($ownnet ne 'ovpn'){
570 &readhasharray("${General::swroot}/ovpn/ovpnconfig", \%ovpnconfhash);
571 foreach my $key (keys %ovpnconfhash) {
572 if ($ovpnconfhash{$key}[3] eq 'net'){
573 my @ovpnnet=split (/\//,$ovpnconfhash{$key}[11]);
574 if (&IpInSubnet($ip,$ovpnnet[0],&iporsubtodec($ovpnnet[1]))){
575 $errormessage=$errormessage.$Lang::tr{'ccd err isovpnn2n'}." $ovpnconfhash{$key}[1] <br>";
576 return $errormessage;
577 }
578 }
579 }
580 }
581
582 #check if we use a network-name/subnet (static-ovpn) that already exists
e2429e8d
AM
583 &readhasharray("${General::swroot}/ovpn/ccd.conf", \%ccdconfhash);
584 foreach my $key (keys %ccdconfhash) {
585 @ccdconf=split(/\//,$ccdconfhash{$key}[1]);
586 if ($ccdname eq $ccdconfhash{$key}[0])
587 {
588 $errormessage=$errormessage.$Lang::tr{'ccd err nameexist'}."<br>";
589 return $errormessage;
590 }
591 my ($newip,$newsub) = split(/\//,$ccdnet);
592 if (&IpInSubnet($newip,$ccdconf[0],&iporsubtodec($ccdconf[1])))
593 {
4d81e0f3 594 $errormessage=$errormessage.$Lang::tr{'ccd err issubnet'}." $ccdconfhash{$key}[0]<br>";
e2429e8d
AM
595 return $errormessage;
596 }
e2429e8d 597 }
4d81e0f3 598
e2429e8d 599 #check if we use a ipsec right network which is already defined
4d81e0f3
AM
600 if($ownnet ne 'ipsec'){
601 &General::readhasharray("${General::swroot}/vpn/config", \%ipsecconf);
602 foreach my $key (keys %ipsecconf){
087e3023 603 if ($ipsecconf{$key}[11] ne '' && $ipsecconf{$key}[36] eq ""){
ecc9c73b 604 foreach my $ipsecsubitem (split(/\|/, $ipsecconf{$key}[11])) {
db4e10a6 605 my ($ipsecip,$ipsecsub) = split (/\//, $ipsecsubitem);
ecc9c73b
HG
606 $ipsecsub=&iporsubtodec($ipsecsub);
607 if($ipsecconf{$key}[1] ne $ccdname){
608 if ( &IpInSubnet ($ip,$ipsecip,$ipsecsub) ){
609 $errormessage=$Lang::tr{'ccd err isipsecnet'}." Name: $ipsecconf{$key}[1]";
610 return $errormessage;
611 }
4d81e0f3 612 }
f7e3d208 613 }
e2429e8d
AM
614 }
615 }
616 }
4d81e0f3
AM
617
618 #check if we use the ipsec RW Network (if defined)
619 &readhash("${General::swroot}/vpn/settings", \%vpnconf);
620 if ($vpnconf{'RW_NET'} ne ''){
621 my ($ipsecrwnet,$ipsecrwsub)=split (/\//, $vpnconf{'RW_NET'});
622 if (&IpInSubnet($ip,$ipsecrwnet,&iporsubtodec($ipsecrwsub)))
623 {
624 $errormessage=$errormessage.$Lang::tr{'ccd err isipsecrw'}."<br>";
625 return $errormessage;
626 }
627 }
4f857eea
AM
628
629 #call check_net_internal
b7ab17ad
AM
630 if ($checktype eq "exact")
631 {
632 &General::check_net_internal_exact($ccdnet);
633 }else{
634 &General::check_net_internal_range($ccdnet);
635 }
e2429e8d
AM
636}
637
b7ab17ad 638sub check_net_internal_range{
29f238b2
AM
639 my $network=shift;
640 my ($ip,$cidr)=split(/\//,$network);
641 my %ownnet=();
642 my $errormessage;
643 $cidr=&iporsubtocidr($cidr);
644 #check if we use one of ipfire's networks (green,orange,blue)
645 &readhash("${General::swroot}/ethernet/settings", \%ownnet);
65c3b7c9
MT
646 if (($ownnet{'GREEN_NETADDRESS'} ne '' && $ownnet{'GREEN_NETADDRESS'} ne '0.0.0.0') && &IpInSubnet($ip,$ownnet{'GREEN_NETADDRESS'},&iporsubtodec($ownnet{'GREEN_NETMASK'}))){ $errormessage=$Lang::tr{'ccd err green'};return $errormessage;}
647 if (($ownnet{'ORANGE_NETADDRESS'} ne '' && $ownnet{'ORANGE_NETADDRESS'} ne '0.0.0.0') && &IpInSubnet($ip,$ownnet{'ORANGE_NETADDRESS'},&iporsubtodec($ownnet{'ORANGE_NETMASK'}))){ $errormessage=$Lang::tr{'ccd err orange'};return $errormessage;}
648 if (($ownnet{'BLUE_NETADDRESS'} ne '' && $ownnet{'BLUE_NETADDRESS'} ne '0.0.0.0') && &IpInSubnet($ip,$ownnet{'BLUE_NETADDRESS'},&iporsubtodec($ownnet{'BLUE_NETMASK'}))){ $errormessage=$Lang::tr{'ccd err blue'};return $errormessage;}
649 if (($ownnet{'RED_NETADDRESS'} ne '' && $ownnet{'RED_NETADDRESS'} ne '0.0.0.0') && &IpInSubnet($ip,$ownnet{'RED_NETADDRESS'},&iporsubtodec($ownnet{'RED_NETMASK'}))){ $errormessage=$Lang::tr{'ccd err red'};return $errormessage;}
b7ab17ad
AM
650}
651
652sub check_net_internal_exact{
653 my $network=shift;
654 my ($ip,$cidr)=split(/\//,$network);
655 my %ownnet=();
656 my $errormessage;
657 $cidr=&iporsubtocidr($cidr);
658 #check if we use one of ipfire's networks (green,orange,blue)
659 &readhash("${General::swroot}/ethernet/settings", \%ownnet);
660 if (($ownnet{'GREEN_NETADDRESS'} ne '' && $ownnet{'GREEN_NETADDRESS'} ne '0.0.0.0') && &Network::network_equal("$ownnet{'GREEN_NETADDRESS'}/$ownnet{'GREEN_NETMASK'}", $network)){ $errormessage=$Lang::tr{'ccd err green'};return $errormessage;}
661 if (($ownnet{'ORANGE_NETADDRESS'} ne '' && $ownnet{'ORANGE_NETADDRESS'} ne '0.0.0.0') && &Network::network_equal("$ownnet{'ORANGE_NETADDRESS'}/$ownnet{'ORANGE_NETMASK'}", $network)){ $errormessage=$Lang::tr{'ccd err orange'};return $errormessage;}
662 if (($ownnet{'BLUE_NETADDRESS'} ne '' && $ownnet{'BLUE_NETADDRESS'} ne '0.0.0.0') && &Network::network_equal("$ownnet{'BLUE_NETADDRESS'}/$ownnet{'BLUE_NETMASK'}", $network)){ $errormessage=$Lang::tr{'ccd err blue'};return $errormessage;}
663 if (($ownnet{'RED_NETADDRESS'} ne '' && $ownnet{'RED_NETADDRESS'} ne '0.0.0.0') && &Network::network_equal("$ownnet{'RED_NETADDRESS'}/$ownnet{'RED_NETMASK'}", $network)){ $errormessage=$Lang::tr{'ccd err red'};return $errormessage;}
29f238b2 664}
e2429e8d 665
ac1cfefa
MT
666sub validport
667{
668 $_ = $_[0];
669
670 if (!/^\d+$/) {
671 return 0; }
672 if (/^0./) {
673 return 0; }
674 if ($_ >= 1 && $_ <= 65535) {
675 return 1; }
676 return 0;
677}
678
d30ea451
CS
679sub validproxyport
680{
681 $_ = $_[0];
682
683 if (!/^\d+$/) {
684 return 0; }
685 if (/^0./) {
686 return 0; }
687 if ($_ == 53 || $_ == 222 || $_ == 444 || $_ == 81 ) {
688 return 0; }
689 elsif ($_ >= 1 && $_ <= 65535) {
690 return 1; }
691 return 0;
692}
693
ac1cfefa
MT
694sub validmac
695{
696 my $checkmac = $_[0];
697 my $ot = '[0-9a-f]{2}'; # 2 Hex digits (one octet)
698 if ($checkmac !~ /^$ot:$ot:$ot:$ot:$ot:$ot$/i)
699 {
700 return 0;
701 }
702 return 1;
703}
704
705sub validhostname
706{
707 # Checks a hostname against RFC1035
708 my $hostname = $_[0];
709
5b4e33bc 710 # Hostname should be at least one character in length
ac1cfefa
MT
711 # but no more than 63 characters
712 if (length ($hostname) < 1 || length ($hostname) > 63) {
713 return 0;}
714 # Only valid characters are a-z, A-Z, 0-9 and -
5b4e33bc 715 if ($hostname !~ /^[a-zA-Z0-9-]*$/) {
ac1cfefa
MT
716 return 0;}
717 # First character can only be a letter or a digit
718 if (substr ($hostname, 0, 1) !~ /^[a-zA-Z0-9]*$/) {
719 return 0;}
720 # Last character can only be a letter or a digit
721 if (substr ($hostname, -1, 1) !~ /^[a-zA-Z0-9]*$/) {
722 return 0;}
723 return 1;
724}
725
726sub validdomainname
727{
728 my $part;
729
5b4e33bc 730 # Checks a domain name against RFC1035 and RFC2181
ac1cfefa 731 my $domainname = $_[0];
5b4e33bc 732 my @parts = split (/\./, $domainname); # Split domain name at the '.'
ac1cfefa
MT
733
734 foreach $part (@parts) {
5b4e33bc
AB
735 # Each part should be at least one character in length
736 # but no more than 63 characters
8ed77b03 737 if (length ($part) < 1 || length ($part) > 63) {
ac1cfefa 738 return 0;}
03306ff6
MT
739 # Only valid characters are a-z, A-Z, 0-9, _ and -
740 if ($part !~ /^[a-zA-Z0-9_-]*$/) {
5b4e33bc 741 return 0;}
ac1cfefa
MT
742 }
743 return 1;
744}
745
746sub validfqdn
747{
5b4e33bc 748 # Checks a fully qualified domain name against RFC1035 and RFC2181
ac1cfefa 749 my $fqdn = $_[0];
5b4e33bc 750 my @parts = split (/\./, $fqdn); # Split FQDN at the '.'
ac1cfefa
MT
751 if (scalar(@parts) < 2) { # At least two parts should
752 return 0;} # exist in a FQDN
b00797e2 753 # (i.e.hostname.domain)
5b4e33bc
AB
754
755 for (my $index=0; $index < scalar(@parts); $index++) {
ac1cfefa
MT
756 # Each part should be at least one character in length
757 # but no more than 63 characters
5b4e33bc 758 if (length ($parts[$index]) < 1 || length ($parts[$index]) > 63) {
ac1cfefa 759 return 0;}
5b4e33bc
AB
760 if ($index eq 0) {
761 # This is the hostname part
762 # Only valid characters are a-z, A-Z, 0-9 and -
763 if ($parts[$index] !~ /^[a-zA-Z0-9-]*$/) {
764 return 0;}
765 # First character can only be a letter or a digit
766 if (substr ($parts[$index], 0, 1) !~ /^[a-zA-Z0-9]*$/) {
767 return 0;}
768 # Last character can only be a letter or a digit
769 if (substr ($parts[$index], -1, 1) !~ /^[a-zA-Z0-9]*$/) {
770 return 0;}
771 } else{
772 # This is the domain part
773 # Only valid characters are a-z, A-Z, 0-9, _ and -
774 if ($parts[$index] !~ /^[a-zA-Z0-9_-]*$/) {
775 return 0;}
776 }
ac1cfefa
MT
777 }
778 return 1;
779}
780
781sub validportrange # used to check a port range
782{
783 my $port = $_[0]; # port values
784 $port =~ tr/-/:/; # replace all - with colons just in case someone used -
785 my $srcdst = $_[1]; # is it a source or destination port
786
787 if (!($port =~ /^(\d+)\:(\d+)$/)) {
788
789 if (!(&validport($port))) {
790 if ($srcdst eq 'src'){
791 return $Lang::tr{'source port numbers'};
792 } else {
793 return $Lang::tr{'destination port numbers'};
794 }
795 }
796 }
797 else
798 {
799 my @ports = ($1, $2);
800 if ($1 >= $2){
801 if ($srcdst eq 'src'){
802 return $Lang::tr{'bad source range'};
803 } else {
804 return $Lang::tr{'bad destination range'};
805 }
806 }
807 foreach $_ (@ports)
808 {
809 if (!(&validport($_))) {
810 if ($srcdst eq 'src'){
811 return $Lang::tr{'source port numbers'};
812 } else {
813 return $Lang::tr{'destination port numbers'};
814 }
815 }
816 }
817 return;
818 }
819}
820
4e9a2b57 821sub IpInSubnet {
ab92dc0c
AM
822 my $addr = shift;
823 my $network = shift;
824 my $netmask = shift;
825
4e9a2b57 826 return &Network::ip_address_in_network($addr, "$network/$netmask");
ac1cfefa
MT
827}
828
c545beb1
MT
829#
830# Return the following IP (IP+1) in dotted notation.
831# Call: NextIP ('1.1.1.1');
832# Return: '1.1.1.2'
833#
4e9a2b57
MT
834sub NextIP {
835 return &Network::find_next_ip_address(shift, 1);
c545beb1 836}
4e9a2b57
MT
837
838sub NextIP2 {
839 return &Network::find_next_ip_address(shift, 4);
8c877a82 840}
4e9a2b57
MT
841
842sub ipcidr {
45762fc6
AF
843 my ($ip,$cidr) = &Net::IPv4Addr::ipv4_parse(shift);
844 return "$ip\/$cidr";
845}
846
4e9a2b57 847sub ipcidr2msk {
54fd0535
MT
848 my ($ip,$cidr) = &Net::IPv4Addr::ipv4_parse(shift);
849 my $netmask = &Net::IPv4Addr::ipv4_cidr2msk($cidr);
850 return "$ip\/$netmask";
851}
852
ac1cfefa 853sub validemail {
b00797e2
AM
854 my $address = shift;
855 my @parts = split( /\@/, $address );
856 my $count=@parts;
857
858 #check if we have one part before and after '@'
859 return 0 if ( $count != 2 );
860
861 #check if one of the parts starts or ends with a dot
862 return 0 if ( substr($parts[0],0,1) eq '.' );
863 return 0 if ( substr($parts[0],-1,1) eq '.' );
864 return 0 if ( substr($parts[1],0,1) eq '.' );
865 return 0 if ( substr($parts[1],-1,1) eq '.' );
866
867 #check first addresspart (before '@' sign)
cc724c14 868 return 0 if ( $parts[0] !~ m/^[a-zA-Z0-9\.!\-\_\+#]+$/ );
b00797e2
AM
869
870 #check second addresspart (after '@' sign)
871 return 0 if ( $parts[1] !~ m/^[a-zA-Z0-9\.\-]+$/ );
872
ac1cfefa
MT
873 return 1;
874}
875
c545beb1
MT
876#
877# Currently only vpnmain use this three procs (readhasharray, writehasharray, findhasharray)
878# The 'key' used is numeric but is perfectly unneeded! This will to be removed so don't use
879# this code. Vpnmain will be splitted in parts: x509/pki, connection ipsec, connection other,... .
880#
ac1cfefa
MT
881sub readhasharray {
882 my ($filename, $hash) = @_;
883 %$hash = ();
884
885 open(FILE, $filename) or die "Unable to read file $filename";
886
887 while (<FILE>) {
888 my ($key, $rest, @temp);
889 chomp;
890 ($key, $rest) = split (/,/, $_, 2);
c545beb1 891 if ($key =~ /^[0-9]+$/) {
ac1cfefa
MT
892 @temp = split (/,/, $rest);
893 $hash->{$key} = \@temp;
894 }
895 }
896 close FILE;
897 return;
898}
899
900sub writehasharray {
901 my ($filename, $hash) = @_;
902 my ($key, @temp, $i);
903
904 open(FILE, ">$filename") or die "Unable to write to file $filename";
905
906 foreach $key (keys %$hash) {
8c877a82
AM
907 if ($key =~ /^[0-9]+$/) {
908 print FILE "$key";
909 foreach $i (0 .. $#{$hash->{$key}}) {
910 print FILE ",$hash->{$key}[$i]";
911 }
912 print FILE "\n";
913 }
ac1cfefa
MT
914 }
915 close FILE;
916 return;
917}
918
919sub findhasharraykey {
920 foreach my $i (1 .. 1000000) {
921 if ( ! exists $_[0]{$i}) {
922 return $i;
923 }
924 }
925}
926
927sub srtarray
928# Darren Critchley - darrenc@telus.net - (c) 2003
929# &srtarray(SortOrder, AlphaNumeric, SortDirection, ArrayToBeSorted)
930# This subroutine will take the following parameters:
931# ColumnNumber = the column which you want to sort on, starts at 1
932# AlphaNumberic = a or n (lowercase) defines whether the sort should be alpha or numberic
933# SortDirection = asc or dsc (lowercase) Ascending or Descending sort
934# ArrayToBeSorted = the array that wants sorting
935#
936# Returns an array that is sorted to your specs
937#
938# If SortOrder is greater than the elements in array, then it defaults to the first element
939#
940{
941 my ($colno, $alpnum, $srtdir, @tobesorted) = @_;
942 my @tmparray;
943 my @srtedarray;
944 my $line;
945 my $newline;
946 my $ctr;
947 my $ttlitems = scalar @tobesorted; # want to know the number of rows in the passed array
948 if ($ttlitems < 1){ # if no items, don't waste our time lets leave
949 return (@tobesorted);
950 }
951 my @tmp = split(/\,/,$tobesorted[0]);
952 $ttlitems = scalar @tmp; # this should be the number of elements in each row of the passed in array
953
954 # Darren Critchley - validate parameters
955 if ($colno > $ttlitems){$colno = '1';}
956 $colno--; # remove one from colno to deal with arrays starting at 0
957 if($colno < 0){$colno = '0';}
958 if ($alpnum ne '') { $alpnum = lc($alpnum); } else { $alpnum = 'a'; }
959 if ($srtdir ne '') { $srtdir = lc($srtdir); } else { $srtdir = 'src'; }
960
961 foreach $line (@tobesorted)
962 {
963 chomp($line);
964 if ($line ne '') {
965 my @temp = split(/\,/,$line);
966 # Darren Critchley - juggle the fields so that the one we want to sort on is first
967 my $tmpholder = $temp[0];
968 $temp[0] = $temp[$colno];
969 $temp[$colno] = $tmpholder;
970 $newline = "";
971 for ($ctr=0; $ctr < $ttlitems ; $ctr++) {
972 $newline=$newline . $temp[$ctr] . ",";
973 }
974 chop($newline);
975 push(@tmparray,$newline);
976 }
977 }
978 if ($alpnum eq 'n') {
979 @tmparray = sort {$a <=> $b} @tmparray;
980 } else {
981 @tmparray = (sort @tmparray);
982 }
983 foreach $line (@tmparray)
984 {
985 chomp($line);
986 if ($line ne '') {
987 my @temp = split(/\,/,$line);
988 my $tmpholder = $temp[0];
989 $temp[0] = $temp[$colno];
990 $temp[$colno] = $tmpholder;
991 $newline = "";
992 for ($ctr=0; $ctr < $ttlitems ; $ctr++){
993 $newline=$newline . $temp[$ctr] . ",";
994 }
995 chop($newline);
996 push(@srtedarray,$newline);
997 }
998 }
999
1000 if ($srtdir eq 'dsc') {
1001 @tmparray = reverse(@srtedarray);
1002 return (@tmparray);
1003 } else {
1004 return (@srtedarray);
1005 }
1006}
1007
1008sub FetchPublicIp {
1009 my %proxysettings;
1010 &General::readhash("${General::swroot}/proxy/settings", \%proxysettings);
1011 if ($_=$proxysettings{'UPSTREAM_PROXY'}) {
1012 my ($peer, $peerport) = (/^(?:[a-zA-Z ]+\:\/\/)?(?:[A-Za-z0-9\_\.\-]*?(?:\:[A-Za-z0-9\_\.\-]*?)?\@)?([a-zA-Z0-9\.\_\-]*?)(?:\:([0-9]{1,5}))?(?:\/.*?)?$/);
1013 Net::SSLeay::set_proxy($peer,$peerport,$proxysettings{'UPSTREAM_USER'},$proxysettings{'UPSTREAM_PASSWORD'} );
1014 }
b2f8244a 1015 my $user_agent = &MakeUserAgent();
0aa0cdcd 1016 my ($out, $response) = Net::SSLeay::get_http( 'checkip4.dns.lightningwirelabs.com',
ac1cfefa
MT
1017 80,
1018 "/",
b2f8244a 1019 Net::SSLeay::make_headers('User-Agent' => $user_agent )
ac1cfefa
MT
1020 );
1021 if ($response =~ m%HTTP/1\.. 200 OK%) {
5a2935b1 1022 $out =~ /Your IP address is: (\d+.\d+.\d+.\d+)/;
ac1cfefa
MT
1023 return $1;
1024 }
1025 return '';
1026}
1027
1028#
1029# Check if hostname.domain provided have IP provided
1030# use gethostbyname to verify that
1031# Params:
1032# IP
1033# hostname
1034# domain
1035# Output
1036# 1 IP matches host.domain
1037# 0 not in sync
1038#
1039sub DyndnsServiceSync ($;$;$) {
1040
1041 my ($ip,$hostName,$domain) = @_;
1042 my @addresses;
1043
1044 #fix me no ip GROUP, what is the name ?
1045 $hostName =~ s/$General::noipprefix//;
1046 if ($hostName) { #may be empty
1047 $hostName = "$hostName.$domain";
1048 @addresses = gethostbyname($hostName);
1049 }
1050
1051 if ($addresses[0] eq '') { # nothing returned ?
1052 $hostName = $domain; # try resolving with domain only
1053 @addresses = gethostbyname($hostName);
1054 }
1055
1056 if ($addresses[0] ne '') { # got something ?
1057 #&General::log("name:$addresses[0], alias:$addresses[1]");
1058 # Build clear text list of IP
1059 @addresses = map ( &Socket::inet_ntoa($_), @addresses[4..$#addresses]);
1060 if (grep (/$ip/, @addresses)) {
1061 return 1;
1062 }
1063 }
1064 return 0;
1065}
1066#
1067# This sub returns the red IP used to compare in DyndnsServiceSync
1068#
1069sub GetDyndnsRedIP {
1070 my %settings;
1071 &General::readhash("${General::swroot}/ddns/settings", \%settings);
1072
1073 open(IP, "${General::swroot}/red/local-ipaddress") or return 'unavailable';
1074 my $ip = <IP>;
1075 close(IP);
1076 chomp $ip;
1077
057dbeeb 1078 # 100.64.0.0/10 is reserved for dual-stack lite (http://tools.ietf.org/html/rfc6598).
ac1cfefa
MT
1079 if (&General::IpInSubnet ($ip,'10.0.0.0','255.0.0.0') ||
1080 &General::IpInSubnet ($ip,'172.16.0.0.','255.240.0.0') ||
057dbeeb
MT
1081 &General::IpInSubnet ($ip,'192.168.0.0','255.255.0.0') ||
1082 &General::IpInSubnet ($ip,'100.64.0.0', '255.192.0.0'))
ac1cfefa
MT
1083 {
1084 if ($settings{'BEHINDROUTER'} eq 'FETCH_IP') {
1085 my $RealIP = &General::FetchPublicIp;
1086 $ip = (&General::validip ($RealIP) ? $RealIP : 'unavailable');
1087 }
1088 }
1089 return $ip;
1090}
c545beb1
MT
1091
1092# Translate ICMP code to text
1093# ref: http://www.iana.org/assignments/icmp-parameters
1094sub GetIcmpDescription ($) {
1095 my $index = shift;
1096 my @icmp_description = (
1097 'Echo Reply', #0
1098 'Unassigned',
1099 'Unassigned',
1100 'Destination Unreachable',
1101 'Source Quench',
1102 'Redirect',
1103 'Alternate Host Address',
1104 'Unassigned',
1105 'Echo',
1106 'Router Advertisement',
1107 'Router Solicitation', #10
1108 'Time Exceeded',
1109 'Parameter Problem',
1110 'Timestamp',
1111 'Timestamp Reply',
1112 'Information Request',
1113 'Information Reply',
1114 'Address Mask Request',
1115 'Address Mask Reply',
1116 'Reserved (for Security)',
1117 'Reserved (for Robustness Experiment)', #20
1118 'Reserved',
1119 'Reserved',
1120 'Reserved',
1121 'Reserved',
1122 'Reserved',
1123 'Reserved',
1124 'Reserved',
1125 'Reserved',
1126 'Reserved',
1127 'Traceroute', #30
1128 'Datagram Conversion Error',
1129 'Mobile Host Redirect',
1130 'IPv6 Where-Are-You',
1131 'IPv6 I-Am-Here',
1132 'Mobile Registration Request',
1133 'Mobile Registration Reply',
1134 'Domain Name Request',
1135 'Domain Name Reply',
1136 'SKIP',
1137 'Photur', #40
1138 'Experimental');
a2b3eba9 1139 if ($index>41) {return 'unknown'} else {return $icmp_description[$index]};
c545beb1 1140}
b2f8244a
MT
1141
1142sub GetCoreUpdateVersion() {
1143 my $core_update;
1144
1145 open(FILE, "/opt/pakfire/db/core/mine");
1146 while (<FILE>) {
1147 $core_update = $_;
1148 last;
1149 }
1150 close(FILE);
1151
1152 return $core_update;
1153}
1154
1155sub MakeUserAgent() {
1156 my $user_agent = "IPFire/$General::version";
1157
1158 my $core_update = &GetCoreUpdateVersion();
1159 if ($core_update ne "") {
1160 $user_agent .= "/$core_update";
1161 }
1162
1163 return $user_agent;
1164}
1165
61027579
MT
1166sub RedIsWireless() {
1167 # This function checks if a network device is a wireless device.
1168
1169 my %settings = ();
1170 &readhash("${General::swroot}/ethernet/settings", \%settings);
1171
1172 # Find the name of the network device.
1173 my $device = $settings{'RED_DEV'};
1174
1175 # Exit, if no device is configured.
1176 return 0 if ($device eq "");
1177
1178 # Return 1 if the device is a wireless one.
1179 my $path = "/sys/class/net/$device/wireless";
1180 if (-d $path) {
1181 return 1;
1182 }
1183
1184 # Otherwise return zero.
1185 return 0;
1186}
1187
dfee7582
SS
1188# Function to read a file with UTF-8 charset.
1189sub read_file_utf8 ($) {
1190 my ($file) = @_;
1191
1192 open my $in, '<:encoding(UTF-8)', $file or die "Could not open '$file' for reading $!";
1193 local $/ = undef;
1194 my $all = <$in>;
1195 close $in;
1196
3e862ce4 1197 return $all;
dfee7582
SS
1198}
1199
1200# Function to write a file with UTF-8 charset.
1201sub write_file_utf8 ($) {
1202 my ($file, $content) = @_;
1203
1204 open my $out, '>:encoding(UTF-8)', $file or die "Could not open '$file' for writing $!";;
1205 print $out $content;
1206 close $out;
1207
1208 return;
1209}
1210
6d8eb5de 1211my $FIREWALL_RELOAD_INDICATOR = "${General::swroot}/firewall/reread";
0e430797
MT
1212
1213sub firewall_config_changed() {
1214 open FILE, ">$FIREWALL_RELOAD_INDICATOR" or die "Could not open $FIREWALL_RELOAD_INDICATOR";
1215 close FILE;
1216}
1217
1218sub firewall_needs_reload() {
1219 if (-e "$FIREWALL_RELOAD_INDICATOR") {
1220 return 1;
1221 }
1222
1223 return 0;
1224}
1225
1226sub firewall_reload() {
2a52353f 1227 &system("/usr/local/bin/firewallctrl");
0e430797
MT
1228}
1229
4cb523d4 1230# Function which will return the used interface for the red network zone (red0, ppp0, etc).
110d4c81 1231# if you change this also check speed.cgi that include a local copy for systemload reasons
4cb523d4
SS
1232sub get_red_interface() {
1233
1234 open(IFACE, "${General::swroot}/red/iface") or die "Could not open /var/ipfire/red/iface";
1235
1236 my $interface = <IFACE>;
1237 close(IFACE);
1238 chomp $interface;
1239
1240 return $interface;
1241}
1242
1a3323f2
DW
1243sub number_cpu_cores() {
1244 open my $cpuinfo, "/proc/cpuinfo" or die "Can't open cpuinfo: $!\n";
1245 my $cores = scalar (map /^processor/, <$cpuinfo>);
1246 close $cpuinfo;
1247
1248 return $cores;
1249}
183b23b5 1250
97022524
SS
1251# Tiny function to grab a single IP-address from a given file.
1252sub grab_address_from_file($) {
1253 my ($file) = @_;
1254
1255 my $address;
1256
1257 # Check if the given file exists.
1258 if(-f $file) {
1259 # Open the file for reading.
1260 open(FILE, $file) or die "Could not read from $file. $!\n";
1261
1262 # Read the address from the file.
1263 $address = <FILE>;
1264
1265 # Close filehandle.
1266 close(FILE);
1267
1268 # Remove newlines.
1269 chomp($address);
1270
1271 # Check if the obtained address is valid.
1272 if (&validip($address)) {
1273 # Return the address.
1274 return $address;
1275 }
1276 }
1277
1278 # Return nothing.
1279 return;
1280}
1281
c8dcd465
SS
1282# Function to get all configured and enabled nameservers.
1283sub get_nameservers () {
1284 my %settings;
1285 my %servers;
1286
1287 my @nameservers;
1288
1289 # Read DNS configuration.
1290 &readhash("$General::swroot/dns/settings", \%settings);
1291
1292 # Read configured DNS servers.
1293 &readhasharray("$General::swroot/dns/servers", \%servers);
1294
1295 # Check if the ISP assigned server should be used.
1296 if ($settings{'USE_ISP_NAMESERVERS'} eq "on") {
1297 # Assign ISP nameserver files.
1298 my @ISP_nameserver_files = ( "/var/run/dns1", "/var/run/dns2" );
1299
1300 # Loop through the array of ISP assigned DNS servers.
1301 foreach my $file (@ISP_nameserver_files) {
1302 # Grab the IP address.
1303 my $address = &grab_address_from_file($file);
1304
1305 # Check if an address has been grabbed.
1306 if ($address) {
1307 # Add the address to the array of nameservers.
1308 push(@nameservers, $address);
1309 }
1310 }
1311 }
1312
1313 # Check if DNS servers are configured.
1314 if (%servers) {
1315 # Loop through the hash of configured DNS servers.
1316 foreach my $id (keys %servers) {
1317 my $address = $servers{$id}[0];
1318 my $status = $servers{$id}[2];
1319
1320 # Check if the current processed server is enabled.
1321 if ($status eq "enabled") {
1322 # Add the address to the array of nameservers.
1323 push(@nameservers, $address);
1324 }
1325 }
1326 }
1327
1328 # Return the array.
e8adbea9 1329 return &uniq(@nameservers);
c8dcd465
SS
1330}
1331
c5f85b11
SS
1332# Function to format a string containing the amount of bytes to
1333# something human-readable.
1334sub formatBytes {
1335 # Private array which contains the units.
1336 my @units = qw(B KB MB GB TB PB);
1337
1338 my $bytes = shift;
1339 my $unit;
1340
1341 # Loop through the array of units.
1342 foreach my $element (@units) {
25932be3
SS
1343 # Assign current processed element to unit.
1344 $unit = $element;
1345
c5f85b11
SS
1346 # Break loop if the bytes are less than the next unit.
1347 last if $bytes < 1024;
1348
1349 # Divide bytes amount with 1024.
1350 $bytes /= 1024;
c5f85b11
SS
1351 }
1352
1353 # Return the divided and rounded bytes count and the unit.
1354 return sprintf("%.2f %s", $bytes, $unit);
1355}
1356
ca1f4a07
SS
1357# Function to collect and generate a hash for translating protocol numbers into
1358# their names.
1359sub generateProtoTransHash () {
1360 # File which contains the protocol definitions.
1361 my $protocols_file = "/etc/protocols";
1362
1363 my %protocols = ();
1364
1365 # Open protocols file.
1366 open(FILE, "$protocols_file") or die "Could not open $protocols_file. $!\n";
1367
1368 # Loop through the file.
1369 while (my $line = <FILE>) {
1370 # Skip comments.
1371 next if ($line =~ /^\#/);
1372
1373 # Skip blank lines.
1374 next if ($line =~ /^\s*$/);
1375
1376 # Remove any newlines.
1377 chomp($line);
1378
1379 # Split line content.
1380 my ($protocol_lc, $number, $protocol_uc, $comment) = split(' ', $line);
1381
1382 # Add proto details to the hash of protocols.
1383 $protocols{$number} = $protocol_uc;
1384 }
1385
1386 # Close file handle.
1387 close(FILE);
1388
1389 # Return the hash.
1390 return %protocols;
1391}
1392
4e58ab4b
MT
1393# Cloud Stuff
1394
46b0f9ab
MT
1395sub running_in_cloud() {
1396 return &running_on_ec2() || &running_on_gcp();
1397}
1398
4e58ab4b
MT
1399sub running_on_ec2() {
1400 if (-e "/var/run/aws-instance-id") {
1401 return 1;
1402 }
1403
1404 return 0;
1405}
1406
e7978f56
MT
1407sub running_on_gcp() {
1408 if (-e "/var/run/gcp-instance-id") {
1409 return 1;
1410 }
1411
1412 return 0;
1413}
1414
ac1cfefa 14151;