Protocolul TAK este contractul de legătură cu care ATAK, WinTAK, iTAK și TAK Server schimbă evenimente Cursor on Target (CoT). Versiunea 0 trimite evenimentul ca XML simplu; versiunea 1 ca mesaj protobuf cu prefix de lungime, de aproximativ două ori mai mic. Aceeași încărcătură călătorește pe trei transporturi: multicast UDP fără server în mesh-ul local, fluxuri TCP/TLS persistente către TAK Server (implicit portul 8089) și federație server-la-server (9000/9001).

Dacă integrați un senzor, un dronă sau un sistem C2 cu ecosistemul TAK, distincția contează imediat: CoT este modelul de date — <event>, <point>, <detail> — în timp ce protocolul TAK definește cum acești octeți sunt încadrați, versionați și negociați pe fiecare transport. Schema XML în sine este tratată în ghidul nostru de format Cursor on Target și în analiza aprofundată a schemei CoT; acest articol este cealaltă jumătate: legătura.

CoT vs. protocolul TAK: model de date vs. contract de legătură

Țineți separate trei straturi — documentația ecosistemului le amestecă în mod constant:

  • Modelul de eveniment CoT. Un document XML per eveniment: cod de tip, UID, time/start/stale, un punct WGS-84, un <detail> extensibil. Conținutul semantic, identic pe toate transporturile.
  • Codificarea (versiunea protocolului TAK). Versiunea 0 codează evenimentul ca text XML; versiunea 1 ca TakMessage protobuf. Ambele poartă aceleași evenimente.
  • Transportul. Multicast UDP în mesh, un flux TLS persistent către TAK Server sau o legătură de federație între servere — fiecare încadrează încărcătura diferit.

Descrierea protocolului distribuită cu produsele TAK stabilește două reguli de bază: un client care trimite versiunea V știe să și decodifice versiunea V, iar fiecare client trebuie încă să decodifice XML-ul versiunii 0. De aceea parcurile mixte continuă să funcționeze — totul coboară lin spre XML.

Diagramă a transporturilor protocolului TAK: dispozitivele ATAK, WinTAK și iTAK împart multicast UDP fără server pe 239.2.3.1:6969; dispozitivele sau un gateway CoT transmite în flux către TAK Server prin TLS mutual pe portul 8089; serverul federa cu un al doilea TAK Server pe porturile 9000 și 9001; fluxurile de senzori și C2 sunt convertite în CoT de serviciul gateway.
Transporturile protocolului TAK: multicast mesh fără server, flux TLS mutual către TAK Server (8089) și federație server-la-server (9000/9001), cu un gateway CoT care alimentează serverul.

Protocolul TAK versiunea 0: CoT XML simplu

Versiunea 0 a purtat ecosistemul în primul său deceniu și rămâne peste tot varianta de rezervă. Se comportă diferit pe fiecare transport:

  • Mesh SA (multicast). Anunțurile de conștientizare situațională sunt datagrame UDP trimise către grupul multicast bine cunoscut 239.2.3.1:6969 — un eveniment CoT XML per datagramă, fără niciun server. Fiecare dispozitiv din grup primește fiecare eveniment, iar retransmisie nu există: o datagramă pierdută este un raport de poziție pierdut. Acesta este modul din spatele blue force tracking-ului fără server pe un segment Wi-Fi de echipă sau MANET. (ATAK face multicast pentru GeoChat pe un grup separat, 224.10.10.1:17012, pe care TAK Server îl poate prelua ca intrare.)
  • Mesaje direcționate. Mesajele către un singur destinatar folosesc o conexiune TCP de scurtă durată: conectare, trimiterea unui eveniment, deconectare. Un dispozitiv ATAK care ascultă peeri direcți le acceptă pe portul TCP 4242 — util pentru a injecta un eveniment într-un singur terminal fără server.
  • Flux către TAK Server. O conexiune persistentă (de obicei TLS) poartă un flux continuu de evenimente XML, fiecare precedat de o declarație XML și urmat de un salt de rând. Receptorul nu primește nici prefix de lungime, nici delimitator: taie fluxul căutând tokenul literal </event> și secționând imediat după el — următoarea declarație începe pe chiar următorul octet.

În practică, forma de flux arată astfel (abreviat):

<?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>

Acest splitter prin scanarea tokenului este comportament de protocol, nu o ciudățenie de implementare — codecul de flux al TAK Server însuși documentează absența delimitatorilor și caută eticheta de închidere. Orice gateway trebuie să emită evenimente care se taie curat: evenimente complete, declarația prima, nimic între ele. Evenimente complete adnotate găsiți în exemplele noastre de mesaje CoT.

Protocolul TAK versiunea 1: TakMessage protobuf

Versiunea 1 înlocuiește textul XML cu un singur mesaj proto3 — atakmap.commoncommo.protobuf.v1.TakMessage — a cărui definiție vine cu distribuțiile TAK și este reflectată în biblioteci precum pachetul Python takproto. Structura este compactă, dar strict specificată:

  • TakMessage conține două părți opționale: un TakControl (evidența protocolului — versiunile min/max decodate de expeditor, plus un UID de contact) și CotEvent-ul propriu-zis.
  • CotEvent poartă plicul: type, uid, how, access/qos/opex opționale, cele trei marcări de timp în milisecunde de la epoca Unix (sendTime, startTime, staleTime) și câmpurile punctului lat, lon, hae, ce, le ca double. Înălțime sau erori necunoscute folosesc valoarea sentinelă 999999, ca în convenția XML.
  • Detail — aici devine interesant. Șase elemente de detail bine cunoscute au devenit submesaje tipizate: contact (endpoint, callsign), group (din __group: name, role), precisionLocation (geopointsrc, altsrc), status (battery), takv (device, platform, os, version), track (speed, course). Tot restul — remarks, corpuri de chat, elemente de plugin — este înghesuit într-un singur string xmlDetail cu XML-ul brut al copiilor rămași.

Două reguli ale specificației salvează echipele de o corupere subtilă. În primul rând, doar elemente întregi: un element de detail este convertit integral în submesajul său tipizat sau rămâne integral în xmlDetail — niciodată tăiat, iar dacă nu se mapează curat, rămâne în xmlDetail. În al doilea rând, receptorii fuzionează submesajele tipizate înapoi în XML, iar la conflict câștigă xmlDetail. Câmpuri noi se pot adăuga doar la sfârșitul mesajelor existente; orice semantică nouă cere o versiune nouă. În practică, câștigul protobuf se subțiază pe măsură ce detail-ul netipizat crește — exact ce vedeți pe trafic bogat în chat sau plugin-uri.

Încadrarea în mesh și în flux: octeții concreți

Ambele versiuni circulă pe ambele transporturi; încadrarea diferă după transport, nu după încărcătură:

  • Datagramă mesh: 0xbf, un varint cu versiunea protocolului, 0xbf, apoi încărcătura. Octetul magic 0xbf (191 în zecimal) îi permite unui receptor să „mirosească” o datagramă și să știe dacă e protobuf sau XML legacy, care începe cu < — intrările UDP ale TAK Server fac exact această verificare pe fiecare datagramă.
  • Cadru de flux: 0xbf, un varint cu lungimea încărcăturii în octeți, apoi încărcătura. Fără octet de versiune — versiunea a fost negociată o dată pe conexiune (secțiunea următoare), așa că repetarea ei per cadru ar fi risipă.

Varint-urile sunt varint-uri protobuf standard fără semn — câte 7 biți odată, cel mai puțin semnificativ prima, bitul cel mai înalt marchează continuarea, maximum 64 de biți (10 octeți). O încărcătură de 258 de octeți se codează 82 02; 127 este 7f, 128 este 80 01.

Diagramă a dispunerii octeților pentru încadrarea TAK: o datagramă UDP mesh ca 0xbf, varint de versiune, 0xbf, apoi încărcătura protobuf TakMessage; un cadru de flux TCP sau TLS ca 0xbf urmat de un varint de lungime și încărcătura; iar evenimentele XML versiunea 0 tăiate pe tokenul de închidere event.
Încadrarea TAK v1: antetul mesh repetă octet magic, versiune, octet magic; antetul fluxului este octet magic plus un varint de lungime; versiunea 0 poartă XML brut tăiat pe tokenul de închidere event.

Fiindcă fiecare cadru își poartă propria lungime, un parser de flux este o mică mașină de stări: așteaptă 0xbf, acumulează varint-ul, bufferați exact atâția octeți, decodează, repetă — cărând cadre parțiale între citiri. Versiunea 0 nu vă oferă nimic din toate astea; scanați textul după </event> și sperați că nimic nu se taie în mijlocul unui eveniment.

Negocierea fluxului: t-x-takp-v, t-x-takp-q, t-x-takp-r

Un client nu poate ști dacă un server vorbește protobuf, deci comutarea se negociază în interiorul conexiunii cu trei evenimente de control CoT — ele însele trimise ca XML:

  1. Oferta (t-x-takp-v). Un server care susține protocolul TAK poate trimite un eveniment de acest tip purtând <detail><TakControl><TakProtocolSupport version="1"/> — un element per versiune susținută, cel mult o dată pe conexiune, după autentificare când intrarea o cere.
  2. Cererea (t-x-takp-q). Clientul alege o versiune din ofertă și răspunde cu <TakRequest version="1"/>, apoi trebuie să înceteze trimiterea de XML (procesând în continuare XML-ul de intrare) și să aștepte — cel puțin un minut înainte de a renunța și a se reconecta.
  3. Răspunsul (t-x-takp-r). Serverul răspunde <TakResponse status="true"/> sau "false". La true, ambele părți comută întreaga conexiune pe încărcături versiunea 1 încadrate prin lungime — aceeași versiune în ambele direcții — și nu mai curge niciun XML. La false, conexiunea rămâne pe XML, iar clientul poate reîncerca mai târziu.

Toate cele trei evenimente împart un UID de tranzacție (protouid-ul specificației), iar dansul e strict: protobuf trimis înainte de răspunsul true se rupe la serverul de referință. În mesh nu există handshake: fiecare dispozitiv difuzează un mesaj TakControl cel puțin la 60 de secunde, declarând versiunile minimă și maximă pe care le decodează; contactele tăcute două minute revin la versiunea ultimului lor mesaj decodabil; și toată lumea transmite la versiunea cea mai mare pe care o pot decodifica toate contactele cunoscute, cu revenire la XML de îndată ce apare un dispozitiv legacy. Testați negocierea sub sarcină înainte de a presupune că parcul s-a comutat — pârghiile de reglaj sunt în ghidul nostru de performanță TAK Server.

Porturile TAK Server: harta implicită

Valori implicite din ghidul de configurare TAK Server 5.7 și din CoreConfig.xml-ul său exemplu; fiecare este configurabil, deci priviți asta ca pe ce deschide o implementare standard, nu ca pe un contract. Propriul sfat de firewall al ghidului e minim: deschideți 8089 și 8443.

PortProtocolRol
8089TCP/TLSIntrarea de flux CoT — unde se conectează cu certificate client ATAK, WinTAK și gateway-urile
8090UDP (QUIC)Intrare de flux QUIC opțională, prezentă în configurația exemplu actuală
8087TCP sau UDPIntrare CoT necriptată (intrări exemplu; doar pentru laborator)
8088TCPFlux TCP fără TLS (stcp) — doar pentru teste
8443TCP/HTTPSInterfața de administrare, API REST și WebTAK (autentificate cu certificat client)
8444TCP/HTTPSHTTPS orientat spre federație (stocul de încredere al federației; descărcarea mission package)
8446TCP/HTTPSÎnregistrarea certificatelor (CSR, HTTP Basic auth) și endpoint-ul de tokenuri OAuth2
9000TCP/TLSAscultător federație v1
9001TCP/TLSAscultător federație v2 (gRPC peste HTTP/2)
9002TCP/TLSAutentificarea tokenurilor de federație (dacă e activată)
239.2.3.1:6969UDP multicastGrupul mesh SA (implicit client; puntabil ca intrare de server)

Două note de subsol. FreeTAKServer, serverul Python al ecosistemului open source (vezi ghidul nostru al ecosistemului TAK open source), păstrează 8089 pentru CoT peste TLS, dar folosește 8087 pentru CoT TCP simplu. Iar federația merită o lectură separată: legătura v1 schimbă mesaje protobuf FederatedEvent în spatele unui prefix de lungime de patru octeți, în timp ce v2 rulează un serviciu gRPC cu RPC-uri de flux și verificări de sănătate — tratate în ghidul nostru de configurare a federației și în prezentarea arhitecturii Federation Hub.

Dimensiunea mesajelor și lățimea de bandă: XML vs. protobuf

Am codificat două evenimente reprezentative în ambele feluri — un raport de poziție proprie în stil ATAK (detail tipizat plus un element uid netipizat) și o pistă mică de dronă de la un pod MAVLink, partea protobuf fiind codificată de encoderul Python de referință:

EvenimentCoT XMLXML în flux (cu declarație)Încărcătură protobufPe legătură (încadrat)
Raport de poziție proprie ATAK578 O634 O258 O261 O
Pistă de la podul de dronă363 O419 O171 O174 O

O reducere de 52–59% pentru aceste forme — consecventă cu cele 55–65% citate în articolul nostru despre integrarea telemetriei de drone și cu măsurătorile de teren Isode din 2025 pentru TAK peste radio HF: evenimente XML de aproximativ 530 de octeți versus mesaje protobuf federație de 376–380 de octeți, înainte de compresie. Protobuf ajută cel mai mult acolo unde XML-ul este plic pur — declarații, nume de atribute, etichete de închidere — în timp ce detail-ul parcat în xmlDetail își păstrează dimensiunea XML.

De ce contează la radio: patruzeci de utilizatori care se autopoziționează la fiecare zece secunde costă aproximativ 20 kbps în XML în flux (câte 634 O) față de aproximativ 8 kbps în protobuf, înainte de suprasarcina de înregistrare TLS per mesaj. Pe bandă îngustă efectul e brutal — la 75 bps, Isode a măsurat 29–33 de secunde de latență end-to-end pentru un singur eveniment. Încă un comportament de dimensiune: ieșirea de flux a TAK Server refuză să trimită un TakMessage protobuf mai mare de 65.536 de octeți; un eveniment supradimensionat este înlocuit cu un mic indicator de transfer de fișier care îi spune clientului să preia XML-ul complet prin HTTPS. Traficul de chat este analizat în articolul nostru despre strategia datelor pentru chatul tactic.

Trimiterea CoT din Python: TLS, certificate, protobuf

Toate cele de mai sus se comprimă într-un program mic — doar biblioteca standard poate deschide o conexiune TLS către intrarea 8089 cu un certificat client și poate transmite evenimente XML versiunea 0, fără dependențe:

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())

Trei detalii duc totul aici. Socket-urile asyncio dezactivează implicit algoritmul lui Nagle, deci fiecare eveniment pleacă imediat — pe socket-uri brute, setați TCP_NODELAY singuri. Sarcina drain nu e decorativă: un server care scrie către un client ce nu citește niciodată se blochează până la urmă pe controlul de flux TCP. Certificatele trebuie să fie PEM: TAK Server emite un PKCS#12 .p12 (ce consumă ATAK), pe care OpenSSL îl convertește în trei linii:

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

Pentru protobuf, pachetul takproto (PyPI) convertește CoT XML în încărcături versiunea 1 și invers și adaugă încadrarea; biblioteca PyTAK înfășoară întreg clientul — COT_URL acceptă tls://host:8089 sau udp+wo://239.2.3.1:6969, TAK_PROTO=1 alege protobuf, iar certificatele se importă direct dintr-un pachet de date TAK .zip. Calculul „construiești singur sau adopți o bibliotecă” este dezvoltat în articolul nostru despre tiparele de integrare C2 cu TAK.

Aici un prototip de weekend întâlnește realitatea operațională: înregistrarea certificatelor la scara parcului, negocierea protobuf între versiuni client mixte, multicast care trebuie efectiv să ruteze. Construim gateway-uri de protocol CoT/TAK, migrăm fluxuri din XML în protobuf și integrăm și întărim TAK Server. Spuneți-ne ce trebuie să conectați →

Semantica livrării, securitatea și capcanele care mușcă

Fără confirmări — treaba o face stale

CoT este fire-and-forget la fiecare nivel: fără confirmări per mesaj, fără numere de secvență, fără sesiuni. Prospețimea este gestionată de marcajul temporal stale — consumatorii îmbătrânesc sau aruncă evenimentele trecute de el — și de cadență: trimiteți clar în interiorul ferestrei voastre stale sau acceptați fantome pe hartă. TAK Server atenuează reconectările cu bufferul său latest SA (clienții noi primesc imediat ultimele poziții cunoscute ale utilizatorilor accesibili), iar ATAK menține conexiunile vii cu un ping (t-x-c-t) la care serverul răspunde cu un pong (t-x-c-t-r). Retrimiteți imaginea curentă după orice reconectare în loc să presupuneți că serverul și-a amintit-o.

Certificate, grupuri, canale

Traficul TAK operațional este TLS mutual: clientul verifică serverul față de CA-ul implementării, serverul verifică un certificat client de la același CA, iar CN-ul certificatului devine numele de utilizator pentru atribuirea în grupuri. Apartenența la grupuri — per intrare, per certificat sau prin backend-uri LDAP/fișiere — este întregul model de control al accesului la cine vede pistele cui; conexiunile fără potrivire aterizează în __ANON__. Federația folosește deliberat un stoc de încredere separat, astfel încât CA-ul unui partener să nu autorizeze niciodată tăcut conexiuni client, iar înregistrarea rulează pe portul 8446 în spatele HTTP Basic auth. Unde o implementare are nevoie de API-uri HTTP în loc de socket-uri brute, suprafața respectivă este descrisă în ghidul nostru de integrare a API-ului CloudTAK.

Modurile de defectare recurente

  • Multicast care nu ajunge: multicastul înaintează doar cât permite TTL (TTL-ul implicit 1 ține datagramele pe segmentul local; configurația exemplu a TAK Server îl urcă la 5), un IGMP snooping greșit configurat aruncă grupuri în tăcere, iar multicastul nu traversează niciodată NAT. Mesh SA este tehnologie de același subnet.
  • Deriva ceasului: cu îmbătrânire pe bază de stale, un ceas greșit fie evaporă pistele tuturor, fie le lasă pe veci. Sincronizați timpul (GNSS sau NTP) înainte de a depana orice altceva.
  • Frecarea formatelor de certificate: serverul vorbește JKS, clienții PKCS#12, serviciul vostru PEM — iar certificatele fără utilizarea extinsă a cheii client-auth sunt respinse deja la handshake. Convertiți conștient și testați lanțul exact.
  • Algoritmul lui Nagle: o întârziere de grupare de 200 ms e invizibilă pe o legătură de datacenter, letală pe una tactică. Dezactivați-l sau grupați explicit.
  • Furtunile de reconectare: o sută de gateway-uri reconectându-se deodată după o pană de radio par un DDoS. Folosiți backoff exponențial cu jitter, reautentificați-vă, redați starea curentă.
  • Presupuneri despre versiuni mixte: un singur client legacy din mesh coboară pe toți înapoi în XML, iar un server care nu oferă niciodată t-x-takp-v nu primește niciodată protobuf. Instrumentați pe ce codare s-au așezat legăturile voastre — octeții pe legătură pe minut spun adevărul.

Arhitectura de referință: un serviciu gateway CoT

Tiparul durabil pentru a alimenta o rețea TAK din sisteme non-TAK este un mic serviciu gateway dedicat, nu cod înglobat în fiecare sursă:

  • Adaptoare de intrare — MAVLink, radar, AIS, trackere GPS, fluxuri REST/WebSocket — fiecare normalizat către un model intern de pistă.
  • Un constructor CoT — un singur loc care deține politica de UID (stabile, cu spațiu de nume, rezistente la coliziuni), maparea tipurilor, codurile how și ferestrele stale per sursă, emițând XML sau protobuf după aceleași reguli de detail.
  • Un supraveghetor de ieșire — un pool de conexiuni TLS autentificate cu negociere (protobuf când e oferit, altfel XML), reconectare cu jitter, modelarea ratei per legătură pentru trasee înguste și redarea stării curente.
  • Suprafață operațională — sănătatea legăturilor, codarea în uz, octeți pe minut și monitorizarea expirării certificatelor; pe rețelele tactice protocolul este primul suspectat și ultimul instrumentat.

Această formă — o margine fidelă protocolului între datele altcuiva și un TAK Server — este o componentă pe care o construim pentru programe de apărare, alături de copilotul TAKpilot pe aceeași infrastructură. Dacă programul vostru desenează acest diagramă chiar acum, aduceți o echipă care a mai livrat una.

Aveți nevoie de asta în rețeaua voastră?

Construim gateway-uri de protocol CoT/TAK, migrăm fluxuri din XML în protobuf și integrăm și întărim TAK Server — inclusiv certificate, grupuri și federație.

Construiți-vă gateway-ul CoT → Vezi TAKpilot →

Pregătit de echipa de inginerie Corvus Intelligence, care construiește gateway-uri CoT/TAK, plugin-uri ATAK și integrări TAK Server pentru programe de apărare (certificat ISO 9001/27001, membru Brave1). Despre Corvus Intelligence →