1 /* 2 * Copyright (C) 2012 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.connectivity; 18 19 import static android.net.ConnectivityManager.TYPE_MOBILE; 20 21 import java.net.Inet4Address; 22 23 import android.content.Context; 24 import android.net.IConnectivityManager; 25 import android.net.InterfaceConfiguration; 26 import android.net.LinkAddress; 27 import android.net.LinkProperties; 28 import android.net.NetworkStateTracker; 29 import android.net.NetworkUtils; 30 import android.net.RouteInfo; 31 import android.os.Handler; 32 import android.os.Message; 33 import android.os.INetworkManagementService; 34 import android.os.RemoteException; 35 import android.util.Slog; 36 37 import com.android.server.net.BaseNetworkObserver; 38 39 /** 40 * @hide 41 * 42 * Class to manage a 464xlat CLAT daemon. 43 */ 44 public class Nat464Xlat extends BaseNetworkObserver { 45 private Context mContext; 46 private INetworkManagementService mNMService; 47 private IConnectivityManager mConnService; 48 private NetworkStateTracker mTracker; 49 private Handler mHandler; 50 51 // Whether we started clatd and expect it to be running. 52 private boolean mIsStarted; 53 // Whether the clatd interface exists (i.e., clatd is running). 54 private boolean mIsRunning; 55 // The LinkProperties of the clat interface. 56 private LinkProperties mLP; 57 58 // This must match the interface name in clatd.conf. 59 private static final String CLAT_INTERFACE_NAME = "clat4"; 60 61 private static final String TAG = "Nat464Xlat"; 62 63 public Nat464Xlat(Context context, INetworkManagementService nmService, 64 IConnectivityManager connService, Handler handler) { 65 mContext = context; 66 mNMService = nmService; 67 mConnService = connService; 68 mHandler = handler; 69 70 mIsStarted = false; 71 mIsRunning = false; 72 mLP = new LinkProperties(); 73 } 74 75 /** 76 * Determines whether an interface requires clat. 77 * @param netType the network type (one of the 78 * android.net.ConnectivityManager.TYPE_* constants) 79 * @param tracker the NetworkStateTracker corresponding to the network type. 80 * @return true if the interface requires clat, false otherwise. 81 */ 82 public boolean requiresClat(int netType, NetworkStateTracker tracker) { 83 LinkProperties lp = tracker.getLinkProperties(); 84 // Only support clat on mobile for now. 85 Slog.d(TAG, "requiresClat: netType=" + netType + ", hasIPv4Address=" + 86 lp.hasIPv4Address()); 87 return netType == TYPE_MOBILE && !lp.hasIPv4Address(); 88 } 89 90 public static boolean isRunningClat(LinkProperties lp) { 91 return lp != null && lp.getAllInterfaceNames().contains(CLAT_INTERFACE_NAME); 92 } 93 94 /** 95 * Starts the clat daemon. 96 * @param lp The link properties of the interface to start clatd on. 97 */ 98 public void startClat(NetworkStateTracker tracker) { 99 if (mIsStarted) { 100 Slog.e(TAG, "startClat: already started"); 101 return; 102 } 103 mTracker = tracker; 104 LinkProperties lp = mTracker.getLinkProperties(); 105 String iface = lp.getInterfaceName(); 106 Slog.i(TAG, "Starting clatd on " + iface + ", lp=" + lp); 107 try { 108 mNMService.startClatd(iface); 109 } catch(RemoteException e) { 110 Slog.e(TAG, "Error starting clat daemon: " + e); 111 } 112 mIsStarted = true; 113 } 114 115 /** 116 * Stops the clat daemon. 117 */ 118 public void stopClat() { 119 if (mIsStarted) { 120 Slog.i(TAG, "Stopping clatd"); 121 try { 122 mNMService.stopClatd(); 123 } catch(RemoteException e) { 124 Slog.e(TAG, "Error stopping clat daemon: " + e); 125 } 126 mIsStarted = false; 127 mIsRunning = false; 128 mTracker = null; 129 mLP.clear(); 130 } else { 131 Slog.e(TAG, "stopClat: already stopped"); 132 } 133 } 134 135 public boolean isStarted() { 136 return mIsStarted; 137 } 138 139 public boolean isRunning() { 140 return mIsRunning; 141 } 142 143 @Override 144 public void interfaceAdded(String iface) { 145 if (iface.equals(CLAT_INTERFACE_NAME)) { 146 Slog.i(TAG, "interface " + CLAT_INTERFACE_NAME + 147 " added, mIsRunning = " + mIsRunning + " -> true"); 148 mIsRunning = true; 149 150 // Create the LinkProperties for the clat interface by fetching the 151 // IPv4 address for the interface and adding an IPv4 default route, 152 // then stack the LinkProperties on top of the link it's running on. 153 // Although the clat interface is a point-to-point tunnel, we don't 154 // point the route directly at the interface because some apps don't 155 // understand routes without gateways (see, e.g., http://b/9597256 156 // http://b/9597516). Instead, set the next hop of the route to the 157 // clat IPv4 address itself (for those apps, it doesn't matter what 158 // the IP of the gateway is, only that there is one). 159 try { 160 InterfaceConfiguration config = mNMService.getInterfaceConfig(iface); 161 LinkAddress clatAddress = config.getLinkAddress(); 162 mLP.clear(); 163 mLP.setInterfaceName(iface); 164 RouteInfo ipv4Default = new RouteInfo(new LinkAddress(Inet4Address.ANY, 0), 165 clatAddress.getAddress(), iface); 166 mLP.addRoute(ipv4Default); 167 mLP.addLinkAddress(clatAddress); 168 mTracker.addStackedLink(mLP); 169 Slog.i(TAG, "Adding stacked link. tracker LP: " + 170 mTracker.getLinkProperties()); 171 } catch(RemoteException e) { 172 Slog.e(TAG, "Error getting link properties: " + e); 173 } 174 175 // Inform ConnectivityService that things have changed. 176 Message msg = mHandler.obtainMessage( 177 NetworkStateTracker.EVENT_CONFIGURATION_CHANGED, 178 mTracker.getNetworkInfo()); 179 Slog.i(TAG, "sending message to ConnectivityService: " + msg); 180 msg.sendToTarget(); 181 } 182 } 183 184 @Override 185 public void interfaceRemoved(String iface) { 186 if (iface == CLAT_INTERFACE_NAME) { 187 if (mIsRunning) { 188 NetworkUtils.resetConnections( 189 CLAT_INTERFACE_NAME, 190 NetworkUtils.RESET_IPV4_ADDRESSES); 191 } 192 Slog.i(TAG, "interface " + CLAT_INTERFACE_NAME + 193 " removed, mIsRunning = " + mIsRunning + " -> false"); 194 mIsRunning = false; 195 mTracker.removeStackedLink(mLP); 196 mLP.clear(); 197 Slog.i(TAG, "mLP = " + mLP); 198 } 199 } 200 }; 201