1 /* 2 * Copyright (C) 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.net.ip; 18 19 import static android.net.INetd.IF_STATE_DOWN; 20 import static android.net.INetd.IF_STATE_UP; 21 22 import android.net.INetd; 23 import android.net.InterfaceConfigurationParcel; 24 import android.net.LinkAddress; 25 import android.net.util.SharedLog; 26 import android.os.RemoteException; 27 import android.os.ServiceSpecificException; 28 import android.system.OsConstants; 29 30 import java.net.Inet4Address; 31 import java.net.InetAddress; 32 33 34 /** 35 * Encapsulates the multiple IP configuration operations performed on an interface. 36 * 37 * TODO: refactor/eliminate the redundant ways to set and clear addresses. 38 * 39 * @hide 40 */ 41 public class InterfaceController { 42 private final static boolean DBG = false; 43 44 private final String mIfName; 45 private final INetd mNetd; 46 private final SharedLog mLog; 47 InterfaceController(String ifname, INetd netd, SharedLog log)48 public InterfaceController(String ifname, INetd netd, SharedLog log) { 49 mIfName = ifname; 50 mNetd = netd; 51 mLog = log; 52 } 53 54 /** 55 * Set the IPv4 address and also optionally bring the interface up or down. 56 */ setInterfaceConfiguration(final LinkAddress ipv4Addr, final Boolean setIfaceUp)57 public boolean setInterfaceConfiguration(final LinkAddress ipv4Addr, 58 final Boolean setIfaceUp) { 59 if (!(ipv4Addr.getAddress() instanceof Inet4Address)) { 60 throw new IllegalArgumentException("Invalid or mismatched Inet4Address"); 61 } 62 // Note: currently netd only support INetd#IF_STATE_UP and #IF_STATE_DOWN. 63 // Other flags would be ignored. 64 65 final InterfaceConfigurationParcel ifConfig = new InterfaceConfigurationParcel(); 66 ifConfig.ifName = mIfName; 67 ifConfig.ipv4Addr = ipv4Addr.getAddress().getHostAddress(); 68 ifConfig.prefixLength = ipv4Addr.getPrefixLength(); 69 // Netd ignores hwaddr in interfaceSetCfg. 70 ifConfig.hwAddr = ""; 71 if (setIfaceUp == null) { 72 // Empty array means no change. 73 ifConfig.flags = new String[0]; 74 } else { 75 // Netd ignores any flag that's not IF_STATE_UP or IF_STATE_DOWN in interfaceSetCfg. 76 ifConfig.flags = setIfaceUp.booleanValue() 77 ? new String[] {IF_STATE_UP} : new String[] {IF_STATE_DOWN}; 78 } 79 try { 80 mNetd.interfaceSetCfg(ifConfig); 81 } catch (RemoteException | ServiceSpecificException e) { 82 logError("Setting IPv4 address to %s/%d failed: %s", 83 ifConfig.ipv4Addr, ifConfig.prefixLength, e); 84 return false; 85 } 86 return true; 87 } 88 89 /** 90 * Set the IPv4 address of the interface. 91 */ setIPv4Address(final LinkAddress address)92 public boolean setIPv4Address(final LinkAddress address) { 93 return setInterfaceConfiguration(address, null); 94 } 95 96 /** 97 * Clear the IPv4Address of the interface. 98 */ clearIPv4Address()99 public boolean clearIPv4Address() { 100 return setIPv4Address(new LinkAddress("0.0.0.0/0")); 101 } 102 setEnableIPv6(boolean enabled)103 private boolean setEnableIPv6(boolean enabled) { 104 try { 105 mNetd.interfaceSetEnableIPv6(mIfName, enabled); 106 } catch (RemoteException | ServiceSpecificException e) { 107 logError("%s IPv6 failed: %s", (enabled ? "enabling" : "disabling"), e); 108 return false; 109 } 110 return true; 111 } 112 113 /** 114 * Enable IPv6 on the interface. 115 */ enableIPv6()116 public boolean enableIPv6() { 117 return setEnableIPv6(true); 118 } 119 120 /** 121 * Disable IPv6 on the interface. 122 */ disableIPv6()123 public boolean disableIPv6() { 124 return setEnableIPv6(false); 125 } 126 127 /** 128 * Enable or disable IPv6 privacy extensions on the interface. 129 * @param enabled Whether the extensions should be enabled. 130 */ setIPv6PrivacyExtensions(boolean enabled)131 public boolean setIPv6PrivacyExtensions(boolean enabled) { 132 try { 133 mNetd.interfaceSetIPv6PrivacyExtensions(mIfName, enabled); 134 } catch (RemoteException | ServiceSpecificException e) { 135 logError("error %s IPv6 privacy extensions: %s", 136 (enabled ? "enabling" : "disabling"), e); 137 return false; 138 } 139 return true; 140 } 141 142 /** 143 * Set IPv6 address generation mode on the interface. 144 * 145 * <p>IPv6 should be disabled before changing the mode. 146 */ setIPv6AddrGenModeIfSupported(int mode)147 public boolean setIPv6AddrGenModeIfSupported(int mode) { 148 try { 149 mNetd.setIPv6AddrGenMode(mIfName, mode); 150 } catch (RemoteException e) { 151 logError("Unable to set IPv6 addrgen mode: %s", e); 152 return false; 153 } catch (ServiceSpecificException e) { 154 if (e.errorCode != OsConstants.EOPNOTSUPP) { 155 logError("Unable to set IPv6 addrgen mode: %s", e); 156 return false; 157 } 158 } 159 return true; 160 } 161 162 /** 163 * Add an address to the interface. 164 */ addAddress(LinkAddress addr)165 public boolean addAddress(LinkAddress addr) { 166 return addAddress(addr.getAddress(), addr.getPrefixLength()); 167 } 168 169 /** 170 * Add an address to the interface. 171 */ addAddress(InetAddress ip, int prefixLen)172 public boolean addAddress(InetAddress ip, int prefixLen) { 173 try { 174 mNetd.interfaceAddAddress(mIfName, ip.getHostAddress(), prefixLen); 175 } catch (ServiceSpecificException | RemoteException e) { 176 logError("failed to add %s/%d: %s", ip, prefixLen, e); 177 return false; 178 } 179 return true; 180 } 181 182 /** 183 * Remove an address from the interface. 184 */ removeAddress(InetAddress ip, int prefixLen)185 public boolean removeAddress(InetAddress ip, int prefixLen) { 186 try { 187 mNetd.interfaceDelAddress(mIfName, ip.getHostAddress(), prefixLen); 188 } catch (ServiceSpecificException | RemoteException e) { 189 logError("failed to remove %s/%d: %s", ip, prefixLen, e); 190 return false; 191 } 192 return true; 193 } 194 195 /** 196 * Remove all addresses from the interface. 197 */ clearAllAddresses()198 public boolean clearAllAddresses() { 199 try { 200 mNetd.interfaceClearAddrs(mIfName); 201 } catch (Exception e) { 202 logError("Failed to clear addresses: %s", e); 203 return false; 204 } 205 return true; 206 } 207 logError(String fmt, Object... args)208 private void logError(String fmt, Object... args) { 209 mLog.e(String.format(fmt, args)); 210 } 211 } 212