| 1 | /*++ |
| 2 | |
| 3 | Copyright (c) Microsoft. All rights reserved. |
| 4 | |
| 5 | Module Name: |
| 6 | |
| 7 | LxssIptables.h |
| 8 | |
| 9 | Abstract: |
| 10 | |
| 11 | This file contains iptables-related function declarations. |
| 12 | |
| 13 | --*/ |
| 14 | |
| 15 | #pragma once |
| 16 | |
| 17 | #include <memory> |
| 18 | #include <mutex> |
| 19 | #include <mi.h> |
| 20 | #include <netfw.h> |
| 21 | #include "LxssUserCallback.h" |
| 22 | |
| 23 | /// <summary> |
| 24 | /// Type to hold a MI_Session instance. Functions creating an instance of this |
| 25 | /// type will construct it in such a way as to also hold an implicit reference |
| 26 | /// to the global application instance. |
| 27 | /// </summary> |
| 28 | using unique_mi_session = std::unique_ptr<MI_Session, std::function<void(MI_Session*)>>; |
| 29 | |
| 30 | /// <summary> |
| 31 | /// Type to hold a MI_Instance instance. Functions creating an instance of this |
| 32 | /// type will construct it in such a way as to also hold an implicit reference |
| 33 | /// to the global application instance. |
| 34 | /// </summary> |
| 35 | using unique_mi_instance = std::unique_ptr<MI_Instance, std::function<void(MI_Instance*)>>; |
| 36 | |
| 37 | /// <summary> |
| 38 | /// Helper class for using Windows Management Interface. |
| 39 | /// </summary> |
| 40 | class LxssManagementInterface |
| 41 | { |
| 42 | public: |
| 43 | /// <summary> |
| 44 | /// Clone an instance. |
| 45 | /// </summary> |
| 46 | static unique_mi_instance CloneInstance(_In_ const MI_Instance* InstanceToClone); |
| 47 | |
| 48 | /// <summary> |
| 49 | /// Closes a MI_Operation instance. |
| 50 | /// </summary> |
| 51 | static void CloseOperation(MI_Operation* Operation); |
| 52 | |
| 53 | /// <summary> |
| 54 | /// Returns the global application instance. |
| 55 | /// </summary> |
| 56 | static std::shared_ptr<MI_Application> GetGlobalApplication(); |
| 57 | |
| 58 | /// <summary> |
| 59 | /// Create a new management interface MI_Instance instance. |
| 60 | /// </summary> |
| 61 | static unique_mi_instance NewInstance(_In_ const std::wstring& ClassName, _In_opt_ const MI_Class* Class); |
| 62 | |
| 63 | /// <summary> |
| 64 | /// Create a new management interface session instance. |
| 65 | /// </summary> |
| 66 | static unique_mi_session NewSession(); |
| 67 | |
| 68 | /// <summary> |
| 69 | /// Local machine root instance. |
| 70 | /// </summary> |
| 71 | static const std::wstring& LocalRoot() |
| 72 | { |
| 73 | return s_localRoot; |
| 74 | } |
| 75 | |
| 76 | private: |
| 77 | /// <summary> |
| 78 | /// Called to destroy the global application instance. Called as a result |
| 79 | /// of the last shared reference being deleted. |
| 80 | /// </summary> |
| 81 | static void CloseGlobalApplication(_Inout_ MI_Application* Application); |
| 82 | |
| 83 | /// <summary> |
| 84 | /// Close a MI_Instance. This is implicitly called via the destruction of |
| 85 | /// an unique_mi_instance instance. |
| 86 | /// </summary> |
| 87 | static void CloseInstance(_In_ std::shared_ptr<MI_Application>, _Inout_ MI_Instance* Instance); |
| 88 | |
| 89 | /// <summary> |
| 90 | /// Close a session. This is implicitly called via the destruction of an |
| 91 | /// unique_mi_session instance. |
| 92 | /// </summary> |
| 93 | static void CloseSession(_In_ std::shared_ptr<MI_Application>, _Inout_ MI_Session* Session); |
| 94 | |
| 95 | /// <summary> |
| 96 | /// Lock for static members. |
| 97 | /// </summary> |
| 98 | static std::mutex s_lock; |
| 99 | |
| 100 | /// <summary> |
| 101 | /// Global MI_Application instance. |
| 102 | /// </summary> |
| 103 | _Guarded_by_(LxssManagementInterface::s_lock) static std::weak_ptr<MI_Application> s_application; |
| 104 | |
| 105 | /// <summary> |
| 106 | /// Local machine root instance. |
| 107 | /// </summary> |
| 108 | static const std::wstring s_localRoot; |
| 109 | }; |
| 110 | |
| 111 | /// <summary> |
| 112 | /// MI_Operation unique instance. |
| 113 | /// </summary> |
| 114 | using unique_mi_operation = |
| 115 | wil::unique_struct<MI_Operation, decltype(LxssManagementInterface::CloseOperation), LxssManagementInterface::CloseOperation>; |
| 116 | |
| 117 | class LxssNetworkingFirewallPort; |
| 118 | class LxssNetworkingNat; |
| 119 | |
| 120 | /// <summary> |
| 121 | /// Emulate iptables functionality. |
| 122 | /// </summary> |
| 123 | class LxssIpTables |
| 124 | { |
| 125 | public: |
| 126 | /// <summary> |
| 127 | /// Constructor. |
| 128 | /// </summary> |
| 129 | LxssIpTables(); |
| 130 | |
| 131 | /// <summary> |
| 132 | /// Enable iptables emulation. |
| 133 | /// </summary> |
| 134 | void EnableIpTablesSupport(_In_ const wil::unique_handle& InstanceHandle); |
| 135 | |
| 136 | /// <summary> |
| 137 | /// Cleanup any persistent data leftover from a non-clean shutdown. |
| 138 | /// </summary> |
| 139 | static void CleanupRemnants(); |
| 140 | |
| 141 | /// <summary> |
| 142 | /// Helper routine to convert an IP address into the string equivalent. |
| 143 | /// </summary> |
| 144 | static std::wstring AddressStringFromAddress(const IP_ADDRESS_PREFIX& Address, bool AddPrefixLength); |
| 145 | |
| 146 | private: |
| 147 | /// <summary> |
| 148 | /// No copy constructor. |
| 149 | /// </summary> |
| 150 | LxssIpTables(const LxssIpTables&) = delete; |
| 151 | |
| 152 | /// <summary> |
| 153 | /// Verify the input prefix address is supported. |
| 154 | /// </summary> |
| 155 | static bool IsAllowedInputPrefix(_In_ CONST IP_ADDRESS_PREFIX& InputPrefix); |
| 156 | |
| 157 | /// <summary> |
| 158 | /// Kernel-mode callback function for iptables operations. |
| 159 | /// </summary> |
| 160 | NTSTATUS |
| 161 | KernelCallback(_In_ PVOID CallbackBuffer, _In_ ULONG_PTR CallbackBufferSize); |
| 162 | |
| 163 | /// <summary> |
| 164 | /// Kernel-mode callback function to configure a port rule via the Windows |
| 165 | /// firewall. |
| 166 | /// </summary> |
| 167 | NTSTATUS |
| 168 | KernelCallbackFirewallPort(_In_ PLXBUS_USER_CALLBACK_IPTABLES_DATA CallbackData); |
| 169 | |
| 170 | /// <summary> |
| 171 | /// Kernel-mode callback function to add a new masquerade entry. |
| 172 | /// </summary> |
| 173 | NTSTATUS |
| 174 | KernelCallbackMasquerade(_In_ PLXBUS_USER_CALLBACK_IPTABLES_DATA CallbackData); |
| 175 | |
| 176 | /// <summary> |
| 177 | /// Kernel-mode callback entrypoint function for iptables operations. |
| 178 | /// </summary> |
| 179 | static NTSTATUS KernelCallbackProxy(_Inout_ LxssIpTables* Self, _In_ PVOID CallbackBuffer, _In_ ULONG_PTR CallbackBufferSize); |
| 180 | |
| 181 | /// <summary> |
| 182 | /// List of port rules. |
| 183 | /// </summary> |
| 184 | std::list<std::unique_ptr<LxssNetworkingFirewallPort>> m_firewallPorts; |
| 185 | |
| 186 | /// <summary> |
| 187 | /// Lock to protect class members. |
| 188 | /// </summary> |
| 189 | std::mutex m_lock; |
| 190 | |
| 191 | /// <summary> |
| 192 | /// List of NATs. |
| 193 | /// </summary> |
| 194 | std::list<std::unique_ptr<LxssNetworkingNat>> m_networkTranslators; |
| 195 | |
| 196 | /// <summary> |
| 197 | /// Callback for the kernel-mode driver to make iptables requests. |
| 198 | /// </summary> |
| 199 | // N.B. This is the last member of the class because it needs to be |
| 200 | // destructed early as the asynchronous callback may rely on other |
| 201 | // members of the class being valid. |
| 202 | std::unique_ptr<LxssUserCallback> m_kernelCallback; |
| 203 | }; |
| 204 | |
| 205 | /// <summary> |
| 206 | /// Class providing access to Windows firewall |
| 207 | /// </summary> |
| 208 | class LxssNetworkingFirewall |
| 209 | { |
| 210 | public: |
| 211 | /// <summary> |
| 212 | /// Default constructor. |
| 213 | /// </summary> |
| 214 | LxssNetworkingFirewall(); |
| 215 | |
| 216 | /// <summary> |
| 217 | /// Create a rule to allow the specified address and port combination. |
| 218 | /// </summary> |
| 219 | std::wstring AddPortRule(const IP_ADDRESS_PREFIX& Address) const; |
| 220 | |
| 221 | /// <summary> |
| 222 | /// Cleanup any persistent data leftover from a non-clean shutdown. |
| 223 | /// </summary> |
| 224 | static void CleanupRemnants(); |
| 225 | |
| 226 | /// <summary> |
| 227 | /// Exclude a network adapter from the firewall's public profile. |
| 228 | /// </summary> |
| 229 | void ExcludeAdapter(const std::wstring& AdapterName); |
| 230 | |
| 231 | /// <summary> |
| 232 | /// Remove a network adapter from the exclusion list. |
| 233 | /// </summary> |
| 234 | void RemoveExcludedAdapter(const std::wstring& AdapterName); |
| 235 | |
| 236 | /// <summary> |
| 237 | /// Remove a port rule created by AddPortRule. |
| 238 | /// </summary> |
| 239 | void RemovePortRule(const std::wstring& RuleName) const; |
| 240 | |
| 241 | private: |
| 242 | /// <summary> |
| 243 | /// No copy constructor. |
| 244 | /// </summary> |
| 245 | LxssNetworkingFirewall(const LxssNetworkingFirewall&) = delete; |
| 246 | |
| 247 | /// <summary> |
| 248 | /// Copies part of a source array to a destination array. |
| 249 | /// </summary> |
| 250 | static void CopyPartialArray(SAFEARRAY* Destination, SAFEARRAY* Source, ULONG DestinationIndexStart, ULONG SourceIndexStart, ULONG ElementsToCopy); |
| 251 | |
| 252 | /// <summary> |
| 253 | /// Creates the unique friendly name of the firewall port rule. |
| 254 | /// </summary> |
| 255 | static std::wstring GeneratePortRuleName(const IP_ADDRESS_PREFIX& Address); |
| 256 | |
| 257 | /// <summary> |
| 258 | /// Returns the existing array of excluded adapters. |
| 259 | /// </summary> |
| 260 | wil::unique_variant GetExcludedAdapters(_Out_opt_ ULONG* AdapterCount) const; |
| 261 | |
| 262 | /// <summary> |
| 263 | /// COM firewall instance. |
| 264 | /// </summary> |
| 265 | wil::com_ptr<INetFwPolicy2> m_firewall; |
| 266 | |
| 267 | /// <summary> |
| 268 | /// Lock to protect class members. |
| 269 | /// </summary> |
| 270 | std::mutex m_lock; |
| 271 | |
| 272 | /// <summary> |
| 273 | /// Firewall rule description. |
| 274 | /// </summary> |
| 275 | static const wil::unique_bstr s_DefaultRuleDescription; |
| 276 | |
| 277 | /// <summary> |
| 278 | /// Prefix to uniquely identify WSL firewall rules. |
| 279 | /// </summary> |
| 280 | static const std::wstring s_FriendlyNamePrefix; |
| 281 | }; |
| 282 | |
| 283 | /// <summary> |
| 284 | /// Class representing a Windows firewall port open rule, removed on |
| 285 | /// destruction. |
| 286 | /// </summary> |
| 287 | class LxssNetworkingFirewallPort |
| 288 | { |
| 289 | public: |
| 290 | /// <summary> |
| 291 | /// Constructor. |
| 292 | /// </summary> |
| 293 | LxssNetworkingFirewallPort(const std::shared_ptr<LxssNetworkingFirewall>& Firewall, const IP_ADDRESS_PREFIX& Address); |
| 294 | |
| 295 | /// <summary> |
| 296 | /// Constructor to take ownership of an existing rule. |
| 297 | /// </summary> |
| 298 | LxssNetworkingFirewallPort(const std::shared_ptr<LxssNetworkingFirewall>& Firewall, const wil::com_ptr<INetFwRule>& Existing); |
| 299 | |
| 300 | /// <summary> |
| 301 | /// Destructor. |
| 302 | /// </summary> |
| 303 | ~LxssNetworkingFirewallPort(); |
| 304 | |
| 305 | /// <summary> |
| 306 | /// Returns the address and port of the firewall rule. |
| 307 | /// </summary> |
| 308 | const IP_ADDRESS_PREFIX& Address() const |
| 309 | { |
| 310 | return m_address; |
| 311 | } |
| 312 | |
| 313 | /// <summary> |
| 314 | /// Returns the underlying firewall instance. |
| 315 | /// </summary> |
| 316 | const std::shared_ptr<LxssNetworkingFirewall> Firewall() const |
| 317 | { |
| 318 | return m_firewall; |
| 319 | } |
| 320 | |
| 321 | private: |
| 322 | /// <summary> |
| 323 | /// No default constructor. |
| 324 | /// </summary> |
| 325 | LxssNetworkingFirewallPort() = delete; |
| 326 | /// <summary> |
| 327 | /// No copy constructor. |
| 328 | /// </summary> |
| 329 | LxssNetworkingFirewallPort(const LxssNetworkingFirewallPort&) = delete; |
| 330 | |
| 331 | /// <summary> |
| 332 | /// Address information for the port rule. |
| 333 | /// </summary> |
| 334 | IP_ADDRESS_PREFIX m_address; |
| 335 | |
| 336 | /// <summary> |
| 337 | /// Pointer to the firewall interface. |
| 338 | /// </summary> |
| 339 | std::shared_ptr<LxssNetworkingFirewall> m_firewall; |
| 340 | |
| 341 | /// <summary> |
| 342 | /// The unique rule name. |
| 343 | /// </summary> |
| 344 | std::wstring m_name; |
| 345 | }; |
| 346 | |
| 347 | /// <summary> |
| 348 | /// Class representing a Windows NAT instance. |
| 349 | /// </summary> |
| 350 | class LxssNetworkingNat |
| 351 | { |
| 352 | public: |
| 353 | /// <summary> |
| 354 | /// Constructor. |
| 355 | /// </summary> |
| 356 | LxssNetworkingNat(const IP_ADDRESS_PREFIX& InputPrefix); |
| 357 | |
| 358 | /// <summary> |
| 359 | /// Constructor to take ownership of an existing NAT. |
| 360 | /// N.B. Not setting m_internalIpAddress as the only usage of this |
| 361 | /// constructor is to wrap an existing instance for cleanup/deletion. |
| 362 | /// If this constructor is to be used for other purposes, need to |
| 363 | /// fetch the s_WmiNatInternalIpAddress property and convert it. |
| 364 | /// </summary> |
| 365 | LxssNetworkingNat(const MI_Instance* ExistingInstance); |
| 366 | |
| 367 | /// <summary> |
| 368 | /// Destructor. |
| 369 | /// </summary> |
| 370 | ~LxssNetworkingNat(); |
| 371 | |
| 372 | /// <summary> |
| 373 | /// The address being NAT'd. |
| 374 | /// </summary> |
| 375 | const IP_ADDRESS_PREFIX& Address() const |
| 376 | { |
| 377 | return m_internalIpAddress; |
| 378 | } |
| 379 | |
| 380 | /// <summary> |
| 381 | /// Cleanup any persistent data leftover from a non-clean shutdown. |
| 382 | /// </summary> |
| 383 | static void CleanupRemnants(); |
| 384 | |
| 385 | private: |
| 386 | /// <summary> |
| 387 | /// No default constructor. |
| 388 | /// </summary> |
| 389 | LxssNetworkingNat() = delete; |
| 390 | /// <summary> |
| 391 | /// No copy constructor. |
| 392 | /// </summary> |
| 393 | LxssNetworkingNat(const LxssNetworkingNat&) = delete; |
| 394 | |
| 395 | /// <summary> |
| 396 | /// The NAT instance. |
| 397 | /// </summary> |
| 398 | unique_mi_instance m_natInstance; |
| 399 | |
| 400 | /// <summary> |
| 401 | /// The session used to create/destroy the NAT. |
| 402 | /// </summary> |
| 403 | unique_mi_session m_session; |
| 404 | |
| 405 | /// <summary> |
| 406 | /// Create a new WMI instance of the NAT type. |
| 407 | /// </summary> |
| 408 | static unique_mi_instance GetNatWmiInstance(const unique_mi_session& Session); |
| 409 | |
| 410 | /// <summary> |
| 411 | /// The IP address prefix to NAT. |
| 412 | /// </summary> |
| 413 | IP_ADDRESS_PREFIX m_internalIpAddress; |
| 414 | |
| 415 | /// <summary> |
| 416 | /// The string prefix for the friendly NAT name. |
| 417 | /// </summary> |
| 418 | static const std::wstring s_FriendlyNamePrefix; |
| 419 | |
| 420 | /// <summary> |
| 421 | /// The string representing the NAT instance ID in WMI. |
| 422 | /// </summary> |
| 423 | static const std::wstring s_WmiNatInstanceId; |
| 424 | |
| 425 | /// <summary> |
| 426 | /// The string representing the NAT internal IP address prefix in WMI. |
| 427 | /// </summary> |
| 428 | static const std::wstring s_WmiNatInternalIpAddress; |
| 429 | |
| 430 | /// <summary> |
| 431 | /// The string representing the NAT name property in WMI. |
| 432 | /// </summary> |
| 433 | static const std::wstring s_WmiNatName; |
| 434 | |
| 435 | /// <summary> |
| 436 | /// The string representing the NAT namespace in WMI. |
| 437 | /// </summary> |
| 438 | static const std::wstring s_WmiNatNamespace; |
| 439 | }; |