Skip to content

Commit a959af8

Browse files
ShelbyZedsiper
authored andcommitted
utils: fix support for ipv6 addresses
- IPv6 bracket validation - fix flb_utils_copy_host_sds - fix bracket finding logic Signed-off-by: Shelby Hagman <shelbyzh@amazon.com>
1 parent f760d58 commit a959af8

1 file changed

Lines changed: 205 additions & 38 deletions

File tree

src/flb_utils.c

Lines changed: 205 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1431,13 +1431,103 @@ static char *flb_utils_copy_host_sds(const char *string, int pos_init, int pos_e
14311431
if (string[pos_end-1] != ']') {
14321432
return NULL;
14331433
}
1434-
return flb_sds_create_len(string + pos_init + 1, pos_end - 1);
1434+
return flb_sds_create_len(string + pos_init + 1, pos_end - pos_init - 2);
14351435
}
14361436
else {
1437-
return flb_sds_create_len(string + pos_init, pos_end);
1437+
return flb_sds_create_len(string + pos_init, pos_end - pos_init);
14381438
}
14391439
}
14401440

1441+
/* Validate IPv6 bracket syntax in URL host part */
1442+
static int validate_ipv6_brackets(const char *p, const char **out_bracket)
1443+
{
1444+
const char *host_end;
1445+
const char *bracket = NULL;
1446+
const char *closing;
1447+
const char *query_or_fragment;
1448+
1449+
/* Only inspect the host portion (up to the first '/', '?', or '#') */
1450+
host_end = strchr(p, '/');
1451+
query_or_fragment = strpbrk(p, "?#");
1452+
1453+
/* Use the earliest delimiter found */
1454+
if (query_or_fragment && (!host_end || query_or_fragment < host_end)) {
1455+
host_end = query_or_fragment;
1456+
}
1457+
1458+
if (!host_end) {
1459+
host_end = p + strlen(p);
1460+
}
1461+
1462+
if (p[0] == '[') {
1463+
closing = memchr(p, ']', host_end - p);
1464+
if (!closing || closing == p + 1) {
1465+
/* Missing closing bracket or empty brackets [] */
1466+
return -1;
1467+
}
1468+
bracket = closing;
1469+
}
1470+
else {
1471+
/* Non-bracketed hosts must not contain ']' before the first '/' */
1472+
closing = memchr(p, ']', host_end - p);
1473+
if (closing) {
1474+
return -1;
1475+
}
1476+
}
1477+
1478+
if (out_bracket) {
1479+
*out_bracket = bracket;
1480+
}
1481+
return 0;
1482+
}
1483+
1484+
/* Helper to create URI with prepended '/' if it starts with '?' or '#' */
1485+
static char *create_uri_with_slash(const char *uri_part)
1486+
{
1487+
char *uri;
1488+
size_t uri_part_len;
1489+
1490+
if (!uri_part || *uri_part == '\0') {
1491+
return flb_strdup("/");
1492+
}
1493+
1494+
/* If URI starts with '?' or '#', prepend '/' */
1495+
if (*uri_part == '?' || *uri_part == '#') {
1496+
uri_part_len = strlen(uri_part);
1497+
/* Allocate space for '/' + uri_part + '\0' */
1498+
uri = flb_malloc(uri_part_len + 2);
1499+
if (!uri) {
1500+
return NULL;
1501+
}
1502+
uri[0] = '/';
1503+
/* +1 to include '\0' */
1504+
memcpy(uri + 1, uri_part, uri_part_len + 1);
1505+
return uri;
1506+
}
1507+
1508+
/* URI already starts with '/' or is a normal path */
1509+
return flb_strdup(uri_part);
1510+
}
1511+
1512+
/* SDS version: Helper to create URI with prepended '/' if it starts with '?' or '#' */
1513+
static flb_sds_t create_uri_with_slash_sds(const char *uri_part)
1514+
{
1515+
char *result;
1516+
flb_sds_t uri;
1517+
1518+
/* Use the regular version to create the string */
1519+
result = create_uri_with_slash(uri_part);
1520+
if (!result) {
1521+
return NULL;
1522+
}
1523+
1524+
/* Convert to SDS */
1525+
uri = flb_sds_create(result);
1526+
flb_free(result);
1527+
1528+
return uri;
1529+
}
1530+
14411531
int flb_utils_url_split(const char *in_url, char **out_protocol,
14421532
char **out_host, char **out_port, char **out_uri)
14431533
{
@@ -1448,6 +1538,7 @@ int flb_utils_url_split(const char *in_url, char **out_protocol,
14481538
char *p;
14491539
char *tmp;
14501540
char *sep;
1541+
const char *bracket = NULL;
14511542

14521543
/* Protocol */
14531544
p = strstr(in_url, "://");
@@ -1467,48 +1558,81 @@ int flb_utils_url_split(const char *in_url, char **out_protocol,
14671558
/* Advance position after protocol */
14681559
p += 3;
14691560

1470-
/* Check for first '/' */
1561+
/* Validate IPv6 brackets */
14711562
sep = strchr(p, '/');
1472-
tmp = strchr(p, ':');
1563+
if (validate_ipv6_brackets(p, &bracket) < 0) {
1564+
flb_errno();
1565+
goto error;
1566+
}
14731567

1474-
/* Validate port separator is found before the first slash */
1475-
if (sep && tmp) {
1476-
if (tmp > sep) {
1477-
tmp = NULL;
1478-
}
1568+
/* Compute end of host segment (before '/', '?', or '#') */
1569+
const char *host_end = sep;
1570+
const char *qf = strpbrk(p, "?#");
1571+
1572+
if (!host_end || (qf && qf < host_end)) {
1573+
host_end = qf;
1574+
}
1575+
if (!host_end) {
1576+
host_end = p + strlen(p);
1577+
}
1578+
1579+
if (bracket) {
1580+
/* For bracketed IPv6, only ports after ']' and before URI delimiters are valid */
1581+
tmp = memchr(bracket, ':', host_end - bracket);
1582+
}
1583+
else {
1584+
/* Non-IPv6: limit ':' search to the host portion */
1585+
tmp = memchr(p, ':', host_end - p);
14791586
}
14801587

1588+
/* Extract host if port separator was found */
14811589
if (tmp) {
14821590
host = flb_copy_host(p, 0, tmp - p);
14831591
if (!host) {
14841592
flb_errno();
14851593
goto error;
14861594
}
14871595
p = tmp + 1;
1596+
}
14881597

1489-
/* Look for an optional URI */
1490-
tmp = strchr(p, '/');
1598+
/* Find URI delimiter (/, ?, or #) */
1599+
tmp = strpbrk(p, "/?#");
1600+
1601+
if (!host) {
1602+
/* No port: extract host */
14911603
if (tmp) {
1492-
port = mk_string_copy_substr(p, 0, tmp - p);
1493-
uri = flb_strdup(tmp);
1604+
host = flb_copy_host(p, 0, tmp - p);
14941605
}
14951606
else {
1496-
port = flb_strdup(p);
1497-
uri = flb_strdup("/");
1607+
host = flb_copy_host(p, 0, strlen(p));
1608+
}
1609+
if (!host) {
1610+
flb_errno();
1611+
goto error;
14981612
}
14991613
}
15001614
else {
1501-
tmp = strchr(p, '/');
1615+
/* Port exists: extract port */
15021616
if (tmp) {
1503-
host = flb_copy_host(p, 0, tmp - p);
1504-
uri = flb_strdup(tmp);
1617+
port = mk_string_copy_substr(p, 0, tmp - p);
15051618
}
15061619
else {
1507-
host = flb_copy_host(p, 0, strlen(p));
1508-
uri = flb_strdup("/");
1620+
port = flb_strdup(p);
15091621
}
15101622
}
15111623

1624+
/* Extract URI */
1625+
if (tmp) {
1626+
uri = create_uri_with_slash(tmp);
1627+
if (!uri) {
1628+
flb_errno();
1629+
goto error;
1630+
}
1631+
}
1632+
else {
1633+
uri = flb_strdup("/");
1634+
}
1635+
15121636
if (!port) {
15131637
if (strcmp(protocol, "http") == 0) {
15141638
port = flb_strdup("80");
@@ -1529,6 +1653,15 @@ int flb_utils_url_split(const char *in_url, char **out_protocol,
15291653
if (protocol) {
15301654
flb_free(protocol);
15311655
}
1656+
if (host) {
1657+
flb_free(host);
1658+
}
1659+
if (port) {
1660+
flb_free(port);
1661+
}
1662+
if (uri) {
1663+
flb_free(uri);
1664+
}
15321665

15331666
return -1;
15341667
}
@@ -1544,6 +1677,7 @@ int flb_utils_url_split_sds(const flb_sds_t in_url, flb_sds_t *out_protocol,
15441677
char *p = NULL;
15451678
char *tmp = NULL;
15461679
char *sep = NULL;
1680+
const char *bracket = NULL;
15471681

15481682
/* Protocol */
15491683
p = strstr(in_url, "://");
@@ -1563,47 +1697,80 @@ int flb_utils_url_split_sds(const flb_sds_t in_url, flb_sds_t *out_protocol,
15631697
/* Advance position after protocol */
15641698
p += 3;
15651699

1566-
/* Check for first '/' */
1700+
/* Validate IPv6 brackets */
15671701
sep = strchr(p, '/');
1568-
tmp = strchr(p, ':');
1702+
if (validate_ipv6_brackets(p, &bracket) < 0) {
1703+
flb_errno();
1704+
goto error;
1705+
}
15691706

1570-
/* Validate port separator is found before the first slash */
1571-
if (sep && tmp) {
1572-
if (tmp > sep) {
1573-
tmp = NULL;
1574-
}
1707+
/* Compute end of host segment (before '/', '?', or '#') */
1708+
const char *host_end = sep;
1709+
const char *qf = strpbrk(p, "?#");
1710+
1711+
if (!host_end || (qf && qf < host_end)) {
1712+
host_end = qf;
1713+
}
1714+
if (!host_end) {
1715+
host_end = p + strlen(p);
15751716
}
15761717

1718+
if (bracket) {
1719+
/* For bracketed IPv6, only ports after ']' and before URI delimiters are valid */
1720+
tmp = memchr(bracket, ':', host_end - bracket);
1721+
}
1722+
else {
1723+
/* Non-IPv6: limit ':' search to the host portion */
1724+
tmp = memchr(p, ':', host_end - p);
1725+
}
1726+
1727+
/* Extract host if port separator was found */
15771728
if (tmp) {
15781729
host = flb_utils_copy_host_sds(p, 0, tmp - p);
15791730
if (!host) {
15801731
flb_errno();
15811732
goto error;
15821733
}
15831734
p = tmp + 1;
1735+
}
15841736

1585-
/* Look for an optional URI */
1586-
tmp = strchr(p, '/');
1737+
/* Find URI delimiter (/, ?, or #) */
1738+
tmp = strpbrk(p, "/?#");
1739+
1740+
if (!host) {
1741+
/* No port: extract host */
15871742
if (tmp) {
1588-
port = flb_sds_create_len(p, tmp - p);
1589-
uri = flb_sds_create(tmp);
1743+
host = flb_utils_copy_host_sds(p, 0, tmp - p);
15901744
}
15911745
else {
1592-
port = flb_sds_create_len(p, strlen(p));
1593-
uri = flb_sds_create("/");
1746+
host = flb_utils_copy_host_sds(p, 0, strlen(p));
1747+
}
1748+
if (!host) {
1749+
flb_errno();
1750+
goto error;
15941751
}
15951752
}
15961753
else {
1597-
tmp = strchr(p, '/');
1754+
/* Port exists: extract port */
15981755
if (tmp) {
1599-
host = flb_utils_copy_host_sds(p, 0, tmp - p);
1600-
uri = flb_sds_create(tmp);
1756+
port = flb_sds_create_len(p, tmp - p);
16011757
}
16021758
else {
1603-
host = flb_utils_copy_host_sds(p, 0, strlen(p));
1604-
uri = flb_sds_create("/");
1759+
port = flb_sds_create_len(p, strlen(p));
1760+
}
1761+
}
1762+
1763+
/* Extract URI */
1764+
if (tmp) {
1765+
uri = create_uri_with_slash_sds(tmp);
1766+
if (!uri) {
1767+
flb_errno();
1768+
goto error;
16051769
}
16061770
}
1771+
else {
1772+
uri = flb_sds_create("/");
1773+
}
16071774

16081775
if (!port) {
16091776
if (strcmp(protocol, "http") == 0) {

0 commit comments

Comments
 (0)