Minecraft 1.9 has rcon and query!

However, there's absolutely no documentation on how it works. Considering it came out just earlier this day I'm not really surprised, but I thought I'd go fix that. Here's a tech document for you guys on how the status query works. To clarify: This means lots of tech data that probably means little to anyone else. Helpful for those of you who run websites for this kinda stuff, not helpful to Mrs. Sue who's looking for a new recipe for crafting her own bread.

The status system is incredibly simple, with only 2 possible packet types that you can send to it. It runs on UDP and thus supports multicast requests (initially), but individually replies to each one. In addition, it uses a challenge token which is explicitly designed to prevent multicast status updates, so you can request a challenge with no issues but when it comes to actually asking for the server status, you're outta luck. Keep in mind, all my diggings into this is from datamining, I am not an absolute authority over the meaning of any of these values. In addition, the protocol is very likely to change in the future. In the case that it does change, I'll update this post (and make a new one saying the changes).

It's also designed to carry a custom 4 bytes (a single int or 4 chars, whatever floats your castle) between requests so you can easily pair-up any data you receive with a request that you initially sent.

Every packet you send must be prefixed with two magic bytes (0xFE, 0xFD), followed by a packet-type (again, a byte). There are two current packet types: 0x00 and 0x09. 0x00 is responsible for actually giving you the status of the server but cannot be used unless you provide your challenge, whereas 0x09 gives you a challenge token.

To receive your challenge token, you send a request like the following:

    [
      0xFE, 0xFD,             // Magic bytes
      0x09,                   // Challenge type
      0x01, 0x02, 0x03, 0x04  // Your ID token
    ]

The ID token may be anything you like, you may even omit it entirely (which will default it to 4 NUL bytes). You'll then receive the following:

    [
      0x09,                   // Challenge type
      0x01, 0x02, 0x03, 0x04, // Your ID token (or 4 NUL)
      0xDE, 0xAD, 0xBE, 0xEF  // Your new challenge token (int-32)
    ]

Simple, right? There's really no need for me to even give you the structures, I've just always wanted to do that. The ID token is the one you provided earlier, and the challenge token is something you will need to save for all future requests. Note that the challenge token is bound to your IP and port (as opposed to the ID token), and lasts up to 30 seconds. You read that right, it's up to; it's not "your token will expire after 30 seconds", it's "every token ever" is expired every 30 seconds. This means it's entirely possible that you may get a token and use it within the same second and have it expire.

Next you'll want to actually find out the status of the server. You'll need to provide your challenge token, or you will not receive any reply. If you provide a token and it's wrong, you still won't receive a reply. With that in mind, if you're going to store your challenge token and use it later then you may want to do some kind of timeout on waiting for a reply, in case the server restarted and your token is no longer valid. It's impossible to identify between an offline server and a server that refused your challenge without any additional requests, so you'll want to try for another challenge token and if that fails then flag them as unavailable.

I said before that there's only one more packet, which is to receive the server status. However, that packet is split into two, depending on exactly how much you want to know about the server. There's no flag saying which you want, instead it's dependent on the structure of your request. Let's go for the "short and sweet" reply, which contains everything you'd want to know at a glance. Send the following:

    [
      0xFE, 0xFD,             // Magic bytes
      0x00,                   // Status type
      0x01, 0x02, 0x03, 0x04, // Your ID token
      0xDE, 0xAD, 0xBE, 0xEF  // Your challenge token
    ]

Nothing fancy there. The challenge must be valid and that's it. You'll receive the following:

    [
      0x00,                   // Status type
      0x01, 0x02, 0x03, 0x04, // Your ID token (that you registered your challenge with)
      payload                 // See below!
    ]

Payload consists of the following information. All strings are null-terminated C-style, and what I refer to as numbers are integers converted into a string in base 10 (So if you receive "30", it's actually 0x1E). Shorts are little-endian, whereas everything else is big-endian.

    string                    // Server MoTD as displayed in the in-game server browser.
    string                    // Game type. Currently hardcoded to "SMP".
    string                    // Name of the default world.
    number                    // How many players are currently online.
    number                    // Maximum number of players this server supports.
    short                     // Port the server is listening on.
    string                    // Host that the server may receive connections on.

Ok, so that's what most people care about. What possible more could you get with the other request type? Well, quite a bit. Stuff that you didn't even think to ask for. How do we access this mystical data pool? Easy. Send the following:

    [
      0xFE, 0xFD,             // Magic bytes
      0x00,                   // Status type
      0x01, 0x02, 0x03, 0x04, // Your ID token
      0xDE, 0xAD, 0xBE, 0xEF, // Your challenge token
      0x01, 0x02, 0x03, 0x04  // Your ID token, again
    ]

Now, this method is actually cached every 5 seconds. Quite unusual, but certainly reasonable. You'll receive the same packet structure, but this time the payload is thus:

    string                    // DEBUG - hardcoded "splitnum".
    int32                     // UNKNOWN - hardcoded "128". (world-height?)
    int32                     // UNKNOWN - hardcoded "0".
    string                    // DEBUG - hardcoded "hostname".
    string                    // Server MoTD as displayed in the in-game server browser.
    string                    // DEBUG - hardcoded "gametype".
    string                    // Game type. Currently hardcoded to "SMP".
    string                    // DEBUG - hardcoded "game_id".
    string                    // Game name. Currently (and probably always will be) hardcoded to "MINECRAFT".
    string                    // DEBUG - hardcoded "version".
    string                    // Version of the server as shown at startup. Example would be, "Beta 1.9 Prerelease 4".
    string                    // DEBUG - hardcoded "plugins".
    string                    // List of plugins(?!) that are on the server. Hardcoded to "" (but obviously will be
                              //  used by Bukkit and other server mods)
    string                    // DEBUG - hardcoded "map".
    string                    // Name of the default world.
    string                    // DEBUG - hardcoded "numplayers".
    number                    // How many players are currently online.
    string                    // DEBUG - hardcoded "maxplayers".
    number                    // Maximum number of players this server supports.
    string                    // DEBUG - hardcoded "hostport".
    short                     // Port the server is listening on.
    string                    // DEBUG - hardcoded "hostname".
    string                    // Host that the server may receive connections on.
    int32                     // UNKNOWN - hardcoded "0".
    int32                     // UNKNOWN - hardcoded "1".
    string                    // DEBUG - hardcoded "player_".
    int32                     // UNKNOWN - hardcoded "0".
    string[numplayers]        // Name of all online players.
    int32                     // UNKNOWN - hardcoded "0".

And there we have it. If anyone has any clues as to the unknown values, please drop me an email or leave a comment. The "plugins" field is very interesting, I propose that we (Bukkit) and any other server modders use a convention like thus:

CraftBukkit 1338: WorldEdit 1.2; LogBlock 4.5; Dynmap 8.2beta

Or without any plugins but just a mod:

SomeMod 123 beta C

Where it's just in the format of:

    [SERVER_MOD_NAME[: PLUGIN_NAME(; PLUGIN_NAME...)]]

Comments

Doctor Sushi
Doctor Sushi on 10/14/2011 5:22 a.m. #

I would return the plugin list as json for fast consumption by services.

dinnerbone
dinnerbone on 10/14/2011 5:57 a.m. #

Hm, there's a thought. But there'd be no way to make it backwards compatible with people who won't follow the idea, and it won't be pretty on sites that just want to print the result.

lairsdragon
lairsdragon on 10/14/2011 9 a.m. #

Nice, but what happens with server running IPv6? The IPv6 will not fit into 4 bytes :-)

cheerio
Lairsdragon

dinnerbone
dinnerbone on 10/14/2011 9:19 a.m. #

Minecraft doesn't support IPv6 :(

lairsdragon
lairsdragon on 10/14/2011 9:32 a.m. #

Maybe its not supported but it works, take a look at mc6.weinreich.org :-)

cheerio
Steve

sadimusi
sadimusi on 10/14/2011 1:02 p.m. #

This might quite likely be used by http://www.gametracker.com

Richard Robertson
Richard Robertson on 10/14/2011 2:32 p.m. #

I propose that Bukkit include a feature to disable this feature.

xPaw
xPaw on 10/14/2011 2:38 p.m. #

I can't really seem to get server to answer on 0x00 packet.. it just doesn't want to respond on it when i put challenge token from 0x09..

Also, how to enable "debug mode" on server, so i can see helpful messages about packets? debug=true in properties doesn't seem to do anything

dinnerbone
dinnerbone on 10/14/2011 6:39 p.m. #

Richard: It's turned off by default. You would ask us to remove it completely? There's no reason to do that at all.

xPaw: Can I see a log of the data you're sending/receiving?

xPaw
xPaw on 10/14/2011 8:53 p.m. #

Sure: https://paste.xpaw.ru/ced6a873d9ec7c1f9fc04a56a9f59c48

dinnerbone
dinnerbone on 10/15/2011 12:54 a.m. #

Weak typed languages make this stuff tricky to spot errors like that. Your $challenge is a string, so it'll send the string instead of a 32-bit int. Check the php docs for the pack() method.

leafstorm
leafstorm on 10/15/2011 3:11 p.m. #

What about rcon? I tried googling "rcon protocol," but there are at least two protocols named rcon in existence (both of which are poorly documented and yet still mutually incompatible), as well as some other things that just happen to be named "rcon." Do you know anything about this?

Eggplant!
Eggplant! on 10/17/2011 1:52 a.m. #

Are you certain about the initial challenge packet response? The response I get back appears to be null terminated string and not a 32 bit int. I see responses something like:

[
0x09,
my token (int-32),
a null terminated string usually 8-9 characters.
]

xPaw
xPaw on 10/17/2011 5:22 p.m. #

Turns out this is Gamespy v3 protocol.

Barney
Barney on 10/18/2011 8:54 p.m. #

hey all. I did some more protocol documentation here: http://wiki.vg/Query

I found a couple of things to be different:
1) 0x09 response gives your challenge as a null-terminated string
2) 0x00 requests *include an ID*. The simple stat is: 0xFE 0xFE 0x00 <4 byte ID token> <4 byte challenge token>. The more advanced stat is the same, but you have to pad it to 15 bytes, so add 4 null bytes at the end.
3) I don't see the 4-byte IPv4 listen address at the beginning of the simple stat.
4) The first 16 bytes of the advance stat payload is just junk data and meaningless

This page is a pretty good overview, but the protocol MC implements is incompatible: http://wiki.unrealadmin.org/UT3_query_protocol

Rcon is documented here: http://wiki.vg/Rcon

Barney
Barney on 10/18/2011 8:55 p.m. #

Holy missing linebreaks batman! Just look here: http://wiki.vg/Query

R3B0RN
R3B0RN on 12/09/2011 3:28 p.m. #

Hey!
If anybody is looking for an RCON Client for Windows, I made one, and it can be downloaded here: http://dl.dropbox.com/u/49943618/RCON.exe. It can handle favorites, and remember last server. Please do not modify it's config file, it causes the application to quit. I hope it helps.

R3B0RN

R3B0RN
R3B0RN on 12/09/2011 3:57 p.m. #

Here is the forum topic if anybody is interested: http://www.minecraftforum.net/topic/852452-minecraft-rcon-tool-by-r3b0rn/

dinnerbone
dinnerbone on 12/09/2011 3:58 p.m. #

Handy! Thanks :)

JamesShadowman
JamesShadowman on 12/13/2011 11:37 p.m. #

R3B0RN Beat me to posting here. I coded RCON 5 days before him :P But he has a nice GUI.

http://www.minecraftforum.net/topic/842376-minecraft-server-rcon-utility/page__gopid__11081097#entry11081097

Leave a comment

Comments are now closed for this entry.