| 1 | /* |
|---|
| 2 | * Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se> |
|---|
| 3 | * |
|---|
| 4 | * Permission to use, copy, modify, and distribute this software for any |
|---|
| 5 | * purpose with or without fee is hereby granted, provided that the above |
|---|
| 6 | * copyright notice and this permission notice appear in all copies. |
|---|
| 7 | * |
|---|
| 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
|---|
| 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
|---|
| 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
|---|
| 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
|---|
| 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
|---|
| 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
|---|
| 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
|---|
| 15 | */ |
|---|
| 16 | |
|---|
| 17 | #include <check.h> |
|---|
| 18 | #include <stdio.h> |
|---|
| 19 | #include <stdlib.h> |
|---|
| 20 | #include <string.h> |
|---|
| 21 | #include <ctype.h> |
|---|
| 22 | #include <sys/types.h> |
|---|
| 23 | #include <sys/socket.h> |
|---|
| 24 | #include <netinet/in.h> |
|---|
| 25 | #include <sys/stat.h> |
|---|
| 26 | #include <arpa/nameser.h> |
|---|
| 27 | |
|---|
| 28 | #include "common.h" |
|---|
| 29 | #include "dns.h" |
|---|
| 30 | #include "encoding.h" |
|---|
| 31 | #include "base32.h" |
|---|
| 32 | #include "test.h" |
|---|
| 33 | |
|---|
| 34 | static void dump_packet(char *, size_t); |
|---|
| 35 | |
|---|
| 36 | static char query_packet[] = |
|---|
| 37 | "\x05\x39\x01\x00\x00\x01\x00\x00\x00\x00\x00\x01\x2D\x41\x6A\x62\x63" |
|---|
| 38 | "\x75\x79\x74\x63\x70\x65\x62\x30\x67\x71\x30\x6C\x74\x65\x62\x75\x78" |
|---|
| 39 | "\x67\x69\x64\x75\x6E\x62\x73\x73\x61\x33\x64\x66\x6F\x6E\x30\x63\x61" |
|---|
| 40 | "\x7A\x64\x62\x6F\x72\x71\x71\x04\x6B\x72\x79\x6F\x02\x73\x65\x00\x00" |
|---|
| 41 | "\x0A\x00\x01\x00\x00\x29\x10\x00\x00\x00\x80\x00\x00\x00"; |
|---|
| 42 | |
|---|
| 43 | static char answer_packet[] = |
|---|
| 44 | "\x05\x39\x84\x00\x00\x01\x00\x01\x00\x00\x00\x00\x05\x73\x69\x6C\x6C" |
|---|
| 45 | "\x79\x04\x68\x6F\x73\x74\x02\x6F\x66\x06\x69\x6F\x64\x69\x6E\x65\x04" |
|---|
| 46 | "\x63\x6F\x64\x65\x04\x6B\x72\x79\x6F\x02\x73\x65\x00\x00\x0A\x00\x01" |
|---|
| 47 | "\xC0\x0C\x00\x0A\x00\x01\x00\x00\x00\x00\x00\x23\x74\x68\x69\x73\x20" |
|---|
| 48 | "\x69\x73\x20\x74\x68\x65\x20\x6D\x65\x73\x73\x61\x67\x65\x20\x74\x6F" |
|---|
| 49 | "\x20\x62\x65\x20\x64\x65\x6C\x69\x76\x65\x72\x65\x64"; |
|---|
| 50 | |
|---|
| 51 | static char answer_packet_high_trans_id[] = |
|---|
| 52 | "\x85\x39\x84\x00\x00\x01\x00\x01\x00\x00\x00\x00\x05\x73\x69\x6C\x6C" |
|---|
| 53 | "\x79\x04\x68\x6F\x73\x74\x02\x6F\x66\x06\x69\x6F\x64\x69\x6E\x65\x04" |
|---|
| 54 | "\x63\x6F\x64\x65\x04\x6B\x72\x79\x6F\x02\x73\x65\x00\x00\x0A\x00\x01" |
|---|
| 55 | "\xC0\x0C\x00\x0A\x00\x01\x00\x00\x00\x00\x00\x23\x74\x68\x69\x73\x20" |
|---|
| 56 | "\x69\x73\x20\x74\x68\x65\x20\x6D\x65\x73\x73\x61\x67\x65\x20\x74\x6F" |
|---|
| 57 | "\x20\x62\x65\x20\x64\x65\x6C\x69\x76\x65\x72\x65\x64"; |
|---|
| 58 | static char *msgData = "this is the message to be delivered"; |
|---|
| 59 | static char *topdomain = "kryo.se"; |
|---|
| 60 | |
|---|
| 61 | static char *innerData = "HELLO this is the test data"; |
|---|
| 62 | |
|---|
| 63 | START_TEST(test_encode_query) |
|---|
| 64 | { |
|---|
| 65 | char buf[512]; |
|---|
| 66 | char resolv[512]; |
|---|
| 67 | struct query q; |
|---|
| 68 | struct encoder *enc; |
|---|
| 69 | char *d; |
|---|
| 70 | size_t len; |
|---|
| 71 | size_t enclen; |
|---|
| 72 | int ret; |
|---|
| 73 | |
|---|
| 74 | enclen = sizeof(resolv); |
|---|
| 75 | memset(&buf, 0, sizeof(buf)); |
|---|
| 76 | memset(&resolv, 0, sizeof(resolv)); |
|---|
| 77 | memset(&q, 0, sizeof(struct query)); |
|---|
| 78 | q.type = T_NULL; |
|---|
| 79 | q.id = 1337; |
|---|
| 80 | d = resolv; |
|---|
| 81 | enc = get_base32_encoder(); |
|---|
| 82 | |
|---|
| 83 | *d++ = 'A'; |
|---|
| 84 | enc->encode(d, &enclen, innerData, strlen(innerData)); |
|---|
| 85 | d = resolv + strlen(resolv); |
|---|
| 86 | if (*d != '.') { |
|---|
| 87 | *d++ = '.'; |
|---|
| 88 | } |
|---|
| 89 | strcpy(d, topdomain); |
|---|
| 90 | len = sizeof(buf); |
|---|
| 91 | ret = dns_encode(buf, len, &q, QR_QUERY, resolv, strlen(resolv)); |
|---|
| 92 | len = sizeof(query_packet) - 1; /* Skip extra null character */ |
|---|
| 93 | |
|---|
| 94 | if (strncmp(query_packet, buf, sizeof(query_packet)) || ret != len) { |
|---|
| 95 | printf("\n"); |
|---|
| 96 | dump_packet(query_packet, len); |
|---|
| 97 | dump_packet(buf, ret); |
|---|
| 98 | } |
|---|
| 99 | fail_unless(strncmp(query_packet, buf, sizeof(query_packet)) == 0, "Did not compile expected packet"); |
|---|
| 100 | fail_unless(ret == len, "Bad packet length: %d, expected %d", ret, len); |
|---|
| 101 | } |
|---|
| 102 | END_TEST |
|---|
| 103 | |
|---|
| 104 | START_TEST(test_decode_query) |
|---|
| 105 | { |
|---|
| 106 | char buf[512]; |
|---|
| 107 | char *domain; |
|---|
| 108 | struct query q; |
|---|
| 109 | struct encoder *enc; |
|---|
| 110 | size_t len; |
|---|
| 111 | |
|---|
| 112 | memset(&q, 0, sizeof(struct query)); |
|---|
| 113 | memset(&buf, 0, sizeof(buf)); |
|---|
| 114 | q.id = 0; |
|---|
| 115 | len = sizeof(query_packet) - 1; |
|---|
| 116 | enc = get_base32_encoder(); |
|---|
| 117 | |
|---|
| 118 | dns_decode(buf, sizeof(buf), &q, QR_QUERY, query_packet, len); |
|---|
| 119 | domain = strstr(q.name, topdomain); |
|---|
| 120 | len = sizeof(buf); |
|---|
| 121 | unpack_data(buf, len, &(q.name[1]), (int) (domain - q.name) - 1, enc); |
|---|
| 122 | |
|---|
| 123 | fail_unless(strncmp(buf, innerData, strlen(innerData)) == 0, "Did not extract expected host: '%s'", buf); |
|---|
| 124 | fail_unless(strlen(buf) == strlen(innerData), "Bad host length: %d, expected %d: '%s'", strlen(buf), strlen(innerData), buf); |
|---|
| 125 | } |
|---|
| 126 | END_TEST |
|---|
| 127 | |
|---|
| 128 | START_TEST(test_encode_response) |
|---|
| 129 | { |
|---|
| 130 | char buf[512]; |
|---|
| 131 | char *host = "silly.host.of.iodine.code.kryo.se"; |
|---|
| 132 | struct query q; |
|---|
| 133 | int len; |
|---|
| 134 | int ret; |
|---|
| 135 | |
|---|
| 136 | len = sizeof(buf); |
|---|
| 137 | memset(&buf, 0, sizeof(buf)); |
|---|
| 138 | memset(&q, 0, sizeof(struct query)); |
|---|
| 139 | strncpy(q.name, host, strlen(host)); |
|---|
| 140 | q.type = T_NULL; |
|---|
| 141 | q.id = 1337; |
|---|
| 142 | |
|---|
| 143 | ret = dns_encode(buf, len, &q, QR_ANSWER, msgData, strlen(msgData)); |
|---|
| 144 | len = sizeof(answer_packet) - 1; /* Skip extra null character */ |
|---|
| 145 | |
|---|
| 146 | fail_unless(strncmp(answer_packet, buf, sizeof(answer_packet)) == 0, "Did not compile expected packet"); |
|---|
| 147 | fail_unless(ret == len, "Bad packet length: %d, expected %d", ret, len); |
|---|
| 148 | } |
|---|
| 149 | END_TEST |
|---|
| 150 | |
|---|
| 151 | START_TEST(test_decode_response) |
|---|
| 152 | { |
|---|
| 153 | char buf[512]; |
|---|
| 154 | struct query q; |
|---|
| 155 | int len; |
|---|
| 156 | int ret; |
|---|
| 157 | |
|---|
| 158 | len = sizeof(buf); |
|---|
| 159 | memset(&buf, 0, sizeof(buf)); |
|---|
| 160 | |
|---|
| 161 | ret = dns_decode(buf, len, &q, QR_ANSWER, answer_packet, sizeof(answer_packet)-1); |
|---|
| 162 | fail_unless(strncmp(msgData, buf, sizeof(msgData)) == 0, "Did not extract expected data"); |
|---|
| 163 | fail_unless(ret == strlen(msgData), "Bad data length: %d, expected %d", ret, strlen(msgData)); |
|---|
| 164 | fail_unless(q.id == 0x0539); |
|---|
| 165 | } |
|---|
| 166 | END_TEST |
|---|
| 167 | |
|---|
| 168 | START_TEST(test_decode_response_with_high_trans_id) |
|---|
| 169 | { |
|---|
| 170 | char buf[512]; |
|---|
| 171 | struct query q; |
|---|
| 172 | int len; |
|---|
| 173 | int ret; |
|---|
| 174 | |
|---|
| 175 | len = sizeof(buf); |
|---|
| 176 | memset(&buf, 0, sizeof(buf)); |
|---|
| 177 | |
|---|
| 178 | ret = dns_decode(buf, len, &q, QR_ANSWER, answer_packet_high_trans_id, sizeof(answer_packet_high_trans_id)-1); |
|---|
| 179 | fail_unless(strncmp(msgData, buf, sizeof(msgData)) == 0, "Did not extract expected data"); |
|---|
| 180 | fail_unless(ret == strlen(msgData), "Bad data length: %d, expected %d", ret, strlen(msgData)); |
|---|
| 181 | fail_unless(q.id == 0x8539, "q.id was %08X instead of %08X!", q.id, 0x8539); |
|---|
| 182 | } |
|---|
| 183 | END_TEST |
|---|
| 184 | |
|---|
| 185 | START_TEST(test_get_id_short_packet) |
|---|
| 186 | { |
|---|
| 187 | char buf[5]; |
|---|
| 188 | int len; |
|---|
| 189 | unsigned short id; |
|---|
| 190 | |
|---|
| 191 | len = sizeof(buf); |
|---|
| 192 | memset(&buf, 5, sizeof(buf)); |
|---|
| 193 | |
|---|
| 194 | id = dns_get_id(buf, len); |
|---|
| 195 | fail_unless(id == 0); |
|---|
| 196 | } |
|---|
| 197 | END_TEST |
|---|
| 198 | |
|---|
| 199 | START_TEST(test_get_id_low) |
|---|
| 200 | { |
|---|
| 201 | unsigned short id; |
|---|
| 202 | |
|---|
| 203 | id = dns_get_id(answer_packet, sizeof(answer_packet)); |
|---|
| 204 | fail_unless(id == 1337); |
|---|
| 205 | } |
|---|
| 206 | END_TEST |
|---|
| 207 | |
|---|
| 208 | START_TEST(test_get_id_high) |
|---|
| 209 | { |
|---|
| 210 | unsigned short id; |
|---|
| 211 | |
|---|
| 212 | id = dns_get_id(answer_packet_high_trans_id, sizeof(answer_packet_high_trans_id)); |
|---|
| 213 | fail_unless(id == 0x8539); |
|---|
| 214 | } |
|---|
| 215 | END_TEST |
|---|
| 216 | |
|---|
| 217 | static void |
|---|
| 218 | dump_packet(char *buf, size_t len) |
|---|
| 219 | { |
|---|
| 220 | int pos; |
|---|
| 221 | |
|---|
| 222 | for (pos = 0; pos < len; pos++) { |
|---|
| 223 | printf("\\x%02X", (unsigned char) buf[pos]); |
|---|
| 224 | } |
|---|
| 225 | printf("\n"); |
|---|
| 226 | for (pos = 0; pos < len; pos++) { |
|---|
| 227 | if (isalnum((unsigned char) buf[pos])) { |
|---|
| 228 | printf(" %c ", (unsigned char) buf[pos]); |
|---|
| 229 | } else { |
|---|
| 230 | printf(" "); |
|---|
| 231 | } |
|---|
| 232 | } |
|---|
| 233 | printf("\n"); |
|---|
| 234 | } |
|---|
| 235 | |
|---|
| 236 | TCase * |
|---|
| 237 | test_dns_create_tests() |
|---|
| 238 | { |
|---|
| 239 | TCase *tc; |
|---|
| 240 | |
|---|
| 241 | tc = tcase_create("Dns"); |
|---|
| 242 | tcase_add_test(tc, test_encode_query); |
|---|
| 243 | tcase_add_test(tc, test_decode_query); |
|---|
| 244 | tcase_add_test(tc, test_encode_response); |
|---|
| 245 | tcase_add_test(tc, test_decode_response); |
|---|
| 246 | tcase_add_test(tc, test_decode_response_with_high_trans_id); |
|---|
| 247 | tcase_add_test(tc, test_get_id_short_packet); |
|---|
| 248 | tcase_add_test(tc, test_get_id_low); |
|---|
| 249 | tcase_add_test(tc, test_get_id_high); |
|---|
| 250 | |
|---|
| 251 | return tc; |
|---|
| 252 | } |
|---|