A high-performance, pure Swift implementation of Multicast DNS (mDNS) and DNS Service Discovery (DNS-SD).
- Pure Swift - No C dependencies, works on all Swift platforms
- High Performance - Zero-copy parsing, inline IP address storage, DNS name compression
- RFC Compliant - Implements RFC 1035 (DNS), RFC 6762 (mDNS), RFC 6763 (DNS-SD)
- Modern Swift - Uses Swift 6 concurrency with actors and Sendable types
- Type Safe - Strongly typed DNS records, questions, and messages
- Swift 6.2+
- macOS 15+ / iOS 18+ / tvOS 18+ / watchOS 11+ / visionOS 2+
Add swift-mDNS to your Package.swift:
dependencies: [
.package(url: "https://github.com/1amageek/swift-mDNS.git", from: "1.0.0")
]Then add mDNS to your target dependencies:
.target(
name: "YourTarget",
dependencies: ["mDNS"]
)import mDNS
let browser = ServiceBrowser()
try await browser.start()
// Browse for HTTP services
try await browser.browse(for: "_http._tcp.local.")
for await event in browser.events {
switch event {
case .found(let service):
print("Found: \(service.name) at \(service.hostName ?? "unknown"):\(service.port ?? 0)")
case .updated(let service):
print("Updated: \(service.name)")
case .removed(let service):
print("Removed: \(service.name)")
case .error(let error):
print("Error: \(error)")
}
}import mDNS
let advertiser = ServiceAdvertiser()
try await advertiser.start()
let service = Service(
name: "My Web Server",
type: "_http._tcp",
port: 8080,
txtRecord: TXTRecord(["path": "/api", "version": "1.0"])
)
try await advertiser.register(service)
// Later, to unregister:
try await advertiser.unregister(service)import mDNS
// Create a query
let query = try DNSMessage.mdnsQuery(for: "_http._tcp.local.")
let encoded = query.encode()
// Decode a response
let message = try DNSMessage.decode(from: receivedData)
for answer in message.answers {
print("\(answer.name) \(answer.type) TTL=\(answer.ttl)")
switch answer.rdata {
case .ptr(let serviceName):
print(" PTR -> \(serviceName)")
case .srv(let srv):
print(" SRV -> \(srv.target):\(srv.port)")
case .txt(let strings):
print(" TXT -> \(strings)")
case .a(let addr):
print(" A -> \(addr)")
case .aaaa(let addr):
print(" AAAA -> \(addr)")
default:
break
}
}import mDNS
// Create from string
let name = try DNSName("_http._tcp.local.")
// Use string literal
let name2: DNSName = "_printer._tcp.local."
// Case-insensitive comparison
let name3: DNSName = "_HTTP._TCP.LOCAL."
print(name == name3) // true
// Encode to wire format
let encoded = name.encode()
// Decode from wire format
let (decoded, bytesConsumed) = try DNSName.decode(from: data, at: 0)import mDNS
// IPv4
let ipv4 = IPv4Address(192, 168, 1, 100)
let ipv4FromString = IPv4Address(string: "192.168.1.100")
print(ipv4.description) // "192.168.1.100"
// IPv6
let ipv6 = IPv6Address(hi: 0xfe80_0000_0000_0000, lo: 0x0000_0000_0000_0001)
let ipv6FromString = IPv6Address(string: "fe80::1")
print(ipv6.description) // "fe80::1"swift-mDNS is optimized for high throughput with minimal memory allocations.
Measured on Apple Silicon (M-series):
| Operation | Throughput | Latency |
|---|---|---|
| IPv4Address creation | 202M ops/sec | 5 ns |
| IPv6Address creation | 479M ops/sec | 2 ns |
| IPv4Address equality | 113M ops/sec | 9 ns |
| IPv4Address parsing | 513K ops/sec | 1.9 μs |
| DNSName decoding | 3.2M ops/sec | 0.31 μs |
| DNSName encoding | 230K ops/sec | 4.3 μs |
| DNSName equality | 512K ops/sec | 2.0 μs |
| DNSMessage query decoding | 1.15M ops/sec | 0.87 μs |
| DNSMessage query encoding | 202K ops/sec | 5.0 μs |
| DNSMessage response decoding | 300K ops/sec | 3.3 μs |
| DNSMessage response encoding | 73K ops/sec | 13.7 μs |
| End-to-end roundtrip | 170K ops/sec | 5.9 μs |
- Zero-copy parsing: DNS messages are parsed directly from
UnsafeRawBufferPointerwithout intermediate allocations - Zero-copy NIO integration: Direct
ByteBufferencoding/decoding withoutDataconversion - Inline IP storage: IPv4/IPv6 addresses use stack-allocated tuples instead of heap-allocated
Data - DNS name compression: Repeated name suffixes are compressed to 2-byte pointers (RFC 1035)
- ContiguousArray: Write buffer uses
ContiguousArray<UInt8>for better cache locality - ASCII case-insensitive comparison: DNS name equality uses byte-level comparison without string allocation
- Non-copyable buffers:
ReadBufferandWriteBufferuse~Copyableto prevent accidental copies
swift test --filter Benchmark| Type | Description |
|---|---|
DNSName |
DNS domain name with label encoding and compression pointer support |
DNSQuestion |
DNS query with QU bit support for mDNS unicast responses |
DNSResourceRecord |
Resource record with cache-flush bit support |
DNSRecordData |
Typed RDATA (A, AAAA, PTR, SRV, TXT, HINFO, NSEC) |
DNSMessage |
Complete DNS message with header and all sections |
IPv4Address |
IPv4 address with inline storage |
IPv6Address |
IPv6 address with inline storage |
| Type | Description |
|---|---|
Service |
Represents a discovered or advertised DNS-SD service |
TXTRecord |
Key-value TXT record attributes (case-insensitive keys) |
ServiceBrowser |
Actor for browsing services via mDNS |
ServiceAdvertiser |
Actor for advertising services via mDNS |
| Type | Value | Description |
|---|---|---|
.a |
1 | IPv4 address |
.aaaa |
28 | IPv6 address |
.ptr |
12 | Domain name pointer |
.srv |
33 | Service location |
.txt |
16 | Text strings |
.hinfo |
13 | Host information |
.nsec |
47 | Next secure record |
.any |
255 | Any record type (queries only) |
- PTR Query: Query for
_service._protocol.local.to get service instances - PTR Response: Returns
ServiceName._service._protocol.local. - SRV/TXT Query: Query for the service instance name
- SRV Response: Returns hostname and port
- TXT Response: Returns service attributes
- A/AAAA Query: Query for the hostname
- A/AAAA Response: Returns IP addresses
- Multicast Address: 224.0.0.251 (IPv4) / ff02::fb (IPv6)
- Port: 5353
- Message ID: Always 0 for mDNS
- Cache-Flush Bit: High bit of class field indicates cache flush
- QU Bit: High bit of question class requests unicast response
- Goodbye: TTL=0 indicates record withdrawal
- RFC 1035 - Domain Names - Implementation and Specification
- RFC 6762 - Multicast DNS
- RFC 6763 - DNS-Based Service Discovery
- RFC 2782 - DNS SRV Records
MIT License