diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl index 5d5d2b384e040..154a5a59bf78f 100644 --- a/core/java/android/os/INetworkManagementService.aidl +++ b/core/java/android/os/INetworkManagementService.aidl @@ -177,6 +177,18 @@ interface INetworkManagementService */ String[] getDnsForwarders(); + /** + * Enables unidirectional packet forwarding from {@code fromIface} to + * {@code toIface}. + */ + void startInterfaceForwarding(String fromIface, String toIface); + + /** + * Disables unidirectional packet forwarding from {@code fromIface} to + * {@code toIface}. + */ + void stopInterfaceForwarding(String fromIface, String toIface); + /** * Enables Network Address Translation between two interfaces. * The address and netmask of the external interface is used for diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java index 6719aa6f5707c..8c56c8c5f0574 100644 --- a/services/core/java/com/android/server/NetworkManagementService.java +++ b/services/core/java/com/android/server/NetworkManagementService.java @@ -1259,6 +1259,27 @@ public class NetworkManagementService extends INetworkManagementService.Stub return filtered; } + private void modifyInterfaceForward(boolean add, String fromIface, String toIface) { + final Command cmd = new Command("ipfwd", add ? "add" : "remove", fromIface, toIface); + try { + mConnector.execute(cmd); + } catch (NativeDaemonConnectorException e) { + throw e.rethrowAsParcelableException(); + } + } + + @Override + public void startInterfaceForwarding(String fromIface, String toIface) { + mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); + modifyInterfaceForward(true, fromIface, toIface); + } + + @Override + public void stopInterfaceForwarding(String fromIface, String toIface) { + mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); + modifyInterfaceForward(false, fromIface, toIface); + } + private void modifyNat(String action, String internalInterface, String externalInterface) throws SocketException { final Command cmd = new Command("nat", action, internalInterface, externalInterface); diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java index 9566f9396d182..5ff7022647fc5 100644 --- a/services/core/java/com/android/server/connectivity/Tethering.java +++ b/services/core/java/com/android/server/connectivity/Tethering.java @@ -980,6 +980,12 @@ public class Tethering extends BaseNetworkObserver { } catch (Exception e) { if (VDBG) Log.e(TAG, "Exception in forceUpdate: " + e.toString()); } + try { + mNMService.stopInterfaceForwarding(mIfaceName, mMyUpstreamIfaceName); + } catch (Exception e) { + if (VDBG) Log.e( + TAG, "Exception in removeInterfaceForward: " + e.toString()); + } try { mNMService.disableNat(mIfaceName, mMyUpstreamIfaceName); } catch (Exception e) { @@ -1033,8 +1039,13 @@ public class Tethering extends BaseNetworkObserver { if (newUpstreamIfaceName != null) { try { mNMService.enableNat(mIfaceName, newUpstreamIfaceName); + mNMService.startInterfaceForwarding(mIfaceName, + newUpstreamIfaceName); } catch (Exception e) { Log.e(TAG, "Exception enabling Nat: " + e.toString()); + try { + mNMService.disableNat(mIfaceName, newUpstreamIfaceName); + } catch (Exception ee) {} try { mNMService.untetherInterface(mIfaceName); } catch (Exception ee) {}