feat: added basic rust wrapper around libnl
This commit is contained in:
parent
2fc1916273
commit
da9aa2178c
@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
FROM rust:1-alpine
|
FROM rust:1-alpine
|
||||||
|
|
||||||
RUN apk add bash docker git cmake make automake musl-dev autoconf libtool \
|
RUN apk add bash docker git cmake make automake musl-dev autoconf libtool valgrind \
|
||||||
flex bison linux-headers openssl-dev apache2-utils docker-compose && \
|
flex bison linux-headers openssl-dev apache2-utils docker-compose && \
|
||||||
mkdir /etc/docker && \
|
mkdir /etc/docker && \
|
||||||
echo '{ "storage-driver": "vfs" }' > /etc/docker/daemon.json
|
echo '{ "storage-driver": "vfs" }' > /etc/docker/daemon.json
|
||||||
@ -14,7 +14,8 @@
|
|||||||
"rust-lang.rust-analyzer",
|
"rust-lang.rust-analyzer",
|
||||||
"ymotongpoo.licenser",
|
"ymotongpoo.licenser",
|
||||||
"ms-azuretools.vscode-docker",
|
"ms-azuretools.vscode-docker",
|
||||||
"bungcip.better-toml"
|
"bungcip.better-toml",
|
||||||
|
"vadimcn.vscode-lldb"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
100
.vscode/launch.json
vendored
Normal file
100
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"type": "lldb",
|
||||||
|
"request": "launch",
|
||||||
|
"name": "Debug unit tests in library 'pcap-sys'",
|
||||||
|
"cargo": {
|
||||||
|
"args": [
|
||||||
|
"test",
|
||||||
|
"--no-run",
|
||||||
|
"--lib",
|
||||||
|
"--package=pcap-sys"
|
||||||
|
],
|
||||||
|
"filter": {
|
||||||
|
"name": "pcap-sys",
|
||||||
|
"kind": "lib"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"args": [],
|
||||||
|
"cwd": "${workspaceFolder}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "lldb",
|
||||||
|
"request": "launch",
|
||||||
|
"name": "Debug executable 'nl-sys'",
|
||||||
|
"cargo": {
|
||||||
|
"args": [
|
||||||
|
"build",
|
||||||
|
"--bin=nl-sys",
|
||||||
|
"--package=nl-sys"
|
||||||
|
],
|
||||||
|
"filter": {
|
||||||
|
"name": "nl-sys",
|
||||||
|
"kind": "bin"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"args": [],
|
||||||
|
"cwd": "${workspaceFolder}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "lldb",
|
||||||
|
"request": "launch",
|
||||||
|
"name": "Debug unit tests in executable 'nl-sys'",
|
||||||
|
"cargo": {
|
||||||
|
"args": [
|
||||||
|
"test",
|
||||||
|
"--no-run",
|
||||||
|
"--bin=nl-sys",
|
||||||
|
"--package=nl-sys"
|
||||||
|
],
|
||||||
|
"filter": {
|
||||||
|
"name": "nl-sys",
|
||||||
|
"kind": "bin"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"args": [],
|
||||||
|
"cwd": "${workspaceFolder}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "lldb",
|
||||||
|
"request": "launch",
|
||||||
|
"name": "Debug executable 'ex-bind-shell-backdoor'",
|
||||||
|
"cargo": {
|
||||||
|
"args": [
|
||||||
|
"build",
|
||||||
|
"--bin=ex-bind-shell-backdoor",
|
||||||
|
"--package=ex-bind-shell-backdoor"
|
||||||
|
],
|
||||||
|
"filter": {
|
||||||
|
"name": "ex-bind-shell-backdoor",
|
||||||
|
"kind": "bin"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"args": [],
|
||||||
|
"cwd": "${workspaceFolder}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "lldb",
|
||||||
|
"request": "launch",
|
||||||
|
"name": "Debug executable 'ex-bind-shell-client'",
|
||||||
|
"cargo": {
|
||||||
|
"args": [
|
||||||
|
"build",
|
||||||
|
"--bin=ex-bind-shell-client",
|
||||||
|
"--package=ex-bind-shell-client"
|
||||||
|
],
|
||||||
|
"filter": {
|
||||||
|
"name": "ex-bind-shell-client",
|
||||||
|
"kind": "bin"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"args": [],
|
||||||
|
"cwd": "${workspaceFolder}"
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -373,6 +373,7 @@ name = "nl-sys"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autotools",
|
"autotools",
|
||||||
|
"cc",
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@ -9,4 +9,5 @@ edition = "2021"
|
|||||||
libc = "0.2.142"
|
libc = "0.2.142"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
autotools = "0.2"
|
autotools = "0.2"
|
||||||
|
cc = "1.0"
|
||||||
@ -14,6 +14,10 @@
|
|||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
cc::Build::new()
|
||||||
|
.file("src/bridge.c")
|
||||||
|
.compile("bridge");
|
||||||
|
|
||||||
let dst = autotools::Config::new("libnl")
|
let dst = autotools::Config::new("libnl")
|
||||||
.reconf("-vi")
|
.reconf("-vi")
|
||||||
.build();
|
.build();
|
||||||
|
|||||||
22
nl-sys/src/bridge.c
Normal file
22
nl-sys/src/bridge.c
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (C) 2023 Andrew Rioux
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/netlink.h>
|
||||||
|
|
||||||
|
int netlink_route() {
|
||||||
|
return NETLINK_ROUTE;
|
||||||
|
}
|
||||||
48
nl-sys/src/error.rs
Normal file
48
nl-sys/src/error.rs
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
// Copyright (C) 2023 Andrew Rioux
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Affero General Public License as
|
||||||
|
// published by the Free Software Foundation, either version 3 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Affero General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use std::{fmt::Display, ffi::CStr};
|
||||||
|
|
||||||
|
use libc::c_int;
|
||||||
|
|
||||||
|
use crate::nl_ffi::nl_geterror;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct Error {
|
||||||
|
error_code: c_int,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Error {
|
||||||
|
pub(crate) fn new(error_code: c_int) -> Self {
|
||||||
|
Error { error_code }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Error {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
let error_msg_utf8 = unsafe {
|
||||||
|
let error_msg = nl_geterror(self.error_code);
|
||||||
|
let error_msg_ptr = CStr::from_ptr(error_msg);
|
||||||
|
std::str::from_utf8(error_msg_ptr.to_bytes()).unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
|
write!(f, "nternal libnl error: {error_msg_utf8}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::error::Error for Error {}
|
||||||
|
|
||||||
|
pub type Result<T> = std::result::Result<T, Error>;
|
||||||
@ -13,12 +13,24 @@
|
|||||||
// You should have received a copy of the GNU Affero General Public License
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
enum nl_sock {}
|
mod nl_ffi;
|
||||||
|
mod netlink;
|
||||||
|
mod route;
|
||||||
|
mod error;
|
||||||
|
|
||||||
extern {
|
// from bridge.c
|
||||||
fn nl_socket_alloc() -> nl_sock;
|
extern "C" {
|
||||||
|
pub(crate) fn netlink_route() -> libc::c_int;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() -> error::Result<()> {
|
||||||
unsafe { nl_socket_alloc(); }
|
let sock = netlink::Socket::new()?;
|
||||||
|
|
||||||
|
let links = sock.get_links()?;
|
||||||
|
|
||||||
|
for link in links.iter() {
|
||||||
|
println!("Link: {}", link.name());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
115
nl-sys/src/netlink.rs
Normal file
115
nl-sys/src/netlink.rs
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
// Copyright (C) 2023 Andrew Rioux
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Affero General Public License as
|
||||||
|
// published by the Free Software Foundation, either version 3 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Affero General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use std::{ptr, marker::PhantomData};
|
||||||
|
|
||||||
|
use libc::AF_UNSPEC;
|
||||||
|
|
||||||
|
use crate::{nl_ffi::*, error};
|
||||||
|
|
||||||
|
pub struct Socket {
|
||||||
|
sock: *mut nl_sock
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Socket {
|
||||||
|
pub fn new() -> error::Result<Self> {
|
||||||
|
unsafe {
|
||||||
|
let sock = Socket { sock: nl_socket_alloc() };
|
||||||
|
|
||||||
|
let ret = nl_connect(sock.sock, crate::netlink_route());
|
||||||
|
if ret < 0 {
|
||||||
|
return Err(error::Error::new(ret));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(sock)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_links(&self) -> error::Result<Cache<crate::route::Link>> {
|
||||||
|
unsafe {
|
||||||
|
let mut link_cache = ptr::null_mut::<nl_cache>();
|
||||||
|
|
||||||
|
let ret = rtnl_link_alloc_cache(self.sock, AF_UNSPEC, &mut link_cache as *mut _);
|
||||||
|
|
||||||
|
if ret < 0 {
|
||||||
|
return Err(error::Error::new(ret));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Cache {
|
||||||
|
cache: link_cache,
|
||||||
|
dt: PhantomData
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Cache<T>
|
||||||
|
where
|
||||||
|
T: From<*mut nl_object>
|
||||||
|
{
|
||||||
|
cache: *mut nl_cache,
|
||||||
|
dt: PhantomData<T>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: From<*mut nl_object>> Cache<T> {
|
||||||
|
pub fn iter(&self) -> CacheIter<'_, T> {
|
||||||
|
let cache_size = unsafe {
|
||||||
|
nl_cache_nitems(self.cache)
|
||||||
|
} as usize;
|
||||||
|
|
||||||
|
CacheIter {
|
||||||
|
obj: unsafe { nl_cache_get_first(self.cache) },
|
||||||
|
cache_size,
|
||||||
|
index: 0,
|
||||||
|
item_type: PhantomData {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: From<*mut nl_object>> Drop for Cache<T> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
nl_cache_put(self.cache);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CacheIter<'a, T> {
|
||||||
|
obj: *mut nl_object,
|
||||||
|
cache_size: usize,
|
||||||
|
index: usize,
|
||||||
|
item_type: PhantomData<&'a T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: From<*mut nl_object>> Iterator for CacheIter<'_, T> {
|
||||||
|
type Item = T;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
if self.index >= self.cache_size || self.obj.is_null() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.index += 1;
|
||||||
|
|
||||||
|
let obj = self.obj;
|
||||||
|
self.obj = unsafe { nl_cache_get_next(obj) };
|
||||||
|
|
||||||
|
Some(T::from(obj))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
|
(self.cache_size, Some(self.cache_size))
|
||||||
|
}
|
||||||
|
}
|
||||||
54
nl-sys/src/nl_ffi.rs
Normal file
54
nl-sys/src/nl_ffi.rs
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
// Copyright (C) 2023 Andrew Rioux
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Affero General Public License as
|
||||||
|
// published by the Free Software Foundation, either version 3 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Affero General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use libc::{c_int, c_void, c_char};
|
||||||
|
|
||||||
|
macro_rules! nl_obj {
|
||||||
|
($name:ident) => {
|
||||||
|
#[repr(C)]
|
||||||
|
#[allow(non_camel_case_types)]
|
||||||
|
pub struct $name {
|
||||||
|
_data: [u8; 0],
|
||||||
|
_marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nl_obj!(nl_sock);
|
||||||
|
nl_obj!(nl_cache);
|
||||||
|
nl_obj!(rtnl_link);
|
||||||
|
nl_obj!(nl_addr);
|
||||||
|
nl_obj!(nl_object);
|
||||||
|
|
||||||
|
// from libnl and libnl-route
|
||||||
|
extern "C" {
|
||||||
|
pub fn nl_socket_alloc() -> *mut nl_sock;
|
||||||
|
pub fn nl_socket_free(sock: *mut nl_sock);
|
||||||
|
pub fn nl_socket_get_local_port(sock: *const nl_sock) -> u32;
|
||||||
|
pub fn nl_connect(sock: *mut nl_sock, protocol: c_int) -> c_int;
|
||||||
|
|
||||||
|
pub fn nl_geterror(error: c_int) -> *const c_char;
|
||||||
|
|
||||||
|
pub fn nl_cache_foreach(cache: *mut nl_cache, cb: extern "C" fn(*mut nl_object, *mut c_void), arg: *mut c_void) -> c_void;
|
||||||
|
pub fn nl_cache_put(cache: *mut nl_cache) -> c_void;
|
||||||
|
pub fn nl_cache_nitems(cache: *mut nl_cache) -> c_int;
|
||||||
|
pub fn nl_cache_get_first(cache: *mut nl_cache) -> *mut nl_object;
|
||||||
|
pub fn nl_cache_get_next(obj: *mut nl_object) -> *mut nl_object;
|
||||||
|
|
||||||
|
pub fn rtnl_link_alloc_cache(sock: *mut nl_sock, family: c_int, result: *mut *mut nl_cache) -> c_int;
|
||||||
|
pub fn rtnl_link_get_by_name(cache: *mut nl_cache, name: *const c_char) -> *mut rtnl_link;
|
||||||
|
pub fn rtnl_link_get_addr(link: *mut rtnl_link) -> *mut nl_addr;
|
||||||
|
pub fn rtnl_link_get_name(link: *mut rtnl_link) -> *const c_char;
|
||||||
|
}
|
||||||
40
nl-sys/src/route.rs
Normal file
40
nl-sys/src/route.rs
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
// Copyright (C) 2023 Andrew Rioux
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Affero General Public License as
|
||||||
|
// published by the Free Software Foundation, either version 3 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Affero General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use std::ffi::CStr;
|
||||||
|
|
||||||
|
use super::nl_ffi::*;
|
||||||
|
|
||||||
|
pub struct Link {
|
||||||
|
link: *mut rtnl_link
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Link {
|
||||||
|
pub fn name(&self) -> String {
|
||||||
|
unsafe {
|
||||||
|
let name = rtnl_link_get_name(self.link);
|
||||||
|
let name_rs = CStr::from_ptr(name);
|
||||||
|
std::str::from_utf8(name_rs.to_bytes()).unwrap().to_owned()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<*mut nl_object> for Link {
|
||||||
|
fn from(value: *mut nl_object) -> Self {
|
||||||
|
Self {
|
||||||
|
link: value as *mut _
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user