X-Git-Url: http://git.ipfire.org/?p=people%2Fteissler%2Fipfire-2.x.git;a=blobdiff_plain;f=config%2Fcfgroot%2Fgeneral-functions.pl;h=adfba5489177320e2b1528223156a620089863bf;hp=cd4bfd56610d0142944c3d21bfd0af07a96613ad;hb=4d81e0f3812fc272b2515a631a2e98c4ae76a42b;hpb=514bee894cc0c0825fb874689d3e245d3fdaf1de diff --git a/config/cfgroot/general-functions.pl b/config/cfgroot/general-functions.pl index cd4bfd566..adfba5489 100644 --- a/config/cfgroot/general-functions.pl +++ b/config/cfgroot/general-functions.pl @@ -18,8 +18,7 @@ use strict; use Socket; use IO::Socket; use Net::SSLeay; -use Net::IPv4Addr; - +use Net::IPv4Addr qw(:all); $|=1; # line buffering $General::version = 'VERSION'; @@ -40,6 +39,96 @@ sub log $logmessage = $1; system('logger', '-t', $tag, $logmessage); } +sub setup_default_networks +{ + my %netsettings=(); + my $defaultNetworks = shift; + + &readhash("/var/ipfire/ethernet/settings", \%netsettings); + + # Get current defined networks (Red, Green, Blue, Orange) + $defaultNetworks->{$Lang::tr{'fwhost any'}}{'IPT'} = "0.0.0.0/0.0.0.0"; + $defaultNetworks->{$Lang::tr{'fwhost any'}}{'NAME'} = "ALL"; + + $defaultNetworks->{$Lang::tr{'green'}}{'IPT'} = "$netsettings{'GREEN_NETADDRESS'}/$netsettings{'GREEN_NETMASK'}"; + $defaultNetworks->{$Lang::tr{'green'}}{'NET'} = "$netsettings{'GREEN_ADDRESS'}"; + $defaultNetworks->{$Lang::tr{'green'}}{'NAME'} = "GREEN"; + + if ($netsettings{'RED_DEV'} ne ''){ + $defaultNetworks->{$Lang::tr{'fwdfw red'}}{'IPT'} = "$netsettings{'RED_NETADDRESS'}/$netsettings{'RED_NETMASK'}"; + $defaultNetworks->{$Lang::tr{'fwdfw red'}}{'NET'} = "$netsettings{'RED_ADDRESS'}"; + $defaultNetworks->{$Lang::tr{'fwdfw red'}}{'NAME'} = "RED"; + } + if ($netsettings{'ORANGE_DEV'} ne ''){ + $defaultNetworks->{$Lang::tr{'orange'}}{'IPT'} = "$netsettings{'ORANGE_NETADDRESS'}/$netsettings{'ORANGE_NETMASK'}"; + $defaultNetworks->{$Lang::tr{'orange'}}{'NET'} = "$netsettings{'ORANGE_ADDRESS'}"; + $defaultNetworks->{$Lang::tr{'orange'}}{'NAME'} = "ORANGE"; + } + + if ($netsettings{'BLUE_DEV'} ne ''){ + $defaultNetworks->{$Lang::tr{'blue'}}{'IPT'} = "$netsettings{'BLUE_NETADDRESS'}/$netsettings{'BLUE_NETMASK'}"; + $defaultNetworks->{$Lang::tr{'blue'}}{'NET'} = "$netsettings{'BLUE_ADDRESS'}"; + $defaultNetworks->{$Lang::tr{'blue'}}{'NAME'} = "BLUE"; + } + + #IPFire himself + $defaultNetworks->{'IPFire'}{'NAME'} = "IPFire"; + + # OpenVPN + if(-e "${General::swroot}/ovpn/settings") + { + my %ovpnSettings = (); + &readhash("${General::swroot}/ovpn/settings", \%ovpnSettings); + + # OpenVPN on Red? + if(defined($ovpnSettings{'DOVPN_SUBNET'})) + { + my ($ip,$sub) = split(/\//,$ovpnSettings{'DOVPN_SUBNET'}); + $sub=&General::iporsubtocidr($sub); + my @tempovpnsubnet = split("\/", $ovpnSettings{'DOVPN_SUBNET'}); + $defaultNetworks->{'OpenVPN ' ."($ip/$sub)"}{'ADR'} = $tempovpnsubnet[0]; + $defaultNetworks->{'OpenVPN ' ."($ip/$sub)"}{'NAME'} = "OpenVPN-Dyn"; + } + } # end OpenVPN + # IPsec RW NET + if(-e "${General::swroot}/vpn/settings") + { + my %ipsecsettings = (); + &readhash("${General::swroot}/vpn/settings", \%ipsecsettings); + if($ipsecsettings{'RW_NET'} ne '') + { + my ($ip,$sub) = split(/\//,$ipsecsettings{'RW_NET'}); + $sub=&General::iporsubtocidr($sub); + my @tempipsecsubnet = split("\/", $ipsecsettings{'RW_NET'}); + $defaultNetworks->{'IPsec RW (' .$ip."/".$sub.")"}{'ADR'} = $tempipsecsubnet[0]; + $defaultNetworks->{'IPsec RW (' .$ip."/".$sub.")"}{'NAME'} = "IPsec RW"; + $defaultNetworks->{'IPsec RW (' .$ip."/".$sub.")"}{'NET'} = &getnextip($ip); + } + } +} +sub get_aliases +{ + + my $defaultNetworks = shift; + open(FILE, "${General::swroot}/ethernet/aliases") or die 'Unable to open aliases file.'; + my @current = ; + close(FILE); + my $ctr = 0; + foreach my $line (@current) + { + if ($line ne ''){ + chomp($line); + my @temp = split(/\,/,$line); + if ($temp[2] eq '') { + $temp[2] = "Alias $ctr : $temp[0]"; + } + $defaultNetworks->{$temp[2]}{'IPT'} = "$temp[0]"; + $defaultNetworks->{$temp[2]}{'NET'} = "$temp[0]"; + + $ctr++; + } + } +} sub readhash { @@ -140,21 +229,36 @@ sub writehashpart close FILE; } -sub age -{ +sub age { my ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size, - $atime, $mtime, $ctime, $blksize, $blocks) = stat $_[0]; - my $now = time; - - my $totalsecs = $now - $mtime; - my $days = int($totalsecs / 86400); - my $totalhours = int($totalsecs / 3600); - my $hours = $totalhours % 24; - my $totalmins = int($totalsecs / 60); - my $mins = $totalmins % 60; + $atime, $mtime, $ctime, $blksize, $blocks) = stat $_[0]; + my $totalsecs = time() - $mtime; + my @s = (); + my $secs = $totalsecs % 60; + $totalsecs /= 60; + if ($secs > 0) { + push(@s, "${secs}s"); + } + + my $min = $totalsecs % 60; + $totalsecs /= 60; + if ($min > 0) { + push(@s, "${min}m"); + } - return "${days}d ${hours}h ${mins}m ${secs}s"; + my $hrs = $totalsecs % 24; + $totalsecs /= 24; + if ($hrs > 0) { + push(@s, "${hrs}h"); + } + + my $days = int($totalsecs); + if ($days > 0) { + push(@s, "${days}d"); + } + + return join(" ", reverse(@s)); } sub validip @@ -212,21 +316,289 @@ sub validipormask return &validmask($mask); } +sub subtocidr +{ + #gets: Subnet in decimal (255.255.255.0) + #Gives: 24 (The cidr of network) + my ($byte1, $byte2, $byte3, $byte4) = split(/\./, $_[0].".0.0.0.0"); + my $num = ($byte1 * 16777216) + ($byte2 * 65536) + ($byte3 * 256) + $byte4; + my $bin = unpack("B*", pack("N", $num)); + my $count = ($bin =~ tr/1/1/); + return $count; +} + +sub cidrtosub +{ + #gets: Cidr of network (20-30 for ccd) + #Konverts 30 to 255.255.255.252 e.g + my $cidr=$_[0]; + my $netmask = &Net::IPv4Addr::ipv4_cidr2msk($cidr); + return "$netmask"; +} + +sub iporsubtodec +{ + #Gets: Ip address or subnetmask in decimal oder CIDR + #Gives: What it gets only in CIDR format + my $subnet=$_[0]; + my $net; + my $mask; + my $full=0; + if ($subnet =~ /^(.*?)\/(.*?)$/) { + ($net,$mask) = split (/\//,$subnet); + $full=1; + return "$subnet"; + }else{ + $mask=$subnet; + } + #Subnet already in decimal and valid? + if ($mask=~/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/ &&(($1<=255 && $2<=$1 && $3<=$2 && $4<=$3 ))) { + for (my $i=8;$i<=32;$i++){ + if (&General::cidrtosub($i) eq $mask){ + if ($full == 0){return $mask;}else{ + return $net."/".$mask; + } + } + } + } + #Subnet in binary format? + if ($mask=~/^(\d{1,2})$/ && (($1<=32 && $1>=8))){ + if($full == 0){ return &General::cidrtosub($mask);}else{ + return $net."/".&General::cidrtosub($mask); + } + }else{ + return 3; + } + return 3; +} + + +sub iporsubtocidr +{ + #gets: Ip Address or subnetmask in decimal oder CIDR + #Gives: What it gets only in CIDR format + my $subnet=$_[0]; + my $net; + my $mask; + my $full=0; + if ($subnet =~ /^(.*?)\/(.*?)$/) { + ($net,$mask) = split (/\//,$subnet); + $full=1; + }else{ + $mask=$subnet; + } + #Subnet in decimal and valid? + if ($mask=~/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/ &&(($1<=255 && $2<=$1 && $3<=$2 && $4<=$3 ))) { + for (my $i=8;$i<=32;$i++){ + if (&General::cidrtosub($i) eq $mask){ + if ($full == 0){return &General::subtocidr($mask);}else{ + return $net."/".&General::subtocidr($mask); + } + } + } + } + #Subnet already in binary format? + if ($mask=~/^(\d{1,2})$/ && (($1<=32 && $1>=8))){ + if($full == 0){ return $mask;}else{ + return $net."/".$mask; + } + }else{ + return 3; + } + return 3; +} + +sub getnetworkip +{ + #Gets: IP, CIDR (10.10.10.0-255, 24) + #Gives: 10.10.10.0 + my ($ccdip,$ccdsubnet) = @_; + my $ip_address_binary = inet_aton( $ccdip ); + my $netmask_binary = ~pack("N", (2**(32-$ccdsubnet))-1); + my $network_address = inet_ntoa( $ip_address_binary & $netmask_binary ); + return $network_address; +} + +sub getccdbc +{ + #Gets: IP in Form ("192.168.0.0/24") + #Gives: Broadcastaddress of network + my $ccdnet=$_; + my ($ccdip,$ccdsubnet) = split "/",$ccdnet; + my $ip_address_binary = inet_aton( $ccdip ); + my $netmask_binary = ~pack("N", (2**(32-$ccdsubnet))-1); + my $broadcast_address = inet_ntoa( $ip_address_binary | ~$netmask_binary ); + return $broadcast_address; +} + +sub ip2dec +{ + my $ip_num; + my $ip=$_[0]; + if ( $ip =~ /(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/ ) { + $ip_num = (($1*256**3) + ($2*256**2) + ($3*256) + $4); + } else { + $ip_num = -1; + } + $ip_num = (($1*256**3) + ($2*256**2) + ($3*256) + $4); + return($ip_num); +} + +sub dec2ip +{ + my $ip; + my $ip_num=$_[0]; + my $o1=$ip_num%256; + $ip_num=int($ip_num/256); + my $o2=$ip_num%256; + $ip_num=int($ip_num/256); + my $o3=$ip_num%256; + $ip_num=int($ip_num/256); + my $o4=$ip_num%256; + $ip="$o4.$o3.$o2.$o1"; + return ($ip); +} + +sub getnextip +{ + my $decip=&ip2dec($_[0]); + $decip=$decip+4; + return &dec2ip($decip); +} + +sub getlastip +{ + my $decip=&ip2dec($_[0]); + $decip--; + return &dec2ip($decip); +} + sub validipandmask { - my $ipandmask = $_[0]; + #Gets: Ip address in 192.168.0.0/24 or 192.168.0.0/255.255.255.0 and checks if subnet valid + #Gives: True bzw 0 if success or false + my $ccdnet=$_[0]; + my $subcidr; + + if (!($ccdnet =~ /^(.*?)\/(.*?)$/)) { + return 0; + } + my ($ccdip,$ccdsubnet)=split (/\//, $ccdnet); + #IP valid? + 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 ))) { + #Subnet in decimal and valid? + if ($ccdsubnet=~/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/ &&(($1<=255 && $2<=$1 && $3<=$2 && $4<=$3 ))) { + for (my $i=8;$i<=32;$i++){ + if (&General::cidrtosub($i) eq $ccdsubnet){ + return 1; + } + } + #Subnet already in binary format? + }elsif ($ccdsubnet=~/^(\d{1,2})$/ && (($1<=32 && $1>=8))){ + return 1; + }else{ + return 0; + } + + } + return 0; +} - # split it into number and mask. - if (!($ipandmask =~ /^(.*?)\/(.*?)$/)) { - return 0; } - my $ip = $1; - my $mask = $2; - # first part not a ip? - if (!(&validip($ip))) { - return 0; } - return &validmask($mask); +sub checksubnets +{ + my %ccdconfhash=(); + my %ovpnconfhash=(); + my %vpnconf=(); + my %ipsecconf=(); + my %ownnet=(); + my %ovpnconf=(); + my @ccdconf=(); + my $ccdname=$_[0]; + my $ccdnet=$_[1]; + my $ownnet=$_[2]; + my $errormessage; + my ($ip,$cidr)=split(/\//,$ccdnet); + $cidr=&iporsubtocidr($cidr); + + #get OVPN-Subnet (dynamic range) + &readhash("${General::swroot}/ovpn/settings", \%ovpnconf); + my ($ovpnip,$ovpncidr)= split (/\//,$ovpnconf{'DOVPN_SUBNET'}); + $ovpncidr=&iporsubtocidr($ovpncidr); + + #check if we try to use same network as ovpn server + if ("$ip/$cidr" eq "$ovpnip/$ovpncidr") { + $errormessage=$errormessage.$Lang::tr{'ccd err isovpnnet'}."
"; + return $errormessage; + } + + #check if we try to use same network as another ovpn N2N + if($ownnet ne 'ovpn'){ + &readhasharray("${General::swroot}/ovpn/ovpnconfig", \%ovpnconfhash); + foreach my $key (keys %ovpnconfhash) { + if ($ovpnconfhash{$key}[3] eq 'net'){ + my @ovpnnet=split (/\//,$ovpnconfhash{$key}[11]); + if (&IpInSubnet($ip,$ovpnnet[0],&iporsubtodec($ovpnnet[1]))){ + $errormessage=$errormessage.$Lang::tr{'ccd err isovpnn2n'}." $ovpnconfhash{$key}[1]
"; + return $errormessage; + } + } + } + } + + #check if we use a network-name/subnet (static-ovpn) that already exists + &readhasharray("${General::swroot}/ovpn/ccd.conf", \%ccdconfhash); + foreach my $key (keys %ccdconfhash) { + @ccdconf=split(/\//,$ccdconfhash{$key}[1]); + if ($ccdname eq $ccdconfhash{$key}[0]) + { + $errormessage=$errormessage.$Lang::tr{'ccd err nameexist'}."
"; + return $errormessage; + } + my ($newip,$newsub) = split(/\//,$ccdnet); + if (&IpInSubnet($newip,$ccdconf[0],&iporsubtodec($ccdconf[1]))) + { + $errormessage=$errormessage.$Lang::tr{'ccd err issubnet'}." $ccdconfhash{$key}[0]
"; + return $errormessage; + } + } + + #check if we use a ipsec right network which is already defined + if($ownnet ne 'ipsec'){ + &General::readhasharray("${General::swroot}/vpn/config", \%ipsecconf); + foreach my $key (keys %ipsecconf){ + if ($ipsecconf{$key}[11] ne ''){ + my ($ipsecip,$ipsecsub) = split (/\//, $ipsecconf{$key}[11]); + $ipsecsub=&iporsubtodec($ipsecsub); + if($ipsecconf{$key}[1] ne $ccdname){ + if ( &IpInSubnet ($ip,$ipsecip,$ipsecsub) ){ + $errormessage=$Lang::tr{'ccd err isipsecnet'}." Name: $ipsecconf{$key}[1]"; + return $errormessage; + } + } + } + } + } + + #check if we use the ipsec RW Network (if defined) + &readhash("${General::swroot}/vpn/settings", \%vpnconf); + if ($vpnconf{'RW_NET'} ne ''){ + my ($ipsecrwnet,$ipsecrwsub)=split (/\//, $vpnconf{'RW_NET'}); + if (&IpInSubnet($ip,$ipsecrwnet,&iporsubtodec($ipsecrwsub))) + { + $errormessage=$errormessage.$Lang::tr{'ccd err isipsecrw'}."
"; + return $errormessage; + } + } + + #check if we use one of ipfire's networks (green,orange,blue) + &readhash("${General::swroot}/ethernet/settings", \%ownnet); + 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;} + 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;} + 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;} + 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;} } + sub validport { $_ = $_[0]; @@ -276,7 +648,7 @@ sub validhostname if (length ($hostname) < 1 || length ($hostname) > 63) { return 0;} # Only valid characters are a-z, A-Z, 0-9 and - - if ($hostname !~ /^[a-zA-Z0-9-]*$/) { + if ($hostname !~ /^[a-zA-Z0-9-\s]*$/) { return 0;} # First character can only be a letter or a digit if (substr ($hostname, 0, 1) !~ /^[a-zA-Z0-9]*$/) { @@ -407,13 +779,26 @@ sub NextIP ) ); } - +sub NextIP2 +{ + return &Socket::inet_ntoa( pack("N", 4 + unpack('N', &Socket::inet_aton(shift)) + ) + ); +} sub ipcidr { my ($ip,$cidr) = &Net::IPv4Addr::ipv4_parse(shift); return "$ip\/$cidr"; } +sub ipcidr2msk +{ + my ($ip,$cidr) = &Net::IPv4Addr::ipv4_parse(shift); + my $netmask = &Net::IPv4Addr::ipv4_cidr2msk($cidr); + return "$ip\/$netmask"; +} + + sub validemail { my $mail = shift; return 0 if ( $mail !~ /^[0-9a-zA-Z\.\-\_]+\@[0-9a-zA-Z\.\-]+$/ ); @@ -457,13 +842,13 @@ sub writehasharray { open(FILE, ">$filename") or die "Unable to write to file $filename"; foreach $key (keys %$hash) { - if ($key =~ /^[0-9]+$/) { - print FILE "$key"; - foreach $i (0 .. $#{$hash->{$key}}) { - print FILE ",$hash->{$key}[$i]"; - } - print FILE "\n"; - } + if ($key =~ /^[0-9]+$/) { + print FILE "$key"; + foreach $i (0 .. $#{$hash->{$key}}) { + print FILE ",$hash->{$key}[$i]"; + } + print FILE "\n"; + } } close FILE; return; @@ -565,13 +950,14 @@ sub FetchPublicIp { my ($peer, $peerport) = (/^(?:[a-zA-Z ]+\:\/\/)?(?:[A-Za-z0-9\_\.\-]*?(?:\:[A-Za-z0-9\_\.\-]*?)?\@)?([a-zA-Z0-9\.\_\-]*?)(?:\:([0-9]{1,5}))?(?:\/.*?)?$/); Net::SSLeay::set_proxy($peer,$peerport,$proxysettings{'UPSTREAM_USER'},$proxysettings{'UPSTREAM_PASSWORD'} ); } - my ($out, $response) = Net::SSLeay::get_http( 'checkip.dyndns.org', + my $user_agent = &MakeUserAgent(); + my ($out, $response) = Net::SSLeay::get_http( 'checkip4.dns.lightningwirelabs.com', 80, "/", - Net::SSLeay::make_headers('User-Agent' => 'IPFire' ) + Net::SSLeay::make_headers('User-Agent' => $user_agent ) ); if ($response =~ m%HTTP/1\.. 200 OK%) { - $out =~ /Current IP Address: (\d+.\d+.\d+.\d+)/; + $out =~ /Your IP address is: (\d+.\d+.\d+.\d+)/; return $1; } return ''; @@ -627,9 +1013,11 @@ sub GetDyndnsRedIP { close(IP); chomp $ip; + # 100.64.0.0/10 is reserved for dual-stack lite (http://tools.ietf.org/html/rfc6598). if (&General::IpInSubnet ($ip,'10.0.0.0','255.0.0.0') || &General::IpInSubnet ($ip,'172.16.0.0.','255.240.0.0') || - &General::IpInSubnet ($ip,'192.168.0.0','255.255.0.0')) + &General::IpInSubnet ($ip,'192.168.0.0','255.255.0.0') || + &General::IpInSubnet ($ip,'100.64.0.0', '255.192.0.0')) { if ($settings{'BEHINDROUTER'} eq 'FETCH_IP') { my $RealIP = &General::FetchPublicIp; @@ -686,6 +1074,95 @@ sub GetIcmpDescription ($) { 'SKIP', 'Photur', #40 'Experimental'); - if ($index>41) {return 'unknown'} else {return @icmp_description[$index]}; + if ($index>41) {return 'unknown'} else {return $icmp_description[$index]}; +} + +sub GetCoreUpdateVersion() { + my $core_update; + + open(FILE, "/opt/pakfire/db/core/mine"); + while () { + $core_update = $_; + last; + } + close(FILE); + + return $core_update; +} + +sub MakeUserAgent() { + my $user_agent = "IPFire/$General::version"; + + my $core_update = &GetCoreUpdateVersion(); + if ($core_update ne "") { + $user_agent .= "/$core_update"; + } + + return $user_agent; +} + +sub RedIsWireless() { + # This function checks if a network device is a wireless device. + + my %settings = (); + &readhash("${General::swroot}/ethernet/settings", \%settings); + + # Find the name of the network device. + my $device = $settings{'RED_DEV'}; + + # Exit, if no device is configured. + return 0 if ($device eq ""); + + # Return 1 if the device is a wireless one. + my $path = "/sys/class/net/$device/wireless"; + if (-d $path) { + return 1; + } + + # Otherwise return zero. + return 0; } + +# Function to read a file with UTF-8 charset. +sub read_file_utf8 ($) { + my ($file) = @_; + + open my $in, '<:encoding(UTF-8)', $file or die "Could not open '$file' for reading $!"; + local $/ = undef; + my $all = <$in>; + close $in; + + return $all; +} + +# Function to write a file with UTF-8 charset. +sub write_file_utf8 ($) { + my ($file, $content) = @_; + + open my $out, '>:encoding(UTF-8)', $file or die "Could not open '$file' for writing $!";; + print $out $content; + close $out; + + return; +} + +my $FIREWALL_RELOAD_INDICATOR = "${General::swroot}/firewall/reread"; + +sub firewall_config_changed() { + open FILE, ">$FIREWALL_RELOAD_INDICATOR" or die "Could not open $FIREWALL_RELOAD_INDICATOR"; + close FILE; +} + +sub firewall_needs_reload() { + if (-e "$FIREWALL_RELOAD_INDICATOR") { + return 1; + } + + return 0; +} + +sub firewall_reload() { + system("/usr/local/bin/firewallctrl"); +} + 1;