/* * Copyright (C) 2014 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.net; import android.net.IpConfiguration; import android.net.IpConfiguration.IpAssignment; import android.net.IpConfiguration.ProxySettings; import android.net.LinkAddress; import android.net.NetworkUtils; import android.net.ProxyInfo; import android.net.RouteInfo; import android.net.StaticIpConfiguration; import android.os.Handler; import android.os.HandlerThread; import android.text.TextUtils; import android.util.Log; import android.util.SparseArray; import com.android.server.net.DelayedDiskWrite; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.EOFException; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.net.InetAddress; import java.net.Inet4Address; import java.util.Map; public class IpConfigStore { private static final String TAG = "IpConfigStore"; private static final boolean DBG = true; protected final DelayedDiskWrite mWriter; /* IP and proxy configuration keys */ protected static final String ID_KEY = "id"; protected static final String IP_ASSIGNMENT_KEY = "ipAssignment"; protected static final String LINK_ADDRESS_KEY = "linkAddress"; protected static final String GATEWAY_KEY = "gateway"; protected static final String DNS_KEY = "dns"; protected static final String PROXY_SETTINGS_KEY = "proxySettings"; protected static final String PROXY_HOST_KEY = "proxyHost"; protected static final String PROXY_PORT_KEY = "proxyPort"; protected static final String PROXY_PAC_FILE = "proxyPac"; protected static final String EXCLUSION_LIST_KEY = "exclusionList"; protected static final String EOS = "eos"; protected static final int IPCONFIG_FILE_VERSION = 2; public IpConfigStore() { mWriter = new DelayedDiskWrite(); } private boolean writeConfig(DataOutputStream out, int configKey, IpConfiguration config) throws IOException { boolean written = false; try { switch (config.ipAssignment) { case STATIC: out.writeUTF(IP_ASSIGNMENT_KEY); out.writeUTF(config.ipAssignment.toString()); StaticIpConfiguration staticIpConfiguration = config.staticIpConfiguration; if (staticIpConfiguration != null) { if (staticIpConfiguration.ipAddress != null) { LinkAddress ipAddress = staticIpConfiguration.ipAddress; out.writeUTF(LINK_ADDRESS_KEY); out.writeUTF(ipAddress.getAddress().getHostAddress()); out.writeInt(ipAddress.getPrefixLength()); } if (staticIpConfiguration.gateway != null) { out.writeUTF(GATEWAY_KEY); out.writeInt(0); // Default route. out.writeInt(1); // Have a gateway. out.writeUTF(staticIpConfiguration.gateway.getHostAddress()); } for (InetAddress inetAddr : staticIpConfiguration.dnsServers) { out.writeUTF(DNS_KEY); out.writeUTF(inetAddr.getHostAddress()); } } written = true; break; case DHCP: out.writeUTF(IP_ASSIGNMENT_KEY); out.writeUTF(config.ipAssignment.toString()); written = true; break; case UNASSIGNED: /* Ignore */ break; default: loge("Ignore invalid ip assignment while writing"); break; } switch (config.proxySettings) { case STATIC: ProxyInfo proxyProperties = config.httpProxy; String exclusionList = proxyProperties.getExclusionListAsString(); out.writeUTF(PROXY_SETTINGS_KEY); out.writeUTF(config.proxySettings.toString()); out.writeUTF(PROXY_HOST_KEY); out.writeUTF(proxyProperties.getHost()); out.writeUTF(PROXY_PORT_KEY); out.writeInt(proxyProperties.getPort()); if (exclusionList != null) { out.writeUTF(EXCLUSION_LIST_KEY); out.writeUTF(exclusionList); } written = true; break; case PAC: ProxyInfo proxyPacProperties = config.httpProxy; out.writeUTF(PROXY_SETTINGS_KEY); out.writeUTF(config.proxySettings.toString()); out.writeUTF(PROXY_PAC_FILE); out.writeUTF(proxyPacProperties.getPacFileUrl().toString()); written = true; break; case NONE: out.writeUTF(PROXY_SETTINGS_KEY); out.writeUTF(config.proxySettings.toString()); written = true; break; case UNASSIGNED: /* Ignore */ break; default: loge("Ignore invalid proxy settings while writing"); break; } if (written) { out.writeUTF(ID_KEY); out.writeInt(configKey); } } catch (NullPointerException e) { loge("Failure in writing " + config + e); } out.writeUTF(EOS); return written; } public void writeIpAndProxyConfigurations(String filePath, final SparseArray networks) { mWriter.write(filePath, new DelayedDiskWrite.Writer() { public void onWriteCalled(DataOutputStream out) throws IOException{ out.writeInt(IPCONFIG_FILE_VERSION); for(int i = 0; i < networks.size(); i++) { writeConfig(out, networks.keyAt(i), networks.valueAt(i)); } } }); } public SparseArray readIpAndProxyConfigurations(String filePath) { SparseArray networks = new SparseArray(); DataInputStream in = null; try { in = new DataInputStream(new BufferedInputStream(new FileInputStream(filePath))); int version = in.readInt(); if (version != 2 && version != 1) { loge("Bad version on IP configuration file, ignore read"); return null; } while (true) { int id = -1; // Default is DHCP with no proxy IpAssignment ipAssignment = IpAssignment.DHCP; ProxySettings proxySettings = ProxySettings.NONE; StaticIpConfiguration staticIpConfiguration = new StaticIpConfiguration(); String proxyHost = null; String pacFileUrl = null; int proxyPort = -1; String exclusionList = null; String key; do { key = in.readUTF(); try { if (key.equals(ID_KEY)) { id = in.readInt(); } else if (key.equals(IP_ASSIGNMENT_KEY)) { ipAssignment = IpAssignment.valueOf(in.readUTF()); } else if (key.equals(LINK_ADDRESS_KEY)) { LinkAddress linkAddr = new LinkAddress( NetworkUtils.numericToInetAddress(in.readUTF()), in.readInt()); if (linkAddr.getAddress() instanceof Inet4Address && staticIpConfiguration.ipAddress == null) { staticIpConfiguration.ipAddress = linkAddr; } else { loge("Non-IPv4 or duplicate address: " + linkAddr); } } else if (key.equals(GATEWAY_KEY)) { LinkAddress dest = null; InetAddress gateway = null; if (version == 1) { // only supported default gateways - leave the dest/prefix empty gateway = NetworkUtils.numericToInetAddress(in.readUTF()); if (staticIpConfiguration.gateway == null) { staticIpConfiguration.gateway = gateway; } else { loge("Duplicate gateway: " + gateway.getHostAddress()); } } else { if (in.readInt() == 1) { dest = new LinkAddress( NetworkUtils.numericToInetAddress(in.readUTF()), in.readInt()); } if (in.readInt() == 1) { gateway = NetworkUtils.numericToInetAddress(in.readUTF()); } RouteInfo route = new RouteInfo(dest, gateway); if (route.isIPv4Default() && staticIpConfiguration.gateway == null) { staticIpConfiguration.gateway = gateway; } else { loge("Non-IPv4 default or duplicate route: " + route); } } } else if (key.equals(DNS_KEY)) { staticIpConfiguration.dnsServers.add( NetworkUtils.numericToInetAddress(in.readUTF())); } else if (key.equals(PROXY_SETTINGS_KEY)) { proxySettings = ProxySettings.valueOf(in.readUTF()); } else if (key.equals(PROXY_HOST_KEY)) { proxyHost = in.readUTF(); } else if (key.equals(PROXY_PORT_KEY)) { proxyPort = in.readInt(); } else if (key.equals(PROXY_PAC_FILE)) { pacFileUrl = in.readUTF(); } else if (key.equals(EXCLUSION_LIST_KEY)) { exclusionList = in.readUTF(); } else if (key.equals(EOS)) { break; } else { loge("Ignore unknown key " + key + "while reading"); } } catch (IllegalArgumentException e) { loge("Ignore invalid address while reading" + e); } } while (true); if (id != -1) { IpConfiguration config = new IpConfiguration(); networks.put(id, config); switch (ipAssignment) { case STATIC: config.staticIpConfiguration = staticIpConfiguration; config.ipAssignment = ipAssignment; break; case DHCP: config.ipAssignment = ipAssignment; break; case UNASSIGNED: loge("BUG: Found UNASSIGNED IP on file, use DHCP"); config.ipAssignment = IpAssignment.DHCP; break; default: loge("Ignore invalid ip assignment while reading."); config.ipAssignment = IpAssignment.UNASSIGNED; break; } switch (proxySettings) { case STATIC: ProxyInfo proxyInfo = new ProxyInfo(proxyHost, proxyPort, exclusionList); config.proxySettings = proxySettings; config.httpProxy = proxyInfo; break; case PAC: ProxyInfo proxyPacProperties = new ProxyInfo(pacFileUrl); config.proxySettings = proxySettings; config.httpProxy = proxyPacProperties; break; case NONE: config.proxySettings = proxySettings; break; case UNASSIGNED: loge("BUG: Found UNASSIGNED proxy on file, use NONE"); config.proxySettings = ProxySettings.NONE; break; default: loge("Ignore invalid proxy settings while reading"); config.proxySettings = ProxySettings.UNASSIGNED; break; } } else { if (DBG) log("Missing id while parsing configuration"); } } } catch (EOFException ignore) { } catch (IOException e) { loge("Error parsing configuration: " + e); } finally { if (in != null) { try { in.close(); } catch (Exception e) {} } } return networks; } protected void loge(String s) { Log.e(TAG, s); } protected void log(String s) { Log.d(TAG, s); } }