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 */
55typedef struct ns_token *netns_token;
56
57extern int netns_init(void);
58extern void netns_uninit(void);
59extern void netns_reap_caches(boolean_t);
60extern boolean_t netns_is_enabled(void);
61
62/*
63 * Metadata about a flow
64 */
65struct 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 */
107extern int netns_reserve(netns_token *token, uint32_t *addr, uint8_t addr_len,
108 uint8_t proto, in_port_t port, uint32_t flags, struct ns_flow_info *nfi);
109
110/*
111 * Reserve a port in the namespace of the provided <addr, proto> tuple, letting
112 * netns pick the port for the caller and saving its value into the port
113 * argument. Aside from this behavior, this function behaves identically to
114 * netns_reserve().
115 */
116extern int netns_reserve_ephemeral(netns_token *token, uint32_t *addr,
117 uint8_t addr_len, uint8_t proto, in_port_t *port, uint32_t flags,
118 struct ns_flow_info *nfi);
119
120/*
121 * Release a port reservation recorded by the provided token.
122 *
123 * After calling, the token passed into the function becomes valid and the
124 * pointer to it will be set to NULL.
125 */
126extern void netns_release(netns_token *token);
127
128/*
129 * Mark a port reservation recorded by the provided token as half closed.
130 * The half closed port will not be included in the list of ports returned
131 * by netns_get_local_ports() when IFNET_GET_LOCAL_PORTS_ACTIVEONLY flag is set.
132 */
133extern void netns_half_close(netns_token *token);
134
135/*
136 * Mark a port reservation recorded by the provided token as withdrawn.
137 * The withdrawn port will not be included in the list of ports returned
138 * by netns_get_local_ports().
139 */
140extern void netns_withdraw(netns_token *token);
141
142/*
143 * Access the flow info associated with a token, by filling out the local struct.
144 * Returns 0 on success, or an error otherwise.
145 */
146extern int netns_get_flow_info(netns_token *token, struct ns_flow_info *nfi);
147
148/*
149 * Update the IP address a port reservation is assigned to - mostly used by
150 * the TCP subsystem of the BSD stack, but technically whenever a pcb element
151 * gets rehashed.
152 *
153 * This operation is atomic - it may fail if the port is already reserved on
154 * the new address and the appropriate reuse flags aren't present, but in this
155 * case the old reservation is kept.
156 *
157 * The passed in token will be updated to reflect this new reservation.
158 */
159extern int netns_change_addr(netns_token *token, uint32_t *new_addr,
160 uint8_t new_addr_len);
161
162/*
163 * Update which network interface a given port reservation corresponds to.
164 * Passing NULL for the ifp argument clears the reservation from all
165 * interfaces.
166 *
167 * Note that a port reservation holds across ALL interfaces in the system,
168 * not just the one set by this function - the ifnet here is primarily used
169 * by netns_get_local_ports() to identify which L4 ports are active on a given
170 * interface.
171 */
172extern void netns_set_ifnet(netns_token *token, ifnet_t ifp);
173
174/*
175 * Unrelate all port reservations to the specified interface (effectively
176 * iterates over all tokens pointed to ifp with netns_set_ifnet, and sets their
177 * ifp to null)
178 */
179extern void netns_ifnet_detach(ifnet_t ifp);
180
181/*
182 * Change flags related to the port reservation, primarily to provide
183 * information about connection state to drivers looking for port offload
184 * lists.
185 *
186 * Cannot be used to change flags related to the initial reservation, like
187 * NETNS_SKYWALK/NETNS_BSD/etc.
188 */
189extern void netns_change_flags(netns_token *token, uint32_t set_flags,
190 uint32_t clear_flags);
191
192/*
193 * Fill in the provided bitfield with the active ports corresponding to the
194 * ifnet specified by ifp. Additional filters can be applied to this bitmap
195 * with the protocol and flags arguments, which behave identically to their
196 * corresponding arguments in ifnet_get_local_ports_extended().
197 */
198extern errno_t
199netns_get_local_ports(ifnet_t ifp, protocol_family_t protocol,
200 u_int32_t flags, u_int8_t *bitfield);
201
202/*
203 * Return 1 if the parent ifnet of the specified ifaddr has any reservations
204 * for the specified protocol, 0 otherwise.
205 */
206extern uint32_t
207netns_find_anyres_byaddr(struct ifaddr *ifa, uint8_t proto);
208
209/*
210 * Return count of existing port reservations in the coresponding namespace, IPv4.
211 */
212extern uint32_t
213netns_lookup_reservations_count_in(struct in_addr addr, uint8_t proto);
214
215/*
216 * Return count of existing port reservations in the coresponding namespace, IPv6.
217 */
218extern uint32_t
219netns_lookup_reservations_count_in6(struct in6_addr addr, uint8_t proto);
220
221/*
222 * Address-family-specific versions of netns_reserve and netns_change_addr.
223 */
224__attribute__((always_inline))
225static inline int
226netns_reserve_in(netns_token *token, struct in_addr addr, uint8_t proto,
227 in_port_t port, uint32_t flags, struct ns_flow_info *nfi)
228{
229 return netns_reserve(token, addr: &addr.s_addr, addr_len: sizeof(struct in_addr),
230 proto, port, flags, nfi);
231}
232
233__attribute__((always_inline))
234static inline int
235netns_reserve_in6(netns_token *token, struct in6_addr addr, uint8_t proto,
236 in_port_t port, uint32_t flags, struct ns_flow_info *nfi)
237{
238 if (IN6_IS_SCOPE_EMBED(&addr)) {
239 addr.s6_addr16[1] = 0;
240 }
241 return netns_reserve(token, addr: &addr.s6_addr32[0],
242 addr_len: sizeof(struct in6_addr), proto, port, flags, nfi);
243}
244
245__attribute__((always_inline))
246static inline int
247netns_change_addr_in(netns_token *token, struct in_addr addr)
248{
249 return netns_change_addr(token, new_addr: &addr.s_addr,
250 new_addr_len: sizeof(struct in_addr));
251}
252
253__attribute__((always_inline))
254static inline int
255netns_change_addr_in6(netns_token *token, struct in6_addr addr)
256{
257 if (IN6_IS_SCOPE_EMBED(&addr)) {
258 addr.s6_addr16[1] = 0;
259 }
260 return netns_change_addr(token, new_addr: &addr.s6_addr32[0],
261 new_addr_len: sizeof(struct in6_addr));
262}
263
264#define NETNS_TOKEN_VALID(token_ptr) ((*token_ptr) != NULL)
265#define NETNS_AF_SIZE(af) \
266 (((af) == AF_INET) ? sizeof (struct in_addr) : sizeof (struct in6_addr))
267
268/* Flags for reserve */
269
270/* The caller is reserving a port on behalf of skywalk, but for a listener */
271#define NETNS_LISTENER 0x00
272/* The caller is reserving a port on behalf of skywalk. */
273#define NETNS_SKYWALK 0x01
274/* The caller is reserving a port on behalf of the BSD stack. */
275#define NETNS_BSD 0x02
276/* The caller is reserving a port on behalf of the Packet Filter (PF). */
277#define NETNS_PF 0x03
278
279#define NETNS_OWNER_MAX NETNS_PF
280#define NETNS_OWNER_MASK 0x07
281/* Danger Will Robinson: This uses the above as a bitmap. */
282#define NETNS_IS_SKYWALK(flags) ((flags & NETNS_BSD) == 0)
283
284/* 0x08 is reserved */
285
286/*
287 * When passing an already-valid token to netns_reserve, behave as a no-op.
288 * Used by the BSD stack which may speculatively create reservations and then
289 * "finalize" them later by calling netns_reserve again.
290 */
291#define NETNS_PRERESERVED 0x10
292
293#define NETNS_RESERVATION_FLAGS (NETNS_PRERESERVED | NETNS_OWNER_MASK)
294
295/* Flags for change_flags */
296
297/*
298 * Set when the reservation backs a socket with the SO_NOWAKEFROMSLEEP option
299 * set
300 */
301#define NETNS_NOWAKEFROMSLEEP 0x20
302
303/* Set when the reservation backs a socket with the SO_RECV_ANYIF option set */
304#define NETNS_RECVANYIF 0x40
305
306/*
307 * Set when the reservation backs a socket with the SO_EXTENDED_BK_IDLE option
308 * set
309 */
310#define NETNS_EXTBGIDLE 0x80
311
312/*
313 * Set when the reservation allows reusing the port for new listener
314 */
315#define NETNS_REUSEPORT 0x100
316
317#define NETNS_CONFIGURATION_FLAGS (NETNS_NOWAKEFROMSLEEP | NETNS_RECVANYIF | \
318 NETNS_EXTBGIDLE | NETNS_REUSEPORT)
319
320#endif /* !_SKYWALK_NAMESPACE_NETNS_H_ */
321