Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Whitelist bundle id of apps for reverse tether #438

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public class GnirehtetActivity extends Activity {

public static final String EXTRA_DNS_SERVERS = "dnsServers";
public static final String EXTRA_ROUTES = "routes";
public static final String EXTRA_BUNDLE_IDS = "whitelistBundleIds";

private static final int VPN_REQUEST_CODE = 0;

Expand Down Expand Up @@ -59,7 +60,11 @@ private static VpnConfiguration createConfig(Intent intent) {
if (routes == null) {
routes = new String[0];
}
return new VpnConfiguration(Net.toInetAddresses(dnsServers), Net.toCIDRs(routes));
String[] whitelistBundleIds = intent.getStringArrayExtra(EXTRA_BUNDLE_IDS);
if (whitelistBundleIds == null) {
whitelistBundleIds = new String[0];
}
return new VpnConfiguration(Net.toInetAddresses(dnsServers), Net.toCIDRs(routes), whitelistBundleIds);
}

private boolean startGnirehtet(VpnConfiguration config) {
Expand Down
13 changes: 13 additions & 0 deletions app/src/main/java/com/genymobile/gnirehtet/GnirehtetService.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.ConnectivityManager;
import android.net.LinkAddress;
import android.net.LinkProperties;
Expand Down Expand Up @@ -135,6 +136,18 @@ private boolean setupVpn(VpnConfiguration config) {
}
}

if (Build.VERSION.SDK_INT >= 21) {
Log.i(TAG, "Setting whitelist bundle id");
for (String app : config.getWhitelistBundleIds()) {
Log.i(TAG, app + " traffic is being routed through USB");
try {
builder.addAllowedApplication(app);
} catch (PackageManager.NameNotFoundException e) {
Log.e(TAG, app + " not found");
}
}
}

// non-blocking by default, but FileChannel is not selectable, that's stupid!
// so switch to synchronous I/O to avoid polling
builder.setBlocking(true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,17 @@ public class VpnConfiguration implements Parcelable {

private final InetAddress[] dnsServers;
private final CIDR[] routes;
private String[] whitelistBundleIds = new String[0];

public VpnConfiguration() {
this.dnsServers = new InetAddress[0];
this.routes = new CIDR[0];
}

public VpnConfiguration(InetAddress[] dnsServers, CIDR[] routes) {
public VpnConfiguration(InetAddress[] dnsServers, CIDR[] routes, String[] whitelistBundleIds) {
this.dnsServers = dnsServers;
this.routes = routes;
this.whitelistBundleIds = whitelistBundleIds;
}

private VpnConfiguration(Parcel source) {
Expand All @@ -48,6 +50,7 @@ private VpnConfiguration(Parcel source) {
throw new AssertionError("Invalid address", e);
}
routes = source.createTypedArray(CIDR.CREATOR);
whitelistBundleIds = source.createStringArray();
}

public InetAddress[] getDnsServers() {
Expand All @@ -58,13 +61,18 @@ public CIDR[] getRoutes() {
return routes;
}

public String[] getWhitelistBundleIds() {
return this.whitelistBundleIds;
}

@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(dnsServers.length);
for (InetAddress addr : dnsServers) {
dest.writeByteArray(addr.getAddress());
}
dest.writeTypedArray(routes, 0);
dest.writeStringArray(whitelistBundleIds);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,15 @@ public class CommandLineArguments {
public static final int PARAM_DNS_SERVER = 1 << 1;
public static final int PARAM_ROUTES = 1 << 2;
public static final int PARAM_PORT = 1 << 3;
public static final int PARAM_WHITELIST_BUNDLE_IDS = 1 << 4;

public static final int DEFAULT_PORT = 31416;

private int port;
private String serial;
private String dnsServers;
private String routes;
private String whitelistBundleIds;

public static CommandLineArguments parse(int acceptedParameters, String... args) {
CommandLineArguments arguments = new CommandLineArguments();
Expand Down Expand Up @@ -69,6 +71,15 @@ public static CommandLineArguments parse(int acceptedParameters, String... args)
throw new IllegalArgumentException("Invalid port: " + arguments.port);
}
++i;
} else if ((acceptedParameters & PARAM_WHITELIST_BUNDLE_IDS) != 0 && "-b".equals(arg)) {
if (arguments.whitelistBundleIds != null) {
throw new IllegalArgumentException("Whitelist bundle ids already set");
}
if (i == args.length - 1) {
throw new IllegalArgumentException("Missing -b parameter");
}
arguments.whitelistBundleIds = args[i + 1];
++i;
} else if ((acceptedParameters & PARAM_SERIAL) != 0 && arguments.serial == null) {
arguments.serial = arg;
} else {
Expand Down Expand Up @@ -96,4 +107,8 @@ public String getRoutes() {
public int getPort() {
return port;
}

public String getWhitelistBundleIds() {
return whitelistBundleIds;
}
}
49 changes: 28 additions & 21 deletions relay-java/src/main/java/com/genymobile/gnirehtet/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ void execute(CommandLineArguments args) throws Exception {
}
},
RUN("run", CommandLineArguments.PARAM_SERIAL | CommandLineArguments.PARAM_DNS_SERVER | CommandLineArguments.PARAM_ROUTES
| CommandLineArguments.PARAM_PORT) {
| CommandLineArguments.PARAM_PORT | CommandLineArguments.PARAM_WHITELIST_BUNDLE_IDS ) {
@Override
String getDescription() {
return "Enable reverse tethering for exactly one device:\n"
Expand All @@ -99,10 +99,10 @@ String getDescription() {

@Override
void execute(CommandLineArguments args) throws Exception {
cmdRun(args.getSerial(), args.getDnsServers(), args.getRoutes(), args.getPort());
cmdRun(args.getSerial(), args.getDnsServers(), args.getRoutes(), args.getPort(), args.getWhitelistBundleIds());
}
},
AUTORUN("autorun", CommandLineArguments.PARAM_DNS_SERVER | CommandLineArguments.PARAM_ROUTES | CommandLineArguments.PARAM_PORT) {
AUTORUN("autorun", CommandLineArguments.PARAM_DNS_SERVER | CommandLineArguments.PARAM_ROUTES | CommandLineArguments.PARAM_PORT | CommandLineArguments.PARAM_WHITELIST_BUNDLE_IDS) {
@Override
String getDescription() {
return "Enable reverse tethering for all devices:\n"
Expand All @@ -112,11 +112,11 @@ String getDescription() {

@Override
void execute(CommandLineArguments args) throws Exception {
cmdAutorun(args.getDnsServers(), args.getRoutes(), args.getPort());
cmdAutorun(args.getDnsServers(), args.getRoutes(), args.getPort(), args.getWhitelistBundleIds());
}
},
START("start", CommandLineArguments.PARAM_SERIAL | CommandLineArguments.PARAM_DNS_SERVER | CommandLineArguments.PARAM_ROUTES
| CommandLineArguments.PARAM_PORT) {
| CommandLineArguments.PARAM_PORT | CommandLineArguments.PARAM_WHITELIST_BUNDLE_IDS) {
@Override
String getDescription() {
return "Start a client on the Android device and exit.\n"
Expand All @@ -126,6 +126,7 @@ String getDescription() {
+ "DNS server(s). Otherwise, use 8.8.8.8 (Google public DNS).\n"
+ "If -r is given, then only reverse tether the specified routes.\n"
+ "If -p is given, then make the relay server listen on the specified\n"
+ "If -b is given, then reverse tethering will be enabled only for specified application's bundle ids\n"
+ "port. Otherwise, use port 31416.\n"
+ "Otherwise, use 0.0.0.0/0 (redirect the whole traffic).\n"
+ "If the client is already started, then do nothing, and ignore\n"
Expand All @@ -135,10 +136,10 @@ String getDescription() {

@Override
void execute(CommandLineArguments args) throws Exception {
cmdStart(args.getSerial(), args.getDnsServers(), args.getRoutes(), args.getPort());
cmdStart(args.getSerial(), args.getDnsServers(), args.getRoutes(), args.getPort(), args.getWhitelistBundleIds());
}
},
AUTOSTART("autostart", CommandLineArguments.PARAM_DNS_SERVER | CommandLineArguments.PARAM_ROUTES | CommandLineArguments.PARAM_PORT) {
AUTOSTART("autostart", CommandLineArguments.PARAM_DNS_SERVER | CommandLineArguments.PARAM_ROUTES | CommandLineArguments.PARAM_PORT | CommandLineArguments.PARAM_WHITELIST_BUNDLE_IDS) {
@Override
String getDescription() {
return "Listen for device connexions and start a client on every detected\n"
Expand All @@ -149,7 +150,7 @@ String getDescription() {

@Override
void execute(CommandLineArguments args) throws Exception {
cmdAutostart(args.getDnsServers(), args.getRoutes(), args.getPort());
cmdAutostart(args.getDnsServers(), args.getRoutes(), args.getPort(), args.getWhitelistBundleIds());
}
},
STOP("stop", CommandLineArguments.PARAM_SERIAL) {
Expand All @@ -166,15 +167,15 @@ void execute(CommandLineArguments args) throws Exception {
}
},
RESTART("restart", CommandLineArguments.PARAM_SERIAL | CommandLineArguments.PARAM_DNS_SERVER | CommandLineArguments.PARAM_ROUTES
| CommandLineArguments.PARAM_PORT) {
| CommandLineArguments.PARAM_PORT | CommandLineArguments.PARAM_WHITELIST_BUNDLE_IDS) {
@Override
String getDescription() {
return "Stop then start.";
}

@Override
void execute(CommandLineArguments args) throws Exception {
cmdRestart(args.getSerial(), args.getDnsServers(), args.getRoutes(), args.getPort());
cmdRestart(args.getSerial(), args.getDnsServers(), args.getRoutes(), args.getPort(), args.getWhitelistBundleIds());
}
},
TUNNEL("tunnel", CommandLineArguments.PARAM_SERIAL | CommandLineArguments.PARAM_PORT) {
Expand Down Expand Up @@ -231,9 +232,9 @@ private static void cmdReinstall(String serial) throws InterruptedException, IOE
cmdInstall(serial);
}

private static void cmdRun(String serial, String dnsServers, String routes, int port) throws IOException {
private static void cmdRun(String serial, String dnsServers, String routes, int port, String whitelistBundleIds) throws IOException {
// start in parallel so that the relay server is ready when the client connects
asyncStart(serial, dnsServers, routes, port);
asyncStart(serial, dnsServers, routes, port, whitelistBundleIds);

Runtime.getRuntime().addShutdownHook(new Thread(() -> {
// executed on Ctrl+C
Expand All @@ -247,10 +248,10 @@ private static void cmdRun(String serial, String dnsServers, String routes, int
cmdRelay(port);
}

private static void cmdAutorun(final String dnsServers, final String routes, int port) throws IOException {
private static void cmdAutorun(final String dnsServers, final String routes, int port, final String whitelistBundleIds) throws IOException {
new Thread(() -> {
try {
cmdAutostart(dnsServers, routes, port);
cmdAutostart(dnsServers, routes, port, whitelistBundleIds);
} catch (Exception e) {
Log.e(TAG, "Cannot auto start clients", e);
}
Expand All @@ -260,7 +261,7 @@ private static void cmdAutorun(final String dnsServers, final String routes, int
}

@SuppressWarnings("checkstyle:MagicNumber")
private static void cmdStart(String serial, String dnsServers, String routes, int port) throws InterruptedException, IOException,
private static void cmdStart(String serial, String dnsServers, String routes, int port, String whitelistBundleIds) throws InterruptedException, IOException,
CommandExecutionException {
if (mustInstallClient(serial)) {
cmdInstall(serial);
Expand All @@ -280,12 +281,15 @@ private static void cmdStart(String serial, String dnsServers, String routes, in
if (routes != null) {
Collections.addAll(cmd, "--esa", "routes", routes);
}
if (whitelistBundleIds != null) {
Collections.addAll(cmd, "--esa", "whitelistBundleIds", whitelistBundleIds);
}
execAdb(serial, cmd);
}

private static void cmdAutostart(final String dnsServers, final String routes, int port) {
private static void cmdAutostart(final String dnsServers, final String routes, int port, final String whitelistBundleIds) {
AdbMonitor adbMonitor = new AdbMonitor((serial) -> {
asyncStart(serial, dnsServers, routes, port);
asyncStart(serial, dnsServers, routes, port, whitelistBundleIds);
});
adbMonitor.monitor();
}
Expand All @@ -296,10 +300,10 @@ private static void cmdStop(String serial) throws InterruptedException, IOExcept
"com.genymobile.gnirehtet/.GnirehtetActivity");
}

private static void cmdRestart(String serial, String dnsServers, String routes, int port) throws InterruptedException, IOException,
private static void cmdRestart(String serial, String dnsServers, String routes, int port, String whitelistBundleIds) throws InterruptedException, IOException,
CommandExecutionException {
cmdStop(serial);
cmdStart(serial, dnsServers, routes, port);
cmdStart(serial, dnsServers, routes, port, whitelistBundleIds);
}

private static void cmdTunnel(String serial, int port) throws InterruptedException, IOException, CommandExecutionException {
Expand All @@ -311,10 +315,10 @@ private static void cmdRelay(int port) throws IOException {
new Relay(port).run();
}

private static void asyncStart(String serial, String dnsServers, String routes, int port) {
private static void asyncStart(String serial, String dnsServers, String routes, int port, String whitelistBundleIds) {
new Thread(() -> {
try {
cmdStart(serial, dnsServers, routes, port);
cmdStart(serial, dnsServers, routes, port, whitelistBundleIds);
} catch (Exception e) {
Log.e(TAG, "Cannot start client", e);
}
Expand Down Expand Up @@ -408,6 +412,9 @@ private static void appendCommandUsage(StringBuilder builder, Command command) {
if ((command.acceptedParameters & CommandLineArguments.PARAM_ROUTES) != 0) {
builder.append(" [-r ROUTE[,ROUTE2,...]]");
}
if ((command.acceptedParameters & CommandLineArguments.PARAM_WHITELIST_BUNDLE_IDS) != 0) {
builder.append(" [-b BUNDLE_ID[,BUNDLE_ID2,...]]");
}
builder.append(NL);
String[] descLines = command.getDescription().split("\n");
for (String descLine : descLines) {
Expand Down
33 changes: 32 additions & 1 deletion relay-rust/src/cli_args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ pub const PARAM_SERIAL: u8 = 1;
pub const PARAM_DNS_SERVERS: u8 = 1 << 1;
pub const PARAM_ROUTES: u8 = 1 << 2;
pub const PARAM_PORT: u8 = 1 << 3;
pub const PARAM_WHITELIST_BUNDLE_IDS: u8 = 1 << 4;

pub const DEFAULT_PORT: u16 = 31416;

Expand All @@ -27,6 +28,7 @@ pub struct CommandLineArguments {
dns_servers: Option<String>,
routes: Option<String>,
port: u16,
whitelist_bundle_ids: Option<String>,
}

impl CommandLineArguments {
Expand All @@ -36,6 +38,7 @@ impl CommandLineArguments {
let mut dns_servers = None;
let mut routes = None;
let mut port = 0;
let mut whitelist_bundle_ids = None;

let mut iter = args.into_iter();
while let Some(arg) = iter.next() {
Expand Down Expand Up @@ -70,6 +73,15 @@ impl CommandLineArguments {
} else {
return Err(String::from("Missing -p parameter"));
}
} else if (accepted_parameters & PARAM_WHITELIST_BUNDLE_IDS) != 0 && "-b" == arg {
if whitelist_bundle_ids.is_some() {
return Err(String::from("Bundle id already set"));
}
if let Some(value) = iter.next() {
whitelist_bundle_ids = Some(value.into());
} else {
return Err(String::from("Missing -b parameter"));
}
} else if (accepted_parameters & PARAM_SERIAL) != 0 && serial.is_none() {
serial = Some(arg);
} else {
Expand All @@ -84,6 +96,7 @@ impl CommandLineArguments {
dns_servers,
routes,
port,
whitelist_bundle_ids
})
}

Expand All @@ -102,19 +115,24 @@ impl CommandLineArguments {
pub fn port(&self) -> u16 {
self.port
}

pub fn whitelist_bundle_ids(&self) -> Option<&str> {
self.whitelist_bundle_ids.as_deref()
}
}

#[cfg(test)]
mod tests {
use super::*;

const ACCEPT_ALL: u8 = PARAM_SERIAL | PARAM_DNS_SERVERS | PARAM_ROUTES;
const ACCEPT_ALL: u8 = PARAM_SERIAL | PARAM_DNS_SERVERS | PARAM_ROUTES | PARAM_WHITELIST_BUNDLE_IDS;

#[test]
fn test_no_args() {
let args = CommandLineArguments::parse(ACCEPT_ALL, Vec::<&str>::new()).unwrap();
assert!(args.serial.is_none());
assert!(args.dns_servers.is_none());
assert!(args.whitelist_bundle_ids.is_none());
}

#[test]
Expand Down Expand Up @@ -178,4 +196,17 @@ mod tests {
let raw_args = vec!["-r"];
assert!(CommandLineArguments::parse(ACCEPT_ALL, raw_args).is_err());
}

#[test]
fn test_bundle_id_parameter() {
let raw_args = vec!["-b", "com.myapp.xyz"];
let args = CommandLineArguments::parse(ACCEPT_ALL, raw_args).unwrap();
assert_eq!("com.myapp.xyz", args.whitelist_bundle_ids.unwrap());
}

#[test]
fn test_no_bundle_id_parameter() {
let raw_args = vec!["-b"];
assert!(CommandLineArguments::parse(ACCEPT_ALL, raw_args).is_err());
}
}
Loading