PwSh.Fw.Network.DHCPv4.psm1
<#
.SYNOPSIS Module to handle DHCP requests .DESCRIPTION Module to handle DHCP packets .NOTES #> # DHCP Packet Format (RFC 2131 - http://www.ietf.org/rfc/rfc2131.txt): # 0 1 2 3 # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | op (1) | htype (1) | hlen (1) | hops (1) | # +---------------+---------------+---------------+---------------+ # | xid (4) | # +-------------------------------+-------------------------------+ # | secs (2) | flags (2) | # +-------------------------------+-------------------------------+ # | ciaddr (4) | # +---------------------------------------------------------------+ # | yiaddr (4) | # +---------------------------------------------------------------+ # | siaddr (4) | # +---------------------------------------------------------------+ # | giaddr (4) | # +---------------------------------------------------------------+ # | | # | chaddr (16) | # | | # | | # +---------------------------------------------------------------+ # | | # | sname (64) | # +---------------------------------------------------------------+ # | | # | file (128) | # +---------------------------------------------------------------+ # | | # | options (variable) | # +---------------------------------------------------------------+ $Script:socketIn = $null $Script:socketOut = $null <# .SYNOPSIS Convert bytes to a human-readable string .DESCRIPTION Convert an array of bytes to a human-readable string. .PARAMETER bytes Array of bytes .EXAMPLE $a = new-object system.text.asciiEncoding $bytes = $a.GetBytes("This is a string") Convert-BytesToString -bytes $bytes Should return "This is a string" .NOTES General notes #> function Convert-BytesToString { [CmdletBinding()] [OutputType([String])] Param ( [Parameter(Mandatory = $true, ValueFromPipeLine = $true)][byte[]]$bytes ) Begin { Write-EnterFunction $char = @() } Process { $char += -join ($bytes | ForEach-Object { [char]$_ }) } End { return -join $char Write-LeaveFunction } } <# .SYNOPSIS Convert bytes to an hexadecimal string .DESCRIPTION Convert an array of bytes to an hexadecimal string. .PARAMETER bytes Array of bytes .EXAMPLE $a = new-object system.text.asciiEncoding $bytes = $a.GetBytes("This is a string") Convert-BytesToHex -bytes $bytes Should return "This is a string" .NOTES General notes #> Function Convert-BytesToHex { [CmdletBinding()] [OutputType([String])] param( [parameter(Mandatory = $true, ValueFromPipeLine = $true)][Byte[]]$Bytes ) Begin { Write-EnterFunction $char = @() } Process { $HexString = [System.Text.StringBuilder]::new($Bytes.Length * 2) ForEach($byte in $Bytes){ $HexString.AppendFormat("{0:x2}", $byte) | Out-Null } $char += $HexString.ToString() } End { return -join $char Write-LeaveFunction } } <# .SYNOPSIS Convert bytes to int .DESCRIPTION Convert an array of bytes to an int .PARAMETER bytes Array of bytes .EXAMPLE [byte]$byte = "0xFF" Convert-BytesToHex -bytes $byte Should be 255 .NOTES General notes #> function Convert-BytesToInt { [CmdletBinding()] [OutputType([int])] Param ( [Parameter(Mandatory = $true, ValueFromPipeLine = $true)][byte[]]$bytes ) Begin { Write-EnterFunction $b = @() } Process { $b += $bytes } End { return [int]"0x$(Convert-BytesToHex -Bytes $b)" Write-LeaveFunction } } <# .SYNOPSIS Short description .DESCRIPTION Long description .PARAMETER string Parameter description .EXAMPLE An example .NOTES General notes #> function Send-DHCPv4Packet { [CmdletBinding()]Param ( [Parameter(Mandatory = $true, ValueFromPipeLine = $true)][DHCPv4Packet]$Packet, [Alias('Destination')] [Parameter(Mandatory = $false, ValueFromPipeLine = $false)][ipAddress]$SendTo =[net.ipAddress]::Broadcast, [Parameter(Mandatory = $false, ValueFromPipeLine = $false)][uint16]$port = 67 ) Begin { Write-EnterFunction } Process { $bytesSent = 0 $bytes = $Packet.ToBytes() $client = new-object net.sockets.udpClient $client.Connect($SendTo, $port) try { # $bytesSent = $client.send($bytes, $bytes.length, $ip, 67) $bytesSent = $client.send($bytes, $bytes.length) } catch { Write-Error "$_" } finally { $client.close() } Write-Debug "$bytesSent bytes sent." } End { Write-LeaveFunction } } function Receive-DHCPv4Packet { [CmdletBinding()] [OutputType([DHCPv4Packet])] Param ( [Parameter(Mandatory = $false, ValueFromPipeLine = $false)][string]$xid, [Alias('ipAddress')] [Parameter(Mandatory = $false, ValueFromPipeLine = $false)][ipAddress]$RecvFrom = [net.ipAddress]::any, [Parameter(Mandatory = $false, ValueFromPipeLine = $false)][uint16]$port = 67, [uint16]$timeout = 1000, [uint16]$retries = 10 ) Begin { Write-EnterFunction } Process { # $packet = [DHCPv4Packet]::New() # $packet.Receive($ipaddress, $xid) $client = new-object net.sockets.udpClient($port) # $client = new-object net.sockets.udpclient # $client.Connect($RecvFrom, $port) $client.Client.ReceiveTimeout = $timeout $ipEP = new-object net.ipendpoint($RecvFrom, $port) try { $i = 0 while ($true) { try { [byte[]]$bytesReceived = $client.receive([ref]$ipEP) Write-Debug "$($bytesReceived.count) bytes received." # [DHCPv4Packet]$response = [DHCPv4Packet]::New($bytesReceived) $Rxid = ($bytesReceived[4..7] | Convert-BytesToHex) $Rchaddr = $bytesReceived[28..33].ForEach('ToString', 'x2') -join ":" Write-Devel "${i}: $Rxid : $($Rchaddr) from $($ipEP.Address.ToString()):$($ipEP.Port.ToString())" } catch { Write-Devel "$_, retrying" } finally { $i++ } if ($i -gt $retries) { break } } } catch { Write-Error "$_" } finally { $client.close() } return $receive } End { Write-LeaveFunction } } |