1 // Copyright 2017 Dolphin Emulator Project
2 // Licensed under GPLv2+
3 // Refer to the license.txt file included.
4
5 #include "Core/IOS/Network/IP/Top.h"
6
7 #include <algorithm>
8 #include <cstddef>
9 #include <cstring>
10 #include <memory>
11 #include <optional>
12 #include <string>
13 #include <utility>
14 #include <vector>
15
16 #ifndef _WIN32
17 #include <netdb.h>
18 #include <poll.h>
19 #endif
20
21 #include <fmt/format.h>
22
23 #include "Common/Assert.h"
24 #include "Common/CommonTypes.h"
25 #include "Common/Logging/Log.h"
26 #include "Common/Network.h"
27 #include "Common/ScopeGuard.h"
28 #include "Common/StringUtil.h"
29
30 #include "Core/Core.h"
31 #include "Core/HW/Memmap.h"
32 #include "Core/IOS/Network/ICMP.h"
33 #include "Core/IOS/Network/MACUtils.h"
34 #include "Core/IOS/Network/Socket.h"
35
36 #ifdef _WIN32
37 #include <iphlpapi.h>
38 #include <ws2tcpip.h>
39
40 #define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x))
41 #define FREE(x) HeapFree(GetProcessHeap(), 0, (x))
42
43 #else
44 #include <arpa/inet.h>
45 #include <ifaddrs.h>
46 #include <netinet/in.h>
47 #include <resolv.h>
48 #include <sys/socket.h>
49 #include <sys/types.h>
50 #include <unistd.h>
51 #endif
52
53 namespace IOS::HLE::Device
54 {
55 enum SOResultCode : s32
56 {
57 SO_ERROR_INVALID_REQUEST = -51,
58 SO_ERROR_HOST_NOT_FOUND = -305,
59 };
60
NetIPTop(Kernel & ios,const std::string & device_name)61 NetIPTop::NetIPTop(Kernel& ios, const std::string& device_name) : Device(ios, device_name)
62 {
63 #ifdef _WIN32
64 int ret = WSAStartup(MAKEWORD(2, 2), &InitData);
65 INFO_LOG(IOS_NET, "WSAStartup: %d", ret);
66 #endif
67 }
68
~NetIPTop()69 NetIPTop::~NetIPTop()
70 {
71 #ifdef _WIN32
72 WSACleanup();
73 #endif
74 }
75
DoState(PointerWrap & p)76 void NetIPTop::DoState(PointerWrap& p)
77 {
78 DoStateShared(p);
79 WiiSockMan::GetInstance().DoState(p);
80 }
81
inet_addr(u8 a,u8 b,u8 c,u8 d)82 static constexpr u32 inet_addr(u8 a, u8 b, u8 c, u8 d)
83 {
84 return (static_cast<u32>(a) << 24) | (static_cast<u32>(b) << 16) | (static_cast<u32>(c) << 8) | d;
85 }
86
inet_pton(const char * src,unsigned char * dst)87 static int inet_pton(const char* src, unsigned char* dst)
88 {
89 int saw_digit = 0;
90 int octets = 0;
91 unsigned char tmp[4]{};
92 unsigned char* tp = tmp;
93 char ch;
94
95 while ((ch = *src++) != '\0')
96 {
97 if (ch >= '0' && ch <= '9')
98 {
99 unsigned int newt = (*tp * 10) + (ch - '0');
100
101 if (newt > 255)
102 return 0;
103 *tp = newt;
104 if (!saw_digit)
105 {
106 if (++octets > 4)
107 return 0;
108 saw_digit = 1;
109 }
110 }
111 else if (ch == '.' && saw_digit)
112 {
113 if (octets == 4)
114 return 0;
115 *++tp = 0;
116 saw_digit = 0;
117 }
118 else
119 {
120 return 0;
121 }
122 }
123 if (octets < 4)
124 return 0;
125 memcpy(dst, tmp, 4);
126 return 1;
127 }
128
129 // Maps SOCKOPT level from Wii to native
MapWiiSockOptLevelToNative(u32 level)130 static s32 MapWiiSockOptLevelToNative(u32 level)
131 {
132 if (level == 0xFFFF)
133 return SOL_SOCKET;
134
135 INFO_LOG(IOS_NET, "SO_SETSOCKOPT: unknown level %u", level);
136 return level;
137 }
138
139 // Maps SOCKOPT optname from native to Wii
MapWiiSockOptNameToNative(u32 optname)140 static s32 MapWiiSockOptNameToNative(u32 optname)
141 {
142 switch (optname)
143 {
144 case 0x4:
145 return SO_REUSEADDR;
146 case 0x1001:
147 return SO_SNDBUF;
148 case 0x1002:
149 return SO_RCVBUF;
150 case 0x1009:
151 return SO_ERROR;
152 }
153
154 INFO_LOG(IOS_NET, "SO_SETSOCKOPT: unknown optname %u", optname);
155 return optname;
156 }
157
158 struct DefaultInterface
159 {
160 u32 inet; ///< IPv4 address
161 u32 netmask; ///< IPv4 subnet mask
162 u32 broadcast; ///< IPv4 broadcast address
163 };
164
GetSystemDefaultInterface()165 static std::optional<DefaultInterface> GetSystemDefaultInterface()
166 {
167 #ifdef _WIN32
168 std::unique_ptr<MIB_IPFORWARDTABLE> forward_table;
169 DWORD forward_table_size = 0;
170 if (GetIpForwardTable(nullptr, &forward_table_size, FALSE) == ERROR_INSUFFICIENT_BUFFER)
171 {
172 forward_table =
173 std::unique_ptr<MIB_IPFORWARDTABLE>((PMIB_IPFORWARDTABLE) operator new(forward_table_size));
174 }
175
176 std::unique_ptr<MIB_IPADDRTABLE> ip_table;
177 DWORD ip_table_size = 0;
178 if (GetIpAddrTable(nullptr, &ip_table_size, FALSE) == ERROR_INSUFFICIENT_BUFFER)
179 {
180 ip_table = std::unique_ptr<MIB_IPADDRTABLE>((PMIB_IPADDRTABLE) operator new(ip_table_size));
181 }
182
183 // find the interface IP used for the default route and use that
184 NET_IFINDEX ifIndex = NET_IFINDEX_UNSPECIFIED;
185 DWORD result = GetIpForwardTable(forward_table.get(), &forward_table_size, FALSE);
186 // can return ERROR_MORE_DATA on XP even after the first call
187 while (result == NO_ERROR || result == ERROR_MORE_DATA)
188 {
189 for (DWORD i = 0; i < forward_table->dwNumEntries; ++i)
190 {
191 if (forward_table->table[i].dwForwardDest == 0)
192 {
193 ifIndex = forward_table->table[i].dwForwardIfIndex;
194 break;
195 }
196 }
197
198 if (result == NO_ERROR || ifIndex != NET_IFINDEX_UNSPECIFIED)
199 break;
200
201 result = GetIpForwardTable(forward_table.get(), &forward_table_size, FALSE);
202 }
203
204 if (ifIndex != NET_IFINDEX_UNSPECIFIED &&
205 GetIpAddrTable(ip_table.get(), &ip_table_size, FALSE) == NO_ERROR)
206 {
207 for (DWORD i = 0; i < ip_table->dwNumEntries; ++i)
208 {
209 const auto& entry = ip_table->table[i];
210 if (entry.dwIndex == ifIndex)
211 return DefaultInterface{entry.dwAddr, entry.dwMask, entry.dwBCastAddr};
212 }
213 }
214 #elif !defined(__ANDROID__)
215 // Assume that the address that is used to access the Internet corresponds
216 // to the default interface.
217 auto get_default_address = []() -> std::optional<in_addr> {
218 const int sock = socket(AF_INET, SOCK_DGRAM, 0);
219 Common::ScopeGuard sock_guard{[sock] { close(sock); }};
220
221 sockaddr_in addr{};
222 socklen_t length = sizeof(addr);
223 addr.sin_family = AF_INET;
224 // The address is irrelevant -- no packet is actually sent. This just needs to be a public IP.
225 addr.sin_addr.s_addr = inet_addr(8, 8, 8, 8);
226 if (connect(sock, reinterpret_cast<const sockaddr*>(&addr), sizeof(addr)) == -1)
227 return {};
228 if (getsockname(sock, reinterpret_cast<sockaddr*>(&addr), &length) == -1)
229 return {};
230 return addr.sin_addr;
231 };
232
233 auto get_addr = [](const sockaddr* addr) {
234 return reinterpret_cast<const sockaddr_in*>(addr)->sin_addr.s_addr;
235 };
236
237 const auto default_interface_address = get_default_address();
238 if (!default_interface_address)
239 return {};
240
241 ifaddrs* iflist;
242 if (getifaddrs(&iflist) != 0)
243 return {};
244 Common::ScopeGuard iflist_guard{[iflist] { freeifaddrs(iflist); }};
245
246 for (const ifaddrs* iface = iflist; iface; iface = iface->ifa_next)
247 {
248 if (iface->ifa_addr && iface->ifa_addr->sa_family == AF_INET &&
249 get_addr(iface->ifa_addr) == default_interface_address->s_addr)
250 {
251 return DefaultInterface{get_addr(iface->ifa_addr), get_addr(iface->ifa_netmask),
252 get_addr(iface->ifa_broadaddr)};
253 }
254 }
255 #endif
256 return {};
257 }
258
GetSystemDefaultInterfaceOrFallback()259 static DefaultInterface GetSystemDefaultInterfaceOrFallback()
260 {
261 static constexpr DefaultInterface FALLBACK_VALUES{
262 inet_addr(10, 0, 1, 30), inet_addr(255, 255, 255, 0), inet_addr(10, 0, 255, 255)};
263 return GetSystemDefaultInterface().value_or(FALLBACK_VALUES);
264 }
265
IOCtl(const IOCtlRequest & request)266 IPCCommandResult NetIPTop::IOCtl(const IOCtlRequest& request)
267 {
268 if (Core::WantsDeterminism())
269 {
270 return GetDefaultReply(IPC_EACCES);
271 }
272
273 switch (request.request)
274 {
275 case IOCTL_SO_INITINTERFACE:
276 return HandleInitInterfaceRequest(request);
277 case IOCTL_SO_SOCKET:
278 return HandleSocketRequest(request);
279 case IOCTL_SO_ICMPSOCKET:
280 return HandleICMPSocketRequest(request);
281 case IOCTL_SO_CLOSE:
282 case IOCTL_SO_ICMPCLOSE:
283 return HandleCloseRequest(request);
284 case IOCTL_SO_ACCEPT:
285 case IOCTL_SO_BIND:
286 case IOCTL_SO_CONNECT:
287 case IOCTL_SO_FCNTL:
288 return HandleDoSockRequest(request);
289 case IOCTL_SO_SHUTDOWN:
290 return HandleShutdownRequest(request);
291 case IOCTL_SO_LISTEN:
292 return HandleListenRequest(request);
293 case IOCTL_SO_GETSOCKOPT:
294 return HandleGetSockOptRequest(request);
295 case IOCTL_SO_SETSOCKOPT:
296 return HandleSetSockOptRequest(request);
297 case IOCTL_SO_GETSOCKNAME:
298 return HandleGetSockNameRequest(request);
299 case IOCTL_SO_GETPEERNAME:
300 return HandleGetPeerNameRequest(request);
301 case IOCTL_SO_GETHOSTID:
302 return HandleGetHostIDRequest(request);
303 case IOCTL_SO_INETATON:
304 return HandleInetAToNRequest(request);
305 case IOCTL_SO_INETPTON:
306 return HandleInetPToNRequest(request);
307 case IOCTL_SO_INETNTOP:
308 return HandleInetNToPRequest(request);
309 case IOCTL_SO_POLL:
310 return HandlePollRequest(request);
311 case IOCTL_SO_GETHOSTBYNAME:
312 return HandleGetHostByNameRequest(request);
313 case IOCTL_SO_ICMPCANCEL:
314 return HandleICMPCancelRequest(request);
315 default:
316 request.DumpUnknown(GetDeviceName(), Common::Log::IOS_NET);
317 break;
318 }
319
320 return GetDefaultReply(IPC_SUCCESS);
321 }
322
IOCtlV(const IOCtlVRequest & request)323 IPCCommandResult NetIPTop::IOCtlV(const IOCtlVRequest& request)
324 {
325 switch (request.request)
326 {
327 case IOCTLV_SO_GETINTERFACEOPT:
328 return HandleGetInterfaceOptRequest(request);
329 case IOCTLV_SO_SENDTO:
330 return HandleSendToRequest(request);
331 case IOCTLV_SO_RECVFROM:
332 return HandleRecvFromRequest(request);
333 case IOCTLV_SO_GETADDRINFO:
334 return HandleGetAddressInfoRequest(request);
335 case IOCTLV_SO_ICMPPING:
336 return HandleICMPPingRequest(request);
337 default:
338 request.DumpUnknown(GetDeviceName(), Common::Log::IOS_NET);
339 break;
340 }
341
342 return GetDefaultReply(IPC_SUCCESS);
343 }
344
Update()345 void NetIPTop::Update()
346 {
347 WiiSockMan::GetInstance().Update();
348 }
349
HandleInitInterfaceRequest(const IOCtlRequest & request)350 IPCCommandResult NetIPTop::HandleInitInterfaceRequest(const IOCtlRequest& request)
351 {
352 request.Log(GetDeviceName(), Common::Log::IOS_WC24);
353 return GetDefaultReply(IPC_SUCCESS);
354 }
355
HandleSocketRequest(const IOCtlRequest & request)356 IPCCommandResult NetIPTop::HandleSocketRequest(const IOCtlRequest& request)
357 {
358 u32 af = Memory::Read_U32(request.buffer_in);
359 u32 type = Memory::Read_U32(request.buffer_in + 4);
360 u32 prot = Memory::Read_U32(request.buffer_in + 8);
361
362 WiiSockMan& sm = WiiSockMan::GetInstance();
363 const s32 return_value = sm.NewSocket(af, type, prot);
364 INFO_LOG(IOS_NET,
365 "IOCTL_SO_SOCKET "
366 "Socket: %08x (%d,%d,%d), BufferIn: (%08x, %i), BufferOut: (%08x, %i)",
367 return_value, af, type, prot, request.buffer_in, request.buffer_in_size,
368 request.buffer_out, request.buffer_out_size);
369
370 return GetDefaultReply(return_value);
371 }
372
HandleICMPSocketRequest(const IOCtlRequest & request)373 IPCCommandResult NetIPTop::HandleICMPSocketRequest(const IOCtlRequest& request)
374 {
375 u32 pf = Memory::Read_U32(request.buffer_in);
376
377 WiiSockMan& sm = WiiSockMan::GetInstance();
378 const s32 return_value = sm.NewSocket(pf, SOCK_RAW, IPPROTO_ICMP);
379 INFO_LOG(IOS_NET, "IOCTL_SO_ICMPSOCKET(%x) %d", pf, return_value);
380 return GetDefaultReply(return_value);
381 }
382
HandleCloseRequest(const IOCtlRequest & request)383 IPCCommandResult NetIPTop::HandleCloseRequest(const IOCtlRequest& request)
384 {
385 u32 fd = Memory::Read_U32(request.buffer_in);
386 WiiSockMan& sm = WiiSockMan::GetInstance();
387 const s32 return_value = sm.DeleteSocket(fd);
388 INFO_LOG(IOS_NET, "%s(%x) %x",
389 request.request == IOCTL_SO_ICMPCLOSE ? "IOCTL_SO_ICMPCLOSE" : "IOCTL_SO_CLOSE", fd,
390 return_value);
391
392 return GetDefaultReply(return_value);
393 }
394
HandleDoSockRequest(const IOCtlRequest & request)395 IPCCommandResult NetIPTop::HandleDoSockRequest(const IOCtlRequest& request)
396 {
397 u32 fd = Memory::Read_U32(request.buffer_in);
398 WiiSockMan& sm = WiiSockMan::GetInstance();
399 sm.DoSock(fd, request, static_cast<NET_IOCTL>(request.request));
400 return GetNoReply();
401 }
402
HandleShutdownRequest(const IOCtlRequest & request)403 IPCCommandResult NetIPTop::HandleShutdownRequest(const IOCtlRequest& request)
404 {
405 request.Log(GetDeviceName(), Common::Log::IOS_WC24);
406
407 u32 fd = Memory::Read_U32(request.buffer_in);
408 u32 how = Memory::Read_U32(request.buffer_in + 4);
409 int ret = shutdown(WiiSockMan::GetInstance().GetHostSocket(fd), how);
410
411 return GetDefaultReply(WiiSockMan::GetNetErrorCode(ret, "SO_SHUTDOWN", false));
412 }
413
HandleListenRequest(const IOCtlRequest & request)414 IPCCommandResult NetIPTop::HandleListenRequest(const IOCtlRequest& request)
415 {
416 u32 fd = Memory::Read_U32(request.buffer_in);
417 u32 BACKLOG = Memory::Read_U32(request.buffer_in + 0x04);
418 u32 ret = listen(WiiSockMan::GetInstance().GetHostSocket(fd), BACKLOG);
419
420 request.Log(GetDeviceName(), Common::Log::IOS_WC24);
421 return GetDefaultReply(WiiSockMan::GetNetErrorCode(ret, "SO_LISTEN", false));
422 }
423
HandleGetSockOptRequest(const IOCtlRequest & request)424 IPCCommandResult NetIPTop::HandleGetSockOptRequest(const IOCtlRequest& request)
425 {
426 u32 fd = Memory::Read_U32(request.buffer_out);
427 u32 level = Memory::Read_U32(request.buffer_out + 4);
428 u32 optname = Memory::Read_U32(request.buffer_out + 8);
429
430 request.Log(GetDeviceName(), Common::Log::IOS_WC24);
431
432 // Do the level/optname translation
433 int nat_level = MapWiiSockOptLevelToNative(level);
434 int nat_optname = MapWiiSockOptNameToNative(optname);
435
436 u8 optval[20];
437 u32 optlen = 4;
438
439 int ret = getsockopt(WiiSockMan::GetInstance().GetHostSocket(fd), nat_level, nat_optname,
440 (char*)&optval, (socklen_t*)&optlen);
441 const s32 return_value = WiiSockMan::GetNetErrorCode(ret, "SO_GETSOCKOPT", false);
442
443 Memory::Write_U32(optlen, request.buffer_out + 0xC);
444 Memory::CopyToEmu(request.buffer_out + 0x10, optval, optlen);
445
446 if (optname == SO_ERROR)
447 {
448 s32 last_error = WiiSockMan::GetInstance().GetLastNetError();
449
450 Memory::Write_U32(sizeof(s32), request.buffer_out + 0xC);
451 Memory::Write_U32(last_error, request.buffer_out + 0x10);
452 }
453
454 return GetDefaultReply(return_value);
455 }
456
HandleSetSockOptRequest(const IOCtlRequest & request)457 IPCCommandResult NetIPTop::HandleSetSockOptRequest(const IOCtlRequest& request)
458 {
459 u32 fd = Memory::Read_U32(request.buffer_in);
460 u32 level = Memory::Read_U32(request.buffer_in + 4);
461 u32 optname = Memory::Read_U32(request.buffer_in + 8);
462 u32 optlen = Memory::Read_U32(request.buffer_in + 0xc);
463 u8 optval[20];
464 optlen = std::min(optlen, (u32)sizeof(optval));
465 Memory::CopyFromEmu(optval, request.buffer_in + 0x10, optlen);
466
467 INFO_LOG(IOS_NET,
468 "IOCTL_SO_SETSOCKOPT(%08x, %08x, %08x, %08x) "
469 "BufferIn: (%08x, %i), BufferOut: (%08x, %i)"
470 "%02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx "
471 "%02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx",
472 fd, level, optname, optlen, request.buffer_in, request.buffer_in_size,
473 request.buffer_out, request.buffer_out_size, optval[0], optval[1], optval[2], optval[3],
474 optval[4], optval[5], optval[6], optval[7], optval[8], optval[9], optval[10], optval[11],
475 optval[12], optval[13], optval[14], optval[15], optval[16], optval[17], optval[18],
476 optval[19]);
477
478 // TODO: bug booto about this, 0x2005 most likely timeout related, default value on Wii is ,
479 // 0x2001 is most likely tcpnodelay
480 if (level == 6 && (optname == 0x2005 || optname == 0x2001))
481 return GetDefaultReply(0);
482
483 // Do the level/optname translation
484 int nat_level = MapWiiSockOptLevelToNative(level);
485 int nat_optname = MapWiiSockOptNameToNative(optname);
486
487 int ret = setsockopt(WiiSockMan::GetInstance().GetHostSocket(fd), nat_level, nat_optname,
488 (char*)optval, optlen);
489 return GetDefaultReply(WiiSockMan::GetNetErrorCode(ret, "SO_SETSOCKOPT", false));
490 }
491
HandleGetSockNameRequest(const IOCtlRequest & request)492 IPCCommandResult NetIPTop::HandleGetSockNameRequest(const IOCtlRequest& request)
493 {
494 u32 fd = Memory::Read_U32(request.buffer_in);
495
496 request.Log(GetDeviceName(), Common::Log::IOS_WC24);
497
498 sockaddr sa;
499 socklen_t sa_len = sizeof(sa);
500 int ret = getsockname(WiiSockMan::GetInstance().GetHostSocket(fd), &sa, &sa_len);
501
502 if (request.buffer_out_size < 2 + sizeof(sa.sa_data))
503 WARN_LOG(IOS_NET, "IOCTL_SO_GETSOCKNAME output buffer is too small. Truncating");
504
505 if (request.buffer_out_size > 0)
506 Memory::Write_U8(request.buffer_out_size, request.buffer_out);
507 if (request.buffer_out_size > 1)
508 Memory::Write_U8(sa.sa_family & 0xFF, request.buffer_out + 1);
509 if (request.buffer_out_size > 2)
510 {
511 Memory::CopyToEmu(request.buffer_out + 2, &sa.sa_data,
512 std::min<size_t>(sizeof(sa.sa_data), request.buffer_out_size - 2));
513 }
514
515 return GetDefaultReply(ret);
516 }
517
HandleGetPeerNameRequest(const IOCtlRequest & request)518 IPCCommandResult NetIPTop::HandleGetPeerNameRequest(const IOCtlRequest& request)
519 {
520 u32 fd = Memory::Read_U32(request.buffer_in);
521
522 sockaddr sa;
523 socklen_t sa_len = sizeof(sa);
524 int ret = getpeername(WiiSockMan::GetInstance().GetHostSocket(fd), &sa, &sa_len);
525
526 if (request.buffer_out_size < 2 + sizeof(sa.sa_data))
527 WARN_LOG(IOS_NET, "IOCTL_SO_GETPEERNAME output buffer is too small. Truncating");
528
529 if (request.buffer_out_size > 0)
530 Memory::Write_U8(request.buffer_out_size, request.buffer_out);
531 if (request.buffer_out_size > 1)
532 Memory::Write_U8(AF_INET, request.buffer_out + 1);
533 if (request.buffer_out_size > 2)
534 {
535 Memory::CopyToEmu(request.buffer_out + 2, &sa.sa_data,
536 std::min<size_t>(sizeof(sa.sa_data), request.buffer_out_size - 2));
537 }
538
539 INFO_LOG(IOS_NET, "IOCTL_SO_GETPEERNAME(%x)", fd);
540 return GetDefaultReply(ret);
541 }
542
HandleGetHostIDRequest(const IOCtlRequest & request)543 IPCCommandResult NetIPTop::HandleGetHostIDRequest(const IOCtlRequest& request)
544 {
545 request.Log(GetDeviceName(), Common::Log::IOS_WC24);
546 const DefaultInterface interface = GetSystemDefaultInterfaceOrFallback();
547 return GetDefaultReply(Common::swap32(interface.inet));
548 }
549
HandleInetAToNRequest(const IOCtlRequest & request)550 IPCCommandResult NetIPTop::HandleInetAToNRequest(const IOCtlRequest& request)
551 {
552 std::string hostname = Memory::GetString(request.buffer_in);
553 struct hostent* remoteHost = gethostbyname(hostname.c_str());
554
555 if (remoteHost == nullptr || remoteHost->h_addr_list == nullptr ||
556 remoteHost->h_addr_list[0] == nullptr)
557 {
558 INFO_LOG(IOS_NET,
559 "IOCTL_SO_INETATON = -1 "
560 "%s, BufferIn: (%08x, %i), BufferOut: (%08x, %i), IP Found: None",
561 hostname.c_str(), request.buffer_in, request.buffer_in_size, request.buffer_out,
562 request.buffer_out_size);
563 return GetDefaultReply(0);
564 }
565
566 Memory::Write_U32(Common::swap32(*(u32*)remoteHost->h_addr_list[0]), request.buffer_out);
567 INFO_LOG(IOS_NET,
568 "IOCTL_SO_INETATON = 0 "
569 "%s, BufferIn: (%08x, %i), BufferOut: (%08x, %i), IP Found: %08X",
570 hostname.c_str(), request.buffer_in, request.buffer_in_size, request.buffer_out,
571 request.buffer_out_size, Common::swap32(*(u32*)remoteHost->h_addr_list[0]));
572 return GetDefaultReply(1);
573 }
574
HandleInetPToNRequest(const IOCtlRequest & request)575 IPCCommandResult NetIPTop::HandleInetPToNRequest(const IOCtlRequest& request)
576 {
577 std::string address = Memory::GetString(request.buffer_in);
578 INFO_LOG(IOS_NET, "IOCTL_SO_INETPTON (Translating: %s)", address.c_str());
579 return GetDefaultReply(inet_pton(address.c_str(), Memory::GetPointer(request.buffer_out + 4)));
580 }
581
HandleInetNToPRequest(const IOCtlRequest & request)582 IPCCommandResult NetIPTop::HandleInetNToPRequest(const IOCtlRequest& request)
583 {
584 // u32 af = Memory::Read_U32(BufferIn);
585 // u32 validAddress = Memory::Read_U32(request.buffer_in + 4);
586 // u32 src = Memory::Read_U32(request.buffer_in + 8);
587
588 char ip_s[16];
589 sprintf(ip_s, "%i.%i.%i.%i", Memory::Read_U8(request.buffer_in + 8),
590 Memory::Read_U8(request.buffer_in + 8 + 1), Memory::Read_U8(request.buffer_in + 8 + 2),
591 Memory::Read_U8(request.buffer_in + 8 + 3));
592
593 INFO_LOG(IOS_NET, "IOCTL_SO_INETNTOP %s", ip_s);
594 Memory::CopyToEmu(request.buffer_out, (u8*)ip_s, strlen(ip_s));
595 return GetDefaultReply(0);
596 }
597
HandlePollRequest(const IOCtlRequest & request)598 IPCCommandResult NetIPTop::HandlePollRequest(const IOCtlRequest& request)
599 {
600 WiiSockMan& sm = WiiSockMan::GetInstance();
601
602 if (!request.buffer_in || !request.buffer_out)
603 return GetDefaultReply(-SO_EINVAL);
604
605 // Negative timeout indicates wait forever
606 const s64 timeout = static_cast<s64>(Memory::Read_U64(request.buffer_in));
607
608 const u32 nfds = request.buffer_out_size / 0xc;
609 if (nfds == 0 || nfds > WII_SOCKET_FD_MAX)
610 {
611 ERROR_LOG(IOS_NET, "IOCTL_SO_POLL failed: Invalid array size %d, ret=%d", nfds, -SO_EINVAL);
612 return GetDefaultReply(-SO_EINVAL);
613 }
614
615 std::vector<pollfd_t> ufds(nfds);
616
617 for (u32 i = 0; i < nfds; ++i)
618 {
619 const s32 wii_fd = Memory::Read_U32(request.buffer_out + 0xc * i);
620 ufds[i].fd = sm.GetHostSocket(wii_fd); // fd
621 const int events = Memory::Read_U32(request.buffer_out + 0xc * i + 4); // events
622 ufds[i].revents = 0;
623
624 // Translate Wii to native events
625 ufds[i].events = WiiSockMan::ConvertEvents(events, WiiSockMan::ConvertDirection::WiiToNative);
626 DEBUG_LOG(IOS_NET,
627 "IOCTL_SO_POLL(%d) "
628 "Sock: %08x, Events: %08x, "
629 "NativeEvents: %08x",
630 i, wii_fd, events, ufds[i].events);
631
632 // Do not pass return-only events to the native poll
633 ufds[i].events &= ~(POLLERR | POLLHUP | POLLNVAL | UNSUPPORTED_WSAPOLL);
634 }
635
636 // Prevents blocking emulation on a blocking poll
637 sm.AddPollCommand({request.address, request.buffer_out, std::move(ufds), timeout});
638 return GetNoReply();
639 }
640
HandleGetHostByNameRequest(const IOCtlRequest & request)641 IPCCommandResult NetIPTop::HandleGetHostByNameRequest(const IOCtlRequest& request)
642 {
643 if (request.buffer_out_size != 0x460)
644 {
645 ERROR_LOG(IOS_NET, "Bad buffer size for IOCTL_SO_GETHOSTBYNAME");
646 return GetDefaultReply(-1);
647 }
648
649 std::string hostname = Memory::GetString(request.buffer_in);
650 hostent* remoteHost = gethostbyname(hostname.c_str());
651
652 INFO_LOG(IOS_NET,
653 "IOCTL_SO_GETHOSTBYNAME "
654 "Address: %s, BufferIn: (%08x, %i), BufferOut: (%08x, %i)",
655 hostname.c_str(), request.buffer_in, request.buffer_in_size, request.buffer_out,
656 request.buffer_out_size);
657
658 if (remoteHost == nullptr)
659 return GetDefaultReply(-1);
660
661 for (int i = 0; remoteHost->h_aliases[i]; ++i)
662 {
663 DEBUG_LOG(IOS_NET, "alias%i:%s", i, remoteHost->h_aliases[i]);
664 }
665
666 for (int i = 0; remoteHost->h_addr_list[i]; ++i)
667 {
668 const u32 ip = Common::swap32(*(u32*)(remoteHost->h_addr_list[i]));
669 const std::string ip_s =
670 fmt::format("{}.{}.{}.{}", ip >> 24, (ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff);
671 DEBUG_LOG(IOS_NET, "addr%i:%s", i, ip_s.c_str());
672 }
673
674 // Host name; located immediately after struct
675 static const u32 GETHOSTBYNAME_STRUCT_SIZE = 0x10;
676 static const u32 GETHOSTBYNAME_IP_LIST_OFFSET = 0x110;
677 // Limit host name length to avoid buffer overflow.
678 u32 name_length = (u32)strlen(remoteHost->h_name) + 1;
679 if (name_length > (GETHOSTBYNAME_IP_LIST_OFFSET - GETHOSTBYNAME_STRUCT_SIZE))
680 {
681 ERROR_LOG(IOS_NET, "Hostname too long in IOCTL_SO_GETHOSTBYNAME");
682 return GetDefaultReply(-1);
683 }
684 Memory::CopyToEmu(request.buffer_out + GETHOSTBYNAME_STRUCT_SIZE, remoteHost->h_name,
685 name_length);
686 Memory::Write_U32(request.buffer_out + GETHOSTBYNAME_STRUCT_SIZE, request.buffer_out);
687
688 // IP address list; located at offset 0x110.
689 u32 num_ip_addr = 0;
690 while (remoteHost->h_addr_list[num_ip_addr])
691 num_ip_addr++;
692 // Limit number of IP addresses to avoid buffer overflow.
693 // (0x460 - 0x340) / sizeof(pointer) == 72
694 static const u32 GETHOSTBYNAME_MAX_ADDRESSES = 71;
695 num_ip_addr = std::min(num_ip_addr, GETHOSTBYNAME_MAX_ADDRESSES);
696 for (u32 i = 0; i < num_ip_addr; ++i)
697 {
698 u32 addr = request.buffer_out + GETHOSTBYNAME_IP_LIST_OFFSET + i * 4;
699 Memory::Write_U32_Swap(*(u32*)(remoteHost->h_addr_list[i]), addr);
700 }
701
702 // List of pointers to IP addresses; located at offset 0x340.
703 // This must be exact: PPC code to convert the struct hardcodes
704 // this offset.
705 static const u32 GETHOSTBYNAME_IP_PTR_LIST_OFFSET = 0x340;
706 Memory::Write_U32(request.buffer_out + GETHOSTBYNAME_IP_PTR_LIST_OFFSET, request.buffer_out + 12);
707 for (u32 i = 0; i < num_ip_addr; ++i)
708 {
709 u32 addr = request.buffer_out + GETHOSTBYNAME_IP_PTR_LIST_OFFSET + i * 4;
710 Memory::Write_U32(request.buffer_out + GETHOSTBYNAME_IP_LIST_OFFSET + i * 4, addr);
711 }
712 Memory::Write_U32(0, request.buffer_out + GETHOSTBYNAME_IP_PTR_LIST_OFFSET + num_ip_addr * 4);
713
714 // Aliases - empty. (Hardware doesn't return anything.)
715 Memory::Write_U32(request.buffer_out + GETHOSTBYNAME_IP_PTR_LIST_OFFSET + num_ip_addr * 4,
716 request.buffer_out + 4);
717
718 // Returned struct must be ipv4.
719 ASSERT_MSG(IOS_NET, remoteHost->h_addrtype == AF_INET && remoteHost->h_length == sizeof(u32),
720 "returned host info is not IPv4");
721 Memory::Write_U16(AF_INET, request.buffer_out + 8);
722 Memory::Write_U16(sizeof(u32), request.buffer_out + 10);
723
724 return GetDefaultReply(0);
725 }
726
HandleICMPCancelRequest(const IOCtlRequest & request)727 IPCCommandResult NetIPTop::HandleICMPCancelRequest(const IOCtlRequest& request)
728 {
729 ERROR_LOG(IOS_NET, "IOCTL_SO_ICMPCANCEL");
730 return GetDefaultReply(0);
731 }
732
HandleGetInterfaceOptRequest(const IOCtlVRequest & request)733 IPCCommandResult NetIPTop::HandleGetInterfaceOptRequest(const IOCtlVRequest& request)
734 {
735 const u32 param = Memory::Read_U32(request.in_vectors[0].address);
736 const u32 param2 = Memory::Read_U32(request.in_vectors[0].address + 4);
737 const u32 param3 = Memory::Read_U32(request.io_vectors[0].address);
738 const u32 param4 = Memory::Read_U32(request.io_vectors[1].address);
739 u32 param5 = 0;
740
741 if (param != 0xfffe)
742 {
743 WARN_LOG(IOS_NET, "GetInterfaceOpt: received invalid request with param0=%08x", param);
744 return GetDefaultReply(SO_ERROR_INVALID_REQUEST);
745 }
746
747 if (request.io_vectors[0].size >= 8)
748 {
749 param5 = Memory::Read_U32(request.io_vectors[0].address + 4);
750 }
751
752 INFO_LOG(IOS_NET,
753 "IOCTLV_SO_GETINTERFACEOPT(%08X, %08X, %X, %X, %X) "
754 "BufferIn: (%08x, %i), BufferIn2: (%08x, %i) ",
755 param, param2, param3, param4, param5, request.in_vectors[0].address,
756 request.in_vectors[0].size,
757 request.in_vectors.size() > 1 ? request.in_vectors[1].address : 0,
758 request.in_vectors.size() > 1 ? request.in_vectors[1].size : 0);
759
760 switch (param2)
761 {
762 case 0xb003: // dns server table
763 {
764 const u32 default_main_dns_resolver = ntohl(::inet_addr("8.8.8.8"));
765 const u32 default_backup_dns_resolver = ntohl(::inet_addr("8.8.4.4"));
766 u32 address = 0;
767 #ifdef _WIN32
768 if (!Core::WantsDeterminism())
769 {
770 PIP_ADAPTER_ADDRESSES AdapterAddresses = nullptr;
771 ULONG OutBufferLength = 0;
772 ULONG RetVal = 0, i;
773 for (i = 0; i < 5; ++i)
774 {
775 RetVal = GetAdaptersAddresses(AF_INET, 0, nullptr, AdapterAddresses, &OutBufferLength);
776
777 if (RetVal != ERROR_BUFFER_OVERFLOW)
778 {
779 break;
780 }
781
782 if (AdapterAddresses != nullptr)
783 {
784 FREE(AdapterAddresses);
785 }
786
787 AdapterAddresses = (PIP_ADAPTER_ADDRESSES)MALLOC(OutBufferLength);
788 if (AdapterAddresses == nullptr)
789 {
790 RetVal = GetLastError();
791 break;
792 }
793 }
794 if (RetVal == NO_ERROR)
795 {
796 unsigned long dwBestIfIndex = 0;
797 IPAddr dwDestAddr = static_cast<IPAddr>(default_main_dns_resolver);
798 // If successful, output some information from the data we received
799 PIP_ADAPTER_ADDRESSES AdapterList = AdapterAddresses;
800 if (GetBestInterface(dwDestAddr, &dwBestIfIndex) == NO_ERROR)
801 {
802 while (AdapterList)
803 {
804 if (AdapterList->IfIndex == dwBestIfIndex && AdapterList->FirstDnsServerAddress &&
805 AdapterList->OperStatus == IfOperStatusUp)
806 {
807 INFO_LOG(IOS_NET, "Name of valid interface: %S", AdapterList->FriendlyName);
808 INFO_LOG(
809 IOS_NET, "DNS: %u.%u.%u.%u",
810 (unsigned char)AdapterList->FirstDnsServerAddress->Address.lpSockaddr->sa_data[2],
811 (unsigned char)AdapterList->FirstDnsServerAddress->Address.lpSockaddr->sa_data[3],
812 (unsigned char)AdapterList->FirstDnsServerAddress->Address.lpSockaddr->sa_data[4],
813 (unsigned char)
814 AdapterList->FirstDnsServerAddress->Address.lpSockaddr->sa_data[5]);
815 address = Common::swap32(
816 *(u32*)(&AdapterList->FirstDnsServerAddress->Address.lpSockaddr->sa_data[2]));
817 break;
818 }
819 AdapterList = AdapterList->Next;
820 }
821 }
822 }
823 if (AdapterAddresses != nullptr)
824 {
825 FREE(AdapterAddresses);
826 }
827 }
828 #elif defined(__linux__) && !defined(__ANDROID__)
829 if (!Core::WantsDeterminism())
830 {
831 if (res_init() == 0)
832 address = ntohl(_res.nsaddr_list[0].sin_addr.s_addr);
833 else
834 WARN_LOG(IOS_NET, "Call to res_init failed");
835 }
836 #endif
837 if (address == 0)
838 address = default_main_dns_resolver;
839
840 INFO_LOG(IOS_NET, "Primary DNS: %X", address);
841 INFO_LOG(IOS_NET, "Secondary DNS: %X", default_backup_dns_resolver);
842
843 Memory::Write_U32(address, request.io_vectors[0].address);
844 Memory::Write_U32(default_backup_dns_resolver, request.io_vectors[0].address + 4);
845 break;
846 }
847 case 0x1003: // error
848 Memory::Write_U32(0, request.io_vectors[0].address);
849 break;
850
851 case 0x1004: // mac address
852 {
853 const Common::MACAddress address = IOS::Net::GetMACAddress();
854 Memory::CopyToEmu(request.io_vectors[0].address, address.data(), address.size());
855 break;
856 }
857
858 case 0x1005: // link state
859 Memory::Write_U32(1, request.io_vectors[0].address);
860 break;
861
862 case 0x3001: // hardcoded value
863 Memory::Write_U32(0x10, request.io_vectors[0].address);
864 break;
865
866 case 0x4002: // ip addr numberHandle
867 Memory::Write_U32(1, request.io_vectors[0].address);
868 break;
869
870 case 0x4003: // ip addr table
871 {
872 // XXX: this isn't exactly right; the buffer can be larger than 12 bytes, in which case
873 // SO can write 12 more bytes.
874 Memory::Write_U32(0xC, request.io_vectors[1].address);
875 const DefaultInterface interface = GetSystemDefaultInterfaceOrFallback();
876 Memory::Write_U32(Common::swap32(interface.inet), request.io_vectors[0].address);
877 Memory::Write_U32(Common::swap32(interface.netmask), request.io_vectors[0].address + 4);
878 Memory::Write_U32(Common::swap32(interface.broadcast), request.io_vectors[0].address + 8);
879 break;
880 }
881
882 case 0x4005: // hardcoded value
883 Memory::Write_U32(0x20, request.io_vectors[0].address);
884 break;
885
886 case 0x6003: // hardcoded value
887 Memory::Write_U32(0x80, request.io_vectors[0].address);
888 break;
889
890 case 0x600a: // hardcoded value
891 Memory::Write_U32(0x80, request.io_vectors[0].address);
892 break;
893
894 case 0x600c: // hardcoded value
895 Memory::Write_U32(0x80, request.io_vectors[0].address);
896 break;
897
898 case 0xb002: // hardcoded value
899 Memory::Write_U32(2, request.io_vectors[0].address);
900 break;
901
902 default:
903 ERROR_LOG(IOS_NET, "Unknown param2: %08X", param2);
904 break;
905 }
906
907 return GetDefaultReply(0);
908 }
909
HandleSendToRequest(const IOCtlVRequest & request)910 IPCCommandResult NetIPTop::HandleSendToRequest(const IOCtlVRequest& request)
911 {
912 u32 fd = Memory::Read_U32(request.in_vectors[1].address);
913 WiiSockMan& sm = WiiSockMan::GetInstance();
914 sm.DoSock(fd, request, IOCTLV_SO_SENDTO);
915 return GetNoReply();
916 }
917
HandleRecvFromRequest(const IOCtlVRequest & request)918 IPCCommandResult NetIPTop::HandleRecvFromRequest(const IOCtlVRequest& request)
919 {
920 u32 fd = Memory::Read_U32(request.in_vectors[0].address);
921 WiiSockMan& sm = WiiSockMan::GetInstance();
922 sm.DoSock(fd, request, IOCTLV_SO_RECVFROM);
923 return GetNoReply();
924 }
925
HandleGetAddressInfoRequest(const IOCtlVRequest & request)926 IPCCommandResult NetIPTop::HandleGetAddressInfoRequest(const IOCtlVRequest& request)
927 {
928 addrinfo hints;
929 const bool hints_valid = request.in_vectors.size() > 2 && request.in_vectors[2].size;
930
931 if (hints_valid)
932 {
933 hints.ai_flags = Memory::Read_U32(request.in_vectors[2].address);
934 hints.ai_family = Memory::Read_U32(request.in_vectors[2].address + 0x4);
935 hints.ai_socktype = Memory::Read_U32(request.in_vectors[2].address + 0x8);
936 hints.ai_protocol = Memory::Read_U32(request.in_vectors[2].address + 0xC);
937 hints.ai_addrlen = Memory::Read_U32(request.in_vectors[2].address + 0x10);
938 hints.ai_canonname = nullptr;
939 hints.ai_addr = nullptr;
940 hints.ai_next = nullptr;
941 }
942
943 // getaddrinfo allows a null pointer for the nodeName or serviceName strings
944 // So we have to do a bit of juggling here.
945 std::string nodeNameStr;
946 const char* pNodeName = nullptr;
947 if (!request.in_vectors.empty() && request.in_vectors[0].size > 0)
948 {
949 nodeNameStr = Memory::GetString(request.in_vectors[0].address, request.in_vectors[0].size);
950 pNodeName = nodeNameStr.c_str();
951 }
952
953 std::string serviceNameStr;
954 const char* pServiceName = nullptr;
955 if (request.in_vectors.size() > 1 && request.in_vectors[1].size > 0)
956 {
957 serviceNameStr = Memory::GetString(request.in_vectors[1].address, request.in_vectors[1].size);
958 pServiceName = serviceNameStr.c_str();
959 }
960
961 addrinfo* result = nullptr;
962 int ret = getaddrinfo(pNodeName, pServiceName, hints_valid ? &hints : nullptr, &result);
963 u32 addr = request.io_vectors[0].address;
964 u32 sockoffset = addr + 0x460;
965 if (ret == 0)
966 {
967 constexpr size_t WII_ADDR_INFO_SIZE = 0x20;
968 for (addrinfo* result_iter = result; result_iter != nullptr; result_iter = result_iter->ai_next)
969 {
970 Memory::Write_U32(result_iter->ai_flags, addr);
971 Memory::Write_U32(result_iter->ai_family, addr + 0x04);
972 Memory::Write_U32(result_iter->ai_socktype, addr + 0x08);
973 Memory::Write_U32(result_iter->ai_protocol, addr + 0x0C);
974 Memory::Write_U32((u32)result_iter->ai_addrlen, addr + 0x10);
975 // what to do? where to put? the buffer of 0x834 doesn't allow space for this
976 Memory::Write_U32(/*result->ai_cannonname*/ 0, addr + 0x14);
977
978 if (result_iter->ai_addr)
979 {
980 Memory::Write_U32(sockoffset, addr + 0x18);
981 Memory::Write_U8(result_iter->ai_addrlen & 0xFF, sockoffset);
982 Memory::Write_U8(result_iter->ai_addr->sa_family & 0xFF, sockoffset + 0x01);
983 Memory::CopyToEmu(sockoffset + 0x2, result_iter->ai_addr->sa_data,
984 sizeof(result_iter->ai_addr->sa_data));
985 sockoffset += 0x1C;
986 }
987 else
988 {
989 Memory::Write_U32(0, addr + 0x18);
990 }
991
992 if (result_iter->ai_next)
993 {
994 Memory::Write_U32(addr + WII_ADDR_INFO_SIZE, addr + 0x1C);
995 }
996 else
997 {
998 Memory::Write_U32(0, addr + 0x1C);
999 }
1000
1001 addr += WII_ADDR_INFO_SIZE;
1002 }
1003
1004 freeaddrinfo(result);
1005 }
1006 else
1007 {
1008 ret = SO_ERROR_HOST_NOT_FOUND;
1009 }
1010
1011 request.Dump(GetDeviceName(), Common::Log::IOS_NET, Common::Log::LINFO);
1012 return GetDefaultReply(ret);
1013 }
1014
HandleICMPPingRequest(const IOCtlVRequest & request)1015 IPCCommandResult NetIPTop::HandleICMPPingRequest(const IOCtlVRequest& request)
1016 {
1017 struct
1018 {
1019 u8 length;
1020 u8 addr_family;
1021 u16 icmp_id;
1022 u32 ip;
1023 } ip_info;
1024
1025 u32 fd = Memory::Read_U32(request.in_vectors[0].address);
1026 u32 num_ip = Memory::Read_U32(request.in_vectors[0].address + 4);
1027 u64 timeout = Memory::Read_U64(request.in_vectors[0].address + 8);
1028
1029 if (num_ip != 1)
1030 {
1031 INFO_LOG(IOS_NET, "IOCTLV_SO_ICMPPING %i IPs", num_ip);
1032 }
1033
1034 ip_info.length = Memory::Read_U8(request.in_vectors[0].address + 16);
1035 ip_info.addr_family = Memory::Read_U8(request.in_vectors[0].address + 17);
1036 ip_info.icmp_id = Memory::Read_U16(request.in_vectors[0].address + 18);
1037 ip_info.ip = Memory::Read_U32(request.in_vectors[0].address + 20);
1038
1039 if (ip_info.length != 8 || ip_info.addr_family != AF_INET)
1040 {
1041 INFO_LOG(IOS_NET,
1042 "IOCTLV_SO_ICMPPING strange IPInfo:\n"
1043 "length %x addr_family %x",
1044 ip_info.length, ip_info.addr_family);
1045 }
1046
1047 INFO_LOG(IOS_NET, "IOCTLV_SO_ICMPPING %x", ip_info.ip);
1048
1049 sockaddr_in addr;
1050 addr.sin_family = AF_INET;
1051 addr.sin_addr.s_addr = Common::swap32(ip_info.ip);
1052 memset(addr.sin_zero, 0, 8);
1053
1054 u8 data[0x20];
1055 memset(data, 0, sizeof(data));
1056 s32 icmp_length = sizeof(data);
1057
1058 if (request.in_vectors.size() > 1 && request.in_vectors[1].size == sizeof(data))
1059 {
1060 Memory::CopyFromEmu(data, request.in_vectors[1].address, request.in_vectors[1].size);
1061 }
1062 else
1063 {
1064 // TODO sequence number is incremented either statically, by
1065 // port, or by socket. Doesn't seem to matter, so we just leave
1066 // it 0
1067 ((u16*)data)[0] = Common::swap16(ip_info.icmp_id);
1068 icmp_length = 22;
1069 }
1070
1071 int ret = icmp_echo_req(WiiSockMan::GetInstance().GetHostSocket(fd), &addr, data, icmp_length);
1072 if (ret == icmp_length)
1073 {
1074 ret = icmp_echo_rep(WiiSockMan::GetInstance().GetHostSocket(fd), &addr,
1075 static_cast<u32>(timeout), icmp_length);
1076 }
1077
1078 // TODO proper error codes
1079 return GetDefaultReply(0);
1080 }
1081 } // namespace IOS::HLE::Device
1082