Changeset View
Changeset View
Standalone View
Standalone View
src/seeder/dns.cpp
Show First 20 Lines • Show All 56 Lines • ▼ Show 20 Lines | enum class DNSResponseCode : uint8_t { | ||||
OK = 0, | OK = 0, | ||||
FORMAT_ERROR = 1, | FORMAT_ERROR = 1, | ||||
SERVER_FAILURE = 2, | SERVER_FAILURE = 2, | ||||
NAME_ERROR = 3, | NAME_ERROR = 3, | ||||
NOT_IMPLEMENTED = 4, | NOT_IMPLEMENTED = 4, | ||||
REFUSED = 5, | REFUSED = 5, | ||||
}; | }; | ||||
int parse_name(const uint8_t **inpos, const uint8_t *inend, | ParseNameStatus parse_name(const uint8_t **inpos, const uint8_t *inend, | ||||
const uint8_t *inbuf, char *buf, size_t bufsize) { | const uint8_t *inbuf, char *buf, size_t bufsize) { | ||||
if (bufsize == 0) { | if (bufsize == 0) { | ||||
return -2; | return ParseNameStatus::OutputBufferError; | ||||
} | } | ||||
size_t bufused = 0; | size_t bufused = 0; | ||||
int init = 1; | int init = 1; | ||||
do { | do { | ||||
if (*inpos == inend) { | if (*inpos == inend) { | ||||
return -1; | return ParseNameStatus::InputError; | ||||
} | } | ||||
// read length of next component | // read length of next component | ||||
int octet = *((*inpos)++); | int octet = *((*inpos)++); | ||||
if (octet == 0) { | if (octet == 0) { | ||||
buf[bufused] = 0; | buf[bufused] = 0; | ||||
return 0; | return ParseNameStatus::OK; | ||||
} | } | ||||
// add dot in output | // add dot in output | ||||
if (!init) { | if (!init) { | ||||
if (bufused == bufsize - 1) { | if (bufused == bufsize - 1) { | ||||
return -2; | return ParseNameStatus::OutputBufferError; | ||||
} | } | ||||
buf[bufused++] = '.'; | buf[bufused++] = '.'; | ||||
} else { | } else { | ||||
init = 0; | init = 0; | ||||
} | } | ||||
// handle references | // handle references | ||||
if ((octet & 0xC0) == 0xC0) { | if ((octet & 0xC0) == 0xC0) { | ||||
if (*inpos == inend) { | if (*inpos == inend) { | ||||
return -1; | return ParseNameStatus::InputError; | ||||
} | } | ||||
int ref = ((octet - 0xC0) << 8) + *((*inpos)++); | int ref = ((octet - 0xC0) << 8) + *((*inpos)++); | ||||
if (ref < 0 || ref >= (*inpos) - inbuf - 2) { | if (ref < 0 || ref >= (*inpos) - inbuf - 2) { | ||||
return -1; | return ParseNameStatus::InputError; | ||||
} | } | ||||
const uint8_t *newbuf = inbuf + ref; | const uint8_t *newbuf = inbuf + ref; | ||||
return parse_name(&newbuf, (*inpos) - 2, inbuf, buf + bufused, | return parse_name(&newbuf, (*inpos) - 2, inbuf, buf + bufused, | ||||
bufsize - bufused); | bufsize - bufused); | ||||
} | } | ||||
if (octet > MAX_LABEL_LENGTH) { | if (octet > MAX_LABEL_LENGTH) { | ||||
return -1; | return ParseNameStatus::InputError; | ||||
} | } | ||||
// The maximum size of a query name is 255. The buffer must have | // The maximum size of a query name is 255. The buffer must have | ||||
// room for the null-character at the end of the buffer after writing | // room for the null-character at the end of the buffer after writing | ||||
// the label. | // the label. | ||||
if (octet + bufused > MAX_QUERY_NAME_LENGTH) { | if (octet + bufused > MAX_QUERY_NAME_LENGTH) { | ||||
return -1; | return ParseNameStatus::InputError; | ||||
} | } | ||||
// copy label | // copy label | ||||
while (octet) { | while (octet) { | ||||
if (*inpos == inend) { | if (*inpos == inend) { | ||||
return -1; | return ParseNameStatus::InputError; | ||||
} | } | ||||
if (bufused == bufsize - 1) { | if (bufused == bufsize - 1) { | ||||
return -2; | return ParseNameStatus::OutputBufferError; | ||||
} | } | ||||
int c = *((*inpos)++); | int c = *((*inpos)++); | ||||
if (c == '.') { | if (c == '.') { | ||||
return -1; | return ParseNameStatus::InputError; | ||||
} | } | ||||
octet--; | octet--; | ||||
buf[bufused++] = c; | buf[bufused++] = c; | ||||
} | } | ||||
} while (1); | } while (1); | ||||
} | } | ||||
// 0: ok | // 0: ok | ||||
▲ Show 20 Lines • Show All 287 Lines • ▼ Show 20 Lines | if (nquestion > 1) { | ||||
goto error; | goto error; | ||||
} | } | ||||
{ | { | ||||
const uint8_t *inpos = inbuf + 12; | const uint8_t *inpos = inbuf + 12; | ||||
const uint8_t *inend = inbuf + insize; | const uint8_t *inend = inbuf + insize; | ||||
char name[MAX_QUERY_NAME_BUFFER_LENGTH]; | char name[MAX_QUERY_NAME_BUFFER_LENGTH]; | ||||
int offset = inpos - inbuf; | int offset = inpos - inbuf; | ||||
int ret = parse_name(&inpos, inend, inbuf, name, | ParseNameStatus ret = parse_name(&inpos, inend, inbuf, name, | ||||
MAX_QUERY_NAME_BUFFER_LENGTH); | MAX_QUERY_NAME_BUFFER_LENGTH); | ||||
if (ret == -1) { | if (ret == ParseNameStatus::InputError) { | ||||
responseCode = DNSResponseCode::FORMAT_ERROR; | responseCode = DNSResponseCode::FORMAT_ERROR; | ||||
goto error; | goto error; | ||||
} | } | ||||
if (ret == -2) { | if (ret == ParseNameStatus::OutputBufferError) { | ||||
responseCode = DNSResponseCode::REFUSED; | responseCode = DNSResponseCode::REFUSED; | ||||
goto error; | goto error; | ||||
} | } | ||||
int namel = strlen(name), hostl = strlen(opt->host); | int namel = strlen(name), hostl = strlen(opt->host); | ||||
if (strcasecmp(name, opt->host) && | if (strcasecmp(name, opt->host) && | ||||
(namel < hostl + 2 || name[namel - hostl - 1] != '.' || | (namel < hostl + 2 || name[namel - hostl - 1] != '.' || | ||||
strcasecmp(name + namel - hostl, opt->host))) { | strcasecmp(name + namel - hostl, opt->host))) { | ||||
▲ Show 20 Lines • Show All 240 Lines • Show Last 20 Lines |