* Copyright 2023-2025, Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include <netinet/in.h>
#include <sys/socket.h>
#include "strace.h"
#include "Syscall.h"
#include "TypeHandler.h"
struct enum_info {
int index;
const char *name;
};
#define ENUM_INFO_ENTRY(name) \
{ name, #name }
#define FLAG_INFO_ENTRY(name) \
{ name, #name }
static const FlagsTypeHandler::FlagInfo kRecvFlagInfos[] = {
FLAG_INFO_ENTRY(MSG_PEEK),
FLAG_INFO_ENTRY(MSG_OOB),
FLAG_INFO_ENTRY(MSG_DONTROUTE),
FLAG_INFO_ENTRY(MSG_EOR),
FLAG_INFO_ENTRY(MSG_TRUNC),
FLAG_INFO_ENTRY(MSG_CTRUNC),
FLAG_INFO_ENTRY(MSG_WAITALL),
FLAG_INFO_ENTRY(MSG_DONTWAIT),
FLAG_INFO_ENTRY(MSG_BCAST),
FLAG_INFO_ENTRY(MSG_MCAST),
FLAG_INFO_ENTRY(MSG_EOF),
FLAG_INFO_ENTRY(MSG_NOSIGNAL),
FLAG_INFO_ENTRY(MSG_CMSG_CLOEXEC),
FLAG_INFO_ENTRY(MSG_CMSG_CLOFORK),
{ 0, NULL }
};
static const enum_info kSocketFamily[] = {
ENUM_INFO_ENTRY(AF_UNSPEC),
ENUM_INFO_ENTRY(AF_INET),
ENUM_INFO_ENTRY(AF_APPLETALK),
ENUM_INFO_ENTRY(AF_ROUTE),
ENUM_INFO_ENTRY(AF_LINK),
ENUM_INFO_ENTRY(AF_INET6),
ENUM_INFO_ENTRY(AF_DLI),
ENUM_INFO_ENTRY(AF_IPX),
ENUM_INFO_ENTRY(AF_NOTIFY),
ENUM_INFO_ENTRY(AF_UNIX),
ENUM_INFO_ENTRY(AF_BLUETOOTH),
{ 0, NULL }
};
static const enum_info kSocketType[] = {
ENUM_INFO_ENTRY(SOCK_STREAM),
ENUM_INFO_ENTRY(SOCK_DGRAM),
ENUM_INFO_ENTRY(SOCK_RAW),
ENUM_INFO_ENTRY(SOCK_SEQPACKET),
ENUM_INFO_ENTRY(SOCK_MISC),
{ 0, NULL }
};
static const enum_info kShutdownHow[] = {
ENUM_INFO_ENTRY(SHUT_RD),
ENUM_INFO_ENTRY(SHUT_WR),
ENUM_INFO_ENTRY(SHUT_RDWR),
{ 0, NULL }
};
static const FlagsTypeHandler::FlagInfo kSocketFlagInfos[] = {
FLAG_INFO_ENTRY(SOCK_NONBLOCK),
FLAG_INFO_ENTRY(SOCK_CLOEXEC),
FLAG_INFO_ENTRY(SOCK_CLOFORK),
{ 0, NULL }
};
static const enum_info kProtocolLevels[] = {
ENUM_INFO_ENTRY(SOL_SOCKET),
ENUM_INFO_ENTRY(IPPROTO_IP),
ENUM_INFO_ENTRY(IPPROTO_IPV6),
{ 0, NULL }
};
struct socket_option_info {
int level;
int option;
const char *name;
TypeHandler *handler;
int length;
};
#define SOCKET_OPTION_INFO_ENTRY(level, option) \
{ level, option, #option, NULL, 0 }
#define SOCKET_OPTION_INFO_ENTRY_TYPE(level, option, type) \
{ level, option, #option, TypeHandlerFactory<type *>::Create(), sizeof(type) }
static const socket_option_info kSocketOptions[] = {
SOCKET_OPTION_INFO_ENTRY(SOL_SOCKET, SO_ACCEPTCONN),
SOCKET_OPTION_INFO_ENTRY_TYPE(SOL_SOCKET, SO_BROADCAST, int32),
SOCKET_OPTION_INFO_ENTRY_TYPE(SOL_SOCKET, SO_DEBUG, int32),
SOCKET_OPTION_INFO_ENTRY_TYPE(SOL_SOCKET, SO_DONTROUTE, int32),
SOCKET_OPTION_INFO_ENTRY_TYPE(SOL_SOCKET, SO_KEEPALIVE, int32),
SOCKET_OPTION_INFO_ENTRY_TYPE(SOL_SOCKET, SO_OOBINLINE, int32),
SOCKET_OPTION_INFO_ENTRY_TYPE(SOL_SOCKET, SO_REUSEADDR, int32),
SOCKET_OPTION_INFO_ENTRY_TYPE(SOL_SOCKET, SO_REUSEPORT, int32),
SOCKET_OPTION_INFO_ENTRY_TYPE(SOL_SOCKET, SO_USELOOPBACK, int32),
SOCKET_OPTION_INFO_ENTRY(SOL_SOCKET, SO_LINGER),
SOCKET_OPTION_INFO_ENTRY_TYPE(SOL_SOCKET, SO_SNDBUF, uint32),
SOCKET_OPTION_INFO_ENTRY(SOL_SOCKET, SO_SNDLOWAT),
SOCKET_OPTION_INFO_ENTRY(SOL_SOCKET, SO_SNDTIMEO),
SOCKET_OPTION_INFO_ENTRY_TYPE(SOL_SOCKET, SO_RCVBUF, uint32),
SOCKET_OPTION_INFO_ENTRY(SOL_SOCKET, SO_RCVLOWAT),
SOCKET_OPTION_INFO_ENTRY(SOL_SOCKET, SO_RCVTIMEO),
SOCKET_OPTION_INFO_ENTRY(SOL_SOCKET, SO_ERROR),
SOCKET_OPTION_INFO_ENTRY(SOL_SOCKET, SO_TYPE),
SOCKET_OPTION_INFO_ENTRY_TYPE(SOL_SOCKET, SO_NONBLOCK, int32),
SOCKET_OPTION_INFO_ENTRY(SOL_SOCKET, SO_BINDTODEVICE),
SOCKET_OPTION_INFO_ENTRY_TYPE(SOL_SOCKET, SO_PEERCRED, struct ucred),
SOCKET_OPTION_INFO_ENTRY(IPPROTO_IP, IP_OPTIONS),
SOCKET_OPTION_INFO_ENTRY_TYPE(IPPROTO_IP, IP_HDRINCL, int),
SOCKET_OPTION_INFO_ENTRY_TYPE(IPPROTO_IP, IP_TOS, int),
SOCKET_OPTION_INFO_ENTRY_TYPE(IPPROTO_IP, IP_TTL, int),
SOCKET_OPTION_INFO_ENTRY(IPPROTO_IP, IP_RECVOPTS),
SOCKET_OPTION_INFO_ENTRY(IPPROTO_IP, IP_RECVRETOPTS),
SOCKET_OPTION_INFO_ENTRY(IPPROTO_IP, IP_RECVDSTADDR),
SOCKET_OPTION_INFO_ENTRY(IPPROTO_IP, IP_RETOPTS),
SOCKET_OPTION_INFO_ENTRY(IPPROTO_IP, IP_MULTICAST_IF),
SOCKET_OPTION_INFO_ENTRY(IPPROTO_IP, IP_MULTICAST_TTL),
SOCKET_OPTION_INFO_ENTRY(IPPROTO_IP, IP_MULTICAST_LOOP),
SOCKET_OPTION_INFO_ENTRY(IPPROTO_IP, IP_ADD_MEMBERSHIP),
SOCKET_OPTION_INFO_ENTRY(IPPROTO_IP, IP_DROP_MEMBERSHIP),
SOCKET_OPTION_INFO_ENTRY(IPPROTO_IP, IP_BLOCK_SOURCE),
SOCKET_OPTION_INFO_ENTRY(IPPROTO_IP, IP_UNBLOCK_SOURCE),
SOCKET_OPTION_INFO_ENTRY(IPPROTO_IP, IP_ADD_SOURCE_MEMBERSHIP),
SOCKET_OPTION_INFO_ENTRY(IPPROTO_IP, IP_DROP_SOURCE_MEMBERSHIP),
SOCKET_OPTION_INFO_ENTRY(IPPROTO_IP, MCAST_JOIN_GROUP),
SOCKET_OPTION_INFO_ENTRY(IPPROTO_IP, MCAST_BLOCK_SOURCE),
SOCKET_OPTION_INFO_ENTRY(IPPROTO_IP, MCAST_UNBLOCK_SOURCE),
SOCKET_OPTION_INFO_ENTRY(IPPROTO_IP, MCAST_LEAVE_GROUP),
SOCKET_OPTION_INFO_ENTRY(IPPROTO_IP, MCAST_JOIN_SOURCE_GROUP),
SOCKET_OPTION_INFO_ENTRY(IPPROTO_IP, MCAST_LEAVE_SOURCE_GROUP),
SOCKET_OPTION_INFO_ENTRY(IPPROTO_IP, IP_DONTFRAG),
SOCKET_OPTION_INFO_ENTRY(IPPROTO_IPV6, IPV6_MULTICAST_IF),
SOCKET_OPTION_INFO_ENTRY(IPPROTO_IPV6, IPV6_MULTICAST_HOPS),
SOCKET_OPTION_INFO_ENTRY(IPPROTO_IPV6, IPV6_MULTICAST_LOOP),
SOCKET_OPTION_INFO_ENTRY(IPPROTO_IPV6, IPV6_UNICAST_HOPS),
SOCKET_OPTION_INFO_ENTRY(IPPROTO_IPV6, IPV6_JOIN_GROUP),
SOCKET_OPTION_INFO_ENTRY(IPPROTO_IPV6, IPV6_LEAVE_GROUP),
SOCKET_OPTION_INFO_ENTRY(IPPROTO_IPV6, IPV6_V6ONLY),
SOCKET_OPTION_INFO_ENTRY(IPPROTO_IPV6, IPV6_PKTINFO),
SOCKET_OPTION_INFO_ENTRY(IPPROTO_IPV6, IPV6_RECVPKTINFO),
SOCKET_OPTION_INFO_ENTRY(IPPROTO_IPV6, IPV6_HOPLIMIT),
SOCKET_OPTION_INFO_ENTRY(IPPROTO_IPV6, IPV6_RECVHOPLIMIT),
SOCKET_OPTION_INFO_ENTRY(IPPROTO_IPV6, IPV6_HOPOPTS),
SOCKET_OPTION_INFO_ENTRY(IPPROTO_IPV6, IPV6_DSTOPTS),
SOCKET_OPTION_INFO_ENTRY(IPPROTO_IPV6, IPV6_RTHDR),
{ -1, -1, NULL, NULL }
};
static FlagsTypeHandler::FlagsList kRecvFlags;
static EnumTypeHandler::EnumMap kSocketFamilyMap;
static EnumTypeHandler::EnumMap kSocketTypeMap;
static EnumTypeHandler::EnumMap kShutdownHowMap;
static FlagsTypeHandler::FlagsList kSocketFlags;
static EnumTypeHandler::EnumMap kProtocolLevelMap;
static TypeHandlerSelector::SelectMap kLevelTypeHandlers;
static EnumTypeHandler::EnumMap kSocketLevelOptionMap;
static EnumTypeHandler::EnumMap kIPProtoLevelOptionMap;
static EnumTypeHandler::EnumMap kIPv6ProtoLevelOptionMap;
static TypeHandlerSelector::SelectMap kSocketLevelOptionTypeHandlers;
static TypeHandlerSelector::SelectMap kIPProtoLevelOptionTypeHandlers;
static TypeHandlerSelector::SelectMap kIPv6ProtoLevelOptionTypeHandlers;
static TypeHandlerSelector::SelectMap kLevelOptionTypeHandlers;
void
patch_network()
{
for (int i = 0; kRecvFlagInfos[i].name != NULL; i++) {
kRecvFlags.push_back(kRecvFlagInfos[i]);
}
for (int i = 0; kSocketFamily[i].name != NULL; i++) {
kSocketFamilyMap[kSocketFamily[i].index] = kSocketFamily[i].name;
}
for (int i = 0; kSocketType[i].name != NULL; i++) {
kSocketTypeMap[kSocketType[i].index] = kSocketType[i].name;
}
for (int i = 0; kShutdownHow[i].name != NULL; i++) {
kShutdownHowMap[kShutdownHow[i].index] = kShutdownHow[i].name;
}
for (int i = 0; kSocketFlagInfos[i].name != NULL; i++) {
kSocketFlags.push_back(kSocketFlagInfos[i]);
}
for (int i = 0; kProtocolLevels[i].name != NULL; i++) {
kProtocolLevelMap[kProtocolLevels[i].index] = kProtocolLevels[i].name;
}
for (int i = 0; kSocketOptions[i].name != NULL; i++) {
EnumTypeHandler::EnumMap* map = NULL;
TypeHandlerSelector::SelectMap* selectMap = NULL;
if (kSocketOptions[i].level == SOL_SOCKET) {
map = &kSocketLevelOptionMap;
selectMap = &kSocketLevelOptionTypeHandlers;
} else if (kSocketOptions[i].level == IPPROTO_IP) {
map = &kIPProtoLevelOptionMap;
selectMap = &kIPProtoLevelOptionTypeHandlers;
} else if (kSocketOptions[i].level == IPPROTO_IPV6) {
map = &kIPv6ProtoLevelOptionMap;
selectMap = &kIPv6ProtoLevelOptionTypeHandlers;
}
if (map != NULL) {
(*map)[kSocketOptions[i].option] = kSocketOptions[i].name;
if (kSocketOptions[i].handler == NULL)
continue;
(*selectMap)[kSocketOptions[i].option] = kSocketOptions[i].handler;
}
}
kLevelTypeHandlers[SOL_SOCKET] = new EnumTypeHandler(kSocketLevelOptionMap);
kLevelOptionTypeHandlers[SOL_SOCKET] = new TypeHandlerSelector(
kSocketLevelOptionTypeHandlers, 2, TypeHandlerFactory<void *>::Create());
kLevelOptionTypeHandlers[IPPROTO_IP] = new TypeHandlerSelector(
kIPProtoLevelOptionTypeHandlers, 2, TypeHandlerFactory<void *>::Create());
kLevelOptionTypeHandlers[IPPROTO_IPV6] = new TypeHandlerSelector(
kIPv6ProtoLevelOptionTypeHandlers, 2, TypeHandlerFactory<void *>::Create());
Syscall *recv = get_syscall("_kern_recv");
recv->GetParameter("flags")->SetHandler(new FlagsTypeHandler(kRecvFlags));
Syscall *recvfrom = get_syscall("_kern_recvfrom");
recvfrom->GetParameter("flags")->SetHandler(new FlagsTypeHandler(kRecvFlags));
Syscall *recvmsg = get_syscall("_kern_recvmsg");
recvmsg->GetParameter("flags")->SetHandler(new FlagsTypeHandler(kRecvFlags));
Syscall *send = get_syscall("_kern_send");
send->GetParameter("flags")->SetHandler(new FlagsTypeHandler(kRecvFlags));
Syscall *sendmsg = get_syscall("_kern_sendmsg");
sendmsg->GetParameter("flags")->SetHandler(new FlagsTypeHandler(kRecvFlags));
Syscall *sendto = get_syscall("_kern_sendto");
sendto->GetParameter("flags")->SetHandler(new FlagsTypeHandler(kRecvFlags));
Syscall *socket = get_syscall("_kern_socket");
socket->GetParameter("family")->SetHandler(
new EnumTypeHandler(kSocketFamilyMap));
socket->GetParameter("type")->SetHandler(
new EnumFlagsTypeHandler(kSocketTypeMap, kSocketFlags));
Syscall *shutdown = get_syscall("_kern_shutdown_socket");
shutdown->GetParameter("how")->SetHandler(
new EnumTypeHandler(kShutdownHowMap));
Syscall *socketPair = get_syscall("_kern_socketpair");
socketPair->ParameterAt(3)->SetOut(true);
socketPair->ParameterAt(3)->SetCount(2);
socketPair->GetParameter("family")->SetHandler(
new EnumTypeHandler(kSocketFamilyMap));
socketPair->GetParameter("type")->SetHandler(
new EnumFlagsTypeHandler(kSocketTypeMap, kSocketFlags));
Syscall *accept = get_syscall("_kern_accept");
accept->GetParameter("flags")->SetHandler(new FlagsTypeHandler(kSocketFlags));
Syscall *getsockopt = get_syscall("_kern_getsockopt");
getsockopt->GetParameter("level")->SetHandler(new EnumTypeHandler(kProtocolLevelMap));
getsockopt->GetParameter("option")->SetHandler(
new TypeHandlerSelector(kLevelTypeHandlers, 1, TypeHandlerFactory<void *>::Create()));
getsockopt->GetParameter("value")->SetHandler(
new TypeHandlerSelector(kLevelOptionTypeHandlers, 1, TypeHandlerFactory<void *>::Create()));
getsockopt->GetParameter("value")->SetOut(true);
Syscall *setsockopt = get_syscall("_kern_setsockopt");
setsockopt->GetParameter("level")->SetHandler(new EnumTypeHandler(kProtocolLevelMap));
setsockopt->GetParameter("option")->SetHandler(
new TypeHandlerSelector(kLevelTypeHandlers, 1, TypeHandlerFactory<void *>::Create()));
setsockopt->GetParameter("value")->SetHandler(
new TypeHandlerSelector(kLevelOptionTypeHandlers, 1, TypeHandlerFactory<void *>::Create()));
}