int domain2name_len (const char * s, int l) { /* TODO make domain2name FAIL at empty label (..) */ int r = 1; /* ending terminator */ /* make functions FAIL at label.length > 63 */ int o = 0; /* label offset */ /* currently domain2name never fails */ for (int i = 0; i < l; i++) { /* NOTE when using BOTH _len, check that they are */ if (s[i] == '.') { /* NOT negative. d2n_len will fail in d future */ if (!o) /* double period or starting period, label is empty */ break; o = 0; continue; } if (!o) /* label has started */ r++; r++; o++; } return r; } int domain2name (char * n /* at least _len bytes */, const char * s, int l) { /* l is length of s */ char * c = n; /* where to write the label size when done with label */ char * w = n; int o = 0; /* label offset */ for (int i = 0; i <= l /* yes, we go one more ... */; i++) { if (i == l /* ... here */ || s[i] == '.') { /* end of label or end of last label */ if (!o) /* double period or starting period, label is empty */ break; if (o <= 63) /* max length of label (six bits) */ *c = o; o = 0; continue; } if (!o++) /* label has started */ c = w++; /* to be filled with length */ if (o <= 63) *w++ = s[i]; if (o == 64) /* if this label is too long, instead of writing it, we silently cap */ *c = 63; /* it at 63 bytes */ } *w++ = '\0'; /* luckily this makes domain2name kind of safe for handling as a string (: */ return w-n; /* we return number of bytes written */ } /* no compression, it's 2022, net bandwidth is unlimited. n2d OFC does decompress ptrs acc2 std. */ int name2domain_len (const char * u /* >= 512 bytes */, const char * n /* name */) { #define N2DO(x) ((x) & ~(1 << 7 & 1 << 6)) /* pointer offset */ int r = 0; if (n < u+512 && *n == '\0') { return 2; } while (n < u+512) { if (*n & 1 << 7) { if (!(*n & 1 << 6)) return -1; /* 10xx xxxx not implemented - reserved for future use */ n = u + N2DO(*n); continue; } if (*n & 1 << 6) return -2; /* 01xx xxxx not implemented - reserved for future use */ if (!*n) return r+1; r += *n+1; n += *n+1; } return -3; /* malformed packet */ } /* returns number of bytes needed for buffer, passed as the first argument of name2domain(). */ const char * name2domain (char * d /* >= _len B */, const char * u /* >= 512 B */, const char * n) { char * w = d; /* if d is NULL nothing is written and last byte of name is returned */ const char * r = NULL; if (n < u+512 && *n == '\0') { *w++ = '.'; *w++ = '\0'; return n; } while (n < u+512) { if (*n & 1 << 7) { if (!(*n & 1 << 6)) return NULL; /* 10xx xxxx N/I - reserved for future use as per RFC */ n = u + N2DO(*n); r = n; continue; } if (*n & 1 << 6) return NULL; /* 01xx xxxx N/I - reserved for future use as per RFC */ if (!*n) { /* end of name */ if (w) *w++ = '\0'; return r ? r : n; } const char * x = n+*n; n++; if (!(x < u+512)) return NULL; /* malformed packet */ while (n <= x) if (w) *w++ = *n++; else n++; if (w) *w++ = '.'; } return NULL; /* malformed packet */ } /* Returns ptr to last byte of name - '\0' or dnsptr. Ret. NULL on fail (_len also returned < 0) */ int normalizedomain_len (const char * s, int l) { int ž = domain2name_len(s, l); if (ž < 0) return -4; char * b = alloca(ž); if (domain2name(b, s, l) != ž) return -5; return name2domain_len(b, b); } int normalizedomain (char * d /* at least _len bytes */, const char * s, int l) { int ž = domain2name_len(s, l); if (ž < 0) return -4; char * b = alloca(ž); if (domain2name(b, s, l) != ž) return -5; if (!name2domain(d, b, b)) return -6; return 0; }