Skip to content

Commit

Permalink
v4: add bootp BOOTREQ
Browse files Browse the repository at this point in the history
  • Loading branch information
leshow committed Jun 13, 2023
1 parent 74d4df5 commit ed7deaa
Show file tree
Hide file tree
Showing 3 changed files with 159 additions and 3 deletions.
143 changes: 143 additions & 0 deletions src/bootreq.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
use std::net::Ipv4Addr;

use argh::FromArgs;
use dhcproto::v4;
use mac_address::MacAddress;

use crate::opts::{self, parse_mac, parse_opts};

#[derive(FromArgs, PartialEq, Eq, Debug, Clone)]
/// Send a DISCOVER msg
#[argh(subcommand, name = "bootreq")]
pub struct BootReqArgs {
/// supply a mac address for DHCPv4 (use "random" for a random mac) [default: first interface mac]
#[argh(
option,
short = 'c',
from_str_fn(parse_mac),
default = "opts::get_mac()"
)]
pub chaddr: MacAddress,
/// address of client [default: None]
#[argh(option, default = "Ipv4Addr::UNSPECIFIED")]
pub ciaddr: Ipv4Addr,
/// giaddr [default: 0.0.0.0]
#[argh(option, short = 'g', default = "Ipv4Addr::UNSPECIFIED")]
pub giaddr: Ipv4Addr,
/// fname [default: None]
#[argh(option)]
pub fname: Option<String>,
/// sname [default: None]
#[argh(option)]
pub sname: Option<String>,
/// add opts to the message
/// [ex: these are equivalent- "118,hex,C0A80001" or "118,ip,192.168.0.1"]
#[argh(option, short = 'o', from_str_fn(parse_opts))]
pub opt: Vec<v4::DhcpOption>,
}

impl Default for BootReqArgs {
fn default() -> Self {
Self {
chaddr: opts::get_mac(),
ciaddr: Ipv4Addr::UNSPECIFIED,
giaddr: Ipv4Addr::UNSPECIFIED,
opt: Vec::new(),
fname: None,
sname: None,
}
}
}

impl BootReqArgs {
pub fn build(&self, broadcast: bool) -> v4::Message {
let mut msg = v4::Message::new(
self.ciaddr,
Ipv4Addr::UNSPECIFIED,
Ipv4Addr::UNSPECIFIED,
self.giaddr,
&self.chaddr.bytes(),
);

if broadcast {
msg.set_flags(v4::Flags::default().set_broadcast());
}

if let Some(fname) = &self.fname {
msg.set_fname_str(fname);
}

if let Some(sname) = &self.sname {
msg.set_sname_str(sname);
}

// insert manually entered opts
for opt in &self.opt {
msg.opts_mut().insert(opt.clone());
}

msg
}
}

#[cfg(feature = "script")]
use rhai::{plugin::*, EvalAltResult};

// exposing DiscoverArgs
#[cfg(feature = "script")]
#[export_module]
pub mod bootreq_mod {
use tracing::trace;
#[rhai_fn()]
pub fn args_default() -> BootReqArgs {
BootReqArgs::default()
}
#[rhai_fn(global, name = "to_string", name = "to_debug", pure)]
pub fn to_string(args: &mut BootReqArgs) -> String {
format!("{:?}", args)
}
// ciaddr
#[rhai_fn(global, get = "ciaddr", pure)]
pub fn get_ciaddr(args: &mut BootReqArgs) -> String {
args.ciaddr.to_string()
}
#[rhai_fn(global, set = "ciaddr")]
pub fn set_ciaddr(args: &mut BootReqArgs, ciaddr: &str) {
trace!(?ciaddr, "setting ciaddr");
args.ciaddr = ciaddr.parse::<Ipv4Addr>().expect("failed to parse ciaddr");
}
// giaddr
#[rhai_fn(global, get = "giaddr", pure)]
pub fn get_giaddr(args: &mut BootReqArgs) -> String {
args.giaddr.to_string()
}
#[rhai_fn(global, set = "giaddr")]
pub fn set_giaddr(args: &mut BootReqArgs, giaddr: &str) {
trace!(?giaddr, "setting giaddr");
args.giaddr = giaddr.parse::<Ipv4Addr>().expect("failed to parse giaddr");
}
// chaddr
#[rhai_fn(global, get = "chaddr", pure)]
pub fn get_chaddr(args: &mut BootReqArgs) -> rhai::Blob {
args.chaddr.bytes().to_vec()
}
#[rhai_fn(global, set = "chaddr")]
pub fn set_chaddr(args: &mut BootReqArgs, chaddr: rhai::Blob) {
trace!(?chaddr, "setting chaddr");
let bytes: [u8; 6] = chaddr.try_into().expect("failed to convert macaddress");
args.chaddr = bytes.into();
}
#[rhai_fn(global, name = "rand_chaddr")]
pub fn rand_chaddr(args: &mut BootReqArgs) {
let chaddr = rand::random::<[u8; 6]>().into();
trace!(?chaddr, "setting random chaddr");
args.chaddr = chaddr;
}
// opt
#[rhai_fn(global, set = "opt")]
pub fn set_opt(args: &mut BootReqArgs, opt: String) {
trace!(?opt, "adding opt to message");
args.opt
.push(crate::opts::parse_opts(&opt).expect("failed to parse opt"));
}
}
17 changes: 14 additions & 3 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ use opts::LogStructure;
use pnet_datalink::NetworkInterface;
use tracing::{error, info, trace};

mod bootreq;
mod decline;
mod discover;
mod inforeq;
Expand All @@ -42,8 +43,9 @@ use opts::{parse_mac, parse_opts, parse_params};
use runner::TimeoutRunner;

use crate::{
decline::DeclineArgs, discover::DiscoverArgs, inforeq::InformationReqArgs, inform::InformArgs,
release::ReleaseArgs, request::RequestArgs, util::Msg,
bootreq::BootReqArgs, decline::DeclineArgs, discover::DiscoverArgs,
inforeq::InformationReqArgs, inform::InformArgs, release::ReleaseArgs, request::RequestArgs,
util::Msg,
};

const V6_MULTICAST: Ipv6Addr = Ipv6Addr::new(0xff02, 0, 0, 0, 0, 0, 1, 2);
Expand Down Expand Up @@ -265,6 +267,8 @@ ex dhcpv4:
dhcpm 0.0.0.0 -p 9901 discover (unicast discover to 0.0.0.0:9901)
dhcpm 192.168.0.1 dora (unicast DORA to 192.168.0.1)
dhcpm 192.168.0.1 dora -o 118,C0A80001 (unicast DORA, incl opt 118:192.168.0.1)
bootp:
dhcpm 255.255.255.255 bootreq (broadcast BOOTREQ)
dhcpv6:
dhcpm ::0 -p 9901 inforeq (unicast inforeq to [::0]:9901)
dhcpm ff02::1:2 inforeq (multicast inforeq to default port)
Expand Down Expand Up @@ -328,6 +332,7 @@ pub enum MsgType {
Inform(InformArgs),
Decline(DeclineArgs),
Dora(DoraArgs),
BootReq(BootReqArgs),
InformationReq(InformationReqArgs),
}

Expand Down Expand Up @@ -418,7 +423,13 @@ pub mod util {
impl Msg {
pub fn get_type(&self) -> String {
match self {
Msg::V4(m) => format!("{:?}", m.opts().msg_type().unwrap()),
Msg::V4(m) => format!(
"{:?}",
m.opts()
.msg_type()
.map(|m| format!("{m:?}").to_uppercase())
.unwrap_or("bootreq".to_owned())
),
Msg::V6(m) => format!("{:?}", m.opts()),
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ impl TimeoutRunner {
MsgType::Release(args) => Msg::V4(args.build()),
MsgType::Inform(args) => Msg::V4(args.build()),
MsgType::Decline(args) => Msg::V4(args.build()),
// bootp
MsgType::BootReq(args) => Msg::V4(args.build(broadcast)),
// should be removed by now
MsgType::Dora(_) => panic!("should be removed in main"),
// dhcpv6
Expand Down

0 comments on commit ed7deaa

Please sign in to comment.