1 /*
2  * Copyright (C) 2017 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 android.net.ip;
18 
19 import android.net.INetd;
20 import android.net.InterfaceConfigurationParcel;
21 import android.net.LinkAddress;
22 import android.net.util.SharedLog;
23 import android.os.RemoteException;
24 import android.os.ServiceSpecificException;
25 import android.system.OsConstants;
26 
27 import java.net.Inet4Address;
28 import java.net.InetAddress;
29 
30 
31 /**
32  * Encapsulates the multiple IP configuration operations performed on an interface.
33  *
34  * TODO: refactor/eliminate the redundant ways to set and clear addresses.
35  *
36  * @hide
37  */
38 public class InterfaceController {
39     private final static boolean DBG = false;
40 
41     private final String mIfName;
42     private final INetd mNetd;
43     private final SharedLog mLog;
44 
InterfaceController(String ifname, INetd netd, SharedLog log)45     public InterfaceController(String ifname, INetd netd, SharedLog log) {
46         mIfName = ifname;
47         mNetd = netd;
48         mLog = log;
49     }
50 
setInterfaceAddress(LinkAddress addr)51     private boolean setInterfaceAddress(LinkAddress addr) {
52         final InterfaceConfigurationParcel ifConfig = new InterfaceConfigurationParcel();
53         ifConfig.ifName = mIfName;
54         ifConfig.ipv4Addr = addr.getAddress().getHostAddress();
55         ifConfig.prefixLength = addr.getPrefixLength();
56         ifConfig.hwAddr = "";
57         ifConfig.flags = new String[0];
58         try {
59             mNetd.interfaceSetCfg(ifConfig);
60         } catch (RemoteException | ServiceSpecificException e) {
61             logError("Setting IPv4 address to %s/%d failed: %s",
62                     ifConfig.ipv4Addr, ifConfig.prefixLength, e);
63             return false;
64         }
65         return true;
66     }
67 
68     /**
69      * Set the IPv4 address of the interface.
70      */
setIPv4Address(LinkAddress address)71     public boolean setIPv4Address(LinkAddress address) {
72         if (!(address.getAddress() instanceof Inet4Address)) {
73             return false;
74         }
75         return setInterfaceAddress(address);
76     }
77 
78     /**
79      * Clear the IPv4Address of the interface.
80      */
clearIPv4Address()81     public boolean clearIPv4Address() {
82         return setInterfaceAddress(new LinkAddress("0.0.0.0/0"));
83     }
84 
setEnableIPv6(boolean enabled)85     private boolean setEnableIPv6(boolean enabled) {
86         try {
87             mNetd.interfaceSetEnableIPv6(mIfName, enabled);
88         } catch (RemoteException | ServiceSpecificException e) {
89             logError("%s IPv6 failed: %s", (enabled ? "enabling" : "disabling"), e);
90             return false;
91         }
92         return true;
93     }
94 
95     /**
96      * Enable IPv6 on the interface.
97      */
enableIPv6()98     public boolean enableIPv6() {
99         return setEnableIPv6(true);
100     }
101 
102     /**
103      * Disable IPv6 on the interface.
104      */
disableIPv6()105     public boolean disableIPv6() {
106         return setEnableIPv6(false);
107     }
108 
109     /**
110      * Enable or disable IPv6 privacy extensions on the interface.
111      * @param enabled Whether the extensions should be enabled.
112      */
setIPv6PrivacyExtensions(boolean enabled)113     public boolean setIPv6PrivacyExtensions(boolean enabled) {
114         try {
115             mNetd.interfaceSetIPv6PrivacyExtensions(mIfName, enabled);
116         } catch (RemoteException | ServiceSpecificException e) {
117             logError("error %s IPv6 privacy extensions: %s",
118                     (enabled ? "enabling" : "disabling"), e);
119             return false;
120         }
121         return true;
122     }
123 
124     /**
125      * Set IPv6 address generation mode on the interface.
126      *
127      * <p>IPv6 should be disabled before changing the mode.
128      */
setIPv6AddrGenModeIfSupported(int mode)129     public boolean setIPv6AddrGenModeIfSupported(int mode) {
130         try {
131             mNetd.setIPv6AddrGenMode(mIfName, mode);
132         } catch (RemoteException e) {
133             logError("Unable to set IPv6 addrgen mode: %s", e);
134             return false;
135         } catch (ServiceSpecificException e) {
136             if (e.errorCode != OsConstants.EOPNOTSUPP) {
137                 logError("Unable to set IPv6 addrgen mode: %s", e);
138                 return false;
139             }
140         }
141         return true;
142     }
143 
144     /**
145      * Add an address to the interface.
146      */
addAddress(LinkAddress addr)147     public boolean addAddress(LinkAddress addr) {
148         return addAddress(addr.getAddress(), addr.getPrefixLength());
149     }
150 
151     /**
152      * Add an address to the interface.
153      */
addAddress(InetAddress ip, int prefixLen)154     public boolean addAddress(InetAddress ip, int prefixLen) {
155         try {
156             mNetd.interfaceAddAddress(mIfName, ip.getHostAddress(), prefixLen);
157         } catch (ServiceSpecificException | RemoteException e) {
158             logError("failed to add %s/%d: %s", ip, prefixLen, e);
159             return false;
160         }
161         return true;
162     }
163 
164     /**
165      * Remove an address from the interface.
166      */
removeAddress(InetAddress ip, int prefixLen)167     public boolean removeAddress(InetAddress ip, int prefixLen) {
168         try {
169             mNetd.interfaceDelAddress(mIfName, ip.getHostAddress(), prefixLen);
170         } catch (ServiceSpecificException | RemoteException e) {
171             logError("failed to remove %s/%d: %s", ip, prefixLen, e);
172             return false;
173         }
174         return true;
175     }
176 
177     /**
178      * Remove all addresses from the interface.
179      */
clearAllAddresses()180     public boolean clearAllAddresses() {
181         try {
182             mNetd.interfaceClearAddrs(mIfName);
183         } catch (Exception e) {
184             logError("Failed to clear addresses: %s", e);
185             return false;
186         }
187         return true;
188     }
189 
logError(String fmt, Object... args)190     private void logError(String fmt, Object... args) {
191         mLog.e(String.format(fmt, args));
192     }
193 }
194