/*
- * Copyright (c) 2017-2018 Apple Inc. All rights reserved.
+ * Copyright (c) 2017-2020 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
#include <net/if_ports_used.h>
#include <netinet/in_pcb.h>
+#include <netinet/tcp_var.h>
+#include <netinet/tcp_fsm.h>
#include <stdbool.h>
SYSCTL_NODE(_net_link_generic_system, OID_AUTO, port_used,
CTLFLAG_RW | CTLFLAG_LOCKED, 0, "if port used");
-static uuid_t current_wakeuuid;
+static uuid_t current_wakeuuid;
SYSCTL_OPAQUE(_net_link_generic_system_port_used, OID_AUTO, current_wakeuuid,
- CTLFLAG_RD|CTLFLAG_LOCKED,
+ CTLFLAG_RD | CTLFLAG_LOCKED,
current_wakeuuid, sizeof(uuid_t), "S,uuid_t", "");
static int sysctl_net_port_info_list SYSCTL_HANDLER_ARGS;
static int use_test_wakeuuid = 0;
static uuid_t test_wakeuuid;
+static uuid_string_t test_wakeuuid_str;
#if (DEVELOPMENT || DEBUG)
SYSCTL_INT(_net_link_generic_system_port_used, OID_AUTO, use_test_wakeuuid,
CTLTYPE_STRUCT | CTLFLAG_RW | CTLFLAG_LOCKED, 0, 0,
sysctl_clear_test_wakeuuid, "S,uuid_t", "");
+int sysctl_test_wakeuuid_str SYSCTL_HANDLER_ARGS;
+SYSCTL_PROC(_net_link_generic_system_port_used, OID_AUTO, test_wakeuuid_str,
+ CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_LOCKED, 0, 0,
+ sysctl_test_wakeuuid_str, "A", "");
+
SYSCTL_OPAQUE(_net_link_generic_system_port_used, OID_AUTO, test_wakeuuid,
- CTLFLAG_RD|CTLFLAG_LOCKED,
+ CTLFLAG_RD | CTLFLAG_LOCKED,
test_wakeuuid, sizeof(uuid_t), "S,uuid_t", "");
#endif /* (DEVELOPMENT || DEBUG) */
wakeuuid_not_set_last_time, CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_LOCKED,
0, 0, sysctl_wakeuuid_not_set_last_time, "S,timeval", "");
-char wakeuuid_not_set_last_if [IFXNAMSIZ];
+char wakeuuid_not_set_last_if[IFXNAMSIZ];
int sysctl_wakeuuid_not_set_last_if SYSCTL_HANDLER_ARGS;
static SYSCTL_PROC(_net_link_generic_system_port_used, OID_AUTO,
wakeuuid_not_set_last_if, CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_LOCKED,
static lck_grp_t *net_port_entry_head_lock_group;
struct net_port_entry {
- SLIST_ENTRY(net_port_entry) npe_next;
- struct net_port_info npe_npi;
+ SLIST_ENTRY(net_port_entry) npe_next;
+ struct net_port_info npe_npi;
};
-static struct zone *net_port_entry_zone = NULL;
-
-#define NET_PORT_ENTRY_ZONE_MAX 128
-#define NET_PORT_ENTRY_ZONE_NAME "net_port_entry"
+static ZONE_DECLARE(net_port_entry_zone, "net_port_entry",
+ sizeof(struct net_port_entry), ZC_NONE);
static SLIST_HEAD(net_port_entry_list, net_port_entry) net_port_entry_list =
SLIST_HEAD_INITIALIZER(&net_port_entry_list);
lck_grp_attributes = lck_grp_attr_alloc_init();
net_port_entry_head_lock_group = lck_grp_alloc_init(
- "net port entry lock", lck_grp_attributes);
+ "net port entry lock", lck_grp_attributes);
lck_attributes = lck_attr_alloc_init();
if (lck_attributes == NULL) {
lck_attributes);
net_port_entry_count = 0;
- net_port_entry_zone = zinit(sizeof(struct net_port_entry),
- NET_PORT_ENTRY_ZONE_MAX * sizeof(struct net_port_entry),
- 0, NET_PORT_ENTRY_ZONE_NAME);
- if (net_port_entry_zone == NULL) {
- panic("%s: zinit(%s) failed", __func__,
- NET_PORT_ENTRY_ZONE_NAME);
- }
- zone_change(net_port_entry_zone, Z_EXPAND, TRUE);
- zone_change(net_port_entry_zone, Z_CALLERACCT, FALSE);
-
if_ports_used_inited = 1;
lck_attr_free(lck_attributes);
}
static bool
-get_test_wake_uuid(uuid_t wakeuuid)
+get_test_wake_uuid(uuid_string_t wakeuuid_str, size_t len)
{
if (__improbable(use_test_wakeuuid)) {
if (!uuid_is_null(test_wakeuuid)) {
- if (wakeuuid != NULL) {
- uuid_copy(wakeuuid, test_wakeuuid);
+ if (wakeuuid_str != NULL && len != 0) {
+ uuid_unparse(test_wakeuuid, wakeuuid_str);
+ }
+ return true;
+ } else if (strlen(test_wakeuuid_str) != 0) {
+ if (wakeuuid_str != NULL && len != 0) {
+ strlcpy(wakeuuid_str, test_wakeuuid_str, len);
}
- return (true);
+ return true;
} else {
- return (false);
+ return false;
}
} else {
- return (false);
+ return false;
}
}
* IOPMCopySleepWakeUUIDKey() tells if SleepWakeUUID is currently set
* That means we are currently in a sleep/wake cycle
*/
- return (get_test_wake_uuid(NULL) || IOPMCopySleepWakeUUIDKey(NULL, 0));
+ return get_test_wake_uuid(NULL, 0) || IOPMCopySleepWakeUUIDKey(NULL, 0);
}
void
uuid_t wakeuuid;
bool wakeuuid_is_set = false;
bool updated = false;
+ uuid_string_t wakeuuid_str;
+
+ uuid_clear(wakeuuid);
if (__improbable(use_test_wakeuuid)) {
- wakeuuid_is_set = get_test_wake_uuid(wakeuuid);
+ wakeuuid_is_set = get_test_wake_uuid(wakeuuid_str,
+ sizeof(wakeuuid_str));
} else {
- uuid_string_t wakeuuid_str;
-
wakeuuid_is_set = IOPMCopySleepWakeUUIDKey(wakeuuid_str,
sizeof(wakeuuid_str));
- if (wakeuuid_is_set) {
- uuid_parse(wakeuuid_str, wakeuuid);
+ }
+
+ if (wakeuuid_is_set) {
+ if (uuid_parse(wakeuuid_str, wakeuuid) != 0) {
+ os_log(OS_LOG_DEFAULT,
+ "%s: IOPMCopySleepWakeUUIDKey got bad value %s\n",
+ __func__, wakeuuid_str);
+ wakeuuid_is_set = false;
}
}
microtime(&wakeuuid_not_set_last_time);
strlcpy(wakeuuid_not_set_last_if, if_name(ifp),
sizeof(wakeuuid_not_set_last_if));
- }
+ }
return;
}
uuid_copy(current_wakeuuid, wakeuuid);
updated = true;
}
- /*
+ /*
* Record the time last checked
*/
microuptime(&wakeuiid_last_check);
x->npi_effective_pid == y->npi_effective_pid &&
x->npi_flags == y->npi_flags &&
memcmp(&x->npi_local_addr_, &y->npi_local_addr_,
- sizeof(union in_addr_4_6)) == 0 &&
+ sizeof(union in_addr_4_6)) == 0 &&
memcmp(&x->npi_foreign_addr_, &y->npi_foreign_addr_,
- sizeof(union in_addr_4_6)) == 0) {
- return (true);
+ sizeof(union in_addr_4_6)) == 0) {
+ return true;
}
- return (false);
+ return false;
}
static bool
SLIST_FOREACH(npe, &net_port_entry_list, npe_next) {
if (net_port_info_equal(&npe->npe_npi, npi)) {
- return (true);
+ return true;
}
}
- return (false);
+ return false;
}
static bool
net_port_info_add_entry(const struct net_port_info *npi)
{
- struct net_port_entry *npe = NULL;
+ struct net_port_entry *npe = NULL;
uint32_t num = 0;
bool entry_added = false;
if (__improbable(is_wakeuuid_set() == false)) {
if (if_ports_used_verbose > 0) {
- log(LOG_ERR, "%s: wakeuuid not set %u not adding "
+ log(LOG_ERR, "%s: wakeuuid not set not adding "
"port: %u flags: 0x%xif: %u pid: %u epid %u\n",
__func__,
ntohs(npi->npi_local_port),
npi->npi_owner_pid,
npi->npi_effective_pid);
}
- return (0);
+ return 0;
}
npe = zalloc(net_port_entry_zone);
npi->npi_if_index,
npi->npi_owner_pid,
npi->npi_effective_pid);
- return (0);
+ return 0;
}
bzero(npe, sizeof(struct net_port_entry));
zfree(net_port_entry_zone, npe);
npe = NULL;
}
- return (entry_added);
+ return entry_added;
}
#if (DEVELOPMENT || DEBUG)
int error = 0;
if (kauth_cred_issuser(kauth_cred_get()) == 0) {
- return (EPERM);
+ return EPERM;
}
if (req->oldptr == USER_ADDR_NULL) {
req->oldidx = sizeof(uuid_t);
- return (0);
+ return 0;
}
if (req->newptr != USER_ADDR_NULL) {
uuid_generate(test_wakeuuid);
error = SYSCTL_OUT(req, test_wakeuuid,
MIN(sizeof(uuid_t), req->oldlen));
- return (error);
+ return error;
}
int
int error = 0;
if (kauth_cred_issuser(kauth_cred_get()) == 0) {
- return (EPERM);
+ return EPERM;
}
if (req->oldptr == USER_ADDR_NULL) {
req->oldidx = sizeof(uuid_t);
- return (0);
+ return 0;
}
if (req->newptr != USER_ADDR_NULL) {
uuid_clear(test_wakeuuid);
error = SYSCTL_OUT(req, test_wakeuuid,
MIN(sizeof(uuid_t), req->oldlen));
- return (error);
+ return error;
+}
+
+int
+sysctl_test_wakeuuid_str SYSCTL_HANDLER_ARGS
+{
+#pragma unused(oidp, arg1, arg2)
+ int error = 0;
+ int changed;
+
+ if (kauth_cred_issuser(kauth_cred_get()) == 0) {
+ return EPERM;
+ }
+ error = sysctl_io_string(req, test_wakeuuid_str, sizeof(test_wakeuuid_str), 1, &changed);
+ if (changed) {
+ os_log_info(OS_LOG_DEFAULT, "%s: test_wakeuuid_str %s",
+ __func__, test_wakeuuid_str);
+ }
+
+ return error;
}
#endif /* (DEVELOPMENT || DEBUG) */
} else {
struct user32_timeval tv = {};
- tv.tv_sec = wakeuuid_not_set_last_time.tv_sec;
+ tv.tv_sec = (user32_time_t)wakeuuid_not_set_last_time.tv_sec;
tv.tv_usec = wakeuuid_not_set_last_time.tv_usec;
return SYSCTL_OUT(req, &tv, sizeof(tv));
}
#pragma unused(oidp, arg1, arg2)
return SYSCTL_OUT(req, &wakeuuid_not_set_last_if,
- strlen(wakeuuid_not_set_last_if) + 1);
+ strlen(wakeuuid_not_set_last_if) + 1);
}
static int
if ((error = priv_check_cred(kauth_cred_get(),
PRIV_NET_PRIVILEGED_NETWORK_STATISTICS, 0)) != 0) {
- return (EPERM);
+ return EPERM;
}
lck_mtx_lock(&net_port_entry_head_lock);
uint32_t cnt = net_port_entry_count;
cnt += cnt >> 4;
req->oldidx = sizeof(struct xnpigen) +
- cnt * sizeof(struct net_port_info);
+ cnt * sizeof(struct net_port_info);
goto done;
}
uuid_copy(xnpigen.xng_wakeuuid, current_wakeuuid);
xnpigen.xng_npi_count = net_port_entry_count;
xnpigen.xng_npi_size = sizeof(struct net_port_info);
- error = SYSCTL_OUT(req, &xnpigen, sizeof (xnpigen));
+ error = SYSCTL_OUT(req, &xnpigen, sizeof(xnpigen));
if (error != 0) {
printf("%s: SYSCTL_OUT(xnpigen) error %d\n",
__func__, error);
done:
lck_mtx_unlock(&net_port_entry_head_lock);
- return (error);
+ return error;
}
/*
}
error = SYSCTL_OUT(req, bitfield, bitstr_size(IP_PORTRANGE_SIZE));
done:
- if (bitfield != NULL)
+ if (bitfield != NULL) {
_FREE(bitfield, M_TEMP);
- return (error);
+ }
+ return error;
}
__private_extern__ void
bzero(&npi, sizeof(struct net_port_info));
- npi.npi_if_index = ifindex;
+ /* This is unlikely to happen but better be safe than sorry */
+ if (ifindex > UINT16_MAX) {
+ os_log(OS_LOG_DEFAULT, "%s: ifindex %u too big\n", __func__, ifindex);
+ return;
+ }
+ npi.npi_if_index = (uint16_t)ifindex;
npi.npi_flags |= NPIF_SOCKET;
- npi.npi_timestamp.tv_sec = wakeuiid_last_check.tv_sec;
+ npi.npi_timestamp.tv_sec = (int32_t)wakeuiid_last_check.tv_sec;
npi.npi_timestamp.tv_usec = wakeuiid_last_check.tv_usec;
if (SOCK_PROTO(so) == IPPROTO_TCP) {
+ struct tcpcb *tp = intotcpcb(inp);
+
npi.npi_flags |= NPIF_TCP;
+ if (tp != NULL && tp->t_state == TCPS_LISTEN) {
+ npi.npi_flags |= NPIF_LISTEN;
+ }
} else if (SOCK_PROTO(so) == IPPROTO_UDP) {
npi.npi_flags |= NPIF_UDP;
} else {
npi.npi_local_port = inp->inp_lport;
npi.npi_foreign_port = inp->inp_fport;
- if (inp->inp_vflag & INP_IPV4) {
+ /*
+ * Take in account IPv4 addresses mapped on IPv6
+ */
+ if ((inp->inp_vflag & INP_IPV6) != 0 && (inp->inp_flags & IN6P_IPV6_V6ONLY) == 0 &&
+ (inp->inp_vflag & (INP_IPV6 | INP_IPV4)) == (INP_IPV6 | INP_IPV4)) {
+ npi.npi_flags |= NPIF_IPV6 | NPIF_IPV4;
+ memcpy(&npi.npi_local_addr_in6,
+ &inp->in6p_laddr, sizeof(struct in6_addr));
+ } else if (inp->inp_vflag & INP_IPV4) {
npi.npi_flags |= NPIF_IPV4;
npi.npi_local_addr_in = inp->inp_laddr;
npi.npi_foreign_addr_in = inp->inp_faddr;
} else {
npi.npi_flags |= NPIF_IPV6;
memcpy(&npi.npi_local_addr_in6,
- &inp->in6p_laddr, sizeof (struct in6_addr));
+ &inp->in6p_laddr, sizeof(struct in6_addr));
memcpy(&npi.npi_foreign_addr_in6,
- &inp->in6p_faddr, sizeof (struct in6_addr));
+ &inp->in6p_faddr, sizeof(struct in6_addr));
+
+ /* Clear the embedded scope ID */
+ if (IN6_IS_ADDR_LINKLOCAL(&npi.npi_local_addr_in6)) {
+ npi.npi_local_addr_in6.s6_addr16[1] = 0;
+ }
+ if (IN6_IS_ADDR_LINKLOCAL(&npi.npi_foreign_addr_in6)) {
+ npi.npi_foreign_addr_in6.s6_addr16[1] = 0;
+ }
}
npi.npi_owner_pid = so->last_pid;