recovery_menu/ios_mcp/source/netdb.c
GerbilSoft 36222846d9
New "Submit System Data" function (#25)
* SubmitSystemData.c: Initial "Submit System Data" function.

This will allow users to submit anonymized system information, including
a masked-off serial number and MLC manufacturer, so we can try to figure
out which serial numbers correspond to which MLC manufacturer, among
other things.

This screen has been implemented using a separate .c file instead of
adding it somewhere in menu.c. I'll split other screens into separate
.c files later.

imports.ld: Added IOSC_GenerateHash() from Gary.

TODO: gethostbyname() for DNS lookup.

* SubmitSystemData.c: Use an array of strings for the description.

Code size difference:

   text    data     bss     dec     hex filename
  27208       0    9696   36904    9028 ios_mcp.elf [before]
  26992       0    9696   36688    8f50 ios_mcp.elf [after]
   -216       0       0    -216     -d8 Difference

* SubmitSystemData.c: Add some more stuff to the hash.

* SubmitSystemData.c: Submit the system data to wiiu.gerbilsoft.com.

Using http instead of https due to the complexity of using https within
the recovery_menu environment, and Wii U doesn't support TLS 1.2 natively.

TODO:
- Implement gethostbyname().
- Check the HTTP response code.

* StartWupserver.c: Split option_StartWupserver() out of menu.c.

* menu.c: Split netconf init from StartWupserver and SubmitSystemData into initNetconf().

Takes an 'index' (Y position) parameter and returns a new Y position,
or 0 if an error occurred.

Removed the "+ 4" from the Wupserver version. Added "+ 4" to the
other messages in Wupserver.

* SystemInformation.c: Split out option_SystemInformation() into a separate file.

* DebugSystemRegion.c: Split out option_DebugSystemRegion() into a separate file.

* Makefile: Add -Werror=implicit-function-declaration.

An implicit function declaration almost always means a header is missing,
and will likely result in a link error later on.

* menu.c: Add a GitHub repository link to the bottom of the main menu.

Well, it's a link in that it's blue and underlined, but you can't exactly
click it here...

* SubmitSystemData.c: Set ddr3Size and ddr3Speed.

* SubmitSystemData.c: Look up the domain name instead of using a hard-coded IP address.

netdb.c: gethostbyname() implementation by @GaryOderNichts.

* SubmitSystemData.c: Parse the HTTP response to show actual successes or failures.

Only the response code is parsed and the response message is shown.

TODO: Show the actual message from the server.

* gfx.h: Add a new attribute GfxPrintFlag_Underline.

This prints an underscore character on top of every character that's
printed, resulting in an underline effect.

Removed the manual underlining code elsewhere.

Code size difference:

   text    data     bss     dec     hex filename
  29068       0   10400   39468    9a2c ios_mcp.elf [before]
  28996       0   10400   39396    99e4 ios_mcp.elf [after]
    -72       0       0     -72     -48 Difference

* SystemInformation.c: Display the BSP revision.

This uses bspGetHardwareVersion(). [imports.ld value provided by Gary]

The BSP version is roughly equivalent to the Console Type value found
on Wii and GameCube, though libogc doesn't set it properly...

Most retail systems will be 0x25100028. (A5X Cafe)

Rearranged System Information to use three columns for the main data.
MLC information is still shown below the main data.

* SubmitSystemData: Add the BSP revision to the submitted data.

* Use gfx_print() instead of gfx_printf() when formatting isn't needed.

* PairDRC.c: Split "Pair DRC" into a separate file.

* SubmitSystemData.c: Get the HTTP message body and print it on screen.

Only the HTTP response code and message body will be displayed in either
green or red. The message printed afterwards will be white.

NOTE: We need to use a fairly large buffer for the HTTP response because
Cloudflare adds a ton of headers. For example, an HTTP/1.1 200 OK response
with the following message:

"System ID is #1. This system was already submitted."

has a 648-byte HTTP response, mostly due to Cloudflare's "Report-To"
header.

To be on the safe side, we'll allow use of the entire buffer allocated
for OTP, SEEPROM, and the POST data struct, since none of those are
needed after sending the HTTP request header. (2,048 bytes)

* gfx_print(): Add support for newlines. ('\n')

If a newline is encountered in a string, the x position will be reset to
the original x position specified by the caller, and the y position will
be advanced by one line. The final y position is returned by the function.

This allows us to consolidate many individual calls to gfx_print() and/or
gfx_printf() into a single call.

Code size differences:

   text    data     bss     dec     hex filename
  29332       0   10400   39732    9b34 ios_mcp.elf [before]
  29364       0   10400   39764    9b54 ios_mcp.elf [add '\n' to gfx_print]
  29220       0   10400   39620    9ac4 ios_mcp.elf [update SubmitSystemData.c]
   -112       0       0    -112     -70 Difference

Simply updating SubmitSystemData.c to take advantage of the newline
support wiped out the code size increase from adding it.

NOTE: The newline support currently only supports adding a single line,
not CHAR_SIZE_DRC_Y + 4. +4 is commonly used for menus, which can't take
advantage of the newline support anyway.

* SystemInformation.c: Make use of newlines for part of the MLC information display.

New flag GfxPrintFlag_NewlinePlus4 that adds CHAR_SIZE_DRC_Y + 4 for
newlines instead of just CHAR_SIZE_DRC_Y.

Code size difference:

   text    data     bss     dec     hex filename
  29220       0   10400   39620    9ac4 ios_mcp.elf [before]
  29148       0   10400   39548    9a7c ios_mcp.elf [after]
    -72       0       0     -72     -48 Difference

* DebugSystemRegion.c: Some minor optimizations.

Code size difference:

   text    data     bss     dec     hex filename
  29148       0   10400   39548    9a7c ios_mcp.elf [before]
  29124       0   10400   39524    9a64 ios_mcp.elf [after]
    -24       0       0     -24     -18 Difference

* SubmitSystemData.c: Make dataBuffer uint8_t*; use it instead of otp for the recv buffer.

This reduces confusion, even though otp and dataBuffer are technically
the same buffer.

Fix a one-byte overflow when ensuring dataBuffer is NULL-terminated.

* initNetconf(): Use a pointer for index and return an actual error code.

* Makefile: Add -Werror=int-conversion.

* SubmitSystemData.c: Submit ddr3Vendor and MLC CID.

Using empty space in the POST data structure instead of shuffling it
around to preserve compatibility (for now).

* SystemInformation.c: Display BSP revision name and DDR3 information.

* SystemInformation.c: Fix text alignment of Column 2's data.

* SubmitSystemData.c: Verify the send() return values.

* SubmitSystemData.c: Use RSA+AES encryption when submitting data.

Since we can't use https, use the next best thing.

NOTE: mini-gmp puts us very close to the 40K .text limit:

   text    data     bss     dec     hex filename
  39612       0   10400   50012    c35c ios_mcp.elf

TODO: Investigate using Thumb mode later.

* imports.h: Clarify that these IOSC_GenerateHash() flags are for SHA-256.

Also add SHA-1 flags.

* SubmitSystemData.c: Send MS, CA, NG, and NG key IDs, and device certificate.

Device certificate is recommended in order to really verify the system
information is authentic. It will be checked against MS, CA, NG, and
NG key IDs.

Rearrange the POST data struct to work better.

Remove MLC name1, since the device name is part of the CID.

NOTE: This requires a server-side change.

* SubmitSystemData.c: Make the submitted info screen match WiiUIdent.

* SubmitSystemData.c: Handle newlines in the server's response message.
2023-04-01 18:45:14 +02:00

123 lines
3.2 KiB
C

#include "netdb.h"
#include "imports.h"
#include <string.h>
int h_errno;
struct dns_querys {
struct dns_querys * next;
uint32_t field1_0x4;
uint32_t send_time;
uint32_t expire_time;
uint16_t tries;
uint16_t lport;
uint16_t id;
uint16_t server_index;
uint32_t fhost;
int32_t replies;
int32_t ipaddrs;
uint32_t ipaddr_list[10];
char* addrptrs[10];
int32_t err;
int32_t rcode;
char dns_names[256];
char ptr_name[256];
uint32_t auths_ip;
char* alist[4];
struct hostent hostent;
uint8_t type;
uint8_t padding[3];
uint32_t field27_0x2a8;
uint32_t field28_0x2ac;
void* dns_req;
uint32_t has_next;
//! self pointer used for pointer offset calculation
void* query_ios_ptr;
};
static_assert(sizeof(struct dns_querys) == 0x2bc, "dns_querys: different size than expected");
struct dns_query_params {
char name[128];
uint8_t type;
uint8_t padding[3];
uint32_t unk0;
uint32_t addr;
uint32_t ttl;
};
static_assert(sizeof(struct dns_query_params) == 0x90, "dns_query_params: different size than expected");
struct dns_ioctlv {
IOSVec_t vecs[2];
uint8_t padding0[104];
struct dns_query_params params;
uint8_t padding1[112];
struct dns_querys query;
uint8_t padding2[68];
};
static_assert(sizeof(struct dns_ioctlv) == 0x480, "dns_ioctlv: different size than expected");
static int do_dns_query(const char* name, uint8_t type, uint32_t addr, uint32_t ttl, struct dns_querys* query)
{
struct dns_ioctlv* ioctlv = IOS_HeapAllocAligned(CROSS_PROCESS_HEAP_ID, sizeof(struct dns_ioctlv), 0x40);
if (!ioctlv) {
return -1;
}
memset(ioctlv, 0, sizeof(*ioctlv));
strncpy(ioctlv->params.name, name, sizeof(ioctlv->params.name));
ioctlv->params.type = type;
ioctlv->params.ttl = ttl;
ioctlv->params.addr = addr;
ioctlv->vecs[0].ptr = &ioctlv->params;
ioctlv->vecs[0].len = sizeof(ioctlv->params);
ioctlv->vecs[1].ptr = &ioctlv->query;
ioctlv->vecs[1].len = sizeof(ioctlv->query);
int32_t res = IOS_Ioctlv(socketInit(), 0x26, 1, 1, ioctlv->vecs);
memcpy(query, &ioctlv->query, sizeof(*query));
// translate pointers
query->hostent.h_aliases = query->alist;
for (int i = 0; i < 2; i++) {
if (query->alist[i]) {
query->alist[i] = (char*) ((uint32_t) query + ((uint32_t) query->alist[i] - (uint32_t) query->query_ios_ptr));
}
}
query->hostent.h_name = (char*) ((uint32_t) query + ((uint32_t) query->hostent.h_name - (uint32_t) query->query_ios_ptr));
IOS_HeapFree(CROSS_PROCESS_HEAP_ID, ioctlv);
return res;
}
struct hostent* gethostbyname(const char* name)
{
if (!name || name[0] == '\0') {
h_errno = 3;
return NULL;
}
static struct dns_querys dns_entry;
do_dns_query(name, 1, 0, 0, &dns_entry);
if (!dns_entry.ipaddrs) {
h_errno = 1;
return NULL;
}
dns_entry.hostent.h_addrtype = AF_INET;
dns_entry.hostent.h_length = 4;
dns_entry.hostent.h_addr_list = dns_entry.addrptrs;
int i;
for (i = 0; i < dns_entry.ipaddrs; i++) {
dns_entry.addrptrs[i] = (char*) &dns_entry.ipaddr_list[i];
}
dns_entry.addrptrs[i] = NULL;
h_errno = 0;
return &dns_entry.hostent;
}