dhcpv4_server/
main.rs

1// Copyright 2018 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use anyhow::{Context as _, Error};
6use dhcpv4::configuration;
7use dhcpv4::protocol::{CLIENT_PORT, Message, SERVER_PORT};
8use dhcpv4::server::{
9    DEFAULT_STASH_ID, DataStore, ResponseTarget, Server, ServerAction, ServerDispatcher,
10    ServerError,
11};
12use dhcpv4::stash::Stash;
13use fuchsia_async::net::UdpSocket;
14use fuchsia_async::{self as fasync};
15use fuchsia_component::server::{ServiceFs, ServiceFsDir};
16use futures::{Future, SinkExt as _, StreamExt as _, TryFutureExt as _, TryStreamExt as _};
17use log::{debug, error, info, warn};
18use net_declare::net::prefix_length_v4;
19use net_types::ethernet::Mac;
20use packet::Serializer;
21use packet::serialize::InnerPacketBuilder;
22use packet_formats::ipv4::Ipv4PacketBuilder;
23use packet_formats::udp::UdpPacketBuilder;
24use sockaddr::IntoSockAddr as _;
25use std::cell::RefCell;
26use std::collections::HashMap;
27use std::convert::{Infallible, TryInto as _};
28use std::net::{IpAddr, Ipv4Addr, SocketAddr};
29
30/// A buffer size in excess of the maximum allowable DHCP message size.
31const BUF_SZ: usize = 1024;
32
33enum IncomingService {
34    Server(fidl_fuchsia_net_dhcp::Server_RequestStream),
35}
36
37const DEFAULT_LEASE_DURATION_SECONDS: u32 = 24 * 60 * 60;
38
39fn default_parameters() -> configuration::ServerParameters {
40    configuration::ServerParameters {
41        server_ips: vec![],
42        lease_length: dhcpv4::configuration::LeaseLength {
43            default_seconds: DEFAULT_LEASE_DURATION_SECONDS,
44            max_seconds: DEFAULT_LEASE_DURATION_SECONDS,
45        },
46        managed_addrs: dhcpv4::configuration::ManagedAddresses {
47            mask: configuration::SubnetMask::new(prefix_length_v4!(0)),
48            pool_range_start: Ipv4Addr::UNSPECIFIED,
49            pool_range_stop: Ipv4Addr::UNSPECIFIED,
50        },
51        permitted_macs: dhcpv4::configuration::PermittedMacs(vec![]),
52        static_assignments: dhcpv4::configuration::StaticAssignments(
53            std::collections::hash_map::HashMap::new(),
54        ),
55        arp_probe: false,
56        bound_device_names: vec![],
57    }
58}
59
60/// dhcpd is the Fuchsia DHCPv4 server.
61#[derive(argh::FromArgs)]
62struct Args {
63    /// enables storage of dhcpd lease and configuration state to persistent storage
64    #[argh(switch)]
65    persistent: bool,
66}
67
68#[fuchsia::main()]
69pub async fn main() -> Result<(), Error> {
70    info!("starting");
71
72    let Args { persistent } = argh::from_env();
73    info!("persistent={}", persistent);
74    if persistent {
75        let stash = Stash::new(DEFAULT_STASH_ID).context("failed to instantiate stash")?;
76        // The server parameters and the client records must be consistent with one another in
77        // order to ensure correct server operation. The records cannot be consistent with default
78        // parameters, so if parameters fail to load from the stash, then the records should
79        // default to empty.
80        let (params, options, records) = match stash.load_parameters().await {
81            Ok(params) => {
82                let options = stash.load_options().await.unwrap_or_else(|e| {
83                    warn!("failed to load options from stash: {:?}", e);
84                    HashMap::new()
85                });
86                let records = stash.load_client_records().await.unwrap_or_else(|e| {
87                    warn!("failed to load client records from stash: {:?}", e);
88                    HashMap::new()
89                });
90                (params, options, records)
91            }
92            Err(e) => {
93                warn!("failed to load parameters from stash: {:?}", e);
94                (default_parameters(), HashMap::new(), HashMap::new())
95            }
96        };
97        let server = match Server::new_from_state(stash.clone(), params, options, records) {
98            Ok(v) => v,
99            Err(e) => {
100                warn!("failed to create server from persistent state: {}", e);
101                Server::new(Some(stash), default_parameters())
102            }
103        };
104        Ok(run(server).await?)
105    } else {
106        Ok(run(Server::<Stash>::new(None, default_parameters())).await?)
107    }
108}
109
110async fn run<DS: DataStore>(server: Server<DS>) -> Result<(), Error> {
111    let server = RefCell::new(ServerDispatcherRuntime::new(server));
112
113    let mut fs = ServiceFs::new_local();
114    let _: &mut ServiceFsDir<'_, _> = fs.dir("svc").add_fidl_service(IncomingService::Server);
115    let _: &mut ServiceFs<_> = fs
116        .take_and_serve_directory_handle()
117        .context("service fs failed to take and serve directory handle")?;
118
119    let (mut socket_sink, socket_stream) =
120        futures::channel::mpsc::channel::<ServerSocketCollection<UdpSocket>>(1);
121
122    // Attempt to enable the server on startup.
123    // NOTE(brunodalbo): Enabling the server on startup should be an explicit
124    // configuration loaded from default configs and stash. For now, just mimic
125    // existing behavior and try to enable. It'll fail if we don't have a valid
126    // configuration from stash/config.
127    match server.borrow_mut().enable() {
128        Ok(None) => unreachable!("server can't be enabled already"),
129        Ok(Some(socket_collection)) => {
130            // Sending here should never fail; we just created the stream above.
131            let () = socket_sink.try_send(socket_collection)?;
132        }
133        Err(e @ zx::Status::INVALID_ARGS) => {
134            info!("server not configured for serving leases: {:?}", e)
135        }
136        Err(e) => warn!("could not enable server on startup: {:?}", e),
137    }
138
139    let admin_fut =
140        fs.then(futures::future::ok).try_for_each_concurrent(None, |incoming_service| async {
141            match incoming_service {
142                IncomingService::Server(stream) => {
143                    run_server(stream, &server, &default_parameters(), socket_sink.clone())
144                        .inspect_err(|e| warn!("run_server failed: {:?}", e))
145                        .await?;
146                    Ok(())
147                }
148            }
149        });
150
151    let server_fut = define_running_server_fut(&server, socket_stream);
152
153    info!("running");
154    let ((), ()) = futures::try_join!(server_fut, admin_fut)?;
155
156    Ok(())
157}
158
159trait SocketServerDispatcher: ServerDispatcher {
160    type Socket;
161
162    fn create_socket(name: &str, src: Ipv4Addr) -> std::io::Result<Self::Socket>;
163    fn dispatch_message(&mut self, msg: Message) -> Result<ServerAction, ServerError>;
164    fn create_sockets(
165        params: &configuration::ServerParameters,
166    ) -> std::io::Result<Vec<SocketWithId<Self::Socket>>>;
167}
168
169impl<DS: DataStore> SocketServerDispatcher for Server<DS> {
170    type Socket = UdpSocket;
171
172    fn create_socket(name: &str, src: Ipv4Addr) -> std::io::Result<Self::Socket> {
173        let socket = socket2::Socket::new(
174            socket2::Domain::IPV4,
175            socket2::Type::DGRAM,
176            Some(socket2::Protocol::UDP),
177        )?;
178        // Since dhcpd may listen to multiple interfaces, we must enable
179        // SO_REUSEPORT so that binding the same (address, port) pair to each
180        // interface can still succeed.
181        let () = socket.set_reuse_port(true)?;
182        let () = socket.bind_device(Some(name.as_bytes()))?;
183        info!("socket bound to device {}", name);
184        let () = socket.set_broadcast(true)?;
185        let () = socket.bind(&SocketAddr::new(IpAddr::V4(src), SERVER_PORT.into()).into())?;
186        Ok(UdpSocket::from_socket(socket.into())?)
187    }
188
189    fn dispatch_message(&mut self, msg: Message) -> Result<ServerAction, ServerError> {
190        self.dispatch(msg)
191    }
192
193    fn create_sockets(
194        params: &configuration::ServerParameters,
195    ) -> std::io::Result<Vec<SocketWithId<Self::Socket>>> {
196        let configuration::ServerParameters { bound_device_names, .. } = params;
197        bound_device_names
198            .iter()
199            .map(|name| {
200                let iface_id =
201                    fuchsia_nix::net::if_::if_nametoindex(name.as_str()).map_err(|e| {
202                        let e: std::io::Error = e.into();
203                        e
204                    })?;
205                let socket = Self::create_socket(name, Ipv4Addr::UNSPECIFIED)?;
206                Ok(SocketWithId { socket, iface_id: iface_id.into() })
207            })
208            .collect()
209    }
210}
211
212/// A wrapper around a [`ServerDispatcher`] that keeps information about the
213/// server status through a [`futures::future::AbortHandle`].
214struct ServerDispatcherRuntime<S> {
215    abort_handle: Option<futures::future::AbortHandle>,
216    server: S,
217}
218
219impl<S> std::ops::Deref for ServerDispatcherRuntime<S> {
220    type Target = S;
221
222    fn deref(&self) -> &Self::Target {
223        &self.server
224    }
225}
226
227impl<S> std::ops::DerefMut for ServerDispatcherRuntime<S> {
228    fn deref_mut(&mut self) -> &mut Self::Target {
229        &mut self.server
230    }
231}
232
233impl<S: SocketServerDispatcher> ServerDispatcherRuntime<S> {
234    /// Creates a new runtime with `server`.
235    fn new(server: S) -> Self {
236        Self { abort_handle: None, server }
237    }
238
239    /// Disables the server.
240    ///
241    /// `disable` will cancel the previous
242    /// [`futures::future::AbortRegistration`] returned by `enable`.
243    ///
244    /// If the server is already disabled, `disable` is a no-op.
245    fn disable(&mut self) {
246        if let Some(abort_handle) = self.abort_handle.take() {
247            let () = abort_handle.abort();
248        }
249    }
250
251    /// Enables the server.
252    ///
253    /// Attempts to enable the server, returning a new
254    /// [`ServerSocketCollection`] on success. The returned collection contains
255    /// the list of sockets where the server can listen on and an abort
256    /// registration that is used to cancel the future that listen on the
257    /// sockets when [`ServerDispatcherRuntime::disable`] is called.
258    ///
259    /// Returns an error if the server couldn't be started or if the closure
260    /// fails, maintaining the server in the disabled state.
261    ///
262    /// If the server is already enabled, `enable` returns `Ok(None)`.
263    fn enable(&mut self) -> Result<Option<ServerSocketCollection<S::Socket>>, zx::Status> {
264        if self.abort_handle.is_some() {
265            // Server already running.
266            return Ok(None);
267        }
268        let params = self.server.try_validate_parameters()?;
269        // Provide the closure with an AbortRegistration and a ref to
270        // parameters.
271        let (abort_handle, abort_registration) = futures::future::AbortHandle::new_pair();
272
273        let sockets = S::create_sockets(params).map_err(|e| {
274            let () = match e.raw_os_error() {
275                // A short-lived SoftAP interface may be, and frequently is, torn down prior to the
276                // full instantiation of its associated dhcpd component. Consequently, binding to
277                // the SoftAP interface name will fail with ENODEV. However, such a failure is
278                // normal and expected under those circumstances.
279                Some(libc::ENODEV) => {
280                    warn!("Failed to create server sockets: {}", e)
281                }
282                Some(_) | None => error!("Failed to create server sockets: {}", e),
283            };
284            zx::Status::IO
285        })?;
286        if sockets.is_empty() {
287            error!("No sockets to run server on");
288            return Err(zx::Status::INVALID_ARGS);
289        }
290        self.abort_handle = Some(abort_handle);
291        Ok(Some(ServerSocketCollection { sockets, abort_registration }))
292    }
293
294    /// Returns `true` if the server is enabled.
295    fn enabled(&self) -> bool {
296        self.abort_handle.is_some()
297    }
298
299    /// Runs the closure `f` only if the server is currently disabled.
300    ///
301    /// Returns `BAD_STATE` error otherwise.
302    fn if_disabled<R, F: FnOnce(&mut S) -> Result<R, zx::Status>>(
303        &mut self,
304        f: F,
305    ) -> Result<R, zx::Status> {
306        if self.abort_handle.is_none() { f(&mut self.server) } else { Err(zx::Status::BAD_STATE) }
307    }
308}
309
310#[derive(Debug, PartialEq)]
311struct SocketWithId<S> {
312    socket: S,
313    iface_id: u64,
314}
315
316/// Helper struct to handle buffer data from sockets.
317struct MessageHandler<'a, S: SocketServerDispatcher> {
318    server: &'a RefCell<ServerDispatcherRuntime<S>>,
319}
320
321impl<'a, S: SocketServerDispatcher> MessageHandler<'a, S> {
322    /// Creates a new `MessageHandler` for `server`.
323    fn new(server: &'a RefCell<ServerDispatcherRuntime<S>>) -> Self {
324        Self { server }
325    }
326
327    /// Handles `buf` from `sender`.
328    ///
329    /// Returns `Ok(Some(sock, msg, dst))` if `msg` must be sent to `dst`
330    /// over `sock`.
331    ///
332    /// Returns `Ok(None)` if no action is required and the handler is ready to
333    /// receive more messages.
334    ///
335    /// Returns `Err` if an unrecoverable error occurs and the server must stop
336    /// serving.
337    fn handle_from_sender(
338        &mut self,
339        buf: &[u8],
340        mut sender: std::net::SocketAddrV4,
341    ) -> Result<Option<(std::net::SocketAddrV4, Message, Option<Mac>)>, Error> {
342        let msg = match Message::from_buffer(buf) {
343            Ok(msg) => {
344                debug!("parsed message from {}: {:?}", sender, msg);
345                msg
346            }
347            Err(e) => {
348                warn!("failed to parse message from {}: {}", sender, e);
349                return Ok(None);
350            }
351        };
352
353        let typ = msg.get_dhcp_type();
354        if sender.ip().is_unspecified() {
355            info!("processing {:?} from {}", typ, msg.chaddr);
356        } else {
357            info!("processing {:?} from {}", typ, sender);
358        }
359
360        // This call should not block because the server is single-threaded.
361        let result = self.server.borrow_mut().dispatch_message(msg);
362        match result {
363            Err(e) => {
364                warn!("error processing client message: {:?}", e);
365                Ok(None)
366            }
367            Ok(ServerAction::AddressRelease(addr)) => {
368                info!("released address: {}", addr);
369                Ok(None)
370            }
371            Ok(ServerAction::AddressDecline(addr)) => {
372                info!("allocated address: {}", addr);
373                Ok(None)
374            }
375            Ok(ServerAction::SendResponse(message, dst)) => {
376                debug!("generated response: {:?}", message);
377
378                let typ = message.get_dhcp_type();
379                // Check if server returned an explicit destination ip.
380                let (addr, chaddr) = match dst {
381                    ResponseTarget::Broadcast => {
382                        info!("sending {:?} to {}", typ, Ipv4Addr::BROADCAST);
383                        (Ipv4Addr::BROADCAST, None)
384                    }
385                    ResponseTarget::Unicast(addr, None) => {
386                        info!("sending {:?} to {}", typ, addr);
387                        (addr, None)
388                    }
389                    ResponseTarget::Unicast(addr, Some(chaddr)) => {
390                        info!("sending {:?} to ip {} chaddr {}", typ, addr, chaddr);
391                        (addr, Some(chaddr))
392                    }
393                };
394                sender.set_ip(addr);
395                Ok(Some((sender, message, chaddr)))
396            }
397        }
398    }
399}
400
401async fn define_msg_handling_loop_future<DS: DataStore>(
402    sock: SocketWithId<<Server<DS> as SocketServerDispatcher>::Socket>,
403    server: &RefCell<ServerDispatcherRuntime<Server<DS>>>,
404) -> Result<Infallible, Error> {
405    let SocketWithId { socket, iface_id } = sock;
406    let mut handler = MessageHandler::new(server);
407    let mut buf = vec![0u8; BUF_SZ];
408    loop {
409        let (received, sender) =
410            socket.recv_from(&mut buf).await.context("failed to read from socket")?;
411        let sender = match sender {
412            std::net::SocketAddr::V4(sender) => sender,
413            std::net::SocketAddr::V6(sender) => {
414                return Err(anyhow::anyhow!(
415                    "IPv4 socket received datagram from IPv6 sender: {}",
416                    sender
417                ));
418            }
419        };
420        if let Some((dst, msg, chaddr)) = handler
421            .handle_from_sender(&buf[..received], sender)
422            .context("failed to handle buffer")?
423        {
424            let chaddr = if let Some(chaddr) = chaddr {
425                chaddr
426            } else {
427                let response = msg.serialize();
428                let sent = socket
429                    .send_to(&response, SocketAddr::V4(dst))
430                    .await
431                    .context("unable to send response")?;
432                if sent != response.len() {
433                    return Err(anyhow::anyhow!(
434                        "sent {} bytes for a message of size {}",
435                        sent,
436                        response.len()
437                    ));
438                }
439                info!("response sent to {}: {} bytes", dst, sent);
440                continue;
441            };
442            // Packet sockets are necessary here because the on-device Netstack does
443            // not yet have a relation linking the `chaddr` MAC address to an IP address.
444            let dst_ip: net_types::ip::Ipv4Addr = (*dst.ip()).into();
445            // Prefer the ServerIdentifier if set; otherwise use the socket's local address.
446            let src_ip: net_types::ip::Ipv4Addr = msg
447                .options
448                .iter()
449                .find_map(|opt| match opt {
450                    dhcpv4::protocol::DhcpOption::ServerIdentifier(addr) => Some(addr.clone()),
451                    _ => None,
452                })
453                // TODO(https://fxbug.dev/42056628): Eliminate this panic.
454                .expect("expect server identifier is always present")
455                .into();
456            let response = msg.serialize();
457            let udp_builder = UdpPacketBuilder::new(src_ip, dst_ip, Some(SERVER_PORT), CLIENT_PORT);
458            // Use the default TTL shared across UNIX systems.
459            const TTL: u8 = 64;
460            let ipv4_builder = Ipv4PacketBuilder::new(
461                src_ip,
462                dst_ip,
463                TTL,
464                packet_formats::ip::Ipv4Proto::Proto(packet_formats::ip::IpProto::Udp),
465            );
466            let packet = response
467                .into_serializer()
468                .wrap_in(udp_builder)
469                .wrap_in(ipv4_builder)
470                .serialize_vec_outer()
471                .expect("serialize packet failed")
472                .unwrap_b();
473
474            let mut sll_addr = [0; 8];
475            (&mut sll_addr[..chaddr.bytes().len()]).copy_from_slice(&chaddr.bytes());
476            let sockaddr_ll = libc::sockaddr_ll {
477                sll_family: libc::AF_PACKET.try_into().expect("convert sll_family failed"),
478                sll_ifindex: iface_id.try_into().expect("convert sll_ifindex failed"),
479                // Network order is big endian.
480                sll_protocol: u16::try_from(libc::ETH_P_IP)
481                    .expect("convert ETH_P_IP failed")
482                    .to_be(),
483                sll_halen: chaddr.bytes().len().try_into().expect("convert chaddr size failed"),
484                sll_addr: sll_addr,
485                sll_hatype: 0,
486                sll_pkttype: 0,
487            };
488
489            // Create the packet socket without binding to a protocol so that
490            // the packet socket is not registered for RX. This desirable since
491            // the socket is only used to send packets and receiving packets
492            // on a packet socket is not free.
493            let socket = socket2::Socket::new(
494                socket2::Domain::PACKET,
495                socket2::Type::DGRAM,
496                None, /* protocol */
497            )
498            .context("create packet socket failed")?;
499
500            let socket = fasync::net::DatagramSocket::new_from_socket(socket)
501                .context("failed to wrap into fuchsia-async DatagramSocket")?;
502
503            let sent = socket
504                .send_to(packet.as_ref(), sockaddr_ll.into_sockaddr())
505                .await
506                .context("unable to send response")?;
507            if sent != packet.as_ref().len() {
508                return Err(anyhow::anyhow!(
509                    "sent {} bytes for a packet of size {}",
510                    sent,
511                    packet.as_ref().len()
512                ));
513            }
514            info!("response sent to {}: {} bytes", dst, sent);
515        }
516    }
517}
518
519fn define_running_server_fut<'a, S, DS>(
520    server: &'a RefCell<ServerDispatcherRuntime<Server<DS>>>,
521    socket_stream: S,
522) -> impl Future<Output = Result<(), Error>> + 'a
523where
524    S: futures::Stream<
525            Item = ServerSocketCollection<<Server<Stash> as SocketServerDispatcher>::Socket>,
526        > + 'static,
527    DS: DataStore,
528{
529    socket_stream.map(Ok).try_for_each(move |socket_collection| async move {
530        let ServerSocketCollection { sockets, abort_registration } = socket_collection;
531        let msg_loops = futures::future::try_join_all(
532            sockets.into_iter().map(|sock| define_msg_handling_loop_future(sock, server)),
533        );
534
535        info!("Server starting");
536        match futures::future::Abortable::new(msg_loops, abort_registration).await {
537            Ok(Ok(v)) => {
538                let _: Vec<Infallible> = v;
539                Err(anyhow::anyhow!("Server futures finished unexpectedly"))
540            }
541            Ok(Err(error)) => {
542                // There was an error handling the server sockets. Disable the
543                // server.
544                error!("Server encountered an error: {:?}. Stopping server.", error);
545                let () = server.borrow_mut().disable();
546                Ok(())
547            }
548            Err(futures::future::Aborted {}) => {
549                info!("Server stopped");
550                Ok(())
551            }
552        }
553    })
554}
555
556struct ServerSocketCollection<S> {
557    sockets: Vec<SocketWithId<S>>,
558    abort_registration: futures::future::AbortRegistration,
559}
560
561async fn run_server<S, C>(
562    stream: fidl_fuchsia_net_dhcp::Server_RequestStream,
563    server: &RefCell<ServerDispatcherRuntime<S>>,
564    default_params: &dhcpv4::configuration::ServerParameters,
565    socket_sink: C,
566) -> Result<(), fidl::Error>
567where
568    S: SocketServerDispatcher,
569    C: futures::sink::Sink<ServerSocketCollection<S::Socket>> + Unpin,
570    C::Error: std::fmt::Debug,
571{
572    stream
573        .try_fold(socket_sink, |mut socket_sink, request| async move {
574            match request {
575                fidl_fuchsia_net_dhcp::Server_Request::StartServing { responder } => {
576                    responder.send(
577                        match server.borrow_mut().enable() {
578                            Ok(Some(socket_collection)) => {
579                                socket_sink.send(socket_collection).await.map_err(|e| {
580                                    error!("Failed to send sockets to sink: {:?}", e);
581                                    // Disable the server again to keep a consistent state.
582                                    let () = server.borrow_mut().disable();
583                                    zx::Status::INTERNAL
584                                })
585                            }
586                            Ok(None) => {
587                                info!("Server already running");
588                                Ok(())
589                            }
590                            Err(status) => Err(status),
591                        }
592                        .map_err(zx::Status::into_raw),
593                    )
594                }
595                fidl_fuchsia_net_dhcp::Server_Request::StopServing { responder } => {
596                    let () = server.borrow_mut().disable();
597                    responder.send()
598                }
599                fidl_fuchsia_net_dhcp::Server_Request::IsServing { responder } => {
600                    responder.send(server.borrow().enabled())
601                }
602                fidl_fuchsia_net_dhcp::Server_Request::GetOption { code: c, responder: r } => r
603                    .send(
604                        server.borrow().dispatch_get_option(c).as_ref().map_err(|e| e.into_raw()),
605                    ),
606                fidl_fuchsia_net_dhcp::Server_Request::GetParameter { name: n, responder: r } => {
607                    let response = server.borrow().dispatch_get_parameter(n);
608                    r.send(response.as_ref().map_err(|e| e.into_raw()))
609                }
610                fidl_fuchsia_net_dhcp::Server_Request::SetOption { value: v, responder: r } => {
611                    r.send(server.borrow_mut().dispatch_set_option(v).map_err(|e| e.into_raw()))
612                }
613                fidl_fuchsia_net_dhcp::Server_Request::SetParameter { value: v, responder: r } => r
614                    .send(
615                        server
616                            .borrow_mut()
617                            .if_disabled(|s| s.dispatch_set_parameter(v))
618                            .map_err(|e| e.into_raw()),
619                    ),
620                fidl_fuchsia_net_dhcp::Server_Request::ListOptions { responder: r } => r.send(
621                    server.borrow().dispatch_list_options().as_deref().map_err(|e| e.into_raw()),
622                ),
623                fidl_fuchsia_net_dhcp::Server_Request::ListParameters { responder: r } => r.send(
624                    server.borrow().dispatch_list_parameters().as_deref().map_err(|e| e.into_raw()),
625                ),
626                fidl_fuchsia_net_dhcp::Server_Request::ResetOptions { responder: r } => {
627                    r.send(server.borrow_mut().dispatch_reset_options().map_err(|e| e.into_raw()))
628                }
629                fidl_fuchsia_net_dhcp::Server_Request::ResetParameters { responder: r } => r.send(
630                    server
631                        .borrow_mut()
632                        .if_disabled(|s| s.dispatch_reset_parameters(&default_params))
633                        .map_err(|e| e.into_raw()),
634                ),
635                fidl_fuchsia_net_dhcp::Server_Request::ClearLeases { responder: r } => r.send(
636                    server.borrow_mut().dispatch_clear_leases().map_err(zx::Status::into_raw),
637                ),
638            }
639            .map(|()| socket_sink)
640        })
641        .await
642        // Discard the socket sink.
643        .map(|_socket_sink: C| ())
644}
645
646#[cfg(test)]
647mod tests {
648    use super::*;
649    use dhcpv4::configuration::ServerParameters;
650    use fuchsia_async as fasync;
651    use futures::FutureExt;
652    use futures::sink::drain;
653    use net_declare::{fidl_ip_v4, std_ip_v4};
654
655    #[derive(Debug, Eq, PartialEq)]
656    struct CannedSocket {
657        name: String,
658        src: Ipv4Addr,
659    }
660
661    struct CannedDispatcher {
662        params: Option<ServerParameters>,
663        mock_leases: u32,
664    }
665
666    impl CannedDispatcher {
667        fn new() -> Self {
668            Self { params: None, mock_leases: 0 }
669        }
670    }
671
672    impl SocketServerDispatcher for CannedDispatcher {
673        type Socket = CannedSocket;
674
675        fn create_socket(name: &str, src: Ipv4Addr) -> std::io::Result<Self::Socket> {
676            let name = name.to_string();
677            Ok(CannedSocket { name, src })
678        }
679
680        fn dispatch_message(&mut self, mut msg: Message) -> Result<ServerAction, ServerError> {
681            msg.op = dhcpv4::protocol::OpCode::BOOTREPLY;
682            Ok(ServerAction::SendResponse(msg, ResponseTarget::Broadcast))
683        }
684
685        fn create_sockets(
686            params: &configuration::ServerParameters,
687        ) -> std::io::Result<Vec<SocketWithId<Self::Socket>>> {
688            let configuration::ServerParameters { bound_device_names, .. } = params;
689            bound_device_names
690                .iter()
691                .map(String::as_str)
692                .enumerate()
693                .map(|(iface_id, name)| {
694                    let iface_id = std::convert::TryInto::try_into(iface_id).map_err(|e| {
695                        std::io::Error::new(
696                            std::io::ErrorKind::InvalidInput,
697                            format!("interface id {} out of range: {}", iface_id, e),
698                        )
699                    })?;
700                    let socket = Self::create_socket(name, Ipv4Addr::UNSPECIFIED)?;
701                    Ok(SocketWithId { socket, iface_id })
702                })
703                .collect()
704        }
705    }
706
707    impl ServerDispatcher for CannedDispatcher {
708        fn try_validate_parameters(&self) -> Result<&ServerParameters, zx::Status> {
709            self.params.as_ref().ok_or(zx::Status::INVALID_ARGS)
710        }
711
712        fn dispatch_get_option(
713            &self,
714            _code: fidl_fuchsia_net_dhcp::OptionCode,
715        ) -> Result<fidl_fuchsia_net_dhcp::Option_, zx::Status> {
716            Ok(fidl_fuchsia_net_dhcp::Option_::SubnetMask(fidl_ip_v4!("0.0.0.0")))
717        }
718        fn dispatch_get_parameter(
719            &self,
720            _name: fidl_fuchsia_net_dhcp::ParameterName,
721        ) -> Result<fidl_fuchsia_net_dhcp::Parameter, zx::Status> {
722            Ok(fidl_fuchsia_net_dhcp::Parameter::Lease(fidl_fuchsia_net_dhcp::LeaseLength {
723                default: None,
724                max: None,
725                ..Default::default()
726            }))
727        }
728        fn dispatch_set_option(
729            &mut self,
730            _value: fidl_fuchsia_net_dhcp::Option_,
731        ) -> Result<(), zx::Status> {
732            Ok(())
733        }
734        fn dispatch_set_parameter(
735            &mut self,
736            _value: fidl_fuchsia_net_dhcp::Parameter,
737        ) -> Result<(), zx::Status> {
738            Ok(())
739        }
740        fn dispatch_list_options(&self) -> Result<Vec<fidl_fuchsia_net_dhcp::Option_>, zx::Status> {
741            Ok(vec![])
742        }
743        fn dispatch_list_parameters(
744            &self,
745        ) -> Result<Vec<fidl_fuchsia_net_dhcp::Parameter>, zx::Status> {
746            Ok(vec![])
747        }
748        fn dispatch_reset_options(&mut self) -> Result<(), zx::Status> {
749            Ok(())
750        }
751        fn dispatch_reset_parameters(
752            &mut self,
753            _defaults: &dhcpv4::configuration::ServerParameters,
754        ) -> Result<(), zx::Status> {
755            Ok(())
756        }
757        fn dispatch_clear_leases(&mut self) -> Result<(), zx::Status> {
758            self.mock_leases = 0;
759            Ok(())
760        }
761    }
762
763    const DEFAULT_DEVICE_NAME: &str = "foo13";
764
765    fn default_params() -> dhcpv4::configuration::ServerParameters {
766        dhcpv4::configuration::ServerParameters {
767            server_ips: vec![std_ip_v4!("192.168.0.1")],
768            lease_length: dhcpv4::configuration::LeaseLength {
769                default_seconds: 86400,
770                max_seconds: 86400,
771            },
772            managed_addrs: dhcpv4::configuration::ManagedAddresses {
773                mask: dhcpv4::configuration::SubnetMask::new(prefix_length_v4!(25)),
774                pool_range_start: std_ip_v4!("192.168.0.0"),
775                pool_range_stop: std_ip_v4!("192.168.0.0"),
776            },
777            permitted_macs: dhcpv4::configuration::PermittedMacs(vec![]),
778            static_assignments: dhcpv4::configuration::StaticAssignments(HashMap::new()),
779            arp_probe: false,
780            bound_device_names: vec![DEFAULT_DEVICE_NAME.to_string()],
781        }
782    }
783
784    async fn run_with_server<T, F, Fut>(f: F) -> T
785    where
786        F: Fn(fidl_fuchsia_net_dhcp::Server_Proxy) -> Fut,
787        Fut: Future<Output = T>,
788    {
789        let (proxy, stream) =
790            fidl::endpoints::create_proxy_and_stream::<fidl_fuchsia_net_dhcp::Server_Marker>();
791        let server = RefCell::new(ServerDispatcherRuntime::new(CannedDispatcher::new()));
792
793        let defaults = default_params();
794        futures::select! {
795            res = f(proxy).fuse() => res,
796            res = run_server(stream, &server, &defaults, drain()).fuse() => {
797                unreachable!("server finished before request: {:?}", res)
798            },
799        }
800    }
801
802    #[fasync::run_singlethreaded(test)]
803    async fn get_option_with_subnet_mask_returns_subnet_mask() {
804        run_with_server(|proxy| async move {
805            assert_eq!(
806                proxy
807                    .get_option(fidl_fuchsia_net_dhcp::OptionCode::SubnetMask)
808                    .await
809                    .expect("get_option failed"),
810                Ok(fidl_fuchsia_net_dhcp::Option_::SubnetMask(fidl_ip_v4!("0.0.0.0")))
811            );
812        })
813        .await
814    }
815
816    #[fasync::run_until_stalled(test)]
817    async fn get_parameter_with_lease_length_returns_lease_length() {
818        run_with_server(|proxy| async move {
819            assert_eq!(
820                proxy
821                    .get_parameter(fidl_fuchsia_net_dhcp::ParameterName::LeaseLength)
822                    .await
823                    .expect("get_parameter failed"),
824                Ok(fidl_fuchsia_net_dhcp::Parameter::Lease(fidl_fuchsia_net_dhcp::LeaseLength {
825                    default: None,
826                    max: None,
827                    ..Default::default()
828                }))
829            );
830        })
831        .await
832    }
833
834    #[fasync::run_singlethreaded(test)]
835    async fn set_option_with_subnet_mask_returns_unit() {
836        run_with_server(|proxy| async move {
837            assert_eq!(
838                proxy
839                    .set_option(&fidl_fuchsia_net_dhcp::Option_::SubnetMask(fidl_ip_v4!("0.0.0.0")))
840                    .await
841                    .expect("set_option failed"),
842                Ok(())
843            );
844        })
845        .await
846    }
847
848    #[fasync::run_singlethreaded(test)]
849    async fn set_parameter_with_lease_length_returns_unit() {
850        run_with_server(|proxy| async move {
851            assert_eq!(
852                proxy
853                    .set_parameter(&fidl_fuchsia_net_dhcp::Parameter::Lease(
854                        fidl_fuchsia_net_dhcp::LeaseLength {
855                            default: None,
856                            max: None,
857                            ..Default::default()
858                        },
859                    ))
860                    .await
861                    .expect("set_parameter failed"),
862                Ok(())
863            );
864        })
865        .await
866    }
867
868    #[fasync::run_singlethreaded(test)]
869    async fn list_options_returns_empty_vec() {
870        run_with_server(|proxy| async move {
871            assert_eq!(proxy.list_options().await.expect("list_options failed"), Ok(Vec::new()));
872        })
873        .await
874    }
875
876    #[fasync::run_singlethreaded(test)]
877    async fn list_parameters_returns_empty_vec() {
878        run_with_server(|proxy| async move {
879            assert_eq!(
880                proxy.list_parameters().await.expect("list_parameters failed"),
881                Ok(Vec::new())
882            );
883        })
884        .await
885    }
886
887    #[fasync::run_singlethreaded(test)]
888    async fn reset_options_returns_unit() {
889        run_with_server(|proxy| async move {
890            assert_eq!(proxy.reset_options().await.expect("reset_options failed"), Ok(()));
891        })
892        .await
893    }
894
895    #[fasync::run_singlethreaded(test)]
896    async fn reset_parameters_returns_unit() {
897        run_with_server(|proxy| async move {
898            assert_eq!(proxy.reset_parameters().await.expect("reset_parameters failed"), Ok(()));
899        })
900        .await
901    }
902
903    #[fasync::run_singlethreaded(test)]
904    async fn clear_leases_returns_unit() {
905        run_with_server(|proxy| async move {
906            assert_eq!(proxy.clear_leases().await.expect("clear_leases failed"), Ok(()));
907        })
908        .await
909    }
910
911    #[fasync::run_singlethreaded(test)]
912    async fn start_stop_server() {
913        let (proxy, stream) =
914            fidl::endpoints::create_proxy_and_stream::<fidl_fuchsia_net_dhcp::Server_Marker>();
915        let (socket_sink, mut socket_stream) =
916            futures::channel::mpsc::channel::<ServerSocketCollection<CannedSocket>>(1);
917
918        let server = RefCell::new(ServerDispatcherRuntime::new(CannedDispatcher::new()));
919        // Set default parameters to the server so we can create sockets.
920        server.borrow_mut().params = Some(default_params());
921
922        let defaults = default_params();
923
924        // Set mock leases that should not change when the server is disabled.
925        server.borrow_mut().mock_leases = 1;
926
927        let test_fut = async {
928            for () in std::iter::repeat(()).take(3) {
929                assert!(
930                    !proxy.is_serving().await.expect("query server status request"),
931                    "server should not be serving"
932                );
933
934                let () = proxy
935                    .start_serving()
936                    .await
937                    .expect("start_serving failed")
938                    .map_err(zx::Status::from_raw)
939                    .expect("start_serving returned an error");
940
941                let ServerSocketCollection { sockets, abort_registration } =
942                    socket_stream.next().await.expect("Socket stream ended unexpectedly");
943
944                // Assert that the sockets that would be created are correct.
945                assert_eq!(
946                    sockets,
947                    vec![SocketWithId {
948                        socket: CannedSocket {
949                            name: DEFAULT_DEVICE_NAME.to_string(),
950                            src: Ipv4Addr::UNSPECIFIED
951                        },
952                        iface_id: 0
953                    }]
954                );
955
956                // Create a dummy future that should be aborted when we disable the
957                // server.
958                let dummy_fut = futures::future::Abortable::new(
959                    futures::future::pending::<()>(),
960                    abort_registration,
961                );
962
963                assert!(
964                    proxy.is_serving().await.expect("query server status request"),
965                    "server should be serving"
966                );
967
968                let () = proxy.stop_serving().await.expect("stop_serving failed");
969
970                // Dummy future was aborted.
971                assert_eq!(dummy_fut.await, Err(futures::future::Aborted {}));
972                // Leases were not cleared.
973                assert_eq!(server.borrow().mock_leases, 1);
974
975                assert!(
976                    !proxy.is_serving().await.expect("query server status request"),
977                    "server should no longer be serving"
978                );
979            }
980        };
981
982        let () = futures::select! {
983            res = test_fut.fuse() => res,
984            res = run_server(stream, &server, &defaults, socket_sink).fuse() => {
985                unreachable!("server finished before request: {:?}", res)
986            },
987        };
988    }
989
990    #[fasync::run_singlethreaded(test)]
991    async fn start_server_fails_on_bad_params() {
992        let (proxy, stream) =
993            fidl::endpoints::create_proxy_and_stream::<fidl_fuchsia_net_dhcp::Server_Marker>();
994        let server = RefCell::new(ServerDispatcherRuntime::new(CannedDispatcher::new()));
995
996        let defaults = default_params();
997        let res = futures::select! {
998            res = proxy.start_serving().fuse() => res.expect("start_serving failed"),
999            res = run_server(stream, &server, &defaults, drain()).fuse() => {
1000                unreachable!("server finished before request: {:?}", res)
1001            },
1002        }
1003        .map_err(zx::Status::from_raw);
1004
1005        // Must have failed to start the server.
1006        assert_eq!(res, Err(zx::Status::INVALID_ARGS));
1007        // No abort handler must've been set.
1008        assert!(server.borrow().abort_handle.is_none());
1009    }
1010
1011    #[fasync::run_singlethreaded(test)]
1012    async fn start_server_fails_on_missing_interface_names() {
1013        let (proxy, stream) =
1014            fidl::endpoints::create_proxy_and_stream::<fidl_fuchsia_net_dhcp::Server_Marker>();
1015        let server = RefCell::new(ServerDispatcherRuntime::new(CannedDispatcher::new()));
1016
1017        let defaults = dhcpv4::configuration::ServerParameters {
1018            bound_device_names: Vec::new(),
1019            ..default_params()
1020        };
1021        server.borrow_mut().params = Some(defaults.clone());
1022
1023        let res = futures::select! {
1024            res = proxy.start_serving().fuse() => res.expect("start_serving failed"),
1025            res = run_server(stream, &server, &defaults, drain()).fuse() => {
1026                unreachable!("server finished before request: {:?}", res)
1027            },
1028        }
1029        .map_err(zx::Status::from_raw);
1030
1031        // Must have failed to start the server.
1032        assert_eq!(res, Err(zx::Status::INVALID_ARGS));
1033        // No abort handler must've been set.
1034        assert!(server.borrow().abort_handle.is_none());
1035    }
1036
1037    #[fasync::run_singlethreaded(test)]
1038    async fn disallow_change_parameters_if_enabled() {
1039        let (proxy, stream) =
1040            fidl::endpoints::create_proxy_and_stream::<fidl_fuchsia_net_dhcp::Server_Marker>();
1041
1042        let server = RefCell::new(ServerDispatcherRuntime::new(CannedDispatcher::new()));
1043        // Set default parameters to the server so we can create sockets.
1044        server.borrow_mut().params = Some(default_params());
1045
1046        let defaults = default_params();
1047
1048        let test_fut = async {
1049            let () = proxy
1050                .start_serving()
1051                .await
1052                .expect("start_serving failed")
1053                .map_err(zx::Status::from_raw)
1054                .expect("start_serving returned an error");
1055
1056            // SetParameter disallowed when the server is enabled.
1057            assert_eq!(
1058                proxy
1059                    .set_parameter(&fidl_fuchsia_net_dhcp::Parameter::Lease(
1060                        fidl_fuchsia_net_dhcp::LeaseLength {
1061                            default: None,
1062                            max: None,
1063                            ..Default::default()
1064                        },
1065                    ))
1066                    .await
1067                    .expect("set_parameter FIDL failure")
1068                    .map_err(zx::Status::from_raw),
1069                Err(zx::Status::BAD_STATE)
1070            );
1071
1072            // ResetParameters disallowed when the server is enabled.
1073            assert_eq!(
1074                proxy
1075                    .reset_parameters()
1076                    .await
1077                    .expect("reset_parameters FIDL failure")
1078                    .map_err(zx::Status::from_raw),
1079                Err(zx::Status::BAD_STATE)
1080            );
1081        };
1082
1083        let () = futures::select! {
1084            res = test_fut.fuse() => res,
1085            res = run_server(stream, &server, &defaults, drain()).fuse() => {
1086                unreachable!("server finished before request: {:?}", res)
1087            },
1088        };
1089    }
1090
1091    /// Test that a malformed message does not cause MessageHandler to return an
1092    /// error.
1093    #[test]
1094    fn handle_failed_parse() {
1095        let server = RefCell::new(ServerDispatcherRuntime::new(CannedDispatcher::new()));
1096        let mut handler = MessageHandler::new(&server);
1097        assert_matches::assert_matches!(
1098            handler.handle_from_sender(
1099                &[0xFF, 0x00, 0xBA, 0x03],
1100                std::net::SocketAddrV4::new(Ipv4Addr::UNSPECIFIED.into(), 0),
1101            ),
1102            Ok(None)
1103        );
1104    }
1105}