@@ -639,23 +639,32 @@ into input for the nsupdate(1) dynamic DNS update utility.
639639
640640REQUIREMENTS
641641
642+ Danectl is written in Bourne shell, and should work on any platform
643+ that has the following prerequisites.
644+
642645In all cases, danectl requires /bin/sh and host (or drill).
643646
647+ On systems like Solaris, /usr/xpg4/bin/sh is used instead of /bin/sh.
648+
644649For TLSA usage, danectl also requires ls, sed, grep, readlink, certbot,
645650openssl, sha256sum, and root privileges (for certbot).
646651
647- For SSHFP usage, danectl also requires sed and ssh-keygen.
652+ For SSHFP usage, danectl also requires sed, perl and ssh-keygen.
648653
649654For OPENPGPKEY usage, danectl also requires perl and gpg.
650655
651656For SMIMEA usage, danectl also requires perl and openssl.
652657
653- On systems like Solaris, /usr/xpg4/bin/sh is used instead of /bin/sh .
658+ For non-ASCII domain names, danectl also requires GNU idn2 .
654659
655660The danectl-zonefile output adapter requires perl.
656661
657662The danectl-nsupdate output adapter requires perl.
658663
664+ For reloading affected services on key rollover, any system with
665+ systemctl, service, rcctl, or service scripts in
666+ /etc/init.d, /etc/rc.d, or /usr/local/etc/rc.d should work.
667+
659668LICENSE
660669
661670Danectl is released under the terms of the GPLv2+
@@ -742,7 +751,7 @@ default_certbot_command()
742751fetch_dns ()
743752{
744753 dns_type=" $1 "
745- dns_name=" $2 "
754+ dns_name=" ` idna $2 ` "
746755
747756 if [ $HAVE_HOST = 1 ]
748757 then
@@ -834,7 +843,7 @@ tlsa_role()
834843 for t in $tlsa
835844 do
836845 domain=" ` case \" $t \" in * .) echo $t ;; * ) echo $t .$certname .;; esac` "
837- printf " $prefix$domain \tIN\tTLSA\t3 1 1 $hash \n"
846+ printf " $prefix ` idna $domain ` \tIN\tTLSA\t3 1 1 $hash \n"
838847 done
839848}
840849
@@ -877,7 +886,7 @@ tlsa_check()
877886 else
878887 [ " $missing " = 0 ] && echo " ; Missing $certname current (must be published)"
879888 missing=1
880- printf " $domain \tIN\tTLSA\t3 1 1 $hash_current \n"
889+ printf " ` idna $domain ` \tIN\tTLSA\t3 1 1 $hash_current \n"
881890 fi
882891 done
883892 missing=0
@@ -890,7 +899,7 @@ tlsa_check()
890899 else
891900 [ " $missing " = 0 ] && echo " ; Missing $certname next (must be published)"
892901 missing=1
893- printf " $domain \tIN\tTLSA\t3 1 1 $hash_next \n"
902+ printf " ` idna $domain ` \tIN\tTLSA\t3 1 1 $hash_next \n"
894903 fi
895904 done
896905 superfluous=0
@@ -1128,12 +1137,26 @@ remove_item()
11281137 sed ' s/ /\n/g' | grep -v " $item "
11291138}
11301139
1140+ # Output the ASCII version (IDNA2008/TR46) of a Unicode domain name
1141+
1142+ idna ()
1143+ {
1144+ domainname=" $1 "
1145+ if echo " $domainname " | LANG=C grep -q ' ^[a-zA-Z0-9-][a-zA-Z0-9.-]*$'
1146+ then
1147+ echo $domainname
1148+ else
1149+ case " ` which idn2 2> /dev/null` " in /* ) ;; * ) die " Failed to find idn2" ;; esac
1150+ idn2 -l -- " $domainname "
1151+ fi
1152+ }
1153+
11311154# Output a form of certname that is suitable for use in a shell variable identifier
11321155
11331156shcertname ()
11341157{
11351158 certname=" $1 "
1136- echo " $certname " | LANG=C sed ' s/[^a-zA-Z0-9]/_/g'
1159+ idna " $certname " | LANG=C sed ' s/[^a-zA-Z0-9]/_/g'
11371160}
11381161
11391162# Check for host or drill
@@ -1237,15 +1260,15 @@ check_sshfp_prerequisites()
12371260
12381261sshfp ()
12391262{
1240- hostname=" $1 "
1263+ hostname=" ` idna $1 ` "
12411264 ssh-keygen -r " $hostname " | sed -e ' s/ /. /' -e ' s/ / /' -e ' s/ / /'
12421265}
12431266
12441267# Check that SSHFP RRs are published
12451268
12461269sshfp_check ()
12471270{
1248- hostname=" $1 "
1271+ hostname=" ` idna $1 ` "
12491272 perl -e '
12501273 use strict;
12511274 use warnings;
@@ -1299,13 +1322,20 @@ openpgpkey()
12991322 $encoded =~ s/^ // if ' $oneline ' == 1 && ' $spaces ' == 1;
13001323 return $encoded;
13011324 }
1325+ sub idna
1326+ {
1327+ my $domain = shift;
1328+ return $domain if $domain =~ /^[a-zA-Z0-9.-]+$/;
1329+ chop($domain = `idn2 -l -- $domain`);
1330+ return $domain;
1331+ }
13021332 my $origin;
13031333 my $prefix;
13041334 my $comment = "";
13051335 my $key_hex = "";
13061336 while (<>)
13071337 {
1308- $origin = $1 , next if /^\$ORIGIN (\S+)/;
1338+ $origin = idna($1) , next if /^\$ORIGIN (\S+)/;
13091339 $comment .= $_, next if /^;/;
13101340 $prefix = $1, next if /^([0-9a-f]+) TYPE61 \\# \d+ \($/;
13111341 $key_hex .= $1, next if /^\s+([0-9a-f]+)$/;
@@ -1343,13 +1373,20 @@ openpgpkey_check()
13431373 $encoded =~ s/^ // if ' $oneline ' == 1 && ' $spaces ' == 1;
13441374 return $encoded;
13451375 }
1376+ sub idna
1377+ {
1378+ my $domain = shift;
1379+ return $domain if $domain =~ /^[a-zA-Z0-9.-]+$/;
1380+ chop($domain = `idn2 -l -- $domain`);
1381+ return $domain;
1382+ }
13461383 my $origin;
13471384 my $prefix;
13481385 my $comment = "";
13491386 my $key_hex = "";
13501387 while (<>)
13511388 {
1352- $origin = $1 , next if /^\$ORIGIN (\S+)/;
1389+ $origin = idna($1) , next if /^\$ORIGIN (\S+)/;
13531390 $comment .= $_, next if /^;/;
13541391 $prefix = $1, next if /^([0-9a-f]+) TYPE61 \\# \d+ \($/;
13551392 $key_hex .= $1, next if /^\s+([0-9a-f]+)$/;
@@ -1366,7 +1403,7 @@ openpgpkey_check()
13661403 my $hash = Digest->new("SHA-256");
13671404 $hash->add($localpart);
13681405 $prefix = substr($hash->hexdigest(), 0, 28 * 2);
1369- $origin = "_openpgpkey.$domain" ;
1406+ $origin = "_openpgpkey." . idna( $domain) ;
13701407 }
13711408 # Is it published? Are any other keys published?
13721409 my $missing = $key_exists;
@@ -1426,6 +1463,13 @@ smimea()
14261463 use Digest;
14271464 binmode(STDIN);
14281465 $/ = undef;
1466+ sub idna
1467+ {
1468+ my $domain = shift;
1469+ return $domain if $domain =~ /^[a-zA-Z0-9.-]+$/;
1470+ chop($domain = `idn2 -l -- $domain`);
1471+ return $domain;
1472+ }
14291473 my $cert = unpack("H*", <STDIN>);
14301474 $cert =~ s/(.{1,56})/\t$1\n/g if ' $oneline ' == 0;
14311475 $cert =~ s/^\t// if ' $oneline ' == 0;
@@ -1437,7 +1481,7 @@ smimea()
14371481 my $hash = Digest->new("SHA-256");
14381482 $hash->add($localpart);
14391483 my $prefix = substr($hash->hexdigest(), 0, 28 * 2);
1440- my $origin = "_smimecert.$domain.";
1484+ my $origin = "_smimecert." . idna( $domain) . " .";
14411485 print("; $email\n");
14421486 my $start = (' $oneline ' == 0) ? "(\n\t" : "";
14431487 my $middle = (' $oneline ' == 0) ? "\n\t" : " ";
@@ -1468,6 +1512,13 @@ smimea_check()
14681512 use Digest;
14691513 binmode(STDIN);
14701514 $/ = undef;
1515+ sub idna
1516+ {
1517+ my $domain = shift;
1518+ return $domain if $domain =~ /^[a-zA-Z0-9.-]+$/;
1519+ chop($domain = `idn2 -l -- $domain`);
1520+ return $domain;
1521+ }
14711522 my $cert = unpack("H*", <STDIN>);
14721523 $cert =~ s/(.{1,56})/\t$1\n/g if ' $oneline ' == 0;
14731524 $cert =~ s/^\t// if ' $oneline ' == 0;
@@ -1480,7 +1531,7 @@ smimea_check()
14801531 $hash->add($localpart);
14811532 my $comment = "; $email\n";
14821533 my $prefix = substr($hash->hexdigest(), 0, 28 * 2);
1483- my $origin = "_smimecert.$domain.";
1534+ my $origin = "_smimecert." . idna( $domain) . " .";
14841535 my $missing = 1;
14851536 my $superfluous = "";
14861537 my $start = (' $oneline ' == 0) ? "(\n\t" : "";
0 commit comments