diff --git a/common/test/run-ip_port_parsing.c b/common/test/run-ip_port_parsing.c index 68b1bdc55..090b7f235 100644 --- a/common/test/run-ip_port_parsing.c +++ b/common/test/run-ip_port_parsing.c @@ -117,6 +117,26 @@ int main(int argc, char *argv[]) common_setup(argv[0]); + /* Check IP/TOR/DNS parser */ + assert(is_ipaddr("192.168.1.2")); + assert(!is_ipaddr("foo.bar.1.2")); + assert(is_toraddr("qubesosfasa4zl44o4tws22di6kepyzfeqv3tg4e3ztknltfxqrymdad.onion")); + assert(is_toraddr("qubesos4rrrrz6n4.onion")); + assert(!is_toraddr("QUBESOSfasa4zl44o4tws22di6kepyzfeqv3tg4e3ztknltfxqrymdad.onion")); + assert(!is_toraddr("QUBESOS4rrrrz6n4.onion")); + assert(!is_toraddr("qubesos-asa4zl44o4tws22di6kepyzfeqv3tg4e3ztknltfxqrymdad.onion")); + assert(is_dnsaddr("example.com")); + assert(is_dnsaddr("example.digits123.com")); + assert(is_dnsaddr("example-hyphen.com")); + assert(is_dnsaddr("123example.com")); + assert(is_dnsaddr("example123.com")); + assert(is_dnsaddr("is-valid.3hostname123.com")); + assert(!is_dnsaddr("UPPERCASE.invalid.com")); + assert(!is_dnsaddr("-.invalid.com")); + assert(!is_dnsaddr("invalid.-example.com")); + assert(!is_dnsaddr("invalid.example-.com")); + assert(!is_dnsaddr("invalid..example.com")); + /* Grossly invalid. */ assert(!separate_address_and_port(tmpctx, "[", &ip, &port)); assert(!separate_address_and_port(tmpctx, "[123", &ip, &port)); @@ -148,6 +168,19 @@ int main(int argc, char *argv[]) assert(streq(ip, "192.168.2.255")); assert(port == 0); + /* DNS types */ + assert(separate_address_and_port(tmpctx, "example.com:42", &ip, &port)); + assert(streq(ip, "example.com")); + assert(port == 42); + assert(separate_address_and_port(tmpctx, "sub.example.com:21", &ip, &port)); + assert(streq(ip, "sub.example.com")); + assert(port == 21); + port = 123; + assert(separate_address_and_port(tmpctx, "sub.example.com", &ip, &port)); + assert(streq(ip, "sub.example.com")); + assert(port == 123); + port = 0; + // unusual but possibly valid case assert(separate_address_and_port(tmpctx, "[::1]", &ip, &port)); assert(streq(ip, "::1")); diff --git a/common/wireaddr.c b/common/wireaddr.c index 6638f2e6e..f9afbc48e 100644 --- a/common/wireaddr.c +++ b/common/wireaddr.c @@ -287,8 +287,8 @@ REGISTER_TYPE_TO_STRING(wireaddr, fmt_wireaddr); * Returns false if it wasn't one of these forms. If it returns true, * it only overwrites *port if it was specified by above. */ -static bool separate_address_and_port(const tal_t *ctx, const char *arg, - char **addr, u16 *port) +bool separate_address_and_port(const tal_t *ctx, const char *arg, + char **addr, u16 *port) { char *portcolon; @@ -322,6 +322,81 @@ static bool separate_address_and_port(const tal_t *ctx, const char *arg, return true; } +bool is_ipaddr(const char *arg) +{ + struct in_addr v4; + struct in6_addr v6; + if (inet_pton(AF_INET, arg, &v4)) + return true; + if (inet_pton(AF_INET6, arg, &v6)) + return true; + return false; +} + +bool is_toraddr(const char *arg) +{ + size_t i, arglen; + arglen = strlen(arg); + if (!strends(arg, ".onion")) + return false; + if (arglen != 16 + 6 && arglen != 56 + 6) + return false; + for (i = 0; i < arglen - 6; i++) { + if (arg[i] >= 'a' && arg[i] <= 'z') + continue; + if (arg[i] >= '0' && arg[i] <= '9') + continue; + return false; + } + return true; +} + +/* Rules: + * + * - not longer than 255 + * - segments are separated with . dot + * - segments do not start or end with - hyphen + * - segments must be longer thant zero + * - lowercase a-z and digits 0-9 and - hyphen + */ +bool is_dnsaddr(const char *arg) +{ + size_t i, arglen; + int lastdot; + + if (is_ipaddr(arg) || is_toraddr(arg)) + return false; + + /* now that its not IP or TOR, check its a DNS name */ + arglen = strlen(arg); + if (arglen > 255) + return false; + lastdot = -1; + for (i = 0; i < arglen; i++) { + if (arg[i] == '.') { + /* segment must be longer than zero */ + if (i - lastdot == 1) + return false; + /* last segment can not end with hypen */ + if (i != 0 && arg[i-1] == '-') + return false; + lastdot = i; + continue; + } + /* segment cannot start with hyphen */ + if (i == lastdot + 1 && arg[i] == '-') + return false; + if (arg[i] >= 'a' && arg[i] <= 'z') + continue; + if (arg[i] >= '0' && arg[i] <= '9') + continue; + if (arg[i] == '-') + continue; + return false; + } + return true; +} + struct wireaddr * wireaddr_from_hostname(const tal_t *ctx, const char *hostname, diff --git a/common/wireaddr.h b/common/wireaddr.h index 3f9cddc62..e9dc0bf8e 100644 --- a/common/wireaddr.h +++ b/common/wireaddr.h @@ -149,6 +149,16 @@ struct wireaddr_internal { bool wireaddr_internal_eq(const struct wireaddr_internal *a, const struct wireaddr_internal *b); + +bool separate_address_and_port(const tal_t *ctx, const char *arg, + char **addr, u16 *port); + +bool is_ipaddr(const char *arg); + +bool is_toraddr(const char *arg); + +bool is_dnsaddr(const char *arg); + bool parse_wireaddr_internal(const char *arg, struct wireaddr_internal *addr, u16 port, bool wildcard_ok, bool dns_ok, bool unresolved_ok, bool allow_deprecated, diff --git a/connectd/connectd.c b/connectd/connectd.c index 1150f6ee7..7cd457d75 100644 --- a/connectd/connectd.c +++ b/connectd/connectd.c @@ -875,6 +875,7 @@ static struct io_plan *conn_init(struct io_conn *conn, break; case ADDR_INTERNAL_WIREADDR: /* If it was a Tor address, we wouldn't be here. */ + assert(!is_toraddr((char*)addr->u.wireaddr.addr)); ai = wireaddr_to_addrinfo(tmpctx, &addr->u.wireaddr); break; }