Home | History | Annotate | Download | only in net
      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.internal.annotations.VisibleForTesting;
     31 import com.android.server.net.DelayedDiskWrite;
     32 
     33 import java.io.BufferedInputStream;
     34 import java.io.DataInputStream;
     35 import java.io.DataOutputStream;
     36 import java.io.EOFException;
     37 import java.io.FileInputStream;
     38 import java.io.FileNotFoundException;
     39 import java.io.IOException;
     40 import java.io.InputStream;
     41 import java.net.InetAddress;
     42 import java.net.Inet4Address;
     43 
     44 public class IpConfigStore {
     45     private static final String TAG = "IpConfigStore";
     46     private static final boolean DBG = false;
     47 
     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 
     65     public IpConfigStore(DelayedDiskWrite writer) {
     66         mWriter = writer;
     67     }
     68 
     69     public IpConfigStore() {
     70         this(new DelayedDiskWrite());
     71     }
     72 
     73     @VisibleForTesting
     74     public static boolean writeConfig(DataOutputStream out, int configKey,
     75                                 IpConfiguration config) throws IOException {
     76         boolean written = false;
     77 
     78         try {
     79             switch (config.ipAssignment) {
     80                 case STATIC:
     81                     out.writeUTF(IP_ASSIGNMENT_KEY);
     82                     out.writeUTF(config.ipAssignment.toString());
     83                     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());
     90                         }
     91                         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());
     96                         }
     97                         for (InetAddress inetAddr : staticIpConfiguration.dnsServers) {
     98                             out.writeUTF(DNS_KEY);
     99                             out.writeUTF(inetAddr.getHostAddress());
    100                         }
    101                     }
    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:
    119                     ProxyInfo proxyProperties = config.httpProxy;
    120                     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());
    127                     if (exclusionList != null) {
    128                         out.writeUTF(EXCLUSION_LIST_KEY);
    129                         out.writeUTF(exclusionList);
    130                     }
    131                     written = true;
    132                     break;
    133                 case PAC:
    134                     ProxyInfo proxyPacProperties = config.httpProxy;
    135                     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) {
    159             loge("Failure in writing " + config + e);
    160         }
    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 
    178     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     }
    190 
    191     public static SparseArray<IpConfiguration> readIpAndProxyConfigurations(
    192             InputStream inputStream) {
    193         SparseArray<IpConfiguration> networks = new SparseArray<IpConfiguration>();
    194         DataInputStream in = null;
    195         try {
    196             in = new DataInputStream(inputStream);
    197 
    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;
    209                 StaticIpConfiguration staticIpConfiguration = new StaticIpConfiguration();
    210                 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());
    226                             if (linkAddr.getAddress() instanceof Inet4Address &&
    227                                     staticIpConfiguration.ipAddress == null) {
    228                                 staticIpConfiguration.ipAddress = linkAddr;
    229                             } else {
    230                                 loge("Non-IPv4 or duplicate address: " + linkAddr);
    231                             }
    232                         } 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());
    238                                 if (staticIpConfiguration.gateway == null) {
    239                                     staticIpConfiguration.gateway = gateway;
    240                                 } else {
    241                                     loge("Duplicate gateway: " + gateway.getHostAddress());
    242                                 }
    243                             } 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                                 }
    252                                 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                                 }
    259                             }
    260                         } else if (key.equals(DNS_KEY)) {
    261                             staticIpConfiguration.dnsServers.add(
    262                                     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 
    287                     switch (ipAssignment) {
    288                         case STATIC:
    289                             config.staticIpConfiguration = staticIpConfiguration;
    290                             config.ipAssignment = ipAssignment;
    291                             break;
    292                         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:
    307                             ProxyInfo proxyInfo =
    308                                     new ProxyInfo(proxyHost, proxyPort, exclusionList);
    309                             config.proxySettings = proxySettings;
    310                             config.httpProxy = proxyInfo;
    311                             break;
    312                         case PAC:
    313                             ProxyInfo proxyPacProperties = new ProxyInfo(pacFileUrl);
    314                             config.proxySettings = proxySettings;
    315                             config.httpProxy = proxyPacProperties;
    316                             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) {
    335             loge("Error parsing configuration: " + e);
    336         } finally {
    337             if (in != null) {
    338                 try {
    339                     in.close();
    340                 } catch (Exception e) {}
    341             }
    342         }
    343 
    344         return networks;
    345     }
    346 
    347     protected static void loge(String s) {
    348         Log.e(TAG, s);
    349     }
    350 
    351     protected static void log(String s) {
    352         Log.d(TAG, s);
    353     }
    354 }
    355