Order of Responses to Queries from Outside a Network

Kevin Darcy kcd at daimlerchrysler.com
Tue Jan 27 04:03:40 UTC 2004


Martin McCormick wrote:

>	Address sorting in bind works beautifully for queries inside
>our network, but I have been asked to add a slight modification.
>
>	Is there a way to tell BIND 9.2.2rc1 to always put a given A
>record first in the list sent to queries from outside the network
>while still maintaining the address sorting for queries from inside the
>network?
>
>	In other words, we want not to break the address sorting
>feature which works inside our network, but add a sort order for
>everyone outside.
>
>	The idea is to guide outsiders to a specific server that can
>handle the load and list servers on campuses with less network
>capacity last.
>  
>
Well, as you've no doubt noticed, negation doesn't seem to work too well 
in sortlist clauses.

The only thing that comes to mind is to create an ACL of everything 
*but* your network(s) and then add a subclause for that to your sortlist 
clause, favoring a particular address or range of addresses, e.g. 
(assuming you hypothetically had the entire lowest quarter -- nets 0 
through 63 -- of the IPv4 address range assigned to you):

acl notmynet { 128/1; 64/2; };

options {
    ...
    sortlist {
             { mysubnet1; mysubnet1; };
             { mysubnet2; mysubnet2; };
              ...
             { notmynet; { 1.2.3.4 };  };
    };
};

It's a little laborious to work out by hand all of the prefixes which 
define the "negative" of a given prefix, so here's a little 
quick-and-dirty Perl script that can do it:

#!/usr/bin/perl

$input = $ARGV[0];

die "invalid syntax!" unless ($input =~ m%^\d+(\.\d+)*/\d{1,2}$%);
($netstring, $numbits) = split(m%/%, $input);
die "prefix too large!" if ($numbits > 32);
@octet = split(/\./, $netstring);
die "too many octets!" if (scalar(@octet) > 4);
for ($i = $#octet; $i >= 0; $i--) {
        die "oversized octet!" if ($octet[$i] > 255);
        $netnum += ($octet[$i] * (256**(3-$i)));
}
die "network not on power-of-two boundary" if ($netnum%(2**(32-$numbits)));
for ($i = 31; $i >= (32 - $numbits); $i--) {
        if ($netnum & (1 << $i)) {
                print_prefix($partial, (32 - $i));
                $partial += (1 << $i);
        } else {
                print_prefix($partial + (1 << $i), (32 - $i));
        }
}

sub print_prefix {
        my ($raw, $bits) = @_;
        my ($octet, $newbits) = (0, $bits - 8);

        print int($raw/(1<<24));
        $raw %= (1<<24);
        while ($newbits > 0) {
                $octet++;
                print "." . int($raw/(1<<(24 - ($octet * 8))));
                $raw %= (1<<(24 - ($octet * 8)));
                $newbits -= 8;
        }
        print "/$bits\n";
}

E.g. running the script with a command-line parameter of "53/8" yields:

128/1
64/2
0/3
32/4
56/5
48/6
54/7
52/8

(Figuring out the "negative" of several different non-adjacent prefixes 
combined is left as an algorithmic exercise for the reader :-)

                                                                         
                                 - Kevin

P.S. You do realize that other nameservers/resolvers caching the query 
results will muck up your careful ordering, right?



More information about the bind-users mailing list