1 /* 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 17 package com.android.server.net; 18 19 import android.net.IpConfiguration; 20 import android.net.IpConfiguration.IpAssignment; 21 import android.net.IpConfiguration.ProxySettings; 22 import android.net.LinkAddress; 23 import android.net.NetworkUtils; 24 import android.net.ProxyInfo; 25 import android.net.RouteInfo; 26 import android.net.StaticIpConfiguration; 27 import android.util.Log; 28 import android.util.SparseArray; 29 30 import com.android.server.net.DelayedDiskWrite; 31 32 import java.io.BufferedInputStream; 33 import java.io.DataInputStream; 34 import java.io.DataOutputStream; 35 import java.io.EOFException; 36 import java.io.FileInputStream; 37 import java.io.IOException; 38 import java.net.InetAddress; 39 import java.net.Inet4Address; 40 41 public class IpConfigStore { 42 private static final String TAG = "IpConfigStore"; 43 private static final boolean DBG = true; 44 45 protected final DelayedDiskWrite mWriter; 46 47 /* IP and proxy configuration keys */ 48 protected static final String ID_KEY = "id"; 49 protected static final String IP_ASSIGNMENT_KEY = "ipAssignment"; 50 protected static final String LINK_ADDRESS_KEY = "linkAddress"; 51 protected static final String GATEWAY_KEY = "gateway"; 52 protected static final String DNS_KEY = "dns"; 53 protected static final String PROXY_SETTINGS_KEY = "proxySettings"; 54 protected static final String PROXY_HOST_KEY = "proxyHost"; 55 protected static final String PROXY_PORT_KEY = "proxyPort"; 56 protected static final String PROXY_PAC_FILE = "proxyPac"; 57 protected static final String EXCLUSION_LIST_KEY = "exclusionList"; 58 protected static final String EOS = "eos"; 59 60 protected static final int IPCONFIG_FILE_VERSION = 2; 61 62 public IpConfigStore() { 63 mWriter = new DelayedDiskWrite(); 64 } 65 66 private boolean writeConfig(DataOutputStream out, int configKey, 67 IpConfiguration config) throws IOException { 68 boolean written = false; 69 70 try { 71 switch (config.ipAssignment) { 72 case STATIC: 73 out.writeUTF(IP_ASSIGNMENT_KEY); 74 out.writeUTF(config.ipAssignment.toString()); 75 StaticIpConfiguration staticIpConfiguration = config.staticIpConfiguration; 76 if (staticIpConfiguration != null) { 77 if (staticIpConfiguration.ipAddress != null) { 78 LinkAddress ipAddress = staticIpConfiguration.ipAddress; 79 out.writeUTF(LINK_ADDRESS_KEY); 80 out.writeUTF(ipAddress.getAddress().getHostAddress()); 81 out.writeInt(ipAddress.getPrefixLength()); 82 } 83 if (staticIpConfiguration.gateway != null) { 84 out.writeUTF(GATEWAY_KEY); 85 out.writeInt(0); // Default route. 86 out.writeInt(1); // Have a gateway. 87 out.writeUTF(staticIpConfiguration.gateway.getHostAddress()); 88 } 89 for (InetAddress inetAddr : staticIpConfiguration.dnsServers) { 90 out.writeUTF(DNS_KEY); 91 out.writeUTF(inetAddr.getHostAddress()); 92 } 93 } 94 written = true; 95 break; 96 case DHCP: 97 out.writeUTF(IP_ASSIGNMENT_KEY); 98 out.writeUTF(config.ipAssignment.toString()); 99 written = true; 100 break; 101 case UNASSIGNED: 102 /* Ignore */ 103 break; 104 default: 105 loge("Ignore invalid ip assignment while writing"); 106 break; 107 } 108 109 switch (config.proxySettings) { 110 case STATIC: 111 ProxyInfo proxyProperties = config.httpProxy; 112 String exclusionList = proxyProperties.getExclusionListAsString(); 113 out.writeUTF(PROXY_SETTINGS_KEY); 114 out.writeUTF(config.proxySettings.toString()); 115 out.writeUTF(PROXY_HOST_KEY); 116 out.writeUTF(proxyProperties.getHost()); 117 out.writeUTF(PROXY_PORT_KEY); 118 out.writeInt(proxyProperties.getPort()); 119 if (exclusionList != null) { 120 out.writeUTF(EXCLUSION_LIST_KEY); 121 out.writeUTF(exclusionList); 122 } 123 written = true; 124 break; 125 case PAC: 126 ProxyInfo proxyPacProperties = config.httpProxy; 127 out.writeUTF(PROXY_SETTINGS_KEY); 128 out.writeUTF(config.proxySettings.toString()); 129 out.writeUTF(PROXY_PAC_FILE); 130 out.writeUTF(proxyPacProperties.getPacFileUrl().toString()); 131 written = true; 132 break; 133 case NONE: 134 out.writeUTF(PROXY_SETTINGS_KEY); 135 out.writeUTF(config.proxySettings.toString()); 136 written = true; 137 break; 138 case UNASSIGNED: 139 /* Ignore */ 140 break; 141 default: 142 loge("Ignore invalid proxy settings while writing"); 143 break; 144 } 145 146 if (written) { 147 out.writeUTF(ID_KEY); 148 out.writeInt(configKey); 149 } 150 } catch (NullPointerException e) { 151 loge("Failure in writing " + config + e); 152 } 153 out.writeUTF(EOS); 154 155 return written; 156 } 157 158 public void writeIpAndProxyConfigurations(String filePath, 159 final SparseArray<IpConfiguration> networks) { 160 mWriter.write(filePath, new DelayedDiskWrite.Writer() { 161 public void onWriteCalled(DataOutputStream out) throws IOException{ 162 out.writeInt(IPCONFIG_FILE_VERSION); 163 for(int i = 0; i < networks.size(); i++) { 164 writeConfig(out, networks.keyAt(i), networks.valueAt(i)); 165 } 166 } 167 }); 168 } 169 170 public SparseArray<IpConfiguration> readIpAndProxyConfigurations(String filePath) { 171 SparseArray<IpConfiguration> networks = new SparseArray<IpConfiguration>(); 172 173 DataInputStream in = null; 174 try { 175 in = new DataInputStream(new BufferedInputStream(new FileInputStream(filePath))); 176 177 int version = in.readInt(); 178 if (version != 2 && version != 1) { 179 loge("Bad version on IP configuration file, ignore read"); 180 return null; 181 } 182 183 while (true) { 184 int id = -1; 185 // Default is DHCP with no proxy 186 IpAssignment ipAssignment = IpAssignment.DHCP; 187 ProxySettings proxySettings = ProxySettings.NONE; 188 StaticIpConfiguration staticIpConfiguration = new StaticIpConfiguration(); 189 String proxyHost = null; 190 String pacFileUrl = null; 191 int proxyPort = -1; 192 String exclusionList = null; 193 String key; 194 195 do { 196 key = in.readUTF(); 197 try { 198 if (key.equals(ID_KEY)) { 199 id = in.readInt(); 200 } else if (key.equals(IP_ASSIGNMENT_KEY)) { 201 ipAssignment = IpAssignment.valueOf(in.readUTF()); 202 } else if (key.equals(LINK_ADDRESS_KEY)) { 203 LinkAddress linkAddr = new LinkAddress( 204 NetworkUtils.numericToInetAddress(in.readUTF()), in.readInt()); 205 if (linkAddr.getAddress() instanceof Inet4Address && 206 staticIpConfiguration.ipAddress == null) { 207 staticIpConfiguration.ipAddress = linkAddr; 208 } else { 209 loge("Non-IPv4 or duplicate address: " + linkAddr); 210 } 211 } else if (key.equals(GATEWAY_KEY)) { 212 LinkAddress dest = null; 213 InetAddress gateway = null; 214 if (version == 1) { 215 // only supported default gateways - leave the dest/prefix empty 216 gateway = NetworkUtils.numericToInetAddress(in.readUTF()); 217 if (staticIpConfiguration.gateway == null) { 218 staticIpConfiguration.gateway = gateway; 219 } else { 220 loge("Duplicate gateway: " + gateway.getHostAddress()); 221 } 222 } else { 223 if (in.readInt() == 1) { 224 dest = new LinkAddress( 225 NetworkUtils.numericToInetAddress(in.readUTF()), 226 in.readInt()); 227 } 228 if (in.readInt() == 1) { 229 gateway = NetworkUtils.numericToInetAddress(in.readUTF()); 230 } 231 RouteInfo route = new RouteInfo(dest, gateway); 232 if (route.isIPv4Default() && 233 staticIpConfiguration.gateway == null) { 234 staticIpConfiguration.gateway = gateway; 235 } else { 236 loge("Non-IPv4 default or duplicate route: " + route); 237 } 238 } 239 } else if (key.equals(DNS_KEY)) { 240 staticIpConfiguration.dnsServers.add( 241 NetworkUtils.numericToInetAddress(in.readUTF())); 242 } else if (key.equals(PROXY_SETTINGS_KEY)) { 243 proxySettings = ProxySettings.valueOf(in.readUTF()); 244 } else if (key.equals(PROXY_HOST_KEY)) { 245 proxyHost = in.readUTF(); 246 } else if (key.equals(PROXY_PORT_KEY)) { 247 proxyPort = in.readInt(); 248 } else if (key.equals(PROXY_PAC_FILE)) { 249 pacFileUrl = in.readUTF(); 250 } else if (key.equals(EXCLUSION_LIST_KEY)) { 251 exclusionList = in.readUTF(); 252 } else if (key.equals(EOS)) { 253 break; 254 } else { 255 loge("Ignore unknown key " + key + "while reading"); 256 } 257 } catch (IllegalArgumentException e) { 258 loge("Ignore invalid address while reading" + e); 259 } 260 } while (true); 261 262 if (id != -1) { 263 IpConfiguration config = new IpConfiguration(); 264 networks.put(id, config); 265 266 switch (ipAssignment) { 267 case STATIC: 268 config.staticIpConfiguration = staticIpConfiguration; 269 config.ipAssignment = ipAssignment; 270 break; 271 case DHCP: 272 config.ipAssignment = ipAssignment; 273 break; 274 case UNASSIGNED: 275 loge("BUG: Found UNASSIGNED IP on file, use DHCP"); 276 config.ipAssignment = IpAssignment.DHCP; 277 break; 278 default: 279 loge("Ignore invalid ip assignment while reading."); 280 config.ipAssignment = IpAssignment.UNASSIGNED; 281 break; 282 } 283 284 switch (proxySettings) { 285 case STATIC: 286 ProxyInfo proxyInfo = 287 new ProxyInfo(proxyHost, proxyPort, exclusionList); 288 config.proxySettings = proxySettings; 289 config.httpProxy = proxyInfo; 290 break; 291 case PAC: 292 ProxyInfo proxyPacProperties = new ProxyInfo(pacFileUrl); 293 config.proxySettings = proxySettings; 294 config.httpProxy = proxyPacProperties; 295 break; 296 case NONE: 297 config.proxySettings = proxySettings; 298 break; 299 case UNASSIGNED: 300 loge("BUG: Found UNASSIGNED proxy on file, use NONE"); 301 config.proxySettings = ProxySettings.NONE; 302 break; 303 default: 304 loge("Ignore invalid proxy settings while reading"); 305 config.proxySettings = ProxySettings.UNASSIGNED; 306 break; 307 } 308 } else { 309 if (DBG) log("Missing id while parsing configuration"); 310 } 311 } 312 } catch (EOFException ignore) { 313 } catch (IOException e) { 314 loge("Error parsing configuration: " + e); 315 } finally { 316 if (in != null) { 317 try { 318 in.close(); 319 } catch (Exception e) {} 320 } 321 } 322 323 return networks; 324 } 325 326 protected void loge(String s) { 327 Log.e(TAG, s); 328 } 329 330 protected void log(String s) { 331 Log.d(TAG, s); 332 } 333 } 334