File: digparse

package info (click to toggle)
dlint 1.4.0-8
  • links: PTS, VCS
  • area: main
  • in suites: bullseye, buster, sid
  • size: 236 kB
  • sloc: sh: 1,173; makefile: 94; perl: 89
file content (208 lines) | stat: -rwxr-xr-x 6,368 bytes parent folder | download | duplicates (3)
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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
#!/usr/bin/perl
#
# digparse
#
# Perl code that converts DiG output (version 2.x, 8.x, 9.x) into
# the easily parsable form:
#
#	HOST	RR	RR-ARGS
# i.e.
#	fire.domtools.com.  A  10.0.0.10
#	fire.domtools.com.  MX  10  flame.domtools.com.
#
# It understands $ORIGIN and @ and can expand @, blank LHS's, and non-dot-terminated
# LHS and RHSs.  No comments or blank lines are printed.
#
# Usage with Dig 2 thru 8:  dig @server.dom.ain. AXFR dom.ain. +ret=2 +noauthor +noaddit \
#			    +noques +noHeader +noheader +cl +noqr +nostats +nocmd | \
#			    digparse > file
#
# Usage with Dig 9:         dig @server.dom.ain. AXFR dom.ain. +ret=2 +noauthority \
#			    +noadditional +noquestion +nostats +nocmd | digparse > file
#
# There are many differences in output between DiG 2.x, 8.x, and 9.x.
# 2.x doesn't display the class ("IN").
# 8.x abbreviates time fields with letters like "h"=hours, "m"=minutes, "s"=seconds,
#     and uses "@" for default origin and sometimes leaves domain off entirely so you
#     have to carry forward the current domain name from lines above.
# 9.x output is perfect in every way.
#
# Example inputs that Digparse can parse (using options above) --
#
#    Dig 9.x:    domtools.com.   86400   IN      SOA     fire.domtools.com. hostmaster.domtools.com. ( 2000111600 28815 3615 2073600 86400 )
#		 domtools.com.   86400   IN      NS      ns0.domtools.com.
#
#    Dig 8.x:    $ORIGIN domtools.com.
#		 @               1D IN SOA       fire hostmaster (
#                                        2000111600      ; serial
#                                        8h15s           ; refresh
#                                        1h15s           ; retry
#                                        3w3d            ; expiry
#                                        1D )            ; minimum
#
#		                 1D IN NS        ns0
#
#    Dig 2.x:    domtools.com.   86400   SOA     fire.domtools.com. hostmaster.domtools.com. (
#                        2000111600      ; serial
#                        28815   ; refresh (8 hours 15 secs)
#                        3615    ; retry (1 hour 15 secs)
#                        2073600 ; expire (24 days)
#                        86400 ) ; minimum (1 day)
#		 domtools.com.   86400   NS      ns0.domtools.com.
#
# Output from digparse for all above inputs:
#
#     domtools.com.       SOA      fire.domtools.com. hostmaster.domtools.com.  2000111600 28815 3615 2073600 86400
#     domtools.com.       NS       ns0.domtools.com.
#
# However the seconds are left as-is, so they'll contain h,m,s abbreviations
# when using BIND 8 (but not 2, or 9!)  We don't care because Dlint doesn't use them.
#
# Paul Balyoz <pab@domtools.com>
#

# RRs that have a domain name for their rightmost field
# (we tack the default domain onto domains that don't end in ".")
%rhs_is_domain = (
	"NS"=>1,
	"PTR"=>1,
	"MX"=>1,
	"CNAME"=>1,
);

# DNS Class Table
%classes = (
	"IN"=>1,	# Internet
	"CH"=>1,	# Chaos
);


# Main Loop - input lines from stdin, handle them.

while (<>) {

	chop;
	next if /^\s*;/;		# skip blank & comment lines
	next if /^\s*$/;

	@f = split;

	if ($f[0] eq '$ORIGIN') {		# literally the string '$ORIGIN'
		$origin = $f[1];
		$origin .= "." if $origin !~ /\.$/;	# append "." if missing
		$origin = "" if $origin eq ".";		# use "" for root domain
		next;
	}
	elsif ($f[0] !~ /\.$/) {	# record name is missing its ending period!
		if ($f[0] eq "@") {
			$f[0] = "$origin";	# expand "@" into domain name
		} else {
			$f[0] .= ".$origin";	# append domain name onto name
		}
	}

	if (/^\s/) {				# empty LHS, use curr. domain name
		unshift @f, $domain;
	}
	else {
		$domain = $f[0];		# memorize this LHS for future lines
	}

	splice(@f,2,1)  if $classes{uc($f[2])};	# Get rid of Class if exists (DiG 8 & newer)


# By this point the records have been standardized like this --
#	$f[0] = LHS   (canonical domain name)
#	$f[1] = TTL
#	$f[2] = RRTYPE
#	$f[3]..$f[$#f] = data (1 or more fields)

	$rr = uc($f[2]);

	if ($rhs_is_domain{$rr} && $f[$#f] !~ /\.$/) {		# empty RHS domain name
		if ($f[$#f] eq "@") {
			$f[$#f] = "$origin";			# "@" is just the origin
		} else {
			$f[$#f] .= ".$origin";			# otherwise append origin
		}
	}

# By this point any domain names in the data fields have been canonicalized.
# (we expanded Dig 2.x's "@" symbols and unqualified names to fqdn's)

#
# If we see a RR continuation marker (left-paren)
# then read and parse the rest of the continuation lines.
# The line looked like this:
# @                       4H IN SOA       pallas hostmaster.pallas (
#
	if (/\(\s*$/) {
		undef($f[$#f]);			# remove the "(" thing
		while (<STDIN>) {
			chop;

# Remove comments from the line.  DiG 2.1 puts parentheses in the comments!

			s/;.*//;

# Next, handle all other data lines in the continuation,
# including the right-paren line.  Expect no comments.
# Those lines look like this:
#                                         712120828       ; serial
#                                         1H              ; refresh
#                                         5M              ; retry
#                                         1W              ; expiry
#                                         4H )            ; minimum

#			if (/\s*([^\);\s]+)\s*\)?\s*;?.*/) {
#} ugh
			if (/\s*([^\)\s]+)\s*\)?.*/) {
				$f[$#f+1] = $1;
			}
			last if /\)/;		# end continuation line
		}
	}

	if ($rr eq "SOA") {
		if ($f[3] !~ /\.$/) {	# record name is missing its ending period!
			if ($f[3] eq "@") {
				$f[3] = "$origin";	# expand "@" into domain name
			} else {
				$f[3] .= ".$origin";	# append domain name onto name
			}
		}
		if ($f[4] !~ /\.$/) {	# record name is missing its ending period!
			if ($f[4] eq "@") {
				$f[4] = "$origin";	# expand "@" into domain name
			} else {
				$f[4] .= ".$origin";	# append domain name onto name
			}
		}
		if ($f[5] eq "(") {
			splice(@f,5,1);		# remove grouping symbols (BIND 9)
		}
		if ($f[$#f] eq ")") {
			splice(@f,$#f,1);	# remove grouping symbols (BIND 9)
		}
	}

# Print resulting data line

	$nspaces = 32 - length($f[0]);
	$nspaces = 1 if $nspaces < 1;
	print $f[0], " " x $nspaces;

	#$str = "$f[1] $f[2]";
	$str = "$f[2]";			# don't bother printing TTL
	$nspaces = 8 - length($str);
	$nspaces = 1 if $nspaces < 1;
	print "$str", " " x $nspaces;

	for ($i=3; $i<=$#f; $i++) {
		print " ",$f[$i];
	}
	print "\n";

}

exit 0;