135 lines
6.2 KiB
Rust
135 lines
6.2 KiB
Rust
//! Example: fetch and display OPNsense Dnsmasq DNS/DHCP settings.
|
|
//!
|
|
//! ```text
|
|
//! cargo run --example list_dnsmasq
|
|
//! ```
|
|
//!
|
|
//! This demonstrates the **full target DX** for the opnsense-api crate:
|
|
//!
|
|
//! 1. Build a typed [`OpnsenseClient`] — prompted for credentials if not set.
|
|
//! 2. Call `GET /api/dnsmasq/settings/get` with full type safety.
|
|
//! 3. Pretty-print the deserialized response.
|
|
//!
|
|
//! ## Credentials
|
|
//!
|
|
//! The client first checks for `OPNSENSE_API_KEY` and `OPNSENSE_API_SECRET`
|
|
//! environment variables. If neither is set, it prompts interactively.
|
|
|
|
use std::env;
|
|
|
|
use opnsense_api::client::OpnsenseClient;
|
|
use opnsense_api::generated::dnsmasq::DnsmasqSettingsResponse;
|
|
|
|
#[tokio::main]
|
|
async fn main() {
|
|
env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init();
|
|
|
|
let base_url = env::var("OPNSENSE_BASE_URL")
|
|
.unwrap_or_else(|_| {
|
|
eprintln!("OPNSENSE_BASE_URL not set, using https://192.168.1.1/api");
|
|
"https://192.168.1.1/api".to_string()
|
|
});
|
|
|
|
let client = match (env::var("OPNSENSE_API_KEY").ok(), env::var("OPNSENSE_API_SECRET").ok()) {
|
|
(Some(key), Some(secret)) => {
|
|
log::info!("Using credentials from environment variables");
|
|
OpnsenseClient::builder()
|
|
.base_url(&base_url)
|
|
.auth_from_key_secret(&key, &secret)
|
|
.skip_tls_verify()
|
|
.build()
|
|
.expect("failed to build HTTP client")
|
|
}
|
|
_ => {
|
|
eprintln!("ERROR: OPNSENSE_API_KEY and OPNSENSE_API_SECRET must be set.");
|
|
eprintln!(" export OPNSENSE_API_KEY=your_key");
|
|
eprintln!(" export OPNSENSE_API_SECRET=your_secret");
|
|
eprintln!(" export OPNSENSE_BASE_URL=https://your-firewall/api");
|
|
std::process::exit(1);
|
|
}
|
|
};
|
|
|
|
log::info!("Fetching /api/dnsmasq/settings/get ...");
|
|
|
|
let response: DnsmasqSettingsResponse = client
|
|
.get_typed("dnsmasq", "settings", "get")
|
|
.await
|
|
.expect("API call failed");
|
|
|
|
println!();
|
|
println!("╔═══════════════════════════════════════════════════════════╗");
|
|
println!("║ OPNsense Dnsmasq Settings ║");
|
|
println!("╚═══════════════════════════════════════════════════════════╝");
|
|
println!();
|
|
|
|
let s = &response.dnsmasq;
|
|
|
|
println!(" General");
|
|
println!(" ─────────────────────────────────────────────────────────");
|
|
println!(" DNS service enabled: {}", toggle(s.enable));
|
|
println!(" DNSSEC validation: {}", toggle(s.dnssec));
|
|
println!(" Log queries: {}", toggle(s.log_queries));
|
|
println!();
|
|
|
|
println!(" DNS Options");
|
|
println!(" ─────────────────────────────────────────────────────────");
|
|
println!(" Domain required: {}", toggle(s.domain_needed));
|
|
println!(" No private revers: {}", toggle(s.no_private_reverse));
|
|
println!(" Strict order: {}", toggle(s.strict_order));
|
|
println!(" No /etc/hosts: {}", toggle(s.no_hosts));
|
|
println!(" Strict bind: {}", toggle(s.strictbind));
|
|
println!(" Cache size: {}", s.cache_size.map(|v| v.to_string()).unwrap_or_else(|| "—".to_string()));
|
|
println!(" Local TTL: {}", s.local_ttl.map(|v| v.to_string()).unwrap_or_else(|| "—".to_string()));
|
|
println!(" DNS port: {}", s.port.map(|v| v.to_string()).unwrap_or_else(|| "53".to_string()));
|
|
println!();
|
|
|
|
println!(" DHCP Registration");
|
|
println!(" ─────────────────────────────────────────────────────────");
|
|
println!(" Register DHCP leases: {}", toggle(s.regdhcp));
|
|
println!(" Register static DHCP: {}", toggle(s.regdhcpstatic));
|
|
println!(" DHCP first: {}", toggle(s.dhcpfirst));
|
|
println!(" No ident: {}", toggle(s.no_ident));
|
|
if let Some(ref domain) = s.regdhcpdomain {
|
|
println!(" Domain: {domain}");
|
|
}
|
|
println!();
|
|
|
|
println!(" DHCP Options");
|
|
println!(" ─────────────────────────────────────────────────────────");
|
|
println!(" Add MAC address: {}", add_mac_label(&s.add_mac));
|
|
println!(" Add subnet: {}", toggle(s.add_subnet));
|
|
println!(" Strip subnet: {}", toggle(s.strip_subnet));
|
|
println!(" No /etc/resolv: {}", toggle(s.no_resolv));
|
|
if let Some(v) = s.dns_forward_max {
|
|
println!(" DNS forward max: {v}");
|
|
}
|
|
println!();
|
|
|
|
println!(" Full response (JSON)");
|
|
println!(" ─────────────────────────────────────────────────────────");
|
|
println!(" {}", serde_json::to_string_pretty(&response).unwrap());
|
|
}
|
|
|
|
fn toggle(b: bool) -> &'static str {
|
|
if b { "enabled ✓" } else { "disabled ✗" }
|
|
}
|
|
|
|
fn add_mac_label(mac: &Option<serde_json::Value>) -> String {
|
|
match mac {
|
|
Some(serde_json::Value::Object(map)) => {
|
|
map.iter()
|
|
.find(|(_, v)| v.get("selected").and_then(|s| s.as_i64()).map(|x| x == 1).unwrap_or(false))
|
|
.map(|(k, v)| {
|
|
if k.is_empty() {
|
|
v.get("value").and_then(|x| x.as_str()).unwrap_or("not set")
|
|
} else {
|
|
k.as_str()
|
|
}
|
|
})
|
|
.unwrap_or("not set")
|
|
.to_string()
|
|
}
|
|
_ => "not set".to_string(),
|
|
}
|
|
}
|