/* * Tests for librpc ndr functions * * Copyright (C) Catalyst.NET Ltd 2020 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include "replace.h" #include #include #include "includes.h" #include "librpc/ndr/libndr.h" #include "librpc/gen_ndr/ndr_dns.h" #include "librpc/gen_ndr/ndr_nbt.h" #include "lib/util/time.h" #define NBT_NAME "EOGFGLGPCACACACACACACACACACACACA" /* "neko" */ static DATA_BLOB generate_obnoxious_dns_name(TALLOC_CTX *mem_ctx, size_t n_labels, size_t dot_every, bool is_nbt) { size_t i, j; char *s; DATA_BLOB name = data_blob_talloc(mem_ctx, NULL, 64 * n_labels + 1); assert_non_null(name.data); s = (char*)name.data; if (is_nbt) { size_t len = strlen(NBT_NAME); *s = len; s++; memcpy(s, NBT_NAME, len); s += len; n_labels--; } for (i = 0; i < n_labels; i++) { *s = 63; s++; for (j = 0; j < 63; j++) { if (j % dot_every == (dot_every - 1)) { *s = '.'; } else { *s = 'x'; } s++; } } *s = 0; s++; name.length = s - (char*)name.data; return name; } static char *_test_ndr_pull_dns_string_list(TALLOC_CTX *mem_ctx, size_t n_labels, size_t dot_every, bool is_nbt) { enum ndr_err_code ndr_err; DATA_BLOB blob = generate_obnoxious_dns_name(mem_ctx, n_labels, dot_every, is_nbt); char *name; ndr_pull_flags_fn_t fn; if (is_nbt) { fn = (ndr_pull_flags_fn_t)ndr_pull_nbt_string; } else { fn = (ndr_pull_flags_fn_t)ndr_pull_dns_string; } ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &name, fn); /* Success here is not expected, but we let it go to measure timing. */ if (ndr_err == NDR_ERR_SUCCESS) { printf("pull succeed\n"); } else { assert_int_equal(ndr_err, NDR_ERR_STRING); } TALLOC_FREE(blob.data); return name; } static void _test_ndr_push_dns_string_list(TALLOC_CTX *mem_ctx, char *name, bool is_nbt) { DATA_BLOB blob; enum ndr_err_code ndr_err; ndr_push_flags_fn_t fn; if (is_nbt) { fn = (ndr_push_flags_fn_t)ndr_push_nbt_string; } else { fn = (ndr_push_flags_fn_t)ndr_push_dns_string; } ndr_err = ndr_push_struct_blob(&blob, mem_ctx, name, fn); /* Success here is not expected, but we let it go to measure timing. */ if (ndr_err == NDR_ERR_SUCCESS) { printf("push succeed\n"); } else { assert_int_equal(ndr_err, NDR_ERR_STRING); } } static uint64_t elapsed_time(struct timespec start, const char *print) { struct timespec end; unsigned long long microsecs; clock_gettime_mono(&end); end.tv_sec -= start.tv_sec; if (end.tv_nsec < start.tv_nsec) { /* we need to borrow */ end.tv_nsec += 1000 * 1000 * 1000; end.tv_sec -= 1; } end.tv_nsec -= start.tv_nsec; microsecs = end.tv_sec * 1000000; microsecs += end.tv_nsec / 1000; if (print != NULL) { printf(" %s: %llu microseconds\n", print, microsecs); } return microsecs; } static void test_ndr_dns_string_half_dots(void **state) { TALLOC_CTX *mem_ctx = talloc_new(NULL); char *name; struct timespec start; uint64_t elapsed; clock_gettime_mono(&start); name =_test_ndr_pull_dns_string_list(mem_ctx, 127, 2, false); elapsed_time(start, "pull"); _test_ndr_push_dns_string_list(mem_ctx, name, false); elapsed = elapsed_time(start, "total"); assert_in_range(elapsed, 0, 200000); talloc_free(mem_ctx); } static void test_ndr_nbt_string_half_dots(void **state) { TALLOC_CTX *mem_ctx = talloc_new(NULL); char *name; struct timespec start; uint64_t elapsed; clock_gettime_mono(&start); name =_test_ndr_pull_dns_string_list(mem_ctx, 127, 2, true); elapsed_time(start, "pull"); _test_ndr_push_dns_string_list(mem_ctx, name, true); elapsed = elapsed_time(start, "total"); assert_in_range(elapsed, 0, 200000); talloc_free(mem_ctx); } static void test_ndr_dns_string_all_dots(void **state) { TALLOC_CTX *mem_ctx = talloc_new(NULL); char *name; struct timespec start; uint64_t elapsed; clock_gettime_mono(&start); name =_test_ndr_pull_dns_string_list(mem_ctx, 127, 1, false); elapsed_time(start, "pull"); _test_ndr_push_dns_string_list(mem_ctx, name, false); elapsed = elapsed_time(start, "total"); assert_in_range(elapsed, 0, 200000); talloc_free(mem_ctx); } static void test_ndr_nbt_string_all_dots(void **state) { TALLOC_CTX *mem_ctx = talloc_new(NULL); char *name; struct timespec start; uint64_t elapsed; clock_gettime_mono(&start); name =_test_ndr_pull_dns_string_list(mem_ctx, 127, 1, true); elapsed_time(start, "pull"); _test_ndr_push_dns_string_list(mem_ctx, name, true); elapsed = elapsed_time(start, "total"); assert_in_range(elapsed, 0, 200000); talloc_free(mem_ctx); } int main(int argc, const char **argv) { const struct CMUnitTest tests[] = { cmocka_unit_test(test_ndr_nbt_string_half_dots), cmocka_unit_test(test_ndr_dns_string_half_dots), cmocka_unit_test(test_ndr_nbt_string_all_dots), cmocka_unit_test(test_ndr_dns_string_all_dots), }; cmocka_set_message_output(CM_OUTPUT_SUBUNIT); return cmocka_run_group_tests(tests, NULL, NULL); }