Metadata-Version: 2.4
Name: usb-reverse-tether
Version: 0.1.0
Summary: Share a PC's internet with a USB-connected Android phone (reverse tethering over adb, no root) using gnirehtet
Project-URL: Homepage, https://github.com/Pandiyarajk/usb-reverse-tether
Project-URL: Repository, https://github.com/Pandiyarajk/usb-reverse-tether
Project-URL: Issues, https://github.com/Pandiyarajk/usb-reverse-tether/issues
Author-email: Pandiyaraj Karuppasamy <pandiyarajk@live.com>
License-Expression: MIT
License-File: LICENSE
Keywords: adb,android,gnirehtet,internet-sharing,reverse-tethering,tethering,usb,vpn
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: System Administrators
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: System :: Networking
Classifier: Topic :: Utilities
Requires-Python: >=3.11
Provides-Extra: dev
Requires-Dist: build>=1.0; extra == 'dev'
Requires-Dist: mypy>=1.11; extra == 'dev'
Requires-Dist: pytest-timeout>=2.3; extra == 'dev'
Requires-Dist: pytest>=7.0; extra == 'dev'
Requires-Dist: ruff>=0.6; extra == 'dev'
Requires-Dist: twine>=4.0; extra == 'dev'
Description-Content-Type: text/markdown

# usb-reverse-tether

<!--
Author: Pandiyaraj Karuppasamy
Date: Oct-21-2026
-->

> **Disclaimer.** Provided **AS IS**, without warranty of any kind, express or implied. **Use
> entirely at your own risk.** The author accepts no liability for data loss, security incidents,
> policy violations, business interruption or any consequential damages. While it runs, every
> packet the phone sends leaves as this PC's own traffic, so the PC's network policy and monitoring
> apply to it. You are responsible for verifying which device you target, for being authorised to
> share this PC's network connection, and for the phone you connect. Not certified for regulated,
> forensic, safety-critical or high-assurance use. The
> [LICENSE](https://github.com/Pandiyarajk/usb-reverse-tether/blob/main/LICENSE) (MIT) is the
> governing text and prevails where it differs from this notice; see also
> [DISCLAIMER.md](https://github.com/Pandiyarajk/usb-reverse-tether/blob/main/DISCLAIMER.md).

Give an Android phone internet access through your PC over a USB cable (reverse tethering). The
phone needs USB debugging. **No root is needed** on the phone or the PC.

This is useful when the phone has no working Wi-Fi or SIM data, for example a test phone with
broken Wi-Fi.

Android's "USB tethering" goes the other way: the phone shares its internet with the PC. Windows
Internet Connection Sharing over USB needs a rooted phone. This tool drives
[gnirehtet](https://github.com/Genymobile/gnirehtet) v2.5.1 instead, from the authors of scrcpy.
gnirehtet is **not bundled**: it is downloaded from its GitHub release on first use and refused
unless its SHA-256 matches the value pinned in this package.

Pure Python, standard library only. Works on Windows, Linux and macOS.

---

## Contents

- [Install](#install)
- [Quick start](#quick-start)
- [1. PC setup (once per PC)](#1-pc-setup-once-per-pc)
- [2. Phone setup (once per phone)](#2-phone-setup-once-per-phone)
- [3. Commands](#3-commands)
- [4. Check that it works](#4-check-that-it-works)
- [Troubleshooting](#troubleshooting)
- [How it works](#how-it-works)
- [Limits and security](#limits-and-security)
- [Uninstall](#uninstall)
- [Measured results](#measured-results)
- [Third-party software](#third-party-software)
- [License](#license)

## Install

```bash
pipx install usb-reverse-tether      # recommended: an isolated install with the command on PATH
pip install usb-reverse-tether       # or into the current environment
```

Needs Python 3.11 or newer. There are no Python dependencies. `python -m usb_reverse_tether` works
as well as the `usb-reverse-tether` command.

## Quick start

```bash
usb-reverse-tether doctor     # read-only checks: adb, phone, settings, cached gnirehtet, java
usb-reverse-tether run        # one phone attached; Ctrl+C stops it
usb-reverse-tether stop       # stop the phone client and remove the adb tunnel
```

The first `run` downloads gnirehtet (a zip under 1 MB), installs the small Gnirehtet app on
the phone and asks once, on the phone, to allow a VPN connection. Tap **OK**.

---

## 1. PC setup (once per PC)

### 1.1 Requirements

- Windows 10 or 11, Linux (x86-64 for the default build) or macOS.
- Python 3.11 or newer.
- A **data-capable** USB cable. Charge-only cables are common and adb will not see the phone
  through them.
- The PC has working internet: Wi-Fi, Ethernet or VPN.
- **macOS, ARM Linux, or `--java`:** a Java 8+ runtime (`java` on `PATH`). gnirehtet publishes no
  Rust build for those platforms, so the Java build is used automatically there.

### 1.2 Install adb (Android platform-tools)

The tool looks for adb in this order:

1. the `ADB` environment variable (full path to the adb executable);
2. `$ANDROID_HOME/platform-tools` and `$ANDROID_SDK_ROOT/platform-tools`;
3. the Android SDK default location, where **Android Studio** installs it:
   - Windows: `%LOCALAPPDATA%\Android\Sdk\platform-tools\adb.exe`
   - macOS: `~/Library/Android/sdk/platform-tools/adb`
   - Linux: `~/Android/Sdk/platform-tools/adb`
4. `adb` on `PATH`.

Without Android Studio:

- **Windows:** download **SDK Platform-Tools for Windows** from
  <https://developer.android.com/tools/releases/platform-tools>, extract it (for example to
  `C:\platform-tools`), then add that folder to `PATH`: Start, "Edit environment variables for
  your account", `Path`, **New**, `C:\platform-tools`. Open a **new** terminal afterwards.
- **macOS:** `brew install --cask android-platform-tools`, or the zip from the page above.
- **Linux:** your distribution's package (`sudo apt install adb`, `sudo dnf install android-tools`),
  or the zip from the page above.

Check it: `adb version`.

### 1.3 USB driver and permissions

- **Windows, most phones:** Windows 10/11 installs a working driver automatically. Check with
  `adb devices` once the phone is set up (step 2).
- **Windows, phone never appears** (a Samsung, or an older phone): install the maker's USB driver,
  or the **Google USB Driver** from Android Studio's SDK Manager. In Device Manager, the phone
  should show under "Android Device" as **Android Composite ADB Interface**.
- **Linux:** if `adb devices` shows `no permissions`, install your distribution's
  `android-udev-rules` (or add a udev rule for the phone's vendor ID), add yourself to the
  `plugdev` group, log out and in, and replug.
- **macOS:** no driver needed.

### 1.4 Fetch gnirehtet ahead of time (optional)

```bash
usb-reverse-tether fetch           # the build for this platform
usb-reverse-tether fetch --java    # the Java build
```

`run` does this automatically when needed. Builds are kept in the per-user cache:

| OS | Cache folder |
|---|---|
| Windows | `%LOCALAPPDATA%\usb-reverse-tether\Cache` |
| macOS | `~/Library/Caches/usb-reverse-tether` |
| Linux | `$XDG_CACHE_HOME/usb-reverse-tether`, else `~/.cache/usb-reverse-tether` |

### 1.5 Desktop shortcuts (Windows only)

```bash
usb-reverse-tether shortcuts
```

This creates two icons on your desktop:

- **USB Reverse Tether** (globe icon): opens a console window that runs the tether. **Leave the
  window open** while you need internet on the phone. Closing it, or pressing Ctrl+C, ends the
  tether. Errors stay readable in the window.
- **USB Reverse Tether - Stop** (red X icon): stops the tether on the phone, then closes after 5
  seconds.

Options:

- **Several phones attached:** bake one in with `usb-reverse-tether shortcuts --serial <serial>`.
  Find the serial with `adb devices`.
- **Remove the shortcuts:** `usb-reverse-tether shortcuts --remove`.
- **Another folder:** `--dir <folder>` instead of the desktop.
- **After reinstalling Python or moving the environment:** run it again. The shortcuts run the
  Python interpreter that created them (`<python> -m usb_reverse_tether`) by absolute path.

The shortcuts are written through Windows PowerShell and the WScript.Shell COM object; nothing else
is installed and the execution policy is not changed.

### 1.6 Firewall

Nothing to open. The relay listens on `127.0.0.1:31416` (this PC only), and the phone reaches it
through adb, not through the network.

---

## 2. Phone setup (once per phone)

### 2.1 Turn on Developer options

1. Open **Settings**, then **About phone**.
2. Tap **Build number** 7 times. On Xiaomi/Redmi/POCO, tap **MIUI version** (or **OS version**)
   instead. Enter your PIN if asked.
3. You will see "You are now a developer".

**Where Developer options lives:**

| Phone | Path |
|---|---|
| Pixel, Nothing, most phones | Settings, System, Developer options |
| Xiaomi / Redmi / POCO | Settings, Additional settings, Developer options |
| Samsung | Settings, Developer options (near the bottom) |

### 2.2 Turn on USB debugging

1. In Developer options, turn on **USB debugging**.
2. Plug the phone into the PC.
3. On the phone, the **"Allow USB debugging?"** prompt appears. Tick **Always allow from this
   computer**, then tap **Allow**.
4. Check on the PC: `adb devices` (or `usb-reverse-tether doctor`) must list the phone as `device`.
   - `unauthorized` means the prompt was not accepted. Unplug, plug back in, and accept it.
   - `offline` means adb lost the connection. Replug, or run `adb kill-server` and try again.
   - Nothing listed means a cable or driver problem (see 1.1 and 1.3).

### 2.3 Xiaomi / Redmi / POCO only (MIUI, HyperOS)

In Developer options, also turn on:

- **Install via USB**. Without it, the first run fails with
  `INSTALL_FAILED_USER_RESTRICTED: Install canceled by user`.
- **USB debugging (Security settings)**. Without it, starting fails with a
  `WRITE_SECURE_SETTINGS` permission denial.

MIUI allows these only with a **SIM card inserted** and a **Mi account signed in**. Each one shows a
warning with a countdown; accept it. `run` and `doctor` detect MIUI and HyperOS and remind you.

### 2.4 Android 14 and newer (other makers)

If starting fails with `WRITE_SECURE_SETTINGS`, turn **off** **Disable permission monitoring** in
Developer options, if your phone has it.

### 2.5 First run on a phone

1. Start the tether (section 3).
2. gnirehtet installs the small **Gnirehtet** app on the phone.
3. The phone asks **"Connection request: Gnirehtet wants to set up a VPN connection"**. Tap **OK**.
   This happens only once per phone, or again after the app is reinstalled.
4. A **key or VPN icon** appears in the status bar, plus a "Reverse tethering enabled"
   notification.

### 2.6 Optional, for apps that wait for Wi-Fi

Android treats this connection as **metered**, like mobile data (see
[Limits](#limits-and-security)). Apps that only download "over Wi-Fi" will wait. For the Play
Store: Play Store, profile picture, **Settings**, **Network preferences**, **App download
preference**, then choose **Over any network**. Do the same for auto-update if you want updates to
run.

---

## 3. Commands

```bash
usb-reverse-tether run                        # exactly one phone attached; Ctrl+C stops it
usb-reverse-tether run --serial 6b8396a30406  # pick a phone when several are attached
usb-reverse-tether run --dns 10.0.0.53        # other DNS server(s), comma-separated IPv4
usb-reverse-tether run --java                 # Java relay instead of Rust (needs java on PATH)
usb-reverse-tether stop [--serial S] [--java] # stop the phone client and remove the tunnel
usb-reverse-tether doctor [--serial S]        # read-only checks
usb-reverse-tether fetch [--java]             # download and verify gnirehtet ahead of time
usb-reverse-tether shortcuts [--serial S] [--remove] [--dir D]   # Windows desktop shortcuts
usb-reverse-tether --help                     # full help, with the disclaimer
```

Add `-v` before the command for debug logging (`usb-reverse-tether -v run`).

**run** picks the only attached device unless `--serial` is given, prints a notice that the phone's
traffic will leave as the PC's traffic, detects MIUI/HyperOS and prints the two-toggle hint, then
runs `gnirehtet run <serial> -d <dns>` with its output streamed to the console. Ctrl+C stops the
relay and the phone client.

**DNS:** the default is `8.8.8.8` (Google). Use `--dns` with your network's DNS server if public
DNS is blocked, for example on some company networks.

**doctor** never changes anything on the phone. It reports: adb path and version; every attached
device and its state, with what to do about `unauthorized`, `offline` and `no permissions`; the
Android version; MIUI/HyperOS with the two toggles; whether the Gnirehtet app is installed; whether
the cached gnirehtet build is present and still matches its verified zip; and whether `java` is
available. It exits 1 if anything is marked `FAIL`.

**Exit codes:** 0 ok (including Ctrl+C after a run), 1 adb or device not found, 2 download,
checksum or extract failure, or unsupported on this platform. Any other code is gnirehtet's own.

### After a phone reboot or unplug

The tunnel does not survive a reboot or unplug. Start it again (shortcut, or Ctrl+C and `run`).
Once the app is installed this takes about 2 seconds.

---

## 4. Check that it works

1. For a clean test, turn **off** the phone's Wi-Fi and mobile data so the tether is its only
   network. On a dual-SIM phone, LTE can stay up even when one SIM's data looks off. Run
   `adb shell svc data disable` to be sure, and `adb shell svc data enable` afterwards.
2. Open a website in the phone's browser. It should load, and the console on the PC logs lines
   like `TcpConnection: 10.0.0.2:xxxxx -> <server>:443 Open`.
3. **Do not test with `ping`.** ICMP is not relayed, so `ping` fails even when the tether works.

Check from the PC:

```bash
adb shell dumpsys connectivity | grep "type: VPN"   # tunnel network is up (PowerShell: Select-String)
adb reverse --list                                  # shows localabstract:gnirehtet tcp:31416
```

---

## Troubleshooting

| Symptom | Cause | Fix |
|---|---|---|
| `Need exactly one attached device, found 0` | Phone not visible to adb | Check the cable, the USB debugging prompt and `adb devices` (2.2); `doctor` explains each state |
| `Need exactly one attached device, found 2` | Several phones or emulators | Use `--serial`, or `shortcuts --serial` |
| `adb not found` | adb not installed or not where the tool looks | Section 1.2, or set `ADB` to its full path |
| `no permissions` (Linux) | No udev rule for the phone | Section 1.3 |
| `INSTALL_FAILED_USER_RESTRICTED` | MIUI blocks installs over USB | Turn on **Install via USB** (2.3) |
| `WRITE_SECURE_SETTINGS` / `Permission Denial` | MIUI security setting, or Android 14 permission monitoring | 2.3 or 2.4 |
| `Checksum mismatch` | The download was corrupted or replaced | It was deleted; run again. If it repeats, do not work around it |
| `java not found on PATH` | macOS, ARM Linux or `--java` without Java | Install a Java 8+ runtime |
| Hangs at "Starting client", no VPN prompt | Known gnirehtet issue #515 | `adb uninstall com.genymobile.gnirehtet`, then start again and accept the prompt |
| VPN icon shows but nothing loads | Issues #531/#587, or a stale tunnel after replugging | `stop`, start again; if it persists, use `--java` |
| `device '<serial>' not found` while running | The phone rebooted or was unplugged | Plug in, wait for boot, start again |
| Play Store says **Pending** or "Waiting for Wi-Fi" | The tether counts as metered | 2.6: App download preference "Over any network" |
| An app shows a server error such as YouTube `[400]`, but the browser works | The app itself is outdated; the network is fine | Update the app from the Play Store (after 2.6) |
| Certificate errors on every HTTPS site | The PC is behind a TLS-inspecting proxy (company network) | Use a network without inspection, or install that proxy's root CA on the phone (issue #586) |
| Some sites fail, others load | IPv6-only sites (the tether is IPv4 only) or blocked public DNS | Try `--dns <your DNS>` |

---

## How it works

```
phone app (VpnService, "Gnirehtet")
   | captures all phone traffic as IP packets
   v
adb reverse  localabstract:gnirehtet -> tcp:31416   (over the USB cable)
   |
   v
relay on this PC, 127.0.0.1:31416 (gnirehtet)
   | opens ordinary TCP/UDP sockets
   v
the PC's own internet connection (Wi-Fi, Ethernet, VPN)
```

The phone's traffic leaves as this PC's own traffic, so no routing or Internet Connection Sharing
is set up on the PC. The tool:

1. finds adb and the phone;
2. makes sure the pinned gnirehtet build is in the cache: it downloads the release zip to a
   temporary folder, checks its SHA-256 against the pinned value (and deletes it on a mismatch),
   checks that no zip entry would land outside the target folder, extracts it, and only then moves
   it into place;
3. runs `gnirehtet run <serial> -d <dns>` with `ADB` and `GNIREHTET_APK` set. That installs the app
   if needed, sets up `adb reverse`, starts the VPN on the phone and runs the relay until Ctrl+C.
   Ctrl+C stops both.

Which gnirehtet build is used:

| Platform | Build |
|---|---|
| Windows (x64; ARM64 through emulation) | `gnirehtet-rust-win64-v2.5.1.zip` |
| Linux x86-64 | `gnirehtet-rust-linux64-v2.5.1.zip` |
| macOS, other Linux CPUs, `--java` anywhere | `gnirehtet-java-v2.5.1.zip` (runs with `java -jar`) |

---

## Limits and security

- **IPv4 only:** TCP and UDP, no IPv6, no ICMP (`ping`). There is no inbound port forwarding to
  the phone.
- **Always metered, cannot be changed without root.** "Wi-Fi only" downloads wait (see 2.6).
  Android (AOSP) marks any VPN with no physical network underneath as metered. The code checked
  was `Vpn.applyUnderlyingCapabilities` on Android 10 and
  `ConnectivityService.applyUnderlyingCapabilities` on Android 12 to 15. With no underlying
  network, both take the `if (!hadUnderlyingNetworks) { metered = true; }` branch. So these do not
  help:
  - patching gnirehtet to call `setMetered(false)` or `setUnderlyingNetworks(...)`;
  - `cmd netpolicy set metered-network`, which only applies to saved Wi-Fi networks.

  The fix has to be per app, such as the Play Store's "Over any network" setting.
- **Needs the cable and the console:** the tunnel exists only while the relay runs and the cable
  is in. A reboot or unplug drops it, and with the phone's own Wi-Fi and data off it then has no
  internet at all.
- **PC network policy applies:** all of the phone's traffic leaves as this PC's traffic, so your
  network's proxy, TLS inspection, monitoring and acceptable-use rules cover it. Check that you are
  allowed to do this on a company network.
- **The phone can reach this PC's localhost:** `10.0.2.2` on the phone maps to `localhost` on this
  PC, so any service bound to loopback here is reachable from the phone.
- **Unauthenticated relay:** it listens on `127.0.0.1:31416` only, so the LAN cannot reach it, but
  any local process on the PC could use it while it runs.
- **Unmaintained upstream:** gnirehtet's last release (v2.5.1) was in 2023. It still works, but
  bugs on new Android versions will not be fixed upstream.

---

## Uninstall

```bash
usb-reverse-tether stop
adb uninstall com.genymobile.gnirehtet     # removes the app from the phone
usb-reverse-tether shortcuts --remove      # Windows, if you created them
pipx uninstall usb-reverse-tether          # or: pip uninstall usb-reverse-tether
```

Then delete the cache folder (see 1.4). Optionally turn off USB debugging on the phone.

---

## Measured results

Measured on Oct-21-2026 with a Redmi 7A (Android 10, MIUI 12.5), PC on Wi-Fi (Windows 11), with
the pinned gnirehtet v2.5.1 Rust build. Most results come from this tool's PowerShell predecessor,
which runs the same gnirehtet commands.

**This package on the same phone:** `usb-reverse-tether` 0.1.0 was installed from the wheel and run
against the phone.

- `run` connected in 3 s.
- With the tunnel as the phone's only network, a Wikipedia page loaded over HTTPS. The relay log
  showed the connection.
- `stop` exited 0, removed the `adb reverse` forward and closed the VPN.
- `doctor` passed every check.

**Setup**
- **First run:** failed with `INSTALL_FAILED_USER_RESTRICTED` until both MIUI toggles (2.3) were on.
- **After that:** the app install, start and first connection took 14 s. Later starts took about
  2 s.

**What worked**
- **Browser:** with the phone's Wi-Fi and mobile data off, https://www.wikipedia.org loaded and a
  YouTube video played in Chrome.
- **Downloads:** Play Store and MIUI app updates downloaded.
- **Shortcuts:** both desktop shortcuts of the PowerShell version worked.

**What needed attention**
- **YouTube app:** version 16.06.34 (2021) showed "There was a problem with the server [400]". The
  network was fine; the app was too old. Its Play Store update sat at **Pending** for about 2
  minutes, then installed (21.40.165). After that the app loaded normally over the tether.

---

## Third-party software

[gnirehtet](https://github.com/Genymobile/gnirehtet) by Genymobile, licensed under the
[Apache License 2.0](https://github.com/Genymobile/gnirehtet/blob/master/LICENSE). It is **not
bundled** with this package. On first use the tool downloads the official v2.5.1 release asset
from <https://github.com/Genymobile/gnirehtet/releases/tag/v2.5.1> and verifies it against these
SHA-256 values:

| File | SHA-256 |
|---|---|
| `gnirehtet-rust-win64-v2.5.1.zip` | `7f5b1063e7895182aa60def1437e50363c3758144088dcd079037bb7c3c46a1c` |
| `gnirehtet-rust-linux64-v2.5.1.zip` | `dee55499ca4fef00ce2559c767d2d8130163736d43fdbce753e923e75309c275` |
| `gnirehtet-java-v2.5.1.zip` | `816748078fa6a304600a294a13338a06ac778bcc0e57b62d88328c7968ad2d3a` |

This project is not affiliated with or endorsed by Genymobile.

## License

MIT, see [LICENSE](https://github.com/Pandiyarajk/usb-reverse-tether/blob/main/LICENSE). The
LICENSE is the governing text; [DISCLAIMER.md](https://github.com/Pandiyarajk/usb-reverse-tether/blob/main/DISCLAIMER.md)
is a plain-language summary of it and of the risks.
