Change netcfg to adapt to the new router
This commit is contained in:
@@ -8,7 +8,7 @@ use smoltcp::storage::PacketMetadata;
|
||||
use smoltcp::time::{Duration, Instant};
|
||||
use smoltcp::wire::{
|
||||
ArpOperation, ArpPacket, ArpRepr, EthernetAddress, EthernetFrame, EthernetProtocol,
|
||||
EthernetRepr, IpAddress, Ipv4Address, Ipv4Cidr,
|
||||
EthernetRepr, IpAddress, IpCidr, Ipv4Address, Ipv4Cidr,
|
||||
};
|
||||
|
||||
use super::LinkDevice;
|
||||
@@ -31,7 +31,7 @@ enum ArpState {
|
||||
|
||||
type PacketBuffer = smoltcp::storage::PacketBuffer<'static, IpAddress>;
|
||||
|
||||
const EMPTY_MAC: EthernetAddress = EthernetAddress([0;6]);
|
||||
const EMPTY_MAC: EthernetAddress = EthernetAddress([0; 6]);
|
||||
|
||||
pub struct EthernetLink {
|
||||
name: Rc<str>,
|
||||
@@ -41,8 +41,8 @@ pub struct EthernetLink {
|
||||
input_buffer: Vec<u8>,
|
||||
output_buffer: Vec<u8>,
|
||||
network_file: File,
|
||||
hardware_address: EthernetAddress,
|
||||
ip_address: Ipv4Cidr,
|
||||
hardware_address: Option<EthernetAddress>,
|
||||
ip_address: Option<Ipv4Cidr>,
|
||||
}
|
||||
|
||||
impl EthernetLink {
|
||||
@@ -54,12 +54,7 @@ impl EthernetLink {
|
||||
const NEIGHBOR_LIVE_TIME: Duration = Duration::from_secs(60);
|
||||
const ARP_SILENCE_TIME: Duration = Duration::from_secs(1);
|
||||
|
||||
pub fn new(
|
||||
name: &str,
|
||||
network_file: File,
|
||||
hardware_address: EthernetAddress,
|
||||
ip_address: Ipv4Cidr,
|
||||
) -> Self {
|
||||
pub fn new(name: &str, network_file: File) -> Self {
|
||||
let waiting_packets = PacketBuffer::new(
|
||||
vec![PacketMetadata::EMPTY; Self::MAX_WAITING_PACKET_COUNT],
|
||||
vec![0u8; Self::WAITING_PACKET_BUFFER_SIZE],
|
||||
@@ -69,8 +64,8 @@ impl EthernetLink {
|
||||
name: name.into(),
|
||||
network_file,
|
||||
waiting_packets,
|
||||
hardware_address,
|
||||
ip_address,
|
||||
hardware_address: None,
|
||||
ip_address: None,
|
||||
input_buffer: vec![0u8; Self::MTU],
|
||||
output_buffer: Vec::with_capacity(Self::MTU),
|
||||
arp_state: Default::default(),
|
||||
@@ -82,8 +77,12 @@ impl EthernetLink {
|
||||
where
|
||||
F: FnOnce(&mut [u8]),
|
||||
{
|
||||
let Some(hardware_address) = self.hardware_address else {
|
||||
return;
|
||||
};
|
||||
|
||||
let repr = EthernetRepr {
|
||||
src_addr: self.hardware_address,
|
||||
src_addr: hardware_address,
|
||||
dst_addr: dst,
|
||||
ethertype: proto,
|
||||
};
|
||||
@@ -104,6 +103,14 @@ impl EthernetLink {
|
||||
}
|
||||
|
||||
fn process_arp(&mut self, packet: &[u8], now: Instant) {
|
||||
let Some(hardware_address) = self.hardware_address else {
|
||||
return;
|
||||
};
|
||||
|
||||
let Some(ip_addr) = self.ip_address else {
|
||||
return;
|
||||
};
|
||||
|
||||
let Ok(repr) = ArpPacket::new_checked(packet).and_then(|packet| ArpRepr::parse(&packet)) else {
|
||||
debug!("Dropped incomming arp packet on {} (Malformed)", self.name);
|
||||
return;
|
||||
@@ -117,7 +124,7 @@ impl EthernetLink {
|
||||
target_hardware_addr,
|
||||
target_protocol_addr,
|
||||
} => {
|
||||
if self.hardware_address != target_hardware_addr {
|
||||
if hardware_address != target_hardware_addr {
|
||||
// Only process packet that are for us
|
||||
return;
|
||||
}
|
||||
@@ -129,8 +136,8 @@ impl EthernetLink {
|
||||
if !source_hardware_addr.is_unicast() || !source_protocol_addr.is_unicast() {
|
||||
return;
|
||||
}
|
||||
|
||||
if !self.ip_address.contains_addr(&target_protocol_addr) {
|
||||
|
||||
if !ip_addr.contains_addr(&target_protocol_addr) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -145,8 +152,8 @@ impl EthernetLink {
|
||||
if let ArpOperation::Request = operation {
|
||||
let response = ArpRepr::EthernetIpv4 {
|
||||
operation: ArpOperation::Reply,
|
||||
source_hardware_addr: self.hardware_address,
|
||||
source_protocol_addr: self.ip_address.address(),
|
||||
source_hardware_addr: hardware_address,
|
||||
source_protocol_addr: ip_addr.address(),
|
||||
target_hardware_addr: source_hardware_addr,
|
||||
target_protocol_addr: source_protocol_addr,
|
||||
};
|
||||
@@ -246,6 +253,14 @@ impl EthernetLink {
|
||||
}
|
||||
|
||||
fn send_arp(&mut self, now: Instant) {
|
||||
let Some(hardware_address) = self.hardware_address else {
|
||||
return;
|
||||
};
|
||||
|
||||
let Some(ip_address) = self.ip_address else {
|
||||
return;
|
||||
};
|
||||
|
||||
match self.arp_state {
|
||||
ArpState::Discovered => {}
|
||||
ArpState::Discovering { silent_until, .. } if silent_until > now => {}
|
||||
@@ -259,8 +274,8 @@ impl EthernetLink {
|
||||
} => {
|
||||
let arp_repr = ArpRepr::EthernetIpv4 {
|
||||
operation: ArpOperation::Request,
|
||||
source_hardware_addr: self.hardware_address,
|
||||
source_protocol_addr: self.ip_address.address(),
|
||||
source_hardware_addr: hardware_address,
|
||||
source_protocol_addr: ip_address.address(),
|
||||
target_hardware_addr: EthernetAddress::BROADCAST,
|
||||
target_protocol_addr: target,
|
||||
};
|
||||
@@ -281,10 +296,9 @@ impl EthernetLink {
|
||||
|
||||
impl LinkDevice for EthernetLink {
|
||||
fn send(&mut self, next_hop: IpAddress, packet: &[u8], now: Instant) {
|
||||
|
||||
let local_broadcast = match self.ip_address.broadcast() {
|
||||
let local_broadcast = match self.ip_address.and_then(|cidr| cidr.broadcast()) {
|
||||
Some(addr) => IpAddress::Ipv4(addr) == next_hop,
|
||||
None => false
|
||||
None => false,
|
||||
};
|
||||
|
||||
if local_broadcast || next_hop.is_broadcast() {
|
||||
@@ -317,6 +331,10 @@ impl LinkDevice for EthernetLink {
|
||||
}
|
||||
|
||||
fn recv(&mut self, now: Instant) -> Option<&[u8]> {
|
||||
let Some(hardware_address) = self.hardware_address else {
|
||||
return None;
|
||||
};
|
||||
|
||||
let mut input_buffer = std::mem::replace(&mut self.input_buffer, Vec::new());
|
||||
loop {
|
||||
if let Err(e) = self.network_file.read(&mut input_buffer) {
|
||||
@@ -336,7 +354,10 @@ impl LinkDevice for EthernetLink {
|
||||
};
|
||||
|
||||
// We let EMPTY_MAC pass because somehow this is the mac used when net=redir is used
|
||||
if !repr.dst_addr.is_broadcast() && repr.dst_addr != EMPTY_MAC && repr.dst_addr != self.hardware_address {
|
||||
if !repr.dst_addr.is_broadcast()
|
||||
&& repr.dst_addr != EMPTY_MAC
|
||||
&& repr.dst_addr != hardware_address
|
||||
{
|
||||
// Drop packets which are not for us
|
||||
continue;
|
||||
}
|
||||
@@ -360,4 +381,21 @@ impl LinkDevice for EthernetLink {
|
||||
// We don't buffer any packets so we can't receive immediatly
|
||||
false
|
||||
}
|
||||
|
||||
fn mac_address(&self) -> Option<EthernetAddress> {
|
||||
self.hardware_address
|
||||
}
|
||||
|
||||
fn set_mac_address(&mut self, addr: EthernetAddress) {
|
||||
self.hardware_address = Some(addr)
|
||||
}
|
||||
|
||||
fn ip_address(&self) -> Option<IpCidr> {
|
||||
Some(IpCidr::Ipv4(self.ip_address?))
|
||||
}
|
||||
|
||||
fn set_ip_address(&mut self, addr: IpCidr) {
|
||||
let IpCidr::Ipv4(addr) = addr;
|
||||
self.ip_address = Some(addr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,4 +46,21 @@ impl LinkDevice for LoopbackDevice {
|
||||
fn can_recv(&self) -> bool {
|
||||
!self.buffer.is_empty()
|
||||
}
|
||||
|
||||
fn mac_address(&self) -> Option<smoltcp::wire::EthernetAddress> {
|
||||
None
|
||||
}
|
||||
|
||||
fn set_mac_address(&mut self, _addr: smoltcp::wire::EthernetAddress) {
|
||||
}
|
||||
|
||||
fn ip_address(&self) -> Option<smoltcp::wire::IpCidr> {
|
||||
Some("127.0.0.1/8".parse().unwrap())
|
||||
}
|
||||
|
||||
fn set_ip_address(&mut self, _addr: smoltcp::wire::IpCidr) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ pub mod ethernet;
|
||||
use std::rc::Rc;
|
||||
|
||||
use smoltcp::time::Instant;
|
||||
use smoltcp::wire::IpAddress;
|
||||
use smoltcp::wire::{IpAddress, EthernetAddress, IpCidr};
|
||||
|
||||
/// Represent a link layer device (eth0, loopback...)
|
||||
pub trait LinkDevice {
|
||||
@@ -24,6 +24,12 @@ pub trait LinkDevice {
|
||||
|
||||
/// Returns wether this device have packets pending
|
||||
fn can_recv(&self) -> bool;
|
||||
|
||||
fn mac_address(&self) -> Option<EthernetAddress>;
|
||||
fn set_mac_address(&mut self, addr: EthernetAddress);
|
||||
|
||||
fn ip_address(&self) -> Option<IpCidr>;
|
||||
fn set_ip_address(&mut self, addr: IpCidr);
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
|
||||
@@ -102,6 +102,7 @@ impl Router {
|
||||
|
||||
let IpAddress::Ipv4(src) = rule.src;
|
||||
if src != packet.src_addr() {
|
||||
error!("Changed packet source {} -> {}", packet.src_addr(), src);
|
||||
packet.set_src_addr(src);
|
||||
packet.fill_checksum()
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use std::fmt::Display;
|
||||
use std::rc::Rc;
|
||||
|
||||
use smoltcp::wire::{IpAddress, IpCidr};
|
||||
@@ -21,6 +22,25 @@ impl Rule {
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Rule {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
if self.filter.prefix_len() == 0 {
|
||||
write!(f, "default")?;
|
||||
} else {
|
||||
write!(f, "{} ", self.filter)?;
|
||||
}
|
||||
|
||||
if let Some(via) = self.via {
|
||||
write!(f, " via {}", via)?;
|
||||
}
|
||||
|
||||
write!(f, " dev {}", self.dev)?;
|
||||
write!(f, " src {}", self.src)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct RouteTable {
|
||||
rules: Vec<Rule>,
|
||||
@@ -42,6 +62,10 @@ impl RouteTable {
|
||||
self.lookup_rule(dst)?.via
|
||||
}
|
||||
|
||||
pub fn lookup_device(&self, dst: &IpAddress) -> Option<Rc<str>> {
|
||||
Some(self.lookup_rule(dst)?.dev.clone())
|
||||
}
|
||||
|
||||
pub fn insert_rule(&mut self, new_rule: Rule) {
|
||||
let i = match self
|
||||
.rules
|
||||
@@ -52,4 +76,24 @@ impl RouteTable {
|
||||
};
|
||||
self.rules.insert(i, new_rule);
|
||||
}
|
||||
|
||||
pub fn remove_rule(&mut self, filter: IpCidr) {
|
||||
self.rules.retain(|rule| rule.filter != filter);
|
||||
}
|
||||
|
||||
pub fn change_src(&mut self, old_src: IpAddress, new_src: IpAddress) {
|
||||
for rule in self.rules.iter_mut().filter(|rule| rule.src == old_src) {
|
||||
rule.src = new_src;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for RouteTable {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
for rule in self.rules.iter() {
|
||||
writeln!(f, "{}", rule)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
+11
-24
@@ -80,10 +80,7 @@ impl Smolnetd {
|
||||
) -> Smolnetd {
|
||||
let hardware_addr = EthernetAddress::from_str(getcfg("mac").unwrap().trim())
|
||||
.expect("Can't parse the 'mac' cfg");
|
||||
let local_ip =
|
||||
IpAddress::from_str(getcfg("ip").unwrap().trim()).expect("Can't parse the 'ip' cfg.");
|
||||
let protocol_addrs = vec![
|
||||
IpCidr::new(local_ip, 24),
|
||||
IpCidr::new(IpAddress::v4(127, 0, 0, 1), 8),
|
||||
];
|
||||
|
||||
@@ -119,27 +116,12 @@ impl Smolnetd {
|
||||
"127.0.0.1".parse().unwrap(),
|
||||
));
|
||||
|
||||
let IpAddress::Ipv4(local_ip) = local_ip;
|
||||
let eth0 = EthernetLink::new(
|
||||
|
||||
let mut eth0 = EthernetLink::new(
|
||||
"eth0",
|
||||
network_file,
|
||||
hardware_addr,
|
||||
Ipv4Cidr::new(local_ip, 24),
|
||||
);
|
||||
|
||||
route_table.borrow_mut().insert_rule(Rule::new(
|
||||
IpCidr::new(IpAddress::Ipv4(local_ip), 24),
|
||||
None,
|
||||
Rc::clone(eth0.name()),
|
||||
IpAddress::Ipv4(local_ip),
|
||||
));
|
||||
|
||||
route_table.borrow_mut().insert_rule(Rule::new(
|
||||
"0.0.0.0/0".parse().unwrap(),
|
||||
Some(IpAddress::Ipv4(default_gw)),
|
||||
Rc::clone(eth0.name()),
|
||||
IpAddress::Ipv4(local_ip),
|
||||
));
|
||||
eth0.set_mac_address(hardware_addr);
|
||||
|
||||
devices.borrow_mut().push(loopback);
|
||||
devices.borrow_mut().push(eth0);
|
||||
@@ -150,7 +132,7 @@ impl Smolnetd {
|
||||
route_table: Rc::clone(&route_table),
|
||||
socket_set: Rc::clone(&socket_set),
|
||||
timer: ::std::time::Instant::now(),
|
||||
link_devices: devices,
|
||||
link_devices: Rc::clone(&devices),
|
||||
time_file,
|
||||
ip_scheme: IpScheme::new(
|
||||
Rc::clone(&iface),
|
||||
@@ -176,7 +158,12 @@ impl Smolnetd {
|
||||
Rc::clone(&socket_set),
|
||||
icmp_file,
|
||||
),
|
||||
netcfg_scheme: NetCfgScheme::new(Rc::clone(&iface), netcfg_file),
|
||||
netcfg_scheme: NetCfgScheme::new(
|
||||
Rc::clone(&iface),
|
||||
netcfg_file,
|
||||
Rc::clone(&route_table),
|
||||
Rc::clone(&devices),
|
||||
),
|
||||
input_queue,
|
||||
buffer_pool,
|
||||
}
|
||||
@@ -267,7 +254,7 @@ impl Smolnetd {
|
||||
Some(delay) => break ::std::cmp::min(MAX_DURATION, delay),
|
||||
None => break MAX_DURATION,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
+167
-162
@@ -2,24 +2,30 @@
|
||||
mod nodes;
|
||||
mod notifier;
|
||||
|
||||
use smoltcp::wire::{IpAddress, EthernetAddress, IpCidr, Ipv4Address};
|
||||
use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr, Ipv4Address, Ipv4Cidr};
|
||||
use std::cell::RefCell;
|
||||
use std::collections::BTreeMap;
|
||||
use std::fs::File;
|
||||
use std::io::{ErrorKind, Read, Write};
|
||||
use std::rc::Rc;
|
||||
use std::mem;
|
||||
use std::str::FromStr;
|
||||
use std::rc::Rc;
|
||||
use std::str;
|
||||
use std::str::FromStr;
|
||||
use syscall;
|
||||
use syscall::data::Stat;
|
||||
use syscall::flag::{MODE_DIR, MODE_FILE};
|
||||
use syscall::{Error as SyscallError, EventFlags as SyscallEventFlags, Packet as SyscallPacket, Result as SyscallResult, SchemeMut};
|
||||
use syscall;
|
||||
use syscall::{
|
||||
Error as SyscallError, EventFlags as SyscallEventFlags, Packet as SyscallPacket,
|
||||
Result as SyscallResult, SchemeMut,
|
||||
};
|
||||
|
||||
use crate::link::DeviceList;
|
||||
use crate::router::route_table::{self, RouteTable, Rule};
|
||||
|
||||
use self::nodes::*;
|
||||
use self::notifier::*;
|
||||
use redox_netstack::error::{Error, Result};
|
||||
use super::{post_fevent, Interface};
|
||||
use redox_netstack::error::{Error, Result};
|
||||
|
||||
const WRITE_BUFFER_MAX_SIZE: usize = 0xffff;
|
||||
|
||||
@@ -28,27 +34,44 @@ fn gateway_cidr() -> IpCidr {
|
||||
IpCidr::new(IpAddress::v4(0, 0, 0, 0), 0)
|
||||
}
|
||||
|
||||
fn parse_default_gw(value: &str) -> SyscallResult<Ipv4Address> {
|
||||
let mut routes = value.lines();
|
||||
if let Some(route) = routes.next() {
|
||||
if !routes.next().is_none() {
|
||||
return Err(SyscallError::new(syscall::EINVAL));
|
||||
}
|
||||
let mut words = route.split_whitespace();
|
||||
if let Some("default") = words.next() {
|
||||
if let Some("via") = words.next() {
|
||||
if let Some(ip) = words.next() {
|
||||
return Ipv4Address::from_str(ip)
|
||||
.map_err(|_| SyscallError::new(syscall::EINVAL));
|
||||
}
|
||||
}
|
||||
}
|
||||
fn parse_route(value: &str, route_table: &RouteTable) -> SyscallResult<Rule> {
|
||||
let mut parts = value.split_whitespace();
|
||||
let cidr_str = parts.next().ok_or(SyscallError::new(syscall::EINVAL))?;
|
||||
let cidr = match cidr_str {
|
||||
"default" => gateway_cidr(),
|
||||
cidr_str => cidr_str
|
||||
.parse()
|
||||
.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))?,
|
||||
_ => return Err(SyscallError::new(syscall::EINVAL)),
|
||||
};
|
||||
|
||||
if !via.is_unicast() {
|
||||
return Err(SyscallError::new(syscall::EINVAL));
|
||||
}
|
||||
Err(SyscallError::new(syscall::EINVAL))
|
||||
|
||||
let rule = route_table
|
||||
.lookup_rule(&via)
|
||||
.ok_or(SyscallError::new(syscall::EINVAL))?;
|
||||
|
||||
Ok(Rule::new(cidr, Some(via), rule.dev.clone(), rule.src))
|
||||
}
|
||||
|
||||
fn mk_root_node(iface: Interface, notifier: NotifierRef, dns_config: DNSConfigRef) -> CfgNodeRef {
|
||||
cfg_node!{
|
||||
fn mk_root_node(
|
||||
iface: Interface,
|
||||
notifier: NotifierRef,
|
||||
dns_config: DNSConfigRef,
|
||||
route_table: Rc<RefCell<RouteTable>>,
|
||||
devices: Rc<RefCell<DeviceList>>,
|
||||
) -> CfgNodeRef {
|
||||
cfg_node! {
|
||||
"resolv" => {
|
||||
"nameserver" => {
|
||||
rw [dns_config, notifier] (Option<Ipv4Address>, None)
|
||||
@@ -79,37 +102,24 @@ fn mk_root_node(iface: Interface, notifier: NotifierRef, dns_config: DNSConfigRe
|
||||
},
|
||||
"route" => {
|
||||
"list" => {
|
||||
ro [iface] || {
|
||||
let mut gateway = None;
|
||||
iface.borrow_mut().routes_mut().update(|map| {
|
||||
gateway = map.iter().find(|route| route.cidr == gateway_cidr()).map(|route| route.via_router)
|
||||
});
|
||||
if let Some(ip) = gateway {
|
||||
format!("default via {}\n", ip)
|
||||
} else {
|
||||
String::new()
|
||||
}
|
||||
ro [route_table] || {
|
||||
format!("{}", route_table.borrow())
|
||||
}
|
||||
},
|
||||
"add" => {
|
||||
wo [iface, notifier] (Option<Ipv4Address>, None)
|
||||
wo [iface, notifier, route_table] (Option<Rule>, None)
|
||||
|cur_value, line| {
|
||||
if cur_value.is_none() {
|
||||
let default_gw = parse_default_gw(line)?;
|
||||
if !default_gw.is_unicast() {
|
||||
return Err(SyscallError::new(syscall::EINVAL));
|
||||
}
|
||||
*cur_value = Some(default_gw);
|
||||
let route = parse_route(line, &route_table.borrow())?;
|
||||
*cur_value = Some(route);
|
||||
Ok(())
|
||||
} else {
|
||||
Err(SyscallError::new(syscall::EINVAL))
|
||||
}
|
||||
}
|
||||
|cur_value| {
|
||||
if let Some(default_gw) = *cur_value {
|
||||
if iface.borrow_mut().routes_mut().add_default_ipv4_route(default_gw).is_err() {
|
||||
return Err(SyscallError::new(syscall::EINVAL));
|
||||
}
|
||||
if let Some(route) = cur_value.take() {
|
||||
route_table.borrow_mut().insert_rule(route);
|
||||
notifier.borrow_mut().schedule_notify("route/list");
|
||||
Ok(())
|
||||
} else {
|
||||
@@ -118,35 +128,25 @@ fn mk_root_node(iface: Interface, notifier: NotifierRef, dns_config: DNSConfigRe
|
||||
}
|
||||
},
|
||||
"rm" => {
|
||||
wo [iface, notifier] (Option<Ipv4Address>, None)
|
||||
wo [iface, notifier, route_table] (Option<IpCidr>, None)
|
||||
|cur_value, line| {
|
||||
if cur_value.is_none() {
|
||||
let default_gw = parse_default_gw(line)?;
|
||||
if !default_gw.is_unicast() {
|
||||
return Err(SyscallError::new(syscall::EINVAL));
|
||||
match line.parse() {
|
||||
Ok(cidr) => {
|
||||
*cur_value = Some(cidr);
|
||||
Ok(())
|
||||
}
|
||||
Err(_) => Err(SyscallError::new(syscall::EINVAL))
|
||||
}
|
||||
*cur_value = Some(default_gw);
|
||||
Ok(())
|
||||
} else {
|
||||
Err(SyscallError::new(syscall::EINVAL))
|
||||
}
|
||||
}
|
||||
|cur_value| {
|
||||
if let Some(default_gw) = *cur_value {
|
||||
let mut iface = iface.borrow_mut();
|
||||
let mut gateway = None;
|
||||
iface.routes_mut().update(|map| {
|
||||
gateway = map.iter().find(|route| route.cidr == gateway_cidr()).map(|route| route.via_router)
|
||||
});
|
||||
match gateway {
|
||||
None => Err(SyscallError::new(syscall::EINVAL)),
|
||||
Some(addr) if addr != IpAddress::Ipv4(default_gw) => Err(SyscallError::new(syscall::EINVAL)),
|
||||
Some(_) => {
|
||||
iface.routes_mut().remove_default_ipv4_route();
|
||||
notifier.borrow_mut().schedule_notify("route/list");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
if let Some(cidr) = *cur_value {
|
||||
route_table.borrow_mut().remove_rule(cidr);
|
||||
notifier.borrow_mut().schedule_notify("route/list");
|
||||
Ok(())
|
||||
} else {
|
||||
Err(SyscallError::new(syscall::EINVAL))
|
||||
}
|
||||
@@ -156,10 +156,17 @@ fn mk_root_node(iface: Interface, notifier: NotifierRef, dns_config: DNSConfigRe
|
||||
"ifaces" => {
|
||||
"eth0" => {
|
||||
"mac" => {
|
||||
rw [iface, notifier] (Option<EthernetAddress>, None)
|
||||
rw [iface, notifier, devices] (Option<EthernetAddress>, None)
|
||||
|| {
|
||||
// format!("{}\n", iface.borrow().hardware_addr())
|
||||
String::new()
|
||||
match devices.borrow().get("eth0") {
|
||||
Some(dev) => {
|
||||
match dev.mac_address() {
|
||||
Some(addr) => format!("{addr}\n"),
|
||||
None => "Not configured\n".into(),
|
||||
}
|
||||
}
|
||||
None => "Device not found\n".into(),
|
||||
}
|
||||
}
|
||||
|cur_value, line| {
|
||||
if cur_value.is_none() {
|
||||
@@ -176,96 +183,76 @@ fn mk_root_node(iface: Interface, notifier: NotifierRef, dns_config: DNSConfigRe
|
||||
}
|
||||
|cur_value| {
|
||||
if let Some(mac) = *cur_value {
|
||||
// iface.borrow_mut().set_hardware_addr(smoltcp::wire::HardwareAddress::Ethernet(mac));
|
||||
notifier.borrow_mut().schedule_notify("ifaces/eth0/mac");
|
||||
if let Some(dev) = devices.borrow_mut().get_mut("eth0") {
|
||||
dev.set_mac_address(mac);
|
||||
notifier.borrow_mut().schedule_notify("ifaces/eth0/mac");
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
},
|
||||
"addr" => {
|
||||
"list" => {
|
||||
ro [iface]
|
||||
ro [devices]
|
||||
|| {
|
||||
let mut ips = String::new();
|
||||
for cidr in iface.borrow().ip_addrs() {
|
||||
ips += &format!("{}\n", cidr);
|
||||
}
|
||||
ips
|
||||
let res = match devices.borrow().get("eth0") {
|
||||
Some(dev) => {
|
||||
match dev.ip_address() {
|
||||
Some(addr) => format!("{addr}\n"),
|
||||
None => "Not configured\n".into(),
|
||||
}
|
||||
}
|
||||
None => "Device not found\n".into(),
|
||||
};
|
||||
res
|
||||
}
|
||||
},
|
||||
"set" => {
|
||||
wo [iface, notifier] (Vec<IpCidr>, Vec::new())
|
||||
wo [iface, notifier, devices, route_table] (Option<IpCidr>, None)
|
||||
|cur_value, line| {
|
||||
let cidr = IpCidr::from_str(line)
|
||||
.map_err(|_| SyscallError::new(syscall::EINVAL))?;
|
||||
if !cidr.address().is_unicast() {
|
||||
return Err(SyscallError::new(syscall::EINVAL));
|
||||
}
|
||||
cur_value.push(cidr);
|
||||
Ok(())
|
||||
}
|
||||
|cur_value| {
|
||||
if !cur_value.is_empty() {
|
||||
let mut iface = iface.borrow_mut();
|
||||
let mut cidrs = vec![];
|
||||
mem::swap(cur_value, &mut cidrs);
|
||||
iface.update_ip_addrs(|s| {
|
||||
*s = cidrs.into_iter().collect();
|
||||
});
|
||||
notifier.borrow_mut().schedule_notify("ifaces/eth0/addr/list");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
},
|
||||
"add" => {
|
||||
wo [iface, notifier] (Vec<IpCidr>, Vec::new())
|
||||
|cur_value, line| {
|
||||
let cidr = IpCidr::from_str(line)
|
||||
.map_err(|_| SyscallError::new(syscall::EINVAL))?;
|
||||
if !cidr.address().is_unicast() {
|
||||
return Err(SyscallError::new(syscall::EINVAL));
|
||||
}
|
||||
cur_value.push(cidr);
|
||||
Ok(())
|
||||
}
|
||||
|cur_value| {
|
||||
let mut iface = iface.borrow_mut();
|
||||
let mut cidrs = iface.ip_addrs().to_vec();
|
||||
for cidr in cur_value {
|
||||
cidrs.insert(0, *cidr);
|
||||
}
|
||||
iface.update_ip_addrs(|s| {
|
||||
*s = cidrs.into_iter().collect();
|
||||
});
|
||||
notifier.borrow_mut().schedule_notify("ifaces/eth0/addr/list");
|
||||
Ok(())
|
||||
}
|
||||
},
|
||||
"rm" => {
|
||||
wo [iface, notifier] (Vec<IpCidr>, Vec::new())
|
||||
|cur_value, line| {
|
||||
let cidr = IpCidr::from_str(line)
|
||||
.map_err(|_| SyscallError::new(syscall::EINVAL))?;
|
||||
if !cidr.address().is_unicast() {
|
||||
return Err(SyscallError::new(syscall::EINVAL));
|
||||
}
|
||||
cur_value.push(cidr);
|
||||
Ok(())
|
||||
}
|
||||
|cur_value| {
|
||||
let mut iface = iface.borrow_mut();
|
||||
let mut cidrs = iface.ip_addrs().to_vec();
|
||||
for cidr in cur_value {
|
||||
let pre_retain_len = cidrs.len();
|
||||
cidrs.retain(|&c| c != *cidr);
|
||||
if pre_retain_len == cidrs.len() {
|
||||
if cur_value.is_none() {
|
||||
let cidr = IpCidr::from_str(line)
|
||||
.map_err(|_| SyscallError::new(syscall::EINVAL))?;
|
||||
if !cidr.address().is_unicast() {
|
||||
return Err(SyscallError::new(syscall::EINVAL));
|
||||
}
|
||||
*cur_value = Some(cidr);
|
||||
Ok(())
|
||||
} else {
|
||||
Err(SyscallError::new(syscall::EINVAL))
|
||||
}
|
||||
}
|
||||
|cur_value| {
|
||||
// TODO: Multiple IPs
|
||||
if let Some(cidr) = cur_value.take() {
|
||||
if let Some(dev) = devices.borrow_mut().get_mut("eth0") {
|
||||
|
||||
let mut route_table = route_table.borrow_mut();
|
||||
if let Some(old_addr) = dev.ip_address() {
|
||||
let IpCidr::Ipv4(old_v4_cidr) = old_addr;
|
||||
let old_network = IpCidr::Ipv4(old_v4_cidr.network());
|
||||
|
||||
route_table.remove_rule(old_network);
|
||||
route_table.change_src(old_addr.address(), cidr.address());
|
||||
iface.borrow_mut().update_ip_addrs(|addrs| addrs.retain(|addr| *addr != old_addr))
|
||||
}
|
||||
|
||||
dev.set_ip_address(cidr);
|
||||
// FIXME: Here, the insert 0 is a workaround to let UDP sockets
|
||||
// work with this interface only.
|
||||
// Smoltcp takes the first ip address when looking for a source
|
||||
// ip address when sending UDP packets.
|
||||
// This behavior will have to be fixed as it's our route table
|
||||
// job to find give this source.
|
||||
iface.borrow_mut().update_ip_addrs(|addrs| addrs.insert(0, cidr).unwrap());
|
||||
|
||||
let IpCidr::Ipv4(v4_cidr) = cidr;
|
||||
let network_cidr = IpCidr::Ipv4(v4_cidr.network());
|
||||
route_table.insert_rule(Rule::new(network_cidr, None, dev.name().clone(), cidr.address()))
|
||||
}
|
||||
notifier.borrow_mut().schedule_notify("ifaces/eth0/addr/list");
|
||||
notifier.borrow_mut().schedule_notify("route/list");
|
||||
}
|
||||
iface.update_ip_addrs(|s| {
|
||||
*s = cidrs.into_iter().collect();
|
||||
});
|
||||
notifier.borrow_mut().schedule_notify("ifaces/eth0/addr/list");
|
||||
Ok(())
|
||||
}
|
||||
},
|
||||
@@ -347,7 +334,12 @@ pub struct NetCfgScheme {
|
||||
}
|
||||
|
||||
impl NetCfgScheme {
|
||||
pub fn new(iface: Interface, scheme_file: File) -> NetCfgScheme {
|
||||
pub fn new(
|
||||
iface: Interface,
|
||||
scheme_file: File,
|
||||
route_table: Rc<RefCell<RouteTable>>,
|
||||
devices: Rc<RefCell<DeviceList>>,
|
||||
) -> NetCfgScheme {
|
||||
let notifier = Notifier::new_ref();
|
||||
let dns_config = Rc::new(RefCell::new(DNSConfig {
|
||||
name_server: Ipv4Address::new(8, 8, 8, 8),
|
||||
@@ -356,7 +348,13 @@ impl NetCfgScheme {
|
||||
scheme_file,
|
||||
next_fd: 1,
|
||||
files: BTreeMap::new(),
|
||||
root_node: mk_root_node(iface, Rc::clone(¬ifier), dns_config),
|
||||
root_node: mk_root_node(
|
||||
iface,
|
||||
Rc::clone(¬ifier),
|
||||
dns_config,
|
||||
route_table,
|
||||
devices,
|
||||
),
|
||||
notifier,
|
||||
}
|
||||
}
|
||||
@@ -368,12 +366,14 @@ impl NetCfgScheme {
|
||||
Ok(0) => {
|
||||
//TODO: Cleanup must occur
|
||||
break Some(());
|
||||
},
|
||||
}
|
||||
Ok(_) => (),
|
||||
Err(err) => if err.kind() == ErrorKind::WouldBlock {
|
||||
break None;
|
||||
} else {
|
||||
return Err(Error::from(err));
|
||||
Err(err) => {
|
||||
if err.kind() == ErrorKind::WouldBlock {
|
||||
break None;
|
||||
} else {
|
||||
return Err(Error::from(err));
|
||||
}
|
||||
}
|
||||
}
|
||||
self.handle(&mut packet);
|
||||
@@ -416,7 +416,11 @@ impl SchemeMut for NetCfgScheme {
|
||||
is_dir: current_node.is_dir(),
|
||||
is_writable: current_node.is_writable(),
|
||||
is_readable: current_node.is_readable(),
|
||||
node_writer: if current_node.is_writable() { current_node.new_writer() } else { None },
|
||||
node_writer: if current_node.is_writable() {
|
||||
current_node.new_writer()
|
||||
} else {
|
||||
None
|
||||
},
|
||||
uid,
|
||||
pos: 0,
|
||||
read_buf,
|
||||
@@ -442,7 +446,8 @@ impl SchemeMut for NetCfgScheme {
|
||||
}
|
||||
|
||||
fn write(&mut self, fd: usize, buf: &[u8]) -> SyscallResult<usize> {
|
||||
let file = self.files
|
||||
let file = self
|
||||
.files
|
||||
.get_mut(&fd)
|
||||
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
|
||||
|
||||
@@ -470,7 +475,8 @@ impl SchemeMut for NetCfgScheme {
|
||||
}
|
||||
|
||||
fn read(&mut self, fd: usize, buf: &mut [u8]) -> SyscallResult<usize> {
|
||||
let file = self.files
|
||||
let file = self
|
||||
.files
|
||||
.get_mut(&fd)
|
||||
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
|
||||
|
||||
@@ -484,15 +490,12 @@ impl SchemeMut for NetCfgScheme {
|
||||
}
|
||||
|
||||
fn fstat(&mut self, fd: usize, stat: &mut Stat) -> SyscallResult<usize> {
|
||||
let file = self.files
|
||||
let file = self
|
||||
.files
|
||||
.get_mut(&fd)
|
||||
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
|
||||
|
||||
stat.st_mode = if file.is_dir {
|
||||
MODE_DIR
|
||||
} else {
|
||||
MODE_FILE
|
||||
};
|
||||
stat.st_mode = if file.is_dir { MODE_DIR } else { MODE_FILE };
|
||||
if file.is_writable {
|
||||
stat.st_mode |= 0o222;
|
||||
}
|
||||
@@ -507,7 +510,8 @@ impl SchemeMut for NetCfgScheme {
|
||||
}
|
||||
|
||||
fn fevent(&mut self, fd: usize, events: SyscallEventFlags) -> SyscallResult<SyscallEventFlags> {
|
||||
let file = self.files
|
||||
let file = self
|
||||
.files
|
||||
.get_mut(&fd)
|
||||
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
|
||||
if events.contains(syscall::EVENT_READ) {
|
||||
@@ -519,7 +523,8 @@ impl SchemeMut for NetCfgScheme {
|
||||
}
|
||||
|
||||
fn fsync(&mut self, fd: usize) -> SyscallResult<usize> {
|
||||
let file = self.files
|
||||
let file = self
|
||||
.files
|
||||
.get_mut(&fd)
|
||||
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user