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.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