summaryrefslogtreecommitdiffstats
path: root/services/core/java/com/android/server/connectivity/Nat464Xlat.java
blob: a15d678520bc7f2b60ace5aae80999329f61686f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
/*
 * Copyright (C) 2012 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.connectivity;

import static android.net.ConnectivityManager.TYPE_MOBILE;

import java.net.Inet4Address;

import android.content.Context;
import android.net.IConnectivityManager;
import android.net.InterfaceConfiguration;
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.NetworkStateTracker;
import android.net.NetworkUtils;
import android.net.RouteInfo;
import android.os.Handler;
import android.os.Message;
import android.os.INetworkManagementService;
import android.os.RemoteException;
import android.util.Slog;

import com.android.server.net.BaseNetworkObserver;

/**
 * @hide
 *
 * Class to manage a 464xlat CLAT daemon.
 */
public class Nat464Xlat extends BaseNetworkObserver {
    private Context mContext;
    private INetworkManagementService mNMService;
    private IConnectivityManager mConnService;
    private NetworkStateTracker mTracker;
    private Handler mHandler;

    // Whether we started clatd and expect it to be running.
    private boolean mIsStarted;
    // Whether the clatd interface exists (i.e., clatd is running).
    private boolean mIsRunning;
    // The LinkProperties of the clat interface.
    private LinkProperties mLP;

    // This must match the interface name in clatd.conf.
    private static final String CLAT_INTERFACE_NAME = "clat4";

    private static final String TAG = "Nat464Xlat";

    public Nat464Xlat(Context context, INetworkManagementService nmService,
                      IConnectivityManager connService, Handler handler) {
        mContext = context;
        mNMService = nmService;
        mConnService = connService;
        mHandler = handler;

        mIsStarted = false;
        mIsRunning = false;
        mLP = new LinkProperties();
    }

    /**
     * Determines whether an interface requires clat.
     * @param netType the network type (one of the
     *   android.net.ConnectivityManager.TYPE_* constants)
     * @param tracker the NetworkStateTracker corresponding to the network type.
     * @return true if the interface requires clat, false otherwise.
     */
    public boolean requiresClat(int netType, NetworkStateTracker tracker) {
        LinkProperties lp = tracker.getLinkProperties();
        // Only support clat on mobile for now.
        Slog.d(TAG, "requiresClat: netType=" + netType + ", hasIPv4Address=" +
               lp.hasIPv4Address());
        return netType == TYPE_MOBILE && !lp.hasIPv4Address();
    }

    public static boolean isRunningClat(LinkProperties lp) {
      return lp != null && lp.getAllInterfaceNames().contains(CLAT_INTERFACE_NAME);
    }

    /**
     * Starts the clat daemon.
     * @param lp The link properties of the interface to start clatd on.
     */
    public void startClat(NetworkStateTracker tracker) {
        if (mIsStarted) {
            Slog.e(TAG, "startClat: already started");
            return;
        }
        mTracker = tracker;
        LinkProperties lp = mTracker.getLinkProperties();
        String iface = lp.getInterfaceName();
        Slog.i(TAG, "Starting clatd on " + iface + ", lp=" + lp);
        try {
            mNMService.startClatd(iface);
        } catch(RemoteException e) {
            Slog.e(TAG, "Error starting clat daemon: " + e);
        }
        mIsStarted = true;
    }

    /**
     * Stops the clat daemon.
     */
    public void stopClat() {
        if (mIsStarted) {
            Slog.i(TAG, "Stopping clatd");
            try {
                mNMService.stopClatd();
            } catch(RemoteException e) {
                Slog.e(TAG, "Error stopping clat daemon: " + e);
            }
            mIsStarted = false;
            mIsRunning = false;
            mTracker = null;
            mLP.clear();
        } else {
            Slog.e(TAG, "stopClat: already stopped");
        }
    }

    public boolean isStarted() {
        return mIsStarted;
    }

    public boolean isRunning() {
        return mIsRunning;
    }

    @Override
    public void interfaceAdded(String iface) {
        if (iface.equals(CLAT_INTERFACE_NAME)) {
            Slog.i(TAG, "interface " + CLAT_INTERFACE_NAME +
                   " added, mIsRunning = " + mIsRunning + " -> true");
            mIsRunning = true;

            // Create the LinkProperties for the clat interface by fetching the
            // IPv4 address for the interface and adding an IPv4 default route,
            // then stack the LinkProperties on top of the link it's running on.
            // Although the clat interface is a point-to-point tunnel, we don't
            // point the route directly at the interface because some apps don't
            // understand routes without gateways (see, e.g., http://b/9597256
            // http://b/9597516). Instead, set the next hop of the route to the
            // clat IPv4 address itself (for those apps, it doesn't matter what
            // the IP of the gateway is, only that there is one).
            try {
                InterfaceConfiguration config = mNMService.getInterfaceConfig(iface);
                LinkAddress clatAddress = config.getLinkAddress();
                mLP.clear();
                mLP.setInterfaceName(iface);
                RouteInfo ipv4Default = new RouteInfo(new LinkAddress(Inet4Address.ANY, 0),
                                                      clatAddress.getAddress(), iface);
                mLP.addRoute(ipv4Default);
                mLP.addLinkAddress(clatAddress);
                mTracker.addStackedLink(mLP);
                Slog.i(TAG, "Adding stacked link. tracker LP: " +
                       mTracker.getLinkProperties());
            } catch(RemoteException e) {
                Slog.e(TAG, "Error getting link properties: " + e);
            }

            // Inform ConnectivityService that things have changed.
            Message msg = mHandler.obtainMessage(
                NetworkStateTracker.EVENT_CONFIGURATION_CHANGED,
                mTracker.getNetworkInfo());
            Slog.i(TAG, "sending message to ConnectivityService: " + msg);
            msg.sendToTarget();
        }
    }

    @Override
    public void interfaceRemoved(String iface) {
        if (iface == CLAT_INTERFACE_NAME) {
            if (mIsRunning) {
                NetworkUtils.resetConnections(
                    CLAT_INTERFACE_NAME,
                    NetworkUtils.RESET_IPV4_ADDRESSES);
            }
            Slog.i(TAG, "interface " + CLAT_INTERFACE_NAME +
                   " removed, mIsRunning = " + mIsRunning + " -> false");
            mIsRunning = false;
            mTracker.removeStackedLink(mLP);
            mLP.clear();
            Slog.i(TAG, "mLP = " + mLP);
        }
    }
};