From 589027568b56f46641422802458ad51d7c33fdb1 Mon Sep 17 00:00:00 2001 From: Erik Ekman Date: Tue, 24 Aug 2021 23:32:57 +0200 Subject: [PATCH] Add option to allow wildcard as start of topdomain --- src/common.c | 14 +++++++++- src/common.h | 2 +- src/iodine.c | 2 +- src/iodined.c | 2 +- tests/common.c | 76 ++++++++++++++++++++++++++++++++++++-------------- 5 files changed, 71 insertions(+), 25 deletions(-) diff --git a/src/common.c b/src/common.c index 3abafac..7465eb5 100644 --- a/src/common.c +++ b/src/common.c @@ -332,7 +332,7 @@ read_password(char *buf, size_t len) } int -check_topdomain(char *str, char **errormsg) +check_topdomain(char *str, int allow_wildcard, char **errormsg) { int i; int dots = 0; @@ -370,6 +370,18 @@ check_topdomain(char *str, char **errormsg) if ((str[i] >= 'a' && str[i] <= 'z') || (str[i] >= 'A' && str[i] <= 'Z') || isdigit(str[i]) || str[i] == '-' || str[i] == '.') { continue; + } else if (allow_wildcard && str[i] == '*') { + /* First char allowed to be wildcard, if followed by dot */ + if (i == 0) { + if (str[i+1] == '.') { + continue; + } + if (errormsg) *errormsg = "Wildcard (*) must be followed by dot"; + return 1; + } else { + if (errormsg) *errormsg = "Wildcard (*) only allowed as first char"; + return 1; + } } else { if (errormsg) *errormsg = "Contains illegal character (allowed: [a-zA-Z0-9-.])"; return 1; diff --git a/src/common.h b/src/common.h index f9adb0c..87800ed 100644 --- a/src/common.h +++ b/src/common.h @@ -126,7 +126,7 @@ void do_pidfile(char *); void read_password(char*, size_t); -int check_topdomain(char *, char **); +int check_topdomain(char *, int, char **); #if defined(WINDOWS32) || defined(ANDROID) #ifndef ANDROID diff --git a/src/iodine.c b/src/iodine.c index 65aa0d7..fbb6481 100644 --- a/src/iodine.c +++ b/src/iodine.c @@ -317,7 +317,7 @@ int main(int argc, char **argv) /* NOTREACHED */ } - if (check_topdomain(topdomain, &errormsg)) { + if (check_topdomain(topdomain, 0, &errormsg)) { warnx("Invalid topdomain: %s", errormsg); usage(); /* NOTREACHED */ diff --git a/src/iodined.c b/src/iodined.c index fb36ff5..0212475 100644 --- a/src/iodined.c +++ b/src/iodined.c @@ -2543,7 +2543,7 @@ main(int argc, char **argv) } topdomain = strdup(argv[1]); - if (check_topdomain(topdomain, &errormsg)) { + if (check_topdomain(topdomain, 0, &errormsg)) { warnx("Invalid topdomain: %s", errormsg); usage(); /* NOTREACHED */ diff --git a/tests/common.c b/tests/common.c index 79408f0..277fd5a 100644 --- a/tests/common.c +++ b/tests/common.c @@ -25,15 +25,18 @@ START_TEST(test_topdomain_ok) { char *error = NULL; - ck_assert(check_topdomain("foo.0123456789.qwertyuiop.asdfghjkl.zxcvbnm.com", &error) == 0); + ck_assert(check_topdomain("foo.0123456789.qwertyuiop.asdfghjkl.zxcvbnm.com", 0, &error) == 0); + ck_assert(error == NULL); + /* Allowing wildcard */ + ck_assert(check_topdomain("foo.0123456789.qwertyuiop.asdfghjkl.zxcvbnm.com", 1, &error) == 0); ck_assert(error == NULL); /* Not allowed to start with dot */ - ck_assert(check_topdomain(".foo.0123456789.qwertyuiop.asdfghjkl.zxcvbnm.com", &error)); + ck_assert(check_topdomain(".foo.0123456789.qwertyuiop.asdfghjkl.zxcvbnm.com", 0, &error)); ck_assert_str_eq("Starts with a dot", error); /* Test missing error msg ptr */ - ck_assert(check_topdomain(".foo", NULL)); + ck_assert(check_topdomain(".foo", 0, NULL)); } END_TEST @@ -42,33 +45,33 @@ START_TEST(test_topdomain_length) char *error; /* Test empty and too short */ - ck_assert(check_topdomain("", &error)); + ck_assert(check_topdomain("", 0, &error)); ck_assert_str_eq("Too short (< 3)", error); error = NULL; - ck_assert(check_topdomain("a", &error)); + ck_assert(check_topdomain("a", 0, &error)); ck_assert_str_eq("Too short (< 3)", error); error = NULL; - ck_assert(check_topdomain(".a", &error)); + ck_assert(check_topdomain(".a", 0, &error)); ck_assert_str_eq("Too short (< 3)", error); error = NULL; - ck_assert(check_topdomain("a.", &error)); + ck_assert(check_topdomain("a.", 0, &error)); ck_assert_str_eq("Too short (< 3)", error); error = NULL; - ck_assert(check_topdomain("ab", &error)); + ck_assert(check_topdomain("ab", 0, &error)); ck_assert_str_eq("Too short (< 3)", error); error = NULL; - ck_assert(check_topdomain("a.b", &error) == 0); + ck_assert(check_topdomain("a.b", 0, &error) == 0); /* Test too long (over 128, need rest of space for data) */ ck_assert(check_topdomain( "abcd12345.abcd12345.abcd12345.abcd12345.abcd12345." "abcd12345.abcd12345.abcd12345.abcd12345.abcd12345." - "abcd12345.abcd12345.foo129xxx", &error)); + "abcd12345.abcd12345.foo129xxx", 0, &error)); ck_assert_str_eq("Too long (> 128)", error); ck_assert(check_topdomain( "abcd12345.abcd12345.abcd12345.abcd12345.abcd12345." "abcd12345.abcd12345.abcd12345.abcd12345.abcd12345." - "abcd12345.abcd12345.foo128xx", &error) == 0); + "abcd12345.abcd12345.foo128xx", 0, &error) == 0); } END_TEST @@ -77,39 +80,69 @@ START_TEST(test_topdomain_chunks) char *error; /* Must have at least one dot */ - ck_assert(check_topdomain("abcde.gh", &error) == 0); - ck_assert(check_topdomain("abcdefgh", &error)); + ck_assert(check_topdomain("abcde.gh", 0, &error) == 0); + ck_assert(check_topdomain("abcdefgh", 0, &error)); ck_assert_str_eq("No dots", error); /* Not two consecutive dots */ - ck_assert(check_topdomain("abc..defgh", &error)); + ck_assert(check_topdomain("abc..defgh", 0, &error)); ck_assert_str_eq("Consecutive dots", error); /* Not end with a dots */ - ck_assert(check_topdomain("abc.defgh.", &error)); + ck_assert(check_topdomain("abc.defgh.", 0, &error)); ck_assert_str_eq("Ends with a dot", error); /* No chunk longer than 63 chars */ ck_assert(check_topdomain("123456789012345678901234567890" - "123456789012345678901234567890333.com", &error) == 0); + "123456789012345678901234567890333.com", 0, &error) == 0); ck_assert(check_topdomain("123456789012345678901234567890" - "1234567890123456789012345678904444.com", &error)); + "1234567890123456789012345678904444.com", 0, &error)); ck_assert_str_eq("Too long domain part (> 63)", error); ck_assert(check_topdomain("abc.123456789012345678901234567890" - "123456789012345678901234567890333.com", &error) == 0); + "123456789012345678901234567890333.com", 0, &error) == 0); ck_assert(check_topdomain("abc.123456789012345678901234567890" - "1234567890123456789012345678904444.com", &error)); + "1234567890123456789012345678904444.com", 0, &error)); ck_assert_str_eq("Too long domain part (> 63)", error); ck_assert(check_topdomain("abc.123456789012345678901234567890" - "123456789012345678901234567890333", &error) == 0); + "123456789012345678901234567890333", 0, &error) == 0); ck_assert(check_topdomain("abc.123456789012345678901234567890" - "1234567890123456789012345678904444", &error)); + "1234567890123456789012345678904444", 0, &error)); ck_assert_str_eq("Too long domain part (> 63)", error); } END_TEST +START_TEST(test_topdomain_wild) +{ + char *error = NULL; + + ck_assert(check_topdomain("*.a", 0, &error) == 1); + ck_assert_str_eq("Contains illegal character (allowed: [a-zA-Z0-9-.])", error); + error = NULL; + ck_assert(check_topdomain("*.a", 1, &error) == 0); + ck_assert(error == NULL); + + ck_assert(check_topdomain("b*.a", 0, &error) == 1); + ck_assert_str_eq("Contains illegal character (allowed: [a-zA-Z0-9-.])", error); + error = NULL; + ck_assert(check_topdomain("b*.a", 1, &error) == 1); + ck_assert_str_eq("Wildcard (*) only allowed as first char", error); + + ck_assert(check_topdomain("*b.a", 0, &error) == 1); + ck_assert_str_eq("Contains illegal character (allowed: [a-zA-Z0-9-.])", error); + error = NULL; + ck_assert(check_topdomain("*b.a", 1, &error) == 1); + ck_assert_str_eq("Wildcard (*) must be followed by dot", error); + + ck_assert(check_topdomain("*.*.a", 0, &error) == 1); + ck_assert_str_eq("Contains illegal character (allowed: [a-zA-Z0-9-.])", error); + error = NULL; + ck_assert(check_topdomain("*.*.a", 1, &error) == 1); + ck_assert_str_eq("Wildcard (*) only allowed as first char", error); +} +END_TEST + START_TEST(test_parse_format_ipv4) { char *host = "192.168.2.10"; @@ -211,6 +244,7 @@ test_common_create_tests() tcase_add_test(tc, test_topdomain_ok); tcase_add_test(tc, test_topdomain_length); tcase_add_test(tc, test_topdomain_chunks); + tcase_add_test(tc, test_topdomain_wild); tcase_add_test(tc, test_parse_format_ipv4); tcase_add_test(tc, test_parse_format_ipv4_listen_all);