Skip to content

Commit

Permalink
Merge pull request #7 from leshow/bootp
Browse files Browse the repository at this point in the history
add bootp BOOTREQ
  • Loading branch information
leshow committed Jul 12, 2023
2 parents 74d4df5 + d959d8f commit 81f9da7
Show file tree
Hide file tree
Showing 4 changed files with 222 additions and 29 deletions.
163 changes: 163 additions & 0 deletions src/bootreq.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
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();
}
// fname
#[rhai_fn(global, get = "fname", pure)]
pub fn get_fname(args: &mut BootReqArgs) -> Option<String> {
args.fname.clone()
}
#[rhai_fn(global, set = "fname")]
pub fn set_fname(args: &mut BootReqArgs, fname: String) {
trace!(?fname, "setting fname");
args.fname = Some(fname);
}
// sname
#[rhai_fn(global, get = "sname", pure)]
pub fn get_sname(args: &mut BootReqArgs) -> Option<String> {
args.sname.clone()
}
#[rhai_fn(global, set = "sname")]
pub fn set_sname(args: &mut BootReqArgs, sname: String) {
trace!(?sname, "setting sname");
args.sname = Some(sname);
}
#[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"));
}
}
16 changes: 13 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,12 @@ 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) => m
.opts()
.msg_type()
.map(|m| format!("{m:?}"))
.unwrap_or(format!("{:?}", m.opcode()))
.to_uppercase(),
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
70 changes: 44 additions & 26 deletions src/script.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ use rhai::{plugin::*, Engine};
use tracing::{debug, info};

use crate::{
decline::DeclineArgs, runner::TimeoutRunner, util::Msg, DiscoverArgs, InformArgs, MsgType,
ReleaseArgs, RequestArgs,
bootreq::BootReqArgs, decline::DeclineArgs, runner::TimeoutRunner, util::Msg, DiscoverArgs,
InformArgs, MsgType, ReleaseArgs, RequestArgs,
};

// exposing Msg
Expand Down Expand Up @@ -98,18 +98,12 @@ mod v4_msg_mod {

pub fn main<P: Into<PathBuf>>(path: P, runner: TimeoutRunner) -> Result<(), Box<EvalAltResult>> {
let mut engine = Engine::new();
// TODO: this is gross
let discover_run = runner.clone();
let request_run = runner.clone();
let release_run = runner.clone();
let decline_run = runner.clone();
let inform_run = runner;

engine
// load random package for rhai scripts
// .register_global_module(rhai_rand::RandomPackage::new().as_shared_module())
// register types
.register_type_with_name::<DiscoverArgs>("DiscoverArgs")
.register_type_with_name::<BootReqArgs>("BootReqArgs")
.register_type_with_name::<RequestArgs>("RequestArgs")
.register_type_with_name::<ReleaseArgs>("ReleaseArgs")
.register_type_with_name::<InformArgs>("InformArgs")
Expand All @@ -123,6 +117,10 @@ pub fn main<P: Into<PathBuf>>(path: P, runner: TimeoutRunner) -> Result<(), Box<
"discover",
exported_module!(crate::discover::discover_mod).into(),
)
.register_static_module(
"bootreq",
exported_module!(crate::bootreq::bootreq_mod).into(),
)
.register_static_module(
"request",
exported_module!(crate::request::request_mod).into(),
Expand All @@ -138,34 +136,54 @@ pub fn main<P: Into<PathBuf>>(path: P, runner: TimeoutRunner) -> Result<(), Box<
.register_static_module("inform", exported_module!(crate::inform::inform_mod).into())
// TODO: return result?
.register_fn("send", {
let runner = runner.clone();
move |args: &mut DiscoverArgs| {
let mut new_runner = discover_run.clone();
let mut new_runner = runner.clone();
// replace runner args so it knows which message type to run
new_runner.args.msg = Some(MsgType::Discover(args.clone()));
new_runner.send().expect("runner failed").unwrap_v4()
}
})
.register_fn("send", move |args: &mut RequestArgs| {
let mut new_runner = request_run.clone();
// replace runner args so it knows which message type to run
new_runner.args.msg = Some(MsgType::Request(args.clone()));
new_runner.send().expect("runner failed").unwrap_v4()
.register_fn("send", {
let runner = runner.clone();
move |args: &mut BootReqArgs| {
let mut new_runner = runner.clone();
// replace runner args so it knows which message type to run
new_runner.args.msg = Some(MsgType::BootReq(args.clone()));
new_runner.send().expect("runner failed").unwrap_v4()
}
})
.register_fn("send", {
let runner = runner.clone();
move |args: &mut RequestArgs| {
let mut new_runner = runner.clone();
// replace runner args so it knows which message type to run
new_runner.args.msg = Some(MsgType::Request(args.clone()));
new_runner.send().expect("runner failed").unwrap_v4()
}
})
.register_fn("send", move |args: &mut ReleaseArgs| {
let mut new_runner = release_run.clone();
// replace runner args so it knows which message type to run
new_runner.args.msg = Some(MsgType::Release(args.clone()));
new_runner.send().expect("runner failed").unwrap_v4()
.register_fn("send", {
let runner = runner.clone();
move |args: &mut ReleaseArgs| {
let mut new_runner = runner.clone();
// replace runner args so it knows which message type to run
new_runner.args.msg = Some(MsgType::Release(args.clone()));
new_runner.send().expect("runner failed").unwrap_v4()
}
})
.register_fn("send", move |args: &mut InformArgs| {
let mut new_runner = inform_run.clone();
// replace runner args so it knows which message type to run
new_runner.args.msg = Some(MsgType::Inform(args.clone()));
new_runner.send().expect("runner failed").unwrap_v4()
.register_fn("send", {
let runner = runner.clone();
move |args: &mut InformArgs| {
let mut new_runner = runner.clone();
// replace runner args so it knows which message type to run
new_runner.args.msg = Some(MsgType::Inform(args.clone()));
new_runner.send().expect("runner failed").unwrap_v4()
}
})
.register_fn("send", {
let runner = runner;
move |args: &mut DeclineArgs| {
let mut new_runner = decline_run.clone();
let mut new_runner = runner.clone();
// replace runner args so it knows which message type to run
new_runner.args.msg = Some(MsgType::Decline(args.clone()));
new_runner.send().expect("runner failed").unwrap_v4()
Expand Down

0 comments on commit 81f9da7

Please sign in to comment.