Skip to content
Akul123Public

About

`netpulse` is a small Linux network-information CLI written in Rust.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

3 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 

Repository files navigation

netpulse

netpulse is an experimental Linux network CLI written in Rust. It reads and changes kernel networking state directly through Netlink without invoking the ip command.

The project is a learning-oriented implementation of a small subset of iproute2. It currently works with links, interface addresses, routes, and neighbours, with human-readable or JSON output.

It is not yet a production-ready network manager.

How it works

netpulse CLI
    |
    | rtnetlink messages
    v
Linux networking subsystem
    |
    +-- links
    +-- addresses
    +-- routes
    +-- neighbour table

Main dependencies:

  • rtnetlink and netlink-packet-route for Netlink communication
  • tokio and futures for asynchronous requests and streams
  • clap for nested command-line parsing
  • serde and serde_json for JSON output
  • colored for terminal formatting
  • ipnetwork for CIDR parsing

Requirements

  • Linux
  • Rust and Cargo
  • A kernel with rtnetlink support

Read-only commands normally do not need root. Commands that add, delete, or modify network state require root or CAP_NET_ADMIN.

Build

cargo build
cargo build --release

The binaries are created at:

target/debug/netpulse
target/release/netpulse

During development:

cargo run -- link show

The -- separates Cargo's arguments from arguments passed to netpulse.

After building:

./target/release/netpulse link show

Command structure

netpulse [GLOBAL OPTIONS] <OBJECT> <ACTION> [ACTION OPTIONS]

Available commands:

link show | add | del | set-mtu
address show | add | del
route show | add | del
neighbours show | add | del

Inspect help at any level:

netpulse --help
netpulse link --help
netpulse link add --help
netpulse route show --help

Global options

JSON

--json is global, so it can appear before or after a subcommand:

netpulse --json link show
netpulse link show --json
netpulse address show --interface wlan0 --json

Current limitation: address, route, and neighbours print a debug representation of the selected action before their normal output. Their --json output therefore contains one non-JSON line. link --json does not have that debug line.

--route-ipversion

The global option below is accepted but currently unused:

--route-ipversion <ROUTE_IPVERSION>

Use the implemented route option instead:

netpulse route show --ip-version v4
netpulse route show --ip-version v6

Links

A link is a kernel network interface such as lo, wlan0, eth0, docker0, or wg0.

Show links

netpulse link show
netpulse link show --interface wlan0
netpulse link show -i wlan0
netpulse --json link show

The output includes interface index, name, state, MTU, MAC address, and selected flags. Without --interface, all links are shown.

Add a link

sudo netpulse link add --name dummy0 --kind dummy
sudo netpulse link add -n wg0 -k wireguard
Option Short Meaning
--name <NAME> -n New interface name
--kind <KIND> -k Link kind such as dummy, bridge, or wireguard

Creating a link does not assign an address or necessarily set the link up.

Set MTU

sudo netpulse link set-mtu --interface dummy0 --mtu 1400
sudo netpulse link set-mtu -i dummy0 -m 1400

Delete a link

sudo netpulse link del --name dummy0
sudo netpulse link del -n dummy0

Deleting a link also removes kernel state attached to it, including connected addresses and routes.

Addresses

An address belongs to an interface and includes a prefix length, such as 192.0.2.10/24 or 2001:db8::10/64.

Show addresses

netpulse address show
netpulse address show --interface wlan0
netpulse address show -i wlan0

The output includes the interface name, address/prefix, and scope.

Add an address

IPv4:

sudo netpulse address add --interface dummy0 --address 192.0.2.10/24

IPv6:

sudo netpulse address add --interface dummy0 --address 2001:db8::10/64

Short form:

sudo netpulse address add -i dummy0 -a 192.0.2.10/24

--address is parsed as IpNetwork, so include the CIDR prefix.

Delete an address

Use the same interface, address, and prefix:

sudo netpulse address del --interface dummy0 --address 192.0.2.10/24
sudo netpulse address del -i dummy0 -a 192.0.2.10/24

Routes

A route tells the kernel where packets for a destination network should go.

Show routes

Show IPv4 and IPv6 routes:

netpulse route show

Filter by family:

netpulse route show --ip-version v4
netpulse route show --ip-version v6
netpulse route show -i v4

Valid values are v4 and v6. The output includes destination, table, gateway, output interface, protocol, and scope.

Add an IPv4 route

sudo netpulse route add \
  --dest 203.0.113.0/24 \
  --gateway 192.168.1.1/32 \
  --table-id 254

Short form:

sudo netpulse route add -d 203.0.113.0/24 -g 192.168.1.1/32 -t 254
Option Short Meaning
--dest <DEST> -d IPv4 destination in CIDR notation
--gateway <GATEWAY> -g IPv4 next-hop gateway, currently parsed as CIDR
--table-id <TABLE_ID> -t Numeric Linux routing-table ID

Common table IDs:

255  local
254  main
253  default

Add/delete currently support IPv4 only. The request does not specify an output interface, so Linux must already be able to resolve the gateway through a connected route.

Delete an IPv4 route

Describe the same destination, gateway, and table used when adding it:

sudo netpulse route del \
  --dest 203.0.113.0/24 \
  --gateway 192.168.1.1/32 \
  --table-id 254

Short form:

sudo netpulse route del -d 203.0.113.0/24 -g 192.168.1.1/32 -t 254

Adding an existing route normally returns File exists. Deleting a missing route normally returns No such process.

Neighbours

The neighbour table maps network addresses to link-layer addresses:

IPv4 -> MAC using ARP
IPv6 -> MAC using NDP

Linux normally learns these mappings automatically. Static entries are mainly useful in controlled networks, virtual networking, broken discovery environments, and tests.

Show neighbours

netpulse neighbours show
netpulse neighbours show --interface wlan0
netpulse neighbours show -i wlan0
netpulse neighbours show --family bridge
netpulse neighbours show -f bridge

Current behavior: only the exact string bridge selects the bridge family. Any other value, or no value, selects IPv4. IPv6 neighbour display is not currently selected by this parameter.

The request also sets the Own neighbour flag, so results may differ from an unfiltered ip neighbour show.

Add a neighbour

sudo netpulse neighbours add \
  --interface wlan0 \
  --ip-addr 192.168.1.50 \
  --mac-address 10:20:30:40:50:60

Short form:

sudo netpulse neighbours add -i wlan0 -a 192.168.1.50 -m 10:20:30:40:50:60
Option Short Meaning
--interface <INTERFACE> -i Interface owning the entry
--ip-addr <IP_ADDR> -a IPv4 or IPv6 neighbour address
--mac-address <MAC_ADDRESS> -m Six colon-separated byte components

Important current limitation: MAC components are parsed in base 10, not base 16. A conventional value containing a through f, such as aa:bb:cc:dd:ee:ff, fails. The accepted example 10:20:30:40:50:60 represents bytes that display in hexadecimal as 0a:14:1e:28:32:3c. Fix the parser before relying on conventional MAC input.

New entries use the rtnetlink default permanent neighbour state.

Delete a neighbour

sudo netpulse neighbours del \
  --interface wlan0 \
  --ip-addr 192.168.1.50 \
  --mac-address 10:20:30:40:50:60

The current CLI requires --mac-address, although deletion identifies the entry by interface and destination IP and does not include the parsed MAC in the Netlink deletion message.

Safe learning workflow

Experiment on a disposable dummy interface instead of changing the primary network interface:

sudo netpulse link add --name dummy0 --kind dummy
sudo netpulse address add --interface dummy0 --address 192.0.2.10/24
netpulse link show --interface dummy0
netpulse address show --interface dummy0
sudo netpulse link set-mtu --interface dummy0 --mtu 1400
sudo netpulse address del --interface dummy0 --address 192.0.2.10/24
sudo netpulse link del --name dummy0

192.0.2.0/24 is reserved for documentation and is suitable for isolated examples.

iproute2 comparison

netpulse Approximate ip equivalent
netpulse link show ip link show
netpulse link show -i wlan0 ip link show dev wlan0
netpulse link add -n dummy0 -k dummy ip link add dummy0 type dummy
netpulse link del -n dummy0 ip link del dummy0
netpulse link set-mtu -i wlan0 -m 1400 ip link set dev wlan0 mtu 1400
netpulse address show ip address show
netpulse address add -i dummy0 -a 192.0.2.10/24 ip address add 192.0.2.10/24 dev dummy0
netpulse address del -i dummy0 -a 192.0.2.10/24 ip address del 192.0.2.10/24 dev dummy0
netpulse route show -i v4 ip -4 route show
netpulse route show -i v6 ip -6 route show
netpulse route add -d NET -g GW -t 254 ip route add NET via GW table 254
netpulse route del -d NET -g GW -t 254 ip route del NET via GW table 254
netpulse neighbours show ip neighbour show (not an exact filter match)

Troubleshooting

Operation not permitted

Mutation requires administrative capability:

sudo netpulse ...

File exists

The interface, address, route, or neighbour already exists. Inspect state before adding it again:

netpulse link show
netpulse address show
netpulse route show
netpulse neighbours show

Interface not found

netpulse link show

Interface names are exact and case-sensitive.

Gateway is unreachable

A gateway must already be reachable through a connected route:

netpulse address show
netpulse route show --ip-version v4

JSON parsing fails

address, route, and neighbours currently emit one debug line before JSON. link --json is currently clean.

Current limitations

  • Linux only and only a subset of iproute2.
  • No command currently sets a link up or down.
  • Link-kind input is not validated by Clap.
  • Route addition and deletion support IPv4 only.
  • Route add/delete always require a gateway and table ID and do not accept an output interface.
  • Global --route-ipversion is unused.
  • Routing-rule code exists internally but is not exposed through the CLI.
  • Network namespace and monitoring commands are not exposed.
  • Neighbour family parsing only recognizes bridge; other values select IPv4.
  • Neighbour display sets the Own flag and may omit expected entries.
  • MAC input is parsed as decimal rather than hexadecimal.
  • Neighbour deletion requires a MAC argument that is not used in the deletion message.
  • Some missing-link paths return success without changing anything.
  • Debug prints contaminate JSON for address, route, and neighbour commands.
  • Some internal errors are unwrapped instead of propagated.

Project layout

src/main.rs        CLI definitions and command dispatch
src/links.rs       Link query and mutation
src/addresses.rs   Address query and mutation
src/routes.rs      Route query and mutation
src/neighbours.rs  Neighbour query and mutation
src/rules.rs       Internal rule display code, not exposed by CLI
src/display.rs     Human-readable formatting and colors

Operational safety

  • Review mutation commands before running them with sudo.
  • Do not delete or reconfigure the interface carrying an SSH session.
  • Prefer a dummy interface or network namespace for experiments.
  • Static neighbour entries can redirect local traffic to a chosen MAC address.
  • Incorrect routes can disconnect the machine or bypass expected paths.
  • Compare results with ip link, ip address, ip route, and ip neighbour while learning.

About

`netpulse` is a small Linux network-information CLI written in Rust.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages