Created
May 8, 2021 18:40
-
-
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).
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<# | |
.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