- Timestamp:
- 04/09/12 18:08:51 (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/DNSDB.pm
r297 r298 736 736 ## 737 737 738 # Replace ZONE in hostname 738 # Replace ZONE in hostname, or create (most of) the actual proper zone name 739 739 sub _ZONE { 740 740 my $zone = shift; 741 741 my $string = shift; 742 742 my $fr = shift || 'f'; # flag for forward/reverse order? nb: ignored for IP 743 744 my $prefix = $zone->network->addr; # Just In Case someone managed to slip in 745 # a funky subnet that had host bits set. 743 my $sep = shift || '-'; # Separator character - unlikely we'll ever need more than . or - 744 745 my $prefix; 746 746 747 747 $string =~ s/,/./ if !$zone->{isv6}; 748 748 $string =~ s/,/::/ if $zone->{isv6}; 749 749 750 # if ($zone->{isv6} && ($zone->masklen % 4) != 0) { 751 # # grumpyfail, non-nibble zone. shouldn't happen 752 # return; 753 # } 754 755 # Subbing ZONE in the host. We need to properly ID the netblock range 756 # The subbed text should have "network IP with trailing zeros stripped" for 757 # blocks lined up on octet (for v4) or 16-bit (for v6) boundaries 758 # For blocks that do NOT line up on these boundaries, we tack on an extra "-0", 759 # then take the most significant octet or 16-bit chunk of the "broadcast" IP and 760 # append it after a double-dash 761 # ie: 762 # 8.0.0.0/6 -> 8.0.0.0 -> 11.255.255.255; sub should be 8--11 763 # 10.0.0.0/12 -> 10.0.0.0 -> 10.0.0.0 -> 10.15.255.255; sub should be 10-0--15 764 # 192.168.4.0/22 -> 192.168.4.0 -> 192.168.7.255; sub should be 192-168-4--7 765 # 192.168.0.8/29 -> 192.168.0.8 -> 192.168.0.15; sub should be 192-168-0-8--15 766 # Similar for v6 767 if (!$zone->{isv6}) { 750 # Subbing ZONE in the host. We need to properly ID the netblock range 751 # The subbed text should have "network IP with trailing zeros stripped" for 752 # blocks lined up on octet (for v4) or hex-quad (for v6) boundaries 753 # For blocks that do NOT line up on these boundaries, we take the most 754 # significant octet or 16-bit chunk of the "broadcast" IP and append it 755 # after a double-dash 756 # ie: 757 # 8.0.0.0/6 -> 8.0.0.0 -> 11.255.255.255; sub should be 8--11 758 # 10.0.0.0/12 -> 10.0.0.0 -> 10.0.0.0 -> 10.15.255.255; sub should be 10-0--15 759 # 192.168.4.0/22 -> 192.168.4.0 -> 192.168.7.255; sub should be 192-168-4--7 760 # 192.168.0.8/29 -> 192.168.0.8 -> 192.168.0.15; sub should be 192-168-0-8--15 761 # Similar for v6 762 763 if (!$zone->{isv6}) { # IPv4 764 765 $prefix = $zone->network->addr; # Just In Case someone managed to slip in 766 # a funky subnet that had host bits set. 767 my $bc = $zone->broadcast->addr; 768 769 if ($zone->masklen > 24) { 770 $bc =~ s/^\d+\.\d+\.\d+\.//; 771 } elsif ($zone->masklen > 16) { 772 $prefix =~ s/\.0$//; 773 $bc =~ s/^\d+\.\d+\.//; 774 } elsif ($zone->masklen > 8) { 775 $bc =~ s/^\d+\.//; 776 $prefix =~ s/\.0\.0$//; 777 } else { 778 $prefix =~ s/\.0\.0\.0$//; 779 } 780 if ($zone->masklen % 8) { 781 $bc =~ s/(\.255)+$//; 782 $prefix .= "--$bc"; #"--".zone->masklen; # use range or mask length? 783 } 784 if ($fr eq 'f') { 785 $prefix =~ s/\.+/$sep/g; 786 } else { 787 $prefix = join($sep, reverse(split(/\./, $prefix))); 788 } 789 790 } else { # IPv6 791 792 if ($fr eq 'f') { 793 794 $prefix = $zone->network->addr; # Just In Case someone managed to slip in 795 # a funky subnet that had host bits set. 768 796 my $bc = $zone->broadcast->addr; 769 if ($zone->masklen > 24) { 770 $bc =~ s/^\d+\.\d+\.\d+\.//; 771 } elsif ($zone->masklen > 16) { 772 $prefix =~ s/\.0$//; 773 $bc =~ s/^\d+\.\d+\.//; 774 } elsif ($zone->masklen > 8) { 775 $bc =~ s/^\d+\.//; 776 $prefix =~ s/\.0\.0$//; 797 if (($zone->masklen % 16) != 0) { 798 # Strip trailing :0 off $prefix, and :ffff off the broadcast IP 799 for (my $i=0; $i<(7-int($zone->masklen / 16)); $i++) { 800 $prefix =~ s/:0$//; 801 $bc =~ s/:ffff$//; 802 } 803 # Strip the leading 16-bit chunks off the front of the broadcast IP 804 $bc =~ s/^([a-f0-9]+:)+//; 805 # Append the remaining 16-bit chunk to the prefix after "--" 806 $prefix .= "--$bc"; 777 807 } else { 778 $prefix =~ s/\.0\.0\.0$//; 808 # Strip off :0 from the end until we reach the netblock length. 809 for (my $i=0; $i<(8-$zone->masklen / 16); $i++) { 810 $prefix =~ s/:0$//; 811 } 779 812 } 780 if ($zone->masklen % 8) { 781 $bc =~ s/(\.255)+$//; 782 $prefix .= "--$bc"; #"--".zone->masklen; # use range or mask length? 813 # Actually deal with the separator 814 $prefix =~ s/:/$sep/g; 815 816 } else { # $fr eq 'f' 817 818 $prefix = $zone->network->full; # Just In Case someone managed to slip in 819 # a funky subnet that had host bits set. 820 my $bc = $zone->broadcast->full; 821 $prefix =~ s/://g; # clean these out since they're not spaced right for this case 822 $bc =~ s/://g; 823 # Strip trailing 0 off $prefix, and f off the broadcast IP, to match the mask length 824 for (my $i=0; $i<(31-int($zone->masklen / 4)); $i++) { 825 $prefix =~ s/0$//; 826 $bc =~ s/f$//; 783 827 } 828 # Split and reverse the order of the nibbles in the network/broadcast IPs 829 my @nbits = reverse split //, $prefix; 830 my @bbits = reverse split //, $bc; 831 # Handle the sub-nibble case. Eww. I feel dirty supporting this... 832 $nbits[0] = "$nbits[0]-$bbits[0]" if ($zone->masklen % 4) != 0; 833 # Glue it back together 834 $prefix = join($sep, @nbits); 835 836 } # $fr ne 'f' 837 838 } # $zone->{isv6} 839 840 # Do the substitution, finally 841 $string =~ s/ZONE/$prefix/; 842 $string =~ s/--/-/ if $sep ne '-'; # - as separator needs extra help for sub-octet v4 netblocks 843 return $string; 844 } # done _ZONE() 845 846 # Not quite a substitution sub, but placed here as it's basically the inverse of above; 847 # given the .arpa zone name, return the CIDR netblock the zone is for. 848 # Supports v4 non-octet/non-classful netblocks as per the method outlined in the Cricket Book (2nd Ed p217-218) 849 # Does NOT support non-quad v6 netblocks via the same scheme; it shouldn't ever be necessary. 850 # Takes a nominal .arpa zone name, returns a success code and NetAddr::IP, or a fail code and message 851 sub _zone2cidr { 852 my $zone = shift; 853 854 my $cidr; 855 my $warnmsg; 856 857 if ($zone =~ /\.in-addr\.arpa\.?$/) { 858 # v4 revzone, formal zone name type 859 my $tmpcidr; 860 my $tmpzone = $zone; 861 $tmpzone =~ s/\.in-addr\.arpa\.?//; 862 return ('FAIL',"Non-numerics in apparent IPv4 reverse zone name") if $tmpzone !~ /^(?:\d+-)?[\d\.]+$/; 863 864 # Snag the octet pieces 865 my @octs = split /\./, $tmpzone; 866 867 # Map result of a range manipulation to a mask length change. Cheaper than finding the 2-root of $octets[0]+1. 868 my %maskmap = (1 => 1, 3 => 2, 7 => 3, 15 => 4, 31 => 5, 63 => 6, 127 => 7); 869 870 # Handle "range" blocks, eg, 80-83.168.192.in-addr.arpa (192.168.80.0/22) 871 # Need to take the size of the range to offset the basic octet-based mask length, 872 # and make sure the first number in the range gets used as the network address for the block 873 my $masklen = 0; 874 if ($octs[0] =~ /(\d+)-\d+/) { # take the range... 875 $masklen -= $maskmap{-(eval $octs[0])}; # find the mask base... 876 $octs[0] = $1; # set the base octet of the range... 877 } 878 @octs = reverse @octs; # We can reverse the octet pieces now that we've extracted and munged any ranges 879 880 # Now we find the "true" mask with the aid of the "base" calculated above 881 if ($#octs == 0) { 882 $masklen += 8; 883 $tmpcidr = "$octs[0].0.0.0/$masklen"; # really hope we don't see one of these very often. 884 } elsif ($#octs == 1) { 885 $masklen += 16; 886 $tmpcidr = "$octs[0].$octs[1].0.0/$masklen"; 887 } elsif ($#octs == 2) { 888 $masklen += 24; 889 $tmpcidr = "$octs[0].$octs[1].$octs[2].0/$masklen"; 784 890 } else { 785 if (($zone->masklen % 16) != 0) { 786 # Strip trailing :0 off $prefix, and :ffff off the broadcast IP 787 # Strip the leading 16-bit chunks off the front of the broadcast IP 788 # Append the remaining 16-bit chunk to the prefix after "--" 789 my $bc = $zone->broadcast->addr; 790 for (my $i=0; $i<(7-int($zone->masklen / 16)); $i++) { 791 $prefix =~ s/:0$//; 792 $bc =~ s/:ffff$//; 793 } 794 $bc =~ s/^([a-f0-9]+:)+//; 795 $prefix .= "--$bc"; 796 } else { 797 # Strip off :0 from the end until we reach the netblock length. 798 for (my $i=0; $i<(8-$zone->masklen / 16); $i++) { 799 $prefix =~ s/:0$//; 800 } 801 } 802 } 803 804 # Replace . and : with - 805 # If flagged for reverse-order, split on . or :, reverse, and join with - 806 if ($fr eq 'f') { 807 $prefix =~ s/[:.]+/-/g; 808 } else { 809 $prefix = join('-', reverse(split(/[:.]/, $prefix))); 810 } 811 $string =~ s/ZONE/$prefix/; 812 # } 813 return $string; 814 } # done _ZONE 815 891 $masklen += 32; 892 $tmpcidr = "$octs[0].$octs[1].$octs[2].$octs[3]/$masklen"; 893 } 894 895 # Just to be sure, use NetAddr::IP to validate. Saves a lot of nasty regex watching for valid octet values. 896 return ('FAIL', "Invalid zone $zone (apparent netblock $cidr)") 897 unless $cidr = NetAddr::IP->new($tmpcidr); 898 899 } elsif ($zone =~ /\.ip6\.arpa$/) { 900 # v6 revzone, formal zone name type 901 my $tmpzone = $zone; 902 $tmpzone =~ s/\.ip6\.arpa\.?//; 903 return ('FAIL',"Non-hexadecimals in apparent IPv6 reverse zone name") if $tmpzone !~ /^[a-fA-F\d\.]+$/; 904 my @quads = reverse(split(/\./, $tmpzone)); 905 $warnmsg .= "Apparent sub-/64 IPv6 reverse zone\n" if $#quads > 15; 906 my $nc; 907 foreach (@quads) { 908 $cidr .= $_; 909 $cidr .= ":" if ++$nc % 4 == 0; 910 } 911 my $nq = 1 if $nc % 4 != 0; 912 my $mask = $nc * 4; # need to do this here because we probably increment it below 913 while ($nc++ % 4 != 0) { 914 $cidr .= "0"; 915 } 916 $cidr .= ($nq ? '::' : ':')."/$mask"; 917 } 918 } # done _zone2cidr() 816 919 817 920
Note:
See TracChangeset
for help on using the changeset viewer.