. "$BST_LIB" # BST-TIMEOUT: 300 # tayga 0.9.2 -- a userspace stateless NAT64 translator, from meta-networking # recipes-connectivity. It owns a TUN interface, reads IPv6 packets off it, # rewrites them as IPv4 (and back) per RFC 6145/6052, and writes them out again. # One C binary, /usr/sbin/tayga, plus /etc/tayga.conf, /etc/tayga.conf.example # and two man pages. # # --------------------------------------------------------------------------- # THIS KERNEL EXPOSES NO TUN DEVICE. That is the wall, and WHERE IT SITS is what # makes this port assertable rather than a single red. # # tayga's only open("/dev/net/tun") is inside tun_setup(), and tun_setup() is # reached from exactly two places in tayga.c, both of them LATE: # # main() -- getopt_long() runs to completion first # ... argument-order checks -- --mktun/--rmtun refusals, before config # read_config(conffile) -- the WHOLE configuration parser # ... # slog("starting TAYGA " VERSION) # tun_setup(...) <-- the wall # # So the entire front half of the program runs for real on this image: the usage # text, the argument validation, every configuration diagnostic, and the version # string. Contrast ipvsadm in this same round, whose ipvs_init() is main()'s # FIRST statement and swallows even --help -- there, none of the four was # reachable. Here all four are, and this suite asserts them against the binary # rather than describing them. # # WHY THE DEVICE IS ABSENT. arch/wasm32/configs/wasm32_defconfig enables TUN's # entire Kconfig parentage -- CONFIG_NETDEVICES=y, CONFIG_NET_CORE=y, and # CONFIG_VIRTIO_NET=y for the one interface this machine has -- and then names no # CONFIG_TUN at all. TUN is a tristate with no `default y`, and that defconfig # states in its own comment that it does not auto-enable dependencies, so an # unnamed symbol is an off symbol. `# CONFIG_MODULES is not set` closes the only # other route. The same file carries `# CONFIG_IPV6 is not set`, so even given a # TUN device there would be no IPv6 stack to originate the traffic tayga # translates. # # THAT SECOND FACT DOES NOT REACH THE PARSER, and the distinction is load-bearing # for this suite. tayga reads IPv6 packets off the tun fd, not from an AF_INET6 # socket, and every IPv6 literal in tayga.conf is parsed by # inet_pton(AF_INET6, ...) -- libc, no kernel involvement. `prefix 64:ff9b::/96` # is therefore accepted, and an illegal prefix length still rejected with the # documented diagnostic, on a kernel with no IPv6 whatever. # # --------------------------------------------------------------------------- # THE STREAM SPLIT IS EXACT, AND EVERY CASE BELOW DEPENDS ON IT. # # * --help and the argument-order refusals are fprintf(stderr, ...) -> STDERR # * everything from read_config() onward goes through slog(), which is # if (use_stdout) vprintf(...) else vsyslog(...) # and use_stdout is set by -d, and ALSO set unconditionally by --mktun and # --rmtun. So under either of those flags the diagnostics land on -> STDOUT # * with none of -d/--mktun/--rmtun, slog() goes to syslog and BOTH streams are # empty -- while the process still exits 1. That silence is asserted below as # a positive fact rather than left as a gap. # # TAYGA HAS NO --version OPTION AT ALL. longopts[] is mktun, rmtun, help, config, # nodetach, user, group, chroot, pidfile and nothing else. The version string # appears in exactly one place, `slog(LOG_INFO, "starting TAYGA " VERSION)`, on # the daemon path just before tun_setup. So the ticket's "version text" IS # obtainable for real -- but only via `tayga -d -c `, and the same # invocation then produces the tun failure. Both are asserted from that one run. # # --------------------------------------------------------------------------- # WHAT IS PROBED RATHER THAN ASSUMED. The NAT64 translation loop needs a TUN # device. Every case that would need one is skipped ONLY where the probe confirms # /dev/net/tun is absent, with tayga's own open-failure diagnostic as the second, # independent reading of the same fact. On an image that grew CONFIG_TUN those # cases run for real instead, so a skip here can never be a suite that gave up. # The gap itself is scored as ONE ATTRIBUTED RED at the end rather than hidden # behind the skips it causes. # # HOW THE EXPECTATIONS WERE PRODUCED. Every literal asserted below was read off a # native x86-64 build of this exact tarball (sha256 2b1f7927...0009c, the one the # recipe pins), not transcribed from the source by eye. Where the native host and # this image legitimately differ -- the native host HAS /dev/net/tun, so its # open() succeeds and TUNSETIFF fails EPERM instead -- the difference is named at # the case. # ------------------------------------------------------------------ locate -- # /usr/sbin, not /sbin: Makefile.am declares sbin_PROGRAMS and autotools puts # those under ${sbindir}, which is /usr/sbin. A red on the path cases means the # distro's sbindir moved, which matters to every autotools package that installs # a daemon. find_prog() { _fp=$(command -v "$1" 2>/dev/null || true) if [ -z "$_fp" ]; then for _p in /usr/sbin/"$1" /sbin/"$1" /usr/bin/"$1" /bin/"$1"; do [ -x "$_p" ] && { _fp=$_p; break; } done fi printf '%s' "$_fp" } TAYGA=$(find_prog tayga) require "${TAYGA:-tayga}" tayga/present D=${TMPDIR:-/tmp}/bst-tayga.$$ rm -rf "$D"; mkdir -p "$D" || { bst_notok tayga/workdir "cannot create $D"; exit 0; } WANT_VERSION="0.9.2" # run : bounded, stderr folded into stdout, text in $out and # status in $rc. Nothing on this image can be killed once it blocks # (brintos/linux#21), and the daemon path is a program whose whole purpose is an # infinite poll() loop -- so every invocation is bounded even where the wall is # expected to end it at once. run() { bst_run "$@"; } # lib/bst.sh: a bound that FIRES # (timeout(1) did not, before the # brintos/linux#77 fix) and a file capture # no wedged child can hold open. # run_split : same, but keeps the streams apart -- # $o_out is stdout only, $o_err is stderr only, $rc the status. The stream split # IS the finding for several cases below, so folding them would erase it. run_split() { _t=$1; shift # Both streams go to files: a `$( )' around a bound that fired still cannot # close while the child holds the pipe (brintos/linux#21), which is the same # reason bst_run captures through a file. # BST-REDIRECT-OK: $D is the suite's tmpfs workdir, never the rootfs. bst_bound "$_t" "$@" >"$D/.stdout" 2>"$D/.stderr"; rc=$? o_out=$(cat "$D/.stdout" 2>/dev/null) o_err=$(cat "$D/.stderr" 2>/dev/null) } # has ... : true iff EVERY needle is a substring. has() { _h=$1; shift for _n in "$@"; do case "$_h" in *"$_n"*) ;; *) return 1 ;; esac; done return 0 } # ---------------------------------------------------------------- fixtures -- # Written here rather than shipped as data files: each one exists to trip exactly # one diagnostic, and keeping the file beside the case it feeds is what lets a # red be read without opening a second file. # # NOTE none of them sets data-dir. On the daemon path tayga chdir()s to data-dir # and, failing with ENOENT, tries mkdir() -- which would fail again if the parent # is absent, and would then preempt the version line this suite needs. With no # data-dir tayga chdir()s to "/" and moves on. /etc/tayga.conf as shipped DOES # set data-dir /var/spool/tayga; it is used only on the --mktun path, which never # reaches that code. GOOD="$D/good.conf" printf 'tun-device nat64\nipv4-addr 192.168.254.1\nipv6-addr fdaa:bb:1::1\nprefix 64:ff9b::/96\n' > "$GOOD" printf 'tun-device nat64\nbogus-directive x\n' > "$D/unknown.conf" printf 'tun-device nat64 extra-arg\nipv4-addr 192.168.254.1\n' > "$D/argc.conf" printf 'tun-device nat64\nprefix 64:ff9b::/96\n' > "$D/noipv4.conf" printf 'tun-device nat64\nipv4-addr 192.168.254.1\n' > "$D/nomap.conf" printf 'tun-device nat64\nipv4-addr 192.168.254.1\nipv4-addr 10.0.0.1\nprefix 64:ff9b::/96\n' > "$D/dup.conf" printf 'tun-device nat64\nipv4-addr 192.168.254.1\nprefix 64:ff9b::/97\n' > "$D/badpfx.conf" printf 'tun-device nat64\nipv4-addr not-an-address\nprefix 64:ff9b::/96\n' > "$D/badaddr.conf" printf '# just a comment\n\n' > "$D/empty.conf" check tayga/fixtures-written test -s "$GOOD" # ---------------------------------------------------------------- inventory -- check_eq tayga/inventory "yes" "$([ -x "$TAYGA" ] && echo yes)" check_eq tayga/install-path "/usr/sbin/tayga" "$TAYGA" check_eq tayga/on-path "$TAYGA" "$(command -v tayga 2>/dev/null)" # The two configuration files the package ships. tayga.conf.example comes from # upstream's dist_sysconf_DATA; tayga.conf is meta-networking's own, installed by # the recipe's do_install:append, and it is what TAYGA_CONF_PATH points at. check tayga/conf-shipped test -f /etc/tayga.conf check tayga/conf-example-shipped test -f /etc/tayga.conf.example # The recipe's do_install:append also installs tayga.service into # ${systemd_unitdir}/system unconditionally. DISTRO_FEATURES is "" here, so # systemd.bbclass's rm_systemd_unitdir removes it from ${D} before packaging -- # which is why the recipe needs no bbappend for it. Asserted as an ABSENCE: a # unit appearing here would mean that class stopped firing, and the package would # then be shipping a file for an init system this image does not have. check tayga/no-systemd-unit test ! -e /lib/systemd/system/tayga.service # ---------------------------------------------------------- the shipped conf -- # /etc/tayga.conf is the file `tayga --mktun` reads when given no -c, so its # validity is not decoration -- it is the default path's precondition. Read the # directives out of it rather than trusting the recipe. SHIPPED_DIRECTIVES=$(grep -vE '^[[:space:]]*(#|$)' /etc/tayga.conf 2>/dev/null | awk '{print $1}' | sort | tr '\n' ' ') check_eq tayga/conf-directives \ "data-dir dynamic-pool ipv4-addr ipv6-addr prefix tun-device " \ "$SHIPPED_DIRECTIVES" # --------------------------------------------------------------- man pages -- for m in "man8/tayga.8" "man5/tayga.conf.5"; do id=tayga/manpage-$(printf '%s' "$m" | sed 's|.*/||; s|\.|-|g') check "$id" test -f /usr/share/man/"$m" done # The header upstream's help2man-generated page actually carries is # `.TH TAYGA "8" "June 2011" "TAYGA 0.9.2" ""` -- the section is a QUOTED field, # not a bare 8, which is what help2man emits and what an eye-transcribed # expectation gets wrong. Matched as written. MP=/usr/share/man/man8/tayga.8 if [ -f "$MP" ]; then case "$(head -n 1 "$MP" 2>/dev/null)" in '.TH TAYGA "8"'*) bst_ok tayga/manpage-is-roff ;; *) bst_notok tayga/manpage-is-roff "want a roff '.TH TAYGA \"8\"' header, got '$(_bst_1line "$(head -n 1 "$MP" 2>/dev/null)")'" ;; esac else bst_notok tayga/manpage-is-roff "no man page to read (see tayga/manpage-tayga-8)" fi # The same page is the source of the "documented" claims this port makes, so its # content is read rather than only its existence: the two operations that reach # tun_setup, and the in-kernel facility they need, must be named in it. The page # says "TUN" and never spells /dev/net/tun -- that path is in tayga.c, not in the # documentation -- so the assertion matches what upstream actually wrote. if [ -f "$MP" ]; then MAN_TEXT=$(cat "$MP" 2>/dev/null) if has "$MAN_TEXT" "mktun" "rmtun" "in-kernel TUN network"; then bst_ok tayga/manpage-documents-tun else bst_notok tayga/manpage-documents-tun "want --mktun, --rmtun and the in-kernel TUN dependency named in tayga.8"; fi else bst_notok tayga/manpage-documents-tun "no man page to read (see tayga/manpage-tayga-8)" fi # ------------------------------------------------------------------- probe -- # The probe every skip below cites. /dev/net/tun is created by the TUN driver's # own miscdevice registration and exists iff CONFIG_TUN is built in. tayga's # open-failure diagnostic further down is the second, independent reading. if [ -e /dev/net/tun ]; then TUN_PRESENT=yes; else TUN_PRESENT=no; fi check_eq tayga/probe-dev-net-tun-absent "no" "$TUN_PRESENT" # CONFIG_MODULES is not set, so nothing could load a TUN driver at runtime even # if a modprobe were present. Recorded because it is the other half of "there is # no path by which this image acquires a tun device". if [ -e /proc/modules ]; then MODULES_PRESENT=yes; else MODULES_PRESENT=no; fi check_eq tayga/probe-no-loadable-modules "no" "$MODULES_PRESENT" # The daemon path opens /dev/urandom before tun_setup, because the address cache # is seeded from it (gcfg->cache_size defaults to 8192, non-zero). If it were # missing, `tayga -d` would die with a DIFFERENT diagnostic and the version case # below would be reporting the wrong wall. Asserted so that a red names itself. check tayga/probe-dev-urandom test -c /dev/urandom # ------------------------------------------------- usage text, asserted for real -- # The ONLY path in this program that exits 0. getopt_long has matched longopts[2] # and fprintf'd USAGE_TEXT to stderr; nothing after it runs. run_split 30 "$TAYGA" --help check_eq tayga/help-rc "0" "$rc" if has "$o_err" \ "Usage:" \ "[-c|--config CONFIGFILE]" \ "--config FILE : Read configuration options from FILE" \ "--nodetach : Do not detach from terminal" \ "--chroot : chroot() to data-dir (specified in config file)" \ "--pidfile FILE : Write process ID of daemon to FILE" then bst_ok tayga/help-text else bst_notok tayga/help-text "usage text incomplete: '$(_bst_1line "$o_err")'"; fi # USAGE_TEXT is fprintf(stderr, ...). A future release moving it to stdout would # be reported here rather than silently absorbed by a 2>&1. check_eq tayga/help-not-on-stdout "" "$o_out" # ----------------------------------------- argument validation, before any config -- # These four refusals sit between getopt_long and read_config, so they fire with # no configuration file in play at all -- which is exactly why they are the # ticket's "argument path" assertions and not merely more parser cases. All four # are fprintf(stderr, ...). argcheck() { _id=$1; _want=$2; shift 2 run_split 30 "$TAYGA" "$@" if [ "$rc" -eq 1 ] && has "$o_err" "$_want"; then bst_ok "$_id" else bst_notok "$_id" "rc=$rc want=1 with '$_want', got err:'$(_bst_1line "$o_err")' out:'$(_bst_1line "$o_out")'"; fi } argcheck tayga/arg-mktun-and-rmtun "Error: both --mktun and --rmtun specified." --mktun --rmtun argcheck tayga/arg-rmtun-and-mktun "Error: both --mktun and --rmtun specified." --rmtun --mktun argcheck tayga/arg-mktun-with-user "Error: cannot specify -u or --user with mktun/rmtun operation" --mktun -u nobody argcheck tayga/arg-mktun-with-group "Error: cannot specify -g or --group with mktun/rmtun operation" --mktun -g nogroup argcheck tayga/arg-mktun-with-chroot "Error: cannot specify -r or --chroot with mktun/rmtun operation" --mktun -r # The same three guard --rmtun, not only --mktun. Asserted separately so a # refactor that guarded one flag and not the other shows up as its own red. argcheck tayga/arg-rmtun-with-user "Error: cannot specify -u or --user with mktun/rmtun operation" --rmtun -u nobody # An option tayga does not have. getopt_long prints its own diagnostic, then the # default: arm prints the "Try ... --help" line. Both are on stderr, rc 1. run_split 30 "$TAYGA" --no-such-option-at-all if [ "$rc" -eq 1 ] && has "$o_err" "unrecognized option" "--help' for more information." then bst_ok tayga/arg-unknown-option else bst_notok tayga/arg-unknown-option "rc=$rc want=1, got err:'$(_bst_1line "$o_err")'"; fi # ------------------------------------- configuration parsing, asserted for real -- # Each case runs under --mktun, which sets use_stdout, so read_config's slog() # output lands on STDOUT and is capturable. --mktun also means the config error # is reached BEFORE tun_setup -- the parser is what stops the program, not the # missing device -- which is the whole reason these assertions survive the wall. cfgcheck() { _id=$1; _file=$2; _want=$3 run_split 30 "$TAYGA" -c "$_file" --mktun if [ "$rc" -eq 1 ] && has "$o_out" "$_want"; then bst_ok "$_id" else bst_notok "$_id" "rc=$rc want=1 with '$_want', got out:'$(_bst_1line "$o_out")' err:'$(_bst_1line "$o_err")'"; fi } cfgcheck tayga/conf-missing-file "$D/no-such-file.conf" "aborting: No such file or directory" cfgcheck tayga/conf-unknown-directive "$D/unknown.conf" 'Unknown directive "bogus-directive" on line 2 of' cfgcheck tayga/conf-wrong-argc "$D/argc.conf" "Incorrect number of arguments on line 1" cfgcheck tayga/conf-no-ipv4-addr "$D/noipv4.conf" "Error: no ipv4-addr directive found" cfgcheck tayga/conf-no-map "$D/nomap.conf" "Error: no translation maps or NAT64 prefix configured" cfgcheck tayga/conf-duplicate "$D/dup.conf" "Error: duplicate ipv4-addr directive on line 3" cfgcheck tayga/conf-bad-address "$D/badaddr.conf" 'Expected an IPv4 address but found "not-an-address" on line 2' # The prefix-length rule is RFC 6052's set, and it is checked even though this # kernel has no IPv6: inet_pton and the length table are libc and arithmetic. cfgcheck tayga/conf-bad-prefix-len "$D/badpfx.conf" "NAT prefix length must be 32, 40, 48, 56, 64 or 96 only, aborting..." # A file with only a comment and a blank line parses to zero directives -- the # comment stripping and the empty-line skip both ran -- and is then rejected by # the post-parse consistency check, not by the tokenizer. cfgcheck tayga/conf-comments-only "$D/empty.conf" "Error: no translation maps or NAT64 prefix configured" # read_config's diagnostics go to STDOUT under --mktun, never stderr. This is the # assertion that pins the slog/use_stdout contract; every cfgcheck above would # still pass if the streams were swapped, because has() reads $o_out only after # run_split has separated them -- but a swap would empty $o_out and they would # all go red together. This case names the reason. run_split 30 "$TAYGA" -c "$D/unknown.conf" --mktun check_eq tayga/conf-diag-not-on-stderr "" "$o_err" # ------------------------------------------------ the --mktun path, to the wall -- # A VALID configuration. The parser now completes, and tun_setup() is reached -- # which is the ticket's "--mktun argument path" asserted end to end. On this # image the open fails; on a host WITH /dev/net/tun the open succeeds and # TUNSETIFF fails EPERM instead, which is why the two are distinguished rather # than matched loosely. run_split 30 "$TAYGA" -c "$GOOD" --mktun check_eq tayga/mktun-rc "1" "$rc" if [ "$TUN_PRESENT" = "no" ]; then if has "$o_out" "Unable to open /dev/net/tun, aborting:"; then bst_ok tayga/mktun-diag-open-failed else bst_notok tayga/mktun-diag-open-failed \ "want 'Unable to open /dev/net/tun, aborting:', got out:'$(_bst_1line "$o_out")' err:'$(_bst_1line "$o_err")'" fi # The errno tail. ENOENT is what an absent CONFIG_TUN produces: the miscdevice # was never registered, so devtmpfs has no node to open. A different errno here # is a genuinely different platform fact and is worth reading rather than # absorbing. ERRNO_TAIL=$(printf '%s\n' "$o_out" | sed -n 's/^.*Unable to open \/dev\/net\/tun, aborting: *//p' | head -n 1) case "$ERRNO_TAIL" in "No such file or directory") bst_ok tayga/mktun-diag-errno-enoent ;; "") bst_notok tayga/mktun-diag-errno-enoent "no errno text after the diagnostic in '$(_bst_1line "$o_out")'" ;; *) bst_notok tayga/mktun-diag-errno-enoent \ "want 'No such file or directory' (no CONFIG_TUN, so no /dev/net/tun), got '$(_bst_1line "$ERRNO_TAIL")'" ;; esac else bst_skip tayga/mktun-diag-open-failed "/dev/net/tun exists on this image -- the open succeeds and this case tests the wrong wall" bst_skip tayga/mktun-diag-errno-enoent "/dev/net/tun exists on this image" fi # --mktun sets use_stdout itself, without -d. So the wall's diagnostic is on # stdout here, exactly as the config diagnostics were. check_eq tayga/mktun-diag-not-on-stderr "" "$o_err" # --rmtun takes the identical route and stops at the identical place. Asserted # separately: the two flags share tun_setup but not their argument handling. run_split 30 "$TAYGA" -c "$GOOD" --rmtun if [ "$rc" -eq 1 ] && { [ "$TUN_PRESENT" = "yes" ] || has "$o_out" "Unable to open /dev/net/tun, aborting:"; } then bst_ok tayga/rmtun-reaches-tun-setup else bst_notok tayga/rmtun-reaches-tun-setup "rc=$rc want=1, got out:'$(_bst_1line "$o_out")' err:'$(_bst_1line "$o_err")'"; fi # The default config path. With no -c, tayga reads TAYGA_CONF_PATH, which # configure.ac sets to ${sysconfdir}/tayga.conf = /etc/tayga.conf -- the file the # recipe ships. Reaching the tun wall from here proves the compiled-in path is # right AND that the shipped file parses; a bad path or a bad file would stop # earlier, with "unable to open" or a parser diagnostic instead. run_split 30 "$TAYGA" --mktun if [ "$rc" -eq 1 ] && { [ "$TUN_PRESENT" = "yes" ] || has "$o_out" "Unable to open /dev/net/tun, aborting:"; } then bst_ok tayga/default-conf-path-parses else bst_notok tayga/default-conf-path-parses \ "want the compiled-in /etc/tayga.conf to parse and reach tun_setup; rc=$rc out:'$(_bst_1line "$o_out")'"; fi # ------------------------------------------- the version string, asserted for real -- # tayga has NO --version option. This one slog() call on the daemon path is the # only place VERSION appears, and -d is what routes it to stdout. The same run # then hits the wall, so both halves of the ticket -- "version text" and "the # documented exit code when /dev/net/tun cannot be opened" -- come from here. run_split 60 "$TAYGA" -d -c "$GOOD" check_eq tayga/daemon-rc "1" "$rc" check_eq tayga/version "starting TAYGA $WANT_VERSION" \ "$(printf '%s\n' "$o_out" | sed -n '1p')" if [ "$TUN_PRESENT" = "no" ]; then if has "$o_out" "Unable to open /dev/net/tun, aborting:"; then bst_ok tayga/daemon-stops-at-tun else bst_notok tayga/daemon-stops-at-tun \ "want the daemon path to reach tun_setup and fail there, got out:'$(_bst_1line "$o_out")'" fi else bst_skip tayga/daemon-stops-at-tun "/dev/net/tun exists on this image -- the daemon would proceed past tun_setup" fi # The version line comes BEFORE the wall, in that order, in one run. Asserted as # an ordering rather than as two independent presences: it is the ordering that # makes the version reachable at all, and a future release that moved the slog() # below tun_setup would put it back out of reach on this image without changing # either string. V_LINE=$(printf '%s\n' "$o_out" | grep -n "starting TAYGA" | head -n 1 | cut -d: -f1) W_LINE=$(printf '%s\n' "$o_out" | grep -n "Unable to open /dev/net/tun" | head -n 1 | cut -d: -f1) if [ "$TUN_PRESENT" = "no" ]; then if [ -n "$V_LINE" ] && [ -n "$W_LINE" ] && [ "$V_LINE" -lt "$W_LINE" ]; then bst_ok tayga/version-precedes-wall else bst_notok tayga/version-precedes-wall "version at line '${V_LINE:-none}', wall at line '${W_LINE:-none}' in '$(_bst_1line "$o_out")'" fi else bst_skip tayga/version-precedes-wall "/dev/net/tun exists on this image -- there is no wall to precede" fi # ------------------------------------------------------ the syslog contract -- # With none of -d/--mktun/--rmtun, use_stdout is 0, openlog() has run and every # slog() goes to syslog. Both streams are empty and the process STILL exits 1 -- # it reached the same wall and said so where nothing on this image is listening. # This is the case that proves the -d in every assertion above is load-bearing # rather than habit. run_split 60 "$TAYGA" -n -c "$GOOD" check_eq tayga/syslog-path-rc "1" "$rc" check_eq tayga/syslog-path-no-stdout "" "$o_out" check_eq tayga/syslog-path-no-stderr "" "$o_err" # ---------------------------------------------- further pre-config validation -- # -u with a user that does not exist. getpwnam() runs before read_config, so this # is reached with any config at all -- and it needs -d to be visible, which is # the syslog contract above used in anger. run_split 30 "$TAYGA" -d -u no-such-user-at-all -c "$GOOD" if [ "$rc" -eq 1 ] && has "$o_out" "Error: user no-such-user-at-all does not exist" then bst_ok tayga/arg-unknown-user else bst_notok tayga/arg-unknown-user "rc=$rc, got out:'$(_bst_1line "$o_out")' err:'$(_bst_1line "$o_err")'"; fi # --pidfile to a path that cannot be opened. This one sits AFTER read_config and # BEFORE the wall, so it also witnesses that the parser completed on $GOOD. run_split 30 "$TAYGA" -d -p "$D/no-such-dir/tayga.pid" -c "$GOOD" if [ "$rc" -eq 1 ] && has "$o_out" "unable to open" "for writing" then bst_ok tayga/arg-bad-pidfile else bst_notok tayga/arg-bad-pidfile "rc=$rc, got out:'$(_bst_1line "$o_out")'"; fi # A pidfile tayga CAN write. It is written before daemon() would fork and before # tun_setup, so on this image the file exists and holds this run's pid even # though the run then dies at the wall -- which is a real filesystem side effect # of the daemon path, executed for real. PIDF="$D/tayga.pid" rm -f "$PIDF" run 60 "$TAYGA" -d -p "$PIDF" -c "$GOOD" if [ -s "$PIDF" ] && [ "$(cat "$PIDF" 2>/dev/null)" -gt 0 ] 2>/dev/null then bst_ok tayga/pidfile-written else bst_notok tayga/pidfile-written "want a pid in $PIDF, got '$(_bst_1line "$(cat "$PIDF" 2>/dev/null)")'"; fi # ------------------------------------------- the translation loop, probed only -- # Everything past tun_setup -- attaching the interface, the poll() loop, and the # RFC 6145 rewriting that is the whole point of the program -- needs a TUN # device. It is skipped ONLY under the probe, and runs for real on an image that # has one. if [ "$TUN_PRESENT" = "no" ]; then bst_skip tayga/nat64-translation-loop \ "no /dev/net/tun on this image (CONFIG_TUN unset in wasm32_defconfig; probe: tayga/probe-dev-net-tun-absent), so the daemon cannot attach an interface -- see tayga/gap-no-tun-device" bst_skip tayga/nat64-interface-attach \ "no /dev/net/tun on this image -- TUNSETIFF is never reached" else # The device exists. tun_setup announces getting past TUNSETIFF by logging the # MTU it read back off the interface; anything short of that line means the # attach itself failed and is a red, not a skip. run 60 "$TAYGA" -d -c "$GOOD" if has "$out" "Using tun device nat64 with MTU"; then bst_ok tayga/nat64-interface-attach else bst_notok tayga/nat64-interface-attach "want the MTU line from tun_setup, got '$(_bst_1line "$out")'"; fi bst_notok tayga/nat64-translation-loop "this image grew a tun device -- the loop is now exercisable and this suite has not been extended to drive it" fi # ------------------------------------------------- the gap, scored explicitly -- # One attributed red rather than a silence. tayga is present, correctly built and # correct in every part of itself this platform can reach; what stops it is the # platform, and that is the finding this port exists to record. It flips green by # itself on an image built with CONFIG_TUN. if [ "$TUN_PRESENT" = "no" ]; then bst_notok tayga/gap-no-tun-device \ "PLATFORM GAP: wasm32_defconfig enables CONFIG_NETDEVICES/NET_CORE/VIRTIO_NET but names no CONFIG_TUN, and CONFIG_MODULES is unset, so /dev/net/tun cannot exist -- tayga's NAT64 loop is unreachable on this image. Front half (usage, argument validation, whole config parser, version) asserted green above." else bst_ok tayga/gap-no-tun-device fi rm -rf "$D"