From 9d5e3eaaf198ce43faf3aa6a7ae43c5bea0d3f16 Mon Sep 17 00:00:00 2001 From: Ricardo Zuasti Date: Mon, 19 Jan 2026 19:03:08 -0500 Subject: [PATCH] Added database support and initial structure creation --- .gitignore | 1 + Cargo.lock | 244 ++++++++++++++++++ Cargo.toml | 3 + TODO.md | 6 + .../01-initial_structure/up.sql | 6 + src/db.rs | 25 ++ src/mac_vendor_finder.rs | 2 +- src/main.rs | 29 ++- 8 files changed, 302 insertions(+), 14 deletions(-) create mode 100644 TODO.md create mode 100644 database_migrations/01-initial_structure/up.sql create mode 100644 src/db.rs diff --git a/.gitignore b/.gitignore index ea8c4bf..ed2031a 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /target +oott.db diff --git a/Cargo.lock b/Cargo.lock index 2fe92e6..96871fe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -67,12 +67,28 @@ version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" +[[package]] +name = "bumpalo" +version = "3.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" + [[package]] name = "bytes" version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" +[[package]] +name = "cc" +version = "1.2.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "755d2fce177175ffca841e9a06afdb2c4ab0f593d53b4dee48147dfaade85932" +dependencies = [ + "find-msvc-tools", + "shlex", +] + [[package]] name = "cfg-if" version = "1.0.4" @@ -118,12 +134,73 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "fallible-iterator" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" + +[[package]] +name = "fallible-streaming-iterator" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" + +[[package]] +name = "find-msvc-tools" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8591b0bcc8a98a64310a2fae1bb3e9b8564dd10e381e6e28010fde8e8e8568db" + +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + [[package]] name = "glob" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +dependencies = [ + "foldhash", +] + +[[package]] +name = "hashlink" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea0b22561a9c04a7cb1a302c013e0259cd3b4bb619f145b32f72b8b4bcbed230" +dependencies = [ + "hashbrown", +] + +[[package]] +name = "include_dir" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "923d117408f1e49d914f1a379a309cffe4f18c05cf4e3d12e613a15fc81bd0dd" +dependencies = [ + "include_dir_macros", +] + +[[package]] +name = "include_dir_macros" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cab85a7ed0bd5f0e76d93846e0147172bed2e2d3f859bcc33a8d9699cad1a75" +dependencies = [ + "proc-macro2", + "quote", +] + [[package]] name = "ipnetwork" version = "0.20.0" @@ -169,12 +246,33 @@ dependencies = [ "syn", ] +[[package]] +name = "js-sys" +version = "0.3.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + [[package]] name = "libc" version = "0.2.180" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" +[[package]] +name = "libsqlite3-sys" +version = "0.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95b4103cffefa72eb8428cb6b47d6627161e51c2739fc5e3b734584157bc642a" +dependencies = [ + "cc", + "pkg-config", + "vcpkg", +] + [[package]] name = "lock_api" version = "0.4.14" @@ -213,6 +311,12 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43794a0ace135be66a25d3ae77d41b91615fb68ae937f904090203e81f755b65" +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + [[package]] name = "once_cell_polyfill" version = "1.70.2" @@ -224,8 +328,11 @@ name = "oott" version = "0.1.0" dependencies = [ "env_logger", + "include_dir", "log", "pnet", + "rusqlite", + "rusqlite_migration", "serde", "serde_json", "tokio", @@ -260,6 +367,12 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + [[package]] name = "pnet" version = "0.35.0" @@ -422,6 +535,48 @@ version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" +[[package]] +name = "rsqlite-vfs" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8a1f2315036ef6b1fbacd1972e8ee7688030b0a2121edfc2a6550febd41574d" +dependencies = [ + "hashbrown", + "thiserror", +] + +[[package]] +name = "rusqlite" +version = "0.38.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1c93dd1c9683b438c392c492109cb702b8090b2bfc8fed6f6e4eb4523f17af3" +dependencies = [ + "bitflags", + "fallible-iterator", + "fallible-streaming-iterator", + "hashlink", + "libsqlite3-sys", + "smallvec", + "sqlite-wasm-rs", +] + +[[package]] +name = "rusqlite_migration" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08e45ef6076d02cdc5b6daa61999bb6a90d7a2e256c178c31ab903d5023f1493" +dependencies = [ + "include_dir", + "log", + "rusqlite", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + [[package]] name = "scopeguard" version = "1.2.0" @@ -471,6 +626,12 @@ dependencies = [ "zmij", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "signal-hook-registry" version = "1.4.8" @@ -497,6 +658,18 @@ dependencies = [ "windows-sys 0.60.2", ] +[[package]] +name = "sqlite-wasm-rs" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f4206ed3a67690b9c29b77d728f6acc3ce78f16bf846d83c94f76400320181b" +dependencies = [ + "cc", + "js-sys", + "rsqlite-vfs", + "wasm-bindgen", +] + [[package]] name = "syn" version = "2.0.114" @@ -508,6 +681,26 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "tokio" version = "1.49.0" @@ -548,12 +741,63 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "wasi" version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" +[[package]] +name = "wasm-bindgen" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "008b239d9c740232e71bd39e8ef6429d27097518b6b30bdf9086833bd5b6d608" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5256bae2d58f54820e6490f9839c49780dff84c65aeab9e772f15d5f0e913a55" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f01b580c9ac74c8d8f0c0e4afb04eeef2acf145458e52c03845ee9cd23e3d12" +dependencies = [ + "unicode-ident", +] + [[package]] name = "winapi" version = "0.3.9" diff --git a/Cargo.toml b/Cargo.toml index b4f0c41..019d8a1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,3 +10,6 @@ pnet = "0.35.0" tokio = { version = "1.0", features = ["full"] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" +rusqlite = { version = "0.38.0", features = ["bundled"] } +rusqlite_migration = { version = "2.4.0", features = ["from-directory"] } +include_dir = "0.7.4" diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..9ac6397 --- /dev/null +++ b/TODO.md @@ -0,0 +1,6 @@ +- [ ] Proper error handling across the board +- [ ] Insert new devices in database or update existing ones last_seen +- [ ] Generate an event when a new device is inserted +- [ ] Run as an endless loop with a configurable pause +- [ ] Deploy as a service in a docker container +- [ ] Deploy as a service via a nix flake diff --git a/database_migrations/01-initial_structure/up.sql b/database_migrations/01-initial_structure/up.sql new file mode 100644 index 0000000..5f77633 --- /dev/null +++ b/database_migrations/01-initial_structure/up.sql @@ -0,0 +1,6 @@ +CREATE TABLE devices( + mac_address TEXT PRIMARY KEY, + ip_address TEXT NOT NULL, + vendor_name TEXT, + last_seen TEXT NOT NULL +); diff --git a/src/db.rs b/src/db.rs new file mode 100644 index 0000000..51c79e6 --- /dev/null +++ b/src/db.rs @@ -0,0 +1,25 @@ +use include_dir::{Dir, include_dir}; +use log::debug; +use rusqlite::{Connection, params}; +use rusqlite_migration::Migrations; +use std::result::Result; +use std::sync::LazyLock; + +static MIGRATIONS_DIR: Dir = include_dir!("$CARGO_MANIFEST_DIR/database_migrations"); + +// Define migrations. These are applied atomically. +static MIGRATIONS: LazyLock> = + LazyLock::new(|| Migrations::from_directory(&MIGRATIONS_DIR).unwrap()); + +pub fn init_db() -> Result { + debug!("Opening database"); + let mut conn = Connection::open("./oott.db").unwrap(); + + debug!("Database open, executing migrations if needed"); + // Update the database schema, atomically + MIGRATIONS.to_latest(&mut conn); + + debug!("Database up to date"); + + Ok(conn) +} diff --git a/src/mac_vendor_finder.rs b/src/mac_vendor_finder.rs index 65af121..ed3cef5 100644 --- a/src/mac_vendor_finder.rs +++ b/src/mac_vendor_finder.rs @@ -1,4 +1,4 @@ -use log::{debug, info, warn}; +use log::{debug, info}; use serde::Deserialize; use std::collections::HashMap; use std::fs; diff --git a/src/main.rs b/src/main.rs index f075b93..28d31ea 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,9 @@ -use log::info; - use crate::mac_vendor_finder::MacVendorFinder; +use log::info; +use rusqlite::Connection; + mod config; +mod db; mod device_finders; mod mac_vendor_finder; @@ -11,19 +13,20 @@ async fn main() { info!("Starting up oott"); let mut mac_vendor_finder = MacVendorFinder::new(); + let mut db_conn = db::init_db().unwrap(); - let devices = device_finders::arp::find("eno1").await; + // let devices = device_finders::arp::find("eno1").await; - info!("Done with ARP probes"); - info!("Found {} online devices", devices.iter().count()); - for device in devices.iter() { - info!("Device found {}", device); - let vendor_result = mac_vendor_finder.find(device.get_mac_prefix().as_str()); - match vendor_result { - Some(vendor) => info!("Device vendor = {}", vendor), - None => info!("Device vendor not found"), - } - } + // info!("Done with ARP probes"); + // info!("Found {} online devices", devices.iter().count()); + // for device in devices.iter() { + // info!("Device found {}", device); + // let vendor_result = mac_vendor_finder.find(device.get_mac_prefix().as_str()); + // match vendor_result { + // Some(vendor) => info!("Device vendor = {}", vendor), + // None => info!("Device vendor not found"), + // } + // } info!("Exiting"); }