Skip to content

Instantly share code, notes, and snippets.

@mkht
Created May 8, 2021 18:40
Show Gist options
  • Save mkht/40181063e79b39dff143369950e8bf26 to your computer and use it in GitHub Desktop.
Save mkht/40181063e79b39dff143369950e8bf26 to your computer and use it in GitHub Desktop.
Encodes a list of domain names into the format specified in Section 4.1.4 of "Domain Names - Implementation And Specification" (RFC 1035).
<#
.SYNOPSIS
Convert domain name list to byte array
.DESCRIPTION
Encodes a list of domain names into the format specified in Section 4.1.4 of "Domain Names - Implementation And Specification" (RFC 1035).
.EXAMPLE
PS C:\> Convert-DomainListToByteArray ('foo.example.com', 'example.com')
.PARAMETER DomainList
Specifies a List of domains
.INPUTS
[string[]] DomainList
.OUTPUTS
[byte[]]
.LINK
https://datatracker.ietf.org/doc/html/rfc1035#section-4.1.4
.AUTHOR
mkht
.DATE
05/09/2021
.LICENSE
MIT License
#>
function Convert-DomainListToByteArray {
[CmdletBinding()]
[OutputType([byte[]])]
param (
[Parameter(Mandatory, ValueFromPipeline, Position = 0)]
[ValidateNotNullOrEmpty()]
[string[]]$DomainList
)
Begin {
$IdnMapping = [System.Globalization.IdnMapping]::new()
$PointerHash = @{}
$Writer = [System.IO.BinaryWriter]::new([System.IO.MemoryStream]::new())
}
Process {
foreach ($Domain in $DomainList) {
while (-not [string]::IsNullOrWhiteSpace($Domain)) {
# Convert internationalized domain names to Punycode
$Domain = $IdnMapping.GetAscii($Domain.Trim("`0", '.').Trim())
# Search duplicates part of a domain name
if ($PointerHash.ContainsKey($Domain)) {
if ($PointerHash[$Domain] -ge 0 -and $PointerHash[$Domain] -le 0x3fff) {
# Compression pointer (2 bytes big endian)
$Pointer = [System.BitConverter]::GetBytes([ipaddress]::NetworkToHostOrder([Int32]((0xc0 -shl 8) + $PointerHash[$Domain])))[2..3]
$Writer.Write([byte[]]$Pointer)
break
}
}
if ($Domain.IndexOf('.') -le 0) {
# Top Level domain
$PointerHash[$Domain] = $Writer.BaseStream.Position
$TLDBytes = [System.Text.Encoding]::UTF8.GetBytes($Domain)
$Writer.Write([byte]$TLDBytes.Length)
$Writer.Write([byte[]]$TLDBytes)
# End flag
$Writer.Write([byte]0x00)
break
}
else {
# Sub Level domain
$PointerHash[$Domain] = $Writer.BaseStream.Position
$SplitDomain = $Domain.Split('.', 2, 1)
$Domain = $SplitDomain[1]
$LLD = $SplitDomain[0].Trim("`0").Trim()
$LLDBytes = [System.Text.Encoding]::UTF8.GetBytes($LLD)
$Writer.Write([byte]$LLDBytes.Length)
$Writer.Write([byte[]]$LLDBytes)
}
}
}
}
End {
$Writer.BaseStream.ToArray()
$Writer.Close()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment