Been a long time since I posted anything here, but thought this might could be helpful on several different levels. While the subject matter (America's Army game query) may not be particularly interesting, the method for figuring out the query, analyzing the packet, and then coding a perl socket program to issue the same query and parse the data should be very useful. Regardless, I hope you guys enjoy it.

Section 1: Topics
Section 2: Problem Description
Section 3: UDP and IP Headers
3a. UDP Datagram Header Diagram
3b. IP Header Diagram
Section 4: Using tcpdump to gather information
Section 5: Analyzing the server query
Section 6: Analyzing the server response
Section 7: The programs
Section 8: References

Section 1.

Topics.

Network sniffing, perl programming, socket programming, packet analysis

Section 2.

Problem.

I enjoy playing a free game called America's Army, an online first person shooter. There is a
company that has provided free webspace and servers for myself and several friends
(dedicated to this game) and in return they requested that I come up with something to track
who is using their servers and to provide information regarding the game status on those
servers.

The game, when a server is selected, will tell who is logged into the server and a little
information about the progress of the game on the server (but not very detailed). I decided
that this would be a good place to start.

Section 3.


UDP and IP headers.

We will need to know the rough layout of an IP (because of encapsulation) and an UDP header
so that we can separate what information returned by tcpdump is part of the network
connection and what part of the information is the actual data that was used to construct the
query to the server. For now, a simple diagram obtained from the relevant RFC's will suffice.

UDP Datagram Header.

From RFC768, we can see the format of a UDP datagram is as follows:

0 7 8 15 16 23 24 31
+--------+--------+--------+--------+
| Source | Destination |
| Port | Port |
+--------+--------+--------+--------+
| | |
| Length | Checksum |
+--------+--------+--------+--------+
|
| data octets ...
+---------------- ...


IP Header.

From RFC791, we can see the format of an IP header is as follows:

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Version| IHL |Type of Service| Total Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Identification |Flags| Fragment Offset |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Time to Live | Protocol | Header Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Source Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Destination Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Options | Padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+



Section 4.

Gathering information.

My home network passes through a UNIX server running firewall software, which lends itself to
be a useful place to watch the network traffic generated by America's Army using the free
network sniffing program 'tcpdump' (http://www.tcpdump.org). The firewall, in this case, is a
good place to observe the traffic since all network traffic from my home network will have to
pass through this system. After a little messing around, I found that the game queries were
issued over udp port 1717 and I used tcpdump to filter down to only this traffic. Tcpdump was
then used to watch the network query issued while I selected a server using the in-game
browser for America's Army.

% tcpdump -n -S -s 15000 -vv -X 'host 192.168.0.159 and udp and port 1717'

-n --> no address resolution
-S --> print absolute IP sequence number
-s --> size of capture for each packet (15000 should be enough to hold data returned by query,
you will have to play with this depending on what type of query you issue)
-vv --> very verbose capture
-X --> print HEX and ASCII version of packet 'host 192.168.0.159 and udp and port 1717' -->
Berkely packet filter syntax. This is equivalent to telling tcpdump to
show network traffic only for IP 192.168.0.159 and to only show UDP traffic and to only
show traffic on port 1717.

Network capture of query:

09:41:54.262946 IP (tos 0x0, ttl 255, id 28832, offset 0, flags [DF], length: 46) 192.168.0.159.33365 > 69.25.16.47.1717: [udp sum ok] UDP, length: 18
0x0000: 4500 002e 70a0 4000 ff11 e2f6 c0a8 009f E...p.@.........
0x0010: 4519 102f 8255 06b5 001a 8e36 fefd 004e E../.U.....6...N
0x0020: bf06 01ff ffff 0000 0000 0000 0000 ..............

Section 5.

Analyzing the server query packet information.

To help figure out what/where things are in the above network capture, I am going to convert a
few relevant things to HEX:

The next four are the 4 octects of the IP for the server
DEC HEX
69 45
25 19
16 10
47 2F

The next four are the 4 octects to the IP for my system
192 C0
168 A8
0 00
159 9F

Source port
33365 8255

Destination port
1717 06B5

IP Packet ID
28832 70a0

Protocol:
17 11


Using the IP header picture as a guide, we can see the source IP 192.168.0.159 (c0a8 009f),
the destination IP 69.25.16.47 (4519 102f). If you count the number of bytes (4 bytes per line)
from the Source IP to the begining of the packet, we see that you arrive at 12 bytes, which
corresponds correctly with the diagram of the IP header. If you wish, you could also observe
the already converted IP packet ID 28832 (70a0) and UDP protocol 17 (11) and compare their
location within the packet to confirm the IP section of the header.

If you look at little further into the packet, you will see the source port 33365 (8255) and
the destination port 1717 (06b5). Using the UDP and IP diagrams as a guide, we know that the
next 8 bytes belong to the end of the UDP and IP header, which leaves us with a binary data
query of 'fefd 004e bf06 01ff ffff 0000 0000 0000 0000.' Of course, now that you know how to
read the actual packet, you could of course look at the nice hint that tcpdump provides (UDP,
length: 18) and count backwards from the end of the packet 18 bytes and arrive at the same
answer Ok, ok, don't shoot me, sometimes you won't always have a nice program like
tcpdump to use and you will have to be able to figure this out yourself.

Section 6.

Server Response.

Regardless, by analyzing the packet, we now know that the game issues a binary string of data
to server, and the server returns a rather large amount of data. The only key to the result to
pay attention to is that all information is seperated by a null character (0x00) and this can be
used to parse the results and that in general the information is broken down by 'name' 0x00
'value':

09:41:54.311114 IP (tos 0x0, ttl 48, id 0, offset 0, flags [DF], length: 1405) 69.25.16.47.1717 > 192.168.0.159.33365: [udp sum ok] UDP, length: 1377
0x0000: 4500 057d 0000 4000 3011 1d49 4519 102f E..}..@.0..IE../
0x0010: c0a8 009f 06b5 8255 0569 e2a9 004e bf06 .......U.i...N..
0x0020: 0168 6f73 746e 616d 6500 552e 532e 2041 .hostname.U.S..A
0x0030: 726d 7920 4f66 6669 6369 616c 2045 2031 rmy.Official.E.1
0x0040: 3231 0067 616d 656e 616d 6500 6172 6d79 21.gamename.army
0x0050: 6761 6d65 0067 616d 6576 6572 0032 2e31 game.gamever.2.1
0x0060: 2e30 0068 6f73 7470 6f72 7400 3137 3136 .0.hostport.1716
0x0070: 006d 6170 6e61 6d65 0057 6561 706f 6e73 .mapname.Weapons
0x0080: 2043 6163 6865 0067 616d 6574 7970 6500 .Cache.gametype.
0x0090: 4141 4750 5f47 616d 6554 6561 6d4f 626a AAGP_GameTeamObj
0x00a0: 6563 7469 7665 006e 756d 706c 6179 6572 ective.numplayer
0x00b0: 7300 3236 006e 756d 7465 616d 7300 3200 s.26.numteams.2.
0x00c0: 6d61 7870 6c61 7965 7273 0032 3600 6761 maxplayers.26.ga
0x00d0: 6d65 6d6f 6465 0063 6c6f 7365 6470 6c61 memode.closedpla
0x00e0: 7969 6e67 0070 6173 7377 6f72 6400 3000 ying.password.0.
0x00f0: 746f 7572 0038 006f 6666 6963 6961 6c00 tour.8.official.
0x0100: 3100 6c65 6173 6564 0030 006e 6174 6f00 1.leased.0.nato.
0x0110: 3000 6d69 6c65 7300 3000 6368 6561 7473 0.miles.0.cheats
0x0120: 0030 006d 696e 686f 6e6f 7200 3100 6d61 .0.minhonor.1.ma
0x0130: 7868 6f6e 6f72 0031 3030 0063 7572 7265 xhonor.100.curre
0x0140: 6e74 5f72 6f75 6e64 0035 2f37 006d 6973 nt_round.5/7.mis
0x0150: 7369 6f6e 5f74 696d 6500 393a 3239 0073 sion_time.9:29.s
0x0160: 765f 7075 6e6b 6275 7374 6572 0031 0074 v_punkbuster.1.t
0x0170: 6f75 726e 616d 656e 7400 3000 756c 7469 ournament.0.ulti
0x0180: 6d61 7465 5f61 7265 6e61 0030 0063 7573 mate_arena.0.cus
0x0190: 746f 6d00 3000 4164 6d69 6e4e 616d 6500 tom.0.AdminName.
0x01a0: 0041 646d 696e 454d 6169 6c00 0000 001a .AdminEMail.....
0x01b0: 6c65 6164 6572 5f00 676f 616c 5f00 686f leader_.goal_.ho
0x01c0: 6e6f 725f 0070 6c61 7965 725f 0070 696e nor_.player_.pin
0x01d0: 675f 0072 6f65 5f00 6b69 615f 0065 6e65 g_.roe_.kia_.ene
0x01e0: 6d79 5f00 0030 0030 0038 0050 6f72 7175 my_..0.0.8.Porqu
0x01f0: 6974 6f00 3234 3500 3000 3000 3000 3000 ito.245.0.0.0.0.
0x0200: 3000 3130 0044 6561 7468 5f62 795f 6275 0.10.Death_by_bu
0x0210: 6e67 6965 0031 3933 0030 0030 0030 0030 ngie.193.0.0.0.0
0x0220: 0030 0037 005b 474c 4144 494f 5d00 3335 .0.7.[GLADIO].35
0x0230: 3400 3000 3000 3000 3000 3000 3130 0049 4.0.0.0.0.0.10.I
0x0240: 6b65 6d61 7374 6572 0032 3332 0030 0030 kemaster.232.0.0
0x0250: 0030 0038 3000 3230 0034 3900 3d5b 4445 .0.80.20.49.=[DE
0x0260: 4f5d 3d5f 6170 6f63 616c 7970 7300 3235 O]=_apocalyps.25
0x0270: 3600 3000 2d31 3000 3130 0031 3000 3230 6.0.-10.10.10.20
0x0280: 0036 006d 616c 636f 6c6d 6675 6e67 0033 .6.malcolmfung.3
0x0290: 3931 0030 0030 0030 0033 3000 3330 0033 91.0.0.0.30.30.3
0x02a0: 3300 3d5d 5b53 4654 4f5d 5b3d 4849 544d 3.=][SFTO][=HITM
0x02b0: 414e 3800 3138 3600 3000 2d31 3000 3230 AN8.186.0.-10.20
0x02c0: 0037 3000 3430 0033 3600 5b47 4b5d 4370 .70.40.36.[GK]Cp
0x02d0: 5444 6f6e 4b61 0032 3639 0030 0030 0031 TDonKa.269.0.0.1
0x02e0: 3000 3000 3000 3233 004b 696c 6c65 7263 0.0.0.23.Killerc
0x02f0: 7261 636b 6572 2832 3532 2900 3237 3600 racker(252).276.
0x0300: 3000 2d32 3000 3000 3230 0037 3500 3133 0.-20.0.20.75.13
0x0310: 007b 466f 477d 416e 6e6f 6e61 746f 7200 .{FoG}Annonator.
0x0320: 3239 3300 2d37 3800 3000 3230 0030 0030 293.-78.0.20.0.0
0x0330: 0031 3000 6461 726b 4d4f 5554 4152 4445 .10.darkMOUTARDE
0x0340: 0032 3733 0030 002d 3330 0033 3000 3330 .273.0.-30.30.30
0x0350: 0034 3000 3230 002d 4372 6970 746c 6173 .40.20.-Criptlas
0x0360: 2d00 3239 3600 3000 2d32 3000 3330 0030 -.296.0.-20.30.0
0x0370: 0034 3000 3231 0079 6f77 7365 7273 3939 .40.21.yowsers99
0x0380: 0032 3136 0030 002d 3230 0035 3000 3136 .216.0.-20.50.16
0x0390: 3000 3530 0031 3100 7b39 7468 696e 667d 0.50.11.{9thinf}
0x03a0: 4b65 7973 6572 536f 7a65 0032 3636 0030 KeyserSoze.266.0
0x03b0: 002d 3130 0030 0030 0034 3000 3233 007b .-10.0.0.40.23.{
0x03c0: 3974 6869 6e66 7d2e 4261 6442 6f79 0032 9thinf}.BadBoy.2
0x03d0: 3531 0030 002d 3330 0033 3000 3000 3132 51.0.-30.30.0.12
0x03e0: 3000 3535 0070 7368 6f6f 7465 7239 3900 0.55.pshooter99.
0x03f0: 3231 3500 3000 2d33 3000 3132 3000 3000 215.0.-30.120.0.
0x0400: 3330 0032 3600 5b4a 6f74 756e 5d00 3137 30.26.[Jotun].17
0x0410: 3000 3000 2d34 3000 3000 2d31 3500 3430 0.0.-40.0.-15.40
0x0420: 0031 3100 6b63 6172 7030 3031 0032 3137 .11.kcarp001.217
0x0430: 002d 3500 2d34 3000 3000 3000 3230 0035 .-5.-40.0.0.20.5
0x0440: 3200 364b 6e69 6768 7468 6177 6b36 0032 2.6Knighthawk6.2
0x0450: 3432 0030 002d 3430 0031 3000 2d31 3500 42.0.-40.10.-15.
0x0460: 3230 0032 3000 6641 6333 732d 4f66 2d64 20.20.fAc3s-Of-d
0x0470: 3361 5468 0032 3032 0030 002d 3530 0035 3aTh.202.0.-50.5
0x0480: 3000 3000 3430 0032 3500 5065 656c 5365 0.0.40.25.PeelSe
0x0490: 656c 3200 3236 3900 2d32 3432 002d 3430 el2.269.-242.-40
0x04a0: 0030 0031 3000 3630 0032 3100 4272 756e .0.10.60.21.Brun
0x04b0: 6f33 3173 745f 5371 7561 6400 3238 3400 o31st_Squad.284.
0x04c0: 3000 2d33 3000 3430 0030 0032 3000 3139 0.-30.40.0.20.19
0x04d0: 005b 4645 415d 2d28 5b4c 6f52 6f5d 292d .[FEA]-([LoRo])-
0x04e0: 4172 4700 3334 3400 2d37 3000 2d34 3000 ArG.344.-70.-40.
0x04f0: 3530 0030 0032 3000 3139 002d 7b54 4243 50.0.20.19.-{TBC
0x0500: 7d2d 4365 7269 616c 5f4b 696c 6c65 7200 }-Cerial_Killer.
0x0510: 3232 3900 3000 2d34 3000 3130 002d 3330 229.0.-40.10.-30
0x0520: 0032 3000 3234 007d 4c54 4b5f 527b 5f66 .20.24.}LTK_R{_f
0x0530: 7361 6c61 7a61 7239 3000 3137 3700 2d31 salazar90.177.-1
0x0540: 3100 2d34 3000 3330 0031 3000 3630 0032 1.-40.30.10.60.2
0x0550: 3700 6f6e 655f 7472 6163 6b5f 6d69 6e64 7.one_track_mind
0x0560: 0031 3733 0030 002d 3130 0032 3000 0002 .173.0.-10.20...
0x0570: 7363 6f72 655f 7400 0031 0033 00 score_t..1.3.

Section 7.

The program.

I decided to break down the functionality of the program into two sections. The first program
that strictly connects to the server, issues the query, captures the data, and prints the data in
a raw format. The second program will take the data from the first one and generate a web
page based on the data.

The server query program:

Code:
#!/bin/perl
#       /*nebulus*/
#                       qaas - query america's army server
#       expects server as first argument, port as second
#       stripped - queries server directly, returns server packet * NO PROCESSING *
#       returns null separated set of values from server
#       
#       Created by Nebulus June 2004 -- All use of this program must be at the authorization
#        of nebulus for Coldyne.  All use of this program should reference nebulus as the
#        creator.
#
# Designed to be run from a pipe (ie, qaas.pl <server> <port> | <processing program>)
#
use strict;                             # strict variable processing
use IO::Socket;                         # needed for socket connections (library)

my $debugging = 0;                      # not in debug mode by default
my $logging = undef;                    # no logging by default
my $logfile = undef;                    # no log file by default
my $time = localtime;                   # time this was run
my $server = undef;                     # server to query
my $port = undef;                       # server port to query

my $queryall = "\xfe\xfd\x00\x4e\xbf\x06\x01\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00";
# queryall is the binary command used by 2.1.0 of AA to query servers
# Since AA is based on the UT2003 engine, the query can be modified.  This query follows the
# rough format of the UT2003 query for all; however, the binary data was obtained by the
# packet sniff

if (defined $logging && defined $logfile)
{
# If the user has enabled logging and defined a logfile, then try to open the log file

        open (LOG, "> $logfile") || die "$time [qaas.pl] Error opening logfile\n";
        exit 1;
}

my $argc = @ARGV;

if($argc != 2)
{
# if improper number of arguments, describe how to use
        if(defined $logging && defined $logfile)
        {
                print LOG "$time [qaas.pl] Insufficient arguments ($argc) to run\n";
        }
        close(LOG);
        exit 2;
}

$_ = shift @ARGV;  $server = (m/\d+\.\d+\.\d+\.\d+/) ? $_ : 0;
# read the server IP, if the IP doesn't match the format, then set IP to 0 
$_ = shift @ARGV;  $port = ($_ < 1 || $_ > 65535) ? 1717 : $_;
# read the server port, if the port is invalid, set it to the default of 1717

if (! $server || ! $port)
{
# if bad port or server, do an error message

        if(defined $logging && defined $logfile)
        {
                print LOG "$time [qaas.pl] server $server or port $port is not valid\n";
                close(LOG);
        }
        elsif($debugging)
        {
                print "$time [qaas.pl] server $server or port $port is not valid\n";
        }
        exit 3;
}

#create socket connection to server
if($debugging) {   print "Connecting to $server on port $port\n"; }

my $mySocket = new IO::Socket::INET->new(TimeOut => 5, PeerAddr => $server, PeerPort => $port, Proto => "udp");
# our time out is 5, with the conneciton being made to server and port over udp
# may need to set higher if network bogged down (or maybe even make it a passable option)

if(! $mySocket)
{
# make sure it connected or quit with error
        if(defined $logging && defined $logfile)
        {
                print LOG "$time [qaas.pl]  Error connecting to $server:$port\n$!\n";
                close(LOG);
        }
        elsif($debugging)
        {
                print "$time [qaas.pl] Error connecting to $server:$port\n$!\n";
        }
        exit 4;
}

# send our captured server query over our newly created socket
print $mySocket "$queryall";
# receive the server response, set recv buffer to max UDP datagram size so no data truncated
$mySocket->recv($_, 65535);
close($mySocket);
# we don't need our socket anymore so we can close it
binmode STDOUT, ":raw";
# since the data returned is in raw binary, we need to return it that way (don't convert null)
print "$_";
exit 0;
The text printing program:

Code:
#!/bin/perl
#               tsp.pl          Text Server Processor
#       Take output from either AA server or qaas and print out simple text
#       
#       Created by Nebulus June 2004 -- All use of this program must be at the authorization
#        of nebulus of Coldyne.  All use of this program should reference nebulus as the
#        creator
#
# Designed to be run from a pipe (ie, qaas.pl <server> <port> | tsp.pl)
#

use strict;

my $kia = "";                                   # player's KIA
my $name = "";                                  # player's name
my $honor = "";                                 # player's honor 
my $ping = "";                                  # player's ping
my $leader = "";                                # player's leader score
my $goal = "";                                  # player's goal score
my $roe = "";                                   # player's ROE penalty
my $enemy = "";                                 # player's kills
my $hostname= "";                               # server's hostname
my $gamename = "";                              # server's gamename 
my $gamever = "";                               # server's game version
my $hostport="";                                # server's hostport
my $mapname="";                                 # map running on server
my $numplayers=0;                               # number of players on server
my $numteams=0;                                 # number of teams on server
my $maxplayers=0;                               # max number of players allowed on server
my $password=0;                                 # password enabled bitflag
my $official = 0;                               # official enabled bitflag
my $leased = 0;                                 # leased enabled bitflag
my $miles=0;                                    # miles enabled bitflag
my $cheats = 0;                                 # cheats enabled bitflag
my $minhonor = 0;                               # minimum honor to join 
my $maxhonor=0;                                 # maximum honor to join
my $current_round = 0;                          # current round on server
my $admin_name = "";                            # administrator of server
my $admin_email = "";                           # administrator's email
my $mission_time = 0;                           # mission time remaining
my $sv_punkbuster=0;                            # punkbuster enabled bitflag
my $nato = 0;                                   # nato enabled server
my @plys = ();                                  # players on the server

# necessary to make it look pretty
format STDOUT =
@<<<<<<<<<<<<<<<<<<< @<<< @<<<< @<<< @<<<  @<<< @<<< @<<<
$name, $honor, $ping, $leader, $goal, $roe, $kia, $enemy
.


$_ = <STDIN>;
# all values are null seperated (read tutorial)
my @trsh = split(/\x00/);


my $ln2 = length @trsh;
while ($ln2 > 1)
{
        $_ = shift @trsh;
        if($_ eq "" ) { next; }
        if(m/hostname/) { $hostname = shift @trsh; } 
        if(m/gamename/) { $gamename = shift @trsh; }
        if(m/gamever/) { $gamever = shift @trsh; }
        if(m/hostport/) { $hostport = shift @trsh; }
        if(m/mapname/) { $mapname = shift @trsh; }
        if(m/numplayers/) { $numplayers = shift @trsh; }
        if(m/numteams/) { $numteams = shift @trsh; }
        if(m/maxplayers/) { $maxplayers = shift @trsh; }
        if(m/password/) { $password = shift @trsh; }
        if(m/official/) { $official = shift @trsh; }
        if(m/leased/) { $leased = shift @trsh; }
        if(m/nato/) { $nato = shift @trsh; }
        if(m/miles/) { $miles = shift @trsh; }
        if(m/cheats/) { $cheats = shift @trsh; }
        if(m/minhonor/) { $minhonor = shift @trsh; }
        if(m/maxhonor/) { $maxhonor = shift @trsh; }
        if(m/current_round/) { $current_round = shift @trsh; }
        if(m/mission_time/) { $mission_time = shift @trsh; }
        if(m/sv_punkbuster/) { $sv_punkbuster = shift @trsh; }
        if(m/AdminName/) { $admin_name = shift @trsh; }
        if(m/AdminEmail/) { $admin_email = shift @trsh; }
        if(m/enemy_/) 
        {
        # players are broken out differently and must be processed differently
                while ($ln2 > 1)
                {
                my $l1 = ""; my $g1 = ""; my $h1 = ""; my $n1 = ""; my $p1 = ""; my $r1 = ""; my $k1 = ""; my $e1 = "";
                        $l1 = shift @trsh;
                        if($l1 eq "") { next; };
                        if($l1 eq "score_t") { last; }
                        $g1 = shift @trsh;
                        $h1 = shift @trsh;
                        $n1 = shift @trsh;
                        $p1 = shift @trsh;
                        $r1 = shift @trsh;
                        $k1 = shift @trsh;
                        $e1 = shift @trsh;
                        @plys = (@plys, "$n1\x00$h1\x00$p1\x00$l1\x00$g1\x00$r1\x00$k1\x00$e1");
                        $ln2 = length @trsh;
                }
        }
        $ln2 = length @trsh;
}
print "Server: $hostname $gamever\n";
print "Map: $mapname ($numplayers" . "/" . "$maxplayers)\n";
print "Server Flags: ";
if($official) { print "Official "; }
if($leased) { print "Leased "; }
if($nato) { print "Nato "; }
if($cheats) { print "Cheat_enabled "; } 
if($sv_punkbuster) { print "Punkbuster "; }
print "\n$minhonor < honor < $maxhonor\n";
print "Round $current_round with $mission_time remaining\n";
print "Player              Honor Ping Leader Goal ROE  KIA  Kills\n";
print "===========================================================\n";


my @tmp = (); my $pl = "";
foreach $pl (@plys)
{
        $_ = $pl;
        @tmp = split(/\x00/);
        $name = @tmp[0]; $honor = @tmp[1]; $ping = @tmp[2]; $leader = @tmp[3]; $goal = @tmp[4];
        $roe = @tmp[5]; $kia = @tmp[6]; $enemy = @tmp[7];
        write STDOUT;
}
Section 8.

References.

RFC768. RFC governing UDP.
RFC791. RFC governing IP.