master
h 184 lines 5.38 KB
Raw
1 // Copyright (C) Microsoft Corporation. All rights reserved.
2
3 #pragma once
4 #include <map>
5 #include <set>
6 #include <utility>
7 #include <optional>
8 #include <NetlinkChannel.h>
9 #include <future>
10 #include <functional>
11 #include <memory>
12 #include <time.h>
13 #include "util.h"
14 #include <linux/seccomp.h>
15 #include "waitablevalue.h"
16 #include "SecCompDispatcher.h"
17 #include "SocketChannel.h"
18 #include "lxinitshared.h"
19
20 class GnsPortTracker
21 {
22 public:
23 GnsPortTracker(
24 std::shared_ptr<wsl::shared::SocketChannel> hvSocketChannel,
25 NetlinkChannel&& netlinkChannel,
26 std::shared_ptr<SecCompDispatcher> seccompDispatcher,
27 LX_MINI_INIT_NETWORKING_MODE networkingMode);
28
29 GnsPortTracker(const GnsPortTracker&) = delete;
30 GnsPortTracker(GnsPortTracker&&) = delete;
31 GnsPortTracker& operator=(const GnsPortTracker&) = delete;
32 GnsPortTracker& operator=(GnsPortTracker&&) = delete;
33
34 void Run();
35
36 int ProcessSecCompNotification(seccomp_notif* notification);
37
38 struct PortAllocation
39 {
40 in6_addr Address = {};
41 std::uint16_t Port = {};
42 int Family = {};
43 int Protocol = {};
44
45 PortAllocation(PortAllocation&&) = default;
46 PortAllocation(const PortAllocation&) = default;
47
48 PortAllocation& operator=(PortAllocation&&) = default;
49 PortAllocation& operator=(const PortAllocation&) = default;
50
51 PortAllocation(std::uint16_t Port, int Family, int Protocol, in6_addr& Address) :
52 Port(Port), Family(Family), Protocol(Protocol)
53 {
54 memcpy(this->Address.s6_addr32, Address.s6_addr32, sizeof(this->Address.s6_addr32));
55 }
56
57 bool operator<(const PortAllocation& other) const
58 {
59 if (Port < other.Port)
60 {
61 return true;
62 }
63 else if (Port > other.Port)
64 {
65 return false;
66 }
67
68 if (Family < other.Family)
69 {
70 return true;
71 }
72 else if (Family > other.Family)
73 {
74 return false;
75 }
76
77 if (Protocol < other.Protocol)
78 {
79 return true;
80 }
81 else if (Protocol > other.Protocol)
82 {
83 return false;
84 }
85
86 static_assert(sizeof(Address.s6_addr32) == 16);
87 if (int res = memcmp(Address.s6_addr32, other.Address.s6_addr32, sizeof(Address.s6_addr32)); res < 0)
88 {
89 return true;
90 }
91 else if (res > 0)
92 {
93 return false;
94 }
95
96 return false;
97 }
98 };
99
100 struct DeferredPortLookup
101 {
102 pid_t Pid;
103 wil::unique_fd DuplicatedSocketFd; // Duplicated via pidfd_getfd while process was stopped
104 int Protocol;
105
106 DeferredPortLookup(pid_t Pid, wil::unique_fd DuplicatedSocketFd, int Protocol) :
107 Pid(Pid), DuplicatedSocketFd(std::move(DuplicatedSocketFd)), Protocol(Protocol)
108 {
109 }
110
111 DeferredPortLookup(DeferredPortLookup&&) = default;
112 DeferredPortLookup& operator=(DeferredPortLookup&&) = default;
113 DeferredPortLookup(const DeferredPortLookup&) = delete;
114 DeferredPortLookup& operator=(const DeferredPortLookup&) = delete;
115 };
116
117 struct BindCall
118 {
119 std::optional<PortAllocation> Request;
120 std::optional<DeferredPortLookup> PortZeroBind;
121 std::uint64_t CallId;
122 };
123
124 private:
125 using ActivePortSet = std::set<std::pair<std::uint16_t, int>>;
126
127 struct ActivePorts
128 {
129 std::set<PortAllocation> FullAllocations;
130 ActivePortSet PortProtocolPairs; // Always populated, but only used in mirrored mode
131 };
132
133 struct PortRefreshResult
134 {
135 ActivePorts Ports;
136 time_t Timestamp;
137 std::function<void()> Resume;
138 };
139
140 bool IsMirroredMode() const
141 {
142 return m_networkingMode == LxMiniInitNetworkingModeMirrored;
143 }
144
145 void OnRefreshAllocatedPorts(const ActivePorts& Ports, time_t Timestamp);
146
147 void RunPortRefresh();
148
149 ActivePorts ListAllocatedPorts();
150
151 std::optional<BindCall> ReadNextRequest();
152
153 std::optional<BindCall> GetCallInfo(uint64_t CallId, pid_t Pid, int Arch, int SysCallNumber, const gsl::span<unsigned long long>& Arguments);
154
155 int RequestPort(const PortAllocation& Port, bool Allocate);
156
157 int HandleRequest(const PortAllocation& Request);
158
159 void CompleteRequest(uint64_t Id, int Result);
160
161 static int GetSocketProtocol(int Pid, int Fd);
162
163 static wil::unique_fd DuplicateSocketFd(pid_t Pid, int SocketFd);
164
165 std::optional<PortAllocation> ResolvePortZeroBind(DeferredPortLookup lookup);
166
167 void TrackPort(PortAllocation allocation);
168
169 std::map<PortAllocation, std::optional<time_t>> m_allocatedPorts;
170 std::shared_ptr<wsl::shared::SocketChannel> m_hvSocketChannel;
171 NetlinkChannel m_channel;
172 std::promise<PortRefreshResult> m_allocatedPortsRefresh;
173
174 WaitableValue<seccomp_notif> m_request;
175 WaitableValue<int> m_reply;
176
177 std::shared_ptr<SecCompDispatcher> m_seccompDispatcher;
178
179 LX_MINI_INIT_NETWORKING_MODE m_networkingMode;
180
181 std::string m_networkNamespace;
182 };
183
184 std::ostream& operator<<(std::ostream& out, const GnsPortTracker::PortAllocation& portAllocation);