#include <stringprep.h>
#endif
+#include "string-util.h"
#include "dns-domain.h"
int dns_label_unescape(const char **name, char *dest, size_t sz) {
#endif
}
-int dns_name_normalize(const char *s, char **_ret) {
+int dns_name_concat(const char *a, const char *b, char **_ret) {
_cleanup_free_ char *ret = NULL;
size_t n = 0, allocated = 0;
- const char *p = s;
+ const char *p = a;
bool first = true;
int r;
- assert(s);
+ assert(a);
for (;;) {
_cleanup_free_ char *t = NULL;
if (r == 0) {
if (*p != 0)
return -EINVAL;
+
+ if (b) {
+ /* Now continue with the second string, if there is one */
+ p = b;
+ b = NULL;
+ continue;
+ }
+
break;
}
if (r < 0)
return r;
- if (!GREEDY_REALLOC(ret, allocated, n + !first + strlen(t) + 1))
- return -ENOMEM;
+ if (_ret) {
+ if (!GREEDY_REALLOC(ret, allocated, n + !first + strlen(t) + 1))
+ return -ENOMEM;
- if (!first)
- ret[n++] = '.';
- else
- first = false;
+ if (!first)
+ ret[n++] = '.';
+ else
+ first = false;
+
+ memcpy(ret + n, t, r);
+ }
- memcpy(ret + n, t, r);
n += r;
}
if (n > DNS_NAME_MAX)
return -EINVAL;
- if (!GREEDY_REALLOC(ret, allocated, n + 1))
- return -ENOMEM;
-
- ret[n] = 0;
-
if (_ret) {
+ if (!GREEDY_REALLOC(ret, allocated, n + 1))
+ return -ENOMEM;
+
+ ret[n] = 0;
*_ret = ret;
ret = NULL;
}
return 0;
}
-unsigned long dns_name_hash_func(const void *s, const uint8_t hash_key[HASH_KEY_SIZE]) {
+void dns_name_hash_func(const void *s, struct siphash *state) {
const char *p = s;
- unsigned long ul = hash_key[0];
int r;
assert(p);
if (k > 0)
r = k;
+ if (r == 0)
+ break;
+
label[r] = 0;
ascii_strlower(label);
- ul = ul * hash_key[1] + ul + string_hash_func(label, hash_key);
+ string_hash_func(label, state);
}
- return ul;
+ /* enforce that all names are terminated by the empty label */
+ string_hash_func("", state);
}
int dns_name_compare_func(const void *a, const void *b) {
- const char *x = a, *y = b;
+ const char *x, *y;
int r, q, k, w;
assert(a);
assert(b);
+ x = (const char *) a + strlen(a);
+ y = (const char *) b + strlen(b);
+
for (;;) {
char la[DNS_LABEL_MAX+1], lb[DNS_LABEL_MAX+1];
- if (*x == 0 && *y == 0)
+ if (x == NULL && y == NULL)
return 0;
- r = dns_label_unescape(&x, la, sizeof(la));
- q = dns_label_unescape(&y, lb, sizeof(lb));
+ r = dns_label_unescape_suffix(a, &x, la, sizeof(la));
+ q = dns_label_unescape_suffix(b, &y, lb, sizeof(lb));
if (r < 0 || q < 0)
return r - q;
}
}
+int dns_name_between(const char *a, const char *b, const char *c) {
+ int n;
+
+ /* Determine if b is strictly greater than a and strictly smaller than c.
+ We consider the order of names to be circular, so that if a is
+ strictly greater than c, we consider b to be between them if it is
+ either greater than a or smaller than c. This is how the canonical
+ DNS name order used in NSEC records work. */
+
+ n = dns_name_compare_func(a, c);
+ if (n == 0)
+ return -EINVAL;
+ else if (n < 0)
+ /* a<---b--->c */
+ return dns_name_compare_func(a, b) < 0 &&
+ dns_name_compare_func(b, c) < 0;
+ else
+ /* <--b--c a--b--> */
+ return dns_name_compare_func(b, c) < 0 ||
+ dns_name_compare_func(a, b) < 0;
+}
+
int dns_name_reverse(int family, const union in_addr_union *a, char **ret) {
const uint8_t *p;
int r;