diff options
author | HimbeerserverDE <himbeerserverde@gmail.com> | 2023-11-03 22:54:00 +0100 |
---|---|---|
committer | HimbeerserverDE <himbeerserverde@gmail.com> | 2023-11-03 22:54:00 +0100 |
commit | e3e3f28dd8a02377288665d8cf94126ad7eeb245 (patch) | |
tree | 0345eec72d429225a501deea6ad5bdec08f44e4a | |
parent | e9db07c2527b2be96a1b0bf7b54ec737ec46bd3c (diff) |
create pppoe discovery socket
-rw-r--r-- | Cargo.lock | 2 | ||||
-rw-r--r-- | Cargo.toml | 2 | ||||
-rw-r--r-- | src/error.rs | 13 | ||||
-rw-r--r-- | src/lib.rs | 3 | ||||
-rw-r--r-- | src/supervisor.rs | 54 |
5 files changed, 72 insertions, 2 deletions
@@ -262,12 +262,14 @@ dependencies = [ name = "rsdsl_pppoe3" version = "0.1.0" dependencies = [ + "libc", "ppproperly", "rand", "rsdsl_ip_config", "serde", "serde_json", "socket2", + "thiserror", "tokio", ] @@ -6,10 +6,12 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +libc = "0.2.149" ppproperly = { git = "https://github.com/rsdsl/ppproperly.git", version = "0.1.0" } rand = "0.8.5" rsdsl_ip_config = { git = "https://github.com/rsdsl/ip_config.git", version = "0.2.3" } serde = "1.0" serde_json = "1.0" socket2 = "0.5.5" +thiserror = "1.0" tokio = { version = "1.0", features = ["rt-multi-thread", "macros", "sync", "time"] } diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 0000000..8da1cfc --- /dev/null +++ b/src/error.rs @@ -0,0 +1,13 @@ +use std::{ffi, io}; + +use thiserror::Error; + +#[derive(Debug, Error)] +pub enum Error { + #[error("io: {0}")] + Io(#[from] io::Error), + #[error("interface name contains nul byte: {0}")] + Nul(#[from] ffi::NulError), +} + +pub type Result<T> = std::result::Result<T, Error>; @@ -1,3 +1,6 @@ +mod error; +pub use error::*; + mod proto; pub use proto::*; diff --git a/src/supervisor.rs b/src/supervisor.rs index 6905a92..a5d349d 100644 --- a/src/supervisor.rs +++ b/src/supervisor.rs @@ -1,3 +1,4 @@ +use crate::Result; use crate::{ chap::ChapClient, pap::PapClient, @@ -5,10 +6,18 @@ use crate::{ proto::{NegotiationProtocol, ProtocolConfig}, }; +use std::ffi::CString; use std::net::Ipv4Addr; +use std::{io, mem}; use ppproperly::{IpCompressionProtocol, IpcpOpt, Ipv6cpOpt, LcpOpt, QualityProtocol}; -// use socket2::Socket; +use socket2::{SockAddr, Socket}; + +macro_rules! os_err { + () => { + return Err(io::Error::last_os_error().into()); + }; +} /// A client control instance for full dual stack PPPoE sessions. #[derive(Debug)] @@ -122,6 +131,47 @@ impl Client { /// Runs the connection. Blocks the caller forever unless a panic occurs. pub fn run(&self) { - // let sock_disc = self.new_discovery_socket(); + let sock_disc = self.new_discovery_socket(); + } + + fn new_discovery_socket(&self) -> Result<Socket> { + use libc::{ + sockaddr_ll, sockaddr_storage, socklen_t, AF_PACKET, ETH_P_PPP_DISC, PF_PACKET, + SOCK_RAW, + }; + + let sock = Socket::new( + PF_PACKET.into(), + SOCK_RAW.into(), + Some(ETH_P_PPP_DISC.into()), + )?; + + sock.set_broadcast(true)?; + + let c_link = CString::new(&*self.link)?; + + let ifi = unsafe { libc::if_nametoindex(c_link.as_ptr()) }; + if ifi == 0 { + os_err!(); + } + + let sa = sockaddr_ll { + sll_family: AF_PACKET as u16, + sll_protocol: (ETH_P_PPP_DISC as u16).to_be(), + sll_ifindex: ifi as i32, + sll_hatype: 0, + sll_pkttype: 0, + sll_halen: 0, + sll_addr: [0; 8], + }; + + sock.bind(&unsafe { + SockAddr::new( + *mem::transmute::<*const sockaddr_ll, *const sockaddr_storage>(&sa), + mem::size_of_val(&sa) as socklen_t, + ) + })?; + + Ok(sock) } } |