]> git.saurik.com Git - apple/xnu.git/blame - bsd/net/if_ports_used.c
xnu-7195.101.1.tar.gz
[apple/xnu.git] / bsd / net / if_ports_used.c
CommitLineData
a39ff7e2 1/*
f427ee49 2 * Copyright (c) 2017-2020 Apple Inc. All rights reserved.
a39ff7e2
A
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
29#include <sys/types.h>
30#include <sys/sysctl.h>
31#include <sys/time.h>
32#include <sys/mcache.h>
33#include <sys/malloc.h>
34#include <sys/kauth.h>
35#include <sys/bitstring.h>
36#include <sys/priv.h>
d9a64523 37#include <sys/protosw.h>
a39ff7e2
A
38#include <sys/socket.h>
39
40#include <kern/locks.h>
41#include <kern/zalloc.h>
42
43#include <libkern/libkern.h>
a39ff7e2
A
44
45#include <net/kpi_interface.h>
46#include <net/if_var.h>
47#include <net/if_ports_used.h>
48
49#include <netinet/in_pcb.h>
94ff46dc
A
50#include <netinet/tcp_var.h>
51#include <netinet/tcp_fsm.h>
a39ff7e2
A
52
53
54#include <stdbool.h>
55
56#include <os/log.h>
57
58extern bool IOPMCopySleepWakeUUIDKey(char *buffer, size_t buf_len);
59
60SYSCTL_DECL(_net_link_generic_system);
61
62SYSCTL_NODE(_net_link_generic_system, OID_AUTO, port_used,
63 CTLFLAG_RW | CTLFLAG_LOCKED, 0, "if port used");
64
0a7de745 65static uuid_t current_wakeuuid;
a39ff7e2 66SYSCTL_OPAQUE(_net_link_generic_system_port_used, OID_AUTO, current_wakeuuid,
0a7de745 67 CTLFLAG_RD | CTLFLAG_LOCKED,
a39ff7e2
A
68 current_wakeuuid, sizeof(uuid_t), "S,uuid_t", "");
69
70static int sysctl_net_port_info_list SYSCTL_HANDLER_ARGS;
71SYSCTL_PROC(_net_link_generic_system_port_used, OID_AUTO, list,
72 CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_LOCKED, 0, 0,
73 sysctl_net_port_info_list, "S,xnpigen", "");
74
75static int use_test_wakeuuid = 0;
76static uuid_t test_wakeuuid;
b226f5e5 77static uuid_string_t test_wakeuuid_str;
a39ff7e2
A
78
79#if (DEVELOPMENT || DEBUG)
80SYSCTL_INT(_net_link_generic_system_port_used, OID_AUTO, use_test_wakeuuid,
81 CTLFLAG_RW | CTLFLAG_LOCKED,
82 &use_test_wakeuuid, 0, "");
83
84int sysctl_new_test_wakeuuid SYSCTL_HANDLER_ARGS;
85SYSCTL_PROC(_net_link_generic_system_port_used, OID_AUTO, new_test_wakeuuid,
86 CTLTYPE_STRUCT | CTLFLAG_RW | CTLFLAG_LOCKED, 0, 0,
87 sysctl_new_test_wakeuuid, "S,uuid_t", "");
88
89int sysctl_clear_test_wakeuuid SYSCTL_HANDLER_ARGS;
90SYSCTL_PROC(_net_link_generic_system_port_used, OID_AUTO, clear_test_wakeuuid,
91 CTLTYPE_STRUCT | CTLFLAG_RW | CTLFLAG_LOCKED, 0, 0,
92 sysctl_clear_test_wakeuuid, "S,uuid_t", "");
93
b226f5e5
A
94int sysctl_test_wakeuuid_str SYSCTL_HANDLER_ARGS;
95SYSCTL_PROC(_net_link_generic_system_port_used, OID_AUTO, test_wakeuuid_str,
96 CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_LOCKED, 0, 0,
97 sysctl_test_wakeuuid_str, "A", "");
98
a39ff7e2 99SYSCTL_OPAQUE(_net_link_generic_system_port_used, OID_AUTO, test_wakeuuid,
0a7de745 100 CTLFLAG_RD | CTLFLAG_LOCKED,
a39ff7e2
A
101 test_wakeuuid, sizeof(uuid_t), "S,uuid_t", "");
102#endif /* (DEVELOPMENT || DEBUG) */
103
104static int sysctl_get_ports_used SYSCTL_HANDLER_ARGS;
105SYSCTL_NODE(_net_link_generic_system, OID_AUTO, get_ports_used,
106 CTLFLAG_RD | CTLFLAG_LOCKED,
107 sysctl_get_ports_used, "");
108
109static uint32_t net_port_entry_count = 0;
110SYSCTL_UINT(_net_link_generic_system_port_used, OID_AUTO, entry_count,
111 CTLFLAG_RW | CTLFLAG_LOCKED,
112 &net_port_entry_count, 0, "");
113
114static uint32_t net_port_entry_gen = 0;
115SYSCTL_UINT(_net_link_generic_system_port_used, OID_AUTO, entry_gen,
116 CTLFLAG_RW | CTLFLAG_LOCKED,
117 &net_port_entry_gen, 0, "");
118
119static int if_ports_used_verbose = 0;
120SYSCTL_INT(_net_link_generic_system_port_used, OID_AUTO, verbose,
121 CTLFLAG_RW | CTLFLAG_LOCKED,
122 &if_ports_used_verbose, 0, "");
123
124static unsigned long wakeuuid_not_set_count = 0;
125SYSCTL_ULONG(_net_link_generic_system_port_used, OID_AUTO,
126 wakeuuid_not_set_count, CTLFLAG_RD | CTLFLAG_LOCKED,
127 &wakeuuid_not_set_count, 0);
128
129struct timeval wakeuuid_not_set_last_time;
130int sysctl_wakeuuid_not_set_last_time SYSCTL_HANDLER_ARGS;
131static SYSCTL_PROC(_net_link_generic_system_port_used, OID_AUTO,
132 wakeuuid_not_set_last_time, CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_LOCKED,
133 0, 0, sysctl_wakeuuid_not_set_last_time, "S,timeval", "");
134
0a7de745 135char wakeuuid_not_set_last_if[IFXNAMSIZ];
a39ff7e2
A
136int sysctl_wakeuuid_not_set_last_if SYSCTL_HANDLER_ARGS;
137static SYSCTL_PROC(_net_link_generic_system_port_used, OID_AUTO,
138 wakeuuid_not_set_last_if, CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_LOCKED,
139 0, 0, sysctl_wakeuuid_not_set_last_if, "A", "");
140
141
142static int if_ports_used_inited = 0;
143
144decl_lck_mtx_data(static, net_port_entry_head_lock);
145static lck_grp_t *net_port_entry_head_lock_group;
146
147struct net_port_entry {
0a7de745
A
148 SLIST_ENTRY(net_port_entry) npe_next;
149 struct net_port_info npe_npi;
a39ff7e2
A
150};
151
f427ee49
A
152static ZONE_DECLARE(net_port_entry_zone, "net_port_entry",
153 sizeof(struct net_port_entry), ZC_NONE);
a39ff7e2
A
154
155static SLIST_HEAD(net_port_entry_list, net_port_entry) net_port_entry_list =
156 SLIST_HEAD_INITIALIZER(&net_port_entry_list);
157
158struct timeval wakeuiid_last_check;
159
160void
161if_ports_used_init(void)
162{
163 if (if_ports_used_inited == 0) {
164 lck_grp_attr_t *lck_grp_attributes = NULL;
165 lck_attr_t *lck_attributes = NULL;
166
167 timerclear(&wakeuiid_last_check);
168 uuid_clear(current_wakeuuid);
169 uuid_clear(test_wakeuuid);
170
171 lck_grp_attributes = lck_grp_attr_alloc_init();
172 net_port_entry_head_lock_group = lck_grp_alloc_init(
0a7de745 173 "net port entry lock", lck_grp_attributes);
a39ff7e2
A
174
175 lck_attributes = lck_attr_alloc_init();
176 if (lck_attributes == NULL) {
177 panic("%s: lck_attr_alloc_init() failed", __func__);
178 }
179 lck_mtx_init(&net_port_entry_head_lock,
180 net_port_entry_head_lock_group,
181 lck_attributes);
182
183 net_port_entry_count = 0;
a39ff7e2
A
184 if_ports_used_inited = 1;
185
186 lck_attr_free(lck_attributes);
187 lck_grp_attr_free(lck_grp_attributes);
188 }
189}
190
191static void
192net_port_entry_list_clear(void)
193{
194 struct net_port_entry *npe;
195
196 LCK_MTX_ASSERT(&net_port_entry_head_lock, LCK_MTX_ASSERT_OWNED);
197
198 while ((npe = SLIST_FIRST(&net_port_entry_list)) != NULL) {
199 SLIST_REMOVE_HEAD(&net_port_entry_list, npe_next);
200
201 zfree(net_port_entry_zone, npe);
202 }
203 net_port_entry_count = 0;
204 net_port_entry_gen++;
205}
206
207static bool
b226f5e5 208get_test_wake_uuid(uuid_string_t wakeuuid_str, size_t len)
a39ff7e2
A
209{
210 if (__improbable(use_test_wakeuuid)) {
211 if (!uuid_is_null(test_wakeuuid)) {
b226f5e5
A
212 if (wakeuuid_str != NULL && len != 0) {
213 uuid_unparse(test_wakeuuid, wakeuuid_str);
214 }
0a7de745 215 return true;
b226f5e5
A
216 } else if (strlen(test_wakeuuid_str) != 0) {
217 if (wakeuuid_str != NULL && len != 0) {
218 strlcpy(wakeuuid_str, test_wakeuuid_str, len);
a39ff7e2 219 }
0a7de745 220 return true;
a39ff7e2 221 } else {
0a7de745 222 return false;
a39ff7e2
A
223 }
224 } else {
0a7de745 225 return false;
a39ff7e2
A
226 }
227}
228
229static bool
230is_wakeuuid_set(void)
231{
232 /*
233 * IOPMCopySleepWakeUUIDKey() tells if SleepWakeUUID is currently set
234 * That means we are currently in a sleep/wake cycle
235 */
0a7de745 236 return get_test_wake_uuid(NULL, 0) || IOPMCopySleepWakeUUIDKey(NULL, 0);
a39ff7e2
A
237}
238
239void
240if_ports_used_update_wakeuuid(struct ifnet *ifp)
241{
242 uuid_t wakeuuid;
243 bool wakeuuid_is_set = false;
244 bool updated = false;
b226f5e5
A
245 uuid_string_t wakeuuid_str;
246
247 uuid_clear(wakeuuid);
a39ff7e2
A
248
249 if (__improbable(use_test_wakeuuid)) {
b226f5e5
A
250 wakeuuid_is_set = get_test_wake_uuid(wakeuuid_str,
251 sizeof(wakeuuid_str));
a39ff7e2 252 } else {
a39ff7e2
A
253 wakeuuid_is_set = IOPMCopySleepWakeUUIDKey(wakeuuid_str,
254 sizeof(wakeuuid_str));
b226f5e5
A
255 }
256
257 if (wakeuuid_is_set) {
258 if (uuid_parse(wakeuuid_str, wakeuuid) != 0) {
259 os_log(OS_LOG_DEFAULT,
260 "%s: IOPMCopySleepWakeUUIDKey got bad value %s\n",
261 __func__, wakeuuid_str);
262 wakeuuid_is_set = false;
a39ff7e2
A
263 }
264 }
265
266 if (!wakeuuid_is_set) {
267 if (if_ports_used_verbose > 0) {
268 os_log_info(OS_LOG_DEFAULT,
269 "%s: SleepWakeUUID not set, "
270 "don't update the port list for %s\n",
271 __func__, ifp != NULL ? if_name(ifp) : "");
272 }
273 wakeuuid_not_set_count += 1;
274 if (ifp != NULL) {
275 microtime(&wakeuuid_not_set_last_time);
276 strlcpy(wakeuuid_not_set_last_if, if_name(ifp),
277 sizeof(wakeuuid_not_set_last_if));
0a7de745 278 }
a39ff7e2
A
279 return;
280 }
281
282 lck_mtx_lock(&net_port_entry_head_lock);
283 if (uuid_compare(wakeuuid, current_wakeuuid) != 0) {
284 net_port_entry_list_clear();
285 uuid_copy(current_wakeuuid, wakeuuid);
286 updated = true;
287 }
0a7de745 288 /*
a39ff7e2
A
289 * Record the time last checked
290 */
291 microuptime(&wakeuiid_last_check);
292 lck_mtx_unlock(&net_port_entry_head_lock);
293
294 if (updated && if_ports_used_verbose > 0) {
295 uuid_string_t uuid_str;
296
297 uuid_unparse(current_wakeuuid, uuid_str);
298 log(LOG_ERR, "%s: current wakeuuid %s\n",
299 __func__,
300 uuid_str);
301 }
302}
303
304static bool
305net_port_info_equal(const struct net_port_info *x,
306 const struct net_port_info *y)
307{
308 ASSERT(x != NULL && y != NULL);
309
310 if (x->npi_if_index == y->npi_if_index &&
311 x->npi_local_port == y->npi_local_port &&
312 x->npi_foreign_port == y->npi_foreign_port &&
313 x->npi_owner_pid == y->npi_owner_pid &&
314 x->npi_effective_pid == y->npi_effective_pid &&
315 x->npi_flags == y->npi_flags &&
316 memcmp(&x->npi_local_addr_, &y->npi_local_addr_,
0a7de745 317 sizeof(union in_addr_4_6)) == 0 &&
a39ff7e2 318 memcmp(&x->npi_foreign_addr_, &y->npi_foreign_addr_,
0a7de745
A
319 sizeof(union in_addr_4_6)) == 0) {
320 return true;
a39ff7e2 321 }
0a7de745 322 return false;
a39ff7e2
A
323}
324
325static bool
326net_port_info_has_entry(const struct net_port_info *npi)
327{
328 struct net_port_entry *npe;
329
330 LCK_MTX_ASSERT(&net_port_entry_head_lock, LCK_MTX_ASSERT_OWNED);
331
332 SLIST_FOREACH(npe, &net_port_entry_list, npe_next) {
333 if (net_port_info_equal(&npe->npe_npi, npi)) {
0a7de745 334 return true;
a39ff7e2
A
335 }
336 }
337
0a7de745 338 return false;
a39ff7e2
A
339}
340
341static bool
342net_port_info_add_entry(const struct net_port_info *npi)
343{
0a7de745 344 struct net_port_entry *npe = NULL;
a39ff7e2
A
345 uint32_t num = 0;
346 bool entry_added = false;
347
348 ASSERT(npi != NULL);
349
350 if (__improbable(is_wakeuuid_set() == false)) {
351 if (if_ports_used_verbose > 0) {
f427ee49 352 log(LOG_ERR, "%s: wakeuuid not set not adding "
a39ff7e2
A
353 "port: %u flags: 0x%xif: %u pid: %u epid %u\n",
354 __func__,
355 ntohs(npi->npi_local_port),
356 npi->npi_flags,
357 npi->npi_if_index,
358 npi->npi_owner_pid,
359 npi->npi_effective_pid);
360 }
0a7de745 361 return 0;
a39ff7e2
A
362 }
363
364 npe = zalloc(net_port_entry_zone);
365 if (__improbable(npe == NULL)) {
366 log(LOG_ERR, "%s: zalloc() failed for "
367 "port: %u flags: 0x%x if: %u pid: %u epid %u\n",
368 __func__,
369 ntohs(npi->npi_local_port),
370 npi->npi_flags,
371 npi->npi_if_index,
372 npi->npi_owner_pid,
373 npi->npi_effective_pid);
0a7de745 374 return 0;
a39ff7e2
A
375 }
376 bzero(npe, sizeof(struct net_port_entry));
377
378 memcpy(&npe->npe_npi, npi, sizeof(npe->npe_npi));
379
380 lck_mtx_lock(&net_port_entry_head_lock);
381
382 if (net_port_info_has_entry(npi) == false) {
383 SLIST_INSERT_HEAD(&net_port_entry_list, npe, npe_next);
384 num = net_port_entry_count++;
385 entry_added = true;
386
387 if (if_ports_used_verbose > 0) {
388 log(LOG_ERR, "%s: num %u for "
389 "port: %u flags: 0x%x if: %u pid: %u epid %u\n",
390 __func__,
391 num,
392 ntohs(npi->npi_local_port),
393 npi->npi_flags,
394 npi->npi_if_index,
395 npi->npi_owner_pid,
396 npi->npi_effective_pid);
397 }
398 } else {
399 if (if_ports_used_verbose > 0) {
400 log(LOG_ERR, "%s: entry already added "
401 "port: %u flags: 0x%x if: %u pid: %u epid %u\n",
402 __func__,
403 ntohs(npi->npi_local_port),
404 npi->npi_flags,
405 npi->npi_if_index,
406 npi->npi_owner_pid,
407 npi->npi_effective_pid);
408 }
409 }
410
411 lck_mtx_unlock(&net_port_entry_head_lock);
412
413 if (entry_added == false) {
414 zfree(net_port_entry_zone, npe);
415 npe = NULL;
416 }
0a7de745 417 return entry_added;
a39ff7e2
A
418}
419
420#if (DEVELOPMENT || DEBUG)
421int
422sysctl_new_test_wakeuuid SYSCTL_HANDLER_ARGS
423{
424#pragma unused(oidp, arg1, arg2)
425 int error = 0;
426
427 if (kauth_cred_issuser(kauth_cred_get()) == 0) {
0a7de745 428 return EPERM;
a39ff7e2
A
429 }
430 if (req->oldptr == USER_ADDR_NULL) {
431 req->oldidx = sizeof(uuid_t);
0a7de745 432 return 0;
a39ff7e2
A
433 }
434 if (req->newptr != USER_ADDR_NULL) {
435 uuid_generate(test_wakeuuid);
436 }
437 error = SYSCTL_OUT(req, test_wakeuuid,
438 MIN(sizeof(uuid_t), req->oldlen));
439
0a7de745 440 return error;
a39ff7e2
A
441}
442
443int
444sysctl_clear_test_wakeuuid SYSCTL_HANDLER_ARGS
445{
446#pragma unused(oidp, arg1, arg2)
447 int error = 0;
448
449 if (kauth_cred_issuser(kauth_cred_get()) == 0) {
0a7de745 450 return EPERM;
a39ff7e2
A
451 }
452 if (req->oldptr == USER_ADDR_NULL) {
453 req->oldidx = sizeof(uuid_t);
0a7de745 454 return 0;
a39ff7e2
A
455 }
456 if (req->newptr != USER_ADDR_NULL) {
457 uuid_clear(test_wakeuuid);
458 }
459 error = SYSCTL_OUT(req, test_wakeuuid,
460 MIN(sizeof(uuid_t), req->oldlen));
461
0a7de745 462 return error;
a39ff7e2
A
463}
464
b226f5e5
A
465int
466sysctl_test_wakeuuid_str SYSCTL_HANDLER_ARGS
467{
468#pragma unused(oidp, arg1, arg2)
469 int error = 0;
470 int changed;
471
472 if (kauth_cred_issuser(kauth_cred_get()) == 0) {
0a7de745 473 return EPERM;
b226f5e5
A
474 }
475 error = sysctl_io_string(req, test_wakeuuid_str, sizeof(test_wakeuuid_str), 1, &changed);
476 if (changed) {
477 os_log_info(OS_LOG_DEFAULT, "%s: test_wakeuuid_str %s",
478 __func__, test_wakeuuid_str);
479 }
480
0a7de745 481 return error;
b226f5e5
A
482}
483
a39ff7e2
A
484#endif /* (DEVELOPMENT || DEBUG) */
485
486int
487sysctl_wakeuuid_not_set_last_time SYSCTL_HANDLER_ARGS
488{
489#pragma unused(oidp, arg1, arg2)
490
491 if (proc_is64bit(req->p)) {
d9a64523 492 struct user64_timeval tv = {};
a39ff7e2
A
493
494 tv.tv_sec = wakeuuid_not_set_last_time.tv_sec;
495 tv.tv_usec = wakeuuid_not_set_last_time.tv_usec;
496 return SYSCTL_OUT(req, &tv, sizeof(tv));
497 } else {
d9a64523 498 struct user32_timeval tv = {};
a39ff7e2 499
f427ee49 500 tv.tv_sec = (user32_time_t)wakeuuid_not_set_last_time.tv_sec;
a39ff7e2
A
501 tv.tv_usec = wakeuuid_not_set_last_time.tv_usec;
502 return SYSCTL_OUT(req, &tv, sizeof(tv));
503 }
504}
505
506int
507sysctl_wakeuuid_not_set_last_if SYSCTL_HANDLER_ARGS
508{
509#pragma unused(oidp, arg1, arg2)
510
511 return SYSCTL_OUT(req, &wakeuuid_not_set_last_if,
0a7de745 512 strlen(wakeuuid_not_set_last_if) + 1);
a39ff7e2
A
513}
514
515static int
516sysctl_net_port_info_list SYSCTL_HANDLER_ARGS
517{
518#pragma unused(oidp, arg1, arg2)
519 int error = 0;
520 struct xnpigen xnpigen;
521 struct net_port_entry *npe;
522
523 if ((error = priv_check_cred(kauth_cred_get(),
524 PRIV_NET_PRIVILEGED_NETWORK_STATISTICS, 0)) != 0) {
0a7de745 525 return EPERM;
a39ff7e2
A
526 }
527 lck_mtx_lock(&net_port_entry_head_lock);
528
529 if (req->oldptr == USER_ADDR_NULL) {
530 /* Add a 25 % cushion */
531 uint32_t cnt = net_port_entry_count;
532 cnt += cnt >> 4;
533 req->oldidx = sizeof(struct xnpigen) +
0a7de745 534 cnt * sizeof(struct net_port_info);
a39ff7e2
A
535 goto done;
536 }
537
538 memset(&xnpigen, 0, sizeof(struct xnpigen));
539 xnpigen.xng_len = sizeof(struct xnpigen);
540 xnpigen.xng_gen = net_port_entry_gen;
541 uuid_copy(xnpigen.xng_wakeuuid, current_wakeuuid);
542 xnpigen.xng_npi_count = net_port_entry_count;
543 xnpigen.xng_npi_size = sizeof(struct net_port_info);
0a7de745 544 error = SYSCTL_OUT(req, &xnpigen, sizeof(xnpigen));
a39ff7e2
A
545 if (error != 0) {
546 printf("%s: SYSCTL_OUT(xnpigen) error %d\n",
547 __func__, error);
548 goto done;
549 }
550
551 SLIST_FOREACH(npe, &net_port_entry_list, npe_next) {
552 error = SYSCTL_OUT(req, &npe->npe_npi,
553 sizeof(struct net_port_info));
554 if (error != 0) {
555 printf("%s: SYSCTL_OUT(npi) error %d\n",
556 __func__, error);
557 goto done;
558 }
559 }
560done:
561 lck_mtx_unlock(&net_port_entry_head_lock);
562
0a7de745 563 return error;
a39ff7e2
A
564}
565
566/*
567 * Mirror the arguments of ifnet_get_local_ports_extended()
568 * ifindex
569 * protocol
570 * flags
571 */
572static int
573sysctl_get_ports_used SYSCTL_HANDLER_ARGS
574{
575#pragma unused(oidp)
576 int *name = (int *)arg1;
577 int namelen = arg2;
578 int error = 0;
579 int idx;
580 protocol_family_t protocol;
581 u_int32_t flags;
582 ifnet_t ifp = NULL;
583 u_int8_t *bitfield = NULL;
584
585 if (req->newptr != USER_ADDR_NULL) {
586 error = EPERM;
587 goto done;
588 }
589 /*
590 * 3 is the required number of parameters: ifindex, protocol and flags
591 */
592 if (namelen != 3) {
593 error = ENOENT;
594 goto done;
595 }
596
597 if (req->oldptr == USER_ADDR_NULL) {
598 req->oldidx = bitstr_size(IP_PORTRANGE_SIZE);
599 goto done;
600 }
601 if (req->oldlen < bitstr_size(IP_PORTRANGE_SIZE)) {
602 error = ENOMEM;
603 goto done;
604 }
605
606 idx = name[0];
607 protocol = name[1];
608 flags = name[2];
609
610 ifnet_head_lock_shared();
611 if (!IF_INDEX_IN_RANGE(idx)) {
612 ifnet_head_done();
613 error = ENOENT;
614 goto done;
615 }
616 ifp = ifindex2ifnet[idx];
617 ifnet_head_done();
618
619 bitfield = _MALLOC(bitstr_size(IP_PORTRANGE_SIZE), M_TEMP,
620 M_WAITOK | M_ZERO);
621 if (bitfield == NULL) {
622 error = ENOMEM;
623 goto done;
624 }
625 error = ifnet_get_local_ports_extended(ifp, protocol, flags, bitfield);
626 if (error != 0) {
627 printf("%s: ifnet_get_local_ports_extended() error %d\n",
628 __func__, error);
629 goto done;
630 }
631 error = SYSCTL_OUT(req, bitfield, bitstr_size(IP_PORTRANGE_SIZE));
632done:
0a7de745 633 if (bitfield != NULL) {
a39ff7e2 634 _FREE(bitfield, M_TEMP);
0a7de745
A
635 }
636 return error;
a39ff7e2
A
637}
638
639__private_extern__ void
640if_ports_used_add_inpcb(const uint32_t ifindex, const struct inpcb *inp)
641{
642 struct net_port_info npi;
643 struct socket *so = inp->inp_socket;
644
645 bzero(&npi, sizeof(struct net_port_info));
646
f427ee49
A
647 /* This is unlikely to happen but better be safe than sorry */
648 if (ifindex > UINT16_MAX) {
649 os_log(OS_LOG_DEFAULT, "%s: ifindex %u too big\n", __func__, ifindex);
650 return;
651 }
652 npi.npi_if_index = (uint16_t)ifindex;
a39ff7e2
A
653
654 npi.npi_flags |= NPIF_SOCKET;
655
f427ee49 656 npi.npi_timestamp.tv_sec = (int32_t)wakeuiid_last_check.tv_sec;
a39ff7e2
A
657 npi.npi_timestamp.tv_usec = wakeuiid_last_check.tv_usec;
658
659 if (SOCK_PROTO(so) == IPPROTO_TCP) {
94ff46dc
A
660 struct tcpcb *tp = intotcpcb(inp);
661
a39ff7e2 662 npi.npi_flags |= NPIF_TCP;
94ff46dc
A
663 if (tp != NULL && tp->t_state == TCPS_LISTEN) {
664 npi.npi_flags |= NPIF_LISTEN;
665 }
a39ff7e2
A
666 } else if (SOCK_PROTO(so) == IPPROTO_UDP) {
667 npi.npi_flags |= NPIF_UDP;
668 } else {
669 panic("%s: unexpected protocol %u for inp %p\n", __func__,
670 SOCK_PROTO(inp->inp_socket), inp);
671 }
672
673 uuid_copy(npi.npi_flow_uuid, inp->necp_client_uuid);
674
675 npi.npi_local_port = inp->inp_lport;
676 npi.npi_foreign_port = inp->inp_fport;
677
94ff46dc
A
678 /*
679 * Take in account IPv4 addresses mapped on IPv6
680 */
681 if ((inp->inp_vflag & INP_IPV6) != 0 && (inp->inp_flags & IN6P_IPV6_V6ONLY) == 0 &&
682 (inp->inp_vflag & (INP_IPV6 | INP_IPV4)) == (INP_IPV6 | INP_IPV4)) {
683 npi.npi_flags |= NPIF_IPV6 | NPIF_IPV4;
684 memcpy(&npi.npi_local_addr_in6,
685 &inp->in6p_laddr, sizeof(struct in6_addr));
686 } else if (inp->inp_vflag & INP_IPV4) {
a39ff7e2
A
687 npi.npi_flags |= NPIF_IPV4;
688 npi.npi_local_addr_in = inp->inp_laddr;
689 npi.npi_foreign_addr_in = inp->inp_faddr;
690 } else {
691 npi.npi_flags |= NPIF_IPV6;
692 memcpy(&npi.npi_local_addr_in6,
0a7de745 693 &inp->in6p_laddr, sizeof(struct in6_addr));
a39ff7e2 694 memcpy(&npi.npi_foreign_addr_in6,
0a7de745 695 &inp->in6p_faddr, sizeof(struct in6_addr));
f427ee49
A
696
697 /* Clear the embedded scope ID */
698 if (IN6_IS_ADDR_LINKLOCAL(&npi.npi_local_addr_in6)) {
699 npi.npi_local_addr_in6.s6_addr16[1] = 0;
700 }
701 if (IN6_IS_ADDR_LINKLOCAL(&npi.npi_foreign_addr_in6)) {
702 npi.npi_foreign_addr_in6.s6_addr16[1] = 0;
703 }
a39ff7e2
A
704 }
705
706 npi.npi_owner_pid = so->last_pid;
707
708 if (so->last_pid != 0) {
709 proc_name(so->last_pid, npi.npi_owner_pname,
710 sizeof(npi.npi_owner_pname));
711 }
712
713 if (so->so_flags & SOF_DELEGATED) {
714 npi.npi_flags |= NPIF_DELEGATED;
715 npi.npi_effective_pid = so->e_pid;
716 if (so->e_pid != 0) {
717 proc_name(so->e_pid, npi.npi_effective_pname,
718 sizeof(npi.npi_effective_pname));
719 }
720 } else {
721 npi.npi_effective_pid = so->last_pid;
722 if (so->last_pid != 0) {
723 strlcpy(npi.npi_effective_pname, npi.npi_owner_pname,
724 sizeof(npi.npi_effective_pname));
725 }
726 }
727
728 (void) net_port_info_add_entry(&npi);
729}
730