Reverse engineering Outernet: time and file services

In my last two posts, I've being talking about my reverse engineering efforts with the Outernet signal and I've described the modulation, coding and framing and the L3 and L4 network protocols used in Outernet. This post is the last in this series. Here I talk about how the time and file services work. Recall that a Free Software implementation of an Outernet receiver based on these descriptions is now available at gr-outernet and free-outernet.

Currently, Outernet provides only two services: the time service and the file service. The purpose of the time service is to update the clock of the receivers, and the purpose of the file service is to broadcast files, which is Outernet's main service.

Time service

The Outernet time service is used to update the clock on the Outernet receivers, since these receivers are designed to run without internet connectivity and they usually do not have a real time clock. The time service broadcasts a time packet approximately every minute. This packet contains a Unix timestamp (as a big-endian 32bit integer), and the Outernet receiver software uses this timestamp to set the system clock.

These are the contents of an OP packet from the time service, as broadcast from the Americas Inmarsat satellite. I have removed the Ethernet headers and the trailing zeros.

0000   00 1c 3c 00 00 00 81 00 00 18 01 04 6f 64 63 32
0010   02 08 00 00 00 00 58 02 63 5b 19 da 95 3d

As I said in the previous post, the time packets are LDP packets with an A field of 0x8100 and a B field of 0x0104. The first bytes of the LDP payload are 0x6f 0x64 0x63 0x32, which is ASCII for odc2. As we will see, in the time packets broadcast from the Europe/Africa satellite, odc3 is used instead. This field is used to identify which satellite/groundstation is broadcasting, since there is no information about this on the other packets other than the source MAC of the Ethernet frames, which may change if they change equipment on the groundstation.

The letters "odc" stand for Outernet Datacasting (I'll explain below why I know this). In fact, currently there is HTTP access to, and They all show the login page of an M7 Satellite Modem, so it seems that Outernet has the satellite modems at its three groundstations exposed online (a terrible idea if you ask me). I have just noticed this while writing this post. I don't know if knowing that the satellite modem used is the M7 would have helped me to reverse engineer the modulation, coding and framing. In the M7 datasheet you can see that it supports much more advanced stuff that the basic schemes that are used for Outernet. We also see that one of the operating modes of the modem is "Ethernet", so now we see why the Outernet frames are Ethernet frames. The frames are generated in a computer, which sends them to the M7 modem by Ethernet (as broadcast frames) and the modem just retransmits these frames.

It's also fun to try to geolocate the IPs for odc2, odc3 and odc4. I'm using for this. Currently odc2 has the IP, which is geolocated to Toronto, odc3 has the IP, which is geolocated to Amsterdam and odc4 has the IP, which is geolocated to Ketu Bay, New Zealand. Other tools may give slightly different results, since IP geolocation is not an exact science.

I don't know what are the next two bytes, which are always 0x02 0x08 and why the next 4 bytes are zeroed out. The next four bytes are the Unix timestamp. In this case, 0x5802635b corresponds to 15 Oct 2016 17:11:55 UTC. The last four bytes are the LDP checksum.

This is a time packet as broadcast from the Europe/Africa Inmarsat satellite.

0000   00 1c 3c 00 00 00 81 00 00 18 01 04 6f 64 63 33
0010   02 08 00 00 00 00 58 02 5d 9d f8 16 9e 39

The only difference is that odc3 is used instead of odc2. I haven't seen any packet from the Asia/Pacific satellite, but I guess that it uses odc4.

Note that this time service is not very good in comparison with other usual time services such as GPS or NTP. The resolution is only one second and the round trip time to geostationary orbit is not accounted for. However, it's useful for its intended application, which is to keep the clocks of the receivers reasonably on time.

File service

The file service is Outernet's main service and is used to broadcast files. It uses three types of packets, and each type uses different LDP A and B fields, so they can be processed correctly in the file service client application. The three types of packets are: file announcements, file blocks and FEC blocks.

File announcements

The transmission of a file starts with the transmission of the corresponding file announcement. This is a large LDP packet that usually gets split in 6 OP fragments. The A field used for file announcements is 0x6900 and the B field is 0x0302. The payload of the file announcement LDP packet is essentially an XML (in ASCII) containing the description of the file details. However, the file announcement is signed with an X.509 certificate or something like that. I guess that this is done to prevent spoofing, but I think one it's unlikely to get spoofing in a satellite application such as this one. One could argue that it is used so that if Outernet manages to sell a lot of receivers another company can't start to broadcast a compatible service for which Outernet receivers can be used. So, first you have the X.509 thing, which is mostly binary but has some ASCII strings and then you have the XML with the file description.

I haven't tried to see how X.509 is being used to sign file announcements, since I don't much interest in this. Outernet's ondd binary is distributed with a CA certificate, so it surely checks the X.509 certificate signing the file announcement against this CA certificate. The ASCII strings found within the X.509 data are "Illinois", "Chicago" (the location for the X.509 certificate), "Outernet", "Datacasting", the dates of creation and expiration of the certificate (it's valid from 2015 to 2031) and "" (in packets from the Europe/Africa satellite). Of course all of these are the different fields of the X.509 certificates. Perhaps if one passes the binary info to openssl, it will give something more. It is from this data from where I have guessed that "odc" stands for "Outernet Datacasting" and from where I got the idea to look up in a web browser.

This is an example of an XML file description. It has being formatted for readability. The original doesn't contain line breaks or indentation.

<?xml version="1.0" encoding="UTF-8"?>

This is mostly self explanatory: the id is used to identify the file in file block and FEC block packets, the path is the path were the file should be saved (compressed files are always saved to the opak folder and the closed-source ondd client decompresses them after they have being downloaded correctly), hash is the SHA256 hash of the file, size is the size of the file in bytes, block_size is always 242 and is the size of the blocks that the file is split into (more about this later) and fec contains the specifications for the FEC used for the file.

FEC (Forward Error Correction) allows the receiver to recover the complete file even if some of the blocks are missing, because the signal was not very good at some times or the path to the satellite was interrupted briefly. This is a good idea, because each block of the file is broadcast only once. It seems that all but the smallest files are sent with FEC (in case there is no FEC the fec tag is just missing) and that an LDPC code is always used for FEC. The specifications of the LDPC code vary a lot from file to file and are probably chosen according to file size using some algorithm.

After the file announcement is sent, the file blocks and FEC blocks for the file are sent. Both the file blocks and the FEC blocks are sent in order, but file blocks and FEC blocks are sent in an interleaved manner. For any particular file, there are many more file blocks than FEC blocks, so the satellite spends most of the time sending file blocks. It seems that Outernet only sends one file at a time, although there is no reason why several files can't be sent at the same time, provided that the file announcements for all of them have being done before sending the corresponding file and FEC blocks. There's also no reason why blocks need to be sent in order.

File blocks

Each file is split into blocks of 242 bytes. When adding a 4 byte header to one of these blocks and embedding it as the payload of an LDP packet, an OP packet of 262 bytes (which is the Outernet MTU) is produced. This explains the choice of 242 bytes as the block size. The last block of the file is generally smaller than 242 bytes, so it is sent in a smaller LDP packet.

This OP packet is an example of a file block. In fact it is the first block of some file.

0000   01 04 3c 02 00 00 18 00 01 00 00 00 06 d9 00 00 
0010   42 5a 68 39 31 41 59 26 53 59 02 3c e3 ff 01 2b
0020   03 7f ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0030   ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0040   ff ff ff e3 3c bf 00 e8 e8 75 f2 5d de 77 9e ee
0050   fb 55 aa f2 ad 0f ae 63 5d e9 e7 de ee ee ed bb
0060   e3 5c b2 f3 65 7a c6 79 80 47 be df 3b e3 a7 3a
0070   6d af b7 ab b9 de 6e fa dd 3a fb dd 3b be d9 4e
0080   dd f0 0e ec 75 e6 af 2e f9 f1 6f 9e eb e7 df 3b
0090   ef bc f3 7b ed cd be b7 3b 3b 7d be e7 65 bd 15
00a0   ef be b5 b8 de b2 b1 5b ee fb dd be f7 52 f3 74
00b0   ef 7d dd d6 f7 bb 9b eb 3e ae ef 79 d8 df 4f be
00c0   a6 f6 dd 74 db dd f7 bb ef 9b de b7 cf 5d 5d 7b
00d0   7d de be f6 df 73 cf 35 ee 57 4d 6d 5f 6e ef 77
00e0   ca fa f1 eb 7d cf 7d ef 7b ef 7d f6 fb cc da 2b
00f0   be ce fb df 7b a7 d7 db 1e be 9d 3d 1d dc 77 76
0100   a0 ef ea 02 69 78                              

You can see that file blocks are sent with an LDP A field of 0x1800 and a B field of 0x0000. The payload of the LDP packet starts with the file id as a 16bit integer. Here we have 0x06d9, which stands for id 1753. The next two bytes are the block number. In this case, their value is 0x0000, since this is the first block. Then the 242 byte block starts.

Since this is a bzip2 compressed file, you can see that the first bytes 0x42 0x5a 0x68 are ASCII for BZh, which is the magic number for bzip2 files. After this you have the byte 0x39 an then you have 0x314159, which, if you haven't noticed, is the first digits of the number \pi in BCD. I think this has being included in the bzip2 format to aid file carving. I think it's neat to show this. If you're interested, you can find what are the other bytes of the bzip2 header in Wikipedia.

There is not much else to say about file blocks. The receiver just has to join all the file blocks in the correct order to recover the file. This is provided it managed to get all the blocks correctly. If it has missed some of the blocks, this brings us to FEC.

FEC blocks

The idea behind FEC is simple: to take a message (in this case the whole file binary data) to be transmitted and produce from it some amount of additional information (sometimes known as FEC data). This is known as FEC encoding. Then the message and the FEC data are sent. Perhaps some parts of the message or FEC data are received with errors (some bits have changed their value) or some parts are missing. Under some conditions, the FEC decoding algorithm manages to recover the whole message even if there are errors or missing parts, by using the extra FEC data. In Outernet, the data is never received with errors, since HDLC frames are checked with their CRC-16CCITT (and LDP frames have an additional 32bit checksum). However, it's perfectly possible that there are missing file blocks if the signal was not good at times. These missing parts are known as erasures in FEC parlance. FEC is used to try to recover the whole file even in this circumstances.

The FEC data is sent in 242 byte blocks similarly to how files are sent. This is an OP packet with a FEC block.

0000   01 04 3c 02 00 00 ff 00 01 00 00 00 06 fe 01 24 
0010   41 ce b4 5b 28 9d 41 07 f7 b5 5d d8 50 61 ff e0
0020   5f 3a 85 2b 30 de 0c bf 07 04 4d 68 00 c8 00 fe
0030   01 1a 43 a3 5b 94 cd ac 76 d9 e2 69 3d f7 6b dc
0040   42 1e e8 a5 98 f6 28 6d 1b 72 f9 6f 3d fb 5a 63
0050   0b 3d e7 2d 49 52 ce 06 7f 38 e5 65 d6 85 d3 a1
0060   4b 95 8f 90 bc 49 59 46 7a 91 df fe 94 9f 88 0b
0070   fc 25 54 4c 3e 09 ae 44 4b bc b8 e6 27 5d bc 81
0080   31 68 d8 9e f6 40 51 5d 54 3e 0b 55 68 2b 4d a3
0090   91 6c bf c3 ef 2c 89 ef 28 67 3e d0 de f7 c4 91
00a0   fa 1e 58 bd 48 80 53 85 a6 29 2c d4 bb a4 8c 5f
00b0   4d 63 8f 1e 3c 17 39 b9 18 52 ee 05 a8 3f 05 6e
00c0   c1 da 03 b0 6e c9 ce f7 b2 69 ae d1 20 85 79 23
00d0   a9 f0 22 cc 79 fb 92 06 e8 9c 54 df 18 09 a4 57
00e0   a3 e6 ed 76 89 ba 85 f9 9e 11 f4 48 d7 1b 12 20
00f0   ec 50 79 b8 44 91 a2 f4 4d 64 ed 80 e1 8e 53 b4
0100   27 2c 18 c4 54 04

As you can see, FEC blocks are sent in LDP packets with an A field of 0xff00 and a B field of 0x0000. The payload of the LDP packet has the same structure as the file blocks. The first two bytes are the file id, in this case 0x06fe or 1790 and the next two bytes are the block number, in this case 0x0124, or block number 292.

The FEC codes used for Outernet produce FEC data whose size is around 20% of the size of the original file. One thing that I find curious is that all the FEC blocks are 242 bytes long (and not less), so the FEC code is arranged so that it always produces FEC data whose size is a multiple of 242 bytes (it doesn't seem that some part of the FEC data is clearly padding).

Unfortunately, that's as much as I can say about FEC. The LDPC codes used for FEC in Outernet are not so easy to reverse engineer for me. There are many different LDPC codes, so it's hard to guess which are being used, and almost every file uses a different set of parameters for its LDPC code. Also, implementing an LDPC decoder is not so trivial. For this reason, I don't intend to work in this in the near future, unless someone with more experience on LDPC codes wants to help.

The free-outernet receiver does not implement LDPC decoding. This means that you need to receive all the file blocks to recover a file completely. However, it is perfectly usable if you have a good signal. Also, the smallest files (APRS data, for instance) don't use FEC at all.

Actual data rate

One thing one can do with this knowledge of the protocols is to compute the actual bandwidth that is available to send files. The file blocks are 242 bytes long, but they are sent in 276 byte Ethernet frames. This means that there is an overhead of 12% for headers. Also, there is an overhead of 20% for FEC data. This works out to a total overhead of 30%. Since the bitrate is 2.1kbps, the actual bandwidth that is used to send files is only 1.47kbps. This amounts to 15876kB of files per day. Here 1kB = 1000B, but keep in mind that 15876kB is only 15.14MB if you use the convention that 1MB = 1024kB, 1kB = 1024B. This is noticeably less that the 20MB per day that Outernet quotes.

4 Replies to “Reverse engineering Outernet: time and file services”

  1. que buenos artículos sobre outernet, hace rato vengo observando este proyecto y usando algunas de sus tecnologías... y siempre me preguntaba como estaba encapsulada la informacion, sus artículos me ayudaron a aclarar ideas.

    deberías compartir esta info en el foro de outernet, seria interesante ver que pasa

    tengo una lighthouse(wetek play hardware) que es un dispositivo linux, este tiene un tuner DVB-S2 de rango (950~2150 MHz), seria posible usarlo en L-band , con free-outernet ???

    la pregunta mas concreta es, se puede usar un tuner DVB-S2 para recibir L-Band ?

    1. Probablemente no es posible usar un tuner DVB-S2 para recibir la señal de Outernet en banda L, ya que esta señal no es DVB-S2. La única posibilidad es que el tuner DVB-S2 permita leer muestras IQ, como hace el RTL-SDR, que originalmente es un tuner DVB-T. Veo poco probable que esto sea posible, y en cualquier caso habría que programar drivers.

      Mi consejo es que substituyas el tuner DVB-S2 por un RTL-SDR o algún otro dongle receptor SDR.

      Voy a poner un anuncio en el foro de Outernet sobre free-outernet, pero antes quiero añadir la capacidad de recibir tramas directamente de gr-outernet y recuperar archivos en tiempo real (ahora mismo hay que usar una grabación KISS).

  2. hola, gracias por responder

    ya soy usuario de outernet lband con los equipos de ellos, que se calientan mucho (la rtlsdr)

    el wetek es un linux rooteable y se conocen los drives, no se si se puedan modificar .... tampoco lo se hacer,

    según este post de outernet se puede usar el tuner del wetek play para lband pero ellos no tienen planeado el desarrollo. . . . . . . . . .
    voy a prepara un equipo con gnuradio para experimentar con gr-outernet

    gracias y que buen trabajo

    1. Dudo que se pueda usar el tuner del wetek play para recibir la señal de Outernet en banda L (en ese hilo no dice eso exactamente). La única posibilidad sería usar este equipo como un pequeño ordenador Linux y conectarle un RTL-SDR (asumo que tiene algún puerto USB).

Leave a Reply

Your email address will not be published. Required fields are marked *