Python • AIS NMEA 0183

AISMixer

Platformă de procesare și rutare a fluxurilor AIS

Normalizează · Deduplică · Etichetează · Rutează · Redirecționează

Combinați fluxuri AIS de la receptoare fixe, de coastă, din porturi și mobile într-un singur flux logic controlat și livrați-l către destinațiile UDP egress care au nevoie de el.

Codul-sursă al proiectului AISMixer este disponibil public sub licența CC BY-NC 4.0; licența nu permite utilizarea comercială.

Procesarea fluxurilor AIS

De la traficul receptoarelor la un flux curat, cu surse identificabile

AISMixer reunește transportul, asamblarea NMEA, metadatele, deduplicarea și livrarea într-un singur traseu de procesare aproape în timp real. Componentele sale de runtime sunt aismixer — mixerul, routerul și serverul UDPSEC; aismixerctl pentru controlul local al rutării și statisticile runtime; și nmea_sproxy — proxy-ul de la stație, de la o sursă locală UDP sau serial/USB la o destinație UDPSEC ori UDP simplu configurată explicit.

Ingress flexibil

Recepționează UDP simplu prin IPv4 sau IPv6 ori trafic de stație UDPSEC autentificat și criptat.

Extragerea propozițiilor AIS

Extrage atât !AIVDM, cât și !AIVDO din ieșirile reale ale receptoarelor și aplicațiilor.

Asamblare multipart

Asamblează fragmente sosite complet în afara ordinii în mesaje logice complete și le emite în ordinea ordinală.

Deduplicare aproape în timp real

Ia o singură decizie atomică la nivelul grupului pentru fiecare mesaj multipart complet, global în modul broadcast sau separat pentru fiecare destinație de rutare.

Metadate TAG controlate

Controlează NMEA TAG s, c și g pe tot ciclul de viață multipart, păstrând metadatele separate de identitatea de rutare.

Redirecționare selectivă

Redirecționează propozițiile acceptate către fiecare ieșire UDP configurată în modul broadcast sau către destinațiile denumite selectate prin rutare logică.

Prezentare vizuală pe scurt

Cum funcționează AISMixer

Un scurt tur vizual de la mai multe surse AIS, prin asamblare, deduplicare, gestionarea metadatelor TAG și rutare logică, până la ieșirile selectate, inclusiv nmea_sproxy și UDPSEC. Materialul video este în limba engleză.

Fundament al planului de date, pregătit pentru o implementare nativă

Procesare explicită, etape cu capacitate finită și egress unificat

Ingress-ul imuabil la nivel de octeți trece prin etape explicite, cu capacitate finită, într-un singur proces. După ce devine disponibilă capacitatea comună de procesare, fiecare cadru admis este asociat unui singur ProcessingSnapshot și procesat de PythonDataPlaneProcessor, care deține starea instanței și rămâne unicul procesor actual de producție și de referință. Acesta returnează un OutputBatch imuabil și ordonat, ale cărui valori ProcessorOutput transportă octeții exacți și ID-urile numerice ale destinațiilor prin handoff-ul egress cu capacitate finită.

Producători UDP / UDPSEC Coadă privată limitată cu IngressFrame pentru fiecare intrare
Admitere limitată la procesare Backpressure, apoi asocierea unui singur ProcessingSnapshot
PythonDataPlaneProcessor cu stare proprie Scanarea octeților, asamblare, politica TAG și deduplicare
Handoff limitat al unui OutputBatch ordonat Octeți exacți și destinații numerice explicite
Egress UDP unificat Expediere locală secvențială prin send_to_ids()

Limită ingress imuabilă

Producătorii UDP și UDPSEC integrați creează obiecte IngressFrame imuabile la nivel de octeți. Scanarea bytes-native și metadatele ParsedSentence parsate o singură dată transportă informațiile despre fragmente și TAG în procesare, fără extragere repetată.

Asocierea snapshot-ului după obținerea capacității

Capacitatea de procesare este obținută înainte ca un singur ProcessingSnapshot imuabil să fie asociat cadrului. Lucrul admis păstrează acel snapshot; cadrele care încă așteaptă capacitate pot observa o înlocuire ulterioară a rutării, locală procesului.

Procesor Python cu stare proprie

O singură instanță PythonDataPlaneProcessor cu durată lungă de viață deține starea mutabilă pentru asamblare, deduplicare, surse, metadate multipart și metricile procesorului. În prezent nu există procesor nativ sau binding-uri.

Octeți exacți în rezultate ordonate

Fiecare propoziție NMEA emisă este codificată UTF-8 o singură dată și devine un payload exact și imuabil într-un OutputBatch ordonat. Fiecare ProcessorOutput conține ID-uri numerice explicite ale destinațiilor; fragmentele multipart rămân payload-uri separate.

Backpressure și finalizare ordonată

Când o limită ingress privată, o limită comună de procesare sau limita egress atinge capacitatea, execuția așteaptă în loc să elimine elementul din coadă. Un lot nevid împiedică procesarea cadrelor următoare până la finalizarea expedierii locale secvențiale. Aceasta nu oferă persistență sau confirmarea livrării la distanță, iar UDP rămâne un transport cu pierderi.

Ciclu de viață fail-fast local procesului

Etapele asyncio esențiale au un singur ciclu de viață supravegheat, local procesului. Un eșec sau o finalizare neașteptată anulează și așteaptă task-urile surori. Nu există repornire automată, reîncercare, rollback, confirmare a livrării sau replay.

Aveți nevoie de semantica exactă a cazurilor marginale? Citiți contractul comportamental.

Responsabilitate explicită pentru ciclul de viață

Stare deterministă sub sarcină

Implementarea de referință face explicite starea păstrată, progresul duratei de viață, admiterea în capacitate, curățarea și observarea, fără a depinde de comportamentul accidental al containerelor.

Starea deduplicării

Identitatea este propoziția exactă sau tuplul multipart ordonat, într-o sferă globală ori separată pentru fiecare destinație. TTL-ul este determinist, duplicatele nu reîmprospătează păstrarea, iar intrările expirate sunt eliminate înaintea evacuării celei mai vechi intrări active.

Obiectul Python acceptă parametrul opțional max_entries; integrarea actuală a serviciului îl lasă la None, astfel încât această dimensiune este nelimitată în serviciul actual.

Starea asamblării multipart

Fragmentele ocupă poziții ordinale. Progresul unic reîmprospătează durata de viață a grupului; un duplicat exact nu o face. Conflictul, expirarea, eliminarea din cauza capacității, finalizarea și resetarea rămân rezultate distincte ale ciclului de viață și curăță contextul TAG asociat.

Obiectul Python acceptă parametrii opționali max_fragments_per_group și max_pending_groups; integrarea actuală a serviciului îi lasă pe amândoi la None.

Protecție anti-replay și sesiuni securizate

Înregistrările anti-replay pentru handshake, sesiunile în așteptare și active, precum și registrul de nonce-uri DATA al fiecărei epoci de chei au limite stricte de capacitate; în timpul unei reîmprospătări a epocii de chei în sesiune, o sesiune are cel mult trei epoci active. Durata de viață a handshake-urilor și a sesiunilor folosește TTL-uri monotone. Fiecare nonce DATA admis rămâne însă memorat pe toată durata utilizabilă a epocii sale, fără TTL independent și fără eliminare. Epuizarea registrului epocii curente eșuează în mod sigur (fail-closed) și încheie sesiunea, iar recuperarea folosește un handshake autentificat nou; epuizarea unei epoci în așteptare sau în retragere elimină numai acea epocă. Starea migrării căii este limitată la un candidat și o cale retrasă pentru fiecare sesiune.

Un candidat în așteptare înlocuiește numai un candidat mai vechi pentru aceeași relație dintre listenerul fizic și peer și păstrează orice sesiune activă până când confirmarea criptată autentificată reușește. Sesiunile aceluiași peer pe listenere UDPSEC fizice separate sunt izolate unele de altele; limitele agregate de capacitate rămân la nivelul procesului. Toată starea securizată rămâne numai în memorie, este locală procesului și se pierde la repornire.

Stare observabilă a componentelor și runtime-ului

Proprietarii stării de deduplicare, asamblare și securitate expun snapshot-uri interne și imuabile ale ciclului de viață. Runtime-ul oferă separat vizualizări pull-based proaspete asupra cozilor, activității procesorului și egress-ului și traficului de intrare și de ieșire. Citirea oricărui tip de snapshot nu modifică starea procesării.

Aceste vizualizări sunt locale procesului și nepersistente; nu reprezintă metrici distribuite sau un sistem de export Prometheus/time-series.

Locală prin proiectare. Această stare este nepersistentă și nu este partajată între procese. Runtime-ul actual supraveghează task-urile asyncio esențiale într-un singur proces; procesele coordonator/worker, IPC și sincronizarea stării între procese nu există încă.

Pregătirea pentru workeri — implementată

Limite pregătite pentru workeri într-un singur proces

Runtime-ul Python actual are limite observabile și cu capacitate finită în jurul etapelor de procesare. Starea mutabilă de procesare are un proprietar explicit la nivel de instanță, lucrul este admis numai când există capacitate, iar statisticile pull-based proaspete fac vizibilă activitatea etapelor fără să o modifice.

Ingress privat și limitat

Fiecare intrare UDP sau UDPSEC configurată are propria coadă limitată, astfel încât elementele acumulate de o intrare să nu consume capacitatea privată a alteia.

Admitere numai când există capacitate

Admiterea comună la procesare are capacitate finită. Un cadru primește ProcessingSnapshot imuabil numai după obținerea capacității, iar când capacitatea este atinsă, execuția așteaptă prin backpressure.

Stare deținută de instanța procesorului

O singură instanță a procesorului deține starea mutabilă pentru asamblare, deduplicare, surse, metadate multipart și metricile procesorului, în spatele unei limite explicite a ciclului de viață.

Egress limitat și ordonat

Un handoff limitat transportă fiecare OutputBatch nevid către expedierea locală secvențială. Bariera de finalizare păstrează ordinea procesării, dar nu confirmă primirea la distanță.

Observabilitate runtime pull-based

Snapshot-urile proaspete și imuabile acoperă starea cozilor și backpressure, activitatea procesorului și egress-ului, traficul de intrare brut și admis și mesajele și octeții pentru fiecare destinație.

Pregătirea pentru workeri este implementată; procesele worker nu sunt. Serviciul actual folosește încă un singur proces cu etape asyncio supravegheate. Nu există un coordonator, procese worker ingress sau egress separate, multiprocessing, IPC, rutare sau agregare de metrici între procese ori repornire și recuperare automată a workerilor. În prezent nu există procesor nativ sau binding-uri.

Rutare și zone logice

Exprimați politica fluxului prin identitățile surselor

Rutarea logică statică leagă surse ingress denumite de destinații UDP egress denumite, prin seturi reutilizabile de surse și rute ordonate. Numele rămân interfața de configurare și control, iar potrivirea din calea de producție folosește un plan numeric precompilat care conține numai destinațiile și le păstrează ordinea.

Ingress denumitSurse UDP și UDPSEC
Zone logiceSeturi de identități ale surselor
Rute ordonateSelectarea declarativă a destinațiilor
Egress denumitDestinații UDP selectate

Seturi compozabile de surse

Definiți zone cu include, union, intersection și difference.

Logice, nu geografice

Zonele sunt seturi de identități interne ale surselor, nu regiuni pe hartă, filtre MMSI, filtre pentru nave sau reguli aplicate payload-ului.

Ordine păstrată și calitate pentru fiecare destinație

Modul de rutare aplică deduplicarea separat pentru fiecare destinație logică, astfel încât o cale de expediere să nu o suprime pe alta. Ordinea configurată a destinațiilor se păstrează în expedierea secvențială.

Numele rămân interfața operatorilor. ID-urile numerice ale destinațiilor sunt locale procesului și nu sunt valori de configurare. Identificatorul source_id rămâne separat de valoarea NMEA TAG s emisă în aval.

Control local și observabilitate runtime

Controlați rutarea și inspectați activitatea runtime

Planul local opțional de control, printr-un socket POSIX din domeniul Unix, oferă operații de rutare și statistici runtime read-only agregate, per intrare și per ieșire, prin comanda aismixerctl instalată global.

Stare și modificări atomice ale rutării

Inspectați generația activă, zonele, rutele și destinațiile; înlocuiți un snapshot validat sau dezactivați rutarea pentru a reveni la modul legacy broadcast. Verificările opționale ale generației resping actualizările învechite.

Statistici runtime agregate

runtime.statistics raportează starea cozilor limitate și backpressure, activitatea procesorului și activitatea egress-ului într-o singură interogare pull proaspătă și locală procesului.

Trafic de intrare și de ieșire

runtime.statistics.inputs separă traficul de transport de cadrele acceptate. runtime.statistics.outputs raportează expedierile locale, mesajele și octeții pentru fiecare destinație.

Interfață locală pentru operatori

Folosiți aismixerctl pentru modificări locale ale rutării și inspecția read-only a activității runtime, cu ieșire lizibilă pentru operatori și JSON pentru automatizări one-shot.

Limita statisticilor read-only. Statisticile sunt păstrate în memorie, sunt locale procesului, nepersistente și se resetează la repornire. Nu reprezintă istoric persistent, metrici distribuite sau un sistem Prometheus/time-series. Expedierea UDP locală reușită nu reprezintă confirmarea livrării la distanță.

Control intenționat local. Rutele runtime nu persistă după repornire, fișierele de configurare nu sunt rescrise, iar adaptoarele nu sunt create dinamic. Permisiunile socketului Unix reprezintă limita actuală de autorizare; nu există token de control la nivelul aplicației.

Controlul punctelor terminale de rețea

Limitați sursele permise și adresele-sursă de ieșire

Controalele simple la nivelul aplicației facilitează integrarea punctelor terminale IPv4 și IPv6 în politica mai largă de firewall și rutare a operatorului.

Ingress allow_from

Limitați listener-ele UDP și UDPSEC la adrese IP literale sau rețele CIDR, inclusiv printr-o regulă explicită de blocare totală.

Adresă de ieșire source_ip

Asociați un socket egress cu o adresă-sursă IPv4 sau IPv6 literală și limitați rezolvarea destinației la aceeași familie de adrese.

Parte a unei limite stratificate

Aceste politici completează regulile de firewall și rutare ale sistemului de operare; nu le înlocuiesc.

source_ip reprezintă asocierea unei adrese-sursă, nu selectarea interfeței, a tabelei de rutare, marcarea socketului sau SDN.

Transportul securizat UDPSECv2

Transport autentificat cu stare locală limitată

UDPSEC este transportul UDP autentificat și criptat, specific proiectului AISMixer, dintre stațiile cu nmea_sproxy și serviciul aismixer. Sursa actuală implementează UDPSECv2: identități ECDSA P-256 pe termen lung configurate, stabilire semnată prin ECDHE efemer P-256 cu dovada criptată a posesiei cheilor prin confirmarea cu secvența zero, DATA protejat cu AES-256-GCM, protecție anti-replay, liveness autentificat, reîmprospătarea epocii de chei în sesiune și migrare autentificată a căii. UDPSECv2, inclusiv funcțiile de continuitate a sesiunii, face parte din versiunea semnată v0.3.0 a codului sursă și este livrat în pachetele OpenWrt semnate 0.3.0-r1.

ClientHello autentificat Semnat cu cheia de identitate, cu o cheie efemeră P-256 nouă
ECDHE efemer P-256 Secret comun nou pentru acest handshake
HKDF-SHA256 Chei C2S și S2C independente
Confirmare criptată cu secvența zero Ping C2S, apoi pong S2C
Sesiune activă Ping-ul autentificat promovează; pong-ul autentificat finalizează

Acord efemer autentificat al cheilor

La fiecare stabilire a unei sesiuni, fiecare endpoint generează o pereche nouă de chei efemere P-256 pentru ECDHE. Cheile P-256 de identitate pe termen lung autentifică numai schimbul, prin semnături ECDSA peste digesturi SHA-256 canonice ale transcriptului, distincte pentru fiecare rol; ele nu participă la acordul de chei ECDHE.

HKDF-SHA256 derivă chei C2S și S2C independente din secretul comun și transcriptul autentificat. AES-256-GCM protejează datele și traficul de control criptat.

Confirmare reciprocă criptată

Clientul confirmă sesiunea în așteptare printr-un ping C2S criptat cu secvența zero. Serverul o promovează numai după autentificarea ping-ului și răspunde cu un pong criptat cu secvența zero folosind cheia S2C a sesiunii promovate; clientul consideră sesiunea stabilită numai după autentificarea acelui pong.

Datagramele fără legătură, malformate, criptate cu o cheie veche sau care au secvența ori sursa greșită nu confirmă candidatul și nici nu prelungesc termenul-limită fix de confirmare.

Sesiuni, epoci de chei și fără revenire automată

O sesiune este legată de stația autentificată și identificată printr-un locator de sesiune emis de mixer, niciodată prin adresa IP și portul sursă. După confirmare, mesajele NMEA DATA, ping/pong-ul keepalive, controlul din sesiune și închiderea best-effort sunt autentificate și criptate, iar fiecare pachet este legat de sesiunea și epoca sa de chei. Receptoarele păstrează fiecare nonce admis pe durata epocii sale și resping repetările.

Cu session_refresh_interval peste zero, stația reînnoiește cheile de trafic în cadrul aceleiași sesiuni, printr-un schimb ECDHE semnat nou; aceasta nu este nici o sesiune nouă, nici o schimbare de cale. UDPSEC nu are resetare în clar, recuperare NOSESSION, control de downgrade sau revenire automată la UDP simplu și nu memorează și nu retransmite payload-uri NMEA. Starea securizată a sesiunilor și protecției anti-replay rămâne numai în memorie, este locală procesului, nepersistentă și se pierde la repornire.

Actualizați ambele endpoint-uri împreună: UDPSECv2, folosit de versiunea v0.3.0 și de pachetele OpenWrt actuale 0.3.0-r1, nu este compatibil cu versiunile anterioare, inclusiv cu v0.2.1 și cu pachetele OpenWrt anterioare 0.2.1-r4.

Forward secrecy, în limitele implementate: compromiterea ulterioară a unei chei de identitate pe termen lung nu permite, prin ea însăși, reconstruirea cheilor sesiunilor deja încheiate, dacă vechile chei private efemere și secretele ECDHE brute nu mai există și niciun endpoint nu a fost compromis cât timp acestea se aflau în memorie. Compromiterea actuală a unei chei de identitate permite uzurparea identității în sesiuni viitoare. Această proprietate implementată este susținută de validare inginerească, nu de verificare criptografică formală.

Limita transportului: UDPSEC autentifică și criptează pachetele de date și de control în domeniul său, dar nu dovedește identitatea sau poziția navei, originea fizică ori absența spoofing-ului AIS, nu garantează livrarea sau ordinea UDP, nu protejează endpoint-uri compromise și nu oferă rezistență completă la atacuri de refuz al serviciului. Nu ascunde adresele IP ale participanților, temporizarea sau lungimile pachetelor și nici identificatorul stației din ClientHello, transmis în clar.

Citiți politica de securitate, contractul comportamental, ghidul nmea_sproxy și Wiki-ul pentru limitele detaliate.

Continuitate mobilă

Păstrarea sesiunii stației în cazul pierderilor mobile obișnuite

UDPSEC funcționează prin NAT și CGNAT. Stațiile mobile pierd pachete, iar adresa lor IP publică sau portul UDP se pot schimba. Testele de teren au arătat că un handover celular păstrează adesea aceeași adresă publică și același port, astfel încât UDPSECv2 tratează o pierdere temporară diferit de o schimbare reală de adresă.

Pierdere scurtă pe aceeași cale

Recuperarea liveness. Stația retrimite, cu o rată limitată, singurul său ping keepalive fără răspuns, cu același număr de secvență și cu o criptare nouă de fiecare dată, până când sosește un răspuns autentificat. Un singur schimb pierdut nu încheie sesiunea; singura limită terminală este peer_timeout după ultima dovadă autentificată.

Adresă publică nouă cât timp sesiunea este activă

Migrare autentificată a căii. O adresă nouă nu este considerată de încredere automat: pachetele ei trebuie să se autentifice cu cheile curente ale sesiunii. Serviciul aismixer trimite apoi o verificare (challenge) către acea adresă și își mută răspunsurile acolo numai după ce răspunsul autentificat al stației sosește de la ea. Verificarea este trimisă de cel mult patru ori în total, la cel puțin 2 secunde distanță, într-o fereastră fixă de 10 secunde; retrimiterile îmbunătățesc livrarea, dar nu acordă autoritate.

Întrerupere lungă sau terminală

Stabilire autentificată nouă. Odată atinsă limita de liveness, stația efectuează un handshake semnat nou, iar serviciul aismixer elimină singur vechea sesiune inactivă.

Limitat, nu fără pierderi. Redirecționarea continuă cât timp liveness-ul este incert, dar UDPSEC nu memorează și nu retransmite niciodată date NMEA: propozițiile trimise în timpul unei întreruperi se pot pierde chiar și atunci când sesiunea supraviețuiește, iar nicio sesiune nu supraviețuiește oricărei întreruperi. Recuperarea liveness pe aceeași cale a fost observată într-un test real pe drum, cu un build de dezvoltare anterior; migrarea căii a trecut teste end-to-end și de securitate într-o rețea simulată, dar o migrare reușită nu a fost încă observată într-un test de teren. Ambele mecanisme sunt incluse în versiunea v0.3.0.

nmea_sproxy și receptoare AIS fizice

Conectați receptoare AIS de rețea sau fizice prin nmea_sproxy

nmea_sproxy este proxy-ul de la stație care conectează o singură intrare AIS locală, UDP, serială fizică ori serială virtuală prin USB, la o singură ieșire de rețea: UDPSEC sau UDP simplu configurat explicit.

Receptor AIS fizic
port serial sau dispozitiv serial virtual prin USB
nmea_sproxy
UDPSEC sau UDP simplu pe o rețea declarată explicit ca fiind de încredere
Ieșire de rețea aismixer prin UDPSEC sau un consumator prin UDP simplu, într-o rețea de încredere

Intrări locale implementate

  • UDP de la un receptor local conectat la rețea sau de la o aplicație AIS.
  • Intrare serială fizică prin nmea_sproxy, inclusiv dispozitive seriale virtuale prin USB puse la dispoziție de sistemul de operare.

Ieșiri implementate

  • UDPSEC autentificat și criptat: proxy-ul autentifică mixerul și este autentificat de acesta, participă la verificarea liveness, răspunde la verificările autentificate ale căii, rulează opțional reîmprospătarea epocii de chei în sesiune și, după o pierdere terminală, trece la un handshake autentificat nou.
  • UDP simplu explicit pentru o rețea LAN, un VPN sau o limită echivalentă declarată de încredere.

Model clar al relației

O intrare locală este asociată unei singure ieșiri configurate. Fiecare potrivire AIS NMEA acceptată este redirecționată fără blocuri TAG de intrare, prefixe, octeți din jur și terminatori. nmea_sproxy nu mixează, nu distribuie către mai multe ieșiri, nu rutează, nu deduplică și nu asamblează AIS multipart, iar deciziile de migrare a căii aparțin serviciului aismixer.

Un receptor de rețea poate trimite UDP local către nmea_sproxy sau direct către serviciul aismixer, în funcție de instalare. Procesul principal al serviciului aismixer nu citește direct porturi seriale. UDP-ul simplu folosit într-o zonă declarată de încredere nu oferă criptare UDPSEC, autentificare, protecție anti-replay sau verificarea activității.

Implementare OpenWrt la marginea rețelei

Rulați serviciul aismixer sau serviciul nmea_sproxy pe OpenWrt

OpenWrt este o țintă de implementare la marginea rețelei acceptată atât pentru serviciul aismixer, cât și pentru nmea_sproxy. Depozitul AISMixer APK semnat pentru OpenWrt 25.12 publică în prezent versiunea 0.3.0-r1 a pachetelor Python/procd, construită din versiunea v0.3.0, pentru arhitecturile x86_64 și mips_24kc. Fișierele semnate ale pachetelor anterioare 0.2.1-r4 rămân disponibile după numele exact al fișierului pentru o revenire explicită la versiunea anterioară, dar nu mai sunt listate în indexurile depozitului.

Pachete semnate

Instalați aismixer sau nmea_sproxy. Dependența comună aismixer-common este adăugată automat la instalarea oricăruia dintre cele două pachete.

Indexuri de depozit publicate:

Ambele arhitecturi folosesc aceeași cheie publică a depozitului; instalați-o în /etc/apk/keys/ înainte de a folosi oricare dintre cele două indexuri.

SHA-256 al cheii: 170d30219e0e05d59898cd8ccd5ec9804e915df7882ab56b8e869ef6e99c8f9c

Două roluri la marginea rețelei

Serviciul aismixer poate rula pe un dispozitiv periferic sau router cu OpenWrt. nmea_sproxy poate rula independent lângă un receptor cu intrare UDP sau serială. Ieșirea poate fi UDP simplu, iar UDPSEC poate proteja legătura de rețea către serviciul aismixer.

nmea_sproxy acceptă intrare serială fizică, inclusiv dispozitive seriale virtuale prin USB puse la dispoziție de sistemul de operare. Dispozitivele CDC ACM apar de obicei ca /dev/ttyACM*, iar adaptoarele USB-UART ca /dev/ttyUSB*. Driverul de nucleu necesar poate fi deja inclus în imaginea OpenWrt; în caz contrar, poate fi necesar pachetul kmod corespunzător, de exemplu kmod-usb-acm pentru CDC ACM. UART-ul nativ și intrarea UDP nu necesită un driver serial USB.

Încredere UDPSEC explicită

Pachetele nu includ chei private. Fluxul init OpenWrt al serviciului aismixer pregătește identitatea locală și, când există o cheie privată validă, poate reface cheia publică pereche. nmea_sproxy poate crea perechea canonică a stației numai când ambele fișiere lipsesc; o pereche de chei a proxy-ului parțială, invalidă sau neconcordantă produce un refuz fail-closed fără înlocuire automată. Încrederea UDPSEC este întotdeauna configurată manual: instalați cheia publică aismixer la stație și autorizați cheia publică a stației în aismixer.

Arhitectura pachetului. PKGARCH:=all descrie payload-ul Python și shell independent de arhitectură; nu face pachetul disponibil în feed-ul fiecărei arhitecturi. Feed-urile construite, semnate și publicate în prezent sunt x86_64 și mips_24kc, fără a exclude intenționat alte ținte potrivite. Selectați arhitectura feed-ului configurat pe dispozitiv; nu o determinați folosind apk --print-arch.

Spațiu disponibil pentru scriere. Runtime-ul Python și dependențele necesită considerabil mai mult spațiu disponibil pentru scriere decât o instalare OpenWrt minimală. Verificați spațiul liber din overlay înainte de instalare; extroot este o opțiune de implementare OpenWrt atunci când spațiul intern disponibil pentru scriere este limitat.

Siguranță la prima pornire. Hook-urile pachetului activează și pornesc aismixer în timpul instalării, iar configurația inclusă inițial conține listenere UDP simple cu acces larg. Aplicați în prealabil reguli de firewall sau izolare de rețea și verificați spațiul disponibil pentru scriere. Opriți serviciul imediat după instalare, configurați listenerele și autorizarea UDPSEC, apoi porniți-l și verificați-l.

# Feed-uri publicate în prezent: x86_64 sau mips_24kc
AISMIXER_ARCH='x86_64'

wget -O /etc/apk/keys/aismixer-openwrt.pem \
  https://aismixer.net/openwrt/keys/aismixer-openwrt.pem

REPO_FILE=/etc/apk/repositories.d/customfeeds.list
REPO_URL="https://aismixer.net/openwrt/25.12/${AISMIXER_ARCH}/packages.adb"

grep -qxF "$REPO_URL" "$REPO_FILE" 2>/dev/null || {
  printf '\n# AISMixer OpenWrt 25.12 %s repository\n%s\n' \
    "$AISMIXER_ARCH" "$REPO_URL" >> "$REPO_FILE"
}

apk update
apk add aismixer
/etc/init.d/aismixer stop
vi /etc/aismixer/config.yaml
vi /etc/aismixer/authorized_keys.yaml
/etc/init.d/aismixer start
/etc/init.d/aismixer status
logread -e aismixer

Versiunea pachetelor. Pachetele 0.3.0-r1 sunt o revizie de pachet a versiunii v0.3.0 a codului sursă, nu o versiune separată a codului sursă, și includ UDPSECv2 cu continuitatea mobilă a sesiunilor. Formatul lor de transmisie UDPSEC nu este compatibil cu cel al build-urilor v0.2.1, inclusiv al pachetelor anterioare 0.2.1-r4: folosiți aceeași linie de versiune la ambele capete ale unei relații UDPSEC. Verificați revizia pachetului, notele versiunii v0.3.0, lista de modificări și versiunile publicate.

Actualizare și revenire la versiunea anterioară. aismixer și nmea_sproxy necesită exact aismixer-common=0.3.0-r1, așa că apk le actualizează împreună atunci când ambele sunt instalate. O stație care are doar nmea_sproxy nu are nevoie de aismixer; specificați numai pachetele instalate, deoarece apk add instalează orice pachet specificat, iar hook-ul acestuia îl activează și îl pornește. Această fixare locală a versiunii nu verifică compatibilitatea UDPSEC dintre dispozitive. Fișierele de configurare editate se păstrează, iar fișierele implicite din pachetul care se instalează sunt salvate alături ca .apk-new, pentru verificare; cele needitate pot fi înlocuite. Păstrați cheile de identitate și, după fiecare actualizare sau revenire, verificați ca fiecare stație și mixerul ei să folosească același port UDPSEC (noua valoare implicită este 17779). Hook-urile de actualizare și de revenire doar pornesc serviciile, așa că un serviciu aflat în execuție poate rula în continuare codul vechi, iar unul oprit intenționat poate porni: reporniți serviciile care trebuie să ruleze și opriți din nou orice serviciu care trebuie să rămână oprit. Indexurile listează acum doar 0.3.0-r1; pentru revenire, folosiți numai fișiere de pachet semnate pentru care apk verify raportează OK înainte de utilizare: fie fișiere salvate în prealabil, fie fișierele arhivate 0.2.1-r4 descărcate după numele exact al fișierului. Nu folosiți niciodată --allow-untrusted și readuceți împreună la versiunea anterioară capetele UDPSEC. Consultați README pentru procedura completă.

Validare cap la cap. Calea de implementare pentru mips_24kc a unei linii anterioare de pachete a fost validată cap la cap cu intrare AIS serială fizică, nmea_sproxy, UDPSEC autentificat, procesare prin serviciul aismixer, funcționarea serviciilor prin procd, control local și observabilitate runtime. Acest rezultat precedă 0.3.0-r1 și nu validează, prin el însuși, noua linie de pachete sau funcțiile sale de continuitate UDPSECv2 în condiții reale.

Doar punctul terminal de lângă receptor. Folosiți apk add nmea_sproxy în loc de apk add aismixer pentru a instala independent proxy-ul de la stație. Consultați README, ghidul nmea_sproxy și ghidul de implementare OpenWrt pentru pașii compleți de implementare și configurare a încrederii.

Implementare și operare pentru familia Debian

Un ciclu de viață pentru familia Debian și systemd, conceput pentru instalări reale

Pentru gazde Debian și Raspberry Pi OS cu systemd, implementarea gestionată din depozit menține aliniate fișierele de runtime, starea operatorului, controlul local al rutării și statisticile runtime read-only. OpenWrt folosește calea APK/procd descrisă mai sus.

Serviciu systemd gestionat din depozit

Serviciul aismixer creează /run/aismixer cât timp rulează și acceptă socketul local opțional de control.

Instalare, actualizare și dezinstalare

Scripturile pentru ciclul de viață gestionează rularea ca root sau prin sudo și întrețin fișierele runtime și unitățile de serviciu instalate. Updaterul aismixer repornește serviciul și poate porni un serviciu inactiv; updaterul nmea_sproxy reîncarcă systemd, dar nu pornește și nu repornește instanțele proxy. Actualizați stațiile UDPSEC împreună cu mixerul. Consultați README și ghidul nmea_sproxy.

Starea operatorului este păstrată

Fluxurile normale de instalare, actualizare și dezinstalare păstrează configurația operatorului și cheile criptografice.

CLI global pentru operatori

Fluxul de instalare plasează aismixerctl în /usr/local/bin pentru rutare runtime locală și statistici read-only.

Documentație și starea proiectului

Funcționalitățile implementate sunt separate clar de pașii următori

README-ul din depozit este prezentarea generală actuală a proiectului pentru operatori, contractul comportamental definește semantica exactă, iar Wiki-ul conține ghiduri mai detaliate de arhitectură și implementare. Roadmap-ul separă fundamentul finalizat de activitatea viitoare fără a promite termene.

Starea versiunilor. Ultima versiune etichetată este v0.3.0, care include UDPSECv2 și continuitatea mobilă a sesiunilor descrisă mai sus. Pachetele OpenWrt publicate (0.3.0-r1) sunt construite din v0.3.0. Modificările ulterioare din main, inclusiv modificările de împachetare deja incluse în 0.3.0-r1, sunt descrise în secțiunea Unreleased din lista de modificări.

Implementat acum

  • Valori IngressFrame imuabile la nivel de octeți, scanare bytes-native, metadate parsate o singură dată și PythonDataPlaneProcessor ca unic procesor actual de producție și de referință.
  • Cozi ingress private și limitate, admitere comună și limitată la procesare, handoff egress limitat, backpressure, starea deținută de instanța procesorului și asocierea ProcessingSnapshot la admitere.
  • Rutare compilată bazată numai pe destinații numerice, octeți exacți și imuabili codificați o singură dată pentru fiecare propoziție emisă, rezultate OutputBatch ordonate și o barieră locală și ordonată de finalizare egress.
  • Zone logice și deduplicare per destinație, actualizări atomice ale rutării locale procesului, aismixerctl interactiv și statistici read-only agregate, per intrare și per ieșire.
  • Asamblare multipart deterministă, gestionarea TAG s/c/g și deduplicare globală sau per destinație.
  • UDPSEC cu ECDHE efemer P-256 autentificat, identități ECDSA P-256 pe termen lung configurate, chei AES-256-GCM direcționale proaspete, confirmarea criptată a posesiei cheilor, date și verificări ale activității autentificate și criptate, închidere best-effort autentificată și criptată, protecție anti-replay DATA pe întreaga epocă a cheii, stare limitată fail-closed și izolarea sesiunilor pe listener fizic.
  • Inclusă în versiunea v0.3.0: continuitatea sesiunilor UDPSECv2 — recuperarea liveness pe aceeași cale, migrarea autentificată a căii cu dovada rutabilității de retur și reîmprospătarea epocii de chei în sesiune.
  • Pentru fiecare proces sau instanță systemd nmea_sproxy, o intrare UDP sau serială spre o ieșire UDPSEC ori o ieșire plain-UDP configurată explicit pentru o rețea de încredere, plus controale endpoint IPv4/IPv6.
  • Implementare pentru familia Debian cu RuntimeDirectory systemd, scripturi pentru ciclul de viață care gestionează privilegiile, păstrarea stării operatorului și CLI global pentru operatori, alături de implementarea APK/procd semnată pentru OpenWrt 25.12, publicată pentru x86_64 și mips_24kc (0.3.0-r1, construită din v0.3.0).

Activități planificate

  • Consolidarea suplimentară a implementării operaționale, de exemplu proprietatea explicită a socketului de control și validarea pe Linux și Raspberry Pi.
  • Un proces coordonator cu procese worker ingress și egress separate, IPC și supraveghere între procese, iar ulterior un procesor nativ în spatele contractelor stabilite, cu verificare diferențială a conformității; în prezent nu există o astfel de implementare și nu se afirmă rezultate de performanță.
  • Operații asupra stării rutării, precum persistența opțională, reîncărcarea sigură a configurației și istoricul pentru rollback.
  • Cercetare privind securitatea maritimă și calitatea datelor, inclusiv detectarea spoofing-ului și a anomaliilor AIS, care nu este implementată în prezent.
  • Extindere ulterioară, precum adaptoare de ieșire suplimentare și control la distanță autentificat.

Comunitatea proiectului

Comunitate și contact

Alegeți canalul public potrivit conversației. Discussions, Ideas și Q&A îi ajută și pe alți utilizatori, iar defectele reproductibile trebuie raportate în Issues. Contactul privat rămâne disponibil în profilul responsabilului de întreținere de mai jos.

Explorați discuțiile

Explorați conversațiile publice despre proiect, anunțurile, experiențele de implementare, testele în teren și alte subiecte ale comunității.

Explorați GitHub Discussions

Propuneți o idee

GitHub Discussions este potrivit pentru propuneri de arhitectură, idei de integrare, experiențe de implementare, testare AIS în teren și colaborări academice sau de cercetare care pot fi discutate public.

Deschideți Ideas

Raportați o problemă

Folosiți GitHub Issues pentru defecte reproductibile și activități concrete în depozitul proiectului, nu pentru corespondență privată generală.

Deschideți GitHub Issues

Adresați o întrebare în Q&A

Folosiți Q&A pentru întrebări concrete despre instalare, configurare, utilizare, arhitectură și operare.

Deschideți Q&A

Fondator și responsabil de întreținere

Iliyan Iliev, PhD

Fondator, inițiator și responsabil de întreținerea AISMixer

Dezvoltator și cercetător în sisteme backend și de rețea, interesat de procesarea AIS/NMEA, securitatea maritimă și regională, transport și turism.

Dezvoltare asistată de IA: ChatGPT sprijină analiza arhitecturală, planificarea, documentația și revizuirea. OpenAI Codex sprijină analiza depozitului, implementarea, testarea și validarea. Anthropic Claude Code sprijină revizuirea depozitului, preluarea implementării, verificarea încrucișată, testarea și validarea. Aceste instrumente sunt utilizate sub conducerea fondatorului; deciziile și responsabilitatea finală pentru proiect rămân umane.