PLC Directory over DNS (experiment)
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 235236┌─────────────────┐ 237│ DNS Server │ 238│ (Port 8053) │ 239└────────┬────────┘ 240241 ├─── Cache Check (5 min TTL) 242243244┌─────────────────┐ 245│ PLC Directory │ 246│ (plc.directory) │ 247└─────────────────┘ 248249 ▼ 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**