1 /*
2 * Copyright (c) 2016-2018 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 #ifndef _SKYWALK_NAMESPACE_NETNS_H_
29 #define _SKYWALK_NAMESPACE_NETNS_H_
30
31 #include <sys/param.h>
32 #include <net/if_var.h>
33
34 /*
35 * The netns module arbitrates local L4 port number usage across Skywalk
36 * and the BSD networking stack. Its aim is to be lightweight and keep as
37 * little state as possible; as such, it can't tell you WHO is using port X
38 * so much as that port X is being used.
39 *
40 * NOTE: This API expects port numbers and IP addresses to be passed in
41 * network byte order.
42 */
43
44
45 /*
46 * netns_token is a structure passed back to port registrants used to keep
47 * track of what they registered and what flags they passed at the time.
48 *
49 * These tokens are intended to be opaque to users and should never be
50 * modified by external code.
51 *
52 * Token memory is managed by netns; they are created as the result of a call
53 * to netns_reserve(), and remain valid until passed into netns_release().
54 */
55 typedef struct ns_token *netns_token;
56
57 extern int netns_init(void);
58 extern void netns_uninit(void);
59 extern void netns_reap_caches(boolean_t);
60 extern boolean_t netns_is_enabled(void);
61
62 /*
63 * Metadata about a flow
64 */
65 struct ns_flow_info {
66 /* rule (flow) UUID */
67 uuid_t nfi_flow_uuid
68 __attribute((aligned(sizeof(uint64_t))));
69
70 struct ifnet *nfi_ifp; /* interface index */
71 union sockaddr_in_4_6 nfi_laddr; /* local IP address */
72 union sockaddr_in_4_6 nfi_faddr; /* foreign IP address */
73 uint8_t nfi_protocol; /* protocol */
74 uint8_t nfi_pad[3]; /* for future */
75 pid_t nfi_owner_pid;
76 pid_t nfi_effective_pid;
77 char nfi_owner_name[MAXCOMLEN + 1];
78 char nfi_effective_name[MAXCOMLEN + 1];
79 };
80
81 /*
82 * Reserve a port in the namespace of the provided <addr, proto> tuple. The
83 * return code indicates whether the reservation succeeded or failed (if the
84 * port was already reserved by another protocol stack).
85 *
86 * The function will create a new netns_token and set the token argument to
87 * point to it. This token should be held for the lifetime of the port
88 * reservation and passed to future netns calls to modify or release
89 * the reservation.
90 *
91 * If a preexisting token is passed in, the call will either panic (if the
92 * NETNS_PRERESERVED flag is not set) or assert that the function arguments
93 * match the reservation pointed to by the token, returning with no further
94 * action (if NETNS_PRERESERVED is set).
95 *
96 * Either NETNS_SKYWALK, NETNS_LISTENER, NETNS_BSD or NETNS_PF must be passed
97 * in through the flags parameter depending on the caller as this is what the
98 * reservation logic uses to determine if a given port is already in use:
99 * - BSD and PF can reserve a port only if it has no Skywalk or Listener
100 * reservations
101 * - Listeners can reserve a port only if it has no Listener, BSD or PF
102 * reservations
103 * - Skywalk can reserve a port only if it has no Skywalk, BSD or PF
104 * reservations, UNLESS there is also a Listener reservation, in which
105 * case the presence of prexisting Skywalk reservations are ignored
106 */
107 extern int netns_reserve(netns_token * token, uint32_t *__sized_by(addr_len) addr,
108 uint8_t addr_len, uint8_t proto, in_port_t port, uint32_t flags,
109 struct ns_flow_info *nfi);
110
111 /*
112 * Reserve a port in the namespace of the provided <addr, proto> tuple, letting
113 * netns pick the port for the caller and saving its value into the port
114 * argument. Aside from this behavior, this function behaves identically to
115 * netns_reserve().
116 */
117 extern int netns_reserve_ephemeral(netns_token * token,
118 uint32_t *__sized_by(addr_len) addr, uint8_t addr_len, uint8_t proto,
119 in_port_t *port, uint32_t flags, struct ns_flow_info *nfi);
120
121 /*
122 * Release a port reservation recorded by the provided token.
123 *
124 * After calling, the token passed into the function becomes valid and the
125 * pointer to it will be set to NULL.
126 */
127 extern void netns_release(netns_token *token);
128
129 /*
130 * Mark a port reservation recorded by the provided token as half closed.
131 * The half closed port will not be included in the list of ports returned
132 * by netns_get_local_ports() when IFNET_GET_LOCAL_PORTS_ACTIVEONLY flag is set.
133 */
134 extern void netns_half_close(netns_token *token);
135
136 /*
137 * Mark a port reservation recorded by the provided token as withdrawn.
138 * The withdrawn port will not be included in the list of ports returned
139 * by netns_get_local_ports().
140 */
141 extern void netns_withdraw(netns_token *token);
142
143 /*
144 * Access the flow info associated with a token, by filling out the local struct.
145 * Returns 0 on success, or an error otherwise.
146 */
147 extern int netns_get_flow_info(netns_token *token, struct ns_flow_info *nfi);
148
149 /*
150 * Update the IP address a port reservation is assigned to - mostly used by
151 * the TCP subsystem of the BSD stack, but technically whenever a pcb element
152 * gets rehashed.
153 *
154 * This operation is atomic - it may fail if the port is already reserved on
155 * the new address and the appropriate reuse flags aren't present, but in this
156 * case the old reservation is kept.
157 *
158 * The passed in token will be updated to reflect this new reservation.
159 */
160 extern int netns_change_addr(netns_token * token,
161 uint32_t *__sized_by(new_addr_len) new_addr, uint8_t new_addr_len);
162
163 /*
164 * Update which network interface a given port reservation corresponds to.
165 * Passing NULL for the ifp argument clears the reservation from all
166 * interfaces.
167 *
168 * Note that a port reservation holds across ALL interfaces in the system,
169 * not just the one set by this function - the ifnet here is primarily used
170 * by netns_get_local_ports() to identify which L4 ports are active on a given
171 * interface.
172 */
173 extern void netns_set_ifnet(netns_token *token, ifnet_t ifp);
174
175 /*
176 * Unrelate all port reservations to the specified interface (effectively
177 * iterates over all tokens pointed to ifp with netns_set_ifnet, and sets their
178 * ifp to null)
179 */
180 extern void netns_ifnet_detach(ifnet_t ifp);
181
182 /*
183 * Change flags related to the port reservation, primarily to provide
184 * information about connection state to drivers looking for port offload
185 * lists.
186 *
187 * Cannot be used to change flags related to the initial reservation, like
188 * NETNS_SKYWALK/NETNS_BSD/etc.
189 */
190 extern void netns_change_flags(netns_token *token, uint32_t set_flags,
191 uint32_t clear_flags);
192
193 /*
194 * Fill in the provided bitfield with the active ports corresponding to the
195 * ifnet specified by ifp. Additional filters can be applied to this bitmap
196 * with the protocol and flags arguments, which behave identically to their
197 * corresponding arguments in ifnet_get_local_ports_extended().
198 */
199 extern errno_t
200 netns_get_local_ports(ifnet_t ifp, protocol_family_t protocol,
201 u_int32_t flags, u_int8_t bitfield[IP_PORTRANGE_BITFIELD_LEN]);
202
203 /*
204 * Return 1 if the parent ifnet of the specified ifaddr has any reservations
205 * for the specified protocol, 0 otherwise.
206 */
207 extern uint32_t
208 netns_find_anyres_byaddr(struct ifaddr *ifa, uint8_t proto);
209
210 /*
211 * Return count of existing port reservations in the coresponding namespace, IPv4.
212 */
213 extern uint32_t
214 netns_lookup_reservations_count_in(struct in_addr addr, uint8_t proto);
215
216 /*
217 * Return count of existing port reservations in the coresponding namespace, IPv6.
218 */
219 extern uint32_t
220 netns_lookup_reservations_count_in6(struct in6_addr addr, uint8_t proto);
221
222 /*
223 * Address-family-specific versions of netns_reserve and netns_change_addr.
224 */
225 __attribute__((always_inline))
226 static inline int
netns_reserve_in(netns_token * token,struct in_addr addr,uint8_t proto,in_port_t port,uint32_t flags,struct ns_flow_info * nfi)227 netns_reserve_in(netns_token *token, struct in_addr addr, uint8_t proto,
228 in_port_t port, uint32_t flags, struct ns_flow_info *nfi)
229 {
230 return netns_reserve(token, &addr.s_addr, sizeof(struct in_addr),
231 proto, port, flags, nfi);
232 }
233
234 __attribute__((always_inline))
235 static inline int
netns_reserve_in6(netns_token * token,struct in6_addr addr,uint8_t proto,in_port_t port,uint32_t flags,struct ns_flow_info * nfi)236 netns_reserve_in6(netns_token *token, struct in6_addr addr, uint8_t proto,
237 in_port_t port, uint32_t flags, struct ns_flow_info *nfi)
238 {
239 if (IN6_IS_SCOPE_EMBED(&addr)) {
240 addr.s6_addr16[1] = 0;
241 }
242 return netns_reserve(token, &addr.s6_addr32[0],
243 sizeof(struct in6_addr), proto, port, flags, nfi);
244 }
245
246 __attribute__((always_inline))
247 static inline int
netns_change_addr_in(netns_token * token,struct in_addr addr)248 netns_change_addr_in(netns_token *token, struct in_addr addr)
249 {
250 return netns_change_addr(token, &addr.s_addr,
251 sizeof(struct in_addr));
252 }
253
254 __attribute__((always_inline))
255 static inline int
netns_change_addr_in6(netns_token * token,struct in6_addr addr)256 netns_change_addr_in6(netns_token *token, struct in6_addr addr)
257 {
258 if (IN6_IS_SCOPE_EMBED(&addr)) {
259 addr.s6_addr16[1] = 0;
260 }
261 return netns_change_addr(token, &addr.s6_addr32[0],
262 sizeof(struct in6_addr));
263 }
264
265 #define NETNS_TOKEN_VALID(token_ptr) ((*token_ptr) != NULL)
266 #define NETNS_AF_SIZE(af) \
267 (((af) == AF_INET) ? sizeof (struct in_addr) : sizeof (struct in6_addr))
268
269 /* Flags for reserve */
270
271 /* The caller is reserving a port on behalf of skywalk, but for a listener */
272 #define NETNS_LISTENER 0x00
273 /* The caller is reserving a port on behalf of skywalk. */
274 #define NETNS_SKYWALK 0x01
275 /* The caller is reserving a port on behalf of the BSD stack. */
276 #define NETNS_BSD 0x02
277 /* The caller is reserving a port on behalf of the Packet Filter (PF). */
278 #define NETNS_PF 0x03
279
280 #define NETNS_OWNER_MAX NETNS_PF
281 #define NETNS_OWNER_MASK 0x07
282 /* Danger Will Robinson: This uses the above as a bitmap. */
283 #define NETNS_IS_SKYWALK(flags) ((flags & NETNS_BSD) == 0)
284
285 /* 0x08 is reserved */
286
287 /*
288 * When passing an already-valid token to netns_reserve, behave as a no-op.
289 * Used by the BSD stack which may speculatively create reservations and then
290 * "finalize" them later by calling netns_reserve again.
291 */
292 #define NETNS_PRERESERVED 0x10
293
294 #define NETNS_RESERVATION_FLAGS (NETNS_PRERESERVED | NETNS_OWNER_MASK)
295
296 /* Flags for change_flags */
297
298 /*
299 * Set when the reservation backs a socket with the SO_NOWAKEFROMSLEEP option
300 * set
301 */
302 #define NETNS_NOWAKEFROMSLEEP 0x20
303
304 /* Set when the reservation backs a socket with the SO_RECV_ANYIF option set */
305 #define NETNS_RECVANYIF 0x40
306
307 /*
308 * Set when the reservation backs a socket with the SO_EXTENDED_BK_IDLE option
309 * set
310 */
311 #define NETNS_EXTBGIDLE 0x80
312
313 /*
314 * Set when the reservation allows reusing the port for new listener
315 */
316 #define NETNS_REUSEPORT 0x100
317
318 #define NETNS_CONFIGURATION_FLAGS (NETNS_NOWAKEFROMSLEEP | NETNS_RECVANYIF | \
319 NETNS_EXTBGIDLE | NETNS_REUSEPORT)
320
321 #endif /* !_SKYWALK_NAMESPACE_NETNS_H_ */
322