Querying UDP Ports with PowerShell: Part 2

In my previous post on working with UDP ports and PowerShell I showed you how you can set up listeners on both your local and remote systems to send and receive data through those ports.  While this is a great way to have some fun and potentially test whether the ports are indeed active on a system, it wasn’t really the best way at checking whether a UDP port is available on a remote system after some further checking.

For this post, I installed the Simple TCP/IP Services which gives me the QOTD (Quote of the Day), Character Generator, Daytime and Discard services each with a specific port that is opened up. I am mostly going to focus on the Character Generator service and its associated UDP port (19) as it gives you a set of 95 printable ASCII characters if the port is open. Some great information and better explanations about this can be found here and here.

The way that these services work is that you must first send a datagram to the port and then it will respond to you with a message in return. The problem that occurs using the method that I mention in my previous article is that when you first create the object with a specified port open, in this case 19 for Character Generator, the system will never get the message from the remote host. See below for the incorrect way to create the UDP object.

$udpobject = new-Object system.Net.Sockets.Udpclient(11000)

Now this is fine if you want the port opened up to receive traffic from another source, but based on my testing does not appear to play nice if you are sending data to a port and want to automatically receive data back from the remote port. Instead, I create my object like this:

$udpobject = new-Object system.Net.Sockets.Udpclient

From there I can continue to use the same code as before to make the connection to my remote system, DC1 and the remote port for Character Generator: 19 and also set a timeout for the receiving of the remote data to 1000 milliseconds (the default is set to 0 which means that it will continue to block access to your session until data is received).

$udpobject.Connect("dc1",19)
$udpobject.Client.ReceiveTimeout = 1000

If you wanted to have more asynchronous operations without the blocking, you can change perform the following change: (More info on Blocking here)

$udpobject.Client.Blocking = $False

I won’t be changing this to True in my example as I would rather wait for the received data before proceeding or let it timeout. The next step is to setup my string and convert it into a byte format so it can be sent to the remote port in hopes of getting a response.

$a = new-object system.text.asciiencoding
$byte = $a.GetBytes("TEST")

image

Looks like bytes to me.

Now to send the datagram to the remote port and also setup the remote endpoint that the UDP object will use to listen for.

[void]$udpobject.Send($byte,$byte.length)
$remoteendpoint = New-Object system.net.ipendpoint([system.net.ipaddress]::Any,0)

Ok, so now that we have configured all of that stuff, the only thing left to do is tell the UDP object to wait until it receives the datagram from the remote host. It will do so based on the timeout property we set up on the client properties of the UDP object.

Try {
    $receivebytes = $udpobject.Receive([ref]$remoteendpoint)
} Catch {
    Write-Warning "$($Error[0])"
}

This is also where you will find out if the port is open on the remote system. If the port is not open, an error will be returned stating the an error like this:

image

You can set up some error handling to better catch this exception like I did in the code snippet above to get something like this:

image

But in my case, I know that this port is not only open, but willing to send out data on the condition that you first send data (which we did earlier). As soon as the object receives the data (or the timeout has been reached), it will stop the blocking and allow the code to continue processing the data if it has any. If there is data, we will need to translate it from bytes back to a string so we actually know what it is saying.

If ($receivebytes) {
    [string]$returndata = $a.GetString($receivebytes)
    $returndata
} Else {
    "No data received from {0} on port {1}" -f $Computername,$Port
}
$udpobject.Close()

Ok, lets see what we get from this…

image

Pretty cool, isn’t it? I was able to get the Character Generator service to respond back to me from UDP Port 19 with the data I was expecting (A lot of ASCII characters).

By the way, the Close() method is used to clean up after myself and close the connection.

Lets now check out the other ports covered by the Simple TCP/IP Services:

Daytime (Port 13)

image

Quote of the Day (Port 17)

image

Echo (Port 7)

image

As you can see, this is a pretty nice way to request information from UDP ports, but you should note that you will not always get a return message back from a UDP port, even if the port is actually open.

Test-Port Function

Being that this is a better way to test for open UDP ports, I updated my Test-Port function to reflect this change. The function is available from the following locations:

Script Repository

Poshcode

Quick demo of the updated Test-Port function

Test-Port -computer DC1 -port 7,8,13,17 -UDP -TCP

image

 

Full code available here (change to suit your needs)

$Computername = 'dc1'
$Port = 7
$udpobject = new-Object system.Net.Sockets.Udpclient
$udpobject.Connect($Computername,$Port)
$udpobject.Client.ReceiveTimeout = 1000
$a = new-object system.text.asciiencoding
$byte = $a.GetBytes("TEST")
[void]$udpobject.Send($byte,$byte.length)
$remoteendpoint = New-Object system.net.ipendpoint([system.net.ipaddress]::Any,0)
Try {
    $receivebytes = $udpobject.Receive([ref]$remoteendpoint)
} Catch {
    Write-Warning "$($Error[0])"
}
If ($receivebytes) {
    [string]$returndata = $a.GetString($receivebytes)
    $returndata
} Else {
    "No data received from {0} on port {1}" -f $Computername,$Port
}
$udpobject.Close()
This entry was posted in powershell, scripts and tagged , , . Bookmark the permalink.

1 Response to Querying UDP Ports with PowerShell: Part 2

  1. tuco says:

    Thanks.
    The UDP send is intuitive but the receive is a Microsoft epic fail. Compared to the ease and logical methods in other scripting languages, and I have used a lot, none of what we have to do here makes sense at all. More weird casts and strange setups to get what you want done when most of what the user has to setup can be done for you. For example, why do you have to say what the length your message is when sending it via Connect()?. Can’t the “Connect” method do that automagically for you if no size is passed? I bet they could. And even more examples similar to that for receiving a datagram.

    And when you make a Connection, shouldn’t you Close that connection as good practice when you’re done?
    $udpobject.Close()

Leave a comment