Coverage Report

Created: 2026-02-26 06:45

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/bind9/lib/dns/rdata/generic/mx_15.c
Line
Count
Source
1
/*
2
 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3
 *
4
 * SPDX-License-Identifier: MPL-2.0
5
 *
6
 * This Source Code Form is subject to the terms of the Mozilla Public
7
 * License, v. 2.0. If a copy of the MPL was not distributed with this
8
 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
9
 *
10
 * See the COPYRIGHT file distributed with this work for additional
11
 * information regarding copyright ownership.
12
 */
13
14
#ifndef RDATA_GENERIC_MX_15_C
15
#define RDATA_GENERIC_MX_15_C
16
17
#include <string.h>
18
19
#include <isc/net.h>
20
21
#include <dns/fixedname.h>
22
23
15.2k
#define RRTYPE_MX_ATTRIBUTES (0)
24
25
static bool
26
0
check_mx(isc_token_t *token) {
27
0
  char tmp[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:123.123.123.123.")];
28
0
  struct in_addr addr;
29
0
  struct in6_addr addr6;
30
31
0
  if (strlcpy(tmp, DNS_AS_STR(*token), sizeof(tmp)) >= sizeof(tmp)) {
32
0
    return true;
33
0
  }
34
35
0
  if (tmp[strlen(tmp) - 1] == '.') {
36
0
    tmp[strlen(tmp) - 1] = '\0';
37
0
  }
38
0
  if (inet_pton(AF_INET, tmp, &addr) == 1 ||
39
0
      inet_pton(AF_INET6, tmp, &addr6) == 1)
40
0
  {
41
0
    return false;
42
0
  }
43
44
0
  return true;
45
0
}
46
47
static isc_result_t
48
10.2k
fromtext_mx(ARGS_FROMTEXT) {
49
10.2k
  isc_token_t token;
50
10.2k
  dns_fixedname_t fn;
51
10.2k
  dns_name_t *name = dns_fixedname_initname(&fn);
52
10.2k
  isc_buffer_t buffer;
53
10.2k
  bool ok;
54
55
10.2k
  REQUIRE(type == dns_rdatatype_mx);
56
57
10.2k
  UNUSED(type);
58
10.2k
  UNUSED(rdclass);
59
60
10.2k
  RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
61
10.2k
              false));
62
10.2k
  if (token.value.as_ulong > 0xffffU) {
63
18
    RETTOK(ISC_R_RANGE);
64
18
  }
65
10.2k
  RETERR(uint16_tobuffer(token.value.as_ulong, target));
66
67
10.2k
  RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
68
10.2k
              false));
69
70
10.2k
  ok = true;
71
10.2k
  if ((options & DNS_RDATA_CHECKMX) != 0) {
72
0
    ok = check_mx(&token);
73
0
  }
74
10.2k
  if (!ok && (options & DNS_RDATA_CHECKMXFAIL) != 0) {
75
0
    RETTOK(DNS_R_MXISADDRESS);
76
0
  }
77
10.2k
  if (!ok && callbacks != NULL) {
78
0
    warn_badmx(&token, lexer, callbacks);
79
0
  }
80
81
10.2k
  buffer_fromregion(&buffer, &token.value.as_region);
82
10.2k
  if (origin == NULL) {
83
2
    origin = dns_rootname;
84
2
  }
85
10.2k
  RETTOK(dns_name_fromtext(name, &buffer, origin, options));
86
10.1k
  RETTOK(dns_name_towire(name, NULL, target));
87
10.1k
  ok = true;
88
10.1k
  if ((options & DNS_RDATA_CHECKNAMES) != 0) {
89
0
    ok = dns_name_ishostname(name, false);
90
0
  }
91
10.1k
  if (!ok && (options & DNS_RDATA_CHECKNAMESFAIL) != 0) {
92
0
    RETTOK(DNS_R_BADNAME);
93
0
  }
94
10.1k
  if (!ok && callbacks != NULL) {
95
0
    warn_badname(name, lexer, callbacks);
96
0
  }
97
10.1k
  return ISC_R_SUCCESS;
98
10.1k
}
99
100
static isc_result_t
101
1.06k
totext_mx(ARGS_TOTEXT) {
102
1.06k
  isc_region_t region;
103
1.06k
  dns_name_t name;
104
1.06k
  dns_name_t prefix;
105
1.06k
  unsigned int opts;
106
1.06k
  char buf[sizeof("64000")];
107
1.06k
  unsigned short num;
108
109
1.06k
  REQUIRE(rdata->type == dns_rdatatype_mx);
110
1.06k
  REQUIRE(rdata->length != 0);
111
112
1.06k
  dns_name_init(&name);
113
1.06k
  dns_name_init(&prefix);
114
115
1.06k
  dns_rdata_toregion(rdata, &region);
116
1.06k
  num = uint16_fromregion(&region);
117
1.06k
  isc_region_consume(&region, 2);
118
1.06k
  snprintf(buf, sizeof(buf), "%u", num);
119
1.06k
  RETERR(str_totext(buf, target));
120
121
1.06k
  RETERR(str_totext(" ", target));
122
123
1.06k
  dns_name_fromregion(&name, &region);
124
1.06k
  opts = name_prefix(&name, tctx->origin, &prefix) ? DNS_NAME_OMITFINALDOT
125
1.06k
               : 0;
126
1.06k
  return dns_name_totext(&prefix, opts, target);
127
1.06k
}
128
129
static isc_result_t
130
1.48k
fromwire_mx(ARGS_FROMWIRE) {
131
1.48k
  dns_name_t name;
132
1.48k
  isc_region_t sregion;
133
134
1.48k
  REQUIRE(type == dns_rdatatype_mx);
135
136
1.48k
  UNUSED(type);
137
1.48k
  UNUSED(rdclass);
138
139
1.48k
  dctx = dns_decompress_setpermitted(dctx, true);
140
141
1.48k
  dns_name_init(&name);
142
143
1.48k
  isc_buffer_activeregion(source, &sregion);
144
1.48k
  if (sregion.length < 2) {
145
10
    return ISC_R_UNEXPECTEDEND;
146
10
  }
147
1.47k
  RETERR(mem_tobuffer(target, sregion.base, 2));
148
1.37k
  isc_buffer_forward(source, 2);
149
1.37k
  return dns_name_fromwire(&name, source, dctx, target);
150
1.47k
}
151
152
static isc_result_t
153
536
towire_mx(ARGS_TOWIRE) {
154
536
  dns_name_t name;
155
536
  isc_region_t region;
156
157
536
  REQUIRE(rdata->type == dns_rdatatype_mx);
158
536
  REQUIRE(rdata->length != 0);
159
160
536
  dns_compress_setpermitted(cctx, true);
161
162
536
  dns_rdata_toregion(rdata, &region);
163
536
  RETERR(mem_tobuffer(target, region.base, 2));
164
535
  isc_region_consume(&region, 2);
165
166
535
  dns_name_init(&name);
167
535
  dns_name_fromregion(&name, &region);
168
169
535
  return dns_name_towire(&name, cctx, target);
170
536
}
171
172
static int
173
6.19M
compare_mx(ARGS_COMPARE) {
174
6.19M
  dns_name_t name1;
175
6.19M
  dns_name_t name2;
176
6.19M
  isc_region_t region1;
177
6.19M
  isc_region_t region2;
178
6.19M
  int order;
179
180
6.19M
  REQUIRE(rdata1->type == rdata2->type);
181
6.19M
  REQUIRE(rdata1->rdclass == rdata2->rdclass);
182
6.19M
  REQUIRE(rdata1->type == dns_rdatatype_mx);
183
6.19M
  REQUIRE(rdata1->length != 0);
184
6.19M
  REQUIRE(rdata2->length != 0);
185
186
6.19M
  order = memcmp(rdata1->data, rdata2->data, 2);
187
6.19M
  if (order != 0) {
188
6.19M
    return order < 0 ? -1 : 1;
189
6.19M
  }
190
191
7.65k
  dns_name_init(&name1);
192
7.65k
  dns_name_init(&name2);
193
194
7.65k
  dns_rdata_toregion(rdata1, &region1);
195
7.65k
  dns_rdata_toregion(rdata2, &region2);
196
197
7.65k
  isc_region_consume(&region1, 2);
198
7.65k
  isc_region_consume(&region2, 2);
199
200
7.65k
  dns_name_fromregion(&name1, &region1);
201
7.65k
  dns_name_fromregion(&name2, &region2);
202
203
7.65k
  return dns_name_rdatacompare(&name1, &name2);
204
6.19M
}
205
206
static isc_result_t
207
0
fromstruct_mx(ARGS_FROMSTRUCT) {
208
0
  dns_rdata_mx_t *mx = source;
209
0
  isc_region_t region;
210
211
0
  REQUIRE(type == dns_rdatatype_mx);
212
0
  REQUIRE(mx != NULL);
213
0
  REQUIRE(mx->common.rdtype == type);
214
0
  REQUIRE(mx->common.rdclass == rdclass);
215
216
0
  UNUSED(type);
217
0
  UNUSED(rdclass);
218
219
0
  RETERR(uint16_tobuffer(mx->pref, target));
220
0
  dns_name_toregion(&mx->mx, &region);
221
0
  return isc_buffer_copyregion(target, &region);
222
0
}
223
224
static isc_result_t
225
0
tostruct_mx(ARGS_TOSTRUCT) {
226
0
  isc_region_t region;
227
0
  dns_rdata_mx_t *mx = target;
228
0
  dns_name_t name;
229
230
0
  REQUIRE(rdata->type == dns_rdatatype_mx);
231
0
  REQUIRE(mx != NULL);
232
0
  REQUIRE(rdata->length != 0);
233
234
0
  DNS_RDATACOMMON_INIT(mx, rdata->type, rdata->rdclass);
235
236
0
  dns_name_init(&name);
237
0
  dns_rdata_toregion(rdata, &region);
238
0
  mx->pref = uint16_fromregion(&region);
239
0
  isc_region_consume(&region, 2);
240
0
  dns_name_fromregion(&name, &region);
241
0
  dns_name_init(&mx->mx);
242
0
  name_duporclone(&name, mctx, &mx->mx);
243
0
  mx->mctx = mctx;
244
0
  return ISC_R_SUCCESS;
245
0
}
246
247
static void
248
0
freestruct_mx(ARGS_FREESTRUCT) {
249
0
  dns_rdata_mx_t *mx = source;
250
251
0
  REQUIRE(mx != NULL);
252
0
  REQUIRE(mx->common.rdtype == dns_rdatatype_mx);
253
254
0
  if (mx->mctx == NULL) {
255
0
    return;
256
0
  }
257
258
0
  dns_name_free(&mx->mx, mx->mctx);
259
0
  mx->mctx = NULL;
260
0
}
261
262
static unsigned char port25_ndata[] = "\003_25\004_tcp";
263
static dns_name_t port25 = DNS_NAME_INITNONABSOLUTE(port25_ndata);
264
265
static isc_result_t
266
0
additionaldata_mx(ARGS_ADDLDATA) {
267
0
  isc_result_t result;
268
0
  dns_fixedname_t fixed;
269
0
  dns_name_t name;
270
0
  isc_region_t region;
271
272
0
  REQUIRE(rdata->type == dns_rdatatype_mx);
273
274
0
  UNUSED(owner);
275
276
0
  dns_name_init(&name);
277
0
  dns_rdata_toregion(rdata, &region);
278
0
  isc_region_consume(&region, 2);
279
0
  dns_name_fromregion(&name, &region);
280
281
0
  if (dns_name_equal(&name, dns_rootname)) {
282
0
    return ISC_R_SUCCESS;
283
0
  }
284
285
0
  RETERR((add)(arg, &name, dns_rdatatype_a, NULL DNS__DB_FILELINE));
286
287
0
  dns_fixedname_init(&fixed);
288
0
  result = dns_name_concatenate(&port25, &name,
289
0
              dns_fixedname_name(&fixed));
290
0
  if (result != ISC_R_SUCCESS) {
291
0
    return ISC_R_SUCCESS;
292
0
  }
293
294
0
  return (add)(arg, dns_fixedname_name(&fixed), dns_rdatatype_tlsa,
295
0
         NULL DNS__DB_FILELINE);
296
0
}
297
298
static isc_result_t
299
0
digest_mx(ARGS_DIGEST) {
300
0
  isc_region_t r1, r2;
301
0
  dns_name_t name;
302
303
0
  REQUIRE(rdata->type == dns_rdatatype_mx);
304
305
0
  dns_rdata_toregion(rdata, &r1);
306
0
  r2 = r1;
307
0
  isc_region_consume(&r2, 2);
308
0
  r1.length = 2;
309
0
  RETERR((digest)(arg, &r1));
310
0
  dns_name_init(&name);
311
0
  dns_name_fromregion(&name, &r2);
312
0
  return dns_name_digest(&name, digest, arg);
313
0
}
314
315
static bool
316
0
checkowner_mx(ARGS_CHECKOWNER) {
317
0
  REQUIRE(type == dns_rdatatype_mx);
318
319
0
  UNUSED(type);
320
0
  UNUSED(rdclass);
321
322
0
  return dns_name_ishostname(name, wildcard);
323
0
}
324
325
static bool
326
0
checknames_mx(ARGS_CHECKNAMES) {
327
0
  isc_region_t region;
328
0
  dns_name_t name;
329
330
0
  REQUIRE(rdata->type == dns_rdatatype_mx);
331
332
0
  UNUSED(owner);
333
334
0
  dns_rdata_toregion(rdata, &region);
335
0
  isc_region_consume(&region, 2);
336
0
  dns_name_init(&name);
337
0
  dns_name_fromregion(&name, &region);
338
0
  if (!dns_name_ishostname(&name, false)) {
339
0
    if (bad != NULL) {
340
0
      dns_name_clone(&name, bad);
341
0
    }
342
0
    return false;
343
0
  }
344
0
  return true;
345
0
}
346
347
static int
348
0
casecompare_mx(ARGS_COMPARE) {
349
0
  return compare_mx(rdata1, rdata2);
350
0
}
351
352
#endif /* RDATA_GENERIC_MX_15_C */