feat: add DHCP subnet (CIDR) configuration parameter

Allow -d to optionally accept a CIDR subnet (e.g. -d 10.0.0.0/24)
to fix the DHCP address range. When specified, the DHCP allocator
uses the configured subnet instead of deriving it from peer IPs.

Changes:
- Add dhcp_cidr field to config struct and ConfigLoader trait
- Modify -d CLI arg to accept optional CIDR string value
- Update DHCP logic to use configured CIDR as default subnet
- Add dhcp_cidr to NetworkConfig proto message
- Update launcher to handle dhcp_cidr in gen_config/new_from_config
- Update i18n translations
This commit is contained in:
copilot-swe-agent[bot]
2026-06-08 15:31:53 +00:00
committed by GitHub
parent 0a8c95879b
commit 8181830902
6 changed files with 49 additions and 7 deletions
+16
View File
@@ -185,6 +185,9 @@ pub trait ConfigLoader: Send + Sync {
fn get_dhcp(&self) -> bool;
fn set_dhcp(&self, dhcp: bool);
fn get_dhcp_cidr(&self) -> Option<cidr::Ipv4Cidr>;
fn set_dhcp_cidr(&self, cidr: Option<cidr::Ipv4Cidr>);
fn add_proxy_cidr(
&self,
cidr: cidr::Ipv4Cidr,
@@ -535,6 +538,7 @@ struct Config {
ipv6_public_addr_auto: Option<bool>,
ipv6_public_addr_prefix: Option<String>,
dhcp: Option<bool>,
dhcp_cidr: Option<String>,
network_identity: Option<NetworkIdentity>,
listeners: Option<Vec<url::Url>>,
mapped_listeners: Option<Vec<url::Url>>,
@@ -768,6 +772,18 @@ impl ConfigLoader for TomlConfigLoader {
self.config.lock().unwrap().dhcp = Some(dhcp);
}
fn get_dhcp_cidr(&self) -> Option<cidr::Ipv4Cidr> {
let locked_config = self.config.lock().unwrap();
locked_config
.dhcp_cidr
.as_ref()
.and_then(|s| s.parse().ok())
}
fn set_dhcp_cidr(&self, cidr: Option<cidr::Ipv4Cidr>) {
self.config.lock().unwrap().dhcp_cidr = cidr.map(|c| c.to_string());
}
fn add_proxy_cidr(
&self,
cidr: cidr::Ipv4Cidr,
+14 -3
View File
@@ -204,7 +204,7 @@ struct NetworkOptions {
num_args = 0..=1,
default_missing_value = "true"
)]
dhcp: Option<bool>,
dhcp: Option<String>,
#[arg(
short,
@@ -907,8 +907,19 @@ impl NetworkOptions {
cfg.set_network_identity(NetworkIdentity::new_credential(network_name));
}
if let Some(dhcp) = self.dhcp {
cfg.set_dhcp(dhcp);
if let Some(ref dhcp) = self.dhcp {
if dhcp == "true" || dhcp == "1" {
cfg.set_dhcp(true);
} else if dhcp == "false" || dhcp == "0" {
cfg.set_dhcp(false);
} else {
// Treat as CIDR, e.g. "10.0.0.0/24"
cfg.set_dhcp(true);
let cidr: cidr::Ipv4Cidr = dhcp.parse().with_context(|| {
format!("failed to parse dhcp cidr: {}", dhcp)
})?;
cfg.set_dhcp_cidr(Some(cidr));
}
}
if let Some(ipv4) = &self.ipv4 {
+10 -2
View File
@@ -829,7 +829,11 @@ impl Instance {
let nic_ctx = self.nic_ctx.clone();
let _peer_packet_receiver = self.peer_packet_receiver.clone();
tokio::spawn(async move {
let default_ipv4_addr = Ipv4Inet::new(Ipv4Addr::new(10, 126, 126, 0), 24).unwrap();
let default_ipv4_addr = if let Some(dhcp_cidr) = global_ctx_c.config.get_dhcp_cidr() {
Ipv4Inet::new(dhcp_cidr.first_address(), dhcp_cidr.network_length()).unwrap()
} else {
Ipv4Inet::new(Ipv4Addr::new(10, 126, 126, 0), 24).unwrap()
};
let mut current_dhcp_ip: Option<Ipv4Inet> = None;
let mut next_sleep_time = 0;
let nic_closed_notifier = Arc::new(Notify::new());
@@ -864,7 +868,11 @@ impl Instance {
used_ipv4.insert(peer_ipv4_addr.into());
}
let dhcp_inet = used_ipv4.iter().next().unwrap_or(&default_ipv4_addr);
let dhcp_inet = if global_ctx_c.config.get_dhcp_cidr().is_some() {
&default_ipv4_addr
} else {
used_ipv4.iter().next().unwrap_or(&default_ipv4_addr)
};
// if old ip is already in this subnet and not conflicted, use it
if let Some(ip) = current_dhcp_ip
&& ip.network() == dhcp_inet.network()
+6
View File
@@ -637,6 +637,11 @@ impl NetworkConfig {
);
cfg.set_hostname(self.hostname.clone());
cfg.set_dhcp(self.dhcp.unwrap_or_default());
if let Some(ref dhcp_cidr) = self.dhcp_cidr {
if let Ok(cidr) = dhcp_cidr.parse::<cidr::Ipv4Cidr>() {
cfg.set_dhcp_cidr(Some(cidr));
}
}
cfg.set_inst_name(self.network_name.clone().unwrap_or_default());
// The web UI does not expose credential inputs directly, but imported/saved
@@ -1019,6 +1024,7 @@ impl NetworkConfig {
}
result.dhcp = Some(config.get_dhcp());
result.dhcp_cidr = config.get_dhcp_cidr().map(|c| c.to_string());
let network_identity = config.get_network_identity();
result.network_name = Some(network_identity.network_name.clone());
+1
View File
@@ -102,6 +102,7 @@ message NetworkConfig {
optional bool disable_relay_data = 65;
optional bool enable_udp_broadcast_relay = 66;
optional uint32 socket_mark = 67;
optional string dhcp_cidr = 68;
}
message PortForwardConfig {