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