master
cpp 548 lines 24.7 KB
Raw
1 // Copyright (C) Microsoft Corporation. All rights reserved.
2
3 #include <iostream>
4 #include <filesystem>
5 #include <lxwil.h>
6 #include "lxinitshared.h"
7 #include "common.h"
8 #include "NetworkManager.h"
9 #include "util.h"
10 #include "address.h"
11 #include "conncheckshared.h"
12 #include "RuntimeErrorWithSourceLocation.h"
13 #include "stringshared.h"
14
15 // Custom table used for storing routes for loopback IPs.
16 constexpr int c_loopbackRoutingTableId = 127;
17 // Custom table used for storing routes for local IPs. A separate table is used for local IPs so that
18 // when the IP addresses are changing, all routes from the table can be deleted before adding routes for the new set of IPs.
19 // The routes for the loopback IPs will always be the same, thus keeping them in a separate table
20 constexpr int c_localRoutingTableId = 128;
21
22 // See comments in AddMirroredLoopbackRoutingRules for explanation about those priorities.
23 constexpr int c_WindowsToLinuxRulePriority = 0;
24 constexpr int c_LinuxToWindowsRulePriority = 1;
25 constexpr int c_LocalRulePriority = 2;
26
27 // Creates routing tables per interface, identified by the interface index plus an offset.
28 constexpr int c_routeTableOffsetFromIndex = 1000;
29
30 // All loopback/local packets will be sent out of the guest via those gateways. There
31 // will be static ARP entries matching those gateways to the MAC address below, such that
32 // every packet will have that as destination MAC.
33 //
34 // Note: Eventually a mechanism will be needed to replace the gateway addresses in case they
35 // conflict with other addresses in the network.
36 const Address c_ipv4LoopbackGateway = {AF_INET, Ipv4MaxPrefixLen, LX_INIT_IPV4_LOOPBACK_GATEWAY_ADDRESS};
37 const Address c_ipv6LoopbackGateway = {AF_INET6, Ipv6MaxPrefixLen, LX_INIT_IPV6_LOOPBACK_GATEWAY_ADDRESS};
38
39 // v4 and v6 loopback address range used in Mirrored mode: 127.0.0.1/32 and ::1/128.
40 //
41 // Note: Although the v4 loopback address range is 127.0.0.0/8, only traffic to 127.0.0.1 can be used to communicate host<->guest
42 // in Mirrored mode. Traffic to other v4 loopback addresses will stay in the guest. This can be changed if other loopback
43 // addresses are needed by host<->guest loopback scenarios.
44 const Address c_loopbackV4AddressRange = {AF_INET, Ipv4MaxPrefixLen, "127.0.0.1"};
45 const Address c_loopbackV6AddressRange = {AF_INET6, Ipv6MaxPrefixLen, "::1"};
46
47 // 00:11:22:33:44:55 represents the MAC address that all loopback/local packets will have as destination
48 // MAC when they are sent out of the guest. This will help Windows to identify which
49 // packets are loopback/local.
50 const MacAddress c_gatewayMacAddress = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55};
51
52 constexpr const char* c_acceptLocalSetting = "accept_local";
53 constexpr const char* c_routeLocalnetSetting = "route_localnet";
54 constexpr char c_disableSetting[] = "0\n";
55 constexpr char c_enableSetting[] = "1\n";
56
57 NetworkManager::NetworkManager(RoutingTable& routingTable) :
58 routingTable(routingTable), loopbackRoutingTable(c_loopbackRoutingTableId), localRoutingTable(c_localRoutingTableId)
59 {
60 }
61
62 std::optional<int> NetworkManager::FindRoutingTableIdForInterface(const Interface& interface) const
63 {
64 return c_routeTableOffsetFromIndex + interface.Index();
65 }
66
67 void NetworkManager::ChangePrimaryRoutingTable(int newTableId)
68 {
69 routingTable.ChangeTableId(newTableId);
70 }
71
72 std::vector<Route> NetworkManager::ListRoutes(int family) const
73 {
74 return routingTable.ListRoutes(family);
75 }
76
77 Interface NetworkManager::CreateVirtualWifiAdapter(Interface& baseAdapter, const std::string& wifiName)
78 {
79 GNS_LOG_INFO("Creating virtual wifi adapter with name {}", wifiName.c_str());
80 baseAdapter.CreateVirtualWifiAdapter(wifiName);
81 auto virtualWifi = Interface::Open(wifiName);
82
83 GNS_LOG_INFO("Enabling Ipv4 loopback routing on virtual wifi adapter with name {}", wifiName.c_str());
84 EnableLoopbackRouting(virtualWifi);
85 return virtualWifi;
86 }
87
88 Interface NetworkManager::CreateProxyWifiAdapter(Interface& baseAdapter, const std::string& wifiName)
89 {
90 baseAdapter.CreateProxyWifiAdapter(wifiName);
91 auto proxyWifi = Interface::Open(wifiName);
92
93 GNS_LOG_INFO("Enabling Ipv4 loopback routing on proxy wifi adapter with name {}", wifiName.c_str());
94 EnableLoopbackRouting(proxyWifi);
95 return proxyWifi;
96 }
97
98 // SUPPORTS IPV4 ONLY, and only supports 1 IP address per adapter.
99 // Not used for mirroring.
100 void NetworkManager::SetAdapterConfiguration(Interface& interface, const wsl::shared::hns::HNSEndpoint& configuration)
101 {
102 InterfaceConfiguration config;
103 config.Addresses.emplace_back(Address{AF_INET, configuration.PrefixLength, wsl::shared::string::WideToMultiByte(configuration.IPAddress)});
104
105 config.LocalAddresses = config.Addresses;
106 config.BroadcastAddress = utils::ComputeBroadcastAddress(config.Addresses[0]);
107
108 std::stringstream addressInfo;
109 addressInfo << config.Addresses[0];
110 GNS_LOG_INFO(
111 "Setting the IPv4 address on endpointID ({}) to {} on interfaceName {}",
112 wsl::shared::string::GuidToString<char>(configuration.ID).c_str(),
113 addressInfo.str().c_str(),
114 interface.Name().c_str());
115 interface.SetIpv4Configuration(config);
116 }
117
118 void NetworkManager::SetInterfaceState(Interface& adapter, InterfaceState state)
119 {
120 GNS_LOG_INFO("Setting interface state to {} on interfaceName {}", state == InterfaceState::Up ? "Up" : "Down", adapter.Name().c_str());
121 if (state == InterfaceState::Up)
122 {
123 adapter.SetUp();
124 }
125 else
126 {
127 adapter.SetDown();
128 }
129 }
130
131 void NetworkManager::SetAdapterName(Interface& adapter, const std::string& name)
132 {
133 adapter.SetName(name);
134 }
135
136 void NetworkManager::SetAdapterNamespace(Interface& adapter, int namespaceFd)
137 {
138 adapter.SetNamespace(namespaceFd);
139 }
140
141 void NetworkManager::SetWiphyNamespace(Interface& adapter, int namespaceFd)
142 {
143 adapter.SetWiphyNamespace(namespaceFd);
144 }
145
146 void NetworkManager::ModifyRoute(const Route& route, Operation operation)
147 {
148 routingTable.ModifyRoute(route, operation);
149 }
150
151 void NetworkManager::ResetRoutingTable(int addressFamily, const Interface& interface)
152 {
153 auto routes = routingTable.ListRoutes(addressFamily);
154 auto pred = [&](const Route& route) {
155 // Routes without gateways are link level routes (scope link)
156 return !route.via.has_value() || route.dev != interface.Index();
157 };
158
159 std::erase_if(routes, pred);
160
161 for (const auto& e : routes)
162 {
163 const auto routeString = utils::Stringify(e);
164 try
165 {
166 GNS_LOG_INFO("Removing route {} from interfaceName {}", routeString, interface.Name());
167 routingTable.ModifyRoute(e, Operation::Remove);
168 }
169 catch (const std::exception& ex)
170 {
171 throw RuntimeErrorWithSourceLocation(std::format("Failed to remove route '{}', {}", routeString, ex.what()));
172 }
173 }
174 }
175
176 void NetworkManager::ModifyAddress(Interface& adapter, const Address& address, Operation operation)
177 {
178 std::vector<Route> routes;
179
180 // If the ip address is changing, the routing table needs to be saved & restored
181 // because netlink doesn't allow ip addresses to be changed, but only deleted and added,
182 // which causes the routing rules attached to the interface to be dropped
183 if (operation == Operation::Update)
184 {
185 routes = routingTable.ListRoutes(address.Family());
186 }
187
188 adapter.ModifyIpAddress(address, operation);
189
190 // Restore the routes for this interface.
191 // Note: If a route fails to be restored, it's probably because the new address's subnet is different,
192 // and so the route would have been unusable with the new address anyway
193 for (const auto& savedRoute : routes)
194 {
195 if (savedRoute.dev == adapter.Index() && savedRoute.via.has_value())
196 {
197 const auto savedRouteString = utils::Stringify(savedRoute);
198
199 try
200 {
201 GNS_LOG_INFO(
202 "Restoring route {} after address change, on interfaceName {}", savedRouteString.c_str(), adapter.Name().c_str());
203 routingTable.ModifyRoute(savedRoute, Operation::Create);
204 }
205 catch (const std::exception& ex)
206 {
207 GNS_LOG_ERROR(
208 "Failed to restore route {} after address change, on interfaceName {}, caught exception "
209 "{}",
210 savedRouteString.c_str(),
211 adapter.Name().c_str(),
212 ex.what());
213 }
214 }
215 }
216 }
217
218 void NetworkManager::SetAdapterMacAddress(Interface& interface, const MacAddress& address)
219 {
220 SetInterfaceState(interface, InterfaceState::Down);
221 interface.SetMacAddress(address);
222 SetInterfaceState(interface, InterfaceState::Up);
223 }
224
225 void NetworkManager::DisassociateAdapterFromBond(const std::string& bondInterfaceName, Interface& interface)
226 {
227 auto bondInterface = Interface::Open(bondInterfaceName);
228 GNS_LOG_INFO(
229 "Trying to disassociate from bond - bondDeviceName {}, interfaceName {}", bondInterfaceName.c_str(), interface.Name().c_str());
230 bondInterface.RemoveFromBond(interface);
231 GNS_LOG_INFO(
232 "Successfully disassociated from bond - bondDeviceName {}, interfaceName {}", bondInterfaceName.c_str(), interface.Name().c_str());
233 }
234
235 void NetworkManager::AssociateAdapterWithBond(const std::string& bondInterfaceName, Interface& interface)
236 {
237 auto bondInterface = Interface::Open(bondInterfaceName);
238 // must set the interface down before associating it to bond
239 SetInterfaceState(interface, InterfaceState::Down);
240 bondInterface.AddToBond(interface);
241 GNS_LOG_INFO(
242 "Successfully associated to bond - bondDeviceName {}, interfaceName {}", bondInterfaceName.c_str(), interface.Name().c_str());
243 SetInterfaceState(interface, InterfaceState::Up);
244 }
245
246 void NetworkManager::ActivateAdapterWithBond(const std::string& bondInterfaceName, const Interface& interface)
247 {
248 auto bondInterface = Interface::Open(bondInterfaceName);
249 bondInterface.SetActiveChild(interface);
250 }
251
252 Interface NetworkManager::CreateBondAdapter(const std::string& name)
253 {
254 Interface::CreateBondAdapter(name);
255 auto bondInterface = Interface::Open(name);
256
257 // Enable routing of IPv4 loopback on the bond interface.
258 GNS_LOG_INFO("Enabling IPv4 loopback routing on bond adapter with name {}", name.c_str());
259 EnableLoopbackRouting(bondInterface);
260 return bondInterface;
261 }
262
263 /*
264 Enable the accept_local and route_localnet settings required to send/receive loopback and local
265 packets on an interface.
266
267 Note: The function supports only IPv4 settings at the moment. There are no equivalent IPv6 settings
268 for accept_local and route_localnet.
269 */
270 void NetworkManager::EnableLoopbackRouting(Interface& interface)
271 {
272 GNS_LOG_INFO("Enabling sysctl accept_local setting on adapter with name {}", interface.Name().c_str());
273 interface.EnableNetworkSetting(c_acceptLocalSetting, AF_INET);
274
275 GNS_LOG_INFO("Enabling sysctl route_localnet setting on adapter with name {}", interface.Name().c_str());
276 interface.EnableNetworkSetting(c_routeLocalnetSetting, AF_INET);
277 }
278
279 /*
280 Note: GELNIC stands for Guest-Exclusive Loopback NIC. It represents the mirrored interface of the host
281 loopback interface. Every packet that arrives in the guest having a loopback destination address will
282 arrive on the GELNIC.
283 */
284 void NetworkManager::InitializeLoopbackConfiguration(Interface& gelnic, wsl::shared::hns::CreateDeviceFlags flags)
285 {
286 if (WI_IsFlagSet(flags, wsl::shared::hns::CreateDeviceFlags::DisableDAD))
287 {
288 gelnic.DisableNetworkSetting("accept_dad", AF_INET6);
289 gelnic.DisableNetworkSetting("dad_transmits", AF_INET6);
290
291 // Toggle ipv6 to reset our temporary address.
292 gelnic.EnableNetworkSetting("disable_ipv6", AF_INET6);
293 gelnic.DisableNetworkSetting("disable_ipv6", AF_INET6);
294 }
295
296 // Enable routing of IPv4 loopback on the GELNIC.
297 GNS_LOG_INFO("Enabling IPv4 loopback routing on GELNIC adapter {}", gelnic.Name().c_str());
298 EnableLoopbackRouting(gelnic);
299
300 // Disable IPv4 reverse path filtering on the GELNIC.
301 // The effective rp_filter setting for interface "name" is the more restrictive between "name" and "all", so both must be set.
302 GNS_LOG_INFO("Disabling sysctl rp_filter setting on loopback adapter");
303 gelnic.DisableNetworkSetting("rp_filter", AF_INET);
304 ModifyNetSetting(AF_INET, "rp_filter", "all", c_disableSetting, strlen(c_disableSetting));
305
306 InitializeLoopbackConfigurationImpl(gelnic, AF_INET);
307 // InitializeLoopbackConfigurationImpl(gelnic, AF_INET6);
308 }
309
310 /*
311 In mirrored networking mode, Linux ip rules (policy based routing) are configured such that
312 loopback traffic or local traffic (local = traffic with destination an IP assigned to Linux/Windows)
313 can flow between Windows and Linux. Note: This applies only to TCP and UDP traffic.
314
315 Below are outputs of "ip rule show" in both NAT and mirrored mode, along with explanations about how
316 the rules work.
317
318 The leftmost part of each rule represents the priority of the rule (priority 0 is the highest priority)
319
320 The "lookup" keyword is followed by the name or id of a routing table
321 The local table is used by Linux to know when to deliver a packet locally (to a Linux process). This table is used
322 for both traffic with destination 127.0.0.1 and traffic with destination an IP assigned to Linux.
323 Table 127 contains routes used to send traffic with destination 127.0.0.1 out of Linux, to be processed by Windows.
324 Traffic will be sent out of Linux via the "GELNIC" interface (which will be called loopback0).
325 Table 128 contains routes used to send traffic with local destination out of Linux, to be processed by Windows.
326 Traffic will be sent out of Linux via the mirrored interface that has the destination IP assigned to it.
327 Tables main and default contain routes that are not related to loopback traffic
328
329 Priority 0 rules will deliver to Linux loopback/local traffic coming from Windows (this can be traffic
330 with origin in Windows or traffic with origin in Linux that was sent to Windows and Windows sent it back to Linux).
331 "iif" represents input interface (the interface on which Linux received the traffic).
332 "loopback0" is the interface used to send 127.0.0.1 traffic between Linux and Windows. "eth0" refers to an
333 interface that was mirrored in Linux. Each time an interface is mirrored, a rule like this needs to be added
334 for that interface. And each time the interface is deleted, the rule needs to be deleted.
335
336 Priority 1 rules are used to send traffic that originates in Linux out of Linux to Windows, so that Windows can decide
337 if that traffic must be sent to Windows or back to Linux. Those rules apply to traffic originating in the Linux
338 root network namespace, but also to traffic that root network namespace receives from other network namespaces, such
339 as Docker containers.
340
341 The priority 2 rule is needed for loopback/local traffic that is not TCP or UDP, such as ICMP. This traffic will
342 stay inside Linux, it cannot be sent between Linux and Windows. The rule is also needed for receiving inbound traffic
343 from an external machine.
344
345 NAT mode ip rule show:
346 0: from all lookup local
347 32766: from all lookup main
348 32767: from all lookup default
349
350 mirrored mode ip rule show:
351 0: from all iif loopback0 ipproto tcp lookup local
352 0: from all iif loopback0 ipproto udp lookup local
353 0: from all iif eth0 ipproto tcp lookup local
354 0: from all iif eth0 ipproto udp lookup local
355 1: from all ipproto tcp lookup 127
356 1: from all ipproto udp lookup 127
357 1: from all ipproto tcp lookup 128
358 1: from all ipproto udp lookup 128
359 2: from all lookup local
360 32766: from all lookup main
361 32767: from all lookup default
362 */
363 void NetworkManager::AddMirroredLoopbackRoutingRules(Interface& gelnic, int addressFamily)
364 {
365 GNS_LOG_INFO("gelnic name {}, addressFamily {}", gelnic.Name().c_str(), addressFamily);
366
367 // Delete rule with priority 0 for local table (from all prio 0 lookup local).
368 Rule rule = Rule(addressFamily, RT_TABLE_LOCAL, 0);
369 ruleManager.ModifyRoutingTablePriority(rule, Operation::Remove);
370
371 // Adding priority 0 rules for the GELNIC interface
372 // Similar priority 0 rules will also be added or deleted when an interface is mirrored in Linux, or deleted
373 UpdateMirroredLoopbackRulesForInterface(gelnic.Name(), Operation::Create);
374
375 auto AddPriority1Rule = [&](const Protocol protocol, const int routingTableId) {
376 Rule rule = Rule(addressFamily, routingTableId, c_LinuxToWindowsRulePriority, protocol);
377 ruleManager.ModifyRoutingTablePriorityWithProtocol(rule, Operation::Create);
378 };
379
380 // Adding priority 1 rules
381 AddPriority1Rule(Protocol::Tcp, c_loopbackRoutingTableId);
382 AddPriority1Rule(Protocol::Udp, c_loopbackRoutingTableId);
383 AddPriority1Rule(Protocol::Tcp, c_localRoutingTableId);
384 AddPriority1Rule(Protocol::Udp, c_localRoutingTableId);
385
386 // Add a rule referencing the local table, with priority 2
387 rule = Rule(addressFamily, RT_TABLE_LOCAL, c_LocalRulePriority);
388 ruleManager.ModifyRoutingTablePriority(rule, Operation::Create);
389 }
390
391 void NetworkManager::UpdateMirroredLoopbackRulesForInterface(const std::string& interfaceName, Operation operation)
392 {
393 assert(operation == Operation::Create || operation == Operation::Remove);
394
395 // Add or remove priority 0 rules needed by mirrored loopback traffic. See the comments in AddMirroredLoopbackRoutingRules for
396 // more details. Currently only IPv4 guest<->host loopback is supported in mirrored mode - adding only IPv4 rules.
397 GNS_LOG_INFO(
398 "{} priority 0 rule for interfaceName {} for TCP", operation == Operation::Create ? "Add" : "Remove", interfaceName.c_str());
399 Rule rule = Rule(AF_INET, RT_TABLE_LOCAL, c_WindowsToLinuxRulePriority, Protocol::Tcp);
400 rule.iif = interfaceName;
401 ruleManager.ModifyLoopbackRule(rule, operation);
402
403 GNS_LOG_INFO(
404 "{} priority 0 rule for interfaceName {} for UDP", operation == Operation::Create ? "Add" : "Remove", interfaceName.c_str());
405 rule = Rule(AF_INET, RT_TABLE_LOCAL, c_WindowsToLinuxRulePriority, Protocol::Udp);
406 rule.iif = interfaceName;
407 ruleManager.ModifyLoopbackRule(rule, operation);
408 }
409
410 /*
411 Adds the policy rules required for loopback. Also adds routes for the loopback address range
412 127.0.0.1/32 or ::1/128.
413 */
414 void NetworkManager::InitializeLoopbackConfigurationImpl(Interface& gelnic, int addressFamily)
415 {
416 // Set to GELNIC to status up before adding the configurations
417 gelnic.SetUp();
418
419 AddMirroredLoopbackRoutingRules(gelnic, addressFamily);
420
421 auto gateway = addressFamily == AF_INET ? c_ipv4LoopbackGateway : c_ipv6LoopbackGateway;
422 auto addressRange = addressFamily == AF_INET ? c_loopbackV4AddressRange : c_loopbackV6AddressRange;
423
424 // Add a static ARP entry for the loopback gateway. The purpose of the static entries is
425 // to guarantee that each loopback packet that leaves the guest has the same destination MAC.
426 GNS_LOG_INFO("Adding static ARP entry for the loopback gateway {}", gateway.Addr().c_str());
427 Neighbor neighbor = Neighbor(gateway, c_gatewayMacAddress, gelnic.Index());
428 neighborManager.ModifyNeighborEntry(neighbor, Operation::Create);
429
430 // Add routes for 127.0.0.1/32 or ::1/128
431 Route route = Route(addressFamily, gateway, gelnic.Index(), false, addressRange, 0);
432 route.isLoopbackRoute = true;
433
434 const auto routeString = utils::Stringify(route);
435 GNS_LOG_INFO("Add route {} on GELNIC adapter {}", routeString.c_str(), gelnic.Name().c_str());
436 loopbackRoutingTable.ModifyRoute(route, Operation::Create);
437 }
438
439 /*
440 Add or remove loopback routes for the set of IP addresses that were added/deleted on an interface. All routes are via the
441 same gateway address. The function can be used for both IPv4 and IPv6 addresses.
442 */
443 void NetworkManager::UpdateLoopbackRoute(Interface& interface, const Address& address, Operation operation)
444 {
445 assert(operation == Operation::Create || operation == Operation::Remove);
446
447 // For the moment don't process IPv6 addresses, since inbound IPv6 loopback is not supported yet (dropped by
448 // default by the Linux stack). Once that is addressed, this check will be removed.
449 if (address.Family() == AF_INET6)
450 {
451 GNS_LOG_INFO("Ignoring IPv6 address {}", utils::Stringify(address).c_str());
452 return;
453 }
454
455 auto gateway = address.Family() == AF_INET ? c_ipv4LoopbackGateway : c_ipv6LoopbackGateway;
456
457 if (operation == Operation::Create)
458 {
459 // When adding routes, always add the static neighbor entry for the loopback gateway. The purpose of the static entries is
460 // to guarantee that each loopback packet that leaves the guest has the same destination MAC.
461 //
462 // Note: The entries are added each time we add routes in order to avoid keeping track of whether they are added or not
463 // (as the entries will be lost when an interface changes state to down).
464 GNS_LOG_INFO("Adding static neighbor entry for the loopback gateway {}", gateway.Addr().c_str());
465 Neighbor neighbor = Neighbor(gateway, c_gatewayMacAddress, interface.Index());
466 neighborManager.ModifyNeighborEntry(neighbor, Operation::Create);
467 }
468
469 Route route = Route(address.Family(), gateway, interface.Index(), false, address, 0);
470 route.isLoopbackRoute = true;
471
472 const auto routeString = utils::Stringify(route);
473 GNS_LOG_INFO(
474 "{} loopback route {} on interfaceName {}",
475 operation == Operation::Create ? "Add" : "Remove",
476 routeString.c_str(),
477 interface.Name().c_str());
478 localRoutingTable.ModifyRoute(route, operation);
479 }
480
481 void NetworkManager::ResetLoopbackRoutes()
482 {
483 localRoutingTable.RemoveAll(AF_UNSPEC);
484 }
485
486 void NetworkManager::CreateTunAdapter(const std::string& name)
487 {
488 Interface::CreateTunAdapter(name);
489
490 // Enable routing of IPv4 loopback on the tunnel interface.
491 GNS_LOG_INFO("Enabling IPv4 loopback routing on tunnel adapter with name {}", name.c_str());
492 Interface tunInterface = {-1, name};
493 EnableLoopbackRouting(tunInterface);
494 }
495
496 void NetworkManager::ModifyNetSetting(int addressFamily, const char* settingName, const char* scope, const char* settingValue, size_t settingValueLen)
497 {
498 const std::filesystem::path settingFilePath =
499 std::format("/proc/sys/net/{}/conf/{}/{}", ((addressFamily == AF_INET) ? "ipv4" : "ipv6"), scope, settingName);
500 wil::unique_fd fd(Syscall(open, settingFilePath.c_str(), (O_WRONLY | O_CLOEXEC)));
501 Syscall(write, fd.get(), settingValue, settingValueLen);
502 }
503
504 void NetworkManager::DisableRouterDiscovery()
505 {
506 ModifyNetSetting(AF_INET6, "accept_ra", "all", c_disableSetting, strlen(c_disableSetting));
507 ModifyNetSetting(AF_INET6, "accept_ra", "default", c_disableSetting, strlen(c_disableSetting));
508 }
509
510 void NetworkManager::DisableDAD()
511 {
512 // DAD is not enabled for IPv4 by default on Linux-based systems, so only disable for IPv6.
513 ModifyNetSetting(AF_INET6, "dad_transmits", "all", c_disableSetting, strlen(c_disableSetting));
514 ModifyNetSetting(AF_INET6, "dad_transmits", "default", c_disableSetting, strlen(c_disableSetting));
515 }
516
517 void NetworkManager::DisableIpv6AddressGeneration()
518 {
519 // Disable autoconfiguration.
520 ModifyNetSetting(AF_INET6, "autoconf", "all", c_disableSetting, strlen(c_disableSetting));
521 ModifyNetSetting(AF_INET6, "autoconf", "default", c_disableSetting, strlen(c_disableSetting));
522
523 // Disable link local address generation.
524 constexpr char c_genModeNone[] = "1\n";
525 ModifyNetSetting(AF_INET6, "addr_gen_mode", "all", c_genModeNone, strlen(c_genModeNone));
526 ModifyNetSetting(AF_INET6, "addr_gen_mode", "default", c_genModeNone, strlen(c_genModeNone));
527
528 // Disable privacy extensions, i.e. temporary address generation.
529 ModifyNetSetting(AF_INET6, "use_tempaddr", "all", c_disableSetting, strlen(c_disableSetting));
530 ModifyNetSetting(AF_INET6, "use_tempaddr", "default", c_disableSetting, strlen(c_disableSetting));
531 }
532
533 void NetworkManager::EnableIpv4ArpFilter()
534 {
535 // sets /proc/sys/net/ipv4/conf/all/arp_filter to a value of 1
536 // this is to stop Linux from attempting to ARP a configured IP address across all connected interfaces
537 // setting this to 1 instructs Linux to only ARP for that address over the interface that the address was assigned
538 // This setting is required to avoid breaking mirroring where multiple interfaces are mirrored on the same network (they have
539 // addresses on the same prefix) which can cause the Host to interpret an ARP from an interface without the address to be a
540 // duplicate which causes the host fail DAD, and DHCP immediately requests a new address (this will just continue in a loop)
541 ModifyNetSetting(AF_INET, "arp_filter", "all", c_enableSetting, strlen(c_enableSetting));
542 ModifyNetSetting(AF_INET, "arp_filter", "default", c_enableSetting, strlen(c_enableSetting));
543 }
544
545 wsl::shared::conncheck::ConnCheckResult NetworkManager::SendConnectRequest(const char* remoteAddress)
546 {
547 return wsl::shared::conncheck::CheckConnection(remoteAddress, nullptr, "80");
548 }