netifd's dhcp.script calls functions.sh's ipcalc without base-files' bin/
on PATH ("ipcalc.sh: not found" at every lease). The Pi's brcmfmac
allows one AP: TollGate's open one, so its private network stays down.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1745 lines
82 KiB
Scheme
1745 lines
82 KiB
Scheme
;;; OpenWrt userland for Guix (Phase 3).
|
|
;;;
|
|
;;; Pinned to the commits OpenWrt main builds (package/*/*/Makefile,
|
|
;;; PKG_SOURCE_VERSION), so the set is one OpenWrt has tested together.
|
|
;;; Update: read those Makefiles, check out the commit, `guix hash -x -r .'.
|
|
;;; Lua bindings and examples are off: nothing here uses Lua (LuCI is ucode).
|
|
(define-module (openwrt)
|
|
;; Same cross toolchain as rpi4.scm, so `guix build --target' of these
|
|
;; packages gives the derivations the system uses (PITFALLS #35).
|
|
#:use-module (cross-libc-fix)
|
|
#:use-module (guix packages)
|
|
#:use-module (guix git-download)
|
|
#:use-module (guix gexp)
|
|
#:use-module (guix utils)
|
|
#:use-module ((guix licenses) #:prefix license:)
|
|
#:use-module (guix build-system cmake)
|
|
#:use-module (guix build-system copy)
|
|
#:use-module (guix build-system gnu)
|
|
#:use-module (gnu packages busybox)
|
|
#:use-module (srfi srfi-13)
|
|
#:use-module (gnu packages compression)
|
|
#:use-module (gnu packages crypto)
|
|
#:use-module (gnu packages linux)
|
|
#:use-module (gnu packages pkg-config)
|
|
#:use-module (gnu packages tls)
|
|
#:use-module ((gnu packages gnunet) #:select (libmicrohttpd))
|
|
#:use-module (guix download)
|
|
#:use-module (gnu packages web))
|
|
|
|
;; CMake looks for `pkg-config', but cross builds only have
|
|
;; TARGET-pkg-config. FindPkgConfig honours $PKG_CONFIG, which must be an
|
|
;; absolute file name; PATH is only set up once the phases run. A procedure,
|
|
;; called from `arguments', so pkg-config-for-target sees the target (a
|
|
;; top-level gexp would capture the native name).
|
|
(define (openwrt-phases)
|
|
#~(modify-phases %standard-phases
|
|
(add-before 'configure 'set-pkg-config
|
|
(lambda _
|
|
(setenv "PKG_CONFIG"
|
|
(or (which #$(pkg-config-for-target))
|
|
(error "pkg-config not found"
|
|
#$(pkg-config-for-target))))))))
|
|
|
|
;; copy-build-system ignores --target (Guix 1.5.0 lowers it with #:target
|
|
;; #f), so a store reference in what it installs -- an input or a gexp
|
|
;; `file-append' -- names an x86_64 build even in a cross-built system
|
|
;; (PITFALLS #39). For script packages that refer to other packages: GNU
|
|
;; build system, which does cross-build, running only copy-build-system's
|
|
;; install phase. Use as #:phases (modify-phases (cross-copy-phases ...) ...)
|
|
;; with #:modules %cross-copy-modules.
|
|
(define %cross-copy-modules
|
|
'((guix build gnu-build-system)
|
|
((guix build copy-build-system) #:prefix copy:)
|
|
(guix build utils)))
|
|
|
|
(define (cross-copy-phases install-plan)
|
|
#~(modify-phases %standard-phases
|
|
(delete 'bootstrap)
|
|
(delete 'configure)
|
|
(delete 'build)
|
|
(delete 'check)
|
|
(replace 'install
|
|
(lambda args
|
|
;; Its `install' isn't exported; take it from its phases.
|
|
(apply (assoc-ref copy:%standard-phases 'install)
|
|
#:install-plan #$install-plan args)))))
|
|
|
|
(define-public libubox
|
|
(let ((commit "e7608b69283d919d031d13cc8e21692503f5dbea")
|
|
(revision "0"))
|
|
(package
|
|
(name "libubox")
|
|
(version (git-version "2026.07.21" revision commit))
|
|
(source
|
|
(origin
|
|
(method git-fetch)
|
|
(uri (git-reference
|
|
(url "https://git.openwrt.org/project/libubox.git")
|
|
(commit commit)))
|
|
(file-name (git-file-name name version))
|
|
(sha256
|
|
(base32 "11qzh7p7qjn8d4qlfv4aclx2y7bs873hhsdaqx2x5qfd61frq7kl"))))
|
|
(build-system cmake-build-system)
|
|
(arguments
|
|
(list #:configure-flags #~'("-DBUILD_LUA=OFF" "-DBUILD_EXAMPLES=OFF")
|
|
#:tests? #f ;tests need cmocka + UNIT_TESTING
|
|
#:phases
|
|
#~(modify-phases #$(openwrt-phases)
|
|
(add-after 'unpack 'absolute-jshn
|
|
;; jshn.sh runs `jshn' from PATH; netifd's protocol
|
|
;; scripts source it with a minimal environment.
|
|
(lambda _
|
|
(substitute* "sh/jshn.sh"
|
|
(("`jshn ")
|
|
(string-append "`" #$output "/bin/jshn "))
|
|
(("^\tjshn ")
|
|
(string-append "\t" #$output "/bin/jshn "))))))))
|
|
(inputs (list json-c))
|
|
(native-inputs (list pkg-config))
|
|
(home-page "https://git.openwrt.org/?p=project/libubox.git")
|
|
(synopsis "OpenWrt base utility library")
|
|
(description
|
|
"libubox is the collection of helpers used throughout the OpenWrt
|
|
userland: lists and AVL trees, the blob/blobmsg binary message format, the
|
|
uloop event loop, ustream I/O, JSON conversion (@code{blobmsg_json}),
|
|
@code{json_script}, and the @command{jshn} shell JSON helper used by netifd
|
|
protocol scripts.")
|
|
;; Mostly ISC; avl.c/avl.h and friends (from olsrd) are BSD-3.
|
|
(license (list license:isc license:bsd-3)))))
|
|
|
|
(define-public ubus
|
|
(let ((commit "414c60a2e29e72c2c4f573bc50ad54aef076d169")
|
|
(revision "0"))
|
|
(package
|
|
(name "ubus")
|
|
(version (git-version "2026.09.25" revision commit))
|
|
(source
|
|
(origin
|
|
(method git-fetch)
|
|
(uri (git-reference
|
|
(url "https://git.openwrt.org/project/ubus.git")
|
|
(commit commit)))
|
|
(file-name (git-file-name name version))
|
|
(sha256
|
|
(base32 "0mmlyw3ad0fzfa6rghmbi6bssznnjvjhm3p1r7lwhs3fvscqsjg5"))))
|
|
(build-system cmake-build-system)
|
|
(arguments
|
|
;; The socket path (/var/run/ubus/ubus.sock) is compiled in; ubusd
|
|
;; doesn't create /var/run/ubus, so the service must.
|
|
(list #:configure-flags #~'("-DBUILD_LUA=OFF" "-DBUILD_EXAMPLES=OFF")
|
|
#:tests? #f
|
|
#:phases (openwrt-phases)))
|
|
(inputs (list libubox json-c))
|
|
(native-inputs (list pkg-config))
|
|
(home-page "https://git.openwrt.org/?p=project/ubus.git")
|
|
(synopsis "OpenWrt system message bus")
|
|
(description
|
|
"ubus is the RPC and event bus of the OpenWrt userland: the
|
|
@command{ubusd} daemon, the @command{ubus} command-line client, and the
|
|
@code{libubus} client library.")
|
|
(license license:lgpl2.1))))
|
|
|
|
(define-public uci
|
|
(let ((commit "66127cd76c5d0bd46d5a90302cc6110f53a4e2f8")
|
|
(revision "0"))
|
|
(package
|
|
(name "uci")
|
|
(version (git-version "2025.12.02" revision commit))
|
|
(source
|
|
(origin
|
|
(method git-fetch)
|
|
(uri (git-reference
|
|
(url "https://git.openwrt.org/project/uci.git")
|
|
(commit commit)))
|
|
(file-name (git-file-name name version))
|
|
(sha256
|
|
(base32 "16rp60i2ypp84higqsnckypm674rc45jmhmnm5bds8m08nqh73ny"))))
|
|
(build-system cmake-build-system)
|
|
(arguments
|
|
(list #:configure-flags #~'("-DBUILD_LUA=OFF")
|
|
#:tests? #f
|
|
#:phases (openwrt-phases)))
|
|
(inputs (list libubox))
|
|
(native-inputs (list pkg-config))
|
|
(home-page "https://git.openwrt.org/?p=project/uci.git")
|
|
(synopsis "OpenWrt Unified Configuration Interface")
|
|
(description
|
|
"UCI is the configuration framework of OpenWrt: the @code{libuci}
|
|
library and @command{uci} tool for reading and changing the
|
|
@file{/etc/config/*} files that all OpenWrt services are configured from.")
|
|
;; libuci is LGPL 2.1; the uci command (cli.c) is GPL 2.
|
|
(license (list license:lgpl2.1 license:gpl2)))))
|
|
|
|
(define-public libnl-tiny
|
|
(let ((commit "40493a655d8caa2ccf5206dde1e733abe2920432")
|
|
(revision "0"))
|
|
(package
|
|
(name "libnl-tiny")
|
|
(version (git-version "2025.12.02" revision commit))
|
|
(source
|
|
(origin
|
|
(method git-fetch)
|
|
(uri (git-reference
|
|
(url "https://git.openwrt.org/project/libnl-tiny.git")
|
|
(commit commit)))
|
|
(file-name (git-file-name name version))
|
|
(sha256
|
|
(base32 "1031dq1h8ls6vl23cah2bcpaldmi2nh6jq53ndz07mcm5ali9v2k"))))
|
|
(build-system cmake-build-system)
|
|
(arguments (list #:tests? #f)) ;no tests
|
|
(home-page "https://git.openwrt.org/?p=project/libnl-tiny.git")
|
|
(synopsis "Small netlink library from OpenWrt")
|
|
(description
|
|
"libnl-tiny is a stripped-down version of libnl with the generic
|
|
netlink parts used by OpenWrt's netifd, ucode and wireless tools. Its headers
|
|
install under @file{include/libnl-tiny} so it can coexist with libnl.")
|
|
(license license:lgpl2.1))))
|
|
|
|
(define-public jsonfilter
|
|
(let ((commit "b9034210bd331749673416c6bf389cccd4e23610")
|
|
(revision "0"))
|
|
(package
|
|
(name "jsonfilter")
|
|
(version (git-version "2026.03.16" revision commit))
|
|
(source
|
|
(origin
|
|
(method git-fetch)
|
|
(uri (git-reference
|
|
(url "https://git.openwrt.org/project/jsonpath.git")
|
|
(commit commit)))
|
|
(file-name (git-file-name name version))
|
|
(sha256
|
|
(base32 "144jhmb06x8xsgx0x3dsral3lkjr32yhg4nad2cjgcw3pwfg0pmw"))))
|
|
(build-system cmake-build-system)
|
|
(arguments
|
|
(list #:tests? #f ;no tests
|
|
;; The lemon rules use paths relative to the source tree.
|
|
#:out-of-source? #f
|
|
#:phases
|
|
#~(modify-phases #$(openwrt-phases)
|
|
(add-after 'install 'install-jsonfilter
|
|
;; Built as `jsonpath'; OpenWrt and its scripts call it
|
|
;; `jsonfilter'.
|
|
(lambda _
|
|
(symlink "jsonpath"
|
|
(string-append #$output "/bin/jsonfilter")))))))
|
|
;; The build compiles and runs the lemon parser generator with the
|
|
;; native `gcc', which cross builds also have.
|
|
(inputs (list libubox json-c))
|
|
(native-inputs (list pkg-config))
|
|
(home-page "https://git.openwrt.org/?p=project/jsonpath.git")
|
|
(synopsis "Query JSON with JSONPath expressions from the shell")
|
|
(description
|
|
"jsonfilter extracts values from JSON documents with JSONPath
|
|
expressions; OpenWrt's shell scripts use it to parse @command{ubus}
|
|
output.")
|
|
(license license:isc))))
|
|
|
|
(define-public ucode
|
|
(let ((commit "b885dd0fe1e974551fb1233ca5f3aa74d80b74d9")
|
|
(revision "0"))
|
|
(package
|
|
(name "ucode")
|
|
(version (git-version "0.0.20250529" revision commit))
|
|
(source
|
|
(origin
|
|
(method git-fetch)
|
|
(uri (git-reference
|
|
(url "https://github.com/jow-/ucode")
|
|
(commit commit)))
|
|
(file-name (git-file-name name version))
|
|
(sha256
|
|
(base32 "00gdsxz0ic5jf5masf5bdana2nnz80fbp1if2k2hhw0rqwv6arjg"))))
|
|
(build-system cmake-build-system)
|
|
(arguments
|
|
(list
|
|
#:configure-flags
|
|
;; The module search path is compiled in and has no run-time
|
|
;; override (only `ucode -L'). Add the system profile, so modules
|
|
;; from other packages (firewall4's fw4.uc, LuCI) are found.
|
|
#~(list (string-append
|
|
"-DLIB_SEARCH_PATH="
|
|
#$output "/lib/ucode/*.so:" #$output "/share/ucode/*.uc:"
|
|
"/run/current-system/profile/lib/ucode/*.so:"
|
|
"/run/current-system/profile/share/ucode/*.uc:"
|
|
"./*.so:./*.uc"))
|
|
#:tests? #f ;tests need a full test harness
|
|
#:phases (openwrt-phases)))
|
|
;; All modules: fs, io, math, debug, struct, socket, log, resolv,
|
|
;; plus ubus, uci, uloop (libubox), rtnl and nl80211 (libnl-tiny),
|
|
;; zlib and digest (libmd).
|
|
(inputs (list json-c libubox ubus uci libnl-tiny zlib libmd))
|
|
(native-inputs (list pkg-config))
|
|
(home-page "https://ucode.mein.io/")
|
|
(synopsis "Small ECMAScript-like scripting language from OpenWrt")
|
|
(description
|
|
"ucode is a tiny scripting language with ECMAScript-like syntax and
|
|
template support, used by OpenWrt for firewall4, netifd's wireless handling,
|
|
rpcd and LuCI. This package provides the @command{ucode} interpreter,
|
|
@code{libucode} and its native modules.")
|
|
(license license:isc))))
|
|
|
|
;;; Files that live in OpenWrt's main tree, not in the projects' own repos
|
|
;;; (netifd's main.uc and ifup/ifdown, base-files' shell library, ...).
|
|
;;; Same commit as the PKG_SOURCE_VERSION pins above; trimmed to the
|
|
;;; directories packages here take files from.
|
|
(define %openwrt-tree-commit "6c8798939303bbe8e19bd50eb810170cfadd0daf")
|
|
|
|
(define-public %openwrt-tree
|
|
(origin
|
|
(method git-fetch)
|
|
(uri (git-reference
|
|
(url "https://github.com/openwrt/openwrt")
|
|
(commit %openwrt-tree-commit)))
|
|
(file-name (git-file-name "openwrt-tree" (string-take %openwrt-tree-commit 7)))
|
|
(sha256
|
|
(base32 "1adbjb400afhl183c4inca0qrq8q39b0qybfvfq3qb142a9190q7"))
|
|
(modules '((guix build utils) (ice-9 ftw)))
|
|
(snippet
|
|
'(let ((keep '("package/base-files/files"
|
|
"package/network/config/netifd/files"
|
|
"package/system/uci/files")))
|
|
(mkdir "keep")
|
|
(for-each (lambda (dir)
|
|
(mkdir-p (string-append "keep/" (dirname dir)))
|
|
(rename-file dir (string-append "keep/" dir)))
|
|
keep)
|
|
(for-each (lambda (f)
|
|
(unless (member f '("." ".." "keep"))
|
|
(delete-file-recursively f)))
|
|
(scandir "."))
|
|
(for-each (lambda (f)
|
|
(unless (member f '("." ".."))
|
|
(rename-file (string-append "keep/" f) f)))
|
|
(scandir "keep"))
|
|
(rmdir "keep")))))
|
|
|
|
(define-public openwrt-base-files
|
|
(package
|
|
(name "openwrt-base-files")
|
|
(version (string-append "0-" (string-take %openwrt-tree-commit 7)))
|
|
(source %openwrt-tree)
|
|
(build-system gnu-build-system) ;not copy: cross refs (PITFALLS #39)
|
|
(arguments
|
|
(list
|
|
#:modules %cross-copy-modules
|
|
#:imported-modules %copy-build-system-modules
|
|
#:phases
|
|
#~(modify-phases
|
|
;; The shell library OpenWrt scripts source (netifd protocols,
|
|
;; hotplug and init scripts): /lib/functions.sh,
|
|
;; /lib/functions/*.sh, and /lib/config/uci.sh from OpenWrt's uci
|
|
;; package. Not the flash, LED, preinit or sysupgrade helpers.
|
|
#$(cross-copy-phases
|
|
#~'(("package/base-files/files/lib/functions.sh" "lib/")
|
|
("package/base-files/files/lib/functions/" "lib/functions/"
|
|
#:include ("network.sh" "ipv4.sh" "system.sh"
|
|
"uci-defaults.sh"))
|
|
("package/system/uci/files/lib/config/uci.sh"
|
|
"lib/config/")
|
|
;; functions.sh's ipcalc() runs it by name.
|
|
("package/base-files/files/bin/ipcalc.sh" "bin/")))
|
|
(add-after 'install 'store-paths
|
|
;; Absolute paths into this package, uci and libubox; plain
|
|
;; command names are found via PATH (set by the services).
|
|
(lambda _
|
|
(substitute* (string-append #$output "/bin/ipcalc.sh")
|
|
;; Not the native bash patch-source-shebangs put there.
|
|
(("^#!.*")
|
|
(string-append "#!" #$(file-append busybox "/bin/sh") "\n")))
|
|
(substitute* (append (find-files (string-append #$output "/lib")
|
|
"\\.sh$")
|
|
(list (string-append #$output
|
|
"/bin/ipcalc.sh")))
|
|
(("/lib/functions\\.sh")
|
|
(string-append #$output "/lib/functions.sh"))
|
|
(("/lib/functions/")
|
|
(string-append #$output "/lib/functions/"))
|
|
(("/lib/config/uci\\.sh")
|
|
(string-append #$output "/lib/config/uci.sh"))
|
|
(("/sbin/uci")
|
|
#$(file-append uci "/bin/uci"))
|
|
(("/usr/share/libubox/jshn\\.sh")
|
|
#$(file-append libubox "/share/libubox/jshn.sh")))
|
|
;; Not every caller has this package's bin/ on PATH: netifd's
|
|
;; dhcp.script ("ipcalc.sh: not found", no subnet check).
|
|
(substitute* (string-append #$output "/lib/functions.sh")
|
|
(("\\$\\(ipcalc\\.sh ")
|
|
(string-append "$(" #$output "/bin/ipcalc.sh "))))))))
|
|
(home-page "https://openwrt.org/")
|
|
(synopsis "OpenWrt shell function library")
|
|
(description
|
|
"The subset of OpenWrt's base-files that its shell scripts source:
|
|
@file{functions.sh} (config loading, @code{append}, @code{ipcalc} with
|
|
@file{bin/ipcalc.sh}, ...),
|
|
@file{functions/network.sh} (@code{network_get_ipaddr} and friends, via
|
|
ubus), and @file{config/uci.sh} (UCI wrappers).")
|
|
(license license:gpl2)))
|
|
|
|
(define-public udebug
|
|
(let ((commit "6726e98ad69402e79b6d0b305012ace857ca0786")
|
|
(revision "0"))
|
|
(package
|
|
(name "udebug")
|
|
(version (git-version "2026.09.25" revision commit))
|
|
(source
|
|
(origin
|
|
(method git-fetch)
|
|
(uri (git-reference
|
|
(url "https://git.openwrt.org/project/udebug.git")
|
|
(commit commit)))
|
|
(file-name (git-file-name name version))
|
|
(sha256
|
|
(base32 "0lqz2hqi0wm212q58ijmlnxyffdcm4c00pci7m5r94cbb310n99w"))))
|
|
(build-system cmake-build-system)
|
|
(arguments (list #:tests? #f #:phases (openwrt-phases)))
|
|
(inputs (list libubox ubus ucode json-c))
|
|
(native-inputs (list pkg-config))
|
|
(home-page "https://git.openwrt.org/?p=project/udebug.git")
|
|
(synopsis "OpenWrt debug ring buffers")
|
|
(description
|
|
"udebug provides shared-memory ring buffers that OpenWrt daemons such
|
|
as netifd log debug data into: @code{libudebug}, the @command{udebugd}
|
|
daemon, the @command{udebug-cli} tool and a ucode module.")
|
|
(license license:gpl2))))
|
|
|
|
(define-public netifd
|
|
(let ((commit "06d06c86d757196e56bb13a1a8d6d69df7cad04d")
|
|
(revision "0"))
|
|
(package
|
|
(name "netifd")
|
|
(version (git-version "2026.09.11" revision commit))
|
|
(source
|
|
(origin
|
|
(method git-fetch)
|
|
(uri (git-reference
|
|
(url "https://git.openwrt.org/project/netifd.git")
|
|
(commit commit)))
|
|
(file-name (git-file-name name version))
|
|
(sha256
|
|
(base32 "19hryqjfz254cv7blygwvmz0r3rbj92gg8c7y54vwvcfwh5rqyh5"))
|
|
;; glibc's popen() is unusable in our cross-built systems
|
|
;; (PITFALLS #35); run /bin/sh directly for handler discovery.
|
|
(patches (list (local-file "patches/netifd-popen-bin-sh.patch")))))
|
|
(build-system cmake-build-system)
|
|
(arguments
|
|
(list
|
|
#:tests? #f ;no tests
|
|
;; make_ethtool_modes_h.sh is run relative to the source tree.
|
|
#:out-of-source? #f
|
|
#:phases
|
|
#~(modify-phases #$(openwrt-phases)
|
|
(add-after 'unpack 'set-main-path
|
|
;; Scripts and ucode files live in OUT/lib/netifd. `-p'
|
|
;; would only cover the shell side: ucode.c loads
|
|
;; DEFAULT_MAIN_PATH "/main.uc" directly.
|
|
(lambda _
|
|
(substitute* "netifd.h"
|
|
(("#define DEFAULT_MAIN_PATH\t\"/lib/netifd\"")
|
|
(string-append "#define DEFAULT_MAIN_PATH\t\""
|
|
#$output "/lib/netifd\"")))))
|
|
(add-after 'install 'install-runtime-files
|
|
;; What OpenWrt's package installs to /lib/netifd. proto/
|
|
;; (dhcp.sh) comes with udhcpc and base-files.
|
|
(lambda _
|
|
(let ((lib (string-append #$output "/lib/netifd"))
|
|
(files (string-append
|
|
#$%openwrt-tree
|
|
"/package/network/config/netifd/files")))
|
|
(for-each (lambda (f) (install-file f lib))
|
|
(append
|
|
(list "scripts/utils.sh"
|
|
"scripts/netifd-proto.sh")
|
|
(find-files (string-append files "/lib/netifd")
|
|
"\\.uc$")))
|
|
;; The dhcp protocol: udhcpc driven by proto/dhcp.sh, with
|
|
;; dhcp.script reporting leases back over ubus.
|
|
(install-file (string-append files "/lib/netifd/dhcp.script")
|
|
lib)
|
|
(install-file (string-append files
|
|
"/lib/netifd/proto/dhcp.sh")
|
|
(string-append lib "/proto"))
|
|
;; Wireless (wifi-scripts): main.uc loads wireless.uc
|
|
;; from its own directory, handlers from wireless/.
|
|
(copy-recursively
|
|
#$(file-append (this-package-input "wifi-scripts")
|
|
"/lib/netifd")
|
|
lib)
|
|
;; ifup/ifdown (one script, by $0), ifstatus, devstatus:
|
|
;; ubus calls to netifd.
|
|
(let ((sbin (string-append #$output "/sbin")))
|
|
(for-each (lambda (f)
|
|
(install-file (string-append files "/sbin/" f)
|
|
sbin))
|
|
'("ifup" "ifstatus" "devstatus"))
|
|
(symlink "ifup" (string-append sbin "/ifdown"))
|
|
(substitute* (list (string-append sbin "/ifstatus")
|
|
(string-append sbin "/devstatus"))
|
|
(("/usr/share/libubox/jshn.sh")
|
|
#$(file-append libubox "/share/libubox/jshn.sh"))))
|
|
(for-each (lambda (f) (chmod f #o755))
|
|
(list (string-append lib "/dhcp.script")
|
|
(string-append lib "/proto/dhcp.sh")
|
|
(string-append #$output "/sbin/ifup")
|
|
(string-append #$output "/sbin/ifstatus")
|
|
(string-append #$output "/sbin/devstatus")))
|
|
;; Sourced by proto scripts: find netifd and jshn.sh in
|
|
;; the store, not /lib/netifd and /usr/share/libubox.
|
|
(substitute* (string-append lib "/netifd-proto.sh")
|
|
(("/lib/netifd\\}") (string-append lib "}"))
|
|
(("/usr/share/libubox/jshn.sh")
|
|
#$(file-append libubox "/share/libubox/jshn.sh")))
|
|
(let ((base #$(this-package-input "openwrt-base-files"))
|
|
(udhcpc #$(file-append (this-package-input "busybox")
|
|
"/sbin/udhcpc")))
|
|
(substitute* (list (string-append lib "/dhcp.script")
|
|
(string-append lib "/proto/dhcp.sh")
|
|
(string-append #$output "/sbin/ifup")
|
|
(string-append #$output "/sbin/ifstatus")
|
|
(string-append #$output "/sbin/devstatus"))
|
|
(("/lib/functions\\.sh")
|
|
(string-append base "/lib/functions.sh"))
|
|
(("/lib/functions/")
|
|
(string-append base "/lib/functions/"))
|
|
(("/lib/config/uci\\.sh")
|
|
(string-append base "/lib/config/uci.sh"))
|
|
(("/lib/netifd/") (string-append lib "/"))
|
|
(("/sbin/udhcpc") udhcpc)
|
|
;; Written for busybox ash (`export -n', ...): run
|
|
;; them with it, not whatever /bin/sh is.
|
|
(("^#!/bin/sh")
|
|
(string-append "#!" #$(file-append
|
|
(this-package-input "busybox")
|
|
"/bin/sh")))
|
|
;; Run by name through netifd: use the store path.
|
|
(("proto_run_command \"\\$config\" udhcpc")
|
|
(string-append "proto_run_command \"$config\" "
|
|
udhcpc))))))))))
|
|
(inputs (list libubox ubus uci ucode json-c libnl-tiny udebug
|
|
openwrt-base-files busybox wifi-scripts))
|
|
(native-inputs (list pkg-config))
|
|
(home-page "https://git.openwrt.org/?p=project/netifd.git")
|
|
(synopsis "OpenWrt network interface configuration daemon")
|
|
(description
|
|
"netifd configures network devices, interfaces, bridges, VLANs and
|
|
routes from UCI (@file{/etc/config/network}) and exposes their state on
|
|
ubus (@code{network.interface.*}); protocol handlers are built in (static)
|
|
or shell/ucode scripts (dhcp, ...).")
|
|
(license license:gpl2))))
|
|
|
|
(define-public odhcpd
|
|
(let ((commit "68f382690bfaec56d5b1f31c3c31c48bcb642e3a")
|
|
(revision "0"))
|
|
(package
|
|
(name "odhcpd")
|
|
(version (git-version "2026.06.28" revision commit))
|
|
(source
|
|
(origin
|
|
(method git-fetch)
|
|
(uri (git-reference
|
|
(url "https://git.openwrt.org/project/odhcpd.git")
|
|
(commit commit)))
|
|
(file-name (git-file-name name version))
|
|
(sha256
|
|
(base32 "0pfj7rid49hsf564az5mjv2q3hlv1kjdy2qvq5q6hfvlb57bywfv"))))
|
|
(build-system cmake-build-system)
|
|
(arguments
|
|
(list
|
|
;; OpenWrt's "odhcpd" (full) variant. DHCPv4 is built in but off
|
|
;; in our UCI seed: dnsmasq serves DHCPv4 and DNS, as on OpenWrt.
|
|
#:configure-flags #~'("-DUBUS=ON" "-DDHCPV4_SUPPORT=ON")
|
|
#:tests? #f ;no tests
|
|
#:phases
|
|
#~(modify-phases #$(openwrt-phases)
|
|
(add-after 'install 'install-odhcpd-update
|
|
;; The `leasetrigger' run (posix_spawn, absolute file name)
|
|
;; when leases change: make dnsmasq reread the hosts files
|
|
;; odhcpd writes to `hostsdir'. OpenWrt's version signals
|
|
;; through procd; here dnsmasq-service-type's `reload' action
|
|
;; sends the SIGHUP. (Not `pkill -x dnsmasq': busybox
|
|
;; matches the whole /gnu/store/.../dnsmasq argv[0].)
|
|
(lambda _
|
|
(let ((script (string-append #$output "/sbin/odhcpd-update"))
|
|
(busybox #$(this-package-input "busybox")))
|
|
(call-with-output-file script
|
|
(lambda (port)
|
|
(format port "#!~a/bin/sh
|
|
# Make dnsmasq reread odhcpd's hosts files.
|
|
exec /run/current-system/profile/bin/herd reload dnsmasq >/dev/null~%"
|
|
busybox)))
|
|
(chmod script #o755)))))))
|
|
(inputs (list libubox ubus uci json-c libnl-tiny busybox))
|
|
(native-inputs (list pkg-config))
|
|
(home-page "https://git.openwrt.org/?p=project/odhcpd.git")
|
|
(synopsis "OpenWrt DHCPv6, router advertisement and NDP server")
|
|
(description
|
|
"odhcpd serves and relays the IPv6 configuration protocols of a home
|
|
router (RFC 6204): router advertisements, DHCPv6 (stateful and stateless,
|
|
with prefix delegation) and NDP proxying, plus optionally DHCPv4. It is
|
|
configured from UCI (@file{/etc/config/dhcp}) and follows netifd's
|
|
interfaces over ubus.")
|
|
(license license:gpl2))))
|
|
|
|
(define-public firewall4
|
|
(let ((commit "b6e5157527d361f99ad52eaa6da273cb0f2dfd59")
|
|
(revision "0"))
|
|
(package
|
|
(name "firewall4")
|
|
(version (git-version "2025.03.17" revision commit))
|
|
(source
|
|
(origin
|
|
(method git-fetch)
|
|
(uri (git-reference
|
|
(url "https://git.openwrt.org/project/firewall4.git")
|
|
(commit commit)))
|
|
(file-name (git-file-name name version))
|
|
(sha256
|
|
(base32 "113sjgwrnlk451b7d3hjl11f44rr9j8vvhy4qych636mvcg29g1m"))))
|
|
(build-system gnu-build-system) ;not copy: cross refs (PITFALLS #39)
|
|
(arguments
|
|
(list
|
|
#:modules %cross-copy-modules
|
|
#:imported-modules %copy-build-system-modules
|
|
#:phases
|
|
#~(modify-phases
|
|
;; OpenWrt's layout, minus /usr. etc/ holds the stock
|
|
;; /etc/config/firewall and the hotplug script, for the
|
|
;; service to use; nothing reads them from the store directly.
|
|
#$(cross-copy-phases
|
|
#~'(("root/sbin/fw4" "sbin/")
|
|
("root/usr/share/firewall4" "share/firewall4")
|
|
("root/usr/share/ucode/fw4.uc" "share/ucode/")
|
|
("root/usr/share/nftables.d" "share/nftables.d")
|
|
;; Not init.d/firewall: a procd script.
|
|
("root/etc" "etc" #:exclude-regexp ("init\\.d"))))
|
|
(add-after 'install 'store-paths
|
|
(lambda _
|
|
(let ((busybox #$(this-package-input "busybox"))
|
|
(nft #$(file-append (this-package-input "nftables")
|
|
"/sbin/nft"))
|
|
(utpl #$(file-append (this-package-input "ucode")
|
|
"/bin/utpl"))
|
|
(share (string-append #$output "/share")))
|
|
(substitute* (string-append share "/ucode/fw4.uc")
|
|
(("/usr/sbin/nft") nft)
|
|
(("/usr/share/firewall4/") (string-append share "/firewall4/"))
|
|
(("/usr/share/nftables.d/")
|
|
(string-append share "/nftables.d/")))
|
|
;; fw4 runs utpl, nft and flock by name, and main.uc runs
|
|
;; firewall includes with `sh': give it its own PATH.
|
|
;; -L: load this fw4.uc, not whatever the profile has.
|
|
(substitute* (string-append #$output "/sbin/fw4")
|
|
;; (patch-source-shebangs has already run.)
|
|
(("^#!.*/bin/sh")
|
|
(string-append "#!" busybox "/bin/sh\n"
|
|
"PATH=" busybox "/bin:" busybox "/sbin:"
|
|
(dirname nft) ":" (dirname utpl)
|
|
":$PATH"))
|
|
(("^MAIN=/usr/share/firewall4/main.uc")
|
|
(string-append "MAIN=" share "/firewall4/main.uc"))
|
|
(("utpl -S")
|
|
(string-append "utpl -L " share "/ucode -S")))
|
|
;; netifd's hotplug: there is no /etc/init.d/firewall;
|
|
;; reload only when fw4 has loaded a ruleset (state file),
|
|
;; i.e. the firewall service runs.
|
|
(substitute* (string-append #$output
|
|
"/etc/hotplug.d/iface/20-firewall")
|
|
;; Not the native bash patch-source-shebangs put there.
|
|
(("^#!.*/bin/sh") (string-append "#!" busybox "/bin/sh"))
|
|
(("^/etc/init.d/firewall enabled \\|\\| exit 0")
|
|
"[ -f /var/run/fw4.state ] || exit 0"))
|
|
;; As OpenWrt's package: LuCI's firewall pages look for
|
|
;; fw3.
|
|
(symlink "fw4" (string-append #$output "/sbin/fw3"))))))))
|
|
(inputs (list busybox nftables ucode))
|
|
(home-page "https://git.openwrt.org/?p=project/firewall4.git")
|
|
(synopsis "OpenWrt nftables firewall configured from UCI")
|
|
(description
|
|
"firewall4 (fw4) generates an nftables ruleset from the UCI firewall
|
|
configuration (@file{/etc/config/firewall}: zones, forwardings, rules,
|
|
redirects, NAT, sets) and loads it into the @code{inet fw4} table. It
|
|
follows netifd's interfaces over ubus and is written in ucode.")
|
|
(license license:isc))))
|
|
|
|
|
|
;; One package's files/ directory from the OpenWrt tree (init scripts, stock
|
|
;; configs): same checkout as %openwrt-tree, another subset.
|
|
(define (openwrt-tree-files dir)
|
|
(origin
|
|
(inherit %openwrt-tree)
|
|
(snippet
|
|
#~(begin
|
|
(use-modules (guix build utils) (ice-9 ftw))
|
|
(rename-file #$dir "../files")
|
|
(for-each (lambda (f)
|
|
(unless (member f '("." ".."))
|
|
(delete-file-recursively f)))
|
|
(scandir "."))
|
|
(copy-recursively "../files" ".")
|
|
(delete-file-recursively "../files")))))
|
|
|
|
;; OpenWrt's dnsmasq init script, which renders /etc/config/dhcp into
|
|
;; dnsmasq's configuration -- what LuCI's DNS and DHCP pages edit.
|
|
(define %openwrt-dnsmasq-files
|
|
(openwrt-tree-files "package/network/services/dnsmasq/files"))
|
|
|
|
(define-public openwrt-dnsmasq
|
|
(package
|
|
(name "openwrt-dnsmasq")
|
|
(version (string-append "0-" (string-take %openwrt-tree-commit 7)))
|
|
(source %openwrt-dnsmasq-files)
|
|
(build-system gnu-build-system) ;not copy: cross refs (PITFALLS #39)
|
|
(arguments
|
|
(list
|
|
#:modules %cross-copy-modules
|
|
#:imported-modules %copy-build-system-modules
|
|
#:phases
|
|
#~(modify-phases
|
|
#$(cross-copy-phases
|
|
#~'(("dnsmasq.init" "share/openwrt-dnsmasq/")
|
|
("dhcpbogushostname.conf" "share/dnsmasq/")
|
|
("rfc6761.conf" "share/dnsmasq/")
|
|
("dhcp-script.sh" "lib/dnsmasq/")))
|
|
(add-after 'install 'store-paths
|
|
(lambda _
|
|
(let* ((busybox #$(this-package-input "busybox"))
|
|
(base #$(this-package-input "openwrt-base-files"))
|
|
(profile "/run/current-system/profile")
|
|
(init (string-append #$output
|
|
"/share/openwrt-dnsmasq/dnsmasq.init")))
|
|
(substitute* init
|
|
;; The service sets DNSMASQ (rpi4.scm's dnsmasq build).
|
|
(("^PROG=/usr/sbin/dnsmasq") "PROG=\"${DNSMASQ:?}\"")
|
|
(("/usr/share/dnsmasq/")
|
|
(string-append #$output "/share/dnsmasq/"))
|
|
(("/usr/lib/dnsmasq/")
|
|
(string-append #$output "/lib/dnsmasq/"))
|
|
(("/lib/functions/network\\.sh")
|
|
(string-append base "/lib/functions/network.sh"))
|
|
;; odhcpd "installed and enabled": a Shepherd service.
|
|
(("\\[ -x /usr/sbin/odhcpd \\] && \\[ -x /etc/init.d/odhcpd \\]")
|
|
(string-append "[ -x " profile "/sbin/odhcpd ]"))
|
|
;; Not `herd status': the renderer must never talk to
|
|
;; Shepherd, which may be waiting on it (PITFALLS #43).
|
|
(("/etc/init.d/odhcpd enabled") "true")
|
|
;; --enable-ubus only if this dnsmasq has it (Guix's
|
|
;; doesn't: "no-UBus").
|
|
(("\\[ \\$ubus -gt 0 \\] && xappend")
|
|
"[ $ubus -gt 0 ] && ! $PROG --version | grep -q no-UBus && xappend"))
|
|
(substitute* (string-append #$output "/lib/dnsmasq/dhcp-script.sh")
|
|
(("^#!.*") (string-append "#!" busybox "/bin/sh\n")))))))))
|
|
(inputs (list busybox openwrt-base-files))
|
|
(home-page "https://openwrt.org/")
|
|
(synopsis "OpenWrt's dnsmasq configuration from UCI")
|
|
(description
|
|
"OpenWrt's dnsmasq init script, which turns @file{/etc/config/dhcp}
|
|
(DNS and DHCPv4 settings, static leases, domains) into a dnsmasq
|
|
configuration; @command{openwrt-rc} (procd-compat) runs it.")
|
|
(license license:gpl2)))
|
|
|
|
;; OpenWrt's uhttpd init script and stock /etc/config/uhttpd: uhttpd
|
|
;; configured from UCI (LuCI, TollGate's setup edit it).
|
|
(define-public openwrt-uhttpd
|
|
(package
|
|
(name "openwrt-uhttpd")
|
|
(version (string-append "0-" (string-take %openwrt-tree-commit 7)))
|
|
(source (openwrt-tree-files "package/network/services/uhttpd/files"))
|
|
(build-system gnu-build-system) ;not copy: cross refs (PITFALLS #39)
|
|
(arguments
|
|
(list
|
|
#:modules %cross-copy-modules
|
|
#:imported-modules %copy-build-system-modules
|
|
#:phases
|
|
#~(modify-phases
|
|
#$(cross-copy-phases
|
|
#~'(("uhttpd.init" "share/openwrt-uhttpd/")
|
|
("uhttpd.config" "share/openwrt-uhttpd/")
|
|
;; OpenWrt installs it as uci-defaults/00_uhttpd_ubus.
|
|
("ubus.default" "share/openwrt-uhttpd/")))
|
|
(add-after 'install 'store-paths
|
|
(lambda _
|
|
(let ((uhttpd #$(this-package-input "uhttpd"))
|
|
(ustream #$(this-package-input "ustream-ssl")))
|
|
(substitute* (string-append #$output
|
|
"/share/openwrt-uhttpd/uhttpd.init")
|
|
(("^UHTTPD_BIN=.*")
|
|
(string-append "UHTTPD_BIN=\"" uhttpd "/bin/uhttpd\"\n"))
|
|
;; Certificate generation (no px5g here).
|
|
(("^OPENSSL_BIN=.*")
|
|
(string-append "OPENSSL_BIN=\""
|
|
#$(this-package-input "openssl")
|
|
"/bin/openssl\"\n"))
|
|
;; Plugin and TLS checks.
|
|
(("/usr/lib/uhttpd_(ubus|ucode|lua)\\.so" _ plugin)
|
|
(string-append uhttpd "/lib/uhttpd_" plugin ".so"))
|
|
(("/lib/libustream-ssl\\.so")
|
|
(string-append ustream "/lib/libustream-ssl.so")))))))))
|
|
(inputs (list uhttpd ustream-ssl openssl))
|
|
(home-page "https://openwrt.org/")
|
|
(synopsis "OpenWrt's uhttpd configuration from UCI")
|
|
(description
|
|
"OpenWrt's uhttpd init script, which starts uhttpd as
|
|
@file{/etc/config/uhttpd} says (listeners, TLS certificate generation,
|
|
ubus and ucode handlers), its stock configuration and uci-defaults script.")
|
|
(license license:gpl2)))
|
|
|
|
;; Guix's iptables-nft (iptables, ip6tables, ... -> xtables-nft-multi) uses
|
|
;; copy-build-system, so in a cross-built system its links point at an
|
|
;; x86_64 iptables (PITFALLS #39). Same links, with the GNU build system.
|
|
(define-public iptables-nft/cross
|
|
(package
|
|
(inherit iptables-nft)
|
|
(build-system gnu-build-system)
|
|
(arguments
|
|
(list
|
|
#:tests? #f
|
|
#:phases
|
|
#~(modify-phases %standard-phases
|
|
(delete 'unpack)
|
|
(delete 'configure)
|
|
(delete 'build)
|
|
(replace 'install
|
|
(lambda _
|
|
(let ((multi #$(file-append (this-package-input "iptables")
|
|
"/sbin/xtables-nft-multi")))
|
|
(for-each
|
|
(lambda (command)
|
|
(let ((link (string-append #$output command)))
|
|
(mkdir-p (dirname link))
|
|
(symlink multi link)))
|
|
(cons "/bin/iptables-xml"
|
|
(apply append
|
|
(map (lambda (xtables)
|
|
(map (lambda (suffix)
|
|
(string-append "/sbin/" xtables
|
|
suffix))
|
|
'("" "-restore" "-save")))
|
|
'("arptables" "ebtables" "iptables"
|
|
"ip6tables")))))))))))))
|
|
|
|
;; As OpenWrt's libmicrohttpd-no-ssl: nodogsplash serves plain HTTP, and
|
|
;; Guix's TLS inputs (gnutls/dane, curl, ...) are a long cross build.
|
|
(define libmicrohttpd/no-tls
|
|
(package
|
|
(inherit libmicrohttpd)
|
|
(name "libmicrohttpd-no-tls")
|
|
(arguments
|
|
(list #:configure-flags
|
|
#~(list "--disable-static" "--disable-https"
|
|
;; Their test programs use curl.
|
|
"--disable-curl")
|
|
#:tests? #f))
|
|
(inputs '())))
|
|
|
|
;; Captive portal (TollGate's gate: `ndsctl auth'). iptables rules, through
|
|
;; iptables-nft beside fw4's nftables table, as on OpenWrt.
|
|
(define-public nodogsplash
|
|
(package
|
|
(name "nodogsplash")
|
|
(version "5.0.2")
|
|
(source
|
|
(origin
|
|
(method url-fetch)
|
|
(uri (string-append "https://codeload.github.com/nodogsplash/"
|
|
"nodogsplash/tar.gz/v" version))
|
|
(file-name (string-append name "-" version ".tar.gz"))
|
|
(sha256
|
|
(base32 "15vp85mkyzm5h5bl4ilxvwsk8xa5qw2nffsczg7gs9ipx5s3d3ch"))))
|
|
(build-system gnu-build-system)
|
|
(arguments
|
|
(list
|
|
#:tests? #f ;no tests
|
|
#:make-flags #~(list (string-append "CC=" #$(cc-for-target)))
|
|
#:phases
|
|
#~(modify-phases %standard-phases
|
|
(delete 'configure)
|
|
(replace 'install
|
|
;; Not its install target (strip, /etc). htdocs are a template
|
|
;; for /etc/nodogsplash/htdocs, which TollGate rewrites.
|
|
(lambda _
|
|
(let ((share (string-append #$output "/share/nodogsplash")))
|
|
(for-each (lambda (f)
|
|
(install-file f (string-append #$output "/bin")))
|
|
'("nodogsplash" "ndsctl"))
|
|
(install-file "resources/nodogsplash.conf" share)
|
|
(for-each (lambda (f)
|
|
(install-file (string-append "resources/" f)
|
|
(string-append share "/htdocs")))
|
|
'("splash.html" "splash.css" "status.html"))
|
|
(install-file "resources/splash.jpg"
|
|
(string-append share "/htdocs/images"))))))))
|
|
(inputs (list libmicrohttpd/no-tls))
|
|
(home-page "https://github.com/nodogsplash/nodogsplash")
|
|
(synopsis "Captive portal for wireless and wired networks")
|
|
(description
|
|
"Nodogsplash gates a network's clients behind a splash page: until a
|
|
client is authenticated (from the page, or with @command{ndsctl auth}), its
|
|
traffic is limited by iptables rules to what the configuration allows.")
|
|
(license license:gpl2+)))
|
|
|
|
;; OpenWrt's nodogsplash files (packages feed, net/nodogsplash/files).
|
|
(define %openwrt-packages-commit "5ff48e80f3c582b71c40d072e04341516690592a")
|
|
|
|
(define (openwrt-packages-file path hash)
|
|
(origin
|
|
(method url-fetch)
|
|
(uri (string-append "https://raw.githubusercontent.com/openwrt/packages/"
|
|
%openwrt-packages-commit "/" path))
|
|
(file-name (string-append "openwrt-packages-"
|
|
(string-take %openwrt-packages-commit 7) "-"
|
|
(basename path)))
|
|
(sha256 (base32 hash))))
|
|
|
|
(define-public openwrt-nodogsplash
|
|
(package
|
|
(name "openwrt-nodogsplash")
|
|
(version (string-append "0-" (string-take %openwrt-packages-commit 7)))
|
|
(source #f)
|
|
(build-system gnu-build-system) ;not copy: cross refs (PITFALLS #39)
|
|
(arguments
|
|
(list
|
|
#:tests? #f
|
|
#:phases
|
|
#~(modify-phases %standard-phases
|
|
(delete 'unpack)
|
|
(delete 'configure)
|
|
(delete 'build)
|
|
(replace 'install
|
|
(lambda _
|
|
(let* ((share (string-append #$output "/share/openwrt-nodogsplash"))
|
|
(busybox #$(this-package-input "busybox"))
|
|
(init (string-append share "/nodogsplash.init"))
|
|
(restart (string-append share "/restart.sh"))
|
|
(defaults (string-append share "/40_nodogsplash"))
|
|
(config (string-append share "/nodogsplash.config")))
|
|
(mkdir-p share)
|
|
(copy-file #$(openwrt-packages-file
|
|
"net/nodogsplash/files/etc/init.d/nodogsplash"
|
|
"0hs5i8j9xv2cny5s4cww24l57aj9q7xizn6bfzfn5n27jqphl478")
|
|
init)
|
|
(copy-file #$(openwrt-packages-file
|
|
"net/nodogsplash/files/etc/config/nodogsplash"
|
|
"1m2k2yxw40m5z6l0as7pkmr4d5mz0s8qwmib8n3swv0g8mpdfc43")
|
|
config)
|
|
(copy-file #$(openwrt-packages-file
|
|
"net/nodogsplash/files/etc/uci-defaults/40_nodogsplash"
|
|
"17l9wkjrc5vr2n47w9hg6v5i3acb7k58c7sm5rzmpd0d18l5336r")
|
|
defaults)
|
|
(copy-file #$(openwrt-packages-file
|
|
"net/nodogsplash/files/usr/lib/nodogsplash/restart.sh"
|
|
"0rddk9wb04krmr6zyhn65dj1mi81rc072nidmyac5jc6mimnc2aj")
|
|
restart)
|
|
(for-each make-file-writable (list init config defaults restart))
|
|
(substitute* init
|
|
(("/usr/bin/nodogsplash")
|
|
#$(file-append (this-package-input "nodogsplash")
|
|
"/bin/nodogsplash"))
|
|
(("include /lib/functions")
|
|
(string-append "include "
|
|
#$(this-package-input "openwrt-base-files")
|
|
"/lib/functions")))
|
|
(substitute* defaults
|
|
;; Written into /etc/config/firewall: a path that
|
|
;; survives upgrades (this package is in the profile).
|
|
(("/usr/lib/nodogsplash/restart.sh")
|
|
"/run/current-system/profile/share/openwrt-nodogsplash/restart.sh"))
|
|
(substitute* restart
|
|
(("^#!.*") (string-append "#!" busybox "/bin/sh\n"))
|
|
;; Run by fw4 (firewall include) on every reload: detach,
|
|
;; so the firewall reload never waits for herd (PITFALLS
|
|
;; #43).
|
|
(("^ /etc/init.d/nodogsplash restart")
|
|
" ( /etc/init.d/nodogsplash restart ) </dev/null >/dev/null 2>&1 &"))
|
|
(chmod restart #o755)))))))
|
|
(inputs (list busybox nodogsplash openwrt-base-files))
|
|
(home-page "https://github.com/openwrt/packages")
|
|
(synopsis "OpenWrt's nodogsplash configuration from UCI")
|
|
(description
|
|
"OpenWrt's nodogsplash init script (which renders
|
|
@file{/etc/config/nodogsplash}), stock configuration, uci-defaults script and
|
|
firewall include.")
|
|
(license license:gpl2+)))
|
|
|
|
;;; OpenWrt's wireless stack: hostapd/wpa_supplicant with OpenWrt's ubus and
|
|
;;; ucode control (wpad), driven by netifd's ucode wireless scripts.
|
|
|
|
(define %openwrt-hostapd-files
|
|
(openwrt-tree-files "package/network/services/hostapd"))
|
|
|
|
;; hostapd + wpa_supplicant as one multicall binary, OpenWrt's
|
|
;; wpad-basic-openssl: upstream hostap at OpenWrt's commit, plus OpenWrt's
|
|
;; source overlay (ubus and ucode control) and patches.
|
|
(define-public wpad
|
|
(let ((commit "831364bf02710ad09c2f27d3efa92abeeb5634c0")
|
|
(revision "0"))
|
|
(package
|
|
(name "wpad")
|
|
(version (git-version "2026.08.07" revision commit))
|
|
(source
|
|
(origin
|
|
(method git-fetch)
|
|
(uri (git-reference
|
|
(url "https://w1.fi/hostap.git")
|
|
(commit commit)))
|
|
(file-name (git-file-name "hostap" version))
|
|
(sha256
|
|
(base32 "1cvndbkg5g5sh9brzvj2fr5q8n2mjk8rfpsqvkh5hyrbrkfh2blg"))))
|
|
(build-system gnu-build-system)
|
|
(arguments
|
|
(list
|
|
#:tests? #f
|
|
#:phases
|
|
#~(modify-phases %standard-phases
|
|
(add-after 'unpack 'openwrt-overlay
|
|
;; As OpenWrt's Build/Prepare: src/ over the tree, then the
|
|
;; patches in order.
|
|
(lambda _
|
|
(let ((owrt #$%openwrt-hostapd-files))
|
|
(copy-recursively (string-append owrt "/src") ".")
|
|
(for-each (lambda (p)
|
|
(invoke "patch" "-p1" "--no-backup-if-mismatch"
|
|
"-i" p))
|
|
(sort (find-files (string-append owrt "/patches")
|
|
"\\.patch$")
|
|
string<?))
|
|
;; Its ucode scripts (hostapd.uc, wifi-scripts' wdev.uc,
|
|
;; ...) from the profile.
|
|
(substitute* "src/utils/ucode.h"
|
|
(("\"/usr/share/hostap/\"")
|
|
"\"/run/current-system/profile/share/hostap/\""))
|
|
(copy-file (string-append owrt "/files/hostapd-basic.config")
|
|
"hostapd/.config")
|
|
(copy-file (string-append owrt
|
|
"/files/wpa_supplicant-basic.config")
|
|
"wpa_supplicant/.config"))))
|
|
(delete 'configure)
|
|
(replace 'build
|
|
;; OpenWrt's Build/Compile/wpad: both halves with the same
|
|
;; CFLAGS (dump_cflags of each), as multicall archives, linked
|
|
;; with multicall.c.
|
|
(lambda _
|
|
(setenv "CC" #$(cc-for-target))
|
|
(setenv "AR" #$(ar-for-target))
|
|
(setenv "BCHECK" "")
|
|
(setenv "CFLAGS"
|
|
(string-append
|
|
"-O2 -I" #$(this-package-input "libnl-tiny")
|
|
"/include/libnl-tiny -I" (getcwd) "/src/crypto"
|
|
" -DCONFIG_LIBNL20 -D_GNU_SOURCE"))
|
|
(setenv "LIBS" (string-append
|
|
"-lubox -lubus -lblobmsg_json -lucode -lm"
|
|
" -lnl-tiny -ludebug -lcrypto -lssl"))
|
|
(let ((opts '("CONFIG_ACS=y" "CONFIG_DRIVER_NL80211=y"
|
|
"CONFIG_IEEE80211AC=y" "CONFIG_IEEE80211AX=y"
|
|
"CONFIG_UCODE=y" "CONFIG_APUP=y"
|
|
"CONFIG_TLS=openssl" "CONFIG_SAE=y"
|
|
"CONFIG_OWE=y" "MULTICALL=1")))
|
|
(invoke "sh" "-c"
|
|
(string-append
|
|
"echo `make -C hostapd -s " (string-join opts)
|
|
" dump_cflags; make -C wpa_supplicant -s "
|
|
(string-join opts) " dump_cflags | sed -e 's,-n ,,g'`"
|
|
" > .cflags"))
|
|
(let ((cflags (call-with-input-file ".cflags"
|
|
(lambda (port)
|
|
(string-trim-both
|
|
((@ (ice-9 rdelim) read-line) port))))))
|
|
(apply invoke "make" "-C" "hostapd"
|
|
(string-append "CFLAGS=" cflags)
|
|
(append opts '("hostapd_cli" "hostapd_multi.a")))
|
|
(apply invoke "make" "-C" "wpa_supplicant"
|
|
(string-append "CFLAGS=" cflags)
|
|
(append opts '("wpa_cli" "wpa_supplicant_multi.a")))
|
|
(apply invoke #$(cc-for-target) "-O2" "-o" "wpad"
|
|
(string-append #$%openwrt-hostapd-files
|
|
"/files/multicall.c")
|
|
"hostapd/hostapd_multi.a"
|
|
"wpa_supplicant/wpa_supplicant_multi.a"
|
|
(string-split (getenv "LIBS") #\space))))))
|
|
(replace 'install
|
|
(lambda _
|
|
(let ((sbin (string-append #$output "/sbin"))
|
|
(share (string-append #$output "/share/hostap"))
|
|
(owrt #$%openwrt-hostapd-files))
|
|
(install-file "wpad" sbin)
|
|
(for-each (lambda (name)
|
|
(symlink "wpad" (string-append sbin "/" name)))
|
|
'("hostapd" "wpa_supplicant"))
|
|
(install-file "hostapd/hostapd_cli" sbin)
|
|
(install-file "wpa_supplicant/wpa_cli" sbin)
|
|
(for-each (lambda (f)
|
|
(install-file (string-append owrt "/files/" f)
|
|
share))
|
|
'("hostapd.uc" "wpa_supplicant.uc"))
|
|
;; FILS DHCP server lookup (hostapd.sh), by profile path.
|
|
(install-file (string-append owrt "/files/dhcp-get-server.sh")
|
|
(string-append #$output "/lib/netifd"))
|
|
(substitute* (string-append #$output
|
|
"/lib/netifd/dhcp-get-server.sh")
|
|
(("^#!.*")
|
|
(string-append "#!" #$(file-append
|
|
(this-package-input "busybox")
|
|
"/bin/sh")
|
|
"\n")))))))))
|
|
(inputs (list libnl-tiny libubox ubus ucode udebug openssl json-c busybox))
|
|
(home-page "https://w1.fi/hostapd/")
|
|
(synopsis "hostapd and wpa_supplicant with OpenWrt's ubus/ucode control")
|
|
(description
|
|
"OpenWrt's wpad: hostapd (access point) and wpa_supplicant (client)
|
|
in one binary, with OpenWrt's patches, which add the ubus objects and ucode
|
|
scripts netifd's wireless handling configures them through.")
|
|
(license license:bsd-3))))
|
|
|
|
;; netifd's wireless handling and `wifi' (OpenWrt's wifi-scripts, ucode
|
|
;; variant): /etc/config/wireless -> hostapd/wpa_supplicant over ubus. The
|
|
;; lib/netifd part must sit next to netifd's main.uc (netifd copies it in);
|
|
;; the ucode modules are found in the profile.
|
|
(define-public wifi-scripts
|
|
(package
|
|
(name "wifi-scripts")
|
|
(version (string-append "0-" (string-take %openwrt-tree-commit 7)))
|
|
(source (openwrt-tree-files "package/network/config/wifi-scripts"))
|
|
(build-system gnu-build-system) ;not copy: cross refs (PITFALLS #39)
|
|
(arguments
|
|
(list
|
|
#:modules %cross-copy-modules
|
|
#:imported-modules %copy-build-system-modules
|
|
#:phases
|
|
#~(modify-phases
|
|
;; files/, then files-ucode/ over it, as the Makefile; minus
|
|
;; WPS buttons, the ath12k trigger, procd hotplug and the ucode
|
|
;; iwinfo CLI (the iwinfo package has the C one).
|
|
#$(cross-copy-phases
|
|
#~'(("files/lib/netifd" "lib/netifd")
|
|
("files/lib/wifi" "lib/wifi")
|
|
("files/sbin/wifi" "sbin/")
|
|
("files/usr/share" "share")
|
|
("files-ucode/lib/netifd" "lib/netifd")
|
|
("files-ucode/usr/share" "share")))
|
|
(add-after 'install 'store-paths
|
|
(lambda _
|
|
(let* ((out #$output)
|
|
(profile "/run/current-system/profile")
|
|
(busybox #$(this-package-input "busybox"))
|
|
(ucode #$(file-append (this-package-input "ucode")
|
|
"/bin/ucode"))
|
|
(base #$(this-package-input "openwrt-base-files"))
|
|
(jshn #$(file-append (this-package-input "libubox")
|
|
"/share/libubox/jshn.sh"))
|
|
(scripts (append (find-files (string-append out "/lib"))
|
|
(find-files (string-append out "/share"))
|
|
(list (string-append out "/sbin/wifi")))))
|
|
(substitute* scripts
|
|
(("/usr/share/libubox/jshn\\.sh") jshn)
|
|
(("/lib/functions/network\\.sh")
|
|
(string-append base "/lib/functions/network.sh"))
|
|
(("([ .])/lib/functions\\.sh" _ pre)
|
|
(string-append pre base "/lib/functions.sh"))
|
|
;; hostapd/wpa_supplicant: wpad, in the profile.
|
|
(("/usr/sbin/(hostapd|wpa_supplicant)" _ prog)
|
|
(string-append profile "/sbin/" prog))
|
|
;; hostap's ucode helpers: here, in the profile (wpad has
|
|
;; its hostapd.uc there too).
|
|
(("/usr/share/hostap/")
|
|
(string-append profile "/share/hostap/"))
|
|
(("/usr/share/(schema/|wifi_devices\\.json|iso3166\\.json)"
|
|
_ rest)
|
|
(string-append out "/share/" rest))
|
|
(("/lib/wifi/mac80211\\.uc")
|
|
(string-append out "/lib/wifi/mac80211.uc"))
|
|
(("include /lib/wifi")
|
|
(string-append "include " out "/lib/wifi"))
|
|
(("/lib/netifd/dhcp-get-server\\.sh")
|
|
(string-append profile "/lib/netifd/dhcp-get-server.sh"))
|
|
(("^#!/usr/bin/ucode") (string-append "#!" ucode)))
|
|
(substitute* (string-append out "/sbin/wifi")
|
|
(("^#!.*/bin/sh")
|
|
(string-append "#!" busybox "/bin/sh\n"
|
|
"PATH=" #$(this-package-input "uci") "/bin:"
|
|
#$(this-package-input "ubus") "/bin:"
|
|
(dirname ucode) ":" busybox "/bin:$PATH")))
|
|
(for-each (lambda (f) (chmod f #o755))
|
|
(list (string-append out "/sbin/wifi")
|
|
(string-append out
|
|
"/lib/netifd/wireless/mac80211.sh")))))))))
|
|
(inputs (list busybox ucode uci ubus libubox openwrt-base-files))
|
|
(home-page "https://openwrt.org/")
|
|
(synopsis "OpenWrt's netifd wireless scripts and wifi command")
|
|
(description
|
|
"OpenWrt's wifi-scripts (ucode variant): netifd's wireless handling,
|
|
which configures hostapd and wpa_supplicant (wpad) over ubus from
|
|
@file{/etc/config/wireless}, radio detection and the @command{wifi}
|
|
command.")
|
|
(license license:gpl2)))
|
|
|
|
;; LuCI's backend: ubus sessions with ACLs, UCI over ubus, plugins.
|
|
(define-public rpcd
|
|
(let ((commit "d99f703e4035d03fbcfbada3cb697db346c2b984")
|
|
(revision "0"))
|
|
(package
|
|
(name "rpcd")
|
|
(version (git-version "2026.10.04" revision commit))
|
|
(source
|
|
(origin
|
|
(method git-fetch)
|
|
(uri (git-reference
|
|
(url "https://git.openwrt.org/project/rpcd.git")
|
|
(commit commit)))
|
|
(file-name (git-file-name name version))
|
|
(sha256
|
|
(base32 "08km7ihigw4pxxwskjw6483hy0h7km0cclav33qhjxw3z4znfb75"))))
|
|
(build-system cmake-build-system)
|
|
(arguments
|
|
(list
|
|
#:tests? #f ;no tests
|
|
#:phases
|
|
#~(modify-phases #$(openwrt-phases)
|
|
(add-after 'unpack 'fix-paths
|
|
(lambda _
|
|
;; INSTALL_PREFIX roots the ACL (share/rpcd/acl.d), plugin
|
|
;; (lib/rpcd, libexec/rpcd) and ucode script
|
|
;; (share/rpcd/ucode) directories, which LuCI packages add
|
|
;; to: the system profile, not this package. rpcd is in the
|
|
;; profile, so its own plugins and ACL are found there too.
|
|
(substitute* "CMakeLists.txt"
|
|
(("-DINSTALL_PREFIX=\"\\$\\{CMAKE_INSTALL_PREFIX\\}\"")
|
|
"-DINSTALL_PREFIX=\"/run/current-system/profile\""))
|
|
(substitute* "uci.c"
|
|
;; `uci apply': procd-compat's reload_config.
|
|
(("\"/sbin/reload_config\"")
|
|
"\"/run/current-system/profile/sbin/reload_config\""))
|
|
(substitute* "sys.c"
|
|
;; LuCI's password change pipes the password twice into
|
|
;; passwd's stdin: busybox's, which reads it without a tty.
|
|
(("\"/bin/passwd\"")
|
|
(string-append "\"" #$(this-package-input "busybox")
|
|
"/bin/passwd\"")))))
|
|
(add-after 'install 'install-acl-and-headers
|
|
(lambda _
|
|
(install-file "../source/unauthenticated.json"
|
|
(string-append #$output
|
|
"/share/rpcd/acl.d"))
|
|
;; For out-of-tree plugins (rpcd-mod-luci), as OpenWrt's
|
|
;; InstallDev.
|
|
(copy-recursively "../source/include/rpcd"
|
|
(string-append #$output
|
|
"/include/rpcd")))))))
|
|
(inputs (list libubox ubus uci ucode json-c libxcrypt busybox iwinfo))
|
|
(native-inputs (list pkg-config))
|
|
(home-page "https://git.openwrt.org/?p=project/rpcd.git")
|
|
(synopsis "OpenWrt ubus RPC daemon for LuCI")
|
|
(description
|
|
"rpcd provides ubus objects for web front ends: @code{session}
|
|
(login against @file{/etc/config/rpcd} and the shadow file, ACLs from
|
|
@file{share/rpcd/acl.d}), @code{uci} (staged changes, commit, apply with
|
|
rollback), @code{rc}, plus plugins: @code{file}, @code{rpc-sys}, @code{iwinfo} and
|
|
@code{ucode} (scripts in @file{share/rpcd/ucode}, as LuCI's backend is).")
|
|
(license license:isc))))
|
|
|
|
;; TLS for uloop streams (uhttpd's HTTPS), on OpenSSL.
|
|
(define-public ustream-ssl
|
|
(let ((commit "99f1c0db5a729f615bc5114b3b52fd8ac8083f34")
|
|
(revision "0"))
|
|
(package
|
|
(name "ustream-ssl")
|
|
(version (git-version "2026.03.01" revision commit))
|
|
(source
|
|
(origin
|
|
(method git-fetch)
|
|
(uri (git-reference
|
|
(url "https://git.openwrt.org/project/ustream-ssl.git")
|
|
(commit commit)))
|
|
(file-name (git-file-name name version))
|
|
(sha256
|
|
(base32 "16gy5fd0n2676w7j4ybpjixp6j5wxr3h2186jk3n1327lkzgfx6x"))))
|
|
(build-system cmake-build-system)
|
|
(arguments
|
|
(list #:tests? #f ;no tests
|
|
#:phases (openwrt-phases)))
|
|
(inputs (list libubox openssl))
|
|
(native-inputs (list pkg-config))
|
|
(home-page "https://git.openwrt.org/?p=project/ustream-ssl.git")
|
|
(synopsis "TLS wrapper for libubox streams")
|
|
(description
|
|
"ustream-ssl adds TLS to libubox's @code{ustream} (client and server),
|
|
on OpenSSL here. uhttpd loads it for HTTPS.")
|
|
(license license:isc))))
|
|
|
|
;; Web server for LuCI: static files, ubus over HTTP (JSON-RPC, rpcd
|
|
;; sessions), ucode handlers (LuCI's dispatcher), HTTPS.
|
|
(define-public uhttpd
|
|
(let ((commit "373145f72c884c36a2b16f7f47e74ffae06bd754")
|
|
(revision "0"))
|
|
(package
|
|
(name "uhttpd")
|
|
(version (git-version "2026.08.24" revision commit))
|
|
(source
|
|
(origin
|
|
(method git-fetch)
|
|
(uri (git-reference
|
|
(url "https://git.openwrt.org/project/uhttpd.git")
|
|
(commit commit)))
|
|
(file-name (git-file-name name version))
|
|
(sha256
|
|
(base32 "1n3kbv9pcsccf2j4l8yh71hxyxv29q91ihfrm5c1msri8r9bmdgl"))))
|
|
(build-system cmake-build-system)
|
|
(arguments
|
|
(list
|
|
#:configure-flags #~'("-DLUA_SUPPORT=OFF")
|
|
#:tests? #f ;no tests
|
|
#:phases
|
|
#~(modify-phases #$(openwrt-phases)
|
|
(add-after 'unpack 'fix-paths
|
|
;; Plugins and libustream-ssl are dlopen()ed by bare name;
|
|
;; uhttpd's RUNPATH doesn't cover them.
|
|
(lambda _
|
|
(substitute* "main.c"
|
|
(("\"(uhttpd_(ucode|ubus)\\.so)\"" _ so)
|
|
(string-append "\"" #$output "/lib/" so "\"")))
|
|
;; CGI programs get a fixed PATH: the profile first.
|
|
(substitute* "main.c"
|
|
(("conf\\.cgi_path = \"/sbin:/usr/sbin:/bin:/usr/bin\"")
|
|
"conf.cgi_path = \"/run/current-system/profile/bin:\
|
|
/run/current-system/profile/sbin:/sbin:/usr/sbin:/bin:/usr/bin\""))
|
|
(substitute* "tls.c"
|
|
(("\"libustream-ssl\\.\" LIB_EXT")
|
|
(string-append "\"" #$(this-package-input "ustream-ssl")
|
|
"/lib/libustream-ssl.\" LIB_EXT"))))))))
|
|
(inputs (list libubox ubus ucode json-c libxcrypt ustream-ssl))
|
|
(native-inputs (list pkg-config))
|
|
(home-page "https://git.openwrt.org/?p=project/uhttpd.git")
|
|
(synopsis "OpenWrt's small HTTP server")
|
|
(description
|
|
"uhttpd is the web server OpenWrt's LuCI runs on: static files, CGI,
|
|
ubus over HTTP (JSON-RPC with rpcd sessions), ucode request handlers, and
|
|
HTTPS through ustream-ssl.")
|
|
(license license:isc))))
|
|
|
|
;; Wireless information library and CLI (nl80211 backend), for LuCI's
|
|
;; rpcd plugins.
|
|
(define-public iwinfo
|
|
(let ((commit "66bdd1a071895d91babc9b9228bb84626bbce226")
|
|
(revision "0"))
|
|
(package
|
|
(name "iwinfo")
|
|
(version (git-version "2026.05.26" revision commit))
|
|
(source
|
|
(origin
|
|
(method git-fetch)
|
|
(uri (git-reference
|
|
(url "https://git.openwrt.org/project/iwinfo.git")
|
|
(commit commit)))
|
|
(file-name (git-file-name name version))
|
|
(sha256
|
|
(base32 "1fppvnp74ps15hfwr9zvqc9hjhk1yy7a04f7r26k6257iw9r4pd6"))))
|
|
(build-system gnu-build-system)
|
|
(arguments
|
|
(list
|
|
#:tests? #f ;no tests
|
|
#:parallel-build? #f ;iwinfo may link before libiwinfo.so
|
|
#:make-flags
|
|
#~(list (string-append "CC=" #$(cc-for-target))
|
|
;; _GNU_SOURCE: struct ucred, FNM_CASEFOLD (musl has them
|
|
;; without it).
|
|
(string-append "CFLAGS=-O2 -D_GNU_SOURCE -I"
|
|
#$(this-package-input "libnl-tiny")
|
|
"/include/libnl-tiny")
|
|
(string-append "LDFLAGS=-Wl,-rpath=" #$output "/lib")
|
|
"FPIC=-fPIC" "BACKENDS=nl80211"
|
|
;; OpenWrt's IWINFO_ABI_VERSION.
|
|
"SOVERSION=20230701"
|
|
;; Not `compile': that builds the Lua binding too.
|
|
"libiwinfo.so" "iwinfo")
|
|
#:phases
|
|
#~(modify-phases %standard-phases
|
|
(delete 'configure)
|
|
(add-after 'unpack 'fix-paths
|
|
(lambda _
|
|
(substitute* "include/iwinfo.h"
|
|
(("\"/usr/share/libiwinfo/devices.txt\"")
|
|
(string-append "\"" #$output
|
|
"/share/libiwinfo/devices.txt\"")))))
|
|
(replace 'install
|
|
(lambda _
|
|
(let ((lib (string-append #$output "/lib"))
|
|
(include (string-append #$output "/include")))
|
|
(install-file "iwinfo" (string-append #$output "/bin"))
|
|
(install-file "libiwinfo.so.20230701" lib)
|
|
(symlink "libiwinfo.so.20230701"
|
|
(string-append lib "/libiwinfo.so"))
|
|
(install-file "include/iwinfo.h" include)
|
|
(copy-recursively "include/iwinfo"
|
|
(string-append include "/iwinfo"))
|
|
(install-file "devices.txt"
|
|
(string-append #$output
|
|
"/share/libiwinfo"))))))))
|
|
(inputs (list libnl-tiny libubox ubus uci))
|
|
(home-page "https://git.openwrt.org/?p=project/iwinfo.git")
|
|
(synopsis "OpenWrt wireless information library")
|
|
(description
|
|
"libiwinfo reports wireless interface details (mode, channel,
|
|
signal, associated stations, scan results, hardware) through nl80211;
|
|
@command{iwinfo} is its command-line front end. rpcd and LuCI use it for
|
|
their wireless pages.")
|
|
(license license:gpl2))))
|
|
|
|
;; HTTP utility library (URL decoding, multipart/urlencoded parsers), with
|
|
;; the ucode binding LuCI's request handling uses.
|
|
(define-public lucihttp
|
|
(let ((commit "9b5b683fbb2bb0010aa031d620d0ab8105516757")
|
|
(revision "0"))
|
|
(package
|
|
(name "lucihttp")
|
|
(version (git-version "2023.03.15" revision commit))
|
|
(source
|
|
(origin
|
|
(method git-fetch)
|
|
(uri (git-reference
|
|
(url "https://github.com/jow-/lucihttp")
|
|
(commit commit)))
|
|
(file-name (git-file-name name version))
|
|
(sha256
|
|
(base32 "16z7zww6nc724w0b6fzn9rkrlj8cjzc5mkhm1yawb805dsxdrj38"))))
|
|
(build-system cmake-build-system)
|
|
(arguments
|
|
(list
|
|
#:configure-flags #~'("-DBUILD_LUA=OFF" "-DBUILD_TESTS=OFF")
|
|
#:tests? #f
|
|
#:phases (openwrt-phases)))
|
|
(inputs (list ucode json-c)) ;ucode's headers include json-c's
|
|
(native-inputs (list pkg-config))
|
|
(home-page "https://github.com/jow-/lucihttp")
|
|
(synopsis "HTTP utility library for LuCI")
|
|
(description
|
|
"liblucihttp provides URL encoding and decoding and streaming parsers
|
|
for urlencoded and multipart HTTP bodies, plus the @code{lucihttp} ucode
|
|
module that LuCI's request handling uses.")
|
|
(license license:isc))))
|
|
|
|
;; CGI helper for LuCI: file upload/download and command output streams
|
|
;; (cgi-exec: log and nftables pages), checked against rpcd session ACLs.
|
|
(define-public cgi-io
|
|
(let ((commit "31cb3c89f02d918d7f17bf62a80c852fc38a1ca1")
|
|
(revision "0"))
|
|
(package
|
|
(name "cgi-io")
|
|
(version (git-version "2026.07.21" revision commit))
|
|
(source
|
|
(origin
|
|
(method git-fetch)
|
|
(uri (git-reference
|
|
(url "https://git.openwrt.org/project/cgi-io.git")
|
|
(commit commit)))
|
|
(file-name (git-file-name name version))
|
|
(sha256
|
|
(base32 "0v7ygn2cii0clxlgfa5zyp5w74pn7545h03l8msmrds8lnpg9nma"))))
|
|
(build-system cmake-build-system)
|
|
(arguments
|
|
(list
|
|
#:tests? #f
|
|
#:phases
|
|
#~(modify-phases #$(openwrt-phases)
|
|
(add-after 'unpack 'fix-paths
|
|
(lambda _
|
|
;; Upload checksums: busybox md5sum/sha256sum applets.
|
|
(substitute* "main.c"
|
|
(("\"/bin/busybox\"")
|
|
(string-append "\"" #$(this-package-input "busybox")
|
|
"/bin/busybox\"")))))
|
|
(add-after 'install 'install-cgi
|
|
;; OpenWrt's layout: libexec/cgi-io, run by uhttpd as
|
|
;; www/cgi-bin/cgi-{upload,download,backup,exec} (mode by
|
|
;; name).
|
|
(lambda _
|
|
(let ((cgi-bin (string-append #$output "/www/cgi-bin")))
|
|
(mkdir-p (string-append #$output "/libexec"))
|
|
(rename-file (string-append #$output "/sbin/cgi-io")
|
|
(string-append #$output "/libexec/cgi-io"))
|
|
(rmdir (string-append #$output "/sbin"))
|
|
(mkdir-p cgi-bin)
|
|
(for-each (lambda (name)
|
|
(symlink "../../libexec/cgi-io"
|
|
(string-append cgi-bin "/cgi-" name)))
|
|
'("upload" "download" "backup" "exec"))))))))
|
|
(inputs (list libubox ubus json-c busybox))
|
|
(native-inputs (list pkg-config))
|
|
(home-page "https://git.openwrt.org/?p=project/cgi-io.git")
|
|
(synopsis "CGI file transfer and command helper for LuCI")
|
|
(description
|
|
"cgi-io handles what LuCI can't do over JSON-RPC: file upload and
|
|
download, configuration backups and streaming command output, each checked
|
|
against the caller's rpcd session ACLs.")
|
|
(license license:gpl2+))))
|
|
|
|
;;; LuCI. One source; rpcd-mod-luci (C, CMake) is its own package, the
|
|
;;; rest -- ucode runtime, JavaScript views, theme, the small C modules --
|
|
;;; is `luci', built from a chosen set of LuCI's packages.
|
|
(define %luci-commit "e14ffa434a908ac6f084eae24b5556def663b55a")
|
|
|
|
(define %luci-source
|
|
(origin
|
|
(method git-fetch)
|
|
(uri (git-reference
|
|
(url "https://git.openwrt.org/project/luci.git")
|
|
(commit %luci-commit)))
|
|
(file-name (git-file-name "luci" (string-take %luci-commit 7)))
|
|
(sha256
|
|
(base32 "1lx3cdxgn4v1falakg287p3vhr44ffd4phplj7hmkgrh0sdqa5rv"))
|
|
;; Process list: parse Guix's busybox `top' too (other columns).
|
|
(patches (list (local-file "patches/luci-busybox-top.patch")))))
|
|
|
|
(define %luci-version (git-version "26.288" "0" %luci-commit))
|
|
|
|
;; rpcd's `luci-rpc' object: network devices, DHCP leases, board info for
|
|
;; LuCI's network and status pages.
|
|
(define-public rpcd-mod-luci
|
|
(package
|
|
(name "rpcd-mod-luci")
|
|
(version %luci-version)
|
|
(source %luci-source)
|
|
(build-system cmake-build-system)
|
|
(arguments
|
|
(list
|
|
#:configure-flags
|
|
#~(list "-DLIBNL_LIBS=-lnl-tiny"
|
|
(string-append "-DCMAKE_C_FLAGS=-I"
|
|
#$(this-package-input "libnl-tiny")
|
|
"/include/libnl-tiny"))
|
|
#:tests? #f
|
|
#:phases
|
|
#~(modify-phases #$(openwrt-phases)
|
|
(add-after 'unpack 'chdir
|
|
(lambda _
|
|
(chdir "libs/rpcd-mod-luci/src")
|
|
;; libiwinfo is dlopen()ed when present.
|
|
(substitute* "luci.c"
|
|
(("\"/usr/lib/libiwinfo\\.so\\*\"")
|
|
(string-append "\"" #$(this-package-input "iwinfo")
|
|
"/lib/libiwinfo.so*\"")))))
|
|
(add-after 'install 'move-to-rpcd
|
|
;; rpcd loads plugins from lib/rpcd.
|
|
(lambda _
|
|
(mkdir-p (string-append #$output "/lib/rpcd"))
|
|
(rename-file (string-append #$output "/lib/luci.so")
|
|
(string-append #$output "/lib/rpcd/luci.so")))))))
|
|
(inputs (list libubox ubus uci libnl-tiny iwinfo rpcd json-c))
|
|
(native-inputs (list pkg-config))
|
|
(home-page "https://github.com/openwrt/luci")
|
|
(synopsis "rpcd plugin with LuCI's network and system queries")
|
|
(description
|
|
"This rpcd plugin publishes the @code{luci-rpc} ubus object: network
|
|
devices and their state, DHCP leases, host hints, board information.")
|
|
(license license:asl2.0)))
|
|
|
|
;; LuCI packages in the build, LuCI repository paths.
|
|
(define %luci-components
|
|
'("modules/luci-base"
|
|
"modules/luci-mod-status"
|
|
"modules/luci-mod-system"
|
|
"modules/luci-mod-network"
|
|
"libs/luci-lib-uqr"
|
|
"themes/luci-theme-bootstrap"
|
|
"applications/luci-app-firewall"))
|
|
|
|
(define-public luci
|
|
(package
|
|
(name "luci")
|
|
(version %luci-version)
|
|
(source %luci-source)
|
|
(build-system gnu-build-system)
|
|
(arguments
|
|
(list
|
|
#:tests? #f
|
|
#:modules '((guix build gnu-build-system)
|
|
(guix build utils)
|
|
(ice-9 match))
|
|
#:phases
|
|
#~(modify-phases %standard-phases
|
|
(delete 'configure)
|
|
(replace 'build
|
|
(lambda _
|
|
(let ((cc #$(cc-for-target)))
|
|
;; luci.core (core.so: lmo translations, crypt, sysinfo)
|
|
;; and luci.version. lemon is a build tool: native gcc.
|
|
(with-directory-excursion "modules/luci-base/src"
|
|
(substitute* "Makefile" (("\tcc -std") "\tgcc -std"))
|
|
(invoke "make" (string-append "CC=" cc) "FPIC=-fPIC"
|
|
"CFLAGS=-O2"
|
|
(string-append "LUCI_VERSION=" #$%luci-version)
|
|
"LUCI_GITBRANCH=master"
|
|
"core.so" "version.uc"))
|
|
;; ucode-mod-html (contrib/package): the `html' module.
|
|
(invoke cc "-O2" "-fPIC" "-shared" "-Wall"
|
|
"-o" "html.so"
|
|
"contrib/package/ucode-mod-html/src/html.c")
|
|
;; luci-bwc: realtime graphs' bandwidth/load collector.
|
|
(with-directory-excursion "modules/luci-mod-status/src"
|
|
(invoke "make" (string-append "CC=" cc) "FPIC=-fPIC"
|
|
"CFLAGS=-O2" "luci-bwc")))))
|
|
(replace 'install
|
|
;; luci.mk's install, minus /usr: htdocs -> www, ucode ->
|
|
;; share/ucode/luci, root/usr/X -> X, root/{www,etc} as is.
|
|
;; Not etc/init.d (procd scripts: ucitrack; procd-compat
|
|
;; triggers do its job).
|
|
(lambda _
|
|
(define (copy-tree from to)
|
|
(when (file-exists? from)
|
|
(copy-recursively from to #:keep-mtime? #t)))
|
|
(for-each
|
|
(lambda (component)
|
|
(let ((root (string-append component "/root")))
|
|
(copy-tree (string-append component "/htdocs")
|
|
(string-append #$output "/www"))
|
|
(copy-tree (string-append component "/ucode")
|
|
(string-append #$output "/share/ucode/luci"))
|
|
(when (file-exists? root)
|
|
(for-each
|
|
(match-lambda
|
|
((from . to)
|
|
(copy-tree (string-append root "/" from)
|
|
(string-append #$output "/" to))))
|
|
'(("usr/share" . "share")
|
|
("usr/libexec" . "libexec")
|
|
("usr/bin" . "bin")
|
|
("www" . "www")
|
|
("etc/config" . "etc/config")
|
|
("etc/uci-defaults" . "etc/uci-defaults"))))))
|
|
'#$%luci-components)
|
|
(install-file "modules/luci-base/src/core.so"
|
|
(string-append #$output "/lib/ucode/luci"))
|
|
(install-file "modules/luci-base/src/version.uc"
|
|
(string-append #$output "/share/ucode/luci"))
|
|
(install-file "html.so" (string-append #$output "/lib/ucode"))
|
|
(install-file "modules/luci-mod-status/src/luci-bwc"
|
|
(string-append #$output "/bin"))))
|
|
(add-after 'install 'fix-paths
|
|
;; Server side: the system profile instead of /usr, where the
|
|
;; profile has it. Client-side paths (fs.exec('/sbin/ip') +
|
|
;; ACLs) are left alone.
|
|
(lambda _
|
|
(let ((profile "/run/current-system/profile")
|
|
(busybox #$(this-package-input "busybox")))
|
|
(substitute* (append
|
|
(find-files (string-append #$output
|
|
"/share/ucode")
|
|
"\\.(uc|ut)$")
|
|
(find-files (string-append #$output
|
|
"/share/rpcd/ucode")))
|
|
(("/usr/share/(ucode|luci|rpcd|firewall4)" _ dir)
|
|
(string-append profile "/share/" dir))
|
|
(("/usr/lib/lua/luci/i18n")
|
|
(string-append profile "/share/luci/i18n"))
|
|
(("/usr/sbin/uhttpd") (string-append profile "/bin/uhttpd"))
|
|
;; Feature checks and commands (getFeatures: /sbin/fw4,
|
|
;; /usr/sbin/wpa_supplicant, ...).
|
|
(("(['\"`])/(usr/)?sbin/" _ quote)
|
|
(string-append quote profile "/sbin/"))
|
|
(("(['\"`])/usr/bin/" _ quote)
|
|
(string-append quote profile "/bin/"))
|
|
(("/bin/busybox") (string-append busybox "/bin/busybox"))
|
|
(("(['\"`])/www/" _ quote)
|
|
(string-append quote profile "/www/")))
|
|
;; Menu entries depending on files ("fs"): check the
|
|
;; profile. (/usr/sbin/uhttpd stays: its page edits a UCI
|
|
;; config uhttpd-service-type doesn't read.)
|
|
(substitute* (find-files (string-append #$output
|
|
"/share/luci/menu.d"))
|
|
(("\"/(usr/)?sbin/(fw3|nft|dnsmasq|odhcpd)\"" _ _ cmd)
|
|
(string-append "\"" profile "/sbin/" cmd "\"")))
|
|
;; Helper scripts rpcd/LuCI run.
|
|
(for-each (lambda (script)
|
|
(substitute* script
|
|
(("^#!.*/bin/sh")
|
|
(string-append "#!" busybox "/bin/sh"))
|
|
;; syslog-wrapper: no logread (ubox); Guix's
|
|
;; syslogd writes /var/log/messages.
|
|
(("/usr/sbin/logread -e \\^")
|
|
"cat /var/log/messages")
|
|
(("^\\. /lib/functions\\.sh")
|
|
(string-append
|
|
". " #$(this-package-input "openwrt-base-files")
|
|
"/lib/functions.sh"))))
|
|
(find-files (string-append #$output "/libexec")))
|
|
(substitute* (string-append #$output "/www/cgi-bin/luci")
|
|
(("^#!.*")
|
|
(string-append "#!" #$(this-package-input "ucode")
|
|
"/bin/ucode\n")))))))))
|
|
(inputs (list ucode json-c libxcrypt busybox openwrt-base-files
|
|
uci libubox ubus)) ;iwinfo.h includes theirs
|
|
(propagated-inputs
|
|
;; What luci-base and the modules depend on (LUCI_DEPENDS), so the
|
|
;; system profile has their files: ucode modules, rpcd plugins, ACLs.
|
|
(list rpcd rpcd-mod-luci lucihttp iwinfo cgi-io))
|
|
(home-page "https://github.com/openwrt/luci")
|
|
(synopsis "OpenWrt's web interface")
|
|
(description
|
|
"LuCI is OpenWrt's web interface: a ucode request dispatcher run by
|
|
uhttpd, JavaScript views talking to rpcd over ubus, and the Bootstrap theme.
|
|
This package has luci-base, the status, system and network modules, and the
|
|
firewall application.")
|
|
(license license:asl2.0)))
|
|
|
|
;;; Not an OpenWrt project: the parts of procd's ubus API that OpenWrt tools
|
|
;;; call, for a system where Shepherd is init. Lives in procd-compat/ next
|
|
;;; to this file. openwrt-services.scm runs it.
|
|
(define-public procd-compat
|
|
(package
|
|
(name "procd-compat")
|
|
(version "0.1")
|
|
(source (local-file "procd-compat" #:recursive? #t))
|
|
(build-system gnu-build-system) ;not copy: cross refs (PITFALLS #39)
|
|
(arguments
|
|
(list
|
|
#:modules %cross-copy-modules
|
|
#:imported-modules %copy-build-system-modules
|
|
#:tests? #f
|
|
#:phases
|
|
#~(modify-phases
|
|
#$(cross-copy-phases
|
|
#~'(("procd-compat.uc" "share/procd-compat/")
|
|
("reload_config" "sbin/")
|
|
("openwrt-rc" "sbin/")
|
|
("logread" "sbin/")))
|
|
(add-after 'install 'store-paths
|
|
(lambda _
|
|
(let ((busybox #$(this-package-input "busybox")))
|
|
(substitute* (string-append #$output "/sbin/reload_config")
|
|
;; (patch-source-shebangs has already run.)
|
|
(("^#!.*/bin/sh")
|
|
(string-append "#!" busybox "/bin/sh\n"
|
|
"PATH=" #$(this-package-input "uci") "/bin:"
|
|
#$(this-package-input "ubus") "/bin:"
|
|
busybox "/bin:$PATH")))
|
|
(substitute* (string-append #$output "/sbin/openwrt-rc")
|
|
(("^#!.*/bin/sh")
|
|
(string-append
|
|
"#!" busybox "/bin/sh\n"
|
|
;; What init scripts run by name: base-files' ipcalc.sh,
|
|
;; uci, ubus, jsonfilter, busybox; then the profile.
|
|
"PATH=" #$(this-package-input "openwrt-base-files") "/bin:"
|
|
#$(this-package-input "uci") "/bin:"
|
|
#$(this-package-input "ubus") "/bin:"
|
|
#$(this-package-input "jsonfilter") "/bin:"
|
|
busybox "/bin:" busybox "/sbin:"
|
|
"/run/current-system/profile/bin:"
|
|
"/run/current-system/profile/sbin:$PATH"))
|
|
(("@base@") #$(this-package-input "openwrt-base-files")))
|
|
(substitute* (string-append #$output "/sbin/logread")
|
|
(("^#!.*/bin/sh")
|
|
(string-append "#!" busybox "/bin/sh\n"
|
|
"PATH=" busybox "/bin:$PATH")))))))))
|
|
(inputs (list busybox ubus uci jsonfilter openwrt-base-files))
|
|
(home-page "https://source.archipelago-foundation.org/ssmithx/guix-router")
|
|
(synopsis "procd's ubus service and system objects, for Shepherd")
|
|
(description
|
|
"A ucode daemon that publishes the ubus @code{service} object (method
|
|
@code{event}: on @code{config.change} it reloads the Shepherd services
|
|
registered for that UCI config, as procd's reload triggers do; method
|
|
@code{get_data}) and the @code{system} object (@code{board}, @code{info},
|
|
@code{reboot}), plus @command{reload_config}, which reports the UCI configs
|
|
changed since its last run, @command{openwrt-rc}, which runs an OpenWrt
|
|
procd init script's service without procd, and @command{logread} over the
|
|
syslog file.")
|
|
(license license:isc)))
|