diff --git a/html/cgi-bin/loxilb.cgi b/html/cgi-bin/loxilb.cgi index bb926dbc1..4541db9e1 100644 --- a/html/cgi-bin/loxilb.cgi +++ b/html/cgi-bin/loxilb.cgi @@ -33,13 +33,18 @@ require "${General::swroot}/location-functions.pl"; require "${General::swroot}/lang.pl"; require "${General::swroot}/header.pl"; +#workaround to suppress a warning when a variable is used only once +my @dummy = ( ${Header::colouryellow} ); +undef (@dummy); + my %color = (); my %mainsettings = (); -my %loxilbsettings=(); +my %settings=(); my %checked=(); my $errormessage=''; +my $setting = "${General::swroot}/main/settings"; my $loxilbsettingfile = "${General::swroot}/loxilb/settings"; - +my $loxilbipfile = "${General::swroot}/loxilb/ipconfig"; # Read configuration file. @@ -48,17 +53,33 @@ my $loxilbsettingfile = "${General::swroot}/loxilb/settings"; &Header::showhttpheaders(); -$loxilbsettings{'ENABLE_LOXILB'} = 'off'; -$loxilbsettings{'ACTION'} = ''; +$settings{'ENABLE_LOXILB'} = 'off'; +$settings{'ACTION'} = ''; -&Header::getcgihash(\%loxilbsettings); +$settings{'KEY1'} = ''; # point record for ACTION +$settings{'virtualIP'} = ''; +$settings{'interface'} = ''; +my @nosaved=('virtualIP','interface'); -if ($loxilbsettings{'ACTION'} eq $Lang::tr{'save'}) +#Define each field that can be used to sort columns +my $sortstring='^virtualIP'; +$settings{'SORT_virtualIPLIST'} = 'virtualIP'; + +# Load multiline data +our @current = (); +if (open(FILE, "$loxilbipfile")) { + @current = ; + close (FILE); +} + +&Header::getcgihash(\%settings); + +if ($settings{'ACTION'} eq $Lang::tr{'save'}) { - &General::writehash("$loxilbsettingfile", \%loxilbsettings); + &General::writehash("$loxilbsettingfile", \%settings); - if ($loxilbsettings{'ENABLE_LOXILB'} eq 'on') { + if ($settings{'ENABLE_LOXILB'} eq 'on') { &General::system('/usr/bin/touch', "${General::swroot}/loxilb/enableloxilb"); &General::system('/usr/local/bin/loxilbctrl', 'start'); } else { @@ -68,22 +89,103 @@ if ($loxilbsettings{'ACTION'} eq $Lang::tr{'save'}) } +if ($settings{'ACTION'} eq $Lang::tr{'add'}) { + # Validate inputs + if (!&General::validipandmask($settings{'virtualIP'})){ + $errormessage = $Lang::tr{'invalid ip'}." / ".$Lang::tr{'invalid netmask'}; + } + + #Check for already existing routing entry + foreach my $line (@current) { + chomp($line); # remove newline + my @temp=split(/\,/,$line); + $temp[1] ='' unless defined $temp[1]; # interface + #Same ip already used? + if($temp[0] eq $settings{'virtualIP'} && $settings{'KEY1'} eq ''){ + $errormessage = $Lang::tr{'ccd err loxilbconfigeexist'}; + last; + } + } + + unless ($errormessage) { + if ($settings{'KEY1'} eq '') { #add or edit ? + unshift (@current, "$settings{'virtualIP'},$settings{'interface'}\n"); + &General::log($Lang::tr{'loxilb lb config added'}); + } else { + @current[$settings{'KEY1'}] = "$settings{'virtualIP'},$settings{'interface'}\n"; + $settings{'KEY1'} = ''; # End edit mode + &General::log($Lang::tr{'loxilb fw changed'}); + } + + &CreateIP(%settings); + + # Write changes to config file. + &SortDataFile; # sort newly added/modified entry + + #map ($settings{$_}='' ,@nosaved); # Clear fields + } +} + +if ($settings{'ACTION'} eq $Lang::tr{'remove'}) { + + my $line = @current[$settings{'KEY1'}]; # KEY1 is the index in current + chomp($line); + my @temp = split(/\,/, $line); + $settings{'virtualIP'}=$temp[0]; + $settings{'interface'}=$temp[1]; + + &DeleteIP(%settings); + + splice (@current,$settings{'KEY1'},1); # Delete line + open(FILE, ">$loxilbipfile") or die "$loxilbipfile open error"; + print FILE @current; + close(FILE); + $settings{'KEY1'} = ''; # End remove mode +} + +## Check if sorting is asked +# If same column clicked, reverse the sort. +if ($ENV{'QUERY_STRING'} =~ /$sortstring/ ) { + my $newsort=$ENV{'QUERY_STRING'}; + my $actual=$settings{'SORT_virtualIPLIST'}; + #Reverse actual sort ? + if ($actual =~ $newsort) { + my $Rev=''; + if ($actual !~ 'Rev') { + $Rev='Rev'; + } + $newsort.=$Rev; + } + $settings{'SORT_virtualIPLIST'}=$newsort; + map (delete ($settings{$_}) ,(@nosaved,'ACTION','KEY1'));# Must never be saved + &General::writehash($setting, \%settings); + &SortDataFile; + $settings{'ACTION'} = 'SORT'; # Create an 'ACTION' + map ($settings{$_} = '' ,@nosaved,'KEY1'); # and reinit vars to empty +} + +if ($settings{'ACTION'} eq '' ) { # First launch from GUI + # Place here default value when nothing is initialized + $settings{'virtualIP'} = ''; + $settings{'interface'} = ''; +} + &Header::openpage($Lang::tr{'loxilb'}, 1, ''); &Header::openbigbox('100%', 'left', '', $errormessage); if ($errormessage) { &Header::openbox('100%', 'left', $Lang::tr{'error messages'}); - print "$errormessage \n"; + print "$errormessage \n"; &Header::closebox(); } # Read configuration file. -&General::readhash("$loxilbsettingfile", \%loxilbsettings); +&General::readhash("$loxilbsettingfile", \%settings); # Checkbox pre-selection. my $checked; -if ($loxilbsettings{'ENABLE_LOXILB'} eq "on") { +if ($settings{'ENABLE_LOXILB'} eq "on") { $checked = "checked='checked'"; } @@ -113,11 +215,254 @@ print < END +print " \n"; + +&Header::closebox(); +# + +my $buttontext = $Lang::tr{'add'}; +if ($settings{'KEY1'} ne '') { + $buttontext = $Lang::tr{'update'}; + &Header::openbox('100%', 'left', $Lang::tr{'loxilb fw edit'}); +} else { + &Header::openbox('100%', 'left', $Lang::tr{'loxilb ip add'}); +} + +my @INTERFACES = ("red0", "green0"); + +#Edited line number (KEY1) passed until cleared by 'save' or 'remove' or 'new sort order' +print < + + + + + + + + + + +
$Lang::tr{'loxilb ip virtualIP'}: 
$Lang::tr{'loxilb ip interface'}:  +
+
+ + + + +
+ +END + &Header::closebox(); -print " \n"; +&Header::openbox('100%', 'left', $Lang::tr{'loxilb ip entries'}); + +print < + + $Lang::tr{'loxilb ip virtualIP'} + $Lang::tr{'loxilb ip interface'} + $Lang::tr{'action'} + +END + # +# Print each line of @current list +# + +my $key = 0; +my $col=""; +foreach my $line (@current) { + chomp($line); # remove newline + my @temp=split(/\,/,$line); + $temp[1] ='' unless defined $temp[1]; # not always populated + + #Choose icon for checkbox + my $gif = ''; + my $gdesc = ''; + if ($temp[0] ne '' ) { + $gif = 'on.gif'; + $gdesc = $Lang::tr{'click to disable'}; + } else { + $gif = 'off.gif'; + $gdesc = $Lang::tr{'click to enable'}; + } + + #Colorize each line + if ($settings{'KEY1'} eq $key) { + print ""; + } elsif ($key % 2) { + print ""; + $col="bgcolor='$color{'color20'}'"; + } else { + print ""; + $col="bgcolor='$color{'color22'}'"; + } + print <$temp[0] +$temp[1] + +
+ + + +
+ + + +
+ + + +
+ + +END + + $key++; +} +print ""; + +# If table contains entries, print 'Key to action icons' +if ($key) { +print < + +  $Lang::tr{'legend'}:  + $Lang::tr{ + $Lang::tr{'click to disable'} +    + $Lang::tr{ + $Lang::tr{'click to enable'} +    + $Lang::tr{ + $Lang::tr{'remove'} + + +END +} + +&Header::closebox(); + &Header::closebigbox(); &Header::closepage(); + +## Ouf it's the end ! + +# Sort the "current" array according to choices +sub SortDataFile +{ + our %entries = (); + + # Sort pair of record received in $a $b special vars. + # When IP is specified use numeric sort else alpha. + # If sortname ends with 'Rev', do reverse sort. + # + sub fixedleasesort { + my $qs=''; # The sort field specified minus 'Rev' + if (rindex ($settings{'SORT_virtualIPLIST'},'Rev') != -1) { + $qs=substr ($settings{'SORT_virtualIPLIST'},0,length($settings{'SORT_virtualIPLIST'})-3); + if ($qs eq 'virtualIP') { + my @a = split(/\./,$entries{$a}->{$qs}); + my @b = split(/\./,$entries{$b}->{$qs}); + ($b[0]<=>$a[0]) || + ($b[1]<=>$a[1]) || + ($b[2]<=>$a[2]) || + ($b[3]<=>$a[3]); + } else { + $entries{$b}->{$qs} cmp $entries{$a}->{$qs}; + } + } else { #not reverse + $qs=$settings{'SORT_virtualIPLIST'}; + if ($qs eq 'virtualIP') { + my @a = split(/\./,$entries{$a}->{$qs}); + my @b = split(/\./,$entries{$b}->{$qs}); + ($a[0]<=>$b[0]) || + ($a[1]<=>$b[1]) || + ($a[2]<=>$b[2]) || + ($a[3]<=>$b[3]); + } else { + $entries{$a}->{$qs} cmp $entries{$b}->{$qs}; + } + } + } + + #Use an associative array (%entries) + my $key = 0; + foreach my $line (@current) { + chomp( $line); #remove newline because can be on field 5 or 6 (addition of REMARK) + my @temp = ( '','','', ''); + @temp = split (',',$line); + + # Build a pair 'Field Name',value for each of the data dataline. + # Each SORTABLE field must have is pair. + # Other data fields (non sortable) can be grouped in one + + my @record = ('KEY',$key++,'virtualIP',$temp[0],'interface',$temp[1]); + my $record = {}; # create a reference to empty hash + %{$record} = @record; # populate that hash with @record + $entries{$record->{KEY}} = $record; # add this to a hash of hashes + } + + open(FILE, ">$loxilbipfile") or die "$loxilbipfile open error"; + + # Each field value is printed , with the newline ! Don't forget separator and order of them. + foreach my $entry (sort fixedleasesort keys %entries) { + print FILE "$entries{$entry}->{virtualIP},$entries{$entry}->{interface}\n"; + } + + close(FILE); + # Reload sorted @current + open (FILE, "$loxilbipfile"); + @current = ; + close (FILE); +} + +sub manageIP { + my ($action, %settings) = @_; + + # Initialize variables + my @loxicmd_options; + my $command = 'loxicmd'; + + my $ip = $settings{'virtualIP'}; + my $interface = $settings{'interface'}; + + push(@loxicmd_options, $action, "ip", $ip, $interface); + + #debug and display output in UI + #my @output = &General::system_output($command, @loxicmd_options); + #$errormessage = join('', @output); + &General::system($command, @loxicmd_options); + +} + +sub CreateIP { + my (%settings) = @_; + manageIP("create", %settings); +} + +sub DeleteIP { + my (%settings) = @_; + manageIP("delete", %settings); +} + diff --git a/langs/en/cgi-bin/en.pl b/langs/en/cgi-bin/en.pl index 2e09b5f7f..05214bef1 100644 --- a/langs/en/cgi-bin/en.pl +++ b/langs/en/cgi-bin/en.pl @@ -2488,6 +2488,10 @@ 'loxilb fw portName' => 'iport', 'loxilb fw preference' => 'preference', 'loxilb fw action' => 'ruleAction', +'loxilb ip entries' => 'LoxiLB Virtual IP Entries', +'loxilb ip virtualIP' => 'Virtual IP', +'loxilb ip interface' => 'Interface', +'loxilb ip add' => 'Add Virtual IP', 'status' => 'Status', 'status information' => 'Status information', 'status ovpn' => 'OpenVPN', diff --git a/langs/zh/cgi-bin/zh.pl b/langs/zh/cgi-bin/zh.pl index 39e0c92ab..86875f9e7 100644 --- a/langs/zh/cgi-bin/zh.pl +++ b/langs/zh/cgi-bin/zh.pl @@ -2455,6 +2455,10 @@ 'loxilb fw portName' => '入端口', 'loxilb fw preference' => '优先级', 'loxilb fw action' => '执行', +'loxilb ip entries' => '负载均衡虚拟IP', +'loxilb ip virtualIP' => '虚拟 IP', +'loxilb ip interface' => '网络接口', +'loxilb ip add' => '添加虚拟 IP', 'status' => '状态', 'status information' => '状态信息', 'status ovpn' => 'OpenVPN',