Semantic DNS is an ISA-95-aligned, UNS-adjacent network context source for environments that need names to reflect what a device is and where it belongs in the process, not just whatever hostname it happened to ask for. It turns asset observations into stable, meaningful DNS records and serves that semantic view as a real DNS zone.
The naming model is now explicitly split into two layers:
- DNS FQDNs carry network and ISA-95 placement context in resolvable,
leaf-first form such as
CaseRobot.Palletizer.Packout.Zone4.Milwaukee.local - hardware identities such as MAC addresses, serial numbers, or future x509 certificate fingerprints bind the record to a real physical or cryptographic endpoint
- application identities such as UNIs and URNs are carried alongside the DNS record as stable identifiers that do not have to change when a device moves in the hierarchy
Instead of treating DNS as a separate manual inventory problem, Semantic DNS
lets you ingest DHCP and discovery data, merge that data into a semantic record
for each device, publish a zone file, and keep an audit trail of how those
names were assigned. In the default deployment, the semantic service maintains
the zone data and the bundled CoreDNS layer serves it on TCP/UDP port 53.
That means you can move from raw sightings like MAC addresses, DHCP
fingerprints, or imported asset inventory to names such as
DriveVFD.Conveyor.Cell5.Zone3.Milwaukee.local with attached metadata and
provenance. The canonical DNS order is leaf-first so each parent label can be a
meaningful resolvable network context: leaf.work-unit.work-center.area.site.local.
- Serves a DNS zone whose records are derived from operational asset context instead of flat, manually curated host lists.
- Builds stable DNS names from ISA-95-aligned context such as site, area, work center, work unit, and function instead of relying on ad hoc hostnames alone.
- Merges multiple observation sources into one semantic record, including manual API input, protocol analysis, switch intelligence, DHCP fingerprinting, discovery, and replacement inference.
- Preserves field-level provenance so you can see where values such as class, vendor, model, or status came from and how confident the record is.
- Resolves devices by FQDN, internal IP, or external IP through the API.
- Publishes a DNS zone file and companion TXT records that expose semantic metadata alongside A records.
- Tracks DHCP leases, quarantine queues, fingerprint rules, role templates, and reconciliation status for the DNS publishing workflow.
- Emits signed audit events for security- and operations-relevant actions such as observation ingest and quarantine authorization.
- Streams record updates over WebSockets so other tooling can react to changes without polling.
- Imports existing asset context from a Fathom-style PostgreSQL database so the DNS view can be bootstrapped from an inventory source of truth.
- Provides a network context layer that can publish into a UNS or adjacent systems without requiring Semantic DNS itself to be the broker of record.
Semantic DNS now models three related but different identity surfaces:
fqdn: the canonical resolvable DNS name for the current network and ISA-95 placementhardware_identities: hardware or certificate-linked identities such as MAC addresses, serial numbers, DHCP client IDs, or x509-derived valuesapplication_identities: stable application-level identifiers such asurn:mes:asset:case-robot-204oruni://packout/palletizer/caserobotaliases: human-friendly or legacy lookup names that should still resolve to the current canonical record
That means:
- DNS is for resolution and topology context
- hardware identities are for binding a record to a real device or trust anchor
- UNI and URN identifiers are for application identity and cross-system joins
- aliases are compatibility handles for operators and older tooling
Records can also carry relations like located-in, served-by, or
reports-to so applications can reason about how an asset sits in a broader
context graph without encoding those relationships in the hostname.
Application identities are searchable and resolvable through the API store layer, but they do not become additional DNS labels.
The default deployment is a small DNS stack:
semantic-dns: the semantic control plane that accepts observations, maintains records, writes the zone file, and exposes the HTTP and WebSocket API on port8088postgres: persistent storage for records, leases, templates, fingerprints, audit history, and sync statednsvia CoreDNS: the DNS serving layer that answers queries on TCP/UDP port53using the zone file maintained by Semantic DNS
In other words, Semantic DNS is not just a library or data model. The shipped deployment runs an actual DNS server in front of a semantic naming engine.
- A system or operator submits an observation with whatever facts are known: IPs, MAC, vendor, model, protocols, ISA-95 hierarchy context, and status.
- Semantic DNS merges that observation into a canonical semantic record and derives a stable FQDN from the available operational context.
- The DNS publisher rewrites the zone file so the current semantic view is available to downstream DNS infrastructure.
- The service records an audit event and broadcasts the updated record to subscribers.
For manual record creation, Semantic DNS now treats ISA-95 hierarchy nodes as
first-class records. That means a device like
CaseRobot.Palletizer.Packout.Zone4.Milwaukee.local is expected to sit beneath
existing work-unit, work-center, area, and site records such as:
Palletizer.Packout.Zone4.Milwaukee.localPackout.Zone4.Milwaukee.localZone4.Milwaukee.localMilwaukee.local
Manual API writes are validated against that parent chain so devices only get published into a hierarchy that can actually resolve step-by-step.
Manual API writes now enforce two things:
- The ISA-95 hierarchy must be complete for the declared
node_kind - A MAC address or another hardware identity must be present
- Parent hierarchy records must already exist for manual
device,work-unit,work-center, andarearecords
So if you want to create a device like
CaseRobot.Palletizer.Packout.Zone4.Milwaukee.local, the following hierarchy
records are expected to exist already:
Milwaukee.localassiteZone4.Milwaukee.localasareaPackout.Zone4.Milwaukee.localaswork-centerPalletizer.Packout.Zone4.Milwaukee.localaswork-unit
Passive discovery and imports are still allowed to land partial context, but manual authoring now reflects the stricter “every step must resolve” rule.
The web console now exposes a guided hierarchy builder so operators do not need to hand-author JSON observations.
The authoring workflow is:
- create or select a
site - create an
areabeneath that site - create a
work-centerbeneath that area - create a
work-unitbeneath that work center - create one or more
devicerecords beneath that work unit
The builder shows:
- the selected
node_kind - a live FQDN preview such as
CaseRobot.Palletizer.Packout.Zone4.Milwaukee.local - whether each parent level already exists and resolves
- whether a MAC address or another hardware identity is present
- whether the target FQDN already exists
- optional UNI, URN, and alias inputs
This means an operator can build the hierarchy in the same order DNS resolves it, while still attaching hardware and application identity at create time.
Semantic DNS now treats hardware identity as a first-class part of the record.
macremains as a convenience fieldhardware_identitiesis the canonical extensible list for device anchoring- DHCP lease data can enrich matching records with MAC-derived hardware identity when the lease can be matched by DNS name or IP
- the model is ready for future x509-linked identities like subject, SAN URI, or SPKI fingerprint
If you want to run Semantic DNS as a real DNS server, start here.
Prerequisites:
- Docker with Compose support
- A host where you can bind TCP/UDP port
53
Create the runtime environment file:
cp deploy/server.env.example deploy/server.envEdit deploy/server.env and replace the placeholder passwords and tokens.
Start the full stack:
docker compose --env-file deploy/server.env -f deploy/server-compose.yaml up -d --buildOnce the stack is up:
- DNS answers on TCP/UDP
53 - The HTTP API is available on
8088 - PostgreSQL stores the semantic state and audit history
- CoreDNS serves the generated zone file from
/data/semantic-dns.zone
The bundled CoreDNS configuration forwards non-local lookups to 8.8.8.8
and serves the semantic zone described in deploy/Corefile.
Prerequisites:
- Rust
1.88 - Docker or another reachable PostgreSQL instance
Start the local PostgreSQL dependency:
docker compose up -d postgresRun the service with the development config:
cargo run -p semantic-dns -- --config config/dev.tomlStart the operator console in a second terminal:
cd apps/web
npm install
npm run devCheck the health endpoint with the development admin token:
curl -H 'Authorization: Bearer semantic-admin-token' \
http://127.0.0.1:8088/api/v1/healthPush a sample DHCP observation:
curl -X POST \
-H 'Authorization: Bearer semantic-dhcp-token' \
-H 'Content-Type: application/json' \
http://127.0.0.1:8088/api/v1/observations \
-d '{
"id":"11111111-1111-7111-8111-111111111111",
"device_id":"22222222-2222-7222-8222-222222222222",
"observed_at":"2026-03-24T18:00:00Z",
"source":"dhcp-fingerprint",
"external_ip":"10.50.3.47",
"internal_ip":"192.168.1.47",
"class":"vfd",
"vendor":"rockwell",
"model":"PowerFlex500",
"protocols":["ethernet-ip"],
"mac":"00:00:BC:3A:47:12",
"switch_port":"Gi1/0/5",
"enterprise":"Butterbones",
"site":"Milwaukee",
"area":"Zone3",
"work_center":"Cell5",
"work_center_kind":"process-cell",
"work_unit":"Conveyor",
"facility":"Milwaukee",
"zone":"Zone3",
"cell":"Cell5",
"process":"Conveyor",
"function":"DriveVFD",
"status":"active"
}'The generated zone file is written to ./semantic-dns.zone when using the
development config.
After ingesting the observation, you can:
- Resolve the resulting record by IP or FQDN
- Query the semantic record index
- Open the operator console at
http://127.0.0.1:5173 - Confirm that
semantic-dns.zonewas rewritten with the new record - Inspect DNS synchronization state and other operational APIs
Resolve the resulting record by IP or FQDN:
curl -H 'Authorization: Bearer semantic-admin-token' \
http://127.0.0.1:8088/api/v1/resolve/192.168.1.47Query the semantic record index:
curl -H 'Authorization: Bearer semantic-admin-token' \
'http://127.0.0.1:8088/api/v1/dns/query?site=Milwaukee&work_center=Cell5&class=vfd'After ingest, the service can also:
- Regenerate
semantic-dns.zonewith the current A and TXT records. - Show DNS synchronization health at
/api/v1/dhcp/dns/sync-status. - Evaluate fingerprint input against stored rules and role templates.
- Import Fathom asset data with
/api/v1/integrations/fathom/import. - Push change notifications to WebSocket clients on
/api/v1/ws.
The HTTP API is the control plane for the DNS server. It lets you:
- Ingest observations with
/api/v1/observations - Resolve names or addresses with
/api/v1/resolve/{target} - Query semantic records with
/api/v1/dns/query - Manage DHCP-related state with the
/api/v1/dhcp/*endpoints - Import external inventory with
/api/v1/integrations/fathom/import - Subscribe to change events with
/api/v1/ws
The DNS plane is the served zone itself. Semantic DNS updates the zone file, and CoreDNS answers queries from that generated data.
The frontend operator console lives in apps/web. It currently provides:
Records: searchable semantic record explorer with field provenanceGraph: ISA-95 hierarchy graph for sites, areas, work centers, work units, and attached devicesOperations: synchronization, quarantine, fingerprints, and role templatesAudit: recent audit ledger events exposed by the HTTP API
Semantic DNS stores ISA-95 hierarchy hints directly on observations and
semantic records, including enterprise, site, area, work_center,
work_center_kind, and work_unit.
For compatibility with older clients and existing data, it also preserves the
legacy aliases facility, zone, cell, and process. Those aliases map to
site, area, work_center, and work_unit respectively.
Implementation note: the codebase is a Rust workspace, but the product it builds is a DNS server and its supporting control plane.
semantic-dns: binary that wires the system togethersdns-api: Axum HTTP API and WebSocket event streamsdns-bind: DNS publication boundary with a file-backed publishersdns-store: PostgreSQL store plus an in-memory test doublesdns-audit: signed audit ledger for asset and DNS eventssdns-core: semantic record model, naming rules, and metadata merge logicsdns-dhcp: fingerprinting, role templates, and replacement detectionsdns-fathom: importer for Fathom AssetDB-style PostgreSQL statesdns-common: shared IDs, config loading, auth roles, and errorsapps/web: React + Tailwind operator console for records, graph, ops, and audit views
Run the standard quality checks locally:
cargo fmt --check
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspaceThe repository includes a pinned toolchain in rust-toolchain.toml and a CI
workflow in .github/workflows/ci.yml that runs the same checks on pushes and
pull requests.
The deployment assets live in the multi-stage Dockerfile, the runtime config generator in deploy/docker-entrypoint.sh, and the full stack definition in deploy/server-compose.yaml.
This repository is licensed under the GNU Affero General Public License v3.0. See LICENSE. The bundled tokens and passwords are development defaults only and must be replaced for any shared or production deployment.
