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