diff --git a/src/common.c b/src/common.c index b4772bb..b15fb7a 100644 --- a/src/common.c +++ b/src/common.c @@ -324,34 +324,62 @@ read_password(char *buf, size_t len) } int -check_topdomain(char *str) +check_topdomain(char *str, char **errormsg) { int i; int dots = 0; int chunklen = 0; - if (strlen(str) < 3) + if (strlen(str) < 3) { + if (errormsg) *errormsg = "Too short (< 3)"; return 1; - if (strlen(str) > 128) + } + if (strlen(str) > 128) { + if (errormsg) *errormsg = "Too long (> 128)"; return 1; + } + + if (str[0] == '.') { + if (errormsg) *errormsg = "Starts with a dot"; + return 1; + } for( i = 0; i < strlen(str); i++) { if(str[i] == '.') { dots++; - /* This will also catch the case where topdomain starts with a dot */ - if (chunklen == 0 || chunklen > 63) + if (chunklen == 0) { + if (errormsg) *errormsg = "Consecutive dots"; return 1; + } + if (chunklen > 63) { + if (errormsg) *errormsg = "Too long domain part (> 63)"; + return 1; + } chunklen = 0; - } else + } else { chunklen++; - if( isalpha(str[i]) || isdigit(str[i]) || str[i] == '-' || str[i] == '.' ) + } + if( (str[i] >= 'a' && str[i] <= 'z') || (str[i] >= 'A' && str[i] <= 'Z') || + isdigit(str[i]) || str[i] == '-' || str[i] == '.' ) { continue; - else + } else { + if (errormsg) *errormsg = "Contains illegal character (allowed: [a-zA-Z0-9-.])"; return 1; + } } - if (chunklen == 0 || chunklen > 63 || dots == 0) + if (dots == 0) { + if (errormsg) *errormsg = "No dots"; return 1; + } + if (chunklen == 0) { + if (errormsg) *errormsg = "Ends with a dot"; + return 1; + } + if (chunklen > 63) { + if (errormsg) *errormsg = "Too long domain part (> 63)"; + return 1; + } return 0; } diff --git a/src/common.h b/src/common.h index bbadc9f..534996c 100644 --- a/src/common.h +++ b/src/common.h @@ -120,7 +120,7 @@ void do_pidfile(char *); void read_password(char*, size_t); -int check_topdomain(char *); +int check_topdomain(char *, char **); #if defined(WINDOWS32) || defined(ANDROID) #ifndef ANDROID diff --git a/src/iodine.c b/src/iodine.c index 0975739..e53ae37 100644 --- a/src/iodine.c +++ b/src/iodine.c @@ -120,6 +120,7 @@ main(int argc, char **argv) { char *nameserv_host; char *topdomain; + char *errormsg; #ifndef WINDOWS32 struct passwd *pw; #endif @@ -149,6 +150,7 @@ main(int argc, char **argv) nameserv_host = NULL; topdomain = NULL; + errormsg = NULL; #ifndef WINDOWS32 pw = NULL; #endif @@ -309,14 +311,8 @@ main(int argc, char **argv) /* NOTREACHED */ } - if (strlen(topdomain) <= 128) { - if(check_topdomain(topdomain)) { - warnx("Topdomain contains invalid characters.\n"); - usage(); - /* NOTREACHED */ - } - } else { - warnx("Use a topdomain max 128 chars long.\n"); + if(check_topdomain(topdomain, &errormsg)) { + warnx("Invalid topdomain: %s", errormsg); usage(); /* NOTREACHED */ } diff --git a/src/iodined.c b/src/iodined.c index 6ebf3a6..ef6c163 100644 --- a/src/iodined.c +++ b/src/iodined.c @@ -2233,6 +2233,7 @@ main(int argc, char **argv) { extern char *__progname; char *listen_ip; + char *errormsg; #ifndef WINDOWS32 struct passwd *pw; #endif @@ -2267,6 +2268,7 @@ main(int argc, char **argv) #ifndef WINDOWS32 pw = NULL; #endif + errormsg = NULL; username = NULL; newroot = NULL; context = NULL; @@ -2403,14 +2405,10 @@ main(int argc, char **argv) } topdomain = strdup(argv[1]); - if (strlen(topdomain) <= 128) { - if(check_topdomain(topdomain)) { - warnx("Topdomain contains invalid characters."); - usage(); - } - } else { - warnx("Use a topdomain max 128 chars long."); + if(check_topdomain(topdomain, &errormsg)) { + warnx("Invalid topdomain: %s", errormsg); usage(); + /* NOTREACHED */ } if (username != NULL) { diff --git a/tests/common.c b/tests/common.c index 9c84e4a..c1bc73f 100644 --- a/tests/common.c +++ b/tests/common.c @@ -6,60 +6,85 @@ START_TEST(test_topdomain_ok) { - fail_if(check_topdomain("foo.0123456789.qwertyuiop.asdfghjkl.zxcvbnm.com")); + char *error; + + fail_if(check_topdomain("foo.0123456789.qwertyuiop.asdfghjkl.zxcvbnm.com", &error)); /* Not allowed to start with dot */ - fail_unless(check_topdomain(".foo.0123456789.qwertyuiop.asdfghjkl.zxcvbnm.com")); + fail_unless(check_topdomain(".foo.0123456789.qwertyuiop.asdfghjkl.zxcvbnm.com", &error)); + fail_if(strcmp("Starts with a dot", error)); + + /* Test missing error msg ptr */ + fail_unless(check_topdomain(".foo", NULL)); } END_TEST START_TEST(test_topdomain_length) { + char *error; + /* Test empty and too short */ - fail_unless(check_topdomain("")); - fail_unless(check_topdomain("a")); - fail_unless(check_topdomain(".a")); - fail_unless(check_topdomain("a.")); - fail_unless(check_topdomain("ab")); - fail_if(check_topdomain("a.b")); + fail_unless(check_topdomain("", &error)); + fail_if(strcmp("Too short (< 3)", error)); + fail_unless(check_topdomain("a", &error)); + fail_if(strcmp("Too short (< 3)", error)); + fail_unless(check_topdomain(".a", &error)); + fail_if(strcmp("Too short (< 3)", error)); + fail_unless(check_topdomain("a.", &error)); + fail_if(strcmp("Too short (< 3)", error)); + fail_unless(check_topdomain("ab", &error)); + fail_if(strcmp("Too short (< 3)", error)); + fail_if(check_topdomain("a.b", &error)); + fail_if(strcmp("Too short (< 3)", error)); /* Test too long (over 128, need rest of space for data) */ fail_unless(check_topdomain( "abcd12345.abcd12345.abcd12345.abcd12345.abcd12345." "abcd12345.abcd12345.abcd12345.abcd12345.abcd12345." - "abcd12345.abcd12345.foo129xxx")); + "abcd12345.abcd12345.foo129xxx", &error)); + fail_if(strcmp("Too long (> 128)", error)); fail_if(check_topdomain( "abcd12345.abcd12345.abcd12345.abcd12345.abcd12345." "abcd12345.abcd12345.abcd12345.abcd12345.abcd12345." - "abcd12345.abcd12345.foo128xx")); + "abcd12345.abcd12345.foo128xx", &error)); } END_TEST START_TEST(test_topdomain_chunks) { + char *error; + /* Must have at least one dot */ - fail_if(check_topdomain("abcde.gh")); - fail_unless(check_topdomain("abcdefgh")); + fail_if(check_topdomain("abcde.gh", &error)); + fail_unless(check_topdomain("abcdefgh", &error)); + fail_if(strcmp("No dots", error)); /* Not two consecutive dots */ - fail_unless(check_topdomain("abc..defgh")); + fail_unless(check_topdomain("abc..defgh", &error)); + fail_if(strcmp("Consecutive dots", error)); /* Not end with a dots */ - fail_unless(check_topdomain("abc.defgh.")); + fail_unless(check_topdomain("abc.defgh.", &error)); + fail_if(strcmp("Ends with a dot", error)); /* No chunk longer than 63 chars */ - fail_unless(check_topdomain("123456789012345678901234567890" - "1234567890123456789012345678904444.com")); fail_if(check_topdomain("123456789012345678901234567890" - "123456789012345678901234567890333.com")); - fail_unless(check_topdomain("abc.123456789012345678901234567890" - "1234567890123456789012345678904444.com")); + "123456789012345678901234567890333.com", &error)); + fail_unless(check_topdomain("123456789012345678901234567890" + "1234567890123456789012345678904444.com", &error)); + fail_if(strcmp("Too long domain part (> 63)", error)); + fail_if(check_topdomain("abc.123456789012345678901234567890" - "123456789012345678901234567890333.com")); + "123456789012345678901234567890333.com", &error)); fail_unless(check_topdomain("abc.123456789012345678901234567890" - "1234567890123456789012345678904444")); + "1234567890123456789012345678904444.com", &error)); + fail_if(strcmp("Too long domain part (> 63)", error)); + fail_if(check_topdomain("abc.123456789012345678901234567890" - "123456789012345678901234567890333")); + "123456789012345678901234567890333", &error)); + fail_unless(check_topdomain("abc.123456789012345678901234567890" + "1234567890123456789012345678904444", &error)); + fail_if(strcmp("Too long domain part (> 63)", error)); } END_TEST