Metadata-Version: 2.4
Name: netgear-tool
Version: 0.1.0
Summary: Python SDK and CLI for Netgear Smart Managed Plus switches
Project-URL: Homepage, https://ordo-artificum.com/products/netgear-tool/
Project-URL: Repository, https://github.com/jfrancis42/netgear-tool
Project-URL: Bug Tracker, https://github.com/jfrancis42/netgear-tool/issues
Author-email: Jeff Francis <gjfrancis@protonmail.com>
License: GPL-3.0-or-later
License-File: LICENSE
Keywords: cli,managed-switch,netgear,network,sdk,switch,vlan
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: System Administrators
Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Libraries
Classifier: Topic :: System :: Networking
Requires-Python: >=3.8
Requires-Dist: requests>=2.20
Description-Content-Type: text/markdown

# netgear-tool

A Python SDK and interactive CLI for **Netgear Smart Managed Plus switches** —
no browser required.

These switches have no REST API, no SSH, and no serial console.  This project
reverse-engineers the HTTP web UI shared by the Netgear Smart Managed Plus
switch family to provide a clean Python interface and a Cisco IOS-inspired
shell.

Developed and tested on:
- Hardware: GS105Ev2 (5-port gigabit)
- Firmware: V1.6.0.24

A full test suite passes against this hardware.  Other Netgear Smart Managed
Plus switches that share the same web UI (GS108Ev3, GS116Ev2, etc.) are likely
compatible.

## Installation

```bash
pip install netgear-tool
```

After installation, the `netgear` CLI command is available and the
`netgear_tool` Python package is importable:

```python
from netgear_tool import Switch, PortSpeed, RateLimit
```

The legacy module name `netgear_switch` is still importable as a
backward-compatibility shim.

## Files

| File | Purpose |
|---|---|
| `src/netgear_tool/__init__.py` | Python SDK (`Switch` class, all read/write operations) |
| `src/netgear_tool/_cli.py` | CLI entry point (installed as `netgear` command) |
| `cli.py` | Standalone CLI script (same as `netgear` command, for direct use) |
| `netgear_switch.py` | Backward-compatibility shim (imports from `netgear_tool`) |
| `docs/sdk.md` | SDK programmer reference |
| `docs/cli.md` | CLI user guide |

## Requirements

```bash
pip install netgear-tool
```

No other dependencies beyond `requests`.  HTML parsing is done with regex
against the known page structure.

## Quick start — SDK

```python
from netgear_tool import Switch, PortSpeed, RateLimit

with Switch('192.168.0.1', password='secret') as sw:
    # Read system info
    print(sw.get_system_info())

    # Port status
    for port in sw.get_port_settings():
        print(port)

    # Configure a port
    sw.set_port(1, speed=PortSpeed.AUTO, fc_enabled=True)

    # Rate limiting
    sw.set_rate_limit(3, RateLimit.M64, RateLimit.M128)

    # 802.1Q VLANs
    sw.set_dot1q_enabled(True)
    sw.add_vlan(10)
    sw.set_vlan_membership(10, '11112')   # ports 1-4 untagged, port 5 tagged
    sw.set_port_pvid(1, 10)
```

See [docs/sdk.md](docs/sdk.md) for the full API reference.

## Quick start — CLI

```bash
netgear 192.168.0.1
# or directly:
python3 cli.py 192.168.0.1
```

```
GS105Ev2# show interfaces
GS105Ev2# configure terminal
GS105Ev2(config)# loop-detection
GS105Ev2(config)# vlan 10
GS105Ev2(config-vlan-10)# exit
GS105Ev2(config)# interface gi1
GS105Ev2(config-if-gi1)# switchport access vlan 10
GS105Ev2(config-if-gi1)# exit
GS105Ev2(config)# end
GS105Ev2# show vlan
GS105Ev2# show running-config
```

Commands can be abbreviated to their shortest unambiguous prefix (`conf t`,
`sho int`, `sw acc vl 10`, etc.).

See [docs/cli.md](docs/cli.md) for the full command reference.

## What is supported

### Read operations
- System info (firmware, MAC, IP, model, serial)
- Switch configuration (name, IP/DHCP settings)
- Port settings (speed, duplex, flow control)
- Port statistics (TX/RX byte counters, CRC errors)
- Rate limits (ingress/egress per port)
- Port mirroring
- IGMP snooping
- Loop detection
- Broadcast filtering
- QoS mode
- Power saving (Green Ethernet) — read-only; see firmware note below
- 802.1Q VLAN (IDs, membership, PVIDs)
- Cable diagnostics (TDR)

### Write operations
Everything listed above except power saving, plus:
- Factory reset
- Reboot
- Password change

## Known firmware issues

### Power saving (Green Ethernet) — GS105Ev2 firmware V1.6.0.24

`set_power_saving()` is implemented and the POST succeeds, but the switch
ignores the request — a subsequent GET always returns the hardware-controlled
state.  This appears to be a firmware limitation on the GS105Ev2: the web UI
shows the toggle but the hardware drives the actual state.  The method is
provided for completeness; it may work on other models or firmware versions.

### Ports cannot be fully removed from VLAN 1

The firmware silently rejects any attempt to set a port's VLAN 1 membership to
`'3'` (not-a-member).  Ports that are access members of another VLAN remain as
tagged members of VLAN 1 in the firmware — they simply have their PVID set to
the access VLAN so untagged ingress traffic is steered correctly.  The CLI's
`show running-config` hides this detail and displays such ports as access ports
on their PVID VLAN.

## Protocol notes

The switch uses an HTTP web UI on port 80.  All pages are at `/<name>.cgi`.

- **Reads**: `GET /<name>.cgi` with a valid `SID` cookie — state is embedded
  in HTML `<input type="hidden">` form elements (not JavaScript variables).
- **Writes**: `POST /<name>.cgi` — every POST must include a session-specific
  CSRF `hash` value extracted from the page's GET response.
- **Authentication**: `MD5(merge(password, rand))` where `rand` is a nonce
  provided in a custom HTTP response header and hidden form field.
- **Session cookie**: The `SID` value contains RFC 6265-invalid characters
  that Python's `http.cookiejar` silently drops.  The SDK works around this
  by extracting the SID from the raw `Set-Cookie` header.
- **Single-session limit**: the switch allows only one active session at a
  time.  The SDK always calls `logout()` (via the context manager) to free
  the slot.

## License

[GNU General Public License v3.0](LICENSE)
