CLI tool
brona/iproute2mac avatar
brona/iproute2mac

iproute2mac gives macOS admins the ip, bridge and ss commands they expect

CLI wrapper for basic network utilites on Mac OS X inspired with iproute2 on Linux systems - ip command.

1,062 stars78 forksPythonMIT

At a glance

What is it?
iproute2mac is a MIT licensed Python CLI that mimics the Linux iproute2 tools on macOS, covering interfaces, addresses, neighbours, routes, bridges and sockets. It is a compatibility layer rather than a replacement, and the README is explicit about where the output stops matching iproute2.
Who is it for?
iproute2mac fits a macOS administrator who already speaks iproute2 and wants the same commands on a Mac, especially in scripts where a one-line change is cheaper than rewriting the logic for netstat and ifconfig. It does not fit a team that needs full iproute2 fidelity, because the README states the output is not fully compatible and lists the gaps, including neighbour listings for IPv6 on a specific interface.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 17 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 21, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Three commands, one Python package, a Linux muscle memory

The problem iproute2mac solves is narrow and familiar to anyone who administers both Linux and macOS. On Linux you type ip, bridge and ss. On macOS none of them exist, and the equivalents are scattered across netstat, ifconfig, ndp, arp, route and networksetup, each with its own syntax. Every script you move from a Linux box to a Mac has to be rewritten, and every muscle memory has to be reloaded.

This project is a CLI wrapper that provides those three commands on macOS. The goal, as the README states it, is to give admins who already use Linux systems a compatible CLI with the same command shortcuts and the same user experience. The three entry points are ip for the link, address, route and neighbour modules, bridge for bridge interfaces, and ss for socket statistics.

The scope is limited, and the README says so in its second sentence: provided functionality is limited and the command output is not fully compatible with iproute2. That sentence is the most important one in the document for an adopter, and the sections below look at where exactly the compatibility stops.

Implementation-wise it is a small Python project. The pyproject.toml names the distribution iproute2mac, pins the version at 1.7.6, requires Python 3.10 or newer, and configures black with a line length of 79 targeting py310 along with isort using the black profile. The source lives in src/, with the entry points as src/ip.py, src/bridge.py and src/ss.py, and there is a test/ directory.

Where the macOS gap shows: neighbour scoping and the route cache

The compatibility gaps are specific and worth knowing before you rely on the tool. The neighbour module is the clearest case. You can show all neighbours, filter to IPv4 ARP entries or IPv6 NDP entries, restrict to a specific interface, or filter by prefix, and you can flush neighbours for an interface. But the README states plainly that IPv6 NDP neighbours cannot currently be shown for a specific interface, and that IPv6 NDP neighbours are flushed for all interfaces rather than just the one you name. So the IPv4 half of the module is more capable than the IPv6 half, and a script that scopes an NDP cleanup to one interface will behave differently than it does on Linux.

The route module has its own gap. Flushing the route cache is a no-op on macOS, as the README says, because macOS has no equivalent of the Linux route cache to clear. Any runbook step that clears the cache before re-reading routes is a no-op here rather than an error, which is a good failure mode, but it means the step does not do what the Linux script implies.

Output ordering is another difference in behaviour rather than in syntax. The changelog for v1.7.1 records that ip addr and ip link return results in ifindex order, and the same release added support for the up filter on both. The point is that ordering is macOS-native rather than Linux-native, and anything that depends on a particular row order will behave differently.

There is a fourth, smaller one. v1.7.3 fixed the ss command so it correctly parses getopt style arguments such as ss -nat, and improved ip command parsing for degenerate cases. The bundled options, like the -j JSON output and the -color family, are modelled on iproute2, but the parsing underneath is a reimplementation, so edge cases are where differences surface.

Four install routes, and the symlink trick that makes ip exist

Installation is well covered, with a preferred path and three maintained alternatives. The preferred route is Homebrew, and the formula is maintained by the project author.

bash
brew install iproute2mac

That is the one command a Mac user needs. Homebrew is also where the formula documentation lives, at formulae.brew.sh, alongside the iproute2mac.rb formula in homebrew-core.

The manual route installs from HEAD and shows how the commands are exposed, which is worth understanding because it explains the whole design. The script files are symlinked into /usr/local/bin under the names you expect.

bash
sudo mkdir /usr/local/iproute2mac
sudo chown -R $(whoami):admin /usr/local/iproute2mac
cd /usr/local/
git clone https://github.com/brona/iproute2mac.git
ln -s iproute2mac/src/ip.py /usr/local/bin/ip
ln -s iproute2mac/src/bridge.py /usr/local/bin/bridge
ln -s iproute2mac/src/ss.py /usr/local/bin/ss

The clone puts the repository in /usr/local/iproute2mac, and the three symlinks give you ip, bridge and ss as commands. There is no compilation step, because the tools are Python scripts.

Two more routes exist and both are maintained by people outside the core project. MacPorts has a port at ports.macports.org with its Portfile in the macports-ports repository, maintained by i0ntempest. Nix has the package in nixpkgs under pkgs/by-name/ip/iproute2mac, maintained by jiegec. The spread of maintainers across four package systems is a good sign for a utility that has to keep working as the underlying macOS tools change.

JSON and colour output are the reason to use a wrapper in scripts

The bridge and ss commands cover less ground than ip, and that is by design. The bridge module lists bridge interfaces, and can show a single one. The ss module covers sockets: all sockets, listening sockets, TCP only, UDP only, IPv4 only, IPv6 only, socket statistics with -s, and all sockets including listening ones with -a. The v1.7.4 release added the -H flag for suppressing the header, and v1.7.6 changed ss -l so it shows only LISTENING sockets, which was a behaviour fix in response to a reported issue.

The output options are where this tool earns its keep in automation. Every command supports JSON output, and the list covers the cases a script actually needs.

bash
ip -j link show
ip -j addr show
ip -j neigh show
ip -j route show
bridge -j -p link show
ss -j
bash
ip -color link show
ip -color=always link show
ip -color=auto link show
ip -color=never link show

The first block produces machine-readable output for every module, and the second controls colouring, with always, auto and never as the three modes. The same options work for bridge and ss, as the README states. Colour matters less than it sounds, because auto means the tool decides based on the output stream, and a pipe to a file or to jq will not get escape codes, which is the behaviour a script needs.

For interactive work, the brief and unfiltered forms are what Linux users expect, including ip -br for the one-line-per-interface format, ip link show en0 for a single interface, ip addr add 10.0.0.5/24 dev en0, ip route get 8.8.8.8 and ip route show default.

Writing to the system is the risky half of the surface

A read-only wrapper is easy to trust. The write operations are where care is needed, and they are all in the same interface: ip link set dev en0 down to shut an interface, ip link set dev en0 up to bring it back, ip addr add and ip addr del for addresses, and ip route add, replace and del for routes, including a default route.

The link module also handles MAC addresses, and this is the part that can surprise you. Beyond setting a custom address such as ip link set dev en0 address 00:12:34:45:78:90, there are two symbolic forms, ip link set en0 address random and ip link set en0 address factory, which ask macOS for a random hardware address or restore the factory one. The second is the undo button for the first, and knowing it exists saves a trip to System Settings or a manual rewrite of the network interface configuration.

The route commands are the ones most likely to break a working network, since ip route add default nexthop 10.0.0.1 changes where traffic goes. The safer read-only companions are ip route get 8.8.8.8, which asks the routing table what path a destination would take, and ip route show default.

The underlying mechanism for all of this is shelling out. The changelog for v1.7.5 records a migration to subprocess.run(), and the README points at the native tools for anything advanced. So every command ultimately calls into the macOS networking utilities, which means the wrapper inherits their permissions model and their error messages. A failure that says a route cannot be added is macOS refusing, not the Python layer, and that is the behaviour you would get from the native tools anyway.

MIT, Python 3.10, and a release every few months

The licence is MIT, which is permissive. You can use, modify and redistribute it, including inside commercial or closed-source tooling, provided the copyright notice and the licence text are retained. The repository has a LICENSE file at the root, an AUTHORS file, a CONTRIBUTING.md and a SECURITY.md. The security policy matters here, because the tool takes administrative actions on a machine's network configuration and a responsible disclosure path is worth reading before you file anything. This is a licensing fact rather than legal advice.

The packaging story is modern. The project uses a pyproject.toml with a standard project table, and a uv.lock file, so the dependency set is locked in the uv format. The absence of a dependencies list in pyproject.toml suggests the tool leans on the standard library and the macOS command line rather than on third-party Python packages, which keeps the install small.

Maintenance looks healthy. The repository is not archived, the default branch is master, and the last push was on 2026-10-06, the same day as the v1.7.6 tag. Before that came v1.7.5 on 2026-08-14 and v1.7.4 on 2026-03-31, so roughly every two to three months. The changelog in the README is maintained per version, with a HEAD section for unreleased work, and the entries are specific enough to be useful, referencing the issue numbers behind each fix.

The upgrade cost for a Homebrew user is one brew upgrade. For the manual install, it is a git pull plus re-pointing the symlinks if the file names ever change, which they have not.

The alternative is the native macOS tools, which is what the README recommends

The honest alternative is to skip the wrapper and use the macOS utilities directly, which is exactly what the README advises for advanced usage: netstat, ifconfig, ndp, arp, route and networksetup. The difference in approach is that those tools expose the real macOS behaviour, with no translation layer between you and the system, and they are always present and always match your OS version.

The cost of that route is the syntax. Every command differs from its Linux counterpart, the output formats are their own, and a script written for Linux has to be rewritten per platform. A team that maintains one script for a mixed fleet faces that cost on every change, which is exactly the friction iproute2mac exists to reduce.

The other alternative is not to use macOS for the job at all. A Linux host over SSH gives you the real iproute2 with full compatibility and no wrapper, and for anything touching switches, routers or containers that is often the better answer. The trade is that the machine you are administering is no longer the machine you are sitting at.

The middle position, which is what the README actually argues for, is to use the wrapper for the basic configuration and debugging tasks it covers well, and to drop to the native tools the moment you need behaviour the wrapper does not reproduce. The example of IPv6 neighbour scoping is the pattern: the wrapper covers the common case, and the gap is documented so you know when to leave it.

Editorial conclusion

iproute2mac fits a macOS administrator who already speaks iproute2 and wants the same commands on a Mac, especially in scripts where a one-line change is cheaper than rewriting the logic for netstat and ifconfig. It does not fit a team that needs full iproute2 fidelity, because the README states the output is not fully compatible and lists the gaps, including neighbour listings for IPv6 on a specific interface. Before adopting it, run the same ip and ss invocations on a Linux host and on the Mac and diff the output, and for anything beyond basic configuration keep netstat, ifconfig, ndp, arp, route and networksetup in reach, as the README advises.

Frequently asked questions

How do I install iproute2mac on macOS?

The preferred route is Homebrew with brew install iproute2mac, and the formula is maintained by the project author. There is also a manual install from HEAD that symlinks src/ip.py, src/bridge.py and src/ss.py into /usr/local/bin, plus maintained MacPorts and Nix packages.

Is iproute2mac fully compatible with Linux iproute2?

No. The README states that provided functionality is limited and command output is not fully compatible with iproute2, and it directs advanced usage to netstat, ifconfig, ndp, arp, route and networksetup directly. For example, IPv6 NDP neighbours cannot currently be shown for a specific interface, and flushing the route cache is a no-op on macOS.

Can iproute2mac output JSON for scripting?

Yes. The README lists JSON output for every module: ip -j link show, ip -j addr show, ip -j neigh show, ip -j route show, bridge -j -p link show and ss -j. Colour output is also configurable with the -color family, including always, auto and never.

Does iproute2mac work with ss on macOS?

Yes, the ss command shows all sockets, listening sockets with -l, TCP with -t, UDP with -u, IPv4 with -4, IPv6 with -6, statistics with -s and all sockets including listening with -a. Version 1.7.6 changed ss -l so it shows only LISTENING sockets, and 1.7.4 added the -H no-header flag.

What are the requirements to run iproute2mac?

The pyproject.toml requires Python 3.10 or newer, and the project is written in Python with no separate build step. The macOS command line utilities that the wrapper drives must be present, since the native tools are what perform the actual work.

Official sources

  1. brona/iproute2mac on GitHub
  2. Issues
  3. License: MIT
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/brona-iproute2mac.svg)](https://hysenlabs.com/projects/brona-iproute2mac)

Was this useful?