1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
|
#!/bin/sh
eval 'exec perl -x $0 ${1+"$@"}'
if 0;
# This hack makes a shell script which calls Perl also a Perl script.
# We do it this way so this script will run on a system where the user
# has Perl, even if Perl is in /usr/local/bin instead of /usr/bin
#!/usr/bin/perl
# This is a tool for converting CSV1 zone files in to a CSV2 compatible format
# Cleanup: Subroutine that removes potentially dangerous stuff from a hostname
sub cleanup {
my($in) = @_;
# Security: Get rid of all ASCII except [0-9A-Za-z\.\@\%\_\-]
$in =~ s/[^0-9A-Za-z\.\@\%\x80-\xff\-\_]//g;
# Get rid of all % except trailing %
if($in =~ /\%$/) {
$in =~ s/\%//g;
$in = $in . "%";
} else { $in =~ s/\%//g; }
return nonmt($in);
}
# non-empty: Subroutine that makes sure a string is not empty
sub nonmt {
my($in) = @_;
return nonmt_r($in,"0");
}
sub nonmt_q {
my($in) = @_;
return nonmt_r($in,"\'\'");
}
sub nonmt_r {
my($in,$replace) = @_;
if($in =~ /^[\s\|]*$/) {
$in = $replace;
}
return $in;
}
while(<>) {
if(/^#/) {print;next;} # Comments are printed as-is
if(/^\s*$/) {print;next;} # Ditto with lines with just whitespace
if(/^(.)(.*)/) {$rrtype = $1; $rest=$2;
($hostname,$ttl,$rdata) = split(/\|/,$rest,3);
# Do security cleanup on hostname
$hostname = cleanup($hostname);
# Security: Get rid of anything that isn't a number in ttl
$ttl =~ s/[^0-9]//g;
$ttl = nonmt($ttl);
if($rrtype =~ /^A/) {
# Remove non numeric and dot from rdata
$rdata =~ s/[^0-9\.]//g;
$rdata = nonmt($rdata);
print "$hostname|+$ttl|A|$rdata\n";
} elsif($rrtype =~ /^N/) {
$rdata = cleanup($rdata);
print "$hostname|+$ttl|NS|$rdata\n";
} elsif($rrtype =~ /^P/) {
$rdata = cleanup($rdata);
print "$hostname|+$ttl|PTR|$rdata\n";
} elsif($rrtype =~ /^C/) {
$rdata = cleanup($rdata);
print "$hostname|+$ttl|CNAME|$rdata\n";
} elsif($rrtype =~ /^@/) {
# MX records
($priority,$h) = split(/\|/,$rdata,2);
$priority =~ s/[^0-9]//g;
$h = cleanup($h);
$priority = nonmt($priority);
print "$hostname|+$ttl|MX|$priority|$h\n";
} elsif($rrtype =~ /^S/) {
# SOA records
($o,$e,$s,$rf,$rt,$ex,$min) = split(/\|/,$rdata,7);
$o = cleanup($o);
$e = cleanup($e);
$s =~ s/[^0-9]//g;
$s = nonmt($s);
$rf =~ s/[^0-9]//g;
$rf = nonmt($rf);
$rt =~ s/[^0-9]//g;
$rt = nonmt($rt);
$ex =~ s/[^0-9]//g;
$ex = nonmt($ex);
$min =~ s/[^0-9]//g;
$min = nonmt($min);
print "$hostname|+$ttl|SOA|$o|$e|$s|$rf|$rt|$ex|$min\n";
}
# It's a little tricky converting TXT and RAW records; this
# hopefully covers all real-world examples.
elsif($rrtype =~ /^T/ || $rrtype =~ /^U/) {
if($rrtype =~ /^U/) {
($rrnum,$rdata) = split(/\|/,$rdata,2);
}
# Security: Get rid of backslashes that would cause
# a syntax error when parsed with the csv1 parser
$rdata =~ s/\\([^\\\%0-3])/$1/g;
$rdata =~ s/\'/\'\\\'\'/g; # make ' -> '\'' (ugh)
$rdata =~ s/\\\%/%/g; # make \% just %
$rdata =~ s/\\\\/\\/g; # make \\ just \
# The following line puts octal numbers outside of
# quotes, since they can not be quoted.
$rdata =~ s/(\\[0-3][0-7][0-7])/\'$1\'/g;
# get rid of ugly (but yes parsable) '' sequences
# '\001''\002''\003' -> '\001\002\003'
$rdata =~
s/(\\[0-3][0-7][0-7])\'\'(\\[0-3][0-7][0-7])/$1$2/g;
# '\'''\'''\'' -> '\'\'\'' by making ''\' simply \'
$rdata =~ s/\'\'\\\'/\\\'/g;
# Put quotes around the string
$rdata = "\'" . $rdata . "\'";
# The next two lines get rid of ugly '' at the
# beginning and end of the string
$rdata =~ s/^\'\'//;
$rdata =~ s/\'\'$//;
# Make sure the final string is not empty
$rdata = nonmt_q($rdata);
if($rrtype =~ /^T/) {
print "$hostname|+$ttl|TXT|$rdata\n";
} else {
print "$hostname|+$ttl|RAW|$rrnum|$rdata\n";
}
}
}
}
|