From acc77ebddd9f6f2aa42066958892bdab75ae2bd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Thu, 9 May 2024 10:13:04 +0800 Subject: [PATCH] PublicIP: add option `--publicip-ipv6` --- doc/json_schema.json | 5 +++++ src/common/networking.h | 1 + src/common/networking_linux.c | 2 +- src/common/networking_windows.c | 2 +- src/data/help.json | 8 ++++++++ src/detection/publicip/publicip.c | 25 +++++++++++++++---------- src/modules/publicip/option.h | 1 + src/modules/publicip/publicip.c | 19 +++++++++++++++++++ 8 files changed, 51 insertions(+), 12 deletions(-) diff --git a/doc/json_schema.json b/doc/json_schema.json index 8c3b3122d..c5cadfec5 100644 --- a/doc/json_schema.json +++ b/doc/json_schema.json @@ -1776,6 +1776,11 @@ "minimum": 0, "default": "disabled (0)" }, + "ipv6": { + "description": "Whether to use IPv6 for public IP detection server", + "type": "boolean", + "default": false + }, "key": { "$ref": "#/$defs/key" }, diff --git a/src/common/networking.h b/src/common/networking.h index cc8285cc5..8122e4eb0 100644 --- a/src/common/networking.h +++ b/src/common/networking.h @@ -22,6 +22,7 @@ typedef struct FFNetworkingState { #endif uint32_t timeout; + bool ipv6; } FFNetworkingState; const char* ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* host, const char* path, const char* headers); diff --git a/src/common/networking_linux.c b/src/common/networking_linux.c index 7a8054918..8bdd16bbd 100644 --- a/src/common/networking_linux.c +++ b/src/common/networking_linux.c @@ -14,7 +14,7 @@ static const char* connectAndSend(FFNetworkingState* state) struct addrinfo* addr; if(getaddrinfo(state->host.chars, "80", &(struct addrinfo) { - .ai_family = AF_INET, + .ai_family = state->ipv6 ? AF_INET6 : AF_INET, .ai_socktype = SOCK_STREAM, }, &addr) != 0) { diff --git a/src/common/networking_windows.c b/src/common/networking_windows.c index 27a884216..e6c8a4616 100644 --- a/src/common/networking_windows.c +++ b/src/common/networking_windows.c @@ -51,7 +51,7 @@ const char* ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* ho struct addrinfo* addr; if(getaddrinfo(host, "80", &(struct addrinfo) { - .ai_family = AF_INET, + .ai_family = state.ipv6 ? AF_INET6 : AF_INET, .ai_socktype = SOCK_STREAM, }, &addr) != 0) return "getaddrinfo() failed"; diff --git a/src/data/help.json b/src/data/help.json index 93e4132e1..7801aafbf 100644 --- a/src/data/help.json +++ b/src/data/help.json @@ -1348,6 +1348,14 @@ "type": "str" } }, + { + "long": "publicip-ipv6", + "desc": "Whether to use IPv6 for public IP detection server", + "arg": { + "type": "bool", + "default": false + } + }, { "long": "weather-location", "desc": "Set the location to be used", diff --git a/src/detection/publicip/publicip.c b/src/detection/publicip/publicip.c index a66d9f3d1..aa5f22419 100644 --- a/src/detection/publicip/publicip.c +++ b/src/detection/publicip/publicip.c @@ -2,21 +2,24 @@ #include "common/networking.h" #define FF_UNITIALIZED ((const char*)(uintptr_t) -1) -static FFNetworkingState state; -static const char* status = FF_UNITIALIZED; +static FFNetworkingState states[2]; +static const char* statuses[2] = { FF_UNITIALIZED, FF_UNITIALIZED }; void ffPreparePublicIp(FFPublicIpOptions* options) { - if (status != FF_UNITIALIZED) + FFNetworkingState* state = &states[options->ipv6]; + const char** status = &statuses[options->ipv6]; + if (*status != FF_UNITIALIZED) { fputs("Error: PublicIp module can only be used once due to internal limitations\n", stderr); exit(1); } - state.timeout = options->timeout; + state->timeout = options->timeout; + state->ipv6 = options->ipv6; if (options->url.length == 0) - status = ffNetworkingSendHttpRequest(&state, "ipinfo.io", "/json", NULL); + *status = ffNetworkingSendHttpRequest(state, options->ipv6 ? "v6.ipinfo.io" : "ipinfo.io", "/json", NULL); else { FF_STRBUF_AUTO_DESTROY host = ffStrbufCreateCopy(&options->url); @@ -40,7 +43,7 @@ void ffPreparePublicIp(FFPublicIpOptions* options) host.chars[pathStartIndex] = '\0'; } - status = ffNetworkingSendHttpRequest(&state, host.chars, path.length == 0 ? "/" : path.chars, NULL); + *status = ffNetworkingSendHttpRequest(state, host.chars, path.length == 0 ? "/" : path.chars, NULL); } } @@ -53,14 +56,16 @@ static inline void wrapYyjsonFree(yyjson_doc** doc) const char* ffDetectPublicIp(FFPublicIpOptions* options, FFPublicIpResult* result) { - if (status == FF_UNITIALIZED) + FFNetworkingState* state = &states[options->ipv6]; + const char** status = &statuses[options->ipv6]; + if (*status == FF_UNITIALIZED) ffPreparePublicIp(options); - if (status != NULL) - return status; + if (*status != NULL) + return *status; FF_STRBUF_AUTO_DESTROY response = ffStrbufCreateA(4096); - const char* error = ffNetworkingRecvHttpResponse(&state, &response); + const char* error = ffNetworkingRecvHttpResponse(state, &response); if (error == NULL) ffStrbufSubstrAfterFirstS(&response, "\r\n\r\n"); else diff --git a/src/modules/publicip/option.h b/src/modules/publicip/option.h index f05b95c23..427bab31a 100644 --- a/src/modules/publicip/option.h +++ b/src/modules/publicip/option.h @@ -11,4 +11,5 @@ typedef struct FFPublicIpOptions FFstrbuf url; uint32_t timeout; + bool ipv6; } FFPublicIpOptions; diff --git a/src/modules/publicip/publicip.c b/src/modules/publicip/publicip.c index eb5a41b0a..7de504790 100644 --- a/src/modules/publicip/publicip.c +++ b/src/modules/publicip/publicip.c @@ -59,6 +59,12 @@ bool ffParsePublicIpCommandOptions(FFPublicIpOptions* options, const char* key, return true; } + if (ffStrEqualsIgnCase(subKey, "ipv6")) + { + options->ipv6 = ffOptionParseBoolean(value); + return true; + } + return false; } @@ -87,6 +93,12 @@ void ffParsePublicIpJsonObject(FFPublicIpOptions* options, yyjson_val* module) continue; } + if (ffStrEqualsIgnCase(key, "ipv6")) + { + options->ipv6 = yyjson_get_bool(val); + continue; + } + ffPrintError(FF_PUBLICIP_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown JSON key %s", key); } } @@ -100,6 +112,12 @@ void ffGeneratePublicIpJsonConfig(FFPublicIpOptions* options, yyjson_mut_doc* do if (!ffStrbufEqual(&options->url, &defaultOptions.url)) yyjson_mut_obj_add_strbuf(doc, module, "url", &options->url); + + if (defaultOptions.timeout != options->timeout) + yyjson_mut_obj_add_uint(doc, module, "timeout", options->timeout); + + if (defaultOptions.ipv6 != options->ipv6) + yyjson_mut_obj_add_bool(doc, module, "ipv6", options->ipv6); } void ffGeneratePublicIpJsonResult(FFPublicIpOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module) @@ -148,6 +166,7 @@ void ffInitPublicIpOptions(FFPublicIpOptions* options) ffStrbufInit(&options->url); options->timeout = 0; + options->ipv6 = false; } void ffDestroyPublicIpOptions(FFPublicIpOptions* options)