-
Notifications
You must be signed in to change notification settings - Fork 24
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
10 changed files
with
330 additions
and
8 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
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
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 |
---|---|---|
@@ -0,0 +1,70 @@ | ||
use anyhow::Result; | ||
|
||
use std::io::{self, Read}; | ||
use std::mem::MaybeUninit; | ||
mod bpf_kernel { | ||
include!(concat!(env!("OUT_DIR"), "/bpf.bpf.skel.rs")); | ||
} | ||
|
||
use bpf_kernel::*; | ||
use libbpf_rs::skel::OpenSkel; | ||
use libbpf_rs::skel::SkelBuilder; | ||
use libbpf_rs::Iter; | ||
|
||
use crate::common; | ||
|
||
#[allow(dead_code)] | ||
pub struct BPFScraper { | ||
link: Option<libbpf_rs::Link>, | ||
debug: bool, | ||
reader: Option<io::BufReader<Iter>>, | ||
} | ||
|
||
#[allow(dead_code)] | ||
impl BPFScraper { | ||
pub fn new(debug: bool) -> Self { | ||
Self { | ||
debug, | ||
link: None, | ||
reader: None, | ||
} | ||
} | ||
|
||
pub fn start(&mut self) -> Result<()> { | ||
let mut builder = BpfSkelBuilder::default(); | ||
builder.obj_builder.debug(self.debug); | ||
|
||
let mut open_object = MaybeUninit::uninit(); | ||
let open = builder.open(&mut open_object)?; | ||
|
||
let skel = open.load()?; | ||
|
||
self.link = Some(skel.progs.dump_bpf_prog.attach()?); | ||
|
||
Ok(()) | ||
} | ||
|
||
pub fn stop(&self) -> Result<()> { | ||
Ok(()) | ||
} | ||
} | ||
|
||
impl IntoIterator for BPFScraper { | ||
type Item = common::bpf::bpf_prog_result; | ||
type IntoIter = std::vec::IntoIter<Self::Item>; | ||
|
||
fn into_iter(self) -> Self::IntoIter { | ||
let mut buffer = vec![0u8; size_of::<common::bpf::bpf_prog_result>()]; | ||
let iter = Iter::new(&self.link.unwrap()).unwrap(); | ||
let mut r = io::BufReader::new(iter); | ||
let mut v = Vec::new(); | ||
|
||
while r.read_exact(&mut buffer).is_ok() { | ||
let item: common::bpf::bpf_prog_result = | ||
unsafe { std::ptr::read(buffer.as_ptr() as *const _) }; | ||
v.push(item); | ||
} | ||
|
||
v.into_iter() | ||
} | ||
} |
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 |
---|---|---|
@@ -0,0 +1,67 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
/* Copyright (c) 2022 Red Hat, Inc. */ | ||
#include <vmlinux.h> | ||
|
||
#include <bpf/bpf_core_read.h> | ||
#include <bpf/bpf_helpers.h> | ||
|
||
#include "common/bpf_iterator.h" | ||
|
||
char _license[] SEC("license") = "GPL"; | ||
|
||
static const char* get_name(struct btf* btf, long btf_id, const char* fallback) { | ||
struct btf_type **types, *t; | ||
unsigned int name_off; | ||
const char* str; | ||
|
||
if (!btf) { | ||
return fallback; | ||
} | ||
str = btf->strings; | ||
types = btf->types; | ||
bpf_probe_read_kernel(&t, sizeof(t), types + btf_id); | ||
name_off = BPF_CORE_READ(t, name_off); | ||
if (name_off >= btf->hdr.str_len) { | ||
return fallback; | ||
} | ||
return str + name_off; | ||
} | ||
|
||
SEC("iter/bpf_link") | ||
int dump_bpf_link(struct bpf_iter__bpf_link* ctx) { | ||
struct seq_file* seq = ctx->meta->seq; | ||
struct bpf_link* link = ctx->link; | ||
int link_id; | ||
|
||
if (!link) { | ||
return 0; | ||
} | ||
|
||
link_id = link->id; | ||
BPF_SEQ_PRINTF(seq, "%d\n", link_id); | ||
return 0; | ||
} | ||
|
||
SEC("iter/bpf_prog") | ||
int dump_bpf_prog(struct bpf_iter__bpf_prog* ctx) { | ||
struct seq_file* seq = ctx->meta->seq; | ||
__u64 seq_num = ctx->meta->seq_num; | ||
struct bpf_prog* prog = ctx->prog; | ||
struct bpf_prog_aux* aux; | ||
|
||
if (!prog) { | ||
return 0; | ||
} | ||
|
||
struct bpf_prog_result result = {0}; | ||
|
||
aux = prog->aux; | ||
|
||
result.id = aux->id; | ||
bpf_core_read_str(result.name, BPF_STR_MAX, get_name(aux->btf, aux->func_info[0].type_id, aux->name)); | ||
bpf_core_read_str(result.attached, BPF_STR_MAX, aux->attach_func_name); | ||
|
||
bpf_seq_write(seq, &result, sizeof(result)); | ||
|
||
return 0; | ||
} |
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 |
---|---|---|
@@ -0,0 +1,6 @@ | ||
#ifndef __SCRAPER_BINDINGS_H | ||
#define __SCRAPER_BINDINGS_H | ||
|
||
#include "bpf_iterator.h" | ||
|
||
#endif |
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 |
---|---|---|
@@ -0,0 +1,12 @@ | ||
#ifndef __SCRAPER_BPF_ITER_H | ||
#define __SCRAPER_BPF_ITER_H | ||
|
||
#define BPF_STR_MAX 32 | ||
|
||
struct bpf_prog_result { | ||
unsigned int id; | ||
char name[BPF_STR_MAX]; | ||
char attached[BPF_STR_MAX]; | ||
}; | ||
|
||
#endif |
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 |
---|---|---|
@@ -0,0 +1,25 @@ | ||
pub mod bpf { | ||
include!(concat!(env!("OUT_DIR"), "/bindings.rs")); | ||
|
||
use std::ffi::CStr; | ||
|
||
impl bpf_prog_result { | ||
pub fn name(&self) -> String { | ||
unsafe { | ||
CStr::from_ptr(self.name.as_ptr()) | ||
.to_str() | ||
.unwrap_or("") | ||
.to_string() | ||
} | ||
} | ||
|
||
pub fn attached(&self) -> String { | ||
unsafe { | ||
CStr::from_ptr(self.attached.as_ptr()) | ||
.to_str() | ||
.unwrap_or("") | ||
.to_string() | ||
} | ||
} | ||
} | ||
} |
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,14 @@ | ||
pub mod bpf; | ||
pub mod common; | ||
pub mod network; | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
|
||
#[test] | ||
fn it_works() { | ||
let result = add(2, 2); | ||
assert_eq!(result, 4); | ||
#[cxx::bridge(namespace = "collector::rust")] | ||
mod ffi { | ||
extern "Rust" { | ||
fn get_bpf_programs() -> Vec<::common::bpf::bpf_prog_result>; | ||
} | ||
} | ||
|
||
pub fn get_bpf_programs() -> Vec<common::bpf::bpf_prog_result> { | ||
vec![] | ||
} |
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
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 |
---|---|---|
@@ -0,0 +1,106 @@ | ||
use std::io::{self, BufRead}; | ||
use std::net::{Ipv4Addr, Ipv6Addr}; | ||
use std::{mem::MaybeUninit, net::IpAddr}; | ||
|
||
use libbpf_rs::skel::OpenSkel; | ||
use libbpf_rs::skel::SkelBuilder; | ||
|
||
use anyhow::Result; | ||
use libbpf_rs::Iter; | ||
use network_kernel::NetworkSkelBuilder; | ||
|
||
mod network_kernel { | ||
include!(concat!(env!("OUT_DIR"), "/network.bpf.skel.rs")); | ||
} | ||
|
||
#[derive(Debug)] | ||
#[allow(dead_code)] | ||
pub struct Connection { | ||
local: IpAddr, | ||
remote: IpAddr, | ||
state: u8, | ||
} | ||
|
||
#[allow(dead_code)] | ||
pub struct NetworkScraper { | ||
link: Option<libbpf_rs::Link>, | ||
debug: bool, | ||
reader: Option<io::BufReader<Iter>>, | ||
} | ||
|
||
impl NetworkScraper { | ||
pub fn new(debug: bool) -> Self { | ||
Self { | ||
link: None, | ||
reader: None, | ||
debug, | ||
} | ||
} | ||
|
||
pub fn start(&mut self) -> Result<()> { | ||
let mut builder = NetworkSkelBuilder::default(); | ||
builder.obj_builder.debug(self.debug); | ||
|
||
let mut open_object = MaybeUninit::uninit(); | ||
let open = builder.open(&mut open_object)?; | ||
|
||
let skel = open.load()?; | ||
|
||
self.link = Some(skel.progs.dump_tcp4.attach()?); | ||
|
||
println!("started"); | ||
Ok(()) | ||
} | ||
|
||
#[allow(dead_code)] | ||
pub fn stop(&self) -> Result<()> { | ||
Ok(()) | ||
} | ||
|
||
fn parse_connection(&self, line: &str) -> Option<Connection> { | ||
let parts: Vec<&str> = line.split_whitespace().collect(); | ||
|
||
let local_raw = parts[1]; | ||
let remote_raw = parts[2]; | ||
let state = parts[3]; | ||
|
||
Some(Connection { | ||
local: self.parse_addr(local_raw), | ||
remote: self.parse_addr(remote_raw), | ||
state: u8::from_str_radix(state, 16).unwrap_or(0), | ||
}) | ||
} | ||
|
||
fn parse_addr(&self, raw: &str) -> IpAddr { | ||
let sections: Vec<&str> = raw.split(':').collect(); | ||
|
||
if sections[0].len() == 8 { | ||
let ip = u32::from_str_radix(sections[0], 16).unwrap(); | ||
Ipv4Addr::from_bits(ip).into() | ||
} else { | ||
let ip = u128::from_str_radix(sections[0], 16).unwrap(); | ||
Ipv6Addr::from_bits(ip).into() | ||
} | ||
} | ||
} | ||
|
||
impl Iterator for NetworkScraper { | ||
type Item = Connection; | ||
|
||
fn next(&mut self) -> Option<Connection> { | ||
let Some(l) = &self.link else { | ||
println!("no link"); | ||
return None; | ||
}; | ||
let iter = Iter::new(l).unwrap(); | ||
let mut r = io::BufReader::new(iter); | ||
|
||
let mut buf = String::new(); | ||
let Ok(_) = r.read_line(&mut buf) else { | ||
println!("line read failed"); | ||
return None; | ||
}; | ||
|
||
self.parse_connection(&buf) | ||
} | ||
} |