summaryrefslogtreecommitdiff
path: root/src/shared/dns-domain.c
diff options
context:
space:
mode:
authorTom Gundersen <teg@jklm.no>2015-07-20 16:01:03 +0200
committerTom Gundersen <teg@jklm.no>2015-07-28 00:07:31 +0200
commit642900d3fa479c01d29ebe8268746d06d1c63703 (patch)
tree2f112bf1234f9cd05b24b652cbb181c721cb07d5 /src/shared/dns-domain.c
parent37d54b938faeefd0a5a74f9197a33d78bbb8d6bf (diff)
shared: dns-name - introduce dns_label_unescape_suffix()
Intended to be called repeatedly, and returns then successive unescaped labels from the most to the least significant (left to right). This is slightly inefficient as it scans the string three times (two would be sufficient): once to find the end of the string, once to find the beginning of each label and lastly once to do the actual unescaping. The latter two could be done in one go, but that seemed unnecessarily convoluted.
Diffstat (limited to 'src/shared/dns-domain.c')
-rw-r--r--src/shared/dns-domain.c62
1 files changed, 62 insertions, 0 deletions
diff --git a/src/shared/dns-domain.c b/src/shared/dns-domain.c
index 20a44ce4e1..8a472fbcb4 100644
--- a/src/shared/dns-domain.c
+++ b/src/shared/dns-domain.c
@@ -114,6 +114,68 @@ int dns_label_unescape(const char **name, char *dest, size_t sz) {
return r;
}
+/* @label_terminal: terminal character of a label, updated to point to the terminal character of
+ * the previous label (always skipping one dot) or to NULL if there are no more
+ * labels. */
+int dns_label_unescape_suffix(const char *name, const char **label_terminal, char *dest, size_t sz) {
+ const char *terminal;
+ int r;
+
+ assert(name);
+ assert(label_terminal);
+ assert(dest);
+
+ /* no more labels */
+ if (!*label_terminal) {
+ if (sz >= 1)
+ *dest = 0;
+
+ return 0;
+ }
+
+ assert(**label_terminal == '.' || **label_terminal == 0);
+
+ /* skip current terminal character */
+ terminal = *label_terminal - 1;
+
+ /* point name to the last label, and terminal to the preceding terminal symbol (or make it a NULL pointer) */
+ for (;;) {
+ if (terminal < name) {
+ /* reached the first label, so indicate that there are no more */
+ terminal = NULL;
+ break;
+ }
+
+ /* find the start of the last label */
+ if (*terminal == '.') {
+ const char *y;
+ unsigned slashes = 0;
+
+ for (y = terminal - 1; y >= name && *y == '\\'; y--)
+ slashes ++;
+
+ if (slashes % 2 == 0) {
+ /* the '.' was not escaped */
+ name = terminal + 1;
+ break;
+ } else {
+ terminal = y;
+ continue;
+ }
+ }
+
+ terminal --;
+ }
+
+ r = dns_label_unescape(&name, dest, sz);
+ if (r < 0)
+ return r;
+
+ *label_terminal = terminal;
+
+ return r;
+}
+
int dns_label_escape(const char *p, size_t l, char **ret) {
_cleanup_free_ char *s = NULL;
char *q;