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