the start of Greatness.
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
[package]
|
||||
name = "lda-ipjs"
|
||||
description = "ip -j show schemas"
|
||||
version = "0.0.1"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
macaddr = { version = "1.0.1", features = ["serde", "serde_std"] }
|
||||
strum = { version = "0.27.2", features = ["derive", "strum_macros"] }
|
||||
serde_json = "1.0.143"
|
||||
serde_with = { version = "3.14.0", features = ["json"] }
|
||||
serde = { version = "1.0.219", features = ["derive"] }
|
||||
@@ -0,0 +1,19 @@
|
||||
//! low
|
||||
//!
|
||||
//! # lda-ipj
|
||||
//!
|
||||
//! this package will represent all my needs with the all the subcommands of ip -j.
|
||||
//!
|
||||
//! ## what i need
|
||||
//!
|
||||
//! ```console
|
||||
//! ip -j neigh
|
||||
//! ```
|
||||
//!
|
||||
//! i also need to see devices and idk MAYBE maybe not MAYBE UHHHHHH maybe broadcast
|
||||
//!
|
||||
|
||||
pub mod neighbor;
|
||||
pub mod utils;
|
||||
|
||||
// i want a generalized way to build and call
|
||||
@@ -0,0 +1,72 @@
|
||||
//! ```
|
||||
//! ip -j n s
|
||||
//! ```
|
||||
//!
|
||||
//! yes. this is a real call.
|
||||
|
||||
use crate::utils::serialize::mac::{des_opm, ser_opm};
|
||||
use std::{borrow::Cow, net::IpAddr};
|
||||
|
||||
use macaddr::MacAddr;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use strum::{Display, EnumString};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Hash, Serialize, Deserialize)]
|
||||
pub struct NeighborInput {
|
||||
/// supports only the last item (ignore), `to` keyword is optional
|
||||
to: IpAddr,
|
||||
/// supports only one item (it complains)
|
||||
dev: String, // im all for simplicity
|
||||
/// takes multiple, has to have `nud` before bro or it will think you `to`
|
||||
nud: Vec<NUDState>,
|
||||
}
|
||||
|
||||
// as input this must be lowercase. as output it is uppercase
|
||||
#[derive(Debug, PartialEq, Eq, EnumString, Display, Clone, Copy, Hash, Serialize, Deserialize)]
|
||||
#[strum(serialize_all = "lowercase", ascii_case_insensitive)]
|
||||
#[serde(rename_all = "UPPERCASE")]
|
||||
pub enum NUDState {
|
||||
/// the neighbour entry is valid forever and can
|
||||
/// be only be removed administratively.
|
||||
Permanent,
|
||||
/// the neighbour entry is valid. No attempts to
|
||||
/// validate this entry will be made but it can
|
||||
/// be removed when its lifetime expires.
|
||||
Noarp,
|
||||
/// the neighbour entry is valid until the
|
||||
/// reachability timeout expires.
|
||||
Reachable,
|
||||
/// the neighbour entry is valid but suspicious.
|
||||
/// This option to ip neigh does not change the
|
||||
/// neighbour state if it was valid and the
|
||||
/// address is not changed by this command.
|
||||
Stale,
|
||||
/// this is a pseudo state used when initially
|
||||
/// creating a neighbour entry or after trying to
|
||||
/// remove it before it becomes free to do so.
|
||||
None,
|
||||
/// the neighbour entry has not (yet) been
|
||||
/// validated/resolved.
|
||||
Incomplete,
|
||||
/// neighbor entry validation is currently
|
||||
/// delayed.
|
||||
Delay,
|
||||
/// neighbor is being probed.
|
||||
Probe,
|
||||
/// max number of probes exceeded without
|
||||
/// success, neighbor validation has ultimately
|
||||
/// failed.
|
||||
Failed,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Hash, Serialize, Deserialize)]
|
||||
|
||||
pub struct NeighborItem {
|
||||
dst: IpAddr,
|
||||
dev: String,
|
||||
#[serde(deserialize_with = "des_opm", serialize_with = "ser_opm")]
|
||||
lladdr: Option<MacAddr>,
|
||||
state: Vec<NUDState>,
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
pub mod serialize;
|
||||
@@ -0,0 +1,44 @@
|
||||
use macaddr::MacAddr;
|
||||
use serde::{self, Deserialize, Deserializer, de::Error as DeError};
|
||||
use serde::{Serialize, Serializer, de};
|
||||
|
||||
pub fn serialize_macs<S>(macs: &[MacAddr], serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
let strings: Vec<String> = macs.iter().map(|m| m.to_string()).collect();
|
||||
serde::Serialize::serialize(&strings, serializer)
|
||||
}
|
||||
|
||||
/// Serialize a MacAddr as a string
|
||||
pub fn serialize_mac<S>(mac: &MacAddr, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
serializer.serialize_str(&mac.to_string())
|
||||
}
|
||||
|
||||
/// Deserialize a MacAddr from a string
|
||||
pub fn deserialize_mac<'de, D>(deserializer: D) -> Result<MacAddr, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let s = <String as serde::Deserialize>::deserialize(deserializer)?;
|
||||
s.parse::<MacAddr>().map_err(DeError::custom)
|
||||
}
|
||||
|
||||
/// serialize an [`Option<MacAddr>`]
|
||||
pub fn ser_opm<S: Serializer>(bro: &Option<MacAddr>, ser: S) -> Result<S::Ok, S::Error> {
|
||||
Option::<String>::serialize(&bro.as_ref().map(ToString::to_string), ser)
|
||||
}
|
||||
|
||||
/// deserialize an [`Option<MacAddr>`]
|
||||
pub fn des_opm<'de, D>(des: D) -> Result<Option<MacAddr>, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
Option::<&str>::deserialize(des)?
|
||||
.map(str::parse)
|
||||
.transpose()
|
||||
.map_err(de::Error::custom)
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
pub mod mac;
|
||||
pub mod vec;
|
||||
@@ -0,0 +1,37 @@
|
||||
use serde::Deserialize;
|
||||
use serde::de;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(untagged)]
|
||||
enum OneOrMany<T> {
|
||||
One(T),
|
||||
Many(Vec<T>),
|
||||
}
|
||||
|
||||
pub fn vec_from_strs<'de, D, T>(des: D) -> Result<Vec<T>, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
T: std::str::FromStr,
|
||||
T::Err: std::fmt::Display,
|
||||
{
|
||||
let raw: OneOrMany<String> = OneOrMany::<String>::deserialize(des)?;
|
||||
let mut out = Vec::new();
|
||||
match raw {
|
||||
OneOrMany::One(s) => {
|
||||
let t = s.trim();
|
||||
if !t.is_empty() {
|
||||
out.push(t.parse().map_err(de::Error::custom)?);
|
||||
}
|
||||
}
|
||||
OneOrMany::Many(vs) => {
|
||||
for s in vs {
|
||||
let t = s.trim();
|
||||
if t.is_empty() {
|
||||
continue;
|
||||
}
|
||||
out.push(t.parse().map_err(de::Error::custom)?);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(out)
|
||||
}
|
||||
Reference in New Issue
Block a user