Genymobile / gnirehtet

Gnirehtet provides reverse tethering for Android
Apache License 2.0
6.13k stars 565 forks source link

Make gnirehtet run whenever I plug in my device #49

Closed twoi closed 6 years ago

twoi commented 6 years ago

Currently, I have to run the command gnirehtet each time I connect my phone to my computer. Is there a way to start the gnirehtet server so it waits in the background and activates reverse tethering every time I plug my phone in?

Biswa96 commented 6 years ago

I found this type of feature in an app called Reverse Tethering NoRoot. But that app includes ads and paid version. It's server exe app in PC constantly running background with adb devices -l command (with small L).

adb.exe devices -l
adb fork-server server
adb.exe -s List forward tcp:port tcp:port
adb.exe -s List shell "pm grant <app_name> android.permission.WRITE_SECURE_SETTINGS"
conhost.exe 0x4

<app_name> are

Hope this info may help.

rom1v commented 6 years ago

It's server exe app in PC constantly running background with adb devices -l command

Yes, that's what I would like to avoid (cf https://github.com/Genymobile/gnirehtet/issues/47#issuecomment-335411761). At least, it won't be the default behavior.

But maybe as an alternative to gnirehtet run, we could add gnirehtet autoor something that provides this behavior.

twoi commented 6 years ago

Thanks @Biswa96 for sketching it out for lazy me.

There sure are more elegant ways to go about this, but in the meantime, the following script does the job for me (here on linux).

On startup, it fires up gnirehtet relay in the background and then, polling adb devices -l, simply does a gnirehtet start [serial] every time a device is plugged in.

#!/usr/bin/env clojure

(import 'java.lang.Runtime)

(def home-dir (java.io.File. (System/getProperty "user.home")))
(def gnirehtet-dir (java.io.File. home-dir "gnirehtet-java"))

(defn- bash-exec
  ([cmd-line] (bash-exec cmd-line nil))
  ([cmd-line home-dir]
   (let [proc (. (Runtime/getRuntime) exec (into-array [ "bash" "-c" cmd-line]) nil gnirehtet-dir)
         proc-in (java.io.BufferedReader. (java.io.InputStreamReader. (.getInputStream proc)))
         proc-err (java.io.BufferedReader. (java.io.InputStreamReader. (.getErrorStream proc)))]
     (concat (line-seq proc-in) (line-seq proc-err)))))

(defn- bash-exec-and-out
  [cmd-line home-dir]
  (doseq [line (bash-exec cmd-line home-dir)]
    (println line)))

(future (bash-exec-and-out "./gnirehtet relay" gnirehtet-dir))

(loop [last-device-set nil]
  (let [device-set (set (bash-exec "adb devices -l|sed -nre 's/^([0-9A-Za-z]+) +device .*$/\\1/p'"))
        new-devices (apply disj device-set last-device-set)]
    (doseq [device new-devices]
      (println "Newly connected device " device)
      (bash-exec-and-out (str "./gnirehtet start " device) gnirehtet-dir))
    (Thread/sleep 1000)
    (recur device-set)))
rom1v commented 6 years ago

Great, it made me discover some clojure code :)

It works for me (I just changed the gnirehtet-dir to "."). You can also replace adb devices -l by adb devices here.

CameronNemo commented 6 years ago

You can do this a lot more easily with udev rules than a daemon that polls adb. Check out the android-udev package on Arch, it matches vendor IDs to detect when an Android device is plugged in.

rom1v commented 6 years ago

@CameronNemo Yes, but:

twoi commented 6 years ago

I rewrote above script, chiefly in order to remove the dependence on (the UNIX specific) external bash and sed commands. @rom1v This version also features something Java is lacking: #"regex literals"

#!/usr/bin/env clojure

(def home-dir (java.io.File. (System/getProperty "user.home")))
(def gnirehtet-dir (java.io.File. home-dir "gnirehtet-java"))

(defn- exec
  ([cmd-line-args] (exec cmd-line-args nil))
  ([cmd-line-args home-dir]
   (let [proc (. (java.lang.Runtime/getRuntime) exec (into-array cmd-line-args) nil home-dir)
         proc-in (java.io.BufferedReader. (java.io.InputStreamReader. (.getInputStream proc)))
         proc-err (java.io.BufferedReader. (java.io.InputStreamReader. (.getErrorStream proc)))]
     (concat (line-seq proc-in) (line-seq proc-err)))))

(defn- gnirehtet
  [& cmd-line-args]
  (doseq [line (exec (concat ["java" "-jar" "gnirehtet.jar"] cmd-line-args) gnirehtet-dir)]
    (println line)))

(defn- replaced-only
  [s match replacement]
  (let [result (clojure.string/replace s match replacement)]
    (if (not= result s)
      result)))

(future (gnirehtet "relay"))

(loop [last-device-set nil]
  (let [adb-devices-out (exec ["adb" "devices"])
        device-set (set (filter identity (map #(replaced-only % #"^(\w+)\s+device$" "$1") adb-devices-out)))
        new-devices (apply disj device-set last-device-set)]
    (doseq [device new-devices]
      (println "Newly connected device" device)
      (gnirehtet "start" device))
    (Thread/sleep 1000)
    (recur device-set)))
doedel commented 6 years ago

Hello I am using gnirehtet on a Linux server.

If you use it frequently udev rules does the trick pretty easy on linux. I fire up the relay server in a tmux session (so I can look whats going on :-) when my server starts and then have the start and stop command executed on usb unplugging or replugging. Only down side is, you have to configure each device manually, but on the other hand, when it is done, you can even connect multiple devices automatically!

rom1v commented 6 years ago

Could you provide the udev rules for people which are interested in the same behavior, please?

CameronNemo commented 6 years ago

https://wiki.archlinux.org/index.php/Android#Adding_udev_Rules

Then add another line with a command using RUN+=

SUBSYSTEM=="usb",ATTR{idVendor}=="[VENDOR ID]",ATTR{idProduct}=="[PRODUCT ID]",RUN+="/full/path/to/gnirehtet start"
tango25001 commented 6 years ago

I did this with my Raspi - runs perfect with the ARM library (thx again :-) )

In /etc/udev/rules.d I put the files 85-1start.rules containing

ACTION=="add", SUBSYSTEM=="usb", ATTRS{idVendor}=="XXXX", ATTRS{idProduct}=="XXXX", RUN+="/home/XX/RT/start1.sh"

86-1stop.rules containing

ACTION=="remove", SUBSYSTEM=="usb", ATTRS{idVendor}=="XXXX", ATTRS{idProduct}=="XXXX", RUN+="/home/XX/RT/stop1.sh"

Both ATTRS{idVendor}=="XXXX" and ATTRS{idProduct}=="XXXX" you get for each device with lsusb when it is plugged

REBOOT to get udev reload

the stop1.sh contains

#!/bin/bash
/home/c2/RT/gnirehtet stop SERIAL

the start1.sh contains

#!/bin/bash
sleep 5
/home/c2/RT/gnirehtet start SERIAL

Further when my raspi starts I have the relay server just started automatically.

With that, just plug the device and after 5 secs it is connected. unplugging and the service ist stopped replug youre device and your back online.

Hope this explains everything

rom1v thank you very very much for the great work and especially for the ARM Binary :-)

rom1v commented 6 years ago

I implemented the feature, see https://github.com/Genymobile/gnirehtet/issues/47#issuecomment-363545799.