IpConfigStore.java revision 79adc958e5cd8daf7231ec042dfa367010d415f4
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
17package com.android.server.net;
18
19import android.net.IpConfiguration;
20import android.net.IpConfiguration.IpAssignment;
21import android.net.IpConfiguration.ProxySettings;
22import android.net.LinkAddress;
23import android.net.NetworkUtils;
24import android.net.ProxyInfo;
25import android.net.RouteInfo;
26import android.net.StaticIpConfiguration;
27import android.os.Handler;
28import android.os.HandlerThread;
29import android.text.TextUtils;
30import android.util.Log;
31import android.util.SparseArray;
32
33import com.android.server.net.DelayedDiskWrite;
34
35import java.io.BufferedInputStream;
36import java.io.BufferedOutputStream;
37import java.io.DataInputStream;
38import java.io.DataOutputStream;
39import java.io.EOFException;
40import java.io.FileInputStream;
41import java.io.FileOutputStream;
42import java.io.IOException;
43import java.net.InetAddress;
44import java.net.Inet4Address;
45import java.util.Map;
46
47public 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