[{"data":1,"prerenderedAt":40},["ShallowReactive",2],{"project-libdiginet-building":3},{"page":4,"others":30},{"slug":5,"src":6,"title":7,"source":8,"toc":9,"html":29},"building","BUILDING.md","Building libdiginet","https:\u002F\u002Fgithub.com\u002FFreeMixer\u002Flibdiginet\u002Fblob\u002F084e09f8eaea72a275f583b8ae148b565aa6a548\u002FBUILDING.md",[10,13,15,17,20,23,26],{"id":11,"title":12},"tests","Tests",{"id":14,"title":14},"diginet-probe",{"id":16,"title":16},"diginet-packet-helper",{"id":18,"title":19},"the-kaitai-grammar","The Kaitai grammar",{"id":21,"title":22},"fuzzing","Fuzzing",{"id":24,"title":25},"ci","CI",{"id":27,"title":28},"packages","Packages","\u003Ch1 id=\"building-libdiginet\">Building libdiginet\u003C\u002Fh1>\n\u003Cp>A hand-kept Makefile, no build system to configure. You need a C11 compiler and \u003Ccode>make\u003C\u002Fcode>.\nNothing else: no library outside libc.\u003C\u002Fp>\n\u003Cpre>\u003Ccode>make                          # libdiginet.a, libdiginet-transport.a and tools\u002Fdiginet-probe\nmake test                     # the unit suite, the same command CI runs\nmake install PREFIX=\u002Fusr\u002Flocal [DESTDIR=...]\nmake clean\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>The code is plain C11 built with \u003Ccode>-Wall -Wextra -Werror\u003C\u002Fcode>, so a warning is a build failure.\n\u003Ccode>CC\u003C\u002Fcode> and \u003Ccode>CFLAGS\u003C\u002Fcode> can be overridden on the command line; the warning flags are kept even then.\u003C\u002Fp>\n\u003Cp>Three libraries come out of one tree:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Ccode>libdiginet\u003C\u002Fcode>: the protocol. Frame grammar, codecs, personalities. No socket, no clock.\u003C\u002Fli>\n\u003Cli>\u003Ccode>libdiginet-transport\u003C\u002Fcode>: the wire. The packet socket and the session (discovery, wake,\nACKs, retransmit, keepalive, coalescing, pacing), and the desk mux (many desks over one\nsocket that hears every interface). It links \u003Ccode>libdiginet\u003C\u002Fcode>.\u003C\u002Fli>\n\u003Cli>\u003Ccode>libdiginet-emu\u003C\u002Fcode>: the desk emulator (see Tests below), installed so that a project testing\nagainst a Control|24 or ProControl links it instead of keeping its own copy.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>\u003Ccode>make install\u003C\u002Fcode> copies the headers to \u003Ccode>$(PREFIX)\u002Finclude\u002Fdiginet\u002F\u003C\u002Fcode>, the archives to\n\u003Ccode>$(PREFIX)\u002Flib\u003C\u002Fcode> (\u003Ccode>LIBDIR=\u003C\u002Fcode> to change it) and three pkg-config files, so a consumer builds with:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>cc app.c $(pkg-config --cflags --libs libdiginet-transport)\ncc test.c $(pkg-config --cflags --libs libdiginet-emu)\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"tests\">Tests\u003C\u002Fh2>\n\u003Cp>Every test runs through \u003Ccode>tests\u002Frun-test.sh\u003C\u002Fcode>, which gives it a timeout: a hang is a failure,\nnever a stalled build. A test that exits 77 proved this machine cannot host it and is reported\nas SKIP, never as a pass.\u003C\u002Fp>\n\u003Cp>The golden frames are in \u003Ccode>tests\u002Fgolden\u002Fframes.txt\u003C\u002Fcode>, one whole Ethernet frame per line in hex.\nThe C suite reads that file and checks every frame against the values \u003Ccode>docs\u002Fprotocol.md\u003C\u002Fcode>\ngives. The same file feeds the Kaitai check below, so the two readings of the grammar cannot\ndrift apart.\u003C\u002Fp>\n\u003Cp>The transport suite needs no desk and no privileges. \u003Ccode>testsupport\u002Fdesk_emu.c\u003C\u002Fcode>, installed as\n\u003Ccode>libdiginet-emu\u003C\u002Fcode>, is a desk emulator that speaks the protocol; \u003Ccode>test_transport\u003C\u002Fcode> drives a\nsession against it on a virtual clock\n(minutes of desk time in milliseconds), \u003Ccode>test_mux\u003C\u002Fcode> drives the desk mux against two of them on\ntwo interfaces, and \u003Ccode>test_fdio\u003C\u002Fcode> does the same on the real clock over a socketpair. \u003Ccode>test_packet\u003C\u002Fcode> runs the real \u003Ccode>AF_PACKET\u003C\u002Fcode> path: it enters a user and network\nnamespace of its own, where it may open packet sockets on a private loopback; where\nunprivileged namespaces are not allowed it exits 77 and reports SKIP. \u003Ccode>test_anyif\u003C\u002Fcode> does the\nsame with two veth pairs: it gives up its capabilities, takes the any-interface socket from\n\u003Ccode>tools\u002Fdiginet-packet-helper\u003C\u002Fcode>, and checks that each desk is heard on its own interface (one\nmade after the socket was opened), that a frame goes out of the interface it is sent to, and\nthat two desk emulators, one on each, come online through one mux over that one socket.\u003C\u002Fp>\n\u003Cp>\u003Ccode>test_probe\u003C\u002Fcode> runs \u003Ccode>tools\u002Fdiginet-probe\u003C\u002Fcode> as its own process against the emulator, with the\nwire on descriptor 3 and the operator's answers on stdin, and checks both the probe's output\nand what the desk received.\u003C\u002Fp>\n\u003Ch2 id=\"diginet-probe\">diginet-probe\u003C\u002Fh2>\n\u003Cp>\u003Ccode>make install\u003C\u002Fcode> puts \u003Ccode>diginet-probe\u003C\u002Fcode> in \u003Ccode>$(PREFIX)\u002Fbin\u003C\u002Fcode>. It opens a packet socket, which needs\n\u003Ccode>cap_net_raw\u003C\u002Fcode>:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>sudo setcap cap_net_raw=ep .\u002Ftools\u002Fdiginet-probe\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Every rebuild or copy makes a binary without the capability, so run \u003Ccode>setcap\u003C\u002Fcode> again after it.\nHow to run it on a desk is in \u003Ca href=\"\u002Fprojects\u002Flibdiginet\u002Fprobe\">docs\u002Fprobe.md\u003C\u002Fa>.\u003C\u002Fp>\n\u003Ch2 id=\"diginet-packet-helper\">diginet-packet-helper\u003C\u002Fh2>\n\u003Cp>\u003Ccode>tools\u002Fdiginet-packet-helper\u003C\u002Fcode> opens the packet socket that hears every interface and hands it\nto the program that started it, over a Unix socket on its descriptor 3, so that program needs\nno capability (\u003Ca href=\"https:\u002F\u002Fgithub.com\u002FFreeMixer\u002Flibdiginet\u002Fblob\u002F084e09f8eaea72a275f583b8ae148b565aa6a548\u002Fdocs\u002Fdiginet-packet-helper.1\">docs\u002Fdiginet-packet-helper.1\u003C\u002Fa>). The helper is\nthe one binary that holds \u003Ccode>cap_net_raw\u003C\u002Fcode>:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>sudo setcap cap_net_raw=ep .\u002Ftools\u002Fdiginet-packet-helper\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>It links the static archives, even in the packages, so it loads no shared library of ours\nwhile it holds the capability.\u003C\u002Fp>\n\u003Ch2 id=\"the-kaitai-grammar\">The Kaitai grammar\u003C\u002Fh2>\n\u003Cp>\u003Ccode>protocol\u002Fdiginet.ksy\u003C\u002Fcode> is the formal byte grammar. To check that it compiles and that the\nparser it generates reads the golden frames as the C library does:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>make ksy-check\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>This needs \u003Ccode>kaitai-struct-compiler\u003C\u002Fcode> (0.11, from https:\u002F\u002Fgithub.com\u002Fkaitai-io\u002Fkaitai_struct_compiler\u002Freleases)\nand the Python runtime (\u003Ccode>pip install kaitaistruct==0.11\u003C\u002Fcode>). CI runs it in a Debian container.\u003C\u002Fp>\n\u003Ch2 id=\"fuzzing\">Fuzzing\u003C\u002Fh2>\n\u003Cp>Every reader of desk bytes has a libFuzzer harness in \u003Ccode>fuzz\u002F\u003C\u002Fcode>, with a seed corpus, a coverage\nfloor, a recorded breakage for every check and one sabotage patch per property;\n\u003Ca href=\"https:\u002F\u002Fgithub.com\u002FFreeMixer\u002Flibdiginet\u002Fblob\u002F084e09f8eaea72a275f583b8ae148b565aa6a548\u002Ffuzz\u002FREADME.md\">fuzz\u002FREADME.md\u003C\u002Fa> says what each checks. They need clang with libFuzzer,\n\u003Ccode>llvm-cov\u003C\u002Fcode> for the coverage witness and the static libc for the static build:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>make fuzz fuzz-run FUZZ_TIME=60 fuzz-sabotage fuzz-records fuzz-coverage fuzz-static\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"ci\">CI\u003C\u002Fh2>\n\u003Cp>\u003Ccode>.github\u002Fworkflows\u002Fci.yml\u003C\u002Fcode> runs \u003Ccode>make\u003C\u002Fcode>, \u003Ccode>make test\u003C\u002Fcode> and \u003Ccode>make install\u003C\u002Fcode> in fedora:44,\ndebian:bookworm and debian:trixie containers, \u003Ccode>make test\u003C\u002Fcode> once more on the bare runner (where\nthe namespace test can run), and \u003Ccode>make ksy-check\u003C\u002Fcode> in a Debian container with the compiler\ninstalled. \u003Ccode>.github\u002Fworkflows\u002Ffuzz.yml\u003C\u002Fcode> builds the harnesses in fedora:44, fuzzes each for 60 s\nand runs \u003Ccode>make fuzz-corpus-check\u003C\u002Fcode>, \u003Ccode>make fuzz-sabotage\u003C\u002Fcode>, \u003Ccode>make fuzz-records\u003C\u002Fcode>,\n\u003Ccode>make fuzz-coverage\u003C\u002Fcode> and \u003Ccode>make fuzz-static\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Ch2 id=\"packages\">Packages\u003C\u002Fh2>\n\u003Cp>One source builds two shared libraries and a tool:\u003C\u002Fp>\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>\u003C\u002Fth>\n\u003Cth>Fedora\u003C\u002Fth>\n\u003Cth>Debian\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>libdiginet, libdiginet-transport\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>libdiginet\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>libdiginet0\u003C\u002Fcode>, \u003Ccode>libdiginet-transport0\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>headers, pkg-config, \u003Ccode>diginet.ksy\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>libdiginet-devel\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>libdiginet-dev\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>diginet-probe\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>diginet-tools\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>diginet-tools\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003Cp>\u003Ccode>packaging\u002Flibdiginet.spec\u003C\u002Fcode> and \u003Ccode>debian\u002F\u003C\u002Fcode> describe them; both run \u003Ccode>make shared\u003C\u002Fcode> and\n\u003Ccode>make install-shared\u003C\u002Fcode>, and \u003Ccode>make test\u003C\u002Fcode> against the result. The RPM gives \u003Ccode>diginet-probe\u003C\u002Fcode>\n\u003Ccode>cap_net_raw\u003C\u002Fcode> with \u003Ccode>%caps\u003C\u002Fcode>; the DEB sets it in \u003Ccode>diginet-tools.postinst\u003C\u002Fcode> with \u003Ccode>setcap\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Cp>The version is the \u003Ccode>VERSION\u003C\u002Fcode> file; the sonames' majors are \u003Ccode>DIGINET_ABI\u003C\u002Fcode> and\n\u003Ccode>DIGINET_TRANSPORT_ABI\u003C\u002Fcode> in \u003Ccode>include\u002Fdiginet\u002Fdiginet.h\u003C\u002Fcode>. \u003Ccode>tests\u002Fconformance-packaging.sh\u003C\u002Fcode> (part of\n\u003Ccode>make test\u003C\u002Fcode>) refuses a header, spec or \u003Ccode>debian\u002F\u003C\u002Fcode> that disagrees with them.\u003C\u002Fp>\n\u003Ch3 id=\"releasing\">Releasing\u003C\u002Fh3>\n\u003Cp>Set the version in \u003Ccode>VERSION\u003C\u002Fcode>, \u003Ccode>include\u002Fdiginet\u002Fdiginet.h\u003C\u002Fcode>, \u003Ccode>Version:\u003C\u002Fcode> in the spec and the top\nentry of \u003Ccode>debian\u002Fchangelog\u003C\u002Fcode>, then tag \u003Ccode>vX.Y.Z\u003C\u002Fcode>. The tag runs \u003Ccode>.github\u002Fworkflows\u002Frelease.yml\u003C\u002Fcode>,\nwhich calls the shared \u003Ccode>build-rpm.yml\u003C\u002Fcode> and \u003Ccode>build-deb.yml\u003C\u002Fcode> workflows of FreeMixer\u002F.github: signed\nRPMs for Fedora 44 (x86_64, aarch64) and DEBs for Debian bookworm and trixie (amd64, arm64) are\npublished to the FreeMixer channel and attached to the GitHub release. A pull request runs the\nsame workflows as a dry run that builds, lints and publishes nothing, then installs the packages\nit built in clean containers and builds a consumer against the development package. Git history\nis the changelog; no changelog file is kept.\u003C\u002Fp>\n",[31,34,37],{"slug":32,"title":33},"","libdiginet",{"slug":35,"title":36},"protocol","The DigiNet surface protocol (Control|24, ProControl)",{"slug":38,"title":39},"probe","diginet-probe: the first test on a real desk",1793954996778]