diff --git a/netstack/src/scheme/netcfg/mod.rs b/netstack/src/scheme/netcfg/mod.rs index b381d1be1c..168d7b1016 100644 --- a/netstack/src/scheme/netcfg/mod.rs +++ b/netstack/src/scheme/netcfg/mod.rs @@ -75,23 +75,41 @@ fn parse_route(value: &str, route_table: &RouteTable) -> SyscallResult { .map_err(|_| SyscallError::new(syscall::EINVAL))?, }; - let via: IpAddress = match parts.next().ok_or(SyscallError::new(syscall::EINVAL))? { - "via" => parts - .next() - .ok_or(SyscallError::new(syscall::EINVAL))? - .parse() - .map_err(|_| SyscallError::new(syscall::EINVAL))?, + let dev; + let via; + let src; + + // Accept "via " or "dev " or both. + match parts.next() { + Some("via") => { + let gw: IpAddress = parts + .next() + .ok_or(SyscallError::new(syscall::EINVAL))? + .parse() + .map_err(|_| SyscallError::new(syscall::EINVAL))?; + if !gw.is_unicast() { + return Err(SyscallError::new(syscall::EINVAL)); + } + let rule = route_table + .lookup_rule(&gw) + .ok_or(SyscallError::new(syscall::EINVAL))?; + via = Some(gw); + dev = rule.dev.clone(); + src = rule.src; + } + Some("dev") => { + dev = parts + .next() + .ok_or(SyscallError::new(syscall::EINVAL))? + .into(); + via = None; + // Use 0.0.0.0 as source for direct routes — the routing + // layer will pick the correct source IP when sending. + src = IpAddress::v4(0, 0, 0, 0); + } _ => return Err(SyscallError::new(syscall::EINVAL)), }; - if !via.is_unicast() { - return Err(SyscallError::new(syscall::EINVAL)); - } - - let rule = route_table - .lookup_rule(&via) - .ok_or(SyscallError::new(syscall::EINVAL))?; - let mut metric: u32 = 0; if let Some(keyword) = parts.next() { if keyword == "metric" { @@ -105,7 +123,7 @@ fn parse_route(value: &str, route_table: &RouteTable) -> SyscallResult { } } - Ok(Rule::new(cidr, Some(via), rule.dev.clone(), rule.src).with_metric(metric)) + Ok(Rule::new(cidr, via, dev, src).with_metric(metric)) } fn mk_root_node(