-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This introduces a datagram packet stream. That socket is created with AF_PACKET and SOCK_DGRAM options. An ethernet address is stored on stream creation to be used as destination address.
- Loading branch information
Showing
2 changed files
with
154 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,15 @@ | ||
// Derived from the mio-afpacket crate by Alexander Polakov <[email protected]>, | ||
// licensed under the MIT license. https://github.com/polachok/mio-afpacket | ||
|
||
use std::convert::TryInto; | ||
use std::io::{Error, ErrorKind, Read, Result, Write}; | ||
use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; | ||
|
||
use libc::{sockaddr_ll, sockaddr_storage, socket, packet_mreq, setsockopt}; | ||
use libc::{AF_PACKET, ETH_P_ALL, SOCK_RAW, SOL_PACKET, SOL_SOCKET, PACKET_MR_PROMISC, | ||
SO_ATTACH_FILTER, PACKET_ADD_MEMBERSHIP, PACKET_DROP_MEMBERSHIP, MSG_DONTWAIT}; | ||
use libc::{ | ||
AF_PACKET, ETH_P_ALL, MSG_DONTWAIT, PACKET_ADD_MEMBERSHIP, PACKET_DROP_MEMBERSHIP, | ||
PACKET_MR_PROMISC, SOCK_DGRAM, SOCK_RAW, SOL_PACKET, SOL_SOCKET, SO_ATTACH_FILTER, | ||
}; | ||
|
||
/// Packet sockets are used to receive or send raw packets at OSI 2 level. | ||
#[derive(Debug, Clone)] | ||
|
@@ -248,3 +251,99 @@ impl Drop for RawPacketStream { | |
} | ||
} | ||
} | ||
|
||
#[derive(Debug, Clone)] | ||
pub struct DgramPacketStream { | ||
ifindex: i32, | ||
dest: [u8; 8], | ||
fd: RawFd, | ||
} | ||
|
||
impl DgramPacketStream { | ||
pub fn new(ifname: &str, dest: [u8; 8]) -> Result<Self> { | ||
let fd = unsafe { socket(AF_PACKET, SOCK_DGRAM, i32::from((ETH_P_ALL as u16).to_be())) }; | ||
if fd == -1 { | ||
return Err(Error::last_os_error()); | ||
} | ||
|
||
let ifindex = index_by_name(ifname)?; | ||
Ok(DgramPacketStream { | ||
ifindex, | ||
dest, | ||
fd: fd as RawFd, | ||
}) | ||
} | ||
|
||
pub fn set_ifname(&mut self, ifname: &str) -> Result<()> { | ||
self.ifindex = index_by_name(ifname)?; | ||
Ok(()) | ||
} | ||
|
||
pub fn set_dest(&mut self, dest: [u8; 8]) { | ||
self.dest = dest; | ||
} | ||
|
||
pub fn set_non_blocking(&mut self) -> Result<()> { | ||
unsafe { | ||
let mut res = libc::fcntl(self.fd, libc::F_GETFL); | ||
if res != -1 { | ||
res = libc::fcntl(self.fd, libc::F_SETFL, res | libc::O_NONBLOCK); | ||
} | ||
if res == -1 { | ||
return Err(Error::last_os_error()); | ||
} | ||
} | ||
Ok(()) | ||
} | ||
} | ||
|
||
fn send_to(fd: RawFd, ifindex: i32, dest: [u8; 8], buf: &[u8]) -> Result<usize> { | ||
let res; | ||
unsafe { | ||
let mut ss: sockaddr_storage = std::mem::zeroed(); | ||
let sll: *mut sockaddr_ll = &mut ss as *mut sockaddr_storage as *mut sockaddr_ll; | ||
(*sll).sll_halen = dest.len() as u8; | ||
(*sll).sll_addr = dest; | ||
(*sll).sll_ifindex = ifindex; | ||
|
||
let sa = (&ss as *const libc::sockaddr_storage) as *const libc::sockaddr; | ||
res = libc::sendto( | ||
fd, | ||
buf.as_ptr() as *const libc::c_void, | ||
buf.len(), | ||
0, | ||
sa, | ||
std::mem::size_of::<sockaddr_ll>() as u32, | ||
); | ||
if res == -1 { | ||
return Err(Error::last_os_error()); | ||
} | ||
} | ||
Ok(res.try_into().unwrap()) | ||
} | ||
|
||
impl Write for DgramPacketStream { | ||
fn write(&mut self, buf: &[u8]) -> Result<usize> { | ||
send_to(self.fd, self.ifindex, self.dest, buf) | ||
} | ||
|
||
fn flush(&mut self) -> Result<()> { | ||
Ok(()) | ||
} | ||
} | ||
|
||
impl<'a> Write for &'a DgramPacketStream { | ||
fn write(&mut self, buf: &[u8]) -> Result<usize> { | ||
send_to(self.fd, self.ifindex, self.dest, buf) | ||
} | ||
|
||
fn flush(&mut self) -> Result<()> { | ||
Ok(()) | ||
} | ||
} | ||
|
||
impl AsRawFd for DgramPacketStream { | ||
fn as_raw_fd(&self) -> RawFd { | ||
self.fd | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters