Compare commits
No commits in common. "514f83f90c4bad0613320129b0bec277c063fe8d" and "6c8298aeecb54484c2df249f2da6bc572c493eeb" have entirely different histories.
514f83f90c
...
6c8298aeec
2 changed files with 12 additions and 51 deletions
35
src/main.rs
35
src/main.rs
|
@ -57,7 +57,7 @@ pub struct Args {
|
||||||
#[derive(Subcommand, Clone, Debug)]
|
#[derive(Subcommand, Clone, Debug)]
|
||||||
pub enum Command {
|
pub enum Command {
|
||||||
/// Fetch a reflected IP address and update A and AAAA entries in DNS.
|
/// Fetch a reflected IP address and update A and AAAA entries in DNS.
|
||||||
Run(Run),
|
Run,
|
||||||
/// List all A and AAAA entries in each zone in the config.
|
/// List all A and AAAA entries in each zone in the config.
|
||||||
List(List),
|
List(List),
|
||||||
}
|
}
|
||||||
|
@ -107,13 +107,6 @@ impl Display for Color {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Parser, Clone, Debug)]
|
|
||||||
pub struct Run {
|
|
||||||
/// The directory to store cache files.
|
|
||||||
#[clap(long)]
|
|
||||||
cache_dir: Option<PathBuf>,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() -> ExitCode {
|
fn main() -> ExitCode {
|
||||||
let runtime = Runtime::new().unwrap();
|
let runtime = Runtime::new().unwrap();
|
||||||
let result = runtime.block_on(real_main());
|
let result = runtime.block_on(real_main());
|
||||||
|
@ -156,12 +149,12 @@ async fn real_main() -> Result<()> {
|
||||||
|
|
||||||
let config = load_config(args.config_file).context("Failed to find a suitable config file")?;
|
let config = load_config(args.config_file).context("Failed to find a suitable config file")?;
|
||||||
match args.cmd {
|
match args.cmd {
|
||||||
Command::Run(run) => handle_run(config, run).await,
|
Command::Run => handle_run(config).await,
|
||||||
Command::List(list) => handle_list(config, list).await,
|
Command::List(list) => handle_list(config, list).await,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_run(conf: Config, run: Run) -> Result<()> {
|
async fn handle_run(conf: Config) -> Result<()> {
|
||||||
let ipv4 = if let Some(addr_to_req) = conf.ip_reflector.ipv4 {
|
let ipv4 = if let Some(addr_to_req) = conf.ip_reflector.ipv4 {
|
||||||
let ip = get_ipv4(addr_to_req)
|
let ip = get_ipv4(addr_to_req)
|
||||||
.await
|
.await
|
||||||
|
@ -183,7 +176,7 @@ async fn handle_run(conf: Config, run: Run) -> Result<()> {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
let ip_cache_path = ip_cache_path(run.cache_dir).context("while getting the ip cache path")?;
|
let ip_cache_path = ip_cache_path().context("while getting the ip cache path")?;
|
||||||
let mut cache_file = load_ip_cache(&ip_cache_path).context("while loading the ip cache")?;
|
let mut cache_file = load_ip_cache(&ip_cache_path).context("while loading the ip cache")?;
|
||||||
|
|
||||||
let mut rate_limit = time::interval(Duration::from_millis(250));
|
let mut rate_limit = time::interval(Duration::from_millis(250));
|
||||||
|
@ -300,10 +293,8 @@ fn load_ip_cache<P: AsRef<Path> + Debug>(path: P) -> Result<CacheFile> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(level = "debug", ret)]
|
fn ip_cache_path() -> Result<PathBuf> {
|
||||||
fn ip_cache_path(cache_dir: Option<PathBuf>) -> Result<PathBuf> {
|
dirs::cache_dir()
|
||||||
cache_dir
|
|
||||||
.or(dirs::cache_dir())
|
|
||||||
.context("Failed to determine cache directory")
|
.context("Failed to determine cache directory")
|
||||||
.map(|path| path.join("cloudflare-ddns.cache"))
|
.map(|path| path.join("cloudflare-ddns.cache"))
|
||||||
}
|
}
|
||||||
|
@ -528,25 +519,13 @@ fn load_config_from_path<P: AsRef<Path>>(path: P) -> Option<Config> {
|
||||||
// mode is a u32, but only the bottom 9 bits represent the
|
// mode is a u32, but only the bottom 9 bits represent the
|
||||||
// permissions. Mask and keep the bits we care about.
|
// permissions. Mask and keep the bits we care about.
|
||||||
let current_mode = metadata.permissions().mode() & 0o777;
|
let current_mode = metadata.permissions().mode() & 0o777;
|
||||||
debug!(found = format!("{current_mode:o}"), "Metadata bits");
|
if current_mode != 0o600 {
|
||||||
|
|
||||||
// Check if it's readable by others
|
|
||||||
if (current_mode & 0o077) > 0 {
|
|
||||||
warn!(
|
warn!(
|
||||||
found = format!("{current_mode:o}"),
|
found = format!("{current_mode:o}"),
|
||||||
expected = "600",
|
expected = "600",
|
||||||
"File permissions too broad! Your GLOBAL Cloudflare API key is accessible to all users on the system!"
|
"File permissions too broad! Your GLOBAL Cloudflare API key is accessible to all users on the system!"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if executable bit is set
|
|
||||||
if (current_mode & 0o100) != 0 {
|
|
||||||
warn!(
|
|
||||||
found = format!("{current_mode:o}"),
|
|
||||||
expected = "600",
|
|
||||||
"Config file has executable bit set"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
warn!("Failed to read metadata for file: {e}");
|
warn!("Failed to read metadata for file: {e}");
|
||||||
|
|
|
@ -5,16 +5,13 @@ After=network-online.target
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Type=oneshot
|
Type=oneshot
|
||||||
ExecStart=/usr/bin/cloudflare-ddns run --config-file "${CREDENTIALS_DIRECTORY}/cloudflare-ddns.toml" --cache-dir "${CACHE_DIRECTORY}"
|
ExecStart=/usr/bin/cloudflare-ddns run
|
||||||
|
|
||||||
# Please modify the path after the : to point to a custom config location if you'd like
|
|
||||||
LoadCredential=cloudflare-ddns.toml:/etc/cloudflare-ddns.toml
|
|
||||||
|
|
||||||
# Security Hardening
|
|
||||||
# Run `systemd-analyze security cloudflare-ddns` for recommendations
|
|
||||||
|
|
||||||
|
# Security
|
||||||
NoNewPrivileges=true
|
NoNewPrivileges=true
|
||||||
ProtectSystem=strict
|
|
||||||
|
# Sandboxing config
|
||||||
|
ProtectSystem=true
|
||||||
PrivateTmp=true
|
PrivateTmp=true
|
||||||
PrivateDevices=true
|
PrivateDevices=true
|
||||||
ProtectHostname=true
|
ProtectHostname=true
|
||||||
|
@ -28,21 +25,6 @@ LockPersonality=true
|
||||||
MemoryDenyWriteExecute=true
|
MemoryDenyWriteExecute=true
|
||||||
RestrictRealtime=true
|
RestrictRealtime=true
|
||||||
RestrictSUIDSGID=true
|
RestrictSUIDSGID=true
|
||||||
CapabilityBoundingSet=
|
|
||||||
SystemCallArchitectures=native
|
|
||||||
SystemCallFilter=@system-service
|
|
||||||
SystemCallFilter=~@privileged
|
|
||||||
SystemCallFilter=~@resources
|
|
||||||
ProtectProc=invisible
|
|
||||||
ProcSubset=pid
|
|
||||||
RestrictAddressFamilies=AF_INET AF_INET6
|
|
||||||
UMask=066
|
|
||||||
DynamicUser=true
|
|
||||||
CacheDirectory=cloudflare-ddns
|
|
||||||
PrivateUsers=true
|
|
||||||
ProtectHome=true
|
|
||||||
# Refuse to execute any other binary
|
|
||||||
ExecPaths=/usr/bin/cloudflare-ddns
|
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy=multi-user.target
|
WantedBy=multi-user.target
|
Loading…
Reference in a new issue