From 877b7b64021410c1bb686cad562e7446eb65c318 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anton=20Luka=20=C5=A0ijanec?= Date: Mon, 2 May 2022 00:45:48 +0200 Subject: dns server. untested. compiles. --- domain2name.c | 135 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 domain2name.c (limited to 'domain2name.c') diff --git a/domain2name.c b/domain2name.c new file mode 100644 index 0000000..47bfdad --- /dev/null +++ b/domain2name.c @@ -0,0 +1,135 @@ +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 may fail in d future */ + if (!o) /* double period or starting period, label is empty */ + break; /* we could return -1 here if r == 1 */ + o = 0; + continue; + } + if (!o) /* label has started */ + r++; + if (o < 63) { /* we cap label length at 64 bytes. we could return -2 here. */ + 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, int s /* size of u */, const char * n /* name */) { +#define N2DO(x) (ntohs(x) & ~(1 << 15 | 1 << 14)) /* pointer offset */ + int r = 0; + char f[s/8+1]; + memset(f, '\0', s/8+1); + if (n < u+s && *n == '\0') { + return 2; + } + while (n < u+s) { + if (*n & 1 << 7) { + if (!(*n & 1 << 6)) + return -1; /* 10xx xxxx not implemented - reserved for future use */ + if (n+1 >= u+s) + return -2; /* malformed packet */ + if (f[(n-u)/8] & 1 << (n-u)%8) + return -3; /* infinite pointer loop detected */ + f[(n-u)/8] |= 1 << (n-u)%8; + n = u + N2DO(*(uint16_t *) n); + continue; + } + if (*n & 1 << 6) + return -4; /* 01xx xxxx not implemented - reserved for future use */ + if (!*n) + return r+1; + r += *n+1; + n += *n+1; + } + return -5; /* 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, int s, const char * n) { + char * w = d; /* if d is NULL nothing is written and last byte of name is returned */ + const char * r = NULL; + char f[s/8+1]; + memset(f, '\0', s/8+1); + if (n < u+s && *n == '\0') { + *w++ = '.'; + *w++ = '\0'; + return n; + } + while (n < u+s) { + if (*n & 1 << 7) { + if (!(*n & 1 << 6)) + return NULL; /* 10xx xxxx N/I - reserved for future use as per RFC */ + if (n+1 >= u+s) + return NULL; + r = n+1; + if (f[(n-u)/8] & 1 << (n-u)%8) + return NULL; /* infinite pointer loop detected */ + f[(n-u)/8] |= 1 << (n-u)%8; + n = u + N2DO(*(uint16_t *) 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+s)) + 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 -6; + char b[ž]; + if (domain2name(b, s, l) != ž) + return -7; + 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 -6; + char b[ž]; + if (domain2name(b, s, l) != ž) + return -7; + if (!name2domain(d, b, ž, b)) + return -8; + return 0; +} -- cgit v1.2.3