diff --git a/README.md b/README.md index dbc5023..6a74a83 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # DNS Service -A Go-based web frontend for managing dnsmasq DNS server configurations. This service provides a RESTful API and web interface for dynamically managing DNS settings, host mappings, and resolver configurations. +A Go-based web frontend for managing dnsmasq DNS server configurations. This service provides a RESTful API and web interface for dynamically managing DNS settings, host mappings, and resolver configurations. The application features a modular architecture with separate packages for server management, API handling, and utility functions. ## Features @@ -12,6 +12,8 @@ A Go-based web frontend for managing dnsmasq DNS server configurations. This ser - **TLS Support**: Optional HTTPS/TLS encryption - **Service Integration**: Systemd-compatible service management - **Cache Control**: Configurable DNS cache size settings +- **Modular Architecture**: Clean separation of concerns with dedicated packages +- **Error Handling**: Comprehensive error handling and logging ## Prerequisites @@ -226,10 +228,14 @@ dns_service/ │ ├── settings.go # Settings API handler │ ├── settings_file.go # Configuration file handler │ └── spa.go # Single-page application handler +├── server/ # Server configuration and startup +│ ├── Configure.go # HTTP routes configuration +│ └── Run.go # Server startup and TLS handling ├── settings/ # Settings management │ ├── get_settings.go # Get settings functionality │ └── set_settings.go # Set settings functionality ├── utils/ # Utility functions +│ ├── LoadEnd.go # Environment loading utilities │ ├── decode_hosts.go # Host parsing utilities │ ├── decode_resolvs.go # Resolver parsing utilities │ ├── decode_settings.go # Settings parsing utilities @@ -240,6 +246,7 @@ dns_service/ ├── go.sum # Go module checksums ├── dns_service.conf # Configuration file ├── dns_service.service # Init script +├── LICENSE # MIT License └── README.md # This file ``` @@ -273,7 +280,78 @@ go test ./api The project uses minimal external dependencies: -- `github.com/joho/godotenv` - Environment variable loading +- `github.com/joho/godotenv` - Environment variable loading from configuration files + +### Architecture + +The application follows a clean modular architecture with clear separation of concerns: + +- **main.go**: Application entry point that orchestrates startup sequence +- **server/**: Server configuration and HTTP handling + - `Configure.go`: HTTP routes and middleware setup + - `Run.go`: Server startup with TLS/HTTP support and error handling +- **api/**: REST API endpoints and frontend serving + - `settings.go`: DNS settings API endpoints + - `settings_file.go`: Configuration file management endpoints + - `spa.go`: Single-page application serving +- **utils/**: Shared utility functions and environment management + - `LoadEnd.go`: Environment variable loading and validation + - Various decode utilities for parsing DNS configurations +- **settings/**: DNS settings management and persistence + - Configuration reading and writing functionality + +### Modular Development Approach + +The codebase is designed with modularity in mind: + +**Benefits:** +- **Maintainability**: Each package has a single responsibility +- **Testability**: Individual components can be tested in isolation +- **Reusability**: Utility functions can be shared across packages +- **Scalability**: New features can be added without affecting existing code +- **Code Organization**: Clear structure makes onboarding easier + +**Development Workflow:** +1. **Environment Setup**: `utils.LoadEnv()` loads configuration +2. **Server Configuration**: `server.Configure()` sets up routes +3. **Server Startup**: `server.Run()` starts the HTTP/HTTPS server +4. **API Handling**: Individual handlers process requests +5. **Settings Management**: Dedicated package manages DNS configurations + +**Adding New Features:** +- Add new API endpoints in `api/` package +- Implement business logic in appropriate packages +- Add utility functions in `utils/` package +- Update server configuration if needed + +### Code Examples + +**Basic Server Setup:** +```go +package main + +import ( + "dns_service/server" + "dns_service/utils" +) + +func main() { + utils.LoadEnv() // Load environment variables + server.Configure() // Configure HTTP routes + server.Run() // Start the server +} +``` + +**Adding Custom Middleware:** +```go +// In server/Configure.go +func Configure() { + // Add custom middleware + http.Handle("/", middleware(api.SpaHandler(http.FS(api.Frontend)))) + http.HandleFunc("/api/settings", api.Settings) + http.HandleFunc("/api/settings/file", api.SettingsFile) +} +``` ## Usage Examples @@ -286,7 +364,7 @@ The project uses minimal external dependencies: ### Home Network Setup -Perfect for home labs and local development: +Perfect for home labs and local development environments: ```json { @@ -300,7 +378,7 @@ Perfect for home labs and local development: } ``` -### Corporate Network Setup +### Corporate/Enterprise Network Setup ```json { @@ -316,21 +394,37 @@ Perfect for home labs and local development: ## Security Considerations -- Always use TLS in production environments -- Restrict access to the management interface -- Use strong SSL certificates from a trusted CA -- Regularly update the service and dependencies -- Monitor logs for suspicious activity -- Consider firewall rules to limit access +- **Always use TLS in production environments** +- **Restrict access to the management interface** (firewall rules, VPN, etc.) +- **Use strong SSL certificates from a trusted CA** (avoid self-signed in production) +- **Regularly update the service and dependencies** +- **Monitor logs for suspicious activity** +- **Consider firewall rules to limit access** to port 8090 +- **Use strong file permissions** on configuration files +- **Regular security audits** of the system configuration ## Troubleshooting ### Common Issues -1. **Service won't start**: Check configuration file syntax and permissions -2. **TLS errors**: Verify certificate files and permissions -3. **Port conflicts**: Ensure port 8090 is not in use by another service -4. **dnsmasq integration**: Verify dnsmasq is installed and properly configured +1. **Service won't start**: + - Check configuration file syntax and permissions + - Verify `/etc/dns_service/dns_service.conf` exists and is readable + - Check if required directories exist + +2. **TLS errors**: + - Verify certificate files exist and have correct permissions + - Check certificate validity dates + - Ensure private key matches certificate + +3. **Port conflicts**: + - Ensure port 8090 is not in use by another service + - Use `netstat -tlnp | grep 8090` to check port usage + +4. **dnsmasq integration**: + - Verify dnsmasq is installed and properly configured + - Check if dnsmasq service is running + - Verify dnsmasq configuration file paths ### Logs diff --git a/main.go b/main.go index a0bb875..e2b8aaf 100644 --- a/main.go +++ b/main.go @@ -1,35 +1,12 @@ package main import ( - "dns_service/api" - "log" - "net/http" - "os" - - "github.com/joho/godotenv" + "dns_service/server" + "dns_service/utils" ) func main() { - err := godotenv.Load("/etc/dns_service/dns_service.conf") - if err != nil { - log.Fatal("Error loading .env file") - } - - http.Handle("/", api.SpaHandler(http.FS(api.Frontend))) - http.HandleFunc("/api/settings", api.Settings) - http.HandleFunc("/api/settings/file", api.SettingsFile) - - if os.Getenv("ENABLE_TLS") == "true" { - http.ListenAndServeTLS( - os.Getenv("SERVER_ADDRESS")+":"+os.Getenv("SERVER_PORT"), - os.Getenv("CERT_FILE"), - os.Getenv("KEY_FILE"), - nil, - ) - } else { - http.ListenAndServe( - os.Getenv("SERVER_ADDRESS")+":"+os.Getenv("SERVER_PORT"), - nil, - ) - } + utils.LoadEnv() + server.Configure() + server.Run() } diff --git a/server/Configure.go b/server/Configure.go new file mode 100644 index 0000000..a00febb --- /dev/null +++ b/server/Configure.go @@ -0,0 +1,12 @@ +package server + +import ( + "dns_service/api" + "net/http" +) + +func Configure() { + http.Handle("/", api.SpaHandler(http.FS(api.Frontend))) + http.HandleFunc("/api/settings", api.Settings) + http.HandleFunc("/api/settings/file", api.SettingsFile) +} diff --git a/server/Run.go b/server/Run.go new file mode 100644 index 0000000..b6e8678 --- /dev/null +++ b/server/Run.go @@ -0,0 +1,29 @@ +package server + +import ( + "log" + "net/http" + "os" +) + +func Run() { + if os.Getenv("ENABLE_TLS") == "true" { + err := http.ListenAndServeTLS( + os.Getenv("SERVER_ADDRESS")+":"+os.Getenv("SERVER_PORT"), + os.Getenv("CERT_FILE"), + os.Getenv("KEY_FILE"), + nil, + ) + if err != nil { + log.Fatal(err) + } + } else { + err := http.ListenAndServe( + os.Getenv("SERVER_ADDRESS")+":"+os.Getenv("SERVER_PORT"), + nil, + ) + if err != nil { + log.Fatal(err) + } + } +} diff --git a/utils/LoadEnd.go b/utils/LoadEnd.go new file mode 100644 index 0000000..15bd702 --- /dev/null +++ b/utils/LoadEnd.go @@ -0,0 +1,14 @@ +package utils + +import ( + "log" + + "github.com/joho/godotenv" +) + +func LoadEnv() { + err := godotenv.Load("/etc/dns_service/dns_service.conf") + if err != nil { + log.Fatal("Error loading .env file") + } +}