Skip to content

Commit

Permalink
Fixed RFC2136 plugin for records other than the root domain.
Browse files Browse the repository at this point in the history
  • Loading branch information
rmbolger committed May 7, 2020
1 parent 58b942c commit 4ac5acb
Show file tree
Hide file tree
Showing 2 changed files with 1 addition and 111 deletions.
4 changes: 1 addition & 3 deletions Posh-ACME/DnsPlugins/RFC2136-Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,7 @@ When using a TSIG key, you will typically have 3 values; a key name, a key type

### Plugin Dependencies

Due to the inexplicable lack of good native DNS libraries within PowerShell/.NET, this plugin relies on external executables to query DNS and send the dynamic updates. On Windows, the queries are performed using `nslookup.exe` which is installed by default on all supported Windows versions. On non-Windows, the `dig` utility is used which is also typically installed by default on most non-Windows OSes.

To send dynamic updates, the plugin uses the `nsupdate` utility which is part of the ISC BIND distribution. Most modern Linux distributions will have this installed by default, but double check to be sure. **On Windows, you will need to download and install the utility.** Go to the [ISC BIND Downloads](https://www.isc.org/download/) page and download the current stable version for Windows. You don't actually need to run the installer. It is sufficient to simply unzip the archive and either add that folder to your `PATH` environment variable or specify the full path to `nsupdate.exe` in the plugin arguments. *(Adding the folder to your PATH also gives you easy access to the `dig` utility which many DNS admins prefer over nslookup)*
Due to the inexplicable lack of good native DNS libraries within PowerShell/.NET, this plugin relies on the `nsupdate` utility which is part of the ISC BIND distribution. Most modern Linux distributions will have this installed by default, but double check to be sure. **On Windows, you will need to download and install the utility.** Go to the [ISC BIND Downloads](https://www.isc.org/download/) page and download the current stable version for Windows. You don't actually need to run the installer. It is sufficient to simply unzip the archive and either add that folder to your `PATH` environment variable or specify the full path to `nsupdate.exe` in the plugin arguments. *(Adding the folder to your PATH also gives you easy access to the `dig` utility which many DNS admins prefer over nslookup)*

## Using the Plugin

Expand Down
108 changes: 0 additions & 108 deletions Posh-ACME/DnsPlugins/RFC2136.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,6 @@ function Add-DnsTxtRFC2136 {
$DDNSKeyValueInsecure = (New-Object PSCredential "user",$DDNSKeyValue).GetNetworkCredential().Password
}

$zoneName = Find-DDNSRootDomain $RecordName $DDNSNameserver
if (-not $zoneName) {
throw "Unable to find authoritative domain for $RecordName on $DDNSNameserver"
}
Write-Verbose "Found authoritative zone $zoneName"

# The nice thing about RFC2136 is that BIND doesn't care if you send duplicate updates
# for the same record and value. So we don't need to check whether the record already
# exists or not. Even if you're removing a record that's already gone, it still works.
Expand All @@ -40,7 +34,6 @@ function Add-DnsTxtRFC2136 {
RecordName = "$RecordName."
TxtValue = $TxtValue
Action = 'add'
Zone = "$zoneName."
Nameserver = $DDNSNameserver
Port = $DDNSPort
NSUpdatePath = $DDNSExePath
Expand Down Expand Up @@ -134,12 +127,6 @@ function Remove-DnsTxtRFC2136 {
$DDNSKeyValueInsecure = (New-Object PSCredential "user",$DDNSKeyValue).GetNetworkCredential().Password
}

$zoneName = Find-DDNSRootDomain $RecordName $DDNSNameserver
if (-not $zoneName) {
throw "Unable to find authoritative domain for $RecordName on $DDNSNameserver"
}
Write-Verbose "Found authoritative zone $zoneName"

# The nice thing about RFC2136 is that BIND doesn't care if you send duplicate updates
# for the same record and value. So we don't need to check whether the record already
# exists or not. Even if you're removing a record that's already gone, it still works.
Expand All @@ -149,7 +136,6 @@ function Remove-DnsTxtRFC2136 {
RecordName = "$RecordName."
TxtValue = $TxtValue
Action = 'del'
Zone = "$zoneName."
Nameserver = $DDNSNameserver
Port = $DDNSPort
NSUpdatePath = $DDNSExePath
Expand Down Expand Up @@ -237,97 +223,6 @@ function Save-DnsTxtRFC2136 {
# Helper Functions
############################

function Find-DDNSRootDomain {
[CmdletBinding()]
param(
[Parameter(Mandatory,Position=0)]
[string]$RecordName,
[Parameter(Mandatory,Position=1)]
[string]$Nameserver
)

if (!$script:RFC2136Zones) { $script:RFC2136Zones = @{} }

if ($script:RFC2136Zones.ContainsKey($RecordName)) {
return $script:RFC2136Zones.$RecordName
}

$pieces = $RecordName.Split('.')
for ($j=1; $j -lt ($pieces.Count-1); $j++) {
$zone = "$( $pieces[$j..($pieces.Count-1)] -join '.' )"
Write-Debug "Checking if $Nameserver is authoritative for $zone"
if (Test-AuthoritativeNameserver "$zone." $Nameserver) {
$script:RFC2136Zones.$RecordName = $zone
return $zone
}
}

return $null
}

function Test-AuthoritativeNameserver {
[CmdletBinding()]
param(
[Parameter(Mandatory,Position=0)]
[string]$Zone,
[Parameter(Mandatory,Position=1)]
[string]$Nameserver
)

# For some inexplicable reason, neither .NET Framework or Core have a decent
# built-in DNS library and taking on a 3rd party library dependency for something
# this simple would be wasteful. So we need to shell out to the native nslookup or
# dig executables in order to make the non-recursive SOA query to test whether
# the specified nameserver is authoritative for the specified zone.

if ($PSEdition -eq 'Desktop' -or $IsWindows) {
# We're definitely on Windows, so we're using nslookup.
Write-Debug 'Using nslookup'

# We're going to use the full path to the Windows native nslookup.exe just in
# case the user has added all of the BIND utilities to %PATH% which includes
# its own copy of nslookup.
$exePath = Join-Path $env:SystemRoot 'System32\nslookup.exe'
$outlines = & $exePath -norecurse -type=soa $Zone $Nameserver 2>&1

# ignore non-authoritative answers
if ($true -in ($outlines | ForEach-Object { $_ -like 'Non-authoritative*' })) {
Write-Debug 'Ignoring non-authoritative answer'
return $false
}

# check for "primary name server = " to indicate a successful result
if ($true -in ($outlines | ForEach-Object { $_ -like '*primary name server = *' })) {
Write-Debug 'Found primary name server'
return $true
} else {
Write-Debug 'No primary name server in output'
return $false
}
}
else {
# Any other OS should have a native dig command
Write-Debug 'Using dig'

$outlines = & dig "@$Nameserver" $Zone soa +norecurse 2>&1

# ignore non-authoritative answers
if ($true -notin ($outlines | ForEach-Object { $_ -like ';; flags: * aa *' })) {
Write-Debug 'Ignoring non-authoritative answer'
return $false
}

# check for ANSWER SECTION
if ($true -in ($outlines | ForEach-Object { $_ -eq ';; ANSWER SECTION:' })) {
Write-Debug 'Found answer section'
return $true
} else {
Write-Debug 'No answer section in output'
return $false
}
}
}

function Send-DynamicTXTUpdate {
[CmdletBinding()]
param(
Expand All @@ -339,8 +234,6 @@ function Send-DynamicTXTUpdate {
[ValidateSet('add','del')]
[string]$Action,
[Parameter(Mandatory)]
[string]$Zone,
[Parameter(Mandatory)]
[string]$Nameserver,
[int]$Port=53,
[string]$TsigKeyName,
Expand All @@ -354,7 +247,6 @@ function Send-DynamicTXTUpdate {
$input = @(
"server $Nameserver $Port"
"key $($TsigKeyType):$TsigKeyName $TsigKeyValue"
"zone $Zone"
"update $Action $RecordName 60 TXT `"$TxtValue`""
'send'
'answer'
Expand Down

0 comments on commit 4ac5acb

Please sign in to comment.