Files
rust-ipam/src/models.rs
mathieu d9ee121fbb feat(networks): add name field to networks
- Migration 0007: ALTER TABLE networks ADD COLUMN name TEXT NOT NULL DEFAULT ''
- Network model, repository, and API updated to include name
- Networks page: name input in the add form, Name column as first column in table
- Delete modal now shows "Name (CIDR)" for clarity
- Hosts page: network dropdowns now show network name instead of CIDR
- Seeds updated with names (LAN, DMZ, Corporate, VPN)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 01:38:40 +02:00

145 lines
6.1 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// models.rs — Shared data models (server + client)
//
// This module defines the structs that represent the IPAM domain entities.
// They are compiled for both the server and WASM, because Leptos needs them
// on both sides:
// - Server : to read/write the database and render HTML
// - Client : to display data inside Leptos components
//
// Each struct derives `Serialize` and `Deserialize` from serde.
// This is required for Leptos to transfer data between the server and the
// browser through server functions (#[server]).
use serde::{Deserialize, Serialize};
// ─── Network ──────────────────────────────────────────────────────────────────
/// An IP network defined by its CIDR range.
///
/// Example: { id: 1, cidr: "192.168.1.0/24" }
/// → covers 192.168.1.0 to 192.168.1.255 (254 usable hosts)
///
/// CIDR (Classless Inter-Domain Routing) combines the network address and
/// the subnet mask into a single field: <address>/<prefix length>.
/// /24 = 24-bit mask = 255.255.255.0
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Network {
/// Unique identifier, auto-incremented by the database.
/// `i64` is a signed 64-bit integer — maps to `BIGINT` in SQL.
pub id: i64,
/// Human-readable name. Examples: "LAN", "DMZ", "VPN"
pub name: String,
/// Address range in CIDR notation.
/// Examples: "10.0.0.0/8", "172.16.0.0/12", "192.168.1.0/24"
pub cidr: String,
}
// ─── Host ─────────────────────────────────────────────────────────────────────
/// A host (server, workstation, network device) belonging to a network.
///
/// Constraint: the IP address must fall within the CIDR range of the network
/// referenced by `network_id`. This is enforced on creation and update.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Host {
pub id: i64,
/// Human-readable name. Examples: "web-server-01", "main-router"
pub name: String,
/// IPv4 address stored as text. Example: "192.168.1.10"
/// We use String instead of IpAddr to simplify serialization
/// and database storage.
pub ip: String,
/// Foreign key referencing the network this host belongs to.
pub network_id: i64,
}
// ─── Port ─────────────────────────────────────────────────────────────────────
/// A network port entry in the global port catalog.
///
/// Ports are defined once here; host_ports and application_ports link them
/// to hosts and applications through separate join tables.
/// Well-known ports (01023) have standardized protocol assignments.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Port {
/// TCP/UDP port number (065535).
/// `u16` is an unsigned 16-bit integer — the exact range for port numbers.
pub number: u16,
/// Description of the protocol typically running on this port.
/// `Option<String>`: absent (None) when the protocol is unknown.
/// Examples: Some("SSH"), Some("HTTPS"), None
pub description: Option<String>,
}
// ─── HostPort ─────────────────────────────────────────────────────────────────
/// Join record representing a port open on a specific host.
///
/// Maps to the `host_ports` table (many-to-many between hosts and ports).
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HostPort {
pub host_id: i64,
pub port_number: u16,
}
impl Port {
/// Returns the standard description for common well-known ports.
/// Used to pre-fill the description field when adding a port.
///
/// `match` is Rust's exhaustive pattern-matching construct (like switch/case,
/// but the compiler enforces that all cases are handled).
pub fn known_protocol(number: u16) -> Option<&'static str> {
// `&'static str`: a reference to a string that lives for the entire
// program lifetime (string literals are stored in the compiled binary).
match number {
21 => Some("FTP"),
22 => Some("SSH"),
23 => Some("Telnet"),
25 => Some("SMTP"),
53 => Some("DNS"),
80 => Some("HTTP"),
110 => Some("POP3"),
143 => Some("IMAP"),
443 => Some("HTTPS"),
3306 => Some("MySQL"),
5432 => Some("PostgreSQL"),
6379 => Some("Redis"),
8080 => Some("HTTP (alternate)"),
_ => None, // `_` is the wildcard pattern — matches everything else
}
}
}
// ─── Application ──────────────────────────────────────────────────────────────
/// An application that uses one or more ports.
///
/// The association between an application and a port is non-strict:
/// the same port can be shared by multiple applications.
/// Example: port 80 might be used by both Nginx and an application proxy.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Application {
pub id: i64,
/// Application name. Examples: "Nginx", "PostgreSQL", "Prometheus"
pub name: String,
}
// ─── ApplicationPort ──────────────────────────────────────────────────────────
/// Join record linking an application to a port (many-to-many relationship).
///
/// A dedicated struct is used instead of Vec<Port> inside Application
/// so it maps directly to the join table in the database.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ApplicationPort {
pub application_id: i64,
pub port_number: u16,
}