我运行 BIND9 DNS 服务器并允许我的客户使用 TSIG 密钥进行动态 DNS 更新。
我的一位客户只使用 Windows 环境,因此使用 PowerShell 来运行脚本。他想使用 PowerShell 向我的服务器发送动态更新。
从 Linux shell 执行测试很容易:使用 nsupdate。
从:https://www.freeipa.org/page/Howto/DNS_updates_and_zone_transfers_with_TSIG
客户
对于 bind-utils 包中的 nsupdate,您必须使用选项 -y algorithm:keyname:keyvalue 或 -k keyfilename 选项。例如
$ nsupdate -y hmac-sha512:keyname:keyvalue
或者
$ nsupdate -k Kkeyname.+165+0316.private
然后进行更新:
从https://linux.die.net/man/8/nsupdate:
# nsupdate > update delete oldhost.example.com A > update add newhost.example.com 86400 A 172.16.1.1 > send
从 Powershell 进行更新没有TSIG ... 有点简单... 我认为?:使用 cmdlet(例如)添加DnsServerResourceRecordA
Add-DnsServerResourceRecordA -Name "host23" -ZoneName "contoso.com" - AllowUpdateAny -IPv4Address "172.18.99.23" -TimeToLive 01:00:00
在仔细查看文档后,我没有看到任何关于交易签名或以某种方式使用 TSIG 密钥的引用。
如何使用 TISG 密钥从 Powershell 向 BIND9 服务器发送动态更新?
很难找到一个例子。我能找到的大多数例子都是使用 PowerShell 通过 API 发送更新,然后(可能)在黑匣子内进行某种部署或动态更新。我只想构建一个 DDNS 更新并使用 PowerShell 发送它。
答案1
他们必须从 BIND 下载 nsupdate(https://www.isc.org/downloads/)。可以从 PowerShell 主机调用 nsupdate。
答案2
如果提供了 tsig 文件,则此脚本将创建并提交 DDNS 请求。确保设置 NTFS 权限以防止未经授权的用户(包括其他管理员)访问此文件。
这确实假设您已经在 C:\windows\system32 中安装了 nsupdate.exe 和相关的 dll,但可以修改为其他路径。
我欢迎任何拉取请求。 https://github.com/ACiDGRiM/UsefulScripts/blob/master/Update-DNS.ps1
Param (
[String]$KeyPath = "C:\Windows\System32\drivers\etc\windows-update-client.txt",
[String]$NSScriptPath = "$env:Temp\nsupdate.txt",
[String]$NSUpdatePath = "$env:SystemRoot\System32"
)
begin {
#Gather status of system IP Addresses, DNS Servers, and domains
$IPAddresses = Get-NetIPAddress | Where-Object -FilterScript { ($_.InterfaceAlias -like "Ethernet*" -or $_.InterfaceAlias -like "Wi-Fi*") -and $_.IPAddress -notlike "fe*"}
$DNSServers = Get-DnsClientServerAddress | Where-Object -FilterScript { $_.InterfaceAlias -like "Ethernet*" -or $_.InterfaceAlias -like "Wi-Fi*"}
$DNSClient = Get-DnsClient | Where-Object -FilterScript { $_.InterfaceAlias -like "Ethernet*" -or $_.InterfaceAlias -like "Wi-Fi*"}
}
process {
[array]$RequestOutput = @()
#Parse network status into simplified objects
foreach ( $if in $IPAddresses ) {
$requesthash = @{
IPAddress = @{Address = $if.IPAddress;AddressFamily = $if.AddressFamily}
Zone = $DNSClient | Where-Object -FilterScript { $_.InterfaceAlias -eq $if.InterfaceAlias } | Select-Object -ExpandProperty "ConnectionSpecificSuffix" -First 1
Servers = $DnsServers | Where-Object -FilterScript { $_.InterfaceAlias -eq $if.InterfaceAlias } | Select-Object -ExpandProperty "ServerAddresses"
}
$RequestObj = New-Object -TypeName psobject -Property $requesthash
$RequestOutput += $RequestObj
}
#Condense zones from multiple interfaces
[array]$UniqueZones = ($RequestOutput.Zone|Sort-Object -Unique)
#Combine IPv6 and IPv4 addresses into a single object property for each zone
[array]$CombinedOutput = @()
for ($i=0;$i -lt $UniqueZones.count;$i++) {
$Combinedhash = @{
Addresses = $RequestOutput | Where-Object -FilterScript {$_.Zone -eq $UniqueZones[$i]} | Select-Object -ExpandProperty "IPAddress"
Servers = $RequestOutput | Where-Object -FilterScript {$_.Zone -eq $UniqueZones[$i]} | Select-Object -ExpandProperty "Servers" | Sort-Object -Unique
Zone = $UniqueZones[$i]
}
$CombinedObj = New-Object -TypeName psobject -Property $Combinedhash
$CombinedOutput += $CombinedObj
}
foreach ( $o in $CombinedOutput ) {
foreach ( $s in $o.Servers ) {
$CurrentRecords = Resolve-DnsName $env:COMPUTERNAME`.$($o.Zone) -Server $s -Type "A_AAAA" -DnsOnly -DnssecOK -QuickTimeout -ErrorAction "SilentlyContinue" | Select-Object -ExpandProperty "IPAddress" -ErrorAction "SilentlyContinue"
if ( $CurrentRecords ) {
$CurrentState = Compare-Object $IPAddresses.IPAddress $CurrentRecords -ErrorAction "SilentlyContinue"
} else {
$CurrentState = $true
}
if ( $CurrentState ) {
$script += "server $s
"
foreach ( $a in $o.Addresses ) {
if ( $a.AddressFamily -eq "IPv4" ) {
$PTR = $a.Address -replace '^(\d+)\.(\d+)\.\d+\.(\d+)$','$3.$2.$1.in-addr.arpa.'
} else {
$PTR = (([char[]][BitConverter]::ToString(([IPAddress]$a.Address).GetAddressBytes())-ne'-')[31..0]-join".")+'.ip6.arpa.'
}
$script += "update delete $env:COMPUTERNAME.$($o.Zone). $(if($a.AddressFamily -eq "IPv4"){"A"}else{"AAAA"})
update add $env:COMPUTERNAME.$($o.Zone). 60 $(if($a.AddressFamily -eq "IPv4"){"A"}else{"AAAA"}) $($a.Address)
update delete $PTR PTR
update add $PTR 60 PTR $env:COMPUTERNAME.$($o.Zone).
"
}
}
}
}
}
end {
$script | Out-File -FilePath $NSScriptPath -Encoding "ascii" -Force
Start-Process -FilePath (Join-Path -Path $NSUpdatePath -ChildPath "nsupdate.exe") -ArgumentList "-d -k `"$KeyPath`" `"$NSScriptPath`"" -Wait -NoNewWindow -RedirectStandardError "$env:TEMP\nsstderr" -RedirectStandardOutput "$env:TEMP\nsstdout" -WorkingDirectory $NSUpdatePath | Out-Null
}
答案3
对于那些没有静态 IP 地址且需要动态更新 DNS 区域和反向 DNS PTR 记录的用户的解决方案
$Server = "your server"; $Hostname = "mail"; $Zonename = "your zone";
$MZone = $Hostname + "." + $Zonename
<# No need to edit below unless you have to change some internal component #>
$oldobj = get-dnsserverresourcerecord -ComputerName $Server -name $Hostname -zonename $zonename -rrtype "A"
$newobj = get-dnsserverresourcerecord -ComputerName $Server -name $Hostname -zonename $zonename -rrtype "A"
$ip = (Invoke-WebRequest ifconfig.me/ip).Content.Trim()
$oip = $oldobj.recorddata.Ipv4address.IpAddressToString
$oipSplit = $oip.Split("."); $oipr = $oipSplit[2] + "." + $oipSplit[1] + "." + $oipSplit[0] + ".in-addr.arpa"
$ipSplit = $ip.Split("."); $ipr = $ipSplit[2] + "." + $ipSplit[1] + "." + $ipSplit[0] + ".in-addr.arpa"
$newobj.recorddata.ipv4address=[System.Net.IPAddress]::parse($ip)
if ($oip -ne $ip) {
Set-dnsserverresourcerecord -ComputerName $Server -newinputobject $newobj -oldinputobject $oldobj -zonename $zonename -passthru
echo "updated A record"
}
$oiprZ = Resolve-DnsName -Name $oipr -Server $Server; $oiprR = 0;
if ($oiprZ.count -gt 0) {
$oiprR = get-dnsserverresourcerecord -ComputerName $Server -ZoneName $oipr -rrtype "PTR" -Name $oipSplit[3] | Select-Object HostName, @{Name='RecordData';Expression={$MZone}}
if ($oiprR -ne 0 -And $oiprR -ne $null -and -not ($oiprR[0].HostName -eq $ipSplit[3] -and $oiprR[0].RecordData -eq $MZone -and $oipr -eq $ipr ) ){
Remove-DnsServerResourceRecord -ComputerName $Server -ZoneName $oipr -rrtype "PTR" -Name $oipSplit[3] -RecordData $MZone -Force
echo "removing existing ptr record"
echo $oiprR
echo "removed existing ptr record"
}
$oiprR =get-dnsserverresourcerecord -ComputerName $Server -ZoneName $oipr -rrtype "PTR"
if (((($oiprR) -eq $null) -or (($oiprR).Count -eq 0)) -And $oipr -ne $ipr ) {
Remove-DnsServerZone -ComputerName $Server $oipr -PassThru -Verbose -Force
echo "Removing RDNS Zone"
echo $oiprZ
echo "Removing RDNS Zone"
}
}
$ipNID = $ipSplit[0] + "." + $ipSplit[1] + "." + $ipSplit[2] + ".0/24"
$iprZ = Resolve-DnsName -Name $ipr -Server $Server; $iprR = 0;
if ($iprZ.count -gt 0) {
$iprR = get-dnsserverresourcerecord -ComputerName $Server -ZoneName $ipr -rrtype "PTR" -Name $ipSplit[3] | Select-Object HostName, @{Name='RecordData';Expression={$MZone}}
if ($iprR -eq $null ){
Add-DnsServerResourceRecordPtr -ComputerName $Server -Name $ipSplit[3] -ZoneName $ipr -AllowUpdateAny -TimeToLive 01:00:00 -AgeRecord -PtrDomainName $MZone
echo "adding ptr record"
echo $iprR
echo "added ptr record"
}
else
{
}
}
if ($iprZ.count -eq 0) {
Add-DnsServerPrimaryZone -ComputerName $Server -DynamicUpdate Secure -NetworkId $ipNID -ReplicationScope Domain
Add-DnsServerResourceRecordPtr -ComputerName $Server -Name $ipSplit[3] -ZoneName $ipr -AllowUpdateAny -TimeToLive 01:00:00 -AgeRecord -PtrDomainName $MZone
}