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 com.android.server.wifi.util; 18 19 import android.content.Context; 20 import android.net.INetd; 21 import android.net.INetdUnsolicitedEventListener; 22 import android.net.InetAddresses; 23 import android.net.InterfaceConfiguration; 24 import android.net.InterfaceConfigurationParcel; 25 import android.net.IpPrefix; 26 import android.net.LinkAddress; 27 import android.net.RouteInfo; 28 import android.os.Handler; 29 import android.os.IBinder; 30 import android.os.RemoteException; 31 import android.os.ServiceSpecificException; 32 import android.text.TextUtils; 33 import android.util.Log; 34 35 import java.net.InetAddress; 36 import java.util.ArrayList; 37 import java.util.HashSet; 38 import java.util.List; 39 import java.util.Set; 40 41 /** 42 * This is a simple wrapper over INetd calls used by wifi stack. 43 * 44 * Based on {@link com.android.server.NetworkManagementService} 45 */ 46 public class NetdWrapper { 47 private static final String TAG = "NetdWrapper"; 48 static final boolean MODIFY_OPERATION_ADD = true; 49 static final boolean MODIFY_OPERATION_REMOVE = false; 50 51 private final INetd mNetdService; 52 private final NetdUnsolicitedEventListener mNetdUnsolicitedEventListener; 53 private final Handler mHandler; 54 private final Set<NetdEventObserver> mObservers = new HashSet<>(); 55 56 /** 57 * Observer for iface events. 58 */ 59 public interface NetdEventObserver { 60 /** 61 * Interface has been added. 62 * 63 * @param iface The interface. 64 */ interfaceAdded(String iface)65 void interfaceAdded(String iface); 66 /** 67 * Interface configuration status has changed. 68 * 69 * @param iface The interface. 70 * @param up True if the interface has been enabled. 71 */ interfaceStatusChanged(String iface, boolean up)72 void interfaceStatusChanged(String iface, boolean up); 73 /** 74 * Interface physical-layer link state has changed. For Ethernet, 75 * this method is invoked when the cable is plugged in or unplugged. 76 * 77 * @param iface The interface. 78 * @param up True if the physical link-layer connection signal is valid. 79 */ interfaceLinkStateChanged(String iface, boolean up)80 void interfaceLinkStateChanged(String iface, boolean up); 81 } 82 83 private class NetdUnsolicitedEventListener extends INetdUnsolicitedEventListener.Stub { 84 @Override onInterfaceClassActivityChanged(boolean isActive, int label, long timestamp, int uid)85 public void onInterfaceClassActivityChanged(boolean isActive, 86 int label, long timestamp, int uid) throws RemoteException { 87 // Unused. 88 } 89 90 @Override onQuotaLimitReached(String alertName, String ifName)91 public void onQuotaLimitReached(String alertName, String ifName) 92 throws RemoteException { 93 // Unused. 94 } 95 96 @Override onInterfaceDnsServerInfo(String ifName, long lifetime, String[] servers)97 public void onInterfaceDnsServerInfo(String ifName, 98 long lifetime, String[] servers) throws RemoteException { 99 // Unused. 100 } 101 102 @Override onInterfaceAddressUpdated(String addr, String ifName, int flags, int scope)103 public void onInterfaceAddressUpdated(String addr, 104 String ifName, int flags, int scope) throws RemoteException { 105 // Unused. 106 } 107 108 @Override onInterfaceAddressRemoved(String addr, String ifName, int flags, int scope)109 public void onInterfaceAddressRemoved(String addr, 110 String ifName, int flags, int scope) throws RemoteException { 111 // Unused. 112 } 113 114 @Override onInterfaceAdded(String ifName)115 public void onInterfaceAdded(String ifName) throws RemoteException { 116 mHandler.post(() -> notifyInterfaceAdded(ifName)); 117 } 118 119 @Override onInterfaceRemoved(String ifName)120 public void onInterfaceRemoved(String ifName) throws RemoteException { 121 // Unused. 122 } 123 124 @Override onInterfaceChanged(String ifName, boolean up)125 public void onInterfaceChanged(String ifName, boolean up) 126 throws RemoteException { 127 mHandler.post(() -> notifyInterfaceStatusChanged(ifName, up)); 128 } 129 130 @Override onInterfaceLinkStateChanged(String ifName, boolean up)131 public void onInterfaceLinkStateChanged(String ifName, boolean up) 132 throws RemoteException { 133 mHandler.post(() -> notifyInterfaceLinkStateChanged(ifName, up)); 134 } 135 136 @Override onRouteChanged(boolean updated, String route, String gateway, String ifName)137 public void onRouteChanged(boolean updated, 138 String route, String gateway, String ifName) throws RemoteException { 139 // Unused. 140 } 141 142 @Override onStrictCleartextDetected(int uid, String hex)143 public void onStrictCleartextDetected(int uid, String hex) throws RemoteException { 144 // Unused. 145 } 146 147 @Override getInterfaceVersion()148 public int getInterfaceVersion() { 149 return INetdUnsolicitedEventListener.VERSION; 150 } 151 152 @Override getInterfaceHash()153 public String getInterfaceHash() { 154 return INetdUnsolicitedEventListener.HASH; 155 } 156 } 157 NetdWrapper(Context context, Handler handler)158 public NetdWrapper(Context context, Handler handler) { 159 mNetdService = INetd.Stub.asInterface( 160 (IBinder) context.getSystemService(Context.NETD_SERVICE)); 161 mNetdUnsolicitedEventListener = new NetdUnsolicitedEventListener(); 162 mHandler = handler; 163 164 try { 165 mNetdService.registerUnsolicitedEventListener(mNetdUnsolicitedEventListener); 166 } catch (RemoteException | ServiceSpecificException e) { 167 Log.e(TAG, "Failed to set Netd unsolicited event listener " + e); 168 } 169 } 170 modifyInterfaceInNetwork(boolean add, int netId, String iface)171 private void modifyInterfaceInNetwork(boolean add, int netId, String iface) { 172 try { 173 if (add) { 174 mNetdService.networkAddInterface(netId, iface); 175 } else { 176 mNetdService.networkRemoveInterface(netId, iface); 177 } 178 } catch (RemoteException | ServiceSpecificException e) { 179 throw new IllegalStateException(e); 180 } 181 } 182 modifyRoute(boolean add, int netId, RouteInfo route)183 private void modifyRoute(boolean add, int netId, RouteInfo route) { 184 final String ifName = route.getInterface(); 185 final String dst = route.getDestination().toString(); 186 final String nextHop; 187 188 switch (route.getType()) { 189 case RouteInfo.RTN_UNICAST: 190 if (route.hasGateway()) { 191 nextHop = route.getGateway().getHostAddress(); 192 } else { 193 nextHop = INetd.NEXTHOP_NONE; 194 } 195 break; 196 case RouteInfo.RTN_UNREACHABLE: 197 nextHop = INetd.NEXTHOP_UNREACHABLE; 198 break; 199 case RouteInfo.RTN_THROW: 200 nextHop = INetd.NEXTHOP_THROW; 201 break; 202 default: 203 nextHop = INetd.NEXTHOP_NONE; 204 break; 205 } 206 try { 207 if (add) { 208 mNetdService.networkAddRoute(netId, ifName, dst, nextHop); 209 } else { 210 mNetdService.networkRemoveRoute(netId, ifName, dst, nextHop); 211 } 212 } catch (RemoteException | ServiceSpecificException e) { 213 throw new IllegalStateException(e); 214 } 215 } 216 217 /** 218 * Add iface to local network. 219 */ addInterfaceToLocalNetwork(String iface, List<RouteInfo> routes)220 public void addInterfaceToLocalNetwork(String iface, List<RouteInfo> routes) { 221 modifyInterfaceInNetwork(MODIFY_OPERATION_ADD, INetd.LOCAL_NET_ID, iface); 222 223 for (RouteInfo route : routes) { 224 if (!route.isDefaultRoute()) { 225 modifyRoute(MODIFY_OPERATION_ADD, INetd.LOCAL_NET_ID, route); 226 } 227 } 228 229 // IPv6 link local should be activated always. 230 modifyRoute(MODIFY_OPERATION_ADD, INetd.LOCAL_NET_ID, 231 new RouteInfo(new IpPrefix("fe80::/64"), null, iface, RouteInfo.RTN_UNICAST)); 232 } 233 234 /** 235 * Remove iface from local network. 236 */ removeInterfaceFromLocalNetwork(String iface)237 public void removeInterfaceFromLocalNetwork(String iface) { 238 modifyInterfaceInNetwork(MODIFY_OPERATION_REMOVE, INetd.LOCAL_NET_ID, iface); 239 } 240 241 /** 242 * Clear iface addresses. 243 */ clearInterfaceAddresses(String iface)244 public void clearInterfaceAddresses(String iface) { 245 try { 246 mNetdService.interfaceClearAddrs(iface); 247 } catch (RemoteException | ServiceSpecificException e) { 248 throw new IllegalStateException(e); 249 } 250 } 251 252 /** 253 * Enable IPv6 on iface. 254 */ enableIpv6(String iface)255 public void enableIpv6(String iface) { 256 try { 257 mNetdService.interfaceSetEnableIPv6(iface, true); 258 } catch (RemoteException | ServiceSpecificException e) { 259 throw new IllegalStateException(e); 260 } 261 } 262 263 /** 264 * Disable IPv6 on iface. 265 */ disableIpv6(String iface)266 public void disableIpv6(String iface) { 267 try { 268 mNetdService.interfaceSetEnableIPv6(iface, false); 269 } catch (RemoteException | ServiceSpecificException e) { 270 throw new IllegalStateException(e); 271 } 272 } 273 274 /** 275 * Convert InterfaceConfiguration to InterfaceConfigurationParcel with given ifname. 276 */ toStableParcel(InterfaceConfiguration cfg, String iface)277 private static InterfaceConfigurationParcel toStableParcel(InterfaceConfiguration cfg, 278 String iface) { 279 InterfaceConfigurationParcel cfgParcel = new InterfaceConfigurationParcel(); 280 cfgParcel.ifName = iface; 281 String hwAddr = cfg.getHardwareAddress(); 282 if (!TextUtils.isEmpty(hwAddr)) { 283 cfgParcel.hwAddr = hwAddr; 284 } else { 285 cfgParcel.hwAddr = ""; 286 } 287 cfgParcel.ipv4Addr = cfg.getLinkAddress().getAddress().getHostAddress(); 288 cfgParcel.prefixLength = cfg.getLinkAddress().getPrefixLength(); 289 ArrayList<String> flags = new ArrayList<>(); 290 for (String flag : cfg.getFlags()) { 291 flags.add(flag); 292 } 293 cfgParcel.flags = flags.toArray(new String[0]); 294 295 return cfgParcel; 296 } 297 298 /** 299 * Construct InterfaceConfiguration from InterfaceConfigurationParcel. 300 */ fromStableParcel(InterfaceConfigurationParcel p)301 private static InterfaceConfiguration fromStableParcel(InterfaceConfigurationParcel p) { 302 InterfaceConfiguration cfg = new InterfaceConfiguration(); 303 cfg.setHardwareAddress(p.hwAddr); 304 305 final InetAddress addr = InetAddresses.parseNumericAddress(p.ipv4Addr); 306 cfg.setLinkAddress(new LinkAddress(addr, p.prefixLength)); 307 for (String flag : p.flags) { 308 cfg.setFlag(flag); 309 } 310 return cfg; 311 } 312 getInterfaceConfig(String iface)313 private InterfaceConfiguration getInterfaceConfig(String iface) { 314 final InterfaceConfigurationParcel result; 315 try { 316 result = mNetdService.interfaceGetCfg(iface); 317 } catch (RemoteException | ServiceSpecificException e) { 318 throw new IllegalStateException(e); 319 } 320 321 try { 322 final InterfaceConfiguration cfg = fromStableParcel(result); 323 return cfg; 324 } catch (IllegalArgumentException iae) { 325 throw new IllegalStateException("Invalid InterfaceConfigurationParcel", iae); 326 } 327 } 328 setInterfaceConfig(String iface, InterfaceConfiguration cfg)329 private void setInterfaceConfig(String iface, InterfaceConfiguration cfg) { 330 LinkAddress linkAddr = cfg.getLinkAddress(); 331 if (linkAddr == null || linkAddr.getAddress() == null) { 332 throw new IllegalStateException("Null LinkAddress given"); 333 } 334 final InterfaceConfigurationParcel cfgParcel = toStableParcel(cfg, iface); 335 336 try { 337 mNetdService.interfaceSetCfg(cfgParcel); 338 } catch (RemoteException | ServiceSpecificException e) { 339 throw new IllegalStateException(e); 340 } 341 } 342 343 /** 344 * List all tethered interfaces. 345 */ listTetheredInterfaces()346 public String[] listTetheredInterfaces() { 347 try { 348 return mNetdService.tetherInterfaceList(); 349 } catch (RemoteException | ServiceSpecificException e) { 350 throw new IllegalStateException(e); 351 } 352 } 353 354 /** 355 * Register a new netd event observer. 356 */ registerObserver(NetdEventObserver observer)357 public void registerObserver(NetdEventObserver observer) { 358 mHandler.post(() -> mObservers.add(observer)); 359 } 360 361 /** 362 * Unregister a new netd event observer. 363 */ unregisterObserver(NetdEventObserver observer)364 public void unregisterObserver(NetdEventObserver observer) { 365 mHandler.post(() -> mObservers.remove(observer)); 366 } 367 368 /** 369 * Set iface down. 370 */ setInterfaceDown(String iface)371 public void setInterfaceDown(String iface) { 372 final InterfaceConfiguration ifcg = getInterfaceConfig(iface); 373 ifcg.setInterfaceDown(); 374 setInterfaceConfig(iface, ifcg); 375 } 376 377 /** 378 * Set iface up. 379 */ setInterfaceUp(String iface)380 public void setInterfaceUp(String iface) { 381 final InterfaceConfiguration ifcg = getInterfaceConfig(iface); 382 ifcg.setInterfaceUp(); 383 setInterfaceConfig(iface, ifcg); 384 } 385 386 /** 387 * Returns whether iface is up. 388 */ isInterfaceUp(String iface)389 public boolean isInterfaceUp(String iface) { 390 final InterfaceConfiguration ifcg = getInterfaceConfig(iface); 391 return ifcg.isUp(); 392 } 393 394 /** 395 * Set iface link address. 396 */ setInterfaceLinkAddress(String iface, LinkAddress linkAddress)397 public void setInterfaceLinkAddress(String iface, LinkAddress linkAddress) { 398 final InterfaceConfiguration ifcg = getInterfaceConfig(iface); 399 ifcg.setLinkAddress(linkAddress); 400 ifcg.setInterfaceUp(); 401 setInterfaceConfig(iface, ifcg); 402 } 403 404 /** 405 * Set iface IPv6 privacy extensions. 406 */ setInterfaceIpv6PrivacyExtensions(String iface, boolean enable)407 public void setInterfaceIpv6PrivacyExtensions(String iface, boolean enable) { 408 try { 409 mNetdService.interfaceSetIPv6PrivacyExtensions(iface, enable); 410 } catch (RemoteException | ServiceSpecificException e) { 411 throw new IllegalStateException(e); 412 } 413 } 414 415 /** 416 * Start tethering. 417 */ startTethering(String[] dhcpRange)418 public void startTethering(String[] dhcpRange) { 419 // an odd number of addrs will fail 420 try { 421 mNetdService.tetherStart(dhcpRange); 422 } catch (RemoteException | ServiceSpecificException e) { 423 throw new IllegalStateException(e); 424 } 425 } 426 427 /** 428 * Stop tethering. 429 */ stopTethering()430 public void stopTethering() { 431 try { 432 mNetdService.tetherStop(); 433 } catch (RemoteException | ServiceSpecificException e) { 434 throw new IllegalStateException(e); 435 } 436 } 437 438 /** 439 * Add tethering on iface. 440 */ tetherInterface(String iface)441 public void tetherInterface(String iface) { 442 try { 443 mNetdService.tetherInterfaceAdd(iface); 444 } catch (RemoteException | ServiceSpecificException e) { 445 throw new IllegalStateException(e); 446 } 447 List<RouteInfo> routes = new ArrayList<>(); 448 // The RouteInfo constructor truncates the LinkAddress to a network prefix, thus making it 449 // suitable to use as a route destination. 450 LinkAddress dest = getInterfaceConfig(iface).getLinkAddress(); 451 RouteInfo route = new RouteInfo( 452 new IpPrefix(dest.getAddress(), dest.getPrefixLength()), 453 null, null, RouteInfo.RTN_UNICAST); 454 routes.add(route); 455 addInterfaceToLocalNetwork(iface, routes); 456 } 457 458 /** 459 * Remove tethering on iface. 460 */ untetherInterface(String iface)461 public void untetherInterface(String iface) { 462 try { 463 mNetdService.tetherInterfaceRemove(iface); 464 } catch (RemoteException | ServiceSpecificException e) { 465 throw new IllegalStateException(e); 466 } finally { 467 removeInterfaceFromLocalNetwork(iface); 468 } 469 } 470 471 /** 472 * Returns whether tethering has been started. 473 */ isTetheringStarted()474 public boolean isTetheringStarted() { 475 try { 476 final boolean isEnabled = mNetdService.tetherIsEnabled(); 477 return isEnabled; 478 } catch (RemoteException | ServiceSpecificException e) { 479 throw new IllegalStateException(e); 480 } 481 } 482 483 484 /** 485 * Notify our observers of an interface added 486 */ notifyInterfaceAdded(String iface)487 private void notifyInterfaceAdded(String iface) { 488 Log.d(TAG, "NetdWrapper interface add, iface= " + iface); 489 for (NetdEventObserver observer : mObservers) { 490 observer.interfaceAdded(iface); 491 } 492 } 493 494 /** 495 * Notify our observers of an interface status change 496 */ notifyInterfaceStatusChanged(String iface, boolean up)497 private void notifyInterfaceStatusChanged(String iface, boolean up) { 498 for (NetdEventObserver observer : mObservers) { 499 observer.interfaceStatusChanged(iface, up); 500 } 501 } 502 503 /** 504 * Notify our observers of an interface link state change 505 * (typically, an Ethernet cable has been plugged-in or unplugged). 506 */ notifyInterfaceLinkStateChanged(String iface, boolean up)507 private void notifyInterfaceLinkStateChanged(String iface, boolean up) { 508 for (NetdEventObserver observer : mObservers) { 509 observer.interfaceLinkStateChanged(iface, up); 510 } 511 } 512 } 513