1# plcdns
2
3**PLC Directory over DNS** - A DNS server that resolves Bluesky/AT Protocol DID PLC identifiers to their associated metadata via DNS TXT records.
4
5## Features
6
7- 🔍 **Handle Resolution** - Resolve DIDs to their AT Protocol handles
8- 🌐 **PDS Discovery** - Find Personal Data Server endpoints
9- 🔧 **Service Resolution** - Resolve any service from DID documents (PDS, labelers, etc.)
10- 🔑 **Public Key Lookup** - Retrieve verification public keys
11- ⚡ **Caching** - 5-minute cache to reduce PLC directory load
12- 🐳 **Docker Support** - Easy deployment with Docker
13- ✅ **Comprehensive Tests** - Full test coverage
14
15## Installation
16
17### From Source
18
19```bash
20# Clone the repository
21git clone https://tangled.org/@tree.fail/plcdns
22cd plcdns
23
24# Install dependencies
25go mod download
26
27# Build
28go build -o plcdns
29
30# Run
31./plcdns -port 8053
32```
33
34### Using Docker
35
36```bash
37# Build
38docker build -t plcdns .
39
40# Run
41docker run -p 8053:8053 -e DNS_PORT=8053 plcdns
42```
43
44### Using Go Install
45
46```bash
47go install tangled.org/@tree.fail/plcdns@latest
48```
49
50## Usage
51
52### Starting the Server
53
54```bash
55# Default port (8053)
56./plcdns
57
58# Custom port via flag
59./plcdns -port 9053
60
61# Custom port via environment variable
62DNS_PORT=9053 ./plcdns
63
64# Custom PLC directory
65./plcdns -port 8053 -plc https://plc.directory
66```
67
68### Query Formats
69
70The server supports four types of queries using different subdomain prefixes:
71
72| Query Type | Format | Returns | Example |
73|:-----------|:-------|:--------|:--------|
74| Handle | `_handle.<did>.plc.atscan.net` | AT Protocol handle | `test.bsky.social` |
75| PDS | `_pds.<did>.plc.atscan.net` | PDS endpoint URL | `https://bsky.social` |
76| Labeler | `_labeler.<did>.plc.atscan.net` | Labeler service URL | `https://mod.bsky.app` |
77| Public Key | `_pubkey.<did>.plc.atscan.net` | Public key (multibase) | `zQ3sh...` |
78
79### Query Examples
80
81```bash
82# Using dig
83dig @localhost -p 8053 _handle.z72i7hdynmk6r22z27h6tvur.plc.atscan.net TXT
84dig @localhost -p 8053 _pds.z72i7hdynmk6r22z27h6tvur.plc.atscan.net TXT
85dig @localhost -p 8053 _labeler.ar7c4by46qjdydhdevvrndac.plc.atscan.net TXT
86dig @localhost -p 8053 _pubkey.z72i7hdynmk6r22z27h6tvur.plc.atscan.net TXT
87
88# Using nslookup
89nslookup -type=TXT _handle.z72i7hdynmk6r22z27h6tvur.plc.atscan.net localhost -port=8053
90
91# Using host
92host -t TXT _pds.z72i7hdynmk6r22z27h6tvur.plc.atscan.net localhost -p 8053
93```
94
95### Example Response
96
97```bash
98$ dig @localhost -p 8053 _handle.z72i7hdynmk6r22z27h6tvur.plc.atscan.net TXT +short
99"bsky.app"
100
101$ dig @localhost -p 8053 _pds.z72i7hdynmk6r22z27h6tvur.plc.atscan.net TXT +short
102"https://bsky.social"
103```
104
105## Configuration
106
107### Command Line Flags
108
109| Flag | Default | Description |
110|:-----|:--------|:------------|
111| `-port` | `8053` | DNS server port |
112| `-plc` | `https://plc.directory` | PLC directory URL |
113
114### Environment Variables
115
116| Variable | Description |
117|:---------|:------------|
118| `DNS_PORT` | Override default port (8053) |
119
120### Cache Settings
121
122- **TTL**: 300 seconds (5 minutes) for DNS records
123- **Cache Duration**: 5 minutes for DID documents
124- **Cache Type**: In-memory map
125
126## Testing
127
128```bash
129# Run all tests
130go test -v
131
132# Run with coverage
133go test -v -cover
134
135# Generate coverage report
136go test -coverprofile=coverage.out
137go tool cover -html=coverage.out
138
139# Run with race detector
140go test -v -race
141```
142
143## API Reference
144
145### DID Document Structure
146
147The server fetches DID documents from the PLC directory with the following structure:
148
149```json
150{
151 "@context": ["https://www.w3.org/ns/did/v1"],
152 "id": "did:plc:z72i7hdynmk6r22z27h6tvur",
153 "alsoKnownAs": ["at://bsky.app"],
154 "verificationMethod": [{
155 "id": "did:plc:z72i7hdynmk6r22z27h6tvur#atproto",
156 "type": "Multikey",
157 "controller": "did:plc:z72i7hdynmk6r22z27h6tvur",
158 "publicKeyMultibase": "zQ3sh..."
159 }],
160 "service": [{
161 "id": "#atproto_pds",
162 "type": "AtprotoPersonalDataServer",
163 "serviceEndpoint": "https://bsky.social"
164 }]
165}
166```
167
168## Deployment
169
170### Systemd Service
171
172Create `/etc/systemd/system/plcdns.service`:
173
174```ini
175[Unit]
176Description=PLC Directory DNS Server
177After=network.target
178
179[Service]
180Type=simple
181User=plcdns
182ExecStart=/usr/local/bin/plcdns -port 53
183Restart=always
184Environment="DNS_PORT=53"
185
186[Install]
187WantedBy=multi-user.target
188```
189
190Enable and start:
191
192```bash
193sudo systemctl enable plcdns
194sudo systemctl start plcdns
195```
196
197### Docker Compose
198
199```yaml
200version: '3.8'
201
202services:
203 plcdns:
204 build: .
205 ports:
206 - "53:53/udp"
207 - "53:53/tcp"
208 environment:
209 - DNS_PORT=53
210 restart: unless-stopped
211```
212
213### Running on Port 53
214
215To run on the standard DNS port (53), you need elevated privileges:
216
217**Linux (with capabilities):**
218```bash
219sudo setcap 'cap_net_bind_service=+ep' ./plcdns
220./plcdns -port 53
221```
222
223**Using sudo:**
224```bash
225sudo ./plcdns -port 53
226```
227
228## Architecture
229
230```
231┌─────────────┐
232│ DNS Client │
233└──────┬──────┘
234 │ Query: _handle.<did>.plc.atscan.net
235 ▼
236┌─────────────────┐
237│ DNS Server │
238│ (Port 8053) │
239└────────┬────────┘
240 │
241 ├─── Cache Check (5 min TTL)
242 │
243 ▼
244┌─────────────────┐
245│ PLC Directory │
246│ (plc.directory) │
247└─────────────────┘
248 │
249 ▼ DID Document
250┌─────────────────┐
251│ Parse & Return │
252│ TXT Record │
253└─────────────────┘
254```
255
256## Performance
257
258- **Cache Hit**: ~1ms response time
259- **Cache Miss**: ~50-200ms (depends on PLC directory)
260- **Concurrent Requests**: Supports thousands of concurrent queries
261- **Memory Usage**: ~10-50MB depending on cache size
262
263## Contributing
264
265Contributions are welcome! Please:
266
2671. Fork the repository
2682. Create a feature branch (`git checkout -b feature/amazing-feature`)
2693. Commit your changes (`git commit -m 'Add amazing feature'`)
2704. Push to the branch (`git push origin feature/amazing-feature`)
2715. Open a Pull Request
272
273### Code Style
274
275- Follow standard Go conventions
276- Run `go fmt` before committing
277- Add tests for new features
278- Update documentation as needed
279
280## License
281
282MIT License - see [LICENSE](LICENSE) file for details
283
284## Related Projects
285
286- [AT Protocol](https://atproto.com/) - Authenticated Transfer Protocol
287- [Bluesky](https://bsky.app/) - Social network built on AT Protocol
288- [PLC Directory](https://plc.directory/) - DID PLC registry
289
290## Acknowledgments
291
292- Built with [miekg/dns](https://github.com/miekg/dns) - DNS library for Go
293- Inspired by the AT Protocol ecosystem
294
295## Roadmap
296
297- [ ] DNSSEC support
298- [ ] Prometheus metrics endpoint
299- [ ] Redis cache backend option
300- [ ] Rate limiting
301- [ ] Multiple PLC directory fallbacks
302- [ ] Web UI for testing queries
303- [ ] REST API endpoint
304
305---
306
307**Made with ❤️ for the AT Protocol community**