Ingress flexibil
Recepționează UDP simplu prin IPv4 sau IPv6 ori trafic de stație UDPSEC autentificat și criptat.
Platformă de procesare și rutare a fluxurilor AIS
Normalizează · Deduplică · Etichetează · Rutează · Redirecționează
Recepționați fluxuri AIS, transformați traficul receptoarelor î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
AISMixer reunește transportul, asamblarea NMEA, metadatele, deduplicarea și livrarea într-un singur traseu de procesare aproape în timp real. Ecosistemul AISMixer include serviciul aismixer pentru procesarea și rutarea fluxurilor, nmea_sproxy, aismixerctl, transportul securizat, instrumentele de implementare și componentele conexe.
Recepționează UDP simplu prin IPv4 sau IPv6 ori trafic de stație UDPSEC autentificat și criptat.
Extrage atât !AIVDM, cât și !AIVDO din ieșirile reale ale receptoarelor și aplicațiilor.
Asamblează fragmente sosite complet în afara ordinii în mesaje logice complete și le emite în ordinea ordinală.
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.
Controlează NMEA TAG s, c și g pe tot ciclul de viață multipart, păstrând metadatele separate de identitatea de rutare.
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
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 din campaniile C–F, pregătit pentru o implementare nativă
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ă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ă.
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.
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.
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.
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.
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ță
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.
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.
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.
Înregistrările anti-replay pentru handshake, precum și sesiunile în așteptare și active, au TTL-uri monotone și limite stricte de capacitate. Fiecare nonce DATA admis rămâne însă memorat pentru întreaga epocă utilizabilă a cheii de trafic direcționale, fără TTL independent și fără eliminare cât timp acea epocă rămâne utilizabilă. Epuizarea invalidează în mod sigur (fail-closed) numai epoca de cheie afectată; recuperarea folosește un handshake autentificat nou, cu chei direcționale proaspete.
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.
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ă.
Campania F — implementată
Campania F a finalizat limitele observabile și cu capacitate finită din jurul runtime-ului Python actual. 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.
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.
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.
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ță.
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ță.
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
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.
Definiți zone cu include, union, intersection și difference.
Zonele sunt seturi de identități interne ale surselor, nu regiuni pe hartă, filtre MMSI, filtre pentru nave sau reguli aplicate payload-ului.
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
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.
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.
runtime.statistics raportează starea cozilor limitate și backpressure, activitatea procesorului și activitatea egress-ului într-o singură interogare pull proaspătă și locală procesului.
runtime.statistics.inputs separă traficul de transport de cadrele acceptate. runtime.statistics.outputs raportează expedierile locale, mesajele și octeții pentru fiecare destinație.
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
Controalele simple la nivelul aplicației facilitează integrarea punctelor terminale IPv4 și IPv6 în politica mai largă de firewall și rutare a operatorului.
Limitați listener-ele UDP și UDPSEC la adrese IP literale sau rețele CIDR, inclusiv printr-o regulă explicită de blocare totală.
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.
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.
Ciclul de viață UDPSEC
Traseul UDPSEC actual din codul-sursă dintre nmea_sproxy și serviciul aismixer folosește identități ECDSA P-256 pe termen lung configurate, ECDHE efemer P-256 semnat, chei AES-256-GCM direcționale proaspete și dovada criptată a posesiei cheilor prin confirmarea cu secvența zero înainte ca clientul să considere stabilită o sesiune nouă.
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.
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.
Ambele endpoint-uri trebuie actualizate împreună. După confirmare, mesajele NMEA DATA, schimburile ping/pong pentru verificarea activității și închiderea best-effort sunt autentificate și criptate. O verificare a activității rămasă fără răspuns sau reîmprospătarea planificată opțională a sesiunii pornește proactiv un handshake ECDHE semnat nou, cu chei direcționale proaspete; UDPSEC nu memorează și nu retransmite payload-uri NMEA în timpul recuperării.
Recuperarea folosește un handshake autentificat nou. UDPSEC nu are resetare în clar, recuperare NOSESSION, control de downgrade sau revenire automată la UDP simplu. Pachetele DATA pentru sesiuni vechi necunoscute sunt ignorate fără răspuns de recuperare în clar. Starea securizată a sesiunilor și protecției anti-replay rămâne numai în memorie, este locală procesului, nepersistentă și se pierde la repornire.
UDPSEC funcționează prin NAT sau CGNAT cât timp adresa și portul sursă observate de server rămân stabile. Reasocierea adresei sau portului ori schimbarea rețelei necesită un handshake autentificat nou; sesiunea existentă nu este migrată automat.
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.
nmea_sproxy și receptoare AIS fizice
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.
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.
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
Depozitul AISMixer APK semnat pentru OpenWrt 25.12 publică versiunea 0.2.1-r1 a pachetelor Python/procd pentru arhitecturile x86_64 și mips_24kc.
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
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.
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, publicate și validate î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.2.1-r1 publicate folosesc o revizie fixată a sursei și pot rămâne în urma modificărilor ulterioare din main. Verificați revizia pachetului, lista de modificări și versiunile publicate înainte de a presupune că sunt incluse consolidări mai noi.
Validare cap la cap. Calea de implementare pentru mips_24kc 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.
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
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.
Serviciul aismixer creează /run/aismixer cât timp rulează și acceptă socketul local opțional de control.
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. Consultați README și ghidul nmea_sproxy.
Fluxurile normale de instalare, actualizare și dezinstalare păstrează configurația operatorului și cheile criptografice.
Fluxul de instalare plasează aismixerctl în /usr/local/bin pentru rutare runtime locală și statistici read-only.
Documentație și starea proiectului
Wiki-ul este ghidul detaliat pentru arhitectură, configurare, rutare, securitate și operare. Roadmap-ul separă fundamentul finalizat de activitatea viitoare fără a promite termene.
Comunitatea proiectului
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 conversațiile publice despre proiect, anunțurile, experiențele de implementare, testele în teren și alte subiecte ale comunității.
Explorați GitHub DiscussionsGitHub 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 IdeasFolosiți GitHub Issues pentru defecte reproductibile și activități concrete în depozitul proiectului, nu pentru corespondență privată generală.
Deschideți GitHub IssuesFolosiți Q&A pentru întrebări concrete despre instalare, configurare, utilizare, arhitectură și operare.
Deschideți Q&AFondator și responsabil de întreținere
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.