X-Git-Url: https://git.distorted.org.uk/~mdw/zoneconf/blobdiff_plain/39bfd16a1962870e56dd5cdbbcfab243cdcb1761..HEAD:/zoneconf.in diff --git a/zoneconf.in b/zoneconf.in index 224710f..541c019 100755 --- a/zoneconf.in +++ b/zoneconf.in @@ -198,6 +198,13 @@ proc run {what command args} { } } +proc isolate {body} { + ## Evaluate BODY without changing the caller's variables. Return its + ## result. + + eval $body +} + ###-------------------------------------------------------------------------- ### Configuration spaces. ### @@ -942,12 +949,21 @@ proc host-canonify {host} { proc local-address-p {addr} { ## Answer whether the ADDR is one of the host's addresses. + global env - if {[catch { set sk [socket -server {} -myaddr $addr 0] }]} { - return false + if {[info exists env(ZONECONF_LOCAL_ADDRESSES)]} { + if {[string match "*:$addr:*" ":$env(ZONECONF_LOCAL_ADDRESSES):"]} { + return true + } else { + return false + } } else { - close $sk - return true + if {[catch { set sk [socket -server {} -myaddr $addr 0] }]} { + return false + } else { + close $sk + return true + } } } @@ -992,15 +1008,15 @@ define-configuration-space zone ZONECFG { define-simple dir-mode 2775 define-simple zone-file "%v/%z.zone" define-simple soa-format increment + define-simple allow-query nil define-list views * define-list sign-views {} define-list signzone-command \ [list "$BINDPROGS/dnssec-signzone" \ - "-g" \ "-S" \ "-K%h/key" \ "-d%h/ds" \ - "-s-3600" "-e+176400" \ + "-s-3600" "-e+176400" "-i90000" \ "-N%q" \ "-o%z" \ "-f%o" \ @@ -1016,12 +1032,19 @@ define-configuration-space zone ZONECFG { "-Sfail" \ "-Wfail" \ "%z" "%f"] + define-list also-notify nil define setvar {name value} { dict set ZONECFG(var) $name $value } define primary {map} { + ## There's a grim hack here: a primary-address entry may have the form + ## REAL!FAKE. If the REAL address is not a local address then this + ## is used as the master address; otherwise the FAKE address is used. + ## This is useful for inter-view updates of dynamic zones on the same + ## host. I suggest abusing 127.0.0.0/8 addresses for this kind of + ## chicanery. if {[llength $map] % 2} { error "master map must have an even number of items" } @@ -1113,6 +1136,16 @@ proc output-file-name {view} { return [string map [list %v $view] $ZONECFG(conf-file)] } +proc temporary-directory {} { + ## Create a temporary directory and set as the working directory. + + global ZONECFG + set tmp [file join $ZONECFG(home-dir) "tmp"] + file mkdir $tmp + cd $tmp + return $tmp +} + proc compute-zone-properties {view config} { ## Derive interesting information from the zone configuration plist CONFIG, ## relative to the stated server VIEW. Return a new plist. @@ -1141,13 +1174,28 @@ proc compute-zone-properties {view config} { if {[info exists zone(mapped-view)]} { foreach {outview hosts} $zone(master-map) { if {[string match $outview $zone(mapped-view)]} { - set zone(masters) $hosts + set masters {} set zone(config-type) slave foreach host $hosts { - if {[local-address-p $host]} { + set bang [string first "!" $host] + if {$bang >= 0} { + set after [string range $host [expr {$bang + 1}] end] + if {$bang} { + set before [string range $host 0 [expr {$bang - 1}]] + } else { + set before $after + } + if {[local-address-p $before]} { + set host $after + } else { + set host $before + } + } elseif {[local-address-p $host]} { set zone(config-type) master } + lappend masters $host } + set zone(masters) $masters break } } @@ -1223,7 +1271,7 @@ proc sign-zone-file {info soafmt infile} { array set zone $info set outfile "$zone(server-file-name).new" - if {![run "zone `$zone(name)' in view `$zone(mapped-view)'" \ + if {![run "sign zone `$zone(name)' in view `$zone(mapped-view)'" \ $zone(signzone-command) \ "%h" $zone(home-dir) \ "%m" $zone(static-dir) \ @@ -1259,6 +1307,9 @@ proc write-zone-stanza {view chan config} { master { puts $chan "\ttype master;" puts $chan "\tfile \"$zone(server-file-name)\";" + if {![string equal $zone(also-notify) "nil"]} { + puts $chan "\talso-notify { [join $zone(also-notify) {; }]; };" + } switch -exact -- $zone(type) { dynamic { write-ddns-update-policy "\t" $chan $config @@ -1279,6 +1330,9 @@ proc write-zone-stanza {view chan config} { } } } + if {![string equal $zone(allow-query) nil]} { + puts $chan "\tallow-query {$zone(allow-query)};" + } puts $chan "};"; } @@ -1292,7 +1346,7 @@ defcmd outputs {} { } { global ZONECFG CONFFILE - confspc-eval toplevel [list source $CONFFILE] + isolate [list confspc-eval toplevel [list source $CONFFILE]] foreach view $ZONECFG(all-views) { puts [output-file-name $view] } } @@ -1302,7 +1356,7 @@ defcmd update {} { global ZONECFG ZONES CONFFILE ## Read the configuration. - confspc-eval toplevel [list source $CONFFILE] + isolate [list confspc-eval toplevel [list source $CONFFILE]] ## Safely update the files. set win false @@ -1351,16 +1405,16 @@ defcmd update {} { defcmd install {user view name} { help-text "Install a new zone file. - The file is for the given zone NAME and \(user-side) VIEW. The file is - provided by the named USER" +The file is for the given zone NAME and \(user-side) VIEW. The file is +provided by the named USER." } { global QUIS ZONECFG ZONES CONFFILE errorInfo errorCode ## Read the configuration. - confspc-eval toplevel [list source $CONFFILE] + isolate [list confspc-eval toplevel [list source $CONFFILE]] ## Make sure there's a temporary directory. - file mkdir [file join $ZONECFG(home-dir) "tmp"] + set tmpdir [temporary-directory] ## Keep track of cleanup jobs. set cleanup {} @@ -1391,8 +1445,7 @@ defcmd install {user view name} { ## Make a new temporary file to read the zone into. set pid [pid] for {set i 0} {$i < 1000} {incr i} { - set tmp [file join $ZONECFG(home-dir) "tmp" \ - "tmp.$pid.$i.$user.$name"] + set tmp [file join $tmpdir "tmp.$pid.$i.$user.$name"] if {![catch { set chan [open $tmp {WRONLY CREAT EXCL}] } msg]} { break } elseif {[string equal [lindex $errorCode 0] POSIX] && \ @@ -1456,7 +1509,11 @@ defcmd sign {} { set rc 0 ## Read the configuration. - confspc-eval toplevel [list source $CONFFILE] + isolate [list confspc-eval toplevel [list source $CONFFILE]] + + ## Sometimes `dnssec-signzone' tries to write temporary files to the + ## current directory. Make sure this is sensible. + temporary-directory ## Grind through all of the zones. array unset seen