blob: 4e211142f0b3cc3eb9a0beb95648fbf20f163139 [file] [log] [blame]
Szymon Jakubczaka0efaec2014-02-14 17:09:43 -05001/*
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
Sreeram Ramachandran72604072014-05-21 13:19:43 -070017// THREAD-SAFETY
18// -------------
19// The methods in this file are called from multiple threads (from CommandListener, FwmarkServer
20// and DnsProxyListener). So, all accesses to shared state are guarded by a lock.
21//
22// In some cases, a single non-const method acquires and releases the lock several times, like so:
23// if (isValidNetwork(...)) { // isValidNetwork() acquires and releases the lock.
24// setDefaultNetwork(...); // setDefaultNetwork() also acquires and releases the lock.
25//
26// It might seem that this allows races where the state changes between the two statements, but in
27// fact there are no races because:
28// 1. This pattern only occurs in non-const methods (i.e., those that mutate state).
29// 2. Only CommandListener calls these non-const methods. The others call only const methods.
30// 3. CommandListener only processes one command at a time. I.e., it's serialized.
31// Thus, no other mutation can occur in between the two statements above.
Szymon Jakubczaka0efaec2014-02-14 17:09:43 -050032
33#include "NetworkController.h"
34
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -070035#include "PermissionsController.h"
36#include "RouteController.h"
37
Sreeram Ramachandran72604072014-05-21 13:19:43 -070038#define LOG_TAG "NetworkController"
39#include "cutils/log.h"
40#include "resolv_netid.h"
41
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -070042namespace {
43
44// Keep these in sync with ConnectivityService.java.
45const unsigned int MIN_NET_ID = 10;
46const unsigned int MAX_NET_ID = 65535;
47
48} // namespace
49
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -070050NetworkController::NetworkController(PermissionsController* permissionsController,
51 RouteController* routeController)
Sreeram Ramachandran574e6332014-05-14 08:31:55 -070052 : mDefaultNetId(NETID_UNSET),
53 mPermissionsController(permissionsController),
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -070054 mRouteController(routeController) {
55}
Szymon Jakubczaka0efaec2014-02-14 17:09:43 -050056
57void NetworkController::clearNetworkPreference() {
58 android::RWLock::AutoWLock lock(mRWLock);
59 mUidMap.clear();
Szymon Jakubczaka0efaec2014-02-14 17:09:43 -050060}
61
62unsigned NetworkController::getDefaultNetwork() const {
Sreeram Ramachandran9c0d3132014-04-10 20:35:04 -070063 android::RWLock::AutoRLock lock(mRWLock);
Szymon Jakubczaka0efaec2014-02-14 17:09:43 -050064 return mDefaultNetId;
65}
66
Sreeram Ramachandran9c0d3132014-04-10 20:35:04 -070067bool NetworkController::setDefaultNetwork(unsigned newNetId) {
Sreeram Ramachandran72604072014-05-21 13:19:43 -070068 // newNetId must be either NETID_UNSET or a valid network. If it's NETID_UNSET, the caller is
69 // asking for there to be no default network, which is a request we support.
70 if (newNetId != NETID_UNSET && !isValidNetwork(newNetId)) {
71 ALOGE("invalid netId %u", newNetId);
Lorenzo Colittice8f5832014-05-29 12:20:55 +090072 errno = EINVAL;
Sreeram Ramachandran72604072014-05-21 13:19:43 -070073 return false;
74 }
75
Sreeram Ramachandran9c0d3132014-04-10 20:35:04 -070076 unsigned oldNetId;
77 {
78 android::RWLock::AutoWLock lock(mRWLock);
79 oldNetId = mDefaultNetId;
80 mDefaultNetId = newNetId;
81 }
82
83 if (oldNetId == newNetId) {
84 return true;
85 }
86
87 bool status = true;
Sreeram Ramachandran72604072014-05-21 13:19:43 -070088 Permission permission;
89 InterfaceRange range;
Sreeram Ramachandran9c0d3132014-04-10 20:35:04 -070090
91 // Add default network rules for the new netId.
Sreeram Ramachandran72604072014-05-21 13:19:43 -070092 permission = mPermissionsController->getPermissionForNetwork(newNetId);
93 range = mNetIdToInterfaces.equal_range(newNetId);
94 for (InterfaceIteratorConst iter = range.first; iter != range.second; ++iter) {
95 if (!mRouteController->addToDefaultNetwork(iter->second.c_str(), permission)) {
96 ALOGE("failed to add interface %s to default netId %u", iter->second.c_str(), newNetId);
97 status = false;
Sreeram Ramachandran9c0d3132014-04-10 20:35:04 -070098 }
99 }
100
101 // Remove the old default network rules.
Sreeram Ramachandran72604072014-05-21 13:19:43 -0700102 permission = mPermissionsController->getPermissionForNetwork(oldNetId);
103 range = mNetIdToInterfaces.equal_range(oldNetId);
104 for (InterfaceIteratorConst iter = range.first; iter != range.second; ++iter) {
105 if (!mRouteController->removeFromDefaultNetwork(iter->second.c_str(), permission)) {
106 ALOGE("failed to remove interface %s from default netId %u", iter->second.c_str(),
107 oldNetId);
108 status = false;
Sreeram Ramachandran9c0d3132014-04-10 20:35:04 -0700109 }
110 }
111
112 return status;
Szymon Jakubczaka0efaec2014-02-14 17:09:43 -0500113}
114
Szymon Jakubczaka0efaec2014-02-14 17:09:43 -0500115bool NetworkController::setNetworkForUidRange(int uid_start, int uid_end, unsigned netId,
Sreeram Ramachandran72604072014-05-21 13:19:43 -0700116 bool forward_dns) {
Lorenzo Colittice8f5832014-05-29 12:20:55 +0900117 if (uid_start > uid_end || !isValidNetwork(netId)) {
118 errno = EINVAL;
Szymon Jakubczaka0efaec2014-02-14 17:09:43 -0500119 return false;
Lorenzo Colittice8f5832014-05-29 12:20:55 +0900120 }
Szymon Jakubczaka0efaec2014-02-14 17:09:43 -0500121
Sreeram Ramachandran72604072014-05-21 13:19:43 -0700122 android::RWLock::AutoWLock lock(mRWLock);
Szymon Jakubczaka0efaec2014-02-14 17:09:43 -0500123 for (std::list<UidEntry>::iterator it = mUidMap.begin(); it != mUidMap.end(); ++it) {
Paul Jensen5b49ab92014-04-03 19:06:00 -0400124 if (it->uid_start != uid_start || it->uid_end != uid_end || it->netId != netId)
Szymon Jakubczaka0efaec2014-02-14 17:09:43 -0500125 continue;
Paul Jensen5b49ab92014-04-03 19:06:00 -0400126 it->forward_dns = forward_dns;
Szymon Jakubczaka0efaec2014-02-14 17:09:43 -0500127 return true;
128 }
129
Paul Jensen5b49ab92014-04-03 19:06:00 -0400130 mUidMap.push_front(UidEntry(uid_start, uid_end, netId, forward_dns));
Szymon Jakubczaka0efaec2014-02-14 17:09:43 -0500131 return true;
132}
133
Paul Jensen5b49ab92014-04-03 19:06:00 -0400134bool NetworkController::clearNetworkForUidRange(int uid_start, int uid_end, unsigned netId) {
Lorenzo Colittice8f5832014-05-29 12:20:55 +0900135 if (uid_start > uid_end || !isValidNetwork(netId)) {
136 errno = EINVAL;
Paul Jensen5b49ab92014-04-03 19:06:00 -0400137 return false;
Lorenzo Colittice8f5832014-05-29 12:20:55 +0900138 }
Paul Jensen5b49ab92014-04-03 19:06:00 -0400139
Sreeram Ramachandran72604072014-05-21 13:19:43 -0700140 android::RWLock::AutoWLock lock(mRWLock);
Paul Jensen5b49ab92014-04-03 19:06:00 -0400141 for (std::list<UidEntry>::iterator it = mUidMap.begin(); it != mUidMap.end(); ++it) {
142 if (it->uid_start != uid_start || it->uid_end != uid_end || it->netId != netId)
143 continue;
144 mUidMap.erase(it);
145 return true;
146 }
Lorenzo Colittice8f5832014-05-29 12:20:55 +0900147
148 errno = ENOENT;
Paul Jensen5b49ab92014-04-03 19:06:00 -0400149 return false;
150}
151
Paul Jensen35c77e32014-04-10 14:57:54 -0400152unsigned NetworkController::getNetwork(int uid, unsigned requested_netId, bool for_dns) const {
Szymon Jakubczaka0efaec2014-02-14 17:09:43 -0500153 android::RWLock::AutoRLock lock(mRWLock);
154 for (std::list<UidEntry>::const_iterator it = mUidMap.begin(); it != mUidMap.end(); ++it) {
155 if (uid < it->uid_start || it->uid_end < uid)
156 continue;
157 if (for_dns && !it->forward_dns)
158 break;
159 return it->netId;
160 }
Sreeram Ramachandran72604072014-05-21 13:19:43 -0700161 if (mValidNetworks.find(requested_netId) != mValidNetworks.end())
Szymon Jakubczaka0efaec2014-02-14 17:09:43 -0500162 return requested_netId;
Szymon Jakubczaka0efaec2014-02-14 17:09:43 -0500163 return mDefaultNetId;
164}
165
Sreeram Ramachandran72604072014-05-21 13:19:43 -0700166unsigned NetworkController::getNetworkId(const char* interface) const {
167 for (InterfaceIteratorConst iter = mNetIdToInterfaces.begin(); iter != mNetIdToInterfaces.end();
168 ++iter) {
169 if (iter->second == interface) {
170 return iter->first;
171 }
172 }
Paul Jensen35c77e32014-04-10 14:57:54 -0400173 return NETID_UNSET;
Szymon Jakubczaka0efaec2014-02-14 17:09:43 -0500174}
175
Paul Jensenae37e8a2014-04-28 10:35:51 -0400176bool NetworkController::createNetwork(unsigned netId, Permission permission) {
Sreeram Ramachandran72604072014-05-21 13:19:43 -0700177 if (netId < MIN_NET_ID || netId > MAX_NET_ID) {
Paul Jensenae37e8a2014-04-28 10:35:51 -0400178 ALOGE("invalid netId %u", netId);
Lorenzo Colittice8f5832014-05-29 12:20:55 +0900179 errno = EINVAL;
Paul Jensenae37e8a2014-04-28 10:35:51 -0400180 return false;
181 }
182
Sreeram Ramachandran72604072014-05-21 13:19:43 -0700183 {
184 android::RWLock::AutoWLock lock(mRWLock);
185 if (!mValidNetworks.insert(netId).second) {
186 ALOGE("duplicate netId %u", netId);
Lorenzo Colittice8f5832014-05-29 12:20:55 +0900187 errno = EEXIST;
Sreeram Ramachandran72604072014-05-21 13:19:43 -0700188 return false;
189 }
190 }
191
Paul Jensenae37e8a2014-04-28 10:35:51 -0400192 mPermissionsController->setPermissionForNetwork(permission, netId);
193 return true;
194}
195
196bool NetworkController::addInterfaceToNetwork(unsigned netId, const char* interface) {
Sreeram Ramachandran72604072014-05-21 13:19:43 -0700197 if (!isValidNetwork(netId) || !interface) {
Sreeram Ramachandran379bd332014-04-10 19:58:06 -0700198 ALOGE("invalid netId %u or interface null", netId);
Lorenzo Colittice8f5832014-05-29 12:20:55 +0900199 errno = EINVAL;
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -0700200 return false;
201 }
202
Sreeram Ramachandran72604072014-05-21 13:19:43 -0700203 unsigned existingNetId = getNetworkId(interface);
Sreeram Ramachandran7619e1b2014-04-15 14:23:08 -0700204 if (existingNetId != NETID_UNSET) {
205 ALOGE("interface %s already assigned to netId %u", interface, existingNetId);
Lorenzo Colittice8f5832014-05-29 12:20:55 +0900206 errno = EBUSY;
Sreeram Ramachandran7619e1b2014-04-15 14:23:08 -0700207 return false;
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -0700208 }
209
Paul Jensenae37e8a2014-04-28 10:35:51 -0400210 Permission permission = mPermissionsController->getPermissionForNetwork(netId);
211 if (!mRouteController->addInterfaceToNetwork(netId, interface, permission)) {
Sreeram Ramachandran72604072014-05-21 13:19:43 -0700212 ALOGE("failed to add interface %s to netId %u", interface, netId);
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -0700213 return false;
214 }
215
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -0700216 mNetIdToInterfaces.insert(std::pair<unsigned, std::string>(netId, interface));
Paul Jensenae37e8a2014-04-28 10:35:51 -0400217
218 if (netId == getDefaultNetwork() &&
Sreeram Ramachandran72604072014-05-21 13:19:43 -0700219 !mRouteController->addToDefaultNetwork(interface, permission)) {
220 ALOGE("failed to add interface %s to default netId %u", interface, netId);
Paul Jensenae37e8a2014-04-28 10:35:51 -0400221 return false;
222 }
223
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -0700224 return true;
225}
226
Paul Jensenae37e8a2014-04-28 10:35:51 -0400227bool NetworkController::removeInterfaceFromNetwork(unsigned netId, const char* interface) {
Sreeram Ramachandran72604072014-05-21 13:19:43 -0700228 if (!isValidNetwork(netId) || !interface) {
Paul Jensenae37e8a2014-04-28 10:35:51 -0400229 ALOGE("invalid netId %u or interface null", netId);
Lorenzo Colittice8f5832014-05-29 12:20:55 +0900230 errno = EINVAL;
Paul Jensenae37e8a2014-04-28 10:35:51 -0400231 return false;
232 }
233
Sreeram Ramachandran72604072014-05-21 13:19:43 -0700234 bool status = false;
235 InterfaceRange range = mNetIdToInterfaces.equal_range(netId);
Paul Jensenae37e8a2014-04-28 10:35:51 -0400236 for (InterfaceIterator iter = range.first; iter != range.second; ++iter) {
237 if (iter->second == interface) {
238 mNetIdToInterfaces.erase(iter);
Sreeram Ramachandran72604072014-05-21 13:19:43 -0700239 status = true;
Paul Jensenae37e8a2014-04-28 10:35:51 -0400240 break;
241 }
242 }
Sreeram Ramachandran72604072014-05-21 13:19:43 -0700243 if (!status) {
244 ALOGE("interface %s not assigned to netId %u", interface, netId);
Lorenzo Colittice8f5832014-05-29 12:20:55 +0900245 errno = ENOENT;
Paul Jensenae37e8a2014-04-28 10:35:51 -0400246 }
247
248 Permission permission = mPermissionsController->getPermissionForNetwork(netId);
249 if (!mRouteController->removeInterfaceFromNetwork(netId, interface, permission)) {
Sreeram Ramachandran72604072014-05-21 13:19:43 -0700250 ALOGE("failed to remove interface %s from netId %u", interface, netId);
Paul Jensenae37e8a2014-04-28 10:35:51 -0400251 status = false;
252 }
253
254 if (netId == getDefaultNetwork() &&
Sreeram Ramachandran72604072014-05-21 13:19:43 -0700255 !mRouteController->removeFromDefaultNetwork(interface, permission)) {
256 ALOGE("failed to remove interface %s from default netId %u", interface, netId);
Paul Jensenae37e8a2014-04-28 10:35:51 -0400257 status = false;
258 }
259
Paul Jensenae37e8a2014-04-28 10:35:51 -0400260 return status;
261}
262
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -0700263bool NetworkController::destroyNetwork(unsigned netId) {
Sreeram Ramachandran72604072014-05-21 13:19:43 -0700264 if (!isValidNetwork(netId)) {
Sreeram Ramachandran379bd332014-04-10 19:58:06 -0700265 ALOGE("invalid netId %u", netId);
Lorenzo Colittice8f5832014-05-29 12:20:55 +0900266 errno = EINVAL;
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -0700267 return false;
268 }
269
Sreeram Ramachandran379bd332014-04-10 19:58:06 -0700270 // TODO: ioctl(SIOCKILLADDR, ...) to kill all sockets on the old network.
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -0700271
272 bool status = true;
273
Sreeram Ramachandran72604072014-05-21 13:19:43 -0700274 InterfaceRange range = mNetIdToInterfaces.equal_range(netId);
275 for (InterfaceIteratorConst iter = range.first; iter != range.second; ) {
276 InterfaceIteratorConst toErase = iter;
Paul Jensenae37e8a2014-04-28 10:35:51 -0400277 ++iter;
278 if (!removeInterfaceFromNetwork(netId, toErase->second.c_str())) {
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -0700279 status = false;
280 }
281 }
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -0700282
Sreeram Ramachandran9c0d3132014-04-10 20:35:04 -0700283 if (netId == getDefaultNetwork()) {
Sreeram Ramachandran9c0d3132014-04-10 20:35:04 -0700284 setDefaultNetwork(NETID_UNSET);
285 }
286
Sreeram Ramachandran72604072014-05-21 13:19:43 -0700287 {
288 android::RWLock::AutoWLock lock(mRWLock);
289 mValidNetworks.erase(netId);
290 }
291
Sreeram Ramachandrana79f6182014-04-24 15:55:26 -0700292 mPermissionsController->setPermissionForNetwork(PERMISSION_NONE, netId);
Sreeram Ramachandrana79f6182014-04-24 15:55:26 -0700293
Sreeram Ramachandran3ced0692014-04-18 09:49:13 -0700294 _resolv_delete_cache_for_net(netId);
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -0700295 return status;
296}
297
Sreeram Ramachandran379bd332014-04-10 19:58:06 -0700298bool NetworkController::setPermissionForUser(Permission permission,
299 const std::vector<unsigned>& uid) {
300 for (size_t i = 0; i < uid.size(); ++i) {
301 mPermissionsController->setPermissionForUser(permission, uid[i]);
302 }
303 return true;
304}
305
306bool NetworkController::setPermissionForNetwork(Permission newPermission,
307 const std::vector<unsigned>& netId) {
308 bool status = true;
309
310 for (size_t i = 0; i < netId.size(); ++i) {
Sreeram Ramachandran72604072014-05-21 13:19:43 -0700311 if (!isValidNetwork(netId[i])) {
Sreeram Ramachandran379bd332014-04-10 19:58:06 -0700312 ALOGE("invalid netId %u", netId[i]);
Lorenzo Colittice8f5832014-05-29 12:20:55 +0900313 errno = EINVAL;
Sreeram Ramachandran379bd332014-04-10 19:58:06 -0700314 status = false;
315 continue;
316 }
317
Sreeram Ramachandran379bd332014-04-10 19:58:06 -0700318 Permission oldPermission = mPermissionsController->getPermissionForNetwork(netId[i]);
319 if (oldPermission == newPermission) {
320 continue;
321 }
322
323 // TODO: ioctl(SIOCKILLADDR, ...) to kill sockets on the network that don't have
324 // newPermission.
325
Sreeram Ramachandran72604072014-05-21 13:19:43 -0700326 InterfaceRange range = mNetIdToInterfaces.equal_range(netId[i]);
327 for (InterfaceIteratorConst iter = range.first; iter != range.second; ++iter) {
Sreeram Ramachandran379bd332014-04-10 19:58:06 -0700328 if (!mRouteController->modifyNetworkPermission(netId[i], iter->second.c_str(),
329 oldPermission, newPermission)) {
Sreeram Ramachandran72604072014-05-21 13:19:43 -0700330 ALOGE("failed to change permission on interface %s of netId %u from %x to %x",
331 iter->second.c_str(), netId[i], oldPermission, newPermission);
Sreeram Ramachandran379bd332014-04-10 19:58:06 -0700332 status = false;
333 }
334 }
335
336 mPermissionsController->setPermissionForNetwork(newPermission, netId[i]);
337 }
338
339 return status;
340}
341
Sreeram Ramachandran7619e1b2014-04-15 14:23:08 -0700342bool NetworkController::addRoute(unsigned netId, const char* interface, const char* destination,
Sreeram Ramachandran38b7af12014-05-22 14:21:49 -0700343 const char* nexthop, bool legacy, unsigned uid) {
344 return modifyRoute(netId, interface, destination, nexthop, true, legacy, uid);
Sreeram Ramachandran7619e1b2014-04-15 14:23:08 -0700345}
346
347bool NetworkController::removeRoute(unsigned netId, const char* interface, const char* destination,
Sreeram Ramachandran38b7af12014-05-22 14:21:49 -0700348 const char* nexthop, bool legacy, unsigned uid) {
349 return modifyRoute(netId, interface, destination, nexthop, false, legacy, uid);
Sreeram Ramachandran7619e1b2014-04-15 14:23:08 -0700350}
351
Sreeram Ramachandran72604072014-05-21 13:19:43 -0700352bool NetworkController::isValidNetwork(unsigned netId) const {
353 if (netId == NETID_UNSET) {
354 return false;
Sreeram Ramachandran7619e1b2014-04-15 14:23:08 -0700355 }
Sreeram Ramachandran7619e1b2014-04-15 14:23:08 -0700356
Sreeram Ramachandran72604072014-05-21 13:19:43 -0700357 android::RWLock::AutoRLock lock(mRWLock);
358 return mValidNetworks.find(netId) != mValidNetworks.end();
Sreeram Ramachandran7619e1b2014-04-15 14:23:08 -0700359}
360
361bool NetworkController::modifyRoute(unsigned netId, const char* interface, const char* destination,
Sreeram Ramachandran38b7af12014-05-22 14:21:49 -0700362 const char* nexthop, bool add, bool legacy, unsigned uid) {
Sreeram Ramachandran72604072014-05-21 13:19:43 -0700363 if (!isValidNetwork(netId)) {
Sreeram Ramachandran7619e1b2014-04-15 14:23:08 -0700364 ALOGE("invalid netId %u", netId);
Lorenzo Colittice8f5832014-05-29 12:20:55 +0900365 errno = EINVAL;
Sreeram Ramachandran7619e1b2014-04-15 14:23:08 -0700366 return false;
367 }
368
Sreeram Ramachandran72604072014-05-21 13:19:43 -0700369 if (getNetworkId(interface) != netId) {
Sreeram Ramachandran7619e1b2014-04-15 14:23:08 -0700370 ALOGE("netId %u has no such interface %s", netId, interface);
Lorenzo Colittice8f5832014-05-29 12:20:55 +0900371 errno = ENOENT;
Sreeram Ramachandran7619e1b2014-04-15 14:23:08 -0700372 return false;
373 }
374
Sreeram Ramachandran38b7af12014-05-22 14:21:49 -0700375 RouteController::TableType tableType;
376 if (legacy) {
377 if (mPermissionsController->getPermissionForUser(uid) & PERMISSION_CONNECTIVITY_INTERNAL) {
378 tableType = RouteController::PRIVILEGED_LEGACY;
379 } else {
380 tableType = RouteController::LEGACY;
381 }
382 } else {
383 tableType = RouteController::INTERFACE;
384 }
385
386 return add ? mRouteController->addRoute(interface, destination, nexthop, tableType, uid) :
387 mRouteController->removeRoute(interface, destination, nexthop, tableType, uid);
Sreeram Ramachandran7619e1b2014-04-15 14:23:08 -0700388}
389
Sreeram Ramachandran72604072014-05-21 13:19:43 -0700390NetworkController::UidEntry::UidEntry(int start, int end, unsigned netId, bool forward_dns)
391 : uid_start(start), uid_end(end), netId(netId), forward_dns(forward_dns) {
Szymon Jakubczaka0efaec2014-02-14 17:09:43 -0500392}