Het TAK-protocol is de wire-overeenkomst waarmee ATAK, WinTAK, iTAK en TAK Server Cursor on Target-events (CoT) uitwisselen. Versie 0 stuurt het event als gewone XML; versie 1 als een protobuf-bericht met lengteprefix, ongeveer half zo groot. Dezelfde payload reist over drie transporten: serverloze UDP-multicast op de lokale mesh, persistente TCP/TLS-streams naar TAK Server (standaard poort 8089) en server-naar-serverfederatie (9000/9001).
Wie een sensor, drone of C2-systeem met het TAK-ecosysteem integreert, voelt dit onderscheid meteen: CoT is het datamodel — <event>, <point>, <detail> — terwijl het TAK-protocol bepaalt hoe die bytes op elk transport geframed, geversioneerd en onderhandeld worden. Het XML-schema zelf staat in onze gids over het Cursor on Target-formaat en de diepe duik in het CoT-schema; dit artikel is de andere helft: de verbinding.
CoT versus het TAK-protocol: datamodel versus verbindingsovereenkomst
Houd drie lagen gescheiden — de documentatie van het ecosysteem vermengt ze regelmatig:
- Het CoT-eventmodel. Eén XML-document per event: typecode, UID,
time/start/stale, een WGS-84-punt, een uitbreidbaar<detail>. De semantische inhoud, op elk transport identiek. - De codering (TAK-protocolversie). Versie 0 codeert het event als XML-tekst; versie 1 als protobuf-
TakMessage. Beide dragen dezelfde events. - Het transport. UDP-multicast op de mesh, een persistente TLS-stream naar TAK Server of een federatielink tussen servers — elk framet de payload anders.
De protocolbeschrijving die met de TAK-producten meeleevert, stelt twee grondregels: een client die versie V verstuurt, kan versie V ook decoderen, en elke client moet nog steeds XML versie 0 kunnen decoderen. Daarom blijven gemengde vlooten werken — alles valt netjes terug op XML.
TAK-protocol versie 0: gewone CoT XML
Versie 0 droeg het ecosysteem een decennium lang en is overal nog de fallback. Per transport gedraagt het zich anders:
- Mesh SA (multicast). Situational-awareness-aankondigingen zijn UDP-datagrammen naar de welbekende multicastgroep
239.2.3.1:6969— één CoT XML-event per datagram, zonder server. Elk apparaat in de groep ontvangt elk event, en er is geen hertransmissie: een verloren datagram is een verloren positiemelding. Dit is de modus achter serverloze blue force tracking op een sectie-Wi-Fi- of MANET-segment. (ATAK multicast GeoChat op een aparte groep,224.10.10.1:17012, die TAK Server als input kan opnemen.) - Gerichte berichten. Berichten naar één ontvanger gebruiken een kortstondige TCP-verbinding: verbind, verstuur één event, verbreek. Een ATAK-apparaat dat naar directe peers luistert, accepteert ze op TCP-poort 4242 — handig om één toestel zonder server van een event te voorzien.
- Stream naar TAK Server. Een persistente verbinding (meestal TLS) draagt een doorlopende stroom XML-events, elk voorafgegaan door een XML-declaratie en gevolgd door een newline. De ontvanger krijgt geen lengteprefix en geen scheidingsteken: hij knipt de stroom door op het letterlijke token
</event>en snijdt direct daarna — de volgende declaratie begint op de allereerstvolgende byte.
In de praktijk ziet de streamingvorm er zo uit (verkort):
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<event version="2.0" uid="RAVEN-1" type="a-f-G-U-C" how="m-g" …>…</event><?xml version="1.0" …?><event …>…</event>
Die token-scannende splitter is protocolgedrag, geen implementatie-eigenaardigheid — TAK Servers eigen streaming-codec documenteert het ontbreken van scheidingstekens en zoekt op de sluittag. Elke gateway moet events emitteren die zuiver knippen: complete events, declaratie voorop, niets ertussen. Geannoteerde volledige events staan in onze voorbeelden van CoT-berichten.
TAK-protocol versie 1: de protobuf-TakMessage
Versie 1 vervangt de XML-tekst door één proto3-bericht — atakmap.commoncommo.protobuf.v1.TakMessage — waarvan de definitie met de TAK-distributies meekomt en weerspiegeld is in bibliotheken zoals het Python-pakket takproto. De structuur is compact maar strikt gespecificeerd:
TakMessagebevat twee optionele delen: eenTakControl(protocolboekhouding — de min/max-versies die de zender decodeert, plus een contact-UID) en hetCotEventzelf.CotEventdraagt de envelop:type,uid,how, optioneleaccess/qos/opex, de drie tijdstempels als milliseconden sinds de Unix-epoch (sendTime,startTime,staleTime) en de puntveldenlat,lon,hae,ce,leals doubles. Onbekende hoogte of foutwaarden gebruiken de sentinel999999, net als in de XML-conventie.Detailwordt hier interessant. Zes bekende detail-elementen werden getypeerde subberichten:contact(endpoint, callsign),group(uit__group: name, role),precisionLocation(geopointsrc, altsrc),status(battery),takv(device, platform, os, version),track(speed, course). Alles andere — remarks, chat-inhouden, plugin-elementen — wordt in éénxmlDetail-string gestopt met de ruwe XML van de overige children.
Twee specificatieregels redden teams van subtiele corruptie. Ten eerste, alleen hele elementen: een detail-element wordt volledig naar zijn getypeerde bericht geconverteerd of blijft volledig in xmlDetail — nooit gesplitst, en als het niet netjes mapt, blijft het in xmlDetail. Ten tweede voegen ontvangers de getypeerde berichten weer samen tot XML, en bij conflict wint xmlDetail. Nieuwe velden mogen alleen achteraan aan bestaande berichten worden toegevoegd; alles semantische vraagt een versieverhoging. In de praktijk krimpt de protobuf-winst naarmate ongetypeerde detail groeit — precies wat je ziet bij chat- of plugin-zwaar verkeer.
Mesh- en stream-framing: de feitelijke bytes
Beide versies rijden op beide transporten; framing verschilt per transport, niet per payload:
- Mesh-datagram:
0xbf, een varint protocolversie,0xbf, dan de payload. De magic byte0xbf(191 decimaal) laat een ontvanger één datagram besnuffelen en weten of het protobuf is of legacy-XML, die begint met<— TAK Servers UDP-inputs doen precies die controle op elk datagram. - Streaming-frame:
0xbf, een varint payloadlengte in bytes, dan de payload. Geen versiebyte — de versie is één keer per verbinding onderhandeld (volgende sectie), dus herhaling per frame zou verspilling zijn.
De varints zijn standaard unsigned protobuf-varints — 7 bits per keer, minst significatief eerst, de hoogste bit markeert voortzetting, maximaal 64 bits (10 bytes). Een payload van 258 bytes codeert als 82 02; 127 is 7f, 128 is 80 01.
Omdat elk frame zijn eigen lengte draagt, is een streamparser een kleine toestandsmachine: verwacht 0xbf, verzamel de varint, buffer precies zoveel bytes, decodeer, herhaal — met partiële frames over leesacties heen. Versie 0 geeft je daar niets van; je scant tekst op </event> en hoopt dat er niets midden in een event afbreekt.
Streaming-onderhandeling: t-x-takp-v, t-x-takp-q, t-x-takp-r
Een client kan niet weten of een server protobuf spreekt, dus de omschakeling wordt binnen de verbinding onderhandeld met drie CoT-besturingsevents — zelf als XML verstuurd:
- Het aanbod (
t-x-takp-v). Een server met TAK-protocolondersteuning mag één event van dit type sturen met<detail><TakControl><TakProtocolSupport version="1"/>— één element per ondersteunde versie, hoogstens één keer per verbinding, na authenticatie als de input die vereist. - Het verzoek (
t-x-takp-q). De client kiest een versie uit het aanbod en antwoordt met<TakRequest version="1"/>, en moet daarna stoppen met XML sturen (inkomende XML blijft verwerken) en wachten — minstens een minuut voordat hij opgeeft en opnieuw verbindt. - Het antwoord (
t-x-takp-r). De server antwoordt<TakResponse status="true"/>of"false". Bijtrueschakelen beide zijden de hele verbinding om naar lengte-geframde versie-1-payloads — dezelfde versie in beide richtingen — en er vloeit geen XML meer. Bijfalseblijft de verbinding op XML en kan de client het later opnieuw proberen.
Alle drie de events delen één transactie-UID (de protouid uit de specificatie), en de dans is streng: vóór het true-antwoord verstuurde protobuf breekt op de referentieserver. Op de mesh is er geen handshake: elk apparaat broadcast minstens elke 60 seconden een TakControl-bericht met de minimale en maximale versies die het decodeert; contacts die twee minuten zwijgen vallen terug op de versie van hun laatste decodeerbare bericht; en iedereen zendt op de hoogste versie die alle bekende contacts kunnen decoderen, met terugval op XML zodra een legacy-apparaat aanwezig is. Belast de onderhandeling met tests voordat je aanneemt dat de vloot is omgeschakeld — de tuningknoppen staan in onze gids voor TAK Server-prestaties.
TAK Server-poorten: de standaardkaart
Standaardwaarden uit de configuratiegids van TAK Server 5.7 en het bijgevoegde voorbeeld-CoreConfig.xml; elk is configureerbaar, dus beschouw dit als wat een voorraadimplementatie opent, niet als een contract. De eigen firewallraad van de gids is minimaal: open 8089 en 8443.
| Poort | Protocol | Rol |
|---|---|---|
8089 | TCP/TLS | CoT-streaming-input — waar ATAK, WinTAK en gateways met clientcertificaten op verbinden |
8090 | UDP (QUIC) | Optionele QUIC-streaming-input, aanwezig in de huidige voorbeeldconfiguratie |
8087 | TCP of UDP | Ongelimiteerde CoT-input (voorbeeldinputs; alleen labgebruik) |
8088 | TCP | Streaming-TCP zonder TLS (stcp) — alleen testen |
8443 | TCP/HTTPS | Beheerinterface, REST API en WebTAK (clientcertificaat-authenticatie) |
8444 | TCP/HTTPS | Federatie-gerichte HTTPS (federatie-truststore; ophalen van mission packages) |
8446 | TCP/HTTPS | Certificaatinschrijving (CSR, HTTP Basic auth) en OAuth2-tokenendpoint |
9000 | TCP/TLS | Federation v1-listener |
9001 | TCP/TLS | Federation v2-listener (gRPC over HTTP/2) |
9002 | TCP/TLS | Federatie-tokenauthenticatie (indien ingeschakeld) |
239.2.3.1:6969 | UDP-multicast | Mesh SA-groep (clientstandaard; als serverinput te bruggen) |
Twee voetnoten. FreeTAKServer, de Python-server van het open-source-ecosysteem (zie onze gids voor het open-source TAK-ecosysteem), houdt 8089 voor CoT over TLS maar gebruikt 8087 voor kale TCP-CoT. En federatie verdient eigen lectuur: de v1-link wisselt protobuf-FederatedEvent-berichten uit achter een vierbytes-lengteprefix, terwijl v2 een gRPC-dienst draait met streaming-RPC's en health checks — behandeld in onze gids voor federatie-setup en het architectuuroverzicht van de Federation Hub.
Berichtgrootte en bandbreedte: XML versus protobuf
We codeerden twee representatieve events op beide manieren — een ATAK-achtige eigen positiemelding (getypeerde detail plus een ongetypeerd uid-element) en een kleine drone-track van een MAVLink-brug, de protobuf-kant met de referentie-Python-encoder:
| Event | CoT XML | XML in een stream (declaratie mee) | Protobuf-payload | Op de lijn (geframed) |
|---|---|---|---|---|
| ATAK-eigen positiemelding | 578 B | 634 B | 258 B | 261 B |
| Track van de dronebrug | 363 B | 419 B | 171 B | 174 B |
Een reductie van 52–59% voor deze vormen — consistent met de 55–65% die we aanhaalden in ons artikel over drone-telemetrie-integratie en met Isodes veldmetingen uit 2025 voor TAK over HF-radio: ruwweg 530-byte XML-events tegenover 376–380-byte gefedereerde protobuf-berichten, vóór compressie. Protobuf helpt het meest waar XML pure envelop is — declaraties, attribuutnamen, sluittags — terwijl detail die in xmlDetail geparkeerd is zijn XML-grootte houdt.
Waarom dat op radio telt: veertig gebruikers die zich elke tien seconden melden kosten circa 20 kbps aan gestreamde XML (634 B per stuk) tegenover circa 8 kbps aan protobuf, vóór de TLS-record-overhead per bericht. Op smalband is het effect genadeloos — bij 75 bps mat Isode 29–33 seconden end-to-end-latency voor één event. Nog één groottegedrag: de streaming-uitgang van TAK Server weigert een protobuf-TakMessage groter dan 65.536 bytes te sturen; een te groot event wordt vervangen door een kleine bestandsoverdracht-verwijzing die de client het volledige XML over HTTPS laat ophalen. Chatverkeer wordt geanalyseerd in ons artikel over de datastrategie voor tactische chat.
CoT versturen vanuit Python: TLS, certificaten, protobuf
Al het bovenstaande comprimeert tot een klein programma — de standaardbibliotheek alleen kan al een TLS-verbinding met de 8089-input openen met een clientcertificaat en versie-0-XML-events streamen, zonder dependencies:
import asyncio
import datetime as dt
import ssl
import xml.etree.ElementTree as ET
TAK_HOST, TAK_PORT = "tak.example.org", 8089 # TLS streaming input
CA_FILE, CERT_FILE, KEY_FILE = "takserver-ca.pem", "client.pem", "client.key"
def ts(t): # CoT time: ISO 8601, UTC, millisecond precision
return t.strftime("%Y-%m-%dT%H:%M:%S.") + f"{t.microsecond // 1000:03d}Z"
def cot_event(uid, cot_type, lat, lon, hae, callsign, stale_s=60):
now = dt.datetime.now(dt.timezone.utc)
ev = ET.Element("event", version="2.0", uid=uid, type=cot_type, how="m-g",
time=ts(now), start=ts(now),
stale=ts(now + dt.timedelta(seconds=stale_s)))
ET.SubElement(ev, "point", lat=f"{lat:.7f}", lon=f"{lon:.7f}",
hae=f"{hae:.1f}", ce="10.0", le="9999999.0")
ET.SubElement(ET.SubElement(ev, "detail"), "contact", callsign=callsign)
return ET.tostring(ev, encoding="utf-8", xml_declaration=False)
async def drain(reader):
# Keep reading the server (its t-x-takp-v offer, other users' SA),
# or TCP flow control eventually stalls its writes to you.
while await reader.read(65536):
pass
async def main():
ctx = ssl.create_default_context(cafile=CA_FILE) # verify server cert + name
ctx.load_cert_chain(CERT_FILE, KEY_FILE) # our client identity
reader, writer = await asyncio.open_connection(TAK_HOST, TAK_PORT, ssl=ctx)
rx = asyncio.create_task(drain(reader))
try:
while not rx.done():
writer.write(cot_event("gw-demo.uav-12", "a-f-A-M-F-Q",
50.4501234, 30.5234567, 640.0, "UAV-12"))
await writer.drain()
await asyncio.sleep(5) # report well inside stale
finally:
writer.close()
asyncio.run(main())
Drie details dragen hier alles. Asyncio-sockets zetten Nagles algoritme standaard uit, dus elk event vertrekt direct — met ruwe sockets zet je TCP_NODELAY zelf. De drain-taak is geen decoratie: een server die schrijft naar een client die nooit leest, blijft uiteindelijk steken op TCP-flowcontrol. Certificaten moeten PEM zijn: TAK Server geeft een PKCS#12-.p12 uit (wat ATAK consumeert), dat OpenSSL in drie regels omzet:
openssl pkcs12 -in gateway-01.p12 -clcerts -nokeys -out client.pem -passin pass:SECRET
openssl pkcs12 -in gateway-01.p12 -nocerts -nodes -out client.key -passin pass:SECRET
openssl pkcs12 -in truststore-root.p12 -nokeys -out takserver-ca.pem -passin pass:SECRET
Voor protobuf converteert het pakket takproto (PyPI) CoT XML naar en vanuit versie-1-payloads en voegt de framing toe; de bibliotheek PyTAK pakt de hele client in — COT_URL accepteert tls://host:8089 of udp+wo://239.2.3.1:6969, TAK_PROTO=1 kiest protobuf, en certificaten importeren rechtstreeks uit een TAK-datapakket .zip. De afweging "zelf bouwen of een bibliotheek nemen" werkt ons artikel over TAK C2-integratiepatronen uit.
Dit is waar een weekendprototype operationele werkelijkheid ontmoet: certificaatinschrijving op vlootschaal, protobuf-onderhandeling over gemengde clientversies, multicast die daadwerkelijk moet routen. Wij bouwen CoT/TAK-protocolgateways, migreren feeds van XML naar protobuf, en integreren en harden TAK Server. Vertel ons wat je moet koppelen →
Afleversemantiek, beveiliging en de valkuilen die bijten
Geen acknowledgements — het stale-tijdstip doet het werk
CoT is fire-and-forget op elke laag: geen acknowledgements per bericht, geen volgnummers, geen sessies. Versheid wordt beheerd door het stale-tijdstempel — consumers laten events daarvoor verouderen of vallen ze af — en door de cadans: verstuur ruim binnen je stale-venster of accepteer spookbeelden op de kaart. TAK Server verzacht reconnects met zijn latest SA-buffer (nieuwe clients krijgen direct de laatst bekende posities van bereikbare gebruikers), en ATAK houdt verbindingen levend met een ping (t-x-c-t) die de server met een pong (t-x-c-t-r) beantwoordt. Stuur je huidige beeld na elke reconnect opnieuw in plaats van aan te nemen dat de server het onthield.
Certificaten, groepen, kanalen
Operationeel TAK-verkeer is mutual TLS: de client verifieert de server tegen de CA van de implementatie, de server verifieert een clientcertificaat van diezelfde CA, en de CN van het certificaat wordt de gebruikersnaam voor groepstoewijzing. Groepslidmaatschap — per input, per certificaat of via LDAP-/bestandsbackends — is het hele toegangsmodel voor wie wiens tracks ziet; niet-matchende verbindingen belanden in __ANON__. Federatie gebruikt bewust een aparte truststore, zodat een partner-CA nooit stilletjes clientverbindingen autoriseert, en inschrijving draait op poort 8446 achter HTTP Basic auth. Waar een implementatie HTTP-API's nodig heeft in plaats van ruwe sockets, beschrijft onze gids voor CloudTAK API-integratie dat vlak.
De terugkerende faalmodi
- Multicast die niet aankomt: multicast wordt alleen doorgestuurd zolang de TTL het toestaat (standaard TTL 1 houdt datagrammen op het lokale segment; de voorbeeldconfiguratie van TAK Server verhoogt die naar 5), verkeerd geconfigureerde IGMP-snooping laat groepen stilletjes vallen, en multicast gaat nooit door NAT. Mesh SA is same-subnet-technologie.
- Klokafwijking: met stale-based veroudering laat een verkeerde klok óf ieders tracks verdampen óf eeuwig blijven. Synchroniseer de tijd (GNSS of NTP) voordat je iets anders debugt.
- Certificaatformatwrijving: de server spreekt JKS, de clients PKCS#12, jouw dienst PEM — en certificaten zonder het extended key usage client-auth worden al in de handshake geweigerd. Converteer bewust en test de exacte keten.
- Nagles algoritme: een batchingvertraging van 200 ms is onzichtbaar op een datacenterlink, dodelijk op een tactische. Zet het uit of batch expliciet.
- Reconnect-stormen: honderd gateways die na een radiostoring tegelijk herverbinden lijken op een DDoS. Gebruik gejitterde exponentiële backoff, herauthenticeer, speel de huidige staat in.
- Aannames over gemengde versies: één legacy-client op de mesh gooit iedereen terug op XML, en een server die nooit
t-x-takp-vaanbiedt krijgt nooit protobuf. Instrumenteer op welke codering je links zijn beland — bytes per minuut op de lijn vertelt de waarheid.
Referentiearchitectuur: een CoT-gatewayservice
Het duurzame patroon om een TAK-netwerk uit niet-TAK-systemen te voeden is een kleine, toegewijde gatewayservice, geen code die in elke bron is ingebed:
- Inkomende adapters — MAVLink, radar, AIS, GPS-trackers, REST/WebSocket-feeds — elk genormaliseerd naar een intern trackmodel.
- Een CoT-builder — één plek die het UID-beleid bezit (stabiel, namespaced, collision-bestendig), typemapping,
how-codes en stale-vensters per bron, en XML of protobuf emitteert volgens dezelfde detailregels. - Een uitgangs-superisor — een pool van geauthenticeerde TLS-verbindingen met onderhandeling (protobuf waar aangeboden, anders XML), gejitterde reconnects, rate-shaping per link voor smalbandpaden en replay van de huidige staat.
- Operationeel vlak — linkgezondheid, actieve codering, bytes per minuut en monitoring van certificaatverloop; op tactische netwerken is het protocol de eerste verdachte en het laatste geïnstrumenteerde.
Die vorm — een protocoll-getrouw rand tussen andersmans data en een TAK Server — is een component die wij bouwen voor defensieprogramma's, naast de TAKpilot-copiloot op dezelfde infrastructuur. Als jouw programma dit diagram nu tekent, haal er een team bij dat het eerder heeft geleverd.
Dit nodig op jouw netwerk?
Wij bouwen CoT/TAK-protocolgateways, migreren feeds van XML naar protobuf, en integreren en harden TAK Server — inclusief certificaten, groepen en federatie.
Opgesteld door het engineeringteam van Corvus Intelligence, dat CoT/TAK-gateways, ATAK-plugins en TAK Server-integraties bouwt voor defensieprogramma's (ISO 9001/27001-gecertificeerd, Brave1-lid). Over Corvus Intelligence →