← Blog

· 15 min branja #rust#mqtt#iot#unikernel#odprta koda

urMQTT: gradimo MQTT posrednik, ki je hkrati operacijski sistem

Razvojni zapiski o urMQTT, unikernelu, napisanem v Rustu, ki je sam po sebi MQTT posrednik: en ELF z lastnim TCP/IP, TLS 1.3, posrednikom in SQLite, zagnan z enega ISO-a.

Naprave v vozilih, na parkiriščih in v elektronskih omarah imajo eno skupno lastnost: pošiljajo majhna sporočila, redko, a jih je veliko in so nenehno povezane. Že leta jih povezujemo z MQTT posredniki in že leta nas muči isto vprašanje. Zakaj za nekaj tako preprostega potrebujemo cel Linux, OpenSSL, izvajalno okolje nekega jezika, SSH, upravitelj paketov in šele nato posrednika? Vsaka od teh plasti prinaša svoje ranljivosti, porablja svoj pomnilnik in dodaja še eno stvar, ki se lahko pokvari, flota naprav pa od strežnika potrebuje le troje: da drži veliko skoraj nedejavnih povezav, da vsako napravo zanesljivo overi in da sporočila prenese brez izgub.

Tako je nastal urMQTT: unikernel, ki je MQTT posrednik. Jedro, TCP/IP, TLS 1.3, MQTT in vgrajena podatkovna baza v enem Rustovem binarnem programu, ki se zažene z enega ISO-a. Ni procesov, ni sistemskih klicev, ni lupine. Prva platforma, na kateri se gradi in preizkuša, je aarch64, isto kodo pa pripravljamo za x86_64, prek UEFI in klasičnega BIOS-a, ter za pravo strojno opremo: cilj je en ISO, ki se zažene na vseh. Projekt je odprtokoden pod licenco MIT ali Apache 2.0, v tem besedilu pa želimo zapisati, kje smo, kako je zgrajen znotraj in česa smo se med delom naučili.

Kaj natančno pomeni »unikernel«

Običajen posrednik je program, ki teče na operacijskem sistemu. urMQTT pod sabo nima operacijskega sistema: sam se zažene prek UEFI firmwara in zagonskega nalagalnika Limine, vzpostavi lastne tabele strani, programira krmilnik prekinitev in časovnik, prek PCIe poišče naprave virtio, naslov pridobi z DHCP in posluša na enih vratih. Vse, kar bi sicer počeli jedro, gonilniki, omrežni sklad in aplikacija, je tu en ELF, ki teče na ravni EL1.

Primerjava s tipično namestitvijo govori sama zase:

Tipičen posrednik na Linuxu urMQTT
Izpostavljene storitve SSH, posrednik, pogosto tudi vrata za metrike ali administracijo samo TCP 8883 (MQTT prek TLS 1.3 z mTLS)
Koda v sliki jedro, uporabniški prostor, libc, OpenSSL, izvajalno okolje en Rustov ELF (plus vendoriran SQLite)
Oddaljeno upravljanje lupina, konfiguracijske datoteke, posodobitve paketov nič. Nova različica je nov ISO
Pomnilnik na nedejavno povezavo kilobajti (medpomnilniki vtičnic, objekti TLS, kopica) cilj ≤ 512 B
Večjedrni model niti in ključavnice ali ena zanka dogodkov nit na jedro, brez skupnega stanja, obdelava do konca
Celovitost kode možne so preslikave, ki so hkrati zapisljive in izvršljive W^X, zaklenjene tabele strani, PAC/BTI

Prednostne naloge so v tem vrstnem redu: varnost, razširljivost, večjedrna zmogljivost, majhen odtis in nespremenljiva namestitev. Kadar sta dva cilja v navzkrižju, zmaga tisti, ki je na tem seznamu višje.

Kje smo zdaj

Projekt je v predalfa fazi, vendar je zaprtih sedemnajst razvojnih mejnikov, od M0 do M17. Danes urMQTT streže MQTT 3.1.1 prek TLS 1.3 z obveznimi odjemalskimi certifikati, stanje pa hrani v SQLite na surovem disku. Na kratko, kaj že deluje:

  • Jedro: lastni vektorji izjem z dekodiranimi poročili, lastne tabele strani z uveljavljenim W^X, zaščitne strani, PAC in BTI, kjer ju procesor ima, GICv3 in GICv2, generični časovnik, SMP do 64 jeder.
  • Odkrivanje strojne opreme iz DTB ali ACPI v en opis platforme, z enakim rezultatom iz obeh virov.
  • Gonilniki: PCIe ECAM, MSI-X, virtio-net, virtio-blk, virtio-scsi in virtio-rng ter CSPRNG, zasejan s strojno entropijo.
  • Omrežje: lasten DHCPv4, ARP, ICMP in strogi IPv4, nato lasten TCP samo za strežniško stran: piškotki SYN, hierarhično kolo časovnikov, NewReno, združevanje ACK-jev, brez stanja TIME_WAIT.
  • TLS: samo TLS 1.3, obvezni mTLS, identiteta naprave iz CN ali SAN URI; rokovanje opravi rustls, nato pa lasten sloj zapisov z AES-128-GCM in ChaCha20-Poly1305. Nadaljevanje seje s PSK-vstopnicami, seznam preklicev, nadzor sprejema že pri rokovanju.
  • MQTT: kodek brez kopiranja, fuzziran in testiran s pravimi odjemalci mosquitto; QoS 0 in 1, nadomestni znaki, obdržana sporočila, oporoka (LWT), trajne seje, ACL z omejitvijo na devices/{id}/#, omejitve hitrosti po napravi.
  • Shranjevanje: SQLite znotraj jedra prek VFS nad surovim diskom, v načinu WAL, s preverjanjem celovitosti ob zagonu; register naprav, preklici, obdržana sporočila, trajne seje z vrstami sporočil za naprave, ki niso povezane; za vsako jedro ločen telemetrijski dnevnik s CRC na zapis in obnovitvijo po sesutju.
  • Delovanje in nadzor: nadzorni časovnik za obdelovalce, preverjanje zdravja, omejeno beleženje, syslog in statsd prek UDP, sprejem, ki preživi nevihte ponovnih povezav.
  • Dostava: bitno enake ponovne izgradnje, preverjene v CI, ISO in surova GPT slika diska, podpisi minisign, navodila za KVM, Proxmox in Hetzner.

Vsak korak je označen z mejnikom, ki ga je prinesel, datoteka docs/PROGRESS.md v repozitoriju pa je edini vir resnice o tem, kaj res deluje.

Arhitektura v treh slikah

Celoten načrt je opisan v docs/ARCHITECTURE.md, razlogi za vsako pomembnejšo odločitev pa so zapisani kot ADR-ji v docs/DECISIONS.md. Tu je pregled.

Plasti

Plasti urMQTT: od posrednika prek kodeka MQTT, TLS, TCP in omrežja do gonilnikov virtio in arhitekturne plasti, vse v enem ELF-u na ravni EL1.
Plasti urMQTT: od posrednika prek kodeka MQTT, TLS, TCP in omrežja do gonilnikov virtio in arhitekturne plasti, vse v enem ELF-u na ravni EL1.

Od vrha navzdol: posrednik (seje, drevo tem, QoS, obdržana sporočila, oporoke, ACL, omejitve), kodek MQTT, TLS, TCP, omrežna plast in nato gonilniki. Ob tej glavni poti stoji shranjevanje (SQLite in telemetrijski dnevnik), pod vsem pa upravljanje pomnilnika, odkrivanje platforme in konfiguracija, ki je ob izgradnji prevedena v konstante, skupaj z vgrajenim certifikatom CA, strežniškim certifikatom in ključem. Hipervizor z napravami virtio je edino, kar je zunaj slike.

Nit na jedro, brez skupnega stanja

Model izvajanja: vsako podatkovno jedro ima svojo zanko in svoj del posrednika, najvišje jedro pa poganja samo SQLite. Jedra komunicirajo izključno z obroči SPSC.
Model izvajanja: vsako podatkovno jedro ima svojo zanko in svoj del posrednika, najvišje jedro pa poganja samo SQLite. Jedra komunicirajo izključno z obroči SPSC.

Vsako podatkovno jedro poganja lastno zanko z lastnim skladom TCP, stanji TLS, delom posrednika (seje in drevo tem), predpomnilnikom kopice in particijo telemetrije. Jedra ne delijo nobenega spremenljivega stanja, le omejene obroče brez ključavnic, po enega za vsak urejen par jeder. Najvišje jedro poganja SQLite in nič drugega.

Omrežna kartica ima danes en par vrst, ki ga drži jedro 0. To vsak tok MQTT glede na Toeplitzev hash njegove četverice usmeri na eno od delovnih jeder in pošlje tisto, kar delovna jedra vrnejo. Seja živi na svojem domačem jedru, določenem s hashem identifikatorja odjemalca, zato prevzem, oporoke in trajnost nikoli ne prečkajo jeder. Povezava, ki pristane na drugem jedru, tam obdrži svoj TCP in TLS, navaden MQTT pa posreduje domačemu jedru z nadzorom pretoka, ki temelji na kreditih. Vsako usmerjeno sporočilo se razdeli tudi na preostale dele posrednika, od katerih vsak drži repliko obdržanih sporočil.

Ta model drže skupaj tri pravila. Obdelava do konca: prejeti paket se v celoti obdela na enem jedru, od TCP prek dešifriranja TLS na mestu, razčlenjevanja MQTT in usmerjanja do šifriranega odgovora, brez vrst opravil in brez kopiranja v aplikacijske medpomnilnike. Prilagodljivo poizvedovanje: pod obremenitvijo se vrste za sprejem aktivno poizvedujejo, v mirovanju pa se jedro vrne k prekinitvam in WFI; obdelovalci prekinitev prekinitev le potrdijo in označijo delo. Nadzorni časovnik: utrip na 10 ms na jedro ujame obdelovalce, ki presežejo svoj proračun.

Življenje enega PUBLISH-a

Pot enega sporočila PUBLISH s QoS 1: od zapisa TLS na omrežni kartici prek dešifriranja, preverjanja ACL in usmerjanja do PUBACK-a, združenega s TCP ACK v enem segmentu.
Pot enega sporočila PUBLISH s QoS 1: od zapisa TLS na omrežni kartici prek dešifriranja, preverjanja ACL in usmerjanja do PUBACK-a, združenega s TCP ACK v enem segmentu.

Naprava pošlje zapis TLS. Omrežna kartica ga preda zanki jedra z deskriptorjem, brez kopiranja. Zanka preveri TCP, dešifrira TLS na mestu in razčleni MQTT iz izposojenega medpomnilnika, nato v pomnilniku preveri ACL, omejitev hitrosti in pot skozi drevo tem. Če drugo jedro ta tema zanima, prejme sporočilo za usmerjanje s sklicem na vsebino in identifikatorjem teme; baza prejme telemetrijski zapis ali posodobitev obdržanega sporočila, v paketu. Odgovor PUBACK se šifrira neposredno v izhodni medpomnilnik in združi s TCP ACK, tako da napravi odide en segment. Drugo jedro sporočilo stane eno šifriranje na naročnika v trenutku pošiljanja.

Koliko stane ena povezava

Cilj je največ 512 bajtov na nedejavno povezavo TLS, z željo po 256. Medtem ko povezava miruje, zanjo ni v medpomnilniku ničesar: prejeti podatki se obdelajo neposredno iz omrežnega okvirja, medpomnilniki za pošiljanje, zapise in MQTT pa obstajajo samo, dokler je kaj nedokončanega ali nepotrjenega. Jedro to meri samo: natančni števci kopice v zahtevanih bajtih in v blokih, ki jih zasedajo, zapisani vsakih deset sekund kot kopica nad osnovno ravnjo na odprto povezavo.

Del Velikost Kako
Kontrolni blok TCP 96 B zapakirane zastavice, 16-bitni RTT/RTO, reža v kolesu časovnikov, brez medpomnilnikov v mirovanju
Reža v tabeli TCP 4–8 B samo indeks povezave, tabela največ do polovice polna
Povezava in stanje zapisov TLS 1.3 152 B skrivnost in zaporedje po smeri (40 B); ključ in IV se izpeljeta za vsak zapis
Povezava MQTT 48 B identiteta in oporoka na kopici samo, dokler obstajata
Seja MQTT, vroča oblika 64 B ena naročnina v vrstici, internirani identifikatorji vozlišč
Naročnina devices/<id>/cmd/# 0 vozlišč drevesa shranjena relativno glede na identifikator seje, skupna vsem napravam

Izmerjeno pod HVF s štirimi virtualnimi jedri, od tega tremi delovnimi, pri čemer vsaka naprava drži povezavo mTLS in eno naročnino s QoS 1, vključno z zaokroževanjem alokatorja:

Povezave Bajtov na povezavo
960 531 B
9 922 494 B
10 197 474 B

Bazen omrežnih okvirjev je fiksnih približno 2 MiB, kar je okoli 200 B na povezavo pri desettisoč povezavah in okoli 2 B pri milijonu. Več od tega nismo mogli izmeriti: uporabniško omrežje QEMU na macOS je prenehalo sprejemati povezave pri 10 197, približno na meji 10 240 deskriptorjev procesa QEMU. Število pada, ko se fiksni deli porazdelijo na več povezav, zato ne raste z njihovim številom.

Varnostni model

Varnost je prva prednostna naloga in dobi vse spore z ostalimi cilji. Model ima več plasti:

  • Ena vrata. TCP 8883, samo TLS 1.3, obvezni odjemalski certifikati, podpisani s CA, vgrajenim v sliko. Identifikator odjemalca MQTT mora biti enak identifikatorju naprave iz certifikata.
  • Brez vhodov. Ni lupine, konzolnega vnosa, SSH, administracijskega API-ja, dinamične kode, SQL, dostopnega prek omrežja, niti datotečnega sistema.
  • Pomnilniška varnost. Rust, s forbid(unsafe_code) v protokolnih paketih; vsak blok unsafe ima komentar // SAFETY:, ki ga preverja lint, na zunanji vnos pa ni panike: clippy v paketih na podatkovni poti prepoveduje unwrap, expect, indeksiranje in panic!.
  • Ublažitev izkoriščanja. W^X se uveljavlja s kodiranjem deskriptorjev in bitom SCTLR_EL1.WXN ter se revidira ob vsakem zagonu. Tabele strani so po zagonu samo za branje, brez zapisljivega aliasa. Spodnja polovica naslovnega prostora je izključena. Vsak sklad ima zaščitne strani, izjeme pa tečejo na ločenem skladu. PAC in BTI se vklopita, ko ju procesor podpira, to pa preverjajo dimni testi.
  • Odpornost na zlorabe. Piškotki SYN; sprejem zavrne nove povezave, pred kakršno koli kriptografijo, ko je kopica nizka, ko baza zaostaja, ko je v teku preveč rokovanj na jedro ali na izvorni naslov ali ko je hitrost rokovanj previsoka. Omejitve hitrosti po napravi, omejene vrste, okno TCP, vezano na protipritisk posrednika, omejeno beleženje, nadzorni časovnik in preverjanje zdravja.
  • Nespremenljivost. Konfiguracija, CA in strežniški ključ so vgrajeni v sliko. Sprememba česar koli pomeni novo sliko.

Model groženj je zapisan v docs/SECURITY.md.

Shranjevanje brez datotečnega sistema

Podatki živijo na ločenem disku, virtio-blk ali virtio-scsi, na katerem ni datotečnega sistema. Razpored je minimalen in lasten:

LBA 0      [ superblok: magija · različica razporeda · uuid · tabela regij · CRC-32C ]
LBA 8, 16  [ tabela velikosti datotek, reži A/B (zmaga najnovejša veljavna) ]
LBA 64     [ SQLite glavna baza ½ ][ SQLite WAL ⅛ ][ dnevnik 1 MiB ][ telemetrijski dnevnik: 8 particij … ]
zadnjih 4 KiB [ prostor za samopreverjanje blokovne naprave ob zagonu ]

SQLite (vendorirana 3.54.1, s preverjanjem izvlečka ob izgradnji) je v jedro preveden s clangom, brez standardne knjižnice, in uporablja fiksno kopico memsys5. Njegov VFS preslika tri fiksne datoteke na regije diska. Deluje v načinu WAL z locking_mode=EXCLUSIVE, zato ne potrebuje indeksa v deljenem pomnilniku, in s synchronous=FULL; če quick_check ob zagonu najde napako, se sistem varno ustavi. V bazi so register naprav, preklici, obdržana sporočila in trajne seje z vrstami sporočil QoS 1 za naprave, ki niso povezane.

Jedro za bazo, tisto z najvišjo številko, poganja SQLite in nič drugega. Podatkovna ravnina mu pošilja spremembe stanja prek obroča SPSC brez ključavnic; te zbira v eno transakcijo vsakih 5 ms ali vsakih 512 operacij, potrditve pa vrača z drugim obročem. Prazen disk se formatira ob prvem zagonu; vsega drugega se nikoli ne formatira čez.

Telemetrija gre po drugi poti. Vsak sprejeti PUBLISH na temah iz storage.telemetry_topics odide v particijo telemetrijskega dnevnika svojega jedra: obroč segmentov s CRC na zapis, osoljenim z zaporedjem segmenta, tako da se stari prehodi obroča nikoli ne pojavijo znova. Jedra zapise predajo bazi z lastnim obročem, brez kopiranja, ta pa jih izpiše vsakih 5 ms ali vsakih 256 KiB. Ob zagonu obnovitev ohrani vsak izpisani zapis, odreže nedokončan rep in nadaljuje v novem segmentu. Hramba je po velikosti, prek obroča, in po starosti, prek retention_days. To smo preverili z milijonom zapisov in z kill -9 sredi pisanja.

Številke

Orodje za obremenitev v tools/loadgen počne tri stvari: nevihto rokovanj TLS 1.3 z mTLS in CONNECT, dolgotrajne povezave s PINGREQ, ki vsako sekundo objavljajo telemetrijo, in nevihte ponovnih povezav. make bench na Apple M4 Pro pod HVF daje:

Delovna jedra rokovanj/s v gostu skaliranje prek uporabniškega omrežja QEMU (povezav/s)
1 862 1,00× 789
2 1 724 2,00× 636
4 3 438 3,99× 536

Število v gostu, kjer sta odjemalec in strežnik znotraj istega virtualnega stroja in vsako delovno jedro dela samo zase, kaže, da podatkovna ravnina skalira linearno. Omrežno število omejuje enonitno uporabniško omrežje QEMU, ne gost; tudi to je zapisano kot ADR-032.

Nevihte ponovnih povezav testiramo tako, da se vse naprave povežejo naenkrat, zavrnjene poskuse ponavljajo z zakasnitvijo in nato vse padejo brez DISCONNECT. Parameter heap_limit_mb= v razvojnem načinu prisili sprejem, da kopico šteje za manjšo, kot je, tako da je nevihto, večjo od kopice, mogoče preizkusiti z malo vtičnicami. V enem takem krogu s 3 000 napravami se jih je v 36 sekundah povezalo 1 368, 5 619 poskusov pa je bilo urejeno zavrnjenih, z omejitvijo 8 MiB; pomnilnik se je po nevihti vrnil.

Kako delamo

Projekt vodi pisna specifikacija, PROMPT.md, z načrtom mejnikov, in vsak mejnik se konča z istim obredom: make check in make smoke zelena, en commit z oznako M<n>, zapis v docs/PROGRESS.md in ADR za vsako odločitev, ki ni očitna. Pravila so kratka in o njih se ne pogajamo: brez panike na zunanji vnos, unsafe samo v strojnih paketih in paketih FFI ter vedno s komentarjem, brez alokacij na vroči poti, komentar ob vsakem vrstnem redu atomskih operacij, vsaka omejitev prihaja iz konfiguracije, namerni začasni deli pa padejo glasno.

CI dela več, kot bi jih mi ročno zmogli: fmt, clippy za gostitelja in za aarch64-unknown-none, typos, actionlint in shellcheck; teste na Linuxu in macOS na arm64; izgradnjo jedra za razvojno in produkcijsko konfiguracijo z velikostjo ELF-a v povzetku; zagon pod QEMU z vsemi scenariji dimnega testa in shranjevanjem serijskih zapisov; cargo-deny za svetovalna obvestila, licence in vire; minuto fuzzinga na vsako od enajstih tarč, ponoči pa deset minut na tarčo s predpomnjenim korpusom. Poleg tega CodeQL, OpenSSF Scorecard, Dependabot in objava s poreklom SLSA. Vsaka tuja akcija je pripeta na polni commit SHA.

Ponovljivost razumemo dobesedno: make repro zgradi HEAD dvakrat v svežih delovnih drevesih in primerja ELF, ISO in surovo sliko bajt za bajtom. Objave so podpisane z minisign, artefakte pa je mogoče preveriti z gh attestation verify. Produkcijska slika vsebuje zasebni ključ strežnika, zato je sam ISO skrivnost; slike ob objavah na GitHubu so razvojne, z začasnimi ključi, in služijo samo za preizkušanje.

Kaj smo se naučili

Nekaj lekcij, ki so spremenile načrt:

  • Lasten TCP se je vendarle izplačal. Prototip je tekel na smoltcp in nam je dobro služil do M13. A strežnik, ki drži stotisoče povezav, ne potrebuje odjemalskega TCP, potrebuje piškotke SYN, kolo časovnikov in stanje s 96 bajti. V M14 smo smoltcp zamenjali z lastnim skladom samo za strežniško stran, s testi simulirane izgube in fuzzingom segmentov.
  • Pomnilnik merite od znotraj. Ocene na povezavo so bile neuporabne, dokler jedro ni samo začelo šteti kopice v blokih alokatorja in ne v zahtevanih bajtih. Šele takrat smo videli, kam dejansko odhaja 512 bajtov, in se spustili na 494.
  • Orodje za testiranje je del izdelka. Največja omejitev ni bilo jedro, temveč uporabniško omrežje QEMU in število efemernih vrat na razvojnem računalniku. Za sto tisoč in več povezav potrebujete vmnet-shared na macOS ali Linux s KVM, vmesnikom tap in več odjemalskimi naslovi.
  • SQLite brez operacijskega sistema je mogoč, a le ob strogih pogojih: fiksna kopica, izključno zaklepanje brez deljenega pomnilnika, VFS, ki ne ve za datoteke, in sprejem, ki bazi ne pusti zaostati.
  • Nevihte ponovnih povezav so običajno stanje, ne izjema. Ko mobilno omrežje pade in se vrne, tisoči naprav trkajo hkrati. Zato sprejem povezavo zavrne pred kakršno koli kriptografijo, vsaka zavrnjena povezava pa stane skoraj nič.

Kaj sledi

Delo po M17 je načrtovano v treh smereh, vrstni red med njimi pa je zapisan v docs/PLAN.md. Nič od tega še ni zgrajeno.

  • En ISO za več platform. Ista datoteka urmqtt-<env>-<različica>.iso in ena surova slika GPT, ki se zaganjata na aarch64 UEFI, x86_64 UEFI in x86_64 BIOS, v virtualnih strojih in na pravi strojni opremi, začenši z enim računalnikom Intel. Še vedno naprava z vsem znotraj, ponovljiva in podpisana.
  • Surovi disk, brez datotečnega sistema. Specifikacija formata na ravni bajta, gostiteljsko orodje urmqtt-disk, ki si s jedrom deli razčlenjevalnike, poravnava regij na 1 MiB, rast diska s podatki, discard za tanko dodeljene diske, posnetki baze A/B, preverjanje bitov in, po izbiri, šifriranje AES-256-XTS s strojnim AES.
  • Dokazljivo varno. Preklic in seznam dovoljenih naprav med delovanjem prek podpisanega kontrolnega kanala, brez nove slike; diferencialno in skladnostno testiranje lastnega TLS in TCP; KASLR, zaščita sklada, kCFI, MTE in utrjen alokator; SQLite, izoliran na ravni EL0; Secure Boot; SBOM in cargo-vet; in na koncu paket za zunanjo revizijo.

Platforme, ki ponujajo samo naprave, ki niso virtio, kot sta AWS ENA ali Azure MANA, zaenkrat niso podprte. Raspberry Pi 4 in 5 kot gostitelj KVM, Hetzner CAX in Oracle Ampere A1 so dokumentirani in podprti s kodo, vendar še niso preizkušeni na pravi storitvi.

Preizkusite

Repozitorij je na github.com/zeljan-alduk/urMQTT. Z Rustom s pripeto nightly verigo orodij in QEMU so make certs, make run in en odjemalec mosquitto dovolj za prvi PUBLISH prek mTLS na vašem računalniku. Opozorilo z začetka velja tudi na koncu: to je predalfa in vse, kar deluje, piše v docs/PROGRESS.md. Prijave napak, vprašanja o zasnovi in varnostne prijave po navodilih v SECURITY.md so dobrodošle. O vsakem naslednjem mejniku se bomo oglasili tukaj.

Komentarji

Pravila komentiranja

Pravila komentiranja

Komentarji so namenjeni izmenjavi izkušenj in vprašanj o temah bloga. Ta pravila ohranjajo razpravo koristno za vse.

  1. Vljudnost Brez žalitev, groženj, nadlegovanja, sovražnega govora in diskriminacije na kakršni koli podlagi. Kritizirajte argument, ne osebe.
  2. Na temo Komentar naj se nanaša na objavo ali na razpravo pod njo.
  3. Brez oglasov in neželene pošte Brez oglaševanja, verižnih sporočil in povezav brez konteksta. Povezave in slike so dobrodošle, kadar prispevajo k razpravi.
  4. Zasebnost drugih Ne objavljajte osebnih podatkov drugih: polnih imen zasebnih oseb, naslovov, telefonov, e-pošte, fotografij brez privolitve.
  5. Avtorske pravice Objavljajte samo vsebino, ki jo smete deliti. Pri citiranju navedite vir.
  6. Ena identiteta Uporabljajte en vzdevek in se ne izdajajte za nekoga drugega.
  7. Potrditev po e-pošti Komentar je objavljen šele, ko potrdite povezavo iz e-pošte. Naslov ni prikazan in se ne uporablja za nič drugega; nepotrjeni komentarji so izbrisani po 48 urah.
  8. Moderiranje Komentarje, ki kršijo pravila, skrijemo ali izbrišemo brez opozorila, razpravo pa lahko zaklenemo. Odločitve moderatorjev so dokončne.
  9. Odgovornost Za vsebino komentarja odgovarja njegov avtor. Komentarji ne odražajo stališč ALDO TECH.
  10. Prijava Neprimerno vsebino prijavite na info@aldo.tech.