A two-layer network and system-configuration stack for FreeBSD. The lower layer is the in-tree IPConfiguration daemon (DHCPv4/v6 + RA, RFC 5227 ARP, lease publish via Mach RPC). The upper layer is a port of Apple's configd — daemon name retained verbatim as configd, Mach-served as com.apple.SystemConfiguration, providing the SystemConfiguration dynamic store via MIG (configd.defs) for scutil, IPConfiguration, and GUI tooling. Companion to the freebsd-launchd-mach port.
freebsd-launchd (AF_UNIX / GNUstep Distributed Objects) repo, where the daemon was renamed netconfigd. Refactored 2026-05-23 to target freebsd-launchd-mach (v2): retains Apple's daemon name configd, Mach IPC, and the original configd.defs MIG IDL. Mach service: com.apple.SystemConfiguration (acquired via bootstrap_check_in). PARTIALLY SHIPPED — the core SCDynamicStore surface is live in src/configd/, the client framework lives at src/libSystemConfiguration/ with mig-generated client stubs, and the daemon is being consumed today by IPConfiguration (sc_publish_ipv4 + sc_publish_ipv6 in src/IPConfiguration/sc_publish.c). The plugin loader and SCPreferences surface are deferred; IPConfiguration is a standalone daemon (not loaded as a configd plugin like Apple does it) and talks to configd over Mach RPC for State:/Network/Service/<UUID>/IPv4 and /IPv6 publishes. The remaining sections describe the full porting plan; everything below should be read with the understanding that the shape is now Mach-MIG, not Distributed Objects.
src/configd/; the client framework lives under src/libSystemConfiguration/.IPConfiguration (DHCPv4/v6 + RA in one daemon, with RFC 5227 ARP probe/announce, lagg/vlan/bridge layering recognition, and userspace RDNSS/DNSSL parsing the kernel can't do). Letting IPConfiguration own the protocol layer keeps configd's responsibility tight: be the dynamic store.src/configd/ — the daemon, MIG-served on Mach service com.apple.SystemConfiguration via bootstrap_check_in. Retains Apple's configd.defs IDL. Backs an in-memory key/value store (State: and Setup: domains), notification keys, pattern subscriptions, and the SCDynamicStoreCreate / SetValue / SetNotificationKeys / CopyValue RPC surface.src/libSystemConfiguration/ — the libSystemConfiguration.so client framework. mig-generated client stubs for configd.defs; wraps them in the canonical SCDynamicStore* CF API.src/IPConfiguration/sc_publish.c — downstream consumer. sc_publish_ipv4() and sc_publish_ipv6() publish bound-lease state to State:/Network/Service/<UUID>/IPv{4,6} via the libSystemConfiguration client.preferences.plist persistence + commit/apply surface). Headers present in src/libSystemConfiguration/; backing store and configd-side RPCs not wired.State: / Setup: as needed.configd.defs retained as the MIG IDL. mig-generated server stubs link into the daemon; mig-generated client stubs link into libSystemConfiguration.so. Service is published as com.apple.SystemConfiguration via bootstrap_check_in. Notifications fan out as mach_msg sends back to subscribed clients on key updates — not as DO callbacks, and not over AF_UNIX.dispatch_source(MACH_RECV) on its service port; routines dispatched by mig demux into store mutation + notification fan-out. DISPATCH_SOURCE_TYPE_VNODE on declarative-config plists (when SCPreferences arrives); DISPATCH_SOURCE_TYPE_READ on PF_ROUTE for kernel-event observation (planned).preferences.plist required for the auto path.configd source files retain their Apache 2.0 headers per-file. NOTICE enumerates Apple, libdispatch, libCoreFoundation, and us.A FreeBSD live ISO that boots with launchd as PID 1, gets a working network in seconds without user intervention, and runs a SystemConfiguration-equivalent layer on top — the Apple-shape SCDynamicStore over Mach RPC for scutil, libIOKit consumers, and GUI tooling — while delegating the protocol-level work (DHCP, RA, ARP collision) to IPConfiguration, the standalone in-tree daemon that already does it. configd is the store; IPConfiguration is the protocol layer; they meet over Mach RPC.
wland's job, not configd's — wland drives stock wpa_supplicant and publishes State:/Network/Interface/<iface>/AirPort into the store itself, over the ordinary SCDynamicStoreSetValue path. configd is the store, not the author. No configd change is required for WLAN. Apple's eapolclient is not ported. See the WLAN plan.InterfaceNamer plugin. Apple's InterfaceNamer uses IOKit to assign persistent names; FreeBSD names interfaces in-kernel. Interface metadata (USB/PCI introspection) is available via libIOKit over hwregd for downstream consumers.mach_msg is the IPC./etc/rc.conf compatibility layer. When SCPreferences arrives, preferences.plist will be the declarative config configd reads — matching Apple's surface.Two layers, separable in time and ownership:
Apple's configd has both layers fused — the IPConfiguration agent (DHCP/RA) is loaded as a plugin inside the configd process. We split it: configd is its own process, IPConfiguration is its own process. The interface between them is the same one Apple's IPConfiguration plugin would use internally — SCDynamicStoreSetValue on State:/Network/Service/<UUID>/IPv{4,6} — just now reached over Mach RPC rather than in-process. From the consumer's point of view (a GUI tool reading the dynamic store) the surface is identical.
The boundary between layers is clean: IPConfiguration owns protocol actions (acquire lease, run RFC 5227 ARP, configure address); configd owns store + IPC (key/value space, subscription, notification fan-out). They communicate via the canonical SCDynamicStore RPC surface; no custom protocol.
Apple ships IPConfiguration as a configd plugin loaded into the configd address space. In freebsd-launchd-mach it runs as its own daemon (src/IPConfiguration/) supervised by launchd. The split is a deliberate choice — the plugin loader is deferred, and the standalone shape made it easier to iterate on the DHCP state machine and RFC 5227 ARP without dragging the rest of configd along.
sc_publish_ipv4() / sc_publish_ipv6() (in src/IPConfiguration/sc_publish.c) which talks to configd over Mach RPC via libSystemConfiguration. configd writes the published dictionary to State:/Network/Service/<UUID>/IPv4 (and v6) and fans the change out to any subscribed client ports.Corrected. An earlier draft of this section had the security/wpa_supplicant port superseding base, arguing faster WPA3-SAE/OWE uptake and more aggressive CVE backports. The WLAN plan §3.3 rules that out: the port is the same 2.11 as base, but installs to /usr/local/sbin and shadows base for no benefit. We keep stock wpa_supplicant from FreeBSD base, untouched — not vendored into nextbsd-userland/src, not taught Mach, not added as a port. It speaks net80211 ioctls downward and a UNIX control socket upward; it never needs to know configd exists. All Mach knowledge lives in wland, which gets it for free by linking libSystemConfiguration. eapolclient (Apple's 802.1X supplicant) is not ported; WPA-Enterprise comes from wpa_supplicant's own EAP stack or not at all.
configd is up and serving. Daemon binary at /usr/libexec/configd (TBD path; matches Apple), launchd plist publishes the com.apple.SystemConfiguration Mach service via MachServices; configd grabs the receive right via bootstrap_check_in, runs a MIG dispatch loop, and answers SCDynamicStoreCreate / SetValue / CopyValue / SetNotificationKeys / CopyKeyList over configd.defs. Notification keys cause the daemon to remember the client's notify port and send a wakeup mach_msg on key change; the client's SCDynamicStore rlsource fires.
The IPConfiguration → configd path is end-to-end: bind a lease, watch State:/Network/Service/<UUID>/IPv4 change in scutil-equivalent test tools. That's the level of "live" we're at.
End state: a launchd-supervised long-running daemon that publishes com.apple.SystemConfiguration, owns the SCDynamicStore, exposes the canonical configd.defs MIG surface, and (when SCPreferences arrives) reads declarative network preferences. Distinct from Apple's shape in that it does not host plugins in-process — the plugin loader is deferred. Things Apple shipped as plugins are either rolled in (IPMonitor's resolv.conf merge, future), run standalone (IPConfiguration), or unbuilt.
configd publishes state to the SystemConfiguration "dynamic store" — a key-value space (keys like State:/Network/Interface/en0/IPv4) that processes subscribe to. Apple's key shape is retained verbatim. The backing store is an in-memory CF dictionary protected by a serial dispatch queue; subscribers register interest via SCDynamicStoreSetNotificationKeys (exact keys or regex patterns); the daemon sends mach_msg wake-ups to the subscriber's notify port when matching keys change.
Sources of state:
sc_publish_ipv4() / sc_publish_ipv6(); that path lands as State:/Network/Service/<UUID>/IPv{4,6} writes via Mach RPC. Shipped.PF_ROUTE socket (planned): address adds/removes, link-state, route changes → populate State:/Network/Interface/<iface>/IPv{4,6}. Apple does this in the KernelEventMonitor plugin.wland (planned): publishes State:/Network/Interface/<iface>/AirPort — {Authenticated, SSID, BSSID, RSSI, Channel, Security}. configd does not read the wpa_supplicant control socket; wland owns it and writes the key like any other SCDynamicStore client. (An earlier draft of this plan had configd populating a …/WiFi key directly — that key name and that ownership are both wrong; see the WLAN plan.) Scan results deliberately do not go in the store: CONFIG_DATA_MAX rejects any value over 8 KiB.Setup:-prefixed keys from preferences.plist — the user's declared service set / interface config.Apple's configd.defs is the IDL, retained. mig-generated server stubs link into configd; mig-generated client stubs link into libSystemConfiguration.so. Representative routines presently wired:
configopen — allocate a session (a CFDictionary store handle); returns a server port the client uses as a session handle.configadd / configset — set value at key (SCDynamicStoreSetValue / SetMultiple).configget — copy value at key (SCDynamicStoreCopyValue).configlist — copy key list, optionally pattern-filtered (SCDynamicStoreCopyKeyList).configadd_notification / configremove_notification — subscribe / unsubscribe to keys or patterns.notifyset — deliver-port handoff: the client passes a Mach port the daemon should mach_msg on change.configclose — tear down session, drop subscriptions.Apple's SCPreferences is the persistence + commit/apply surface over preferences.plist. Header surface present in src/libSystemConfiguration/SCPreferences.c; backing store and configd-side RPCs are not yet wired. When this lands, configd will:
preferences.plist (Apple-canonical path) via CFPropertyList.Setup: keys in the dynamic store from the parsed prefs.SCPreferencesCommit-shaped RPCs from clients; rewrite the plist atomically; reload Setup:; notify subscribers.The shape is Apple-canonical — no FreeBSD-only Network.plist alternative; preferences.plist is the file.
| Source type | Watches | Reaction |
|---|---|---|
dispatch_source(MACH_RECV) | configd's service port (from bootstrap_check_in) | mig demux: dispatch routine; mutate store; fan out notifications |
DISPATCH_SOURCE_TYPE_READ (planned) | PF_ROUTE socket | parse routing message; update dynamic store State:/Network/Interface/<iface>/...; fan out to subscribers |
DISPATCH_SOURCE_TYPE_VNODE (deferred) | preferences.plist | reload via CFPropertyList; diff against last snapshot; rewrite Setup: keys; notify |
DISPATCH_SOURCE_TYPE_SIGNAL | SIGTERM / SIGHUP | SIGTERM: clean shutdown. SIGHUP: force config reload. |
freebsd-launchd-mach/src/freebsd-launchd-mach/src/
├── configd/ The daemon. PARTIALLY SHIPPED.
│ ├── configd.c Service publish + MIG demux + dispatch_main
│ ├── config.defs Apple configd.defs IDL (retained verbatim)
│ ├── config_session.{c,h} Per-client session state, port tracking
│ ├── config_store.{c,h} In-memory key/value store + pattern subs
│ ├── config_wire.{c,h} MIG server stub helpers (CFData marshalling)
│ ├── config_types.h Shared types between defs and impl
│ └── *test.c in-tree integration tests against the live
│ Mach service (configtest, listtest, patterntest,
│ notifytest, multitest)
│
├── libSystemConfiguration/ The client framework. PARTIALLY SHIPPED.
│ ├── SCDynamicStore.c Public SCDynamicStoreCreate / SetValue /
│ │ CopyValue / SetNotificationKeys; wraps mig
│ │ client stubs into the CF API
│ ├── SCD.c, SCDMultiple.c Bulk SCDynamicStore variants
│ ├── SCNotify.c Notify rlsource + callback dispatch
│ ├── SCNetworkInterface.c Iface enumeration (planned full surface)
│ ├── SCNetworkService.c, Set.c Network-service / set enumeration (planned)
│ ├── SCNetworkProtocol.c
│ ├── SCNetworkConfigurationInternal.{c,h}
│ ├── SCBridgeInterface.c, SCBondInterface.c, SCVLANInterface.c
│ ├── SCPreferences.c (deferred — backing store + RPCs not wired)
│ ├── SCInternal.h
│ ├── SystemConfiguration/ public header umbrella
│ └── *test.c sctest, scnotifytest, scrltest, etc.
│
└── IPConfiguration/ Standalone DHCP/RA daemon. SHIPPED through iter 6.
├── ipconfigd.c, ipconfig.c daemon + CLI
├── ipconfig.defs IPConfiguration's own MIG IDL (separate from
│ configd's)
├── dhcp_discover.c, ra_listen.c, lease_loop.c
├── arp_probe.c RFC 5227 probe + announce (iter 6)
├── apply_lease.c, apply_lease_v6.c
├── bound_state.c fires sc_publish on BOUND
├── sc_publish.{c,h} sc_publish_ipv4 / sc_publish_ipv6
│ -> libSystemConfiguration -> configd via Mach
├── mach_service.c
└── ...
Top-level (freebsd-launchd-mach/) hosts the launchd plist for configd (com.apple.SystemConfiguration registered via MachServices in the plist; configd calls bootstrap_check_in on the published name to obtain the receive right).
The configd source is derived from Apple's configd (latest open tag configd-963.270.3). What's retained is the surface that's directly relevant to SCDynamicStore + the configd.defs IDL; the bulky plugin tree (IPMonitor, KernelEventMonitor, LinkConfiguration, PreferencesMonitor, SCNetworkReachability, InterfaceNamer, SimulatorSupport, QoSMarking) is not present. Files that are in-tree retain their Apache 2.0 headers per-file.
| Decision | Choice |
|---|---|
| Target kernel | FreeBSD 14.x and 15.x. No Linux, no NetBSD. |
| Daemon name | configd — Apple-canonical, retained verbatim. NOT renamed to netconfigd (that's the sibling repo's choice). |
| DHCPv4 / DHCPv6 / RA / SLAAC / ARP | In-tree IPConfiguration (Apple's port). Standalone daemon, not loaded as a configd plugin. RFC 5227 ARP probe / announce shipped in iter 6. |
| WLAN authentication | Stock wpa_supplicant from base, driven by wland. Not the port. Apple's eapolclient is not ported. |
| IPC | Mach IPC. Apple's configd.defs MIG IDL is retained verbatim. mig-generated server stubs in configd, client stubs in libSystemConfiguration. NOT Distributed Objects, NOT AF_UNIX (that's the sibling repo). |
| Service publish | Mach service com.apple.SystemConfiguration, registered in the launchd plist MachServices dict; bootstrap_check_in hands the receive right to configd at startup. |
| Notification fan-out | The daemon sends a wake-up mach_msg back to subscribed clients' notify ports on key change. The client's SCDynamicStore rlsource demuxes and fires the user callback. |
| Event loop | libdispatch dispatch sources. dispatch_source(MACH_RECV) on the service port for inbound RPC; plus PF_ROUTE / vnode sources as features land. |
| Plist parsing | libCoreFoundation CFPropertyListCreateWithData (XML + binary). |
| Source of truth for declarative config | preferences.plist (Apple-canonical path), when SCPreferences lands. No rc.conf parser. No FreeBSD-only Network.plist file. |
| Plugin loader | Deferred. IPConfiguration runs standalone; other Apple plugins are not built. |
| License (top-level) | BSD-2-Clause. Apple configd files retain Apache 2.0 per-file. |
| Build platform | FreeBSD only, inside the same VM-action chroot the launchd build uses. |
src/configd/ + src/libSystemConfiguration/)Apple source baseline: configd-963.270.3 (~289 files, ~5.5 MB pre-pruning). What's not in-tree: the plugin tree (IPMonitor, KernelEventMonitor, LinkConfiguration, PreferencesMonitor, SCNetworkReachability), InterfaceNamer, SimulatorSupport, QoSMarking, AirPort, Apple-Wireless-Diagnostics, Swift test harnesses, Xcode build infra.
configd.xcodeproj/, xcconfigs/, xcscripts/ — Xcode build infra (replaced by gmake Makefiles)Plugins/QoSMarking/, Plugins/SimulatorSupport/, Plugins/InterfaceNamer/ — non-goals on FreeBSDPlugins/IPMonitor/IPMonitorAWDReport.{c,h} — Apple-Wireless-DiagnosticsSCTest-Swift/ — Swift test harnesslibSystemConfiguration/SCDPlugin*.{c,h} — plugin loader (deferred)| Component | In-tree at | Status | Notes |
|---|---|---|---|
| configd daemon core | src/configd/configd.c + config_session.c + config_store.c + config_wire.c | SHIPPED | dispatch_main + MIG demux on the com.apple.SystemConfiguration service port. Session-per-client state. Store backs State: + Setup:; pattern subs via regex. |
| configd.defs IDL | src/configd/config.defs | SHIPPED | Apple IDL retained. Drives both server stubs (in configd) and client stubs (in libSystemConfiguration). |
| SCDynamicStore (client) | src/libSystemConfiguration/SCDynamicStore.c + SCD.c + SCDMultiple.c + SCNotify.c | SHIPPED | Wraps mig client stubs into CF API. SCDynamicStoreCreate / SetValue / CopyValue / SetNotificationKeys / CreateRunLoopSource all functional. |
| libSystemConfiguration enumeration surface (SCNetworkInterface, Service, Set, Protocol) | src/libSystemConfiguration/SCNetwork*.c | PARTIAL | Header surface present; runtime gets fuller as configd's Setup: side comes online. |
| SCBridgeInterface, SCBondInterface, SCVLANInterface | src/libSystemConfiguration/SCBridge/Bond/VLAN*.c | PARTIAL | Compose against FreeBSD's ifconfig surface where possible. |
| SCPreferences | src/libSystemConfiguration/SCPreferences.c | DEFERRED | Header present, backing store + configd-side RPCs not wired. |
| IPConfiguration (lease publish) | src/IPConfiguration/sc_publish.c, sc_publish.h | SHIPPED | Calls SCDynamicStoreSetValue on State:/Network/Service/<UUID>/IPv{4,6} via libSystemConfiguration. This is the working proof that the daemon serves real consumers. |
| IPMonitor (resolv.conf merge) | not imported | FUTURE | Once multiple services need to compose into one resolv.conf, port the Apple plugin's merge logic into configd directly (no plugin loader). |
| KernelEventMonitor (PF_ROUTE) | not imported | FUTURE | Rewrite as a configd-internal source: DISPATCH_SOURCE_TYPE_READ on PF_ROUTE; populate State:/Network/Interface/<iface>/.... |
| SCNetworkReachability | not imported | FUTURE | Port the public API; PF_ROUTE for change events; serve over MIG. |
| scutil CLI | not imported | FUTURE | Port as a libSystemConfiguration client. --show / --get / --set / --watch. |
| nwi (network-information) | not yet imported | FUTURE | Mostly pure data structures; port when a consumer needs it. |
| Feature | Apple's configd does | This port (FreeBSD) |
|---|---|---|
| DHCP / RA / ARP | Loaded as the IPConfiguration plugin inside the configd process. | Runs as its own daemon (src/IPConfiguration/). Same Apple code lineage, same SCDynamicStore publish surface; just out-of-process. Talks to configd over Mach RPC instead of in-process function calls. |
| Kernel iface events | PF_SYSTEM + KEV_NETWORK_CLASS + kern_event | PF_ROUTE socket. Planned configd-internal source; observation-only (IPConfiguration owns its own PF_ROUTE feed for action). |
| Service IPC | Mach ports + XPC + bootstrap server | Same shape. Mach IPC retained; configd.defs retained as the MIG IDL; service published as com.apple.SystemConfiguration via bootstrap_check_in. (XPC is also available in this repo; configd just doesn't use it — it's a raw MIG server.) |
| WLAN auth | AirPort framework + eapolclient | Stock wpa_supplicant from base, driven by wland. No eapolclient. |
| Iface naming | InterfaceNamer plugin: IOKit USB/PCI introspection | FreeBSD kernel handles iface naming. Drop the plugin. Iface metadata (USB/PCI introspection) is separately available via libIOKit over hwregd. |
| Plugin loading | Mach host port + bundle dlopen at startup | Deferred. IPConfiguration is its own daemon; other Apple plugins are unbuilt or rolled in directly. |
| Build-system gates | iOS / macOS / sim / catalyst #if TARGET_OS_* | One target (FreeBSD). Apple gates dropped. |
Build-time: clang, lld (FreeBSD base); mig (in-tree, builds the server + client stubs from config.defs); pkgconf; system-domain headers/libraries at /System/Library/.
Runtime (on the ISO):
libdispatch.so — mainloop + MIG receive source.libCoreFoundation.so — CF types (CFString, CFDictionary, CFData) used by SCDynamicStore values.libxpc.so — bootstrap APIs (bootstrap_check_in); not used for XPC framing in configd itself, but present in the libxpc-bootstrap path.libSystemConfiguration.so — this repo's client framework; consumed by IPConfiguration and any other SCDynamicStore client.wpa_supplicant from FreeBSD base — already present, untouched. Not security/wpa_supplicant from ports.<?xml version="1.0" encoding="UTF-8"?>
<plist version="1.0">
<dict>
<key>Label</key> <string>com.apple.IPConfiguration</string>
<key>ProgramArguments</key> <array>
<string>/usr/libexec/IPConfiguration</string>
</array>
<key>RunAtLoad</key> <true/>
<key>KeepAlive</key> <true/>
</dict>
</plist>
IPConfiguration runs in foreground supervised by launchd; KeepAlive=true respawns it if it dies. Apple-canonical Label.
<plist version="1.0">
<dict>
<key>Label</key> <string>com.apple.configd</string>
<key>ProgramArguments</key> <array><string>/usr/libexec/configd</string></array>
<key>RunAtLoad</key> <true/>
<key>KeepAlive</key> <true/>
<key>MachServices</key> <dict>
<key>com.apple.SystemConfiguration</key>
<true/>
</dict>
</dict>
</plist>
launchd registers the com.apple.SystemConfiguration Mach service at boot. configd calls bootstrap_check_in("com.apple.SystemConfiguration", &recv_port) at startup to obtain the receive right. Until configd is up, RPCs from libSystemConfiguration clients block at bootstrap_look_up (or get a queued send right depending on launchd's OnDemand semantics — tracking this in iter wash). After check-in, configd runs dispatch_source(MACH_RECV) on the port and dispatches incoming MIG messages.
preferences.plist schema (DEFERRED — SCPreferences)One canonical declarative configuration file at Apple's path. The GUI tooling reads/writes it via SCPreferences*; configd loads it into Setup: keys and re-evaluates on commit. The shape below is illustrative — final shape will follow Apple's preferences.plist schema (network-service-keyed, with NetworkServices, Sets, System dicts). Until SCPreferences lands, no plist is consulted; the auto-DHCP path through IPConfiguration runs unaided.
The example below is the original FreeBSD-only sketch from the sibling repo's plan, preserved for the data-model intent only:
<?xml version="1.0" encoding="UTF-8"?>
<plist version="1.0">
<dict>
<key>Hostname</key>
<string>my-host</string>
<key>Interfaces</key>
<dict>
<key>em0</key>
<dict>
<key>Method</key> <string>DHCP</string>
</dict>
<key>em1</key>
<dict>
<key>Method</key> <string>Static</string>
<key>IPv4</key>
<dict>
<key>Address</key> <string>192.168.1.10/24</string>
<key>Router</key> <string>192.168.1.1</string>
</dict>
</dict>
<key>wlan0</key>
<dict>
<key>Method</key> <string>WPA</string>
<key>WPA</key>
<dict>
<key>ConfigFile</key> <string>/etc/wpa_supplicant.conf</string>
</dict>
<key>IPv4</key>
<dict>
<key>Method</key> <string>DHCP</string>
</dict>
</dict>
</dict>
<key>DNS</key>
<dict>
<!-- Optional. If absent, DNS is taken from DHCP. -->
<key>Servers</key>
<array>
<string>1.1.1.1</string>
<string>1.0.0.1</string>
</array>
<key>Search</key>
<array><string>example.com</string></array>
</dict>
</dict>
</plist>
Empty / absent preferences.plist → IPConfiguration's defaults apply (auto-DHCP everything, RA on every iface). The no-config-needed default; today's live behavior.
Per-iface dict missing → IPConfiguration's defaults apply for that iface. A user who wants em0 to NOT auto-DHCP would express that through the SCPreferences API once it lands.
The Apple preferences.plist ships an explicit version key in its top-level dict. The port follows.
scutil CLI tool (FUTURE)Apple's scutil is the system-configuration shell. Ported as a libSystemConfiguration client (which means it talks to configd over the same Mach RPC surface as every other client). Initial command set when it lands:
scutil --show — dump the entire dynamic storescutil --get Hostname / --set Hostname my-host — single-key editsscutil --interfaces — list managed interfaces with current statescutil --reload — force configd to re-read SCPreferences (once SCPreferences lands)scutil --watch <key> — long-running, prints on store changes (via the Mach notify-port path)The Apple interactive store-shell mode is in scope — it builds on the same MIG surface configd already speaks, so it should be straightforward.
In the meantime, the in-tree test programs (configtest, listtest, patterntest, notifytest, multitest, sctest, scnotifytest) cover most of what an early scutil would expose.
Top-level BSD-2-Clause; Apple configd source files retain their Apache 2.0 headers per-file (inbound=outbound). New code is BSD-2-Clause with SPDX headers.
| Source | License | How we handle it |
|---|---|---|
Apple configd-963.270.3 | Apache 2.0 (Apple OSRef) | Keep Apple header verbatim. Files stay Apache regardless of top-level. |
Apple IPConfiguration (Apple OSRef) | Apache 2.0 | Keep Apple header verbatim; same handling. |
| libdispatch, libCoreFoundation, libxpc (Apple OSRef, in this repo's tree) | Apache 2.0 with Runtime Library Exception | Per-file Apache; listed in NOTICE. |
| wpa_supplicant (base, separate process) | BSD-3-Clause | Already in base; not linked into configd. Listed in NOTICE when WLAN ships. |
| This repo's new code | BSD-2-Clause | Each new file gets a BSD-2-Clause SPDX header. |
src/configd/ + src/libSystemConfiguration/ hosted under freebsd-launchd-mach. Apple source baseline configd-963.270.3.src/configd/configd.c: bootstrap_check_in("com.apple.SystemConfiguration", &recv_port); dispatch_source(MACH_RECV); MIG demux for config.defs routines.config_store.c: in-memory store (CF dictionary), pattern subscription via regex.config_session.c: per-client session state, notify-port tracking, subscription bookkeeping.mach_msg to each subscribed client's notify port on matching key change.configtest, listtest, patterntest, notifytest, multitest — all exercise the live Mach service.SCDynamicStore.c: SCDynamicStoreCreate / SetValue / CopyValue / SetNotificationKeys / CopyKeyList / CreateRunLoopSource.config.defs linked in.mach_msg, demuxes keys, fires the user's callback on the runloop.SCDMultiple.c).SCNetworkInterface.c, SCNetworkService.c, etc.) — header-complete, runtime grows with SCPreferences.src/IPConfiguration/sc_publish.c — sc_publish_ipv4() / sc_publish_ipv6().SCDynamicStoreSetValue(store, "State:/Network/Service/<UUID>/IPv4", value).scnotifytest subscribed to State:/Network/Service/.* wakes on IPConfiguration's publish.SCPreferencesCreate / Lock / Commit / Apply on the libSystemConfiguration side.preferences.plist on startup, populate Setup: keys; persist on commit; reload on SIGHUP.SCNetworkServiceCopyAll returns real data).DISPATCH_SOURCE_TYPE_READ on PF_ROUTE.State:/Network/Interface/<iface>/IPv{4,6} + /Link.scutil as a libSystemConfiguration client.--show / --get / --set / --interfaces / --reload / --watch <key>; interactive store-shell mode.libSystemConfiguration.so; reachability queries reach configd via MIG.preferences.plist credentials + per-iface wpa_supplicant management).wland — known networks live in SCPreferences and wland is the sole author of wpa_supplicant's network blocks. Not configd's. See the WLAN plan, Phase 3.configd — Apple-canonical, retained. The sibling freebsd-launchd (AF_UNIX/DO) repo renames to netconfigd; this Mach-IPC repo does not.
configd.defs retained as the MIG IDL verbatim. mig-generated server stubs in configd; mig-generated client stubs in libSystemConfiguration.so. Service published as com.apple.SystemConfiguration via bootstrap_check_in.
SCDynamicStoreSetValue on State:/Network/Service/<UUID>/IPv{4,6} via libSystemConfiguration — the Apple-canonical key shape, the Apple-canonical API. Shipped at src/IPConfiguration/sc_publish.c.
IPConfiguration (Apple source lineage), running as a standalone daemon — not loaded as a configd plugin. RFC 5227 ARP probe/announce shipped in iter 6.
src/configd/ and src/libSystemConfiguration/ under freebsd-launchd-mach.
/usr/libexec/configd for the daemon (matches Apple); /usr/sbin/scutil for the CLI client (when ported).
/etc/resolv.conf ownership. Apple's IPMonitor plugin watches DNS-related State: keys and writes resolv.conf via merging policy. Port that logic into configd directly when multi-service DNS composition matters (today, single-service IPConfiguration writes resolv.conf via its own path).
preferences.plist ships a specific shape (NetworkServices / Sets / System dicts, version key). Port the schema as-is or simplify for the FreeBSD-only world? Lean Apple-as-is for ABI affinity with macOS scutil dumps.
wland's question, not configd's. Short version: plaintext either way, because there is no keychain and none is started. The only choice is which plaintext file — /etc/wpa_supplicant.conf (0600, root) or a root-owned preferences.plist under /Local/Library/Preferences/SystemConfiguration. Not a security difference, only an architectural one. A real keychain is greenfield and its own multi-month project (Keychain plan).
libsystem_network's nwi as a small read-only mmaped state file that configd writes. Useful for fast in-process reachability heuristics without IPC. Port when an in-process consumer cares.
configd source: github.com/apple-oss-distributions/configd (latest tag configd-963.270.3).IPConfiguration source: github.com/apple-oss-distributions/bootp (IPConfiguration lives under bootp/IPConfiguration.bproj/).netconfigd there.security/wpa_supplicant.libIOKit).route(4) / PF_ROUTE: man 4 route.man 1 mig; the regenerator runs at build-time from src/configd/config.defs.
Revision history.
2026-05-23 — Architecture pivot: refactored from the sibling AF_UNIX/DO track to freebsd-launchd-mach (v2, the Mach-IPC track). Daemon name restored to Apple-canonical configd; configd.defs MIG IDL retained verbatim; Mach service com.apple.SystemConfiguration registered via bootstrap_check_in; libSystemConfiguration.so client framework hosts the mig-generated client stubs. PARTIALLY SHIPPED: the core SCDynamicStore RPC surface is live and consumed by IPConfiguration's sc_publish_ipv4 / sc_publish_ipv6. SCPreferences, PF_ROUTE source, scutil CLI, and SCNetworkReachability are planned in subsequent iterations. The plugin loader is deferred indefinitely; IPConfiguration runs as a standalone daemon and reaches configd over Mach RPC for State:/Network/Service/<UUID>/IPv{4,6} publishes.
(previous) — Original plan filed against the sibling freebsd-launchd (AF_UNIX/DO) track; daemon renamed netconfigd; service-to-service IPC via GNUstep Distributed Objects over AF_UNIX. Superseded for this repo.