|
1 #! /usr/bin/perl |
|
2 #dig TLSA _25._tcp.ssl.schlittermann.de +dnssec +m |
|
3 #dig TLSA _25._tcp.hh.schlittermann.de |
|
4 # http://search.cpan.org/~nierlein/Monitoring-Plugin-0.39/lib/Monitoring/Plugin.pm |
|
5 # http://perldoc.perl.org/File/Basename.html |
|
6 # needs debian packet: libmonitoring-plugin-perl |
|
7 #TLSA Record generieren |
|
8 # openssl x509 -in <servername>.crt -outform DER | openssl sha256 |
|
9 # neben sha256 gibt's noch sha1 sha224 sha256 sha384 sha512 |
|
10 # sowie md2 md5 rmd160 (wobei ich diese nicht in betracht ziehe) |
|
11 # ssl certifikat von einem remote server anfordern |
|
12 # openssl s_client -showcerts -connect ssl.schlittermann.de:443 < /dev/null |
|
13 # https://github.com/monitoring-plugins |
|
14 # https://github.com/monitoring-plugins/monitoring-plugin-perl/blob/master/t/check_stuff.pl |
|
15 |
|
16 #openssl s_client -starttls smtp -connect ssl.schlittermann.de:25 | openssl x509 -pubkey | openssl rsa -pubin -inform PEM -outform DER | openssl sha256 |
|
17 #openssl s_client -starttls smtp -connect ssl.schlittermann.de:25 | openssl x509 -outform DER | openssl sha256 |
|
18 |
|
19 use strict; |
|
20 use warnings; |
|
21 use 5.010; |
|
22 use Monitoring::Plugin; |
|
23 use File::Basename; |
|
24 |
|
25 #devel |
|
26 use Data::Dumper; |
|
27 |
|
28 use constant LF => "\n"; |
|
29 |
|
30 my $VERSION = '0.1'; |
|
31 my $blurb = 'This Plugin is intendet to check TLSA Record'; |
|
32 my $url = 'https://schlittermann.de'; |
|
33 my $author = 'Heike Yvonne Pesch'; |
|
34 my $email = '<pesch@schlittermann.de>'; |
|
35 my $extra = LF.'Author: '.$author.' '.$email.LF |
|
36 . 'For more information visit '.$url; |
|
37 my $license = 'GPLv3'; |
|
38 my $usage = 'Usage: %s [ -v|--verbose ] [-H <host>] [-t <timeout>] ' |
|
39 . '[ -c|--critical=<critical threshold> ] ' |
|
40 . '[ -w|--warning=<warning threshold> ] ' |
|
41 . '[ -p|--port=<portnumber> ] ' |
|
42 . '[ -q|--queryserver=<DNS-Server-IP> ] '; |
|
43 |
|
44 my $check_tlsa = Monitoring::Plugin->new( |
|
45 usage => $usage, |
|
46 version => $VERSION, |
|
47 blurb => $blurb, |
|
48 extra => $extra, |
|
49 url => $url, |
|
50 license => $license, |
|
51 plugin => basename $0, |
|
52 timeout => 60, |
|
53 ); |
|
54 |
|
55 $check_tlsa->add_arg( |
|
56 spec => 'host|H=s', |
|
57 help => q|Host/Domain to check|, |
|
58 required => 0, |
|
59 ); |
|
60 |
|
61 $check_tlsa->add_arg( |
|
62 spec => 'hostlist|f=s', |
|
63 help => q|Host/Domainlist in file to check|, |
|
64 required => 0, |
|
65 ); |
|
66 |
|
67 $check_tlsa->add_arg( |
|
68 spec => 'expiry|e', |
|
69 help => q|check expiry of Certificate|, |
|
70 required => 0, |
|
71 ); |
|
72 |
|
73 $check_tlsa->add_arg( |
|
74 spec => 'port|p=i', |
|
75 help => q|Port of Domain to check the TLSA (default: 443)|, |
|
76 required => 0, |
|
77 default => 443, |
|
78 ); |
|
79 |
|
80 $check_tlsa->add_arg( |
|
81 spec => 'queryserver|q=s', |
|
82 help => q|DNS Server to ask to check the TLSA (default: defined in resolve.conf)|, |
|
83 required => 0, |
|
84 #default => '8.8.8.8', |
|
85 ); |
|
86 |
|
87 $check_tlsa->add_arg( |
|
88 spec => 'protocol|P=s', |
|
89 help => q|DNS Server to ask to check the TLSA (default: tcp)|, |
|
90 required => 0, |
|
91 default => 'tcp', |
|
92 ); |
|
93 |
|
94 $check_tlsa->getopts; |
|
95 |
|
96 my $domain = $check_tlsa->opts->host; |
|
97 my $domainlist = $check_tlsa->opts->hostlist; |
|
98 my $expiry = $check_tlsa->opts->expiry; |
|
99 |
|
100 if (!$domain && !$domainlist) { |
|
101 my $script = basename $0; |
|
102 my $excuse = "Please set -H <domain> or -f <domainlist>\n" |
|
103 . "For all options try $script --help"; |
|
104 |
|
105 print $excuse,LF; |
|
106 exit 1; |
|
107 } |
|
108 |
|
109 |
|
110 my $port; |
|
111 my $cert; |
|
112 my $check_date; |
|
113 |
|
114 if ( defined $domainlist && -e $domainlist){ |
|
115 print get_domains(); |
|
116 } |
|
117 else { print check_tlsa(); } |
|
118 |
|
119 sub check_tlsa { |
|
120 my $protocol = $check_tlsa->opts->protocol; |
|
121 |
|
122 $port = $check_tlsa->opts->port unless $port ; |
|
123 |
|
124 if ("$port" eq '25') { |
|
125 $cert = "openssl s_client -starttls smtp -connect $domain:$port " |
|
126 . '< /dev/null 2>/dev/null'; |
|
127 } |
|
128 else { |
|
129 #$port = $check_tlsa->opts->port; |
|
130 $cert = "openssl s_client -connect $domain:$port " |
|
131 . '< /dev/null 2>/dev/null'; |
|
132 } |
|
133 |
|
134 my $digquery = "dig TLSA _$port._$protocol.$domain +short"; |
|
135 my $diganswer = qx($digquery); |
|
136 my $dig = substr($diganswer, 6, ); |
|
137 $dig =~ s/(\S*)\s+(\S*)$/$1$2/; |
|
138 my $tlsa_usage = substr($diganswer, 0, 1); |
|
139 my $tlsa_selector = substr($diganswer, 2, 1); |
|
140 my $tlsa_match_type = substr($diganswer, 4, 1); |
|
141 my $hashit; |
|
142 |
|
143 given ($tlsa_match_type) { |
|
144 when('0') { die 'certs will be compared directly'} |
|
145 when('1') {$hashit = 'sha256'} |
|
146 when('2') {$hashit = 'sha512'} |
|
147 default {$hashit = 'sha256'} |
|
148 }; |
|
149 |
|
150 my $gentlsa = 'openssl x509 -pubkey | ' |
|
151 . 'openssl rsa -pubin -inform PEM -outform DER 2>/dev/null| ' |
|
152 . "openssl $hashit"; |
|
153 my $certtlsa = "$cert | $gentlsa"; |
|
154 |
|
155 $check_date = 'openssl x509 -noout -startdate -enddate'; |
|
156 $check_date = "$cert|$check_date"; |
|
157 |
|
158 |
|
159 my $return; |
|
160 |
|
161 my $tlsa_record = qx($certtlsa) or die "nothing found!\n"; |
|
162 $tlsa_record =~ s/^.*= (.*$)/$1/gi; |
|
163 $tlsa_record = uc($tlsa_record); |
|
164 |
|
165 if (defined $expiry) { |
|
166 print check_cert_expiry(); |
|
167 } |
|
168 |
|
169 if ("$tlsa_record" eq "$dig") { |
|
170 #$return = "TLSA record is $tlsa_record and valid"; |
|
171 #funktioniert nich nicht optimal mit hostliste |
|
172 $return = $check_tlsa->plugin_exit(OK, "$domain: TLSA record is valid") |
|
173 . "$domain: TLSA record is valid\n"; |
|
174 } |
|
175 else { |
|
176 $check_tlsa->plugin_exit(CRITICAL, "$domain: TLSA record NOT valid"); |
|
177 } |
|
178 return $return; |
|
179 #return $cert; |
|
180 } |
|
181 |
|
182 |
|
183 |
|
184 sub get_domains { |
|
185 open(my $filehandle, '<', $domainlist); |
|
186 |
|
187 my $pattern = '^(?<domain>\S*\.[a-z]{2,4}?):{0,1}(?<port>[0-9]*$)'; |
|
188 my %domain2check; |
|
189 while(<$filehandle>) { |
|
190 if (/$pattern/ig) { |
|
191 $domain = $+{domain}; |
|
192 $port = $+{port}; |
|
193 #print "nunu,file ok",LF,"port: $+{port}",LF,"domain: $+{domain}",LF; |
|
194 $domain2check{$domain} = $port; |
|
195 |
|
196 |
|
197 |
|
198 |
|
199 |
|
200 #print check_tlsa(); |
|
201 } |
|
202 else { |
|
203 die "wrong content"; |
|
204 } |
|
205 |
|
206 foreach my $key (%domain2check) |
|
207 { |
|
208 $domain = $key; |
|
209 $port = $domain2check{$key}; |
|
210 print $domain, ' ', $port,"\n"; |
|
211 |
|
212 |
|
213 if ( "$port" =~ /^\s*$/) { $port = '443'; } |
|
214 print $domain, ' ', $port,"\n"; |
|
215 |
|
216 check_tlsa($domain,$port); |
|
217 } |
|
218 |
|
219 } |
|
220 } |
|
221 |
|
222 sub check_cert_expiry { |
|
223 my $return = qx($check_date); |
|
224 return $return; |
|
225 } |
|
226 |