Fix #2192 - honor addr%scopeid ipv6 notation

This commit is contained in:
cpq 2023-09-27 07:31:01 +01:00
parent a628a05efb
commit 46ecb07fc8
6 changed files with 74 additions and 39 deletions

View File

@ -4099,6 +4099,7 @@ static bool mg_v4mapped(struct mg_str str, struct mg_addr *addr) {
static bool mg_aton6(struct mg_str str, struct mg_addr *addr) { static bool mg_aton6(struct mg_str str, struct mg_addr *addr) {
size_t i, j = 0, n = 0, dc = 42; size_t i, j = 0, n = 0, dc = 42;
addr->scope_id = 0;
if (str.len > 2 && str.ptr[0] == '[') str.ptr++, str.len -= 2; if (str.len > 2 && str.ptr[0] == '[') str.ptr++, str.len -= 2;
if (mg_v4mapped(str, addr)) return true; if (mg_v4mapped(str, addr)) return true;
for (i = 0; i < str.len; i++) { for (i = 0; i < str.len; i++) {
@ -4107,7 +4108,7 @@ static bool mg_aton6(struct mg_str str, struct mg_addr *addr) {
(str.ptr[i] >= 'A' && str.ptr[i] <= 'F')) { (str.ptr[i] >= 'A' && str.ptr[i] <= 'F')) {
unsigned long val; unsigned long val;
if (i > j + 3) return false; if (i > j + 3) return false;
// MG_DEBUG(("%zu %zu [%.*s]", i, j, (int) (i - j + 1), &str.ptr[j])); // MG_DEBUG(("%lu %lu [%.*s]", i, j, (int) (i - j + 1), &str.ptr[j]));
val = mg_unhexn(&str.ptr[j], i - j + 1); val = mg_unhexn(&str.ptr[j], i - j + 1);
addr->ip[n] = (uint8_t) ((val >> 8) & 255); addr->ip[n] = (uint8_t) ((val >> 8) & 255);
addr->ip[n + 1] = (uint8_t) (val & 255); addr->ip[n + 1] = (uint8_t) (val & 255);
@ -4121,6 +4122,11 @@ static bool mg_aton6(struct mg_str str, struct mg_addr *addr) {
} }
if (n > 14) return false; if (n > 14) return false;
addr->ip[n] = addr->ip[n + 1] = 0; // For trailing :: addr->ip[n] = addr->ip[n + 1] = 0; // For trailing ::
} else if (str.ptr[i] == '%') { // Scope ID
for (i = i + 1; i < str.len; i++) {
if (str.ptr[i] < '0' || str.ptr[i] > '9') return false;
addr->scope_id *= 10, addr->scope_id += (uint8_t) (str.ptr[i] - '0');
}
} else { } else {
return false; return false;
} }
@ -6309,6 +6315,7 @@ static socklen_t tousa(struct mg_addr *a, union usa *usa) {
if (a->is_ip6) { if (a->is_ip6) {
usa->sin.sin_family = AF_INET6; usa->sin.sin_family = AF_INET6;
usa->sin6.sin6_port = a->port; usa->sin6.sin6_port = a->port;
usa->sin6.sin6_scope_id = a->scope_id;
memcpy(&usa->sin6.sin6_addr, a->ip, sizeof(a->ip)); memcpy(&usa->sin6.sin6_addr, a->ip, sizeof(a->ip));
len = sizeof(usa->sin6); len = sizeof(usa->sin6);
} }
@ -6324,6 +6331,7 @@ static void tomgaddr(union usa *usa, struct mg_addr *a, bool is_ip6) {
if (is_ip6) { if (is_ip6) {
memcpy(a->ip, &usa->sin6.sin6_addr, sizeof(a->ip)); memcpy(a->ip, &usa->sin6.sin6_addr, sizeof(a->ip));
a->port = usa->sin6.sin6_port; a->port = usa->sin6.sin6_port;
a->scope_id = (uint8_t) usa->sin6.sin6_scope_id;
} }
#endif #endif
} }

View File

@ -1180,9 +1180,10 @@ struct mg_dns {
}; };
struct mg_addr { struct mg_addr {
uint8_t ip[16]; // Holds IPv4 or IPv6 address, in network byte order uint8_t ip[16]; // Holds IPv4 or IPv6 address, in network byte order
uint16_t port; // TCP or UDP port in network byte order uint16_t port; // TCP or UDP port in network byte order
bool is_ip6; // True when address is IPv6 address uint8_t scope_id; // IPv6 scope ID
bool is_ip6; // True when address is IPv6 address
}; };
struct mg_mgr { struct mg_mgr {

View File

@ -77,6 +77,7 @@ static bool mg_v4mapped(struct mg_str str, struct mg_addr *addr) {
static bool mg_aton6(struct mg_str str, struct mg_addr *addr) { static bool mg_aton6(struct mg_str str, struct mg_addr *addr) {
size_t i, j = 0, n = 0, dc = 42; size_t i, j = 0, n = 0, dc = 42;
addr->scope_id = 0;
if (str.len > 2 && str.ptr[0] == '[') str.ptr++, str.len -= 2; if (str.len > 2 && str.ptr[0] == '[') str.ptr++, str.len -= 2;
if (mg_v4mapped(str, addr)) return true; if (mg_v4mapped(str, addr)) return true;
for (i = 0; i < str.len; i++) { for (i = 0; i < str.len; i++) {
@ -85,7 +86,7 @@ static bool mg_aton6(struct mg_str str, struct mg_addr *addr) {
(str.ptr[i] >= 'A' && str.ptr[i] <= 'F')) { (str.ptr[i] >= 'A' && str.ptr[i] <= 'F')) {
unsigned long val; unsigned long val;
if (i > j + 3) return false; if (i > j + 3) return false;
// MG_DEBUG(("%zu %zu [%.*s]", i, j, (int) (i - j + 1), &str.ptr[j])); // MG_DEBUG(("%lu %lu [%.*s]", i, j, (int) (i - j + 1), &str.ptr[j]));
val = mg_unhexn(&str.ptr[j], i - j + 1); val = mg_unhexn(&str.ptr[j], i - j + 1);
addr->ip[n] = (uint8_t) ((val >> 8) & 255); addr->ip[n] = (uint8_t) ((val >> 8) & 255);
addr->ip[n + 1] = (uint8_t) (val & 255); addr->ip[n + 1] = (uint8_t) (val & 255);
@ -99,6 +100,11 @@ static bool mg_aton6(struct mg_str str, struct mg_addr *addr) {
} }
if (n > 14) return false; if (n > 14) return false;
addr->ip[n] = addr->ip[n + 1] = 0; // For trailing :: addr->ip[n] = addr->ip[n + 1] = 0; // For trailing ::
} else if (str.ptr[i] == '%') { // Scope ID
for (i = i + 1; i < str.len; i++) {
if (str.ptr[i] < '0' || str.ptr[i] > '9') return false;
addr->scope_id *= 10, addr->scope_id += (uint8_t) (str.ptr[i] - '0');
}
} else { } else {
return false; return false;
} }

View File

@ -13,9 +13,10 @@ struct mg_dns {
}; };
struct mg_addr { struct mg_addr {
uint8_t ip[16]; // Holds IPv4 or IPv6 address, in network byte order uint8_t ip[16]; // Holds IPv4 or IPv6 address, in network byte order
uint16_t port; // TCP or UDP port in network byte order uint16_t port; // TCP or UDP port in network byte order
bool is_ip6; // True when address is IPv6 address uint8_t scope_id; // IPv6 scope ID
bool is_ip6; // True when address is IPv6 address
}; };
struct mg_mgr { struct mg_mgr {

View File

@ -62,6 +62,7 @@ static socklen_t tousa(struct mg_addr *a, union usa *usa) {
if (a->is_ip6) { if (a->is_ip6) {
usa->sin.sin_family = AF_INET6; usa->sin.sin_family = AF_INET6;
usa->sin6.sin6_port = a->port; usa->sin6.sin6_port = a->port;
usa->sin6.sin6_scope_id = a->scope_id;
memcpy(&usa->sin6.sin6_addr, a->ip, sizeof(a->ip)); memcpy(&usa->sin6.sin6_addr, a->ip, sizeof(a->ip));
len = sizeof(usa->sin6); len = sizeof(usa->sin6);
} }
@ -77,6 +78,7 @@ static void tomgaddr(union usa *usa, struct mg_addr *a, bool is_ip6) {
if (is_ip6) { if (is_ip6) {
memcpy(a->ip, &usa->sin6.sin6_addr, sizeof(a->ip)); memcpy(a->ip, &usa->sin6.sin6_addr, sizeof(a->ip));
a->port = usa->sin6.sin6_port; a->port = usa->sin6.sin6_port;
a->scope_id = (uint8_t) usa->sin6.sin6_scope_id;
} }
#endif #endif
} }

View File

@ -766,8 +766,8 @@ static int fetch(struct mg_mgr *mgr, char *buf, const char *url,
if (strstr(url, "127.0.0.1") != NULL) { if (strstr(url, "127.0.0.1") != NULL) {
// Local connection, use self-signed certificates // Local connection, use self-signed certificates
opts.ca = mg_str(s_tls_ca); opts.ca = mg_str(s_tls_ca);
//opts.cert = mg_str(s_tls_cert); // opts.cert = mg_str(s_tls_cert);
//opts.key = mg_str(s_tls_key); // opts.key = mg_str(s_tls_key);
} }
mg_tls_init(c, &opts); mg_tls_init(c, &opts);
} }
@ -1205,7 +1205,7 @@ static void test_tls(void) {
char buf[FETCH_BUF_SIZE]; char buf[FETCH_BUF_SIZE];
struct mg_tls_opts opts; struct mg_tls_opts opts;
memset(&opts, 0, sizeof(opts)); memset(&opts, 0, sizeof(opts));
//opts.ca = mg_str(s_tls_ca); // opts.ca = mg_str(s_tls_ca);
opts.cert = mg_str(s_tls_cert); opts.cert = mg_str(s_tls_cert);
opts.key = mg_str(s_tls_key); opts.key = mg_str(s_tls_key);
mg_mgr_init(&mgr); mg_mgr_init(&mgr);
@ -1263,7 +1263,7 @@ static void test_http_client(void) {
ASSERT(c != NULL); ASSERT(c != NULL);
if (c != NULL) { if (c != NULL) {
opts.ca = mg_str_n(data, size); opts.ca = mg_str_n(data, size);
//opts.name = mg_url_host(url); // opts.name = mg_url_host(url);
mg_tls_init(c, &opts); mg_tls_init(c, &opts);
} }
for (i = 0; i < 1500 && ok <= 0; i++) mg_mgr_poll(&mgr, 1); for (i = 0; i < 1500 && ok <= 0; i++) mg_mgr_poll(&mgr, 1);
@ -1283,7 +1283,7 @@ static void test_http_client(void) {
ASSERT(ok == 777); ASSERT(ok == 777);
mg_mgr_poll(&mgr, 1); mg_mgr_poll(&mgr, 1);
opts.name = mg_str("cesanta.com"); opts.name = mg_str("cesanta.com");
opts.ca = mg_str(""); opts.ca = mg_str("");
c = mg_http_connect(&mgr, "https://cesanta.com", f3, &ok); c = mg_http_connect(&mgr, "https://cesanta.com", f3, &ok);
mg_tls_init(c, &opts); mg_tls_init(c, &opts);
@ -2158,10 +2158,11 @@ static void test_dns(void) {
} }
static void test_util(void) { static void test_util(void) {
const char *e;
char buf[100], *p, *s; char buf[100], *p, *s;
struct mg_addr a; struct mg_addr a;
uint32_t ipv4; uint32_t ipv4;
memset(&a, 0, sizeof(a)); memset(&a, 0xa5, sizeof(a));
ASSERT(mg_file_printf(&mg_fs_posix, "data.txt", "%s", "hi") == true); ASSERT(mg_file_printf(&mg_fs_posix, "data.txt", "%s", "hi") == true);
// if (system("ls -l") != 0) (void) 0; // if (system("ls -l") != 0) (void) 0;
ASSERT((p = mg_file_read(&mg_fs_posix, "data.txt", NULL)) != NULL); ASSERT((p = mg_file_read(&mg_fs_posix, "data.txt", NULL)) != NULL);
@ -2177,57 +2178,73 @@ static void test_util(void) {
memcpy(&ipv4, a.ip, sizeof(ipv4)); memcpy(&ipv4, a.ip, sizeof(ipv4));
ASSERT(ipv4 == mg_htonl(0x7f000001)); ASSERT(ipv4 == mg_htonl(0x7f000001));
memset(a.ip, 0xa5, sizeof(a.ip));
ASSERT(mg_aton(mg_str("1:2:3:4:5:6:7:8"), &a) == true); ASSERT(mg_aton(mg_str("1:2:3:4:5:6:7:8"), &a) == true);
ASSERT(a.is_ip6 == true); ASSERT(a.is_ip6 == true);
ASSERT( e = "\x00\x01\x00\x02\x00\x03\x00\x04\x00\x05\x00\x06\x00\x07\x00\x08";
memcmp(a.ip, ASSERT(memcmp(a.ip, e, sizeof(a.ip)) == 0);
"\x00\x01\x00\x02\x00\x03\x00\x04\x00\x05\x00\x06\x00\x07\x00\x08",
sizeof(a.ip)) == 0); memset(a.ip, 0xa5, sizeof(a.ip));
ASSERT(mg_aton(mg_str("1:2::3"), &a) == true);
ASSERT(a.is_ip6 == true);
e = "\x00\x01\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03";
ASSERT(memcmp(a.ip, e, sizeof(a.ip)) == 0);
memset(a.ip, 0xaa, sizeof(a.ip)); memset(a.ip, 0xaa, sizeof(a.ip));
ASSERT(mg_aton(mg_str("1::1"), &a) == true); ASSERT(mg_aton(mg_str("1::1"), &a) == true);
ASSERT(a.is_ip6 == true); ASSERT(a.is_ip6 == true);
ASSERT( e = "\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01";
memcmp(a.ip, ASSERT(memcmp(a.ip, e, sizeof(a.ip)) == 0);
"\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01",
sizeof(a.ip)) == 0);
memset(a.ip, 0xaa, sizeof(a.ip)); memset(a.ip, 0xaa, sizeof(a.ip));
ASSERT(mg_aton(mg_str("::fFff:1.2.3.4"), &a) == true); ASSERT(mg_aton(mg_str("::fFff:1.2.3.4"), &a) == true);
ASSERT(a.is_ip6 == true); ASSERT(a.is_ip6 == true);
ASSERT(memcmp(a.ip, e = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x01\x02\x03\x04";
"\x00\x00\x00\x00\x00\x00\x00\x00" ASSERT(memcmp(a.ip, e, sizeof(a.ip)) == 0);
"\x00\x00\xff\xff\x01\x02\x03\x04",
sizeof(a.ip)) == 0);
memset(a.ip, 0xaa, sizeof(a.ip)); memset(a.ip, 0xaa, sizeof(a.ip));
ASSERT(mg_aton(mg_str("::1"), &a) == true); ASSERT(mg_aton(mg_str("::1"), &a) == true);
ASSERT(a.is_ip6 == true); ASSERT(a.is_ip6 == true);
ASSERT( ASSERT(a.scope_id == 0);
memcmp(a.ip, e = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01";
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01", ASSERT(memcmp(a.ip, e, sizeof(a.ip)) == 0);
sizeof(a.ip)) == 0);
memset(a.ip, 0xaa, sizeof(a.ip)); memset(a.ip, 0xaa, sizeof(a.ip));
ASSERT(mg_aton(mg_str("1::"), &a) == true); ASSERT(mg_aton(mg_str("1::"), &a) == true);
ASSERT(a.is_ip6 == true); ASSERT(a.is_ip6 == true);
ASSERT( e = "\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
memcmp(a.ip, ASSERT(memcmp(a.ip, e, sizeof(a.ip)) == 0);
"\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
sizeof(a.ip)) == 0);
memset(a.ip, 0xaa, sizeof(a.ip)); memset(a.ip, 0xaa, sizeof(a.ip));
ASSERT(mg_aton(mg_str("2001:4860:4860::8888"), &a) == true); ASSERT(mg_aton(mg_str("2001:4860:4860::8888"), &a) == true);
ASSERT(a.is_ip6 == true); ASSERT(a.is_ip6 == true);
ASSERT( e = "\x20\x01\x48\x60\x48\x60\x00\x00\x00\x00\x00\x00\x00\x00\x88\x88";
memcmp(a.ip, ASSERT(memcmp(a.ip, e, sizeof(a.ip)) == 0);
"\x20\x01\x48\x60\x48\x60\x00\x00\x00\x00\x00\x00\x00\x00\x88\x88",
sizeof(a.ip)) == 0);
ASSERT(strcmp(mg_hex("abc", 3, buf), "616263") == 0); ASSERT(strcmp(mg_hex("abc", 3, buf), "616263") == 0);
ASSERT(mg_url_decode("a=%", 3, buf, sizeof(buf), 0) < 0); ASSERT(mg_url_decode("a=%", 3, buf, sizeof(buf), 0) < 0);
ASSERT(mg_url_decode("&&&a=%", 6, buf, sizeof(buf), 0) < 0); ASSERT(mg_url_decode("&&&a=%", 6, buf, sizeof(buf), 0) < 0);
memset(a.ip, 0xaa, sizeof(a.ip));
ASSERT(mg_aton(mg_str("::1%1"), &a) == true);
ASSERT(a.is_ip6 == true);
ASSERT(a.scope_id == 1);
memset(a.ip, 0xaa, sizeof(a.ip));
ASSERT(mg_aton(mg_str("abcd::aabb:ccdd%17"), &a) == true);
ASSERT(a.is_ip6 == true);
ASSERT(a.scope_id == 17);
memset(a.ip, 0xaa, sizeof(a.ip));
ASSERT(mg_aton(mg_str("::1%17"), &a) == true);
ASSERT(a.is_ip6 == true);
ASSERT(a.scope_id == 17);
memset(a.ip, 0xaa, sizeof(a.ip));
ASSERT(mg_aton(mg_str("::1%255"), &a) == true);
ASSERT(a.is_ip6 == true);
ASSERT(a.scope_id == 255);
{ {
size_t n; size_t n;
ASSERT((n = mg_url_encode("", 0, buf, sizeof(buf))) == 0); ASSERT((n = mg_url_encode("", 0, buf, sizeof(buf))) == 0);
@ -2637,7 +2654,7 @@ static void test_udp(void) {
} }
static void test_check_ip_acl(void) { static void test_check_ip_acl(void) {
struct mg_addr ip = {{1, 2, 3, 4}, 0, false}; // 1.2.3.4 struct mg_addr ip = {{1, 2, 3, 4}, 0, 0, false}; // 1.2.3.4
ASSERT(mg_check_ip_acl(mg_str(NULL), &ip) == 1); ASSERT(mg_check_ip_acl(mg_str(NULL), &ip) == 1);
ASSERT(mg_check_ip_acl(mg_str(""), &ip) == 1); ASSERT(mg_check_ip_acl(mg_str(""), &ip) == 1);
ASSERT(mg_check_ip_acl(mg_str("invalid"), &ip) == -1); ASSERT(mg_check_ip_acl(mg_str("invalid"), &ip) == -1);