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