浏览代码

Add a few DHCP options

Closes: #255
Approved by: whitequark
Astro 6 年之前
父节点
当前提交
7920f84729
共有 3 个文件被更改,包括 63 次插入7 次删除
  1. 1 0
      Cargo.toml
  2. 57 3
      src/wire/dhcpv4.rs
  3. 5 4
      src/wire/mod.rs

+ 1 - 0
Cargo.toml

@@ -39,6 +39,7 @@ verbose = []
 "socket-udp" = []
 "socket-tcp" = []
 "socket-icmp" = []
+"proto-dhcpv4" = ["proto-ipv4"]
 default = [
   "std", "log", # needed for `cargo test --no-default-features --features default` :/
   "phy-raw_socket", "phy-tap_interface",

+ 57 - 3
src/wire/dhcpv4.rs

@@ -50,6 +50,8 @@ pub enum DhcpOption<'a> {
     RequestedIp(Ipv4Address),
     ClientIdentifier(EthernetAddress),
     ServerIdentifier(Ipv4Address),
+    Router(Ipv4Address),
+    SubnetMask(Ipv4Address),
     Other { kind: u8, data: &'a [u8] }
 }
 
@@ -91,6 +93,12 @@ impl<'a> DhcpOption<'a> {
                     (field::OPT_SERVER_IDENTIFIER, 4) => {
                         option = DhcpOption::ServerIdentifier(Ipv4Address::from_bytes(data));
                     }
+                    (field::OPT_ROUTER, 4) => {
+                        option = DhcpOption::Router(Ipv4Address::from_bytes(data));
+                    }
+                    (field::OPT_SUBNET_MASK, 4) => {
+                        option = DhcpOption::SubnetMask(Ipv4Address::from_bytes(data));
+                    }
                     (_, _) => {
                         option = DhcpOption::Other { kind: kind, data: data };
                     }
@@ -108,7 +116,10 @@ impl<'a> DhcpOption<'a> {
             &DhcpOption::ClientIdentifier(eth_addr) => {
                 3 + eth_addr.as_bytes().len()
             }
-            &DhcpOption::RequestedIp(ip) | &DhcpOption::ServerIdentifier(ip) => {
+            &DhcpOption::RequestedIp(ip) |
+            &DhcpOption::ServerIdentifier(ip) |
+            &DhcpOption::Router(ip) |
+            &DhcpOption::SubnetMask(ip) => {
                 2 + ip.as_bytes().len()
             },
             &DhcpOption::Other { data, .. } => 2 + data.len()
@@ -148,6 +159,14 @@ impl<'a> DhcpOption<'a> {
                         buffer[0] = field::OPT_SERVER_IDENTIFIER;
                         buffer[2..6].copy_from_slice(ip.as_bytes());
                     }
+                    &DhcpOption::Router(ip)  => {
+                        buffer[0] = field::OPT_ROUTER;
+                        buffer[2..6].copy_from_slice(ip.as_bytes());
+                    }
+                    &DhcpOption::SubnetMask(mask)  => {
+                        buffer[0] = field::OPT_SUBNET_MASK;
+                        buffer[2..6].copy_from_slice(mask.as_bytes());
+                    }
                     &DhcpOption::Other { kind, data: provided } => {
                         buffer[0] = kind;
                         buffer[2..skip_length].copy_from_slice(provided);
@@ -165,7 +184,7 @@ pub struct Packet<T: AsRef<[u8]>> {
     buffer: T
 }
 
-mod field {
+pub(crate) mod field {
     #![allow(non_snake_case)]
     #![allow(unused)]
 
@@ -604,6 +623,10 @@ pub struct Repr<'a> {
     /// This field is also known as `siaddr` in the RFC. It may be set by the server in DHCPOFFER
     /// and DHCPACK messages, and represent the address of the next server to use in bootstrap.
     pub server_ip: Ipv4Address,
+    /// Default gateway
+    pub router: Option<Ipv4Address>,
+    /// This field comes from a corresponding DhcpOption.
+    pub subnet_mask: Option<Ipv4Address>,
     /// This field is also known as `giaddr` in the RFC. In order to allow DHCP clients on subnets
     /// not directly served by DHCP servers to communicate with DHCP servers, DHCP relay agents can
     /// be installed on these subnets. The DHCP client broadcasts on the local link; the relay
@@ -636,6 +659,8 @@ pub struct Repr<'a> {
     /// The parameter request list informs the server about which configuration parameters
     /// the client is interested in.
     pub parameter_request_list: Option<&'a [u8]>,
+    /// DNS servers
+    pub dns_servers: Option<[Option<Ipv4Address>; 3]>,
 }
 
 impl<'a> Repr<'a> {
@@ -681,7 +706,10 @@ impl<'a> Repr<'a> {
         let mut requested_ip = None;
         let mut client_identifier = None;
         let mut server_identifier = None;
+        let mut router = None;
+        let mut subnet_mask = None;
         let mut parameter_request_list = None;
+        let mut dns_servers = None;
 
         let mut options = packet.options()?;
         while options.len() > 0 {
@@ -703,9 +731,25 @@ impl<'a> Repr<'a> {
                 DhcpOption::ServerIdentifier(ip) => {
                     server_identifier = Some(ip);
                 }
+                DhcpOption::Router(ip) => {
+                    router = Some(ip);
+                }
+                DhcpOption::SubnetMask(mask) => {
+                    subnet_mask = Some(mask);
+                }
                 DhcpOption::Other {kind: field::OPT_PARAMETER_REQUEST_LIST, data} => {
                     parameter_request_list = Some(data);
                 }
+                DhcpOption::Other {kind: field::OPT_DOMAIN_NAME_SERVER, data} => {
+                    let mut dns_servers_inner = [None; 3];
+                    for i in 0.. {
+                        let offset = 4 * i;
+                        let end = offset + 4;
+                        if end > data.len() { break }
+                        dns_servers_inner[i] = Some(Ipv4Address::from_bytes(&data[offset..end]));
+                    }
+                    dns_servers = Some(dns_servers_inner);
+                }
                 DhcpOption::Other {..} => {}
             }
             options = next_options;
@@ -715,7 +759,8 @@ impl<'a> Repr<'a> {
 
         Ok(Repr {
             transaction_id, client_hardware_address, client_ip, your_ip, server_ip, relay_agent_ip,
-            broadcast, requested_ip, server_identifier, client_identifier, parameter_request_list,
+            broadcast, requested_ip, server_identifier, router,
+            subnet_mask, client_identifier, parameter_request_list, dns_servers,
             message_type: message_type?,
         })
     }
@@ -747,6 +792,12 @@ impl<'a> Repr<'a> {
             if let Some(ip) = self.server_identifier {
                 let tmp = options; options = DhcpOption::ServerIdentifier(ip).emit(tmp);
             }
+            if let Some(ip) = self.router {
+                let tmp = options; options = DhcpOption::Router(ip).emit(tmp);
+            }
+            if let Some(ip) = self.subnet_mask {
+                let tmp = options; options = DhcpOption::SubnetMask(ip).emit(tmp);
+            }
             if let Some(ip) = self.requested_ip {
                 let tmp = options; options = DhcpOption::RequestedIp(ip).emit(tmp);
             }
@@ -879,12 +930,15 @@ mod test {
             client_ip: IP_NULL,
             your_ip: IP_NULL,
             server_ip: IP_NULL,
+            router: None,
+            subnet_mask: None,
             relay_agent_ip: IP_NULL,
             broadcast: false,
             requested_ip: Some(IP_NULL),
             client_identifier: Some(CLIENT_MAC),
             server_identifier: None,
             parameter_request_list: Some(&[1, 3, 6, 42]),
+            dns_servers: None,
         }
     }
 

+ 5 - 4
src/wire/mod.rs

@@ -109,8 +109,8 @@ mod ndiscoption;
 mod mld;
 mod udp;
 mod tcp;
-#[cfg(feature = "proto-ipv4")]
-mod dhcpv4;
+#[cfg(feature = "proto-dhcpv4")]
+pub(crate) mod dhcpv4;
 
 pub use self::pretty_print::PrettyPrinter;
 
@@ -216,6 +216,7 @@ pub use self::tcp::{SeqNumber as TcpSeqNumber,
                     Repr as TcpRepr,
                     Control as TcpControl};
 
-#[cfg(feature = "proto-ipv4")]
+#[cfg(feature = "proto-dhcpv4")]
 pub use self::dhcpv4::{Packet as DhcpPacket,
-                       Repr as DhcpRepr};
+                       Repr as DhcpRepr,
+                       MessageType as DhcpMessageType};