| use super::{ClientFqdn, err::IResult}; | ||
| use super::helpers::{parse_ipv4, parse_mac}; | ||
| use super::options::{DhcpOption, DhcpOptions}; | ||
| use nom::bytes::complete::{tag, take}; | ||
| use nom::multi::many_till; | ||
| use nom::number::complete::{be_u16, be_u32, be_u8}; | ||
| use pnet::util::MacAddr; | ||
| use std::net::Ipv4Addr; | ||
| pub const BROADCAST_FLAG: u16 = 0x8000; | ||
| const DHCP_COOKIE: [u8; 4] = [99, 130, 83, 99]; | ||
| #[derive(Debug)] | ||
| pub struct DhcpPacket { | ||
| /// Message op code. | ||
| pub op: u8, | ||
| /// Client sets to zero, optionally used by relay agents | ||
| /// when booting via a relay agent. | ||
| pub hops: u8, | ||
| /// Transaction ID, a random number chosen by the | ||
| /// client, used by the client and server to associate | ||
| /// messages and responses between a client and a | ||
| /// server. | ||
| pub xid: u32, | ||
| /// Filled in by client, seconds elapsed since client | ||
| /// began address acquisition or renewal process. | ||
| pub secs: u16, | ||
| /// Used to indicate if message is unicast or broadcast | ||
| pub flags: u16, | ||
| /// Client IP address; only filled in if client is in | ||
| /// BOUND, RENEW or REBINDING state and can respond | ||
| /// to ARP requests. | ||
| pub ciaddr: Ipv4Addr, | ||
| /// 'your' (client) IP address. | ||
| pub yiaddr: Ipv4Addr, | ||
| /// IP address of next server to use in bootstrap; | ||
| /// returned in DHCPOFFER, DHCPACK by server. | ||
| pub siaddr: Ipv4Addr, | ||
| /// Relay agent IP address, used in booting via a | ||
| /// relay agent. | ||
| pub giaddr: Ipv4Addr, | ||
| /// Client hardware address. | ||
| pub chaddr: MacAddr, | ||
| pub options: Vec<DhcpOption>, | ||
| } | ||
| pub const BOOT_REQUEST: u8 = 1; // From Client; | ||
| pub const BOOT_REPLY: u8 = 2; // From Server; | ||
| pub const ETHERNET_TYPE: u8 = 1; | ||
| pub const ETHERNET_ADDRESS_LEN: u8 = 6; | ||
| pub const DHCP_PACKET_MIN_SIZE: usize = 272; | ||
| macro_rules! get_option { | ||
| ($fn:ident, $option:tt, $type:tt) => { | ||
| pub fn $fn(&self) -> Option<$type> { | ||
| for opt in &self.options { | ||
| match opt { | ||
| DhcpOption::$option(t) => return Some(*t), | ||
| _ => {} | ||
| } | ||
| } | ||
| return None; | ||
| } | ||
| }; | ||
| } | ||
| macro_rules! get_option_ref { | ||
| ($fn:ident, $option:tt, $type:path) => { | ||
| pub fn $fn(&self) -> Option<&$type> { | ||
| for opt in &self.options { | ||
| match opt { | ||
| DhcpOption::$option(t) => return Some(t), | ||
| _ => {} | ||
| } | ||
| } | ||
| return None; | ||
| } | ||
| }; | ||
| } | ||
| macro_rules! add_option { | ||
| ($fn:ident, $option:tt, $type:path) => { | ||
| pub fn $fn(&mut self, val: $type) { | ||
| self.options.push(DhcpOption::$option(val)); | ||
| } | ||
| }; | ||
| } | ||
| impl DhcpPacket { | ||
| pub fn new_reply() -> Self { | ||
| let mut p = Self::default(); | ||
| p.op = BOOT_REPLY; | ||
| return p; | ||
| } | ||
| pub fn new_request() -> Self { | ||
| let mut p = Self::default(); | ||
| p.op = BOOT_REQUEST; | ||
| return p; | ||
| } | ||
| pub fn set_broadcast(&mut self) { | ||
| self.flags = self.flags & BROADCAST_FLAG; | ||
| } | ||
| get_option!(dhcp_msg_type, DhcpMsgType, u8); | ||
| get_option!(dhcp_server_id, DhcpServerId, Ipv4Addr); | ||
| get_option_ref!(hostname, HostName, String); | ||
| get_option_ref!(message, Message, String); | ||
| get_option_ref!(parameter_request_list, ParameterRequestList, Vec<u8>); | ||
| get_option!(requested_ip_address, RequestedIpAddress, Ipv4Addr); | ||
| add_option!(add_broadcast_address, BroadcastAddress, Ipv4Addr); | ||
| add_option!(add_client_fqdn, ClientFqdn, ClientFqdn); | ||
| add_option!(add_dhcp_msg_type, DhcpMsgType, u8); | ||
| add_option!(add_dhcp_server_id, DhcpServerId, Ipv4Addr); | ||
| add_option!(add_domain_name, DomainName, String); | ||
| add_option!(add_domain_server, DomainServer, Vec<Ipv4Addr>); | ||
| add_option!(add_hostname, HostName, String); | ||
| add_option!(add_ip_address_lease_time, IpAddressLeaseTime, u32); | ||
| add_option!(add_message, Message, String); | ||
| add_option!(add_netbios_name_server, NetbiosNameServer, Vec<Ipv4Addr>); | ||
| add_option!(add_parameter_request_list, ParameterRequestList, Vec<u8>); | ||
| add_option!(add_requested_ip_address, RequestedIpAddress, Ipv4Addr); | ||
| add_option!(add_renewal_time, RenewalTime, u32); | ||
| add_option!(add_rebinding_time, RebindingTime, u32); | ||
| add_option!(add_router, Router, Vec<Ipv4Addr>); | ||
| add_option!(add_subnet_mask, SubnetMask, Ipv4Addr); | ||
| add_option!(add_wpad, WPAD, String); | ||
| pub fn build(&self) -> Vec<u8> { | ||
| let mut raw = Vec::new(); | ||
| raw.push(self.op); | ||
| raw.push(ETHERNET_TYPE); | ||
| raw.push(ETHERNET_ADDRESS_LEN); | ||
| raw.push(self.hops); | ||
| raw.extend(&self.xid.to_be_bytes()); | ||
| raw.extend(&self.secs.to_be_bytes()); | ||
| raw.extend(&self.flags.to_be_bytes()); | ||
| raw.extend(&self.ciaddr.octets()); | ||
| raw.extend(&self.yiaddr.octets()); | ||
| raw.extend(&self.siaddr.octets()); | ||
| raw.extend(&self.giaddr.octets()); | ||
| raw.extend(&self.chaddr.octets()); | ||
| raw.extend(&[0; 10]); | ||
| raw.extend(&[0; 64]); | ||
| raw.extend(&[0; 128]); | ||
| raw.extend(&DHCP_COOKIE); | ||
| for opt in &self.options { | ||
| raw.extend(&opt.build()); | ||
| } | ||
| raw.push(DhcpOptions::END); | ||
| while raw.len() < DHCP_PACKET_MIN_SIZE { | ||
| raw.push(0); | ||
| } | ||
| return raw; | ||
| } | ||
| pub fn parse(raw: &[u8]) -> IResult<&[u8], Self> { | ||
| let (raw, op) = be_u8(raw)?; | ||
| let (raw, _htype) = be_u8(raw)?; | ||
| let (raw, _hlen) = be_u8(raw)?; | ||
| let (raw, hops) = be_u8(raw)?; | ||
| let (raw, xid) = be_u32(raw)?; | ||
| let (raw, secs) = be_u16(raw)?; | ||
| let (raw, flags) = be_u16(raw)?; | ||
| let (raw, ciaddr) = parse_ipv4(raw)?; | ||
| let (raw, yiaddr) = parse_ipv4(raw)?; | ||
| let (raw, siaddr) = parse_ipv4(raw)?; | ||
| let (raw, giaddr) = parse_ipv4(raw)?; | ||
| let (raw, chaddr) = parse_mac(raw)?; | ||
| let (raw, _chaddr_padding) = take(10u8)(raw)?; | ||
| // Optional server host name, null terminated string. | ||
| let (raw, _sname) = take(64u8)(raw)?; | ||
| // Boot file name, null terminated string; "generic" | ||
| // name or null in DHCPDISCOVER, fully qualified | ||
| // directory-path name in DHCPOFFER. | ||
| let (raw, _file) = take(128u8)(raw)?; | ||
| let (raw, _) = tag(DHCP_COOKIE)(raw)?; | ||
| let (raw, (options, _)) = | ||
| many_till(DhcpOption::parse, tag(&[DhcpOptions::END]))(raw)?; | ||
| return Ok(( | ||
| raw, | ||
| Self { | ||
| op, | ||
| hops, | ||
| xid, | ||
| secs, | ||
| flags, | ||
| ciaddr, | ||
| yiaddr, | ||
| siaddr, | ||
| giaddr, | ||
| chaddr, | ||
| options, | ||
| }, | ||
| )); | ||
| } | ||
| } | ||
| impl Default for DhcpPacket { | ||
| fn default() -> Self { | ||
| return DhcpPacket { | ||
| op: BOOT_REPLY, | ||
| hops: 0, | ||
| xid: 0, | ||
| secs: 0, | ||
| flags: 0, | ||
| ciaddr: Ipv4Addr::from(0), | ||
| yiaddr: Ipv4Addr::from(0), | ||
| siaddr: Ipv4Addr::from(0), | ||
| giaddr: Ipv4Addr::from(0), | ||
| chaddr: MacAddr::new(0, 0, 0, 0, 0, 0), | ||
| options: Vec::new(), | ||
| }; | ||
| } | ||
| } |
| { | ||
| "git": { | ||
| "sha1": "88da1d11d180d77ae4ac0aec55c88dea495fb98f" | ||
| "sha1": "bd29ec7353d9abddeb8d18269d8fbcc5bd5259e6" | ||
| } | ||
| } |
+1
-1
@@ -114,3 +114,3 @@ # This file is automatically @generated by Cargo. | ||
| name = "dhcplayer" | ||
| version = "0.1.3" | ||
| version = "0.1.4" | ||
| dependencies = [ | ||
@@ -117,0 +117,0 @@ "clap", |
+1
-1
@@ -16,3 +16,3 @@ # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO | ||
| name = "dhcplayer" | ||
| version = "0.1.3" | ||
| version = "0.1.4" | ||
| authors = ["Eloy Pérez <zer1t0ps@protonmail.com>"] | ||
@@ -19,0 +19,0 @@ description = "A tool to play and attack DHCP" |
+24
-0
@@ -80,2 +80,20 @@ use std::{net::Ipv4Addr, time::Duration}; | ||
| .arg( | ||
| Arg::with_name("fqdn") | ||
| .long("fqdn") | ||
| .takes_value(true) | ||
| .help("Fully Qualified Domain Name of the client (the hostname with the domain)") | ||
| ) | ||
| .arg( | ||
| Arg::with_name("dns-update") | ||
| .long("dns-update") | ||
| .help("Requests creation of DNS record using the given FQDN or hostname. If none of them are given, can be used to delete the DNS record.") | ||
| ) | ||
| .arg( | ||
| Arg::with_name("hostname") | ||
| .long("hostname") | ||
| .short("H") | ||
| .takes_value(true) | ||
| .help("Hostname to send in the petition") | ||
| ) | ||
| .arg( | ||
| Arg::with_name("verbosity") | ||
@@ -97,2 +115,5 @@ .short("v") | ||
| pub servers: Option<Vec<Ipv4Addr>>, | ||
| pub hostname: Option<String>, | ||
| pub fqdn: Option<String>, | ||
| pub dns_update: bool, | ||
| pub verbosity: usize, | ||
@@ -118,2 +139,5 @@ } | ||
| servers: helpers::parse_ips(matches, "server"), | ||
| hostname: helpers::parse_string(matches, "hostname"), | ||
| fqdn: helpers::parse_string(matches, "fqdn"), | ||
| dns_update: matches.is_present("dns-update"), | ||
| verbosity: matches.occurrences_of("verbosity") as usize, | ||
@@ -120,0 +144,0 @@ } |
+6
-0
@@ -8,2 +8,8 @@ | ||
| impl<I> From<nom::Err<(I, nom::error::ErrorKind)>> for Error<I> { | ||
| fn from(error: nom::Err<(I, nom::error::ErrorKind)>) -> Self { | ||
| return Self::NomError(error); | ||
| } | ||
| } | ||
| impl<I> nom::error::ParseError<I> for Error<I> { | ||
@@ -10,0 +16,0 @@ fn from_error_kind(input: I, kind: nom::error::ErrorKind) -> Self { |
+3
-240
@@ -6,245 +6,8 @@ // Adapted from https://github.com/krolaw/dhcp4r | ||
| mod options; | ||
| mod packet; | ||
| use err::IResult; | ||
| use helpers::{parse_ipv4, parse_mac}; | ||
| use nom::bytes::complete::{tag, take}; | ||
| use nom::multi::many_till; | ||
| use nom::number::complete::{be_u16, be_u32, be_u8}; | ||
| pub use options::{DhcpMessageTypes, DhcpOption, DhcpOptions}; | ||
| use pnet::util::MacAddr; | ||
| use std::net::Ipv4Addr; | ||
| pub use packet::DhcpPacket; | ||
| pub use options::{ClientFqdn, DhcpMessageTypes, DhcpOption, DhcpOptions}; | ||
| pub const DHCP_SERVER_PORT: u16 = 67; | ||
| pub const DHCP_CLIENT_PORT: u16 = 68; | ||
| pub const BROADCAST_FLAG: u16 = 0x8000; | ||
| const DHCP_COOKIE: [u8; 4] = [99, 130, 83, 99]; | ||
| #[derive(Debug)] | ||
| pub struct DhcpPacket { | ||
| /// Message op code. | ||
| pub op: u8, | ||
| /// Client sets to zero, optionally used by relay agents | ||
| /// when booting via a relay agent. | ||
| pub hops: u8, | ||
| /// Transaction ID, a random number chosen by the | ||
| /// client, used by the client and server to associate | ||
| /// messages and responses between a client and a | ||
| /// server. | ||
| pub xid: u32, | ||
| /// Filled in by client, seconds elapsed since client | ||
| /// began address acquisition or renewal process. | ||
| pub secs: u16, | ||
| /// Used to indicate if message is unicast or broadcast | ||
| pub flags: u16, | ||
| /// Client IP address; only filled in if client is in | ||
| /// BOUND, RENEW or REBINDING state and can respond | ||
| /// to ARP requests. | ||
| pub ciaddr: Ipv4Addr, | ||
| /// 'your' (client) IP address. | ||
| pub yiaddr: Ipv4Addr, | ||
| /// IP address of next server to use in bootstrap; | ||
| /// returned in DHCPOFFER, DHCPACK by server. | ||
| pub siaddr: Ipv4Addr, | ||
| /// Relay agent IP address, used in booting via a | ||
| /// relay agent. | ||
| pub giaddr: Ipv4Addr, | ||
| /// Client hardware address. | ||
| pub chaddr: MacAddr, | ||
| pub options: Vec<DhcpOption>, | ||
| } | ||
| pub const BOOT_REQUEST: u8 = 1; // From Client; | ||
| pub const BOOT_REPLY: u8 = 2; // From Server; | ||
| pub const ETHERNET_TYPE: u8 = 1; | ||
| pub const ETHERNET_ADDRESS_LEN: u8 = 6; | ||
| pub const DHCP_PACKET_MIN_SIZE: usize = 272; | ||
| macro_rules! get_option { | ||
| ($fn:ident, $option:tt, $type:tt) => { | ||
| pub fn $fn(&self) -> Option<$type> { | ||
| for opt in &self.options { | ||
| match opt { | ||
| DhcpOption::$option(t) => return Some(*t), | ||
| _ => {} | ||
| } | ||
| } | ||
| return None; | ||
| } | ||
| }; | ||
| } | ||
| macro_rules! get_option_ref { | ||
| ($fn:ident, $option:tt, $type:path) => { | ||
| pub fn $fn(&self) -> Option<&$type> { | ||
| for opt in &self.options { | ||
| match opt { | ||
| DhcpOption::$option(t) => return Some(t), | ||
| _ => {} | ||
| } | ||
| } | ||
| return None; | ||
| } | ||
| }; | ||
| } | ||
| macro_rules! add_option { | ||
| ($fn:ident, $option:tt, $type:path) => { | ||
| pub fn $fn(&mut self, val: $type) { | ||
| self.options.push(DhcpOption::$option(val)); | ||
| } | ||
| }; | ||
| } | ||
| impl DhcpPacket { | ||
| pub fn new_reply() -> Self { | ||
| let mut p = Self::default(); | ||
| p.op = BOOT_REPLY; | ||
| return p; | ||
| } | ||
| pub fn new_request() -> Self { | ||
| let mut p = Self::default(); | ||
| p.op = BOOT_REQUEST; | ||
| return p; | ||
| } | ||
| pub fn set_broadcast(&mut self) { | ||
| self.flags = self.flags & BROADCAST_FLAG; | ||
| } | ||
| get_option!(dhcp_msg_type, DhcpMsgType, u8); | ||
| get_option!(dhcp_server_id, DhcpServerId, Ipv4Addr); | ||
| get_option_ref!(hostname, HostName, String); | ||
| get_option_ref!(message, Message, String); | ||
| get_option_ref!(parameter_request_list, ParameterRequestList, Vec<u8>); | ||
| get_option!(requested_ip_address, RequestedIpAddress, Ipv4Addr); | ||
| add_option!(add_broadcast_address, BroadcastAddress, Ipv4Addr); | ||
| add_option!(add_dhcp_msg_type, DhcpMsgType, u8); | ||
| add_option!(add_dhcp_server_id, DhcpServerId, Ipv4Addr); | ||
| add_option!(add_domain_name, DomainName, String); | ||
| add_option!(add_domain_server, DomainServer, Vec<Ipv4Addr>); | ||
| add_option!(add_ip_address_lease_time, IpAddressLeaseTime, u32); | ||
| add_option!(add_message, Message, String); | ||
| add_option!(add_netbios_name_server, NetbiosNameServer, Vec<Ipv4Addr>); | ||
| add_option!(add_parameter_request_list, ParameterRequestList, Vec<u8>); | ||
| add_option!(add_requested_ip_address, RequestedIpAddress, Ipv4Addr); | ||
| add_option!(add_renewal_time, RenewalTime, u32); | ||
| add_option!(add_rebinding_time, RebindingTime, u32); | ||
| add_option!(add_router, Router, Vec<Ipv4Addr>); | ||
| add_option!(add_subnet_mask, SubnetMask, Ipv4Addr); | ||
| add_option!(add_wpad, WPAD, String); | ||
| pub fn build(&self) -> Vec<u8> { | ||
| let mut raw = Vec::new(); | ||
| raw.push(self.op); | ||
| raw.push(ETHERNET_TYPE); | ||
| raw.push(ETHERNET_ADDRESS_LEN); | ||
| raw.push(self.hops); | ||
| raw.extend(&self.xid.to_be_bytes()); | ||
| raw.extend(&self.secs.to_be_bytes()); | ||
| raw.extend(&self.flags.to_be_bytes()); | ||
| raw.extend(&self.ciaddr.octets()); | ||
| raw.extend(&self.yiaddr.octets()); | ||
| raw.extend(&self.siaddr.octets()); | ||
| raw.extend(&self.giaddr.octets()); | ||
| raw.extend(&self.chaddr.octets()); | ||
| raw.extend(&[0; 10]); | ||
| raw.extend(&[0; 64]); | ||
| raw.extend(&[0; 128]); | ||
| raw.extend(&DHCP_COOKIE); | ||
| for opt in &self.options { | ||
| raw.extend(&opt.build()); | ||
| } | ||
| raw.push(DhcpOptions::END); | ||
| while raw.len() < DHCP_PACKET_MIN_SIZE { | ||
| raw.push(0); | ||
| } | ||
| return raw; | ||
| } | ||
| pub fn parse(raw: &[u8]) -> IResult<&[u8], Self> { | ||
| let (raw, op) = be_u8(raw)?; | ||
| let (raw, _htype) = be_u8(raw)?; | ||
| let (raw, _hlen) = be_u8(raw)?; | ||
| let (raw, hops) = be_u8(raw)?; | ||
| let (raw, xid) = be_u32(raw)?; | ||
| let (raw, secs) = be_u16(raw)?; | ||
| let (raw, flags) = be_u16(raw)?; | ||
| let (raw, ciaddr) = parse_ipv4(raw)?; | ||
| let (raw, yiaddr) = parse_ipv4(raw)?; | ||
| let (raw, siaddr) = parse_ipv4(raw)?; | ||
| let (raw, giaddr) = parse_ipv4(raw)?; | ||
| let (raw, chaddr) = parse_mac(raw)?; | ||
| let (raw, _chaddr_padding) = take(10u8)(raw)?; | ||
| // Optional server host name, null terminated string. | ||
| let (raw, _sname) = take(64u8)(raw)?; | ||
| // Boot file name, null terminated string; "generic" | ||
| // name or null in DHCPDISCOVER, fully qualified | ||
| // directory-path name in DHCPOFFER. | ||
| let (raw, _file) = take(128u8)(raw)?; | ||
| let (raw, _) = tag(DHCP_COOKIE)(raw)?; | ||
| let (raw, (options, _)) = | ||
| many_till(DhcpOption::parse, tag(&[DhcpOptions::END]))(raw)?; | ||
| return Ok(( | ||
| raw, | ||
| Self { | ||
| op, | ||
| hops, | ||
| xid, | ||
| secs, | ||
| flags, | ||
| ciaddr, | ||
| yiaddr, | ||
| siaddr, | ||
| giaddr, | ||
| chaddr, | ||
| options, | ||
| }, | ||
| )); | ||
| } | ||
| } | ||
| impl Default for DhcpPacket { | ||
| fn default() -> Self { | ||
| return DhcpPacket { | ||
| op: BOOT_REPLY, | ||
| hops: 0, | ||
| xid: 0, | ||
| secs: 0, | ||
| flags: 0, | ||
| ciaddr: Ipv4Addr::from(0), | ||
| yiaddr: Ipv4Addr::from(0), | ||
| siaddr: Ipv4Addr::from(0), | ||
| giaddr: Ipv4Addr::from(0), | ||
| chaddr: MacAddr::new(0, 0, 0, 0, 0, 0), | ||
| options: Vec::new(), | ||
| }; | ||
| } | ||
| } |
+67
-5
@@ -1,2 +0,2 @@ | ||
| use super::err::IResult; | ||
| use super::err::{Error, IResult}; | ||
| use super::helpers::{parse_ipv4, parse_utf8}; | ||
@@ -11,2 +11,3 @@ use nom::bytes::complete::take; | ||
| BroadcastAddress(Ipv4Addr), | ||
| ClientFqdn(ClientFqdn), | ||
| DhcpMsgType(u8), | ||
@@ -42,2 +43,5 @@ DhcpServerId(Ipv4Addr), | ||
| } | ||
| DhcpOptions::CLIENT_FQDN => DhcpOption::ClientFqdn( | ||
| ClientFqdn::parse(data).map_err(|e| nom::Err::Error(e))?, | ||
| ), | ||
| DhcpOptions::DHCP_MSG_TYPE => { | ||
@@ -105,2 +109,6 @@ DhcpOption::DhcpMsgType(be_u8(data)?.1) | ||
| }, | ||
| Self::ClientFqdn(cf) => RawDhcpOption { | ||
| code: DhcpOptions::CLIENT_FQDN, | ||
| data: cf.build(), | ||
| }, | ||
| Self::DhcpMsgType(mtype) => RawDhcpOption { | ||
@@ -133,6 +141,5 @@ code: DhcpOptions::DHCP_MSG_TYPE, | ||
| }, | ||
| Self::NameServer(addrs) => RawDhcpOption::from_addrs( | ||
| DhcpOptions::NAME_SERVER, | ||
| addrs, | ||
| ), | ||
| Self::NameServer(addrs) => { | ||
| RawDhcpOption::from_addrs(DhcpOptions::NAME_SERVER, addrs) | ||
| } | ||
| Self::NetbiosNameServer(addrs) => RawDhcpOption::from_addrs( | ||
@@ -176,2 +183,3 @@ DhcpOptions::NETBIOS_NAME_SERVER, | ||
| Self::BroadcastAddress(addr) => format!("{}", addr), | ||
| Self::ClientFqdn(cf) => format!("{}", cf.value_str()), | ||
| Self::DhcpMsgType(mtype) => { | ||
@@ -249,2 +257,53 @@ format!( | ||
| pub const FQDN_SERVER_UDPATE: u8 = 0x1; | ||
| /// Defined in https://datatracker.ietf.org/doc/html/rfc4702 | ||
| #[derive(PartialEq, Debug, Clone)] | ||
| pub struct ClientFqdn { | ||
| pub flags: u8, | ||
| pub aresult: u8, | ||
| pub ptrresult: u8, | ||
| pub name: String, | ||
| } | ||
| impl ClientFqdn { | ||
| pub fn parse(input: &[u8]) -> Result<Self, Error<&[u8]>> { | ||
| let (input, flags) = be_u8(input)?; | ||
| let (input, aresult) = be_u8(input)?; | ||
| let (input, ptrresult) = be_u8(input)?; | ||
| let name = parse_utf8(input)?; | ||
| return Ok(Self { | ||
| flags, | ||
| aresult, | ||
| ptrresult, | ||
| name, | ||
| }); | ||
| } | ||
| pub fn build(&self) -> Vec<u8> { | ||
| let mut raw = Vec::new(); | ||
| raw.push(self.flags); | ||
| raw.push(self.aresult); | ||
| raw.push(self.ptrresult); | ||
| raw.extend(self.name.as_bytes()); | ||
| return raw; | ||
| } | ||
| pub fn value_str(&self) -> String { | ||
| let flags_names = if (self.flags & FQDN_SERVER_UDPATE) != 0 { | ||
| " (server-update)" | ||
| } else { | ||
| "" | ||
| }; | ||
| format!( | ||
| "flags: 0x{:x}{} A-result: {} PTR-result: {} {}", | ||
| self.flags, flags_names, self.aresult, self.ptrresult, self.name | ||
| ) | ||
| } | ||
| } | ||
| #[allow(non_snake_case)] | ||
@@ -279,2 +338,4 @@ pub mod DhcpOptions { | ||
| pub const CLIENT_FQDN: u8 = 81; | ||
| pub const WPAD: u8 = 252; | ||
@@ -302,2 +363,3 @@ | ||
| REBINDING_TIME => Some("Rebinding Time"), | ||
| CLIENT_FQDN => Some("Client FQDN"), | ||
| WPAD => Some("WPAD"), | ||
@@ -304,0 +366,0 @@ _ => None, |
+73
-22
| use std::net::Ipv4Addr; | ||
| use crate::dhcp::{DhcpMessageTypes, DhcpOption, DhcpPacket}; | ||
| use crate::dhcp::{ClientFqdn, DhcpMessageTypes, DhcpOption, DhcpPacket}; | ||
| use crate::{ | ||
@@ -36,5 +36,2 @@ args, | ||
| let mut channel = TransportChannel::new(iface, Some(args.timeout)) | ||
| .map_err(|e| format!("Unable to create a raw socket: {}", e))?; | ||
| let request_list = match args.options { | ||
@@ -51,2 +48,25 @@ Some(options) => options, | ||
| let dns_update = args.dns_update; | ||
| let fqdn = args.fqdn.unwrap_or("".to_string()); | ||
| let client_fqdn = if dns_update || fqdn.len() != 0 { | ||
| Some(ClientFqdn { | ||
| flags: dns_update as u8, | ||
| aresult: 0, | ||
| ptrresult: 0, | ||
| name: fqdn, | ||
| }) | ||
| } else { | ||
| None | ||
| }; | ||
| let client_options = ClientOptions { | ||
| request_list, | ||
| hostname: args.hostname, | ||
| client_fqdn, | ||
| }; | ||
| let mut channel = TransportChannel::new(iface, Some(args.timeout)) | ||
| .map_err(|e| format!("Unable to create a raw socket: {}", e))?; | ||
| match get_action(args.inform, args.send_request) { | ||
@@ -57,3 +77,3 @@ Action::Discover => discover_all( | ||
| ether_mac, | ||
| request_list, | ||
| &client_options, | ||
| args.servers.as_ref(), | ||
@@ -66,3 +86,3 @@ )?, | ||
| ether_mac, | ||
| request_list, | ||
| &client_options, | ||
| args.servers.as_ref(), | ||
@@ -84,3 +104,3 @@ )?; | ||
| ether_mac, | ||
| request_list, | ||
| &client_options, | ||
| args.servers.as_ref(), | ||
@@ -110,3 +130,3 @@ )?; | ||
| ether_mac: MacAddr, | ||
| request_list: Vec<u8>, | ||
| client_options: &ClientOptions, | ||
| servers: Option<&Vec<Ipv4Addr>>, | ||
@@ -118,3 +138,9 @@ ) -> Result<(), String> { | ||
| info!("DISCOVER sent - Client MAC {}", dhcp_mac); | ||
| send_discover(channel, transaction_id, dhcp_mac, ether_mac, request_list)?; | ||
| send_discover( | ||
| channel, | ||
| transaction_id, | ||
| dhcp_mac, | ||
| ether_mac, | ||
| client_options, | ||
| )?; | ||
@@ -147,3 +173,3 @@ loop { | ||
| ether_mac: MacAddr, | ||
| request_list: Vec<u8>, | ||
| client_options: &ClientOptions, | ||
| servers: Option<&Vec<Ipv4Addr>>, | ||
@@ -161,3 +187,3 @@ ) -> Result<(), String> { | ||
| ether_mac, | ||
| request_list, | ||
| client_options, | ||
| client_ip, | ||
@@ -241,3 +267,3 @@ )?; | ||
| ether_mac: MacAddr, | ||
| request_list: Vec<u8>, | ||
| client_options: &ClientOptions, | ||
| servers: Option<&Vec<Ipv4Addr>>, | ||
@@ -254,3 +280,3 @@ ) -> Result<DhcpPacket, String> { | ||
| ether_mac, | ||
| request_list.clone(), | ||
| client_options, | ||
| servers, | ||
@@ -272,3 +298,3 @@ )?; | ||
| ether_mac, | ||
| request_list, | ||
| client_options, | ||
| client_ip, | ||
@@ -284,6 +310,12 @@ dhcp_server, | ||
| ether_mac: MacAddr, | ||
| request_list: Vec<u8>, | ||
| client_options: &ClientOptions, | ||
| servers: Option<&Vec<Ipv4Addr>>, | ||
| ) -> Result<DhcpPacket, String> { | ||
| send_discover(channel, transaction_id, dhcp_mac, ether_mac, request_list)?; | ||
| send_discover( | ||
| channel, | ||
| transaction_id, | ||
| dhcp_mac, | ||
| ether_mac, | ||
| client_options, | ||
| )?; | ||
@@ -305,3 +337,3 @@ let (_, dhcp_resp) = channel.recv_dhcp( | ||
| ether_mac: MacAddr, | ||
| request_list: Vec<u8>, | ||
| client_options: &ClientOptions, | ||
| ) -> Result<(), String> { | ||
@@ -312,3 +344,3 @@ let mut dp = DhcpPacket::new_request(); | ||
| dp.chaddr = dhcp_mac; | ||
| dp.add_parameter_request_list(request_list); | ||
| set_client_options(&mut dp, client_options); | ||
@@ -336,3 +368,3 @@ channel | ||
| ether_mac: MacAddr, | ||
| request_list: Vec<u8>, | ||
| client_options: &ClientOptions, | ||
| client_ip: Ipv4Addr, | ||
@@ -347,4 +379,5 @@ dhcp_server: Ipv4Addr, | ||
| dp.add_dhcp_server_id(dhcp_server); | ||
| dp.add_parameter_request_list(request_list); | ||
| set_client_options(&mut dp, client_options); | ||
| channel | ||
@@ -378,3 +411,3 @@ .build_and_send( | ||
| ether_mac: MacAddr, | ||
| request_list: Vec<u8>, | ||
| client_options: &ClientOptions, | ||
| client_ip: Ipv4Addr, | ||
@@ -387,3 +420,3 @@ ) -> Result<(), String> { | ||
| dp.chaddr = dhcp_mac; | ||
| dp.add_parameter_request_list(request_list.clone()); | ||
| set_client_options(&mut dp, client_options); | ||
@@ -405,1 +438,19 @@ channel | ||
| } | ||
| pub fn set_client_options(dp: &mut DhcpPacket, co: &ClientOptions) { | ||
| dp.add_parameter_request_list(co.request_list.clone()); | ||
| if let Some(hostname) = &co.hostname { | ||
| dp.add_hostname(hostname.clone()); | ||
| } | ||
| if let Some(client_fqdn) = &co.client_fqdn { | ||
| dp.add_client_fqdn(client_fqdn.clone()); | ||
| } | ||
| } | ||
| pub struct ClientOptions { | ||
| pub request_list: Vec<u8>, | ||
| pub hostname: Option<String>, | ||
| pub client_fqdn: Option<ClientFqdn>, | ||
| } |
Sorry, the diff of this file is not supported yet