Add 'tls-padding' test.

This commit is contained in:
Jim Hague 2018-01-16 12:56:50 +00:00
parent fdafb458ef
commit a4ff6de985
1 changed files with 146 additions and 6 deletions

View File

@ -52,6 +52,8 @@
#define DEFAULT_LOOKUP_NAME "getdnsapi.net" #define DEFAULT_LOOKUP_NAME "getdnsapi.net"
#define DEFAULT_LOOKUP_TYPE GETDNS_RRTYPE_AAAA #define DEFAULT_LOOKUP_TYPE GETDNS_RRTYPE_AAAA
#define EDNS0_PADDING_CODE 12
#define EXAMPLE_PIN "pin-sha256=\"E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=\"" #define EXAMPLE_PIN "pin-sha256=\"E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=\""
/* Plugin exit values */ /* Plugin exit values */
@ -193,6 +195,10 @@ static void usage()
" Check server certificate validity, report\n" " Check server certificate validity, report\n"
" warning or critical if days to expiry at\n" " warning or critical if days to expiry at\n"
" or below thresholds (default 14,7).\n" " or below thresholds (default 14,7).\n"
" tls-padding <blocksize> [<name> [<type>]]\n"
" Check server support for EDNS0 padding in TLS\n"
" Special blocksize values are 0 = off,\n"
" 1 = sensible default.\n"
"\n" "\n"
"Enabling monitoring mode ensures output messages and exit statuses conform\n" "Enabling monitoring mode ensures output messages and exit statuses conform\n"
"to the requirements of monitoring plugins (www.monitoring-plugins.org).\n", "to the requirements of monitoring plugins (www.monitoring-plugins.org).\n",
@ -471,14 +477,19 @@ static exit_value_t get_report_info(const struct test_info_s *test_info,
static exit_value_t get_answers(const struct test_info_s *test_info, static exit_value_t get_answers(const struct test_info_s *test_info,
const getdns_dict *response, const getdns_dict *response,
const char *section,
getdns_list **answers, getdns_list **answers,
size_t *no_answers) size_t *no_answers)
{ {
getdns_return_t ret; getdns_return_t ret;
char buf[40];
if ((ret = getdns_dict_get_list(response, "/replies_tree/0/answer", answers)) != GETDNS_RETURN_GOOD) { snprintf(buf, sizeof(buf), "/replies_tree/0/%s", section);
if ((ret = getdns_dict_get_list(response, buf, answers)) != GETDNS_RETURN_GOOD) {
fprintf(test_info->errout, fprintf(test_info->errout,
"Cannot get answers: %s (%d)", "Cannot get section '%s': %s (%d)",
section,
getdns_get_errorstr_by_id(ret), getdns_get_errorstr_by_id(ret),
ret); ret);
return EXIT_UNKNOWN; return EXIT_UNKNOWN;
@ -486,13 +497,16 @@ static exit_value_t get_answers(const struct test_info_s *test_info,
if ((ret = getdns_list_get_length(*answers, no_answers)) != GETDNS_RETURN_GOOD) { if ((ret = getdns_list_get_length(*answers, no_answers)) != GETDNS_RETURN_GOOD) {
fprintf(test_info->errout, fprintf(test_info->errout,
"Cannot get number of answers: %s (%d)", "Cannot get number of items in '%s': %s (%d)",
section,
getdns_get_errorstr_by_id(ret), getdns_get_errorstr_by_id(ret),
ret); ret);
return EXIT_UNKNOWN; return EXIT_UNKNOWN;
} }
if (*no_answers <= 0) { if (*no_answers <= 0) {
fputs("Got zero answers", test_info->errout); fprintf(test_info->errout,
"Zero entries in '%s'",
section);
return EXIT_WARNING; return EXIT_WARNING;
} }
@ -507,7 +521,7 @@ static exit_value_t check_answer_type(const struct test_info_s *test_info,
size_t no_answers; size_t no_answers;
exit_value_t xit; exit_value_t xit;
if ((xit = get_answers(test_info, response, &answers, &no_answers)) != EXIT_OK) if ((xit = get_answers(test_info, response, "answer", &answers, &no_answers)) != EXIT_OK)
return xit; return xit;
for (size_t i = 0; i < no_answers; ++i) { for (size_t i = 0; i < no_answers; ++i) {
@ -744,7 +758,7 @@ static exit_value_t test_qname_minimisation(const struct test_info_s *test_info,
getdns_list *answers; getdns_list *answers;
size_t no_answers; size_t no_answers;
if ((xit = get_answers(test_info, response, &answers, &no_answers)) != EXIT_OK) if ((xit = get_answers(test_info, response, "answer", &answers, &no_answers)) != EXIT_OK)
return xit; return xit;
for (size_t i = 0; i < no_answers; ++i) { for (size_t i = 0; i < no_answers; ++i) {
@ -773,6 +787,7 @@ static exit_value_t test_qname_minimisation(const struct test_info_s *test_info,
continue; continue;
getdns_bindata *rtxt; getdns_bindata *rtxt;
if ((ret = getdns_dict_get_bindata(answer, "/rdata/txt_strings/0", &rtxt)) != GETDNS_RETURN_GOOD) { if ((ret = getdns_dict_get_bindata(answer, "/rdata/txt_strings/0", &rtxt)) != GETDNS_RETURN_GOOD) {
fputs("No answer text", test_info->errout); fputs("No answer text", test_info->errout);
return EXIT_WARNING; return EXIT_WARNING;
@ -799,6 +814,130 @@ static exit_value_t test_qname_minimisation(const struct test_info_s *test_info,
return EXIT_UNKNOWN; return EXIT_UNKNOWN;
} }
static exit_value_t test_padding(const struct test_info_s *test_info,
char ** av)
{
getdns_dict *response;
exit_value_t xit;
long blocksize;
char *endptr;
const char USAGE[] = "padding takes arguments <blocksize> [<name> [<type>]]";
if (!*av || (blocksize = strtol(*av, &endptr, 10), *endptr != '\0' || blocksize < 0)) {
fputs(USAGE, test_info->errout);
return EXIT_USAGE;
}
++av;
getdns_return_t ret;
if ((ret = getdns_context_set_tls_query_padding_blocksize(test_info->context, (uint16_t) blocksize)) != GETDNS_RETURN_GOOD) {
fprintf(test_info->errout,
"Cannot set padding blocksize: %s (%d)",
getdns_get_errorstr_by_id(ret),
ret);
return EXIT_UNKNOWN;
}
if ((xit = parse_search_check(test_info,
av,
USAGE,
&response,
NULL,
NULL,
NULL)) != EXIT_OK)
return xit;
getdns_list *answers;
size_t no_answers;
if ((xit = get_answers(test_info, response, "additional", &answers, &no_answers)) != EXIT_OK)
return xit;
for (size_t i = 0; i < no_answers; ++i) {
getdns_dict *answer;
getdns_return_t ret;
if ((ret = getdns_list_get_dict(answers, i, &answer)) != GETDNS_RETURN_GOOD) {
fprintf(test_info->errout,
"Cannot get answer number %zu: %s (%d)",
i,
getdns_get_errorstr_by_id(ret),
ret);
return EXIT_UNKNOWN;
}
uint32_t rtype;
if ((ret = getdns_dict_get_int(answer, "type", &rtype)) != GETDNS_RETURN_GOOD) {
fprintf(test_info->errout,
"Cannot get answer type: %s (%d)",
getdns_get_errorstr_by_id(ret),
ret);
return EXIT_UNKNOWN;
}
if (rtype != GETDNS_RRTYPE_OPT)
continue;
getdns_list *options;
size_t no_options;
if ((ret = getdns_dict_get_list(answer, "/rdata/options", &options)) != GETDNS_RETURN_GOOD) {
goto no_padding;
}
if ((ret = getdns_list_get_length(options, &no_options)) != GETDNS_RETURN_GOOD) {
fprintf(test_info->errout,
"Cannot get number of options: %s (%d)",
getdns_get_errorstr_by_id(ret),
ret);
return EXIT_UNKNOWN;
}
for (size_t j = 0; j < no_options; ++j) {
getdns_dict *option;
uint32_t code;
if ((ret = getdns_list_get_dict(options, j, &option)) != GETDNS_RETURN_GOOD) {
fprintf(test_info->errout,
"Cannot get option number %zu: %s (%d)",
j,
getdns_get_errorstr_by_id(ret),
ret);
return EXIT_UNKNOWN;
}
if ((ret = getdns_dict_get_int(option, "option_code", &code)) != GETDNS_RETURN_GOOD) {
fprintf(test_info->errout,
"Cannot get option code: %s (%d)",
getdns_get_errorstr_by_id(ret),
ret);
return EXIT_UNKNOWN;
}
if (code != EDNS0_PADDING_CODE)
continue;
/* Yes, we have padding! */
getdns_bindata *data;
if ((ret = getdns_dict_get_bindata(option, "option_data", &data)) != GETDNS_RETURN_GOOD) {
fprintf(test_info->errout,
"Cannot get option code: %s (%d)",
getdns_get_errorstr_by_id(ret),
ret);
return EXIT_UNKNOWN;
}
fprintf(test_info->errout,
"Padding found, length %zu",
data->size);
return EXIT_OK;
}
}
no_padding:
fputs("No padding found", test_info->errout);
return EXIT_CRITICAL;
}
static struct test_funcs_s static struct test_funcs_s
{ {
const char *name; const char *name;
@ -811,6 +950,7 @@ static struct test_funcs_s
{ "qname-min", false, test_qname_minimisation }, { "qname-min", false, test_qname_minimisation },
{ "tls-auth", true, test_authenticate }, { "tls-auth", true, test_authenticate },
{ "tls-cert-valid", true, test_certificate_valid }, { "tls-cert-valid", true, test_certificate_valid },
{ "tls-padding", true, test_padding },
{ NULL, false, NULL } { NULL, false, NULL }
}; };