Index: ldirectord =================================================================== RCS file: /home/cvs/linux-ha/linux-ha/ldirectord/ldirectord,v retrieving revision 1.13 diff -u -r1.13 ldirectord --- ldirectord 2000/07/06 10:06:01 1.13 +++ ldirectord 2000/07/13 01:47:58 @@ -116,17 +116,19 @@ =head2 These commands must follow a B entry and must be indented (minimum 4 spaces or one tab) -B I B|B|B [I] [B<">IB<", ">IB<">] +B I B|B|B [I] [B<">IB<", ">IB<">] -Defines a real service by IP-address and port. The second argument -defines the forwarding method, must be B, B or B. -The thrid argument is optional and defines the weight for that real server. -The last two arguments are optional. They define a request-receive pair to -be used to check if a server is alive. They override the request-receive -pair in the virtual server section. These two strings must be quoted. -If the request string starts with I the IP-address of the real -server is overridden, otherwise the IP-address of the real server is used. -This may be used to send a request over a transparent proxy. +Defines a real service by IP-address and port. Optionally a range of IP +addresses mqy be give, in which case each IP address in the range will be +treated as a real server using the given port. The second argument defines +the forwarding method, must be B, B or B. The thrid +argument is optional and defines the weight for that real server. The last +two arguments are optional. They define a request-receive pair to be used +to check if a server is alive. They override the request-receive pair in +the virtual server section. These two strings must be quoted. If the +request string starts with I the IP-address of the real server +is overridden, otherwise the IP-address of the real server is used. This +may be used to send a request over a transparent proxy. =head2 More than one of these entries may be inside a virtual section: @@ -134,21 +136,21 @@ The type of service to monitor. None denotes a service that will not be monitored. If the port specfied for the virtual server is 80 the default -service is B. If the port specified is 443 the default service is B. -If the port specified is 21 the default service is B. Otherwise the default -service is B. +service is B. If the port specified is 443 the default service is +B. If the port specified is 21 the default service is B. +Otherwise the default service is B. BIB<"> -This object will be requested each checkinterval seconds on each real server. -The string must be inside quotes. Note that this string may be overridden -by an optional per real-server based request-string. +This object will be requested each checkinterval seconds on each real +server. The string must be inside quotes. Note that this string may be +overridden by an optional per real-server based request-string. BIB<"> If the requested result contains this I, the real server -is declared alive. The string must be inside quotes. Note that this string may -be overridden by an optional per real-server based receive-string. +is declared alive. The string must be inside quotes. Note that this string +may be overridden by an optional per real-server based receive-string. This string is ignored for ftp services. Ftp service only checks if the file exists. @@ -184,7 +186,7 @@ Jacob Rief -Simon Horm +Horms =cut @@ -208,6 +210,7 @@ $initializing; use Getopt::Std; +use Socket; #use LWP::Parallel::UserAgent; getopts("dh"); @@ -394,36 +397,13 @@ my $rcmd = $1; next if ($rcmd =~ /^#/); if ($rcmd =~ /^real\s*=\s*(.*)/) { - $1 =~ /(\d+\.\d+\.\d+\.\d+:\d+)\s+(.*)/ + $1 =~ /(\d+\.\d+\.\d+\.\d+)(-(\d+\.\d+\.\d+\.\d+))?:(\d+)\s+(.*)/ or config_error($line, "invalid address for real server"); - my $rmt = $1; - $2 =~ /(\w+)(.*)/ && ($1 eq "gate" || $1 eq "masq" || $1 eq "ipip") - or config_error($line, "forward method must be gate, masq or ipip"); - my $fwd = $1; - if ($2 =~ /\s+(\d+)\s+(.*)/) { - my $weight = $1; - if ($2 =~ /\"(.*)\",\s*\"(.*)\"/) { - push(@rsrv, {"server"=>$rmt, "forward"=>$fwd, "weight"=>$weight, "request"=>$1, "receive"=>$2}); - } else { - push(@rsrv, {"server"=>$rmt, "forward"=>$fwd, "weight"=>$weight}); - } - } elsif ($2 =~ /\s+\"(.*)\",\s*\"(.*)\"/) { - push(@rsrv, {"server"=>$rmt, "forward"=>$fwd, "request"=>$1, "receive"=>$2}); - } else { - push(@rsrv, {"server"=>$rmt, "forward"=>$fwd}); - } - my $realsrv=0; - foreach $r (@REAL){ - if($r->{"real"} eq $vsrv{protocol}.":".$rmt){ - my $ref=$r->{"virtual"}; - push(@$ref, $vsrv{"protocol"}.":".$vsrv{"server"}); - $realsrv=1; - last; - } + if ( defined ($2) ) { + add_real_server_range($line, \%vsrv, \@rsrv, $1, $3, $4, $5); } - if($realsrv==0){ - push(@REAL, { "real"=>$vsrv{protocol}.":".$rmt, - "virtual"=>[ $vsrv{protocol}.":".$vsrv{"server"} ] }); + else { + add_real_server($line, \%vsrv, \@rsrv, $1.":".$4, $5); } } elsif ($rcmd =~ /^request\s*=\s*\"(.*)\"/) { $1 =~ /(.+)/ or config_error($line, "no request string specified"); @@ -515,7 +495,68 @@ return(0); } +sub add_real_server_range +{ + my ($line, $vsrv, $rsrv, $first, $last, $port, $flags) = (@_); + + my (@tmp, $first_i, $last_i, $i); + + if ( ($first_i=ip_to_decimal($first)) <0 ) { + config_error($line, "Invalid IP address: $first"); + } + if ( ($last_i=ip_to_decimal($last)) <0 ) { + config_error($line, "Invalid IP address: $last"); + } + + if ($first_i>$last_i) { + config_error($line, "Invalid Range: $first-$last: First value must be less than or equal to the second value"); + } + + # A for loop didn't seem to want to work + $i=$first_i; + while ( $i le $last_i ) { + add_real_server($line, $vsrv, $rsrv, decimal_to_ip($i) . ":" . $port, $flags); + $i++; + } +} + +sub add_real_server +{ + my ($line, $vsrv, $rsrv, $rmt, $flags) = (@_); + + my $ref; + my $realsrv=0; + $flags =~ /(\w+)(.*)/ && ($1 eq "gate" || $1 eq "masq" || $1 eq "ipip") + or config_error($line, "forward method must be gate, masq or ipip"); + my $fwd = $1; + if ($2 =~ /\s+(\d+)\s+(.*)/) { + my $weight = $1; + if ($2 =~ /\"(.*)\",\s*\"(.*)\"/) { + push(@$rsrv, {"server"=>$rmt, "forward"=>$fwd, "weight"=>$weight, "request"=>$1, "receive"=>$2}); + } else { + push(@$rsrv, {"server"=>$rmt, "forward"=>$fwd, "weight"=>$weight}); + } + } elsif ($2 =~ /\s+\"(.*)\",\s*\"(.*)\"/) { + push(@$rsrv, {"server"=>$rmt, "forward"=>$fwd, "request"=>$1, "receive"=>$2}); + } else { + push(@$rsrv, {"server"=>$rmt, "forward"=>$fwd}); + } + + foreach $r (@REAL){ + if($r->{"real"} eq $vsrv->{protocol}.":".$rmt){ + my $ref=$r->{"virtual"}; + push(@$ref, $vsrv->{"protocol"}.":".$vsrv->{"server"}); + $realsrv=1; + last; + } + } + if($realsrv==0){ + push(@REAL, { "real"=>$vsrv->{protocol}.":".$rmt, + "virtual"=>[ $vsrv->{protocol}.":".$vsrv->{"server"} ] }); + } +} + sub config_error { my ($line, $msg) = @_; @@ -943,8 +984,6 @@ # pre: LIST: arguments to pass to system() # post: system is called and if it returns non-zero a failure message is logged # return: none -# -# Added by Horms , 11th January 2000 sub system_wrapper { @@ -952,5 +991,80 @@ my $now = localtime() . "|$CONFIG"; system(@_) == 0 or print LOGFILE "[$now] system(@args) failed\n" +} + + +# See if a number is an octet, that is >=0 and <=255 +# pre: alleged_octet: the octect to test +# post: 1 if the alleged_octet is an octet +# 0 otherwise + +sub is_octet { + my ($alleged_octet)=(@_); + + if($alleged_octet<0){ return 0; } + if($alleged_octet>255){ return 0; } + + return(1); +} + + +# is_ip +# Check that a given string is an IP address +# pre: alleged_ip: string representing ip address +# post: 1 if alleged_ip is a valid ip address +# 0 otherwise + +sub is_ip { + my ($alleged_ip)=(@_); + + #If we don't have four, . delimited numbers then we have no hope + unless($alleged_ip=~m/^(\d+)\.(\d+)\.(\d+)\.(\d+)$/) { return 0; } + + #Each octet mist be >=0 and <=255 + unless(&is_octet($1)){ return 0; } + unless(&is_octet($2)){ return 0; } + unless(&is_octet($3)){ return 0; } + unless(&is_octet($4)){ return 0; } + + return(1); +} + + +# ip_to_decimal +# Turn an IP address given as a dotted quad into a decimal +# pre: ip_address: string representing IP address +# post: -1 if an error occurs +# decimal representation of IP address otherwise + +sub ip_to_decimal { + my ($ip_address)=(@_); + + unless(&is_ip($ip_address)){ return(-1); } + unless($ip_address=~m/^(\d+)\.(\d+)\.(\d+)\.(\d+)$/){ return(-1); } + + return(((((($1<<8)+$2)<<8)+$3)<<8)+$4); +} + +###################################################################### +# decimal_to_ip +# Turn an IP address given as a dotted quad into a decimal +# pre: ip_address: string representing IP address +# post: -1 if an error occurs +# decimal representation of IP address otherwise +###################################################################### + +sub decimal_to_ip { + my ($ip_address)=(@_); + + my $result=""; + + return(sprintf( + "%d.%d.%d.%d", + ($ip_address>>24)&255, + ($ip_address>>16)&255, + ($ip_address>>8)&255, + $ip_address&255 + )); } Index: ldirectord.cf =================================================================== RCS file: /home/cvs/linux-ha/linux-ha/ldirectord/ldirectord.cf,v retrieving revision 1.1 diff -u -r1.1 ldirectord.cf --- ldirectord.cf 2000/04/24 07:08:13 1.1 +++ ldirectord.cf 2000/07/13 01:47:58 @@ -37,3 +37,15 @@ # receive="Test Page" # scheduler=rr # #persistent=600 + + +# Sample configuration for a service using a range of real servers +# and a single real server for a virtual service + +#virtual=192.168.6.240:80 +# real=192.168.6.2-192.168.6.30:80 gate +# real=192.168.6.32:80 gate +# service=http +# request="index.html" +# receive="Test Page" +# scheduler=rr