blob: 4d56468f2fe675dc54d8bf28c8c991e5c2bec223 [file] [log] [blame]
Jaewan Kim63461552014-03-10 17:10:51 +09001/*
2 * Copyright (C) 2014 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.net;
18
19import android.net.IpConfiguration;
20import android.net.IpConfiguration.IpAssignment;
21import android.net.IpConfiguration.ProxySettings;
22import android.net.LinkAddress;
Jaewan Kim63461552014-03-10 17:10:51 +090023import android.net.NetworkUtils;
24import android.net.ProxyInfo;
25import android.net.RouteInfo;
Lorenzo Colitti0a82e802014-07-31 00:48:01 +090026import android.net.StaticIpConfiguration;
Jaewan Kim63461552014-03-10 17:10:51 +090027import android.util.Log;
28import android.util.SparseArray;
29
Roshan Pius06fe3282016-06-01 17:51:28 -070030import com.android.internal.annotations.VisibleForTesting;
Jaewan Kim63461552014-03-10 17:10:51 +090031import com.android.server.net.DelayedDiskWrite;
32
33import java.io.BufferedInputStream;
Jaewan Kim63461552014-03-10 17:10:51 +090034import java.io.DataInputStream;
35import java.io.DataOutputStream;
36import java.io.EOFException;
37import java.io.FileInputStream;
Roshan Pius06fe3282016-06-01 17:51:28 -070038import java.io.FileNotFoundException;
Jaewan Kim63461552014-03-10 17:10:51 +090039import java.io.IOException;
Roshan Pius06fe3282016-06-01 17:51:28 -070040import java.io.InputStream;
Jaewan Kim63461552014-03-10 17:10:51 +090041import java.net.InetAddress;
Lorenzo Colitti0a82e802014-07-31 00:48:01 +090042import java.net.Inet4Address;
Jaewan Kim63461552014-03-10 17:10:51 +090043
44public class IpConfigStore {
45 private static final String TAG = "IpConfigStore";
Joe Onorato12acbd72016-02-01 17:49:31 -080046 private static final boolean DBG = false;
Jaewan Kim63461552014-03-10 17:10:51 +090047
48 protected final DelayedDiskWrite mWriter;
49
50 /* IP and proxy configuration keys */
51 protected static final String ID_KEY = "id";
52 protected static final String IP_ASSIGNMENT_KEY = "ipAssignment";
53 protected static final String LINK_ADDRESS_KEY = "linkAddress";
54 protected static final String GATEWAY_KEY = "gateway";
55 protected static final String DNS_KEY = "dns";
56 protected static final String PROXY_SETTINGS_KEY = "proxySettings";
57 protected static final String PROXY_HOST_KEY = "proxyHost";
58 protected static final String PROXY_PORT_KEY = "proxyPort";
59 protected static final String PROXY_PAC_FILE = "proxyPac";
60 protected static final String EXCLUSION_LIST_KEY = "exclusionList";
61 protected static final String EOS = "eos";
62
63 protected static final int IPCONFIG_FILE_VERSION = 2;
64
Roshan Pius718df422016-02-22 17:06:47 -080065 public IpConfigStore(DelayedDiskWrite writer) {
66 mWriter = writer;
67 }
68
Jaewan Kim63461552014-03-10 17:10:51 +090069 public IpConfigStore() {
Roshan Pius718df422016-02-22 17:06:47 -080070 this(new DelayedDiskWrite());
Jaewan Kim63461552014-03-10 17:10:51 +090071 }
72
Roshan Pius06fe3282016-06-01 17:51:28 -070073 @VisibleForTesting
74 public static boolean writeConfig(DataOutputStream out, int configKey,
Lorenzo Colitti0a82e802014-07-31 00:48:01 +090075 IpConfiguration config) throws IOException {
Jaewan Kim63461552014-03-10 17:10:51 +090076 boolean written = false;
77
78 try {
Jaewan Kim63461552014-03-10 17:10:51 +090079 switch (config.ipAssignment) {
80 case STATIC:
81 out.writeUTF(IP_ASSIGNMENT_KEY);
82 out.writeUTF(config.ipAssignment.toString());
Lorenzo Colitti0a82e802014-07-31 00:48:01 +090083 StaticIpConfiguration staticIpConfiguration = config.staticIpConfiguration;
84 if (staticIpConfiguration != null) {
85 if (staticIpConfiguration.ipAddress != null) {
86 LinkAddress ipAddress = staticIpConfiguration.ipAddress;
87 out.writeUTF(LINK_ADDRESS_KEY);
88 out.writeUTF(ipAddress.getAddress().getHostAddress());
89 out.writeInt(ipAddress.getPrefixLength());
Jaewan Kim63461552014-03-10 17:10:51 +090090 }
Lorenzo Colitti0a82e802014-07-31 00:48:01 +090091 if (staticIpConfiguration.gateway != null) {
92 out.writeUTF(GATEWAY_KEY);
93 out.writeInt(0); // Default route.
94 out.writeInt(1); // Have a gateway.
95 out.writeUTF(staticIpConfiguration.gateway.getHostAddress());
Jaewan Kim63461552014-03-10 17:10:51 +090096 }
Lorenzo Colitti0a82e802014-07-31 00:48:01 +090097 for (InetAddress inetAddr : staticIpConfiguration.dnsServers) {
98 out.writeUTF(DNS_KEY);
99 out.writeUTF(inetAddr.getHostAddress());
100 }
Jaewan Kim63461552014-03-10 17:10:51 +0900101 }
102 written = true;
103 break;
104 case DHCP:
105 out.writeUTF(IP_ASSIGNMENT_KEY);
106 out.writeUTF(config.ipAssignment.toString());
107 written = true;
108 break;
109 case UNASSIGNED:
110 /* Ignore */
111 break;
112 default:
113 loge("Ignore invalid ip assignment while writing");
114 break;
115 }
116
117 switch (config.proxySettings) {
118 case STATIC:
Lorenzo Colitti0a82e802014-07-31 00:48:01 +0900119 ProxyInfo proxyProperties = config.httpProxy;
Jaewan Kim63461552014-03-10 17:10:51 +0900120 String exclusionList = proxyProperties.getExclusionListAsString();
121 out.writeUTF(PROXY_SETTINGS_KEY);
122 out.writeUTF(config.proxySettings.toString());
123 out.writeUTF(PROXY_HOST_KEY);
124 out.writeUTF(proxyProperties.getHost());
125 out.writeUTF(PROXY_PORT_KEY);
126 out.writeInt(proxyProperties.getPort());
Geoffrey Borggaard79adc952014-11-20 14:35:32 -0500127 if (exclusionList != null) {
128 out.writeUTF(EXCLUSION_LIST_KEY);
129 out.writeUTF(exclusionList);
130 }
Jaewan Kim63461552014-03-10 17:10:51 +0900131 written = true;
132 break;
133 case PAC:
Lorenzo Colitti0a82e802014-07-31 00:48:01 +0900134 ProxyInfo proxyPacProperties = config.httpProxy;
Jaewan Kim63461552014-03-10 17:10:51 +0900135 out.writeUTF(PROXY_SETTINGS_KEY);
136 out.writeUTF(config.proxySettings.toString());
137 out.writeUTF(PROXY_PAC_FILE);
138 out.writeUTF(proxyPacProperties.getPacFileUrl().toString());
139 written = true;
140 break;
141 case NONE:
142 out.writeUTF(PROXY_SETTINGS_KEY);
143 out.writeUTF(config.proxySettings.toString());
144 written = true;
145 break;
146 case UNASSIGNED:
147 /* Ignore */
148 break;
149 default:
150 loge("Ignore invalid proxy settings while writing");
151 break;
152 }
153
154 if (written) {
155 out.writeUTF(ID_KEY);
156 out.writeInt(configKey);
157 }
158 } catch (NullPointerException e) {
Lorenzo Colitti0a82e802014-07-31 00:48:01 +0900159 loge("Failure in writing " + config + e);
Jaewan Kim63461552014-03-10 17:10:51 +0900160 }
161 out.writeUTF(EOS);
162
163 return written;
164 }
165
166 public void writeIpAndProxyConfigurations(String filePath,
167 final SparseArray<IpConfiguration> networks) {
168 mWriter.write(filePath, new DelayedDiskWrite.Writer() {
169 public void onWriteCalled(DataOutputStream out) throws IOException{
170 out.writeInt(IPCONFIG_FILE_VERSION);
171 for(int i = 0; i < networks.size(); i++) {
172 writeConfig(out, networks.keyAt(i), networks.valueAt(i));
173 }
174 }
175 });
176 }
177
Roshan Pius06fe3282016-06-01 17:51:28 -0700178 public static SparseArray<IpConfiguration> readIpAndProxyConfigurations(String filePath) {
179 BufferedInputStream bufferedInputStream;
180 try {
181 bufferedInputStream = new BufferedInputStream(new FileInputStream(filePath));
182 } catch (FileNotFoundException e) {
183 // Return an empty array here because callers expect an empty array when the file is
184 // not present.
185 loge("Error opening configuration file: " + e);
186 return new SparseArray<>();
187 }
188 return readIpAndProxyConfigurations(bufferedInputStream);
189 }
Jaewan Kim63461552014-03-10 17:10:51 +0900190
Roshan Pius06fe3282016-06-01 17:51:28 -0700191 public static SparseArray<IpConfiguration> readIpAndProxyConfigurations(
192 InputStream inputStream) {
193 SparseArray<IpConfiguration> networks = new SparseArray<IpConfiguration>();
Jaewan Kim63461552014-03-10 17:10:51 +0900194 DataInputStream in = null;
195 try {
Roshan Pius06fe3282016-06-01 17:51:28 -0700196 in = new DataInputStream(inputStream);
Jaewan Kim63461552014-03-10 17:10:51 +0900197
198 int version = in.readInt();
199 if (version != 2 && version != 1) {
200 loge("Bad version on IP configuration file, ignore read");
201 return null;
202 }
203
204 while (true) {
205 int id = -1;
206 // Default is DHCP with no proxy
207 IpAssignment ipAssignment = IpAssignment.DHCP;
208 ProxySettings proxySettings = ProxySettings.NONE;
Lorenzo Colitti0a82e802014-07-31 00:48:01 +0900209 StaticIpConfiguration staticIpConfiguration = new StaticIpConfiguration();
Jaewan Kim63461552014-03-10 17:10:51 +0900210 String proxyHost = null;
211 String pacFileUrl = null;
212 int proxyPort = -1;
213 String exclusionList = null;
214 String key;
215
216 do {
217 key = in.readUTF();
218 try {
219 if (key.equals(ID_KEY)) {
220 id = in.readInt();
221 } else if (key.equals(IP_ASSIGNMENT_KEY)) {
222 ipAssignment = IpAssignment.valueOf(in.readUTF());
223 } else if (key.equals(LINK_ADDRESS_KEY)) {
224 LinkAddress linkAddr = new LinkAddress(
225 NetworkUtils.numericToInetAddress(in.readUTF()), in.readInt());
Lorenzo Colitti0a82e802014-07-31 00:48:01 +0900226 if (linkAddr.getAddress() instanceof Inet4Address &&
227 staticIpConfiguration.ipAddress == null) {
228 staticIpConfiguration.ipAddress = linkAddr;
229 } else {
230 loge("Non-IPv4 or duplicate address: " + linkAddr);
231 }
Jaewan Kim63461552014-03-10 17:10:51 +0900232 } else if (key.equals(GATEWAY_KEY)) {
233 LinkAddress dest = null;
234 InetAddress gateway = null;
235 if (version == 1) {
236 // only supported default gateways - leave the dest/prefix empty
237 gateway = NetworkUtils.numericToInetAddress(in.readUTF());
Lorenzo Colitti0a82e802014-07-31 00:48:01 +0900238 if (staticIpConfiguration.gateway == null) {
239 staticIpConfiguration.gateway = gateway;
240 } else {
241 loge("Duplicate gateway: " + gateway.getHostAddress());
242 }
Jaewan Kim63461552014-03-10 17:10:51 +0900243 } else {
244 if (in.readInt() == 1) {
245 dest = new LinkAddress(
246 NetworkUtils.numericToInetAddress(in.readUTF()),
247 in.readInt());
248 }
249 if (in.readInt() == 1) {
250 gateway = NetworkUtils.numericToInetAddress(in.readUTF());
251 }
Lorenzo Colitti0a82e802014-07-31 00:48:01 +0900252 RouteInfo route = new RouteInfo(dest, gateway);
253 if (route.isIPv4Default() &&
254 staticIpConfiguration.gateway == null) {
255 staticIpConfiguration.gateway = gateway;
256 } else {
257 loge("Non-IPv4 default or duplicate route: " + route);
258 }
Jaewan Kim63461552014-03-10 17:10:51 +0900259 }
Jaewan Kim63461552014-03-10 17:10:51 +0900260 } else if (key.equals(DNS_KEY)) {
Lorenzo Colitti0a82e802014-07-31 00:48:01 +0900261 staticIpConfiguration.dnsServers.add(
Jaewan Kim63461552014-03-10 17:10:51 +0900262 NetworkUtils.numericToInetAddress(in.readUTF()));
263 } else if (key.equals(PROXY_SETTINGS_KEY)) {
264 proxySettings = ProxySettings.valueOf(in.readUTF());
265 } else if (key.equals(PROXY_HOST_KEY)) {
266 proxyHost = in.readUTF();
267 } else if (key.equals(PROXY_PORT_KEY)) {
268 proxyPort = in.readInt();
269 } else if (key.equals(PROXY_PAC_FILE)) {
270 pacFileUrl = in.readUTF();
271 } else if (key.equals(EXCLUSION_LIST_KEY)) {
272 exclusionList = in.readUTF();
273 } else if (key.equals(EOS)) {
274 break;
275 } else {
276 loge("Ignore unknown key " + key + "while reading");
277 }
278 } catch (IllegalArgumentException e) {
279 loge("Ignore invalid address while reading" + e);
280 }
281 } while (true);
282
283 if (id != -1) {
284 IpConfiguration config = new IpConfiguration();
285 networks.put(id, config);
286
Jaewan Kim63461552014-03-10 17:10:51 +0900287 switch (ipAssignment) {
288 case STATIC:
Lorenzo Colitti0a82e802014-07-31 00:48:01 +0900289 config.staticIpConfiguration = staticIpConfiguration;
290 config.ipAssignment = ipAssignment;
291 break;
Jaewan Kim63461552014-03-10 17:10:51 +0900292 case DHCP:
293 config.ipAssignment = ipAssignment;
294 break;
295 case UNASSIGNED:
296 loge("BUG: Found UNASSIGNED IP on file, use DHCP");
297 config.ipAssignment = IpAssignment.DHCP;
298 break;
299 default:
300 loge("Ignore invalid ip assignment while reading.");
301 config.ipAssignment = IpAssignment.UNASSIGNED;
302 break;
303 }
304
305 switch (proxySettings) {
306 case STATIC:
Lorenzo Colitti0a82e802014-07-31 00:48:01 +0900307 ProxyInfo proxyInfo =
Jaewan Kim63461552014-03-10 17:10:51 +0900308 new ProxyInfo(proxyHost, proxyPort, exclusionList);
Lorenzo Colitti0a82e802014-07-31 00:48:01 +0900309 config.proxySettings = proxySettings;
310 config.httpProxy = proxyInfo;
Jaewan Kim63461552014-03-10 17:10:51 +0900311 break;
312 case PAC:
Lorenzo Colitti0a82e802014-07-31 00:48:01 +0900313 ProxyInfo proxyPacProperties = new ProxyInfo(pacFileUrl);
Jaewan Kim63461552014-03-10 17:10:51 +0900314 config.proxySettings = proxySettings;
Lorenzo Colitti0a82e802014-07-31 00:48:01 +0900315 config.httpProxy = proxyPacProperties;
Jaewan Kim63461552014-03-10 17:10:51 +0900316 break;
317 case NONE:
318 config.proxySettings = proxySettings;
319 break;
320 case UNASSIGNED:
321 loge("BUG: Found UNASSIGNED proxy on file, use NONE");
322 config.proxySettings = ProxySettings.NONE;
323 break;
324 default:
325 loge("Ignore invalid proxy settings while reading");
326 config.proxySettings = ProxySettings.UNASSIGNED;
327 break;
328 }
329 } else {
330 if (DBG) log("Missing id while parsing configuration");
331 }
332 }
333 } catch (EOFException ignore) {
334 } catch (IOException e) {
Lorenzo Colitti56cf7c52014-05-21 16:30:22 -0700335 loge("Error parsing configuration: " + e);
Jaewan Kim63461552014-03-10 17:10:51 +0900336 } finally {
337 if (in != null) {
338 try {
339 in.close();
340 } catch (Exception e) {}
341 }
342 }
343
344 return networks;
345 }
346
Roshan Pius06fe3282016-06-01 17:51:28 -0700347 protected static void loge(String s) {
Jaewan Kim63461552014-03-10 17:10:51 +0900348 Log.e(TAG, s);
349 }
350
Roshan Pius06fe3282016-06-01 17:51:28 -0700351 protected static void log(String s) {
Jaewan Kim63461552014-03-10 17:10:51 +0900352 Log.d(TAG, s);
353 }
354}