mIRC Scripting

mIRC: UDP Sockets

This article assumes that you have intermediate to advanced knowledge of the mIRC Scripting Language.

Sockets

UDP is one of the core protocols of the TCP/IP suite. Here are a few pointers regarding UDP:

User Datagram Protocol (UDP):
     - Connectionless Service
     - No logical connection established between End Systems
     - Unreliable - "best effort" delivery
     - Used when speed is required and guaranteed delivery is secondary

mIRC lets you create UDP socket as well. Remember: since UDP is connectionless there is no virtual circuit, thus no sockopen/sockread/sockclose events. The basic syntax for creating a UDP socket is:

/sockudp [-k] <name> <ipaddress> <port> [text|%var|&binvar]

By default, when a UDP socket is created, the data is sent to the specific port and destination IP/URL and then immediately closed. Using the -k switch we can force the UDP socket to stay open, giving us the ability to listen to incoming data.

If you are expecting data back from the server, by forcing the -k switch, the udpread syntax is:

on *:udpRead:SockName: {
  ;code
}

 

Example 1 (TIME Protocol):

For this example we will use the TIME protocol, as defined in RFC 868.

When used via UDP the time service works as follows:

S: Listen on port 37 (45 octal).
U: Send an empty datagram to port 37.
S: Receive the empty datagram.
S: Send a datagram containing the time as a 32 bit binary number.
U: Receive the time datagram.

The server listens for a datagram on port 37. When a datagram
arrives, the server returns a datagram containing the 32-bit time
value. If the server is unable to determine the time at its site, it
should discard the arriving datagram and make no reply.

The first thing we need to do is send an empty datagram to their server (I used 0 instead of null because I couldn't get null to work):

Alias getTime {
  ; Time-a.nist.gov = 129.6.15.28
  sockudp -k getTime 129.6.15.28 37 0
}

Now, all we have to do is wait for the datagram response. Remember that since UDP is connectionless protocol, its header is mucher small, thus much faster (Ideal for a time protocol).

on *:udpRead:getTime: {
  sockread -f &time
  var %time $bvar(&time,1,$bvar(&time,0))
  var %bin $regsubex(%time,/(\d+)/g,$base(\1,10,2,8))
  echo -a our 32-bit time value: %bin
  sockclose $sockname
}

Let's make sense of this 32bit time value, shall we?

Once again, from the RFC 868:

The Time

The time is the number of seconds since 00:00 (midnight) 1 January 1900
GMT, such that the time 1 is 12:00:01 am on 1 January 1900 GMT; this
base will serve until the year 2036.

For example:

the time 2,208,988,800 corresponds to 00:00 1 Jan 1970 GMT,
2,398,291,200 corresponds to 00:00 1 Jan 1976 GMT,
2,524,521,600 corresponds to 00:00 1 Jan 1980 GMT,
2,629,584,000 corresponds to 00:00 1 May 1983 GMT,
and -1,297,728,000 corresponds to 00:00 17 Nov 1858 GMT.

Since we know that 2,208,988,800 = 00:00 1 Jan 1970 GMT (Unix epoch). We can just do $calc(%time - 2208988800) to get the current Unix time. Now all we got to do is use $asctime to format it nicely.

on *:udpRead:getTime: {
  sockread -f &time
  var %time $bvar(&time,1,$bvar(&time,0))
  ;convert to binary, remove spaces
  var %bin $regsubex(%time,/(\d+|\s)/g,$base(\1,10,2,8))
  ;get the current unix time in decimal system
  var %time = $base(%bin,2,10)
  echo -a Currnt Time/Date: $asctime($calc(%time - 2208988800),yyyy-mm-dd hh:nn:ss TT)
  sockclose $sockname
}

Example 2 (QOTD Protocol):

In this example we will use an interesting protocol, the Quote Of The Day, RFC 865. This is a very simple protocol; you send a blank datagram, and the server responds with a quote. The hardest part was actually finding a website that still supports this protocol. (The reason most servers don't have this service enabled is because it is vulnerable to a ping-pong attack, where an attacker spoofs a server's IP (that supports QOTD protocol) and sends a request to a second server that support it, causing both server to flood each other)

Create a socket:

alias QOTD {
  ; Dns resolved quotes4all.net to 85.25.143.214
  sockudp -k QOTD 85.25.143.214 17 0
}

Wait for incoming data:

on *:udpRead:QOTD: {
  var %Quote
  sockread -f %Quote
  echo -ea %Quote
  sockclose $sockname
}