Coverage Report

Created: 2026-09-06 06:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/bind9/lib/dns/rdata/generic/loc_29.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
/* RFC1876 */
15
16
#ifndef RDATA_GENERIC_LOC_29_C
17
#define RDATA_GENERIC_LOC_29_C
18
19
25.9k
#define RRTYPE_LOC_ATTRIBUTES (0)
20
21
static isc_result_t
22
loc_getdecimal(const char *str, unsigned long max, size_t precision, char units,
23
7.57k
         unsigned long *valuep) {
24
7.57k
  bool ok;
25
7.57k
  char *e;
26
7.57k
  size_t i;
27
7.57k
  long tmp;
28
7.57k
  unsigned long value;
29
30
7.57k
  value = strtoul(str, &e, 10);
31
7.57k
  if (*e != 0 && *e != '.' && *e != units) {
32
56
    return DNS_R_SYNTAX;
33
56
  }
34
7.51k
  if (value > max) {
35
194
    return ISC_R_RANGE;
36
194
  }
37
7.32k
  ok = e != str;
38
7.32k
  if (*e == '.') {
39
2.53k
    e++;
40
6.34k
    for (i = 0; i < precision; i++) {
41
5.13k
      if (*e == 0 || *e == units) {
42
1.31k
        break;
43
1.31k
      }
44
3.81k
      if ((tmp = decvalue(*e++)) < 0) {
45
10
        return DNS_R_SYNTAX;
46
10
      }
47
3.80k
      ok = true;
48
3.80k
      value *= 10;
49
3.80k
      value += tmp;
50
3.80k
    }
51
4.68k
    for (; i < precision; i++) {
52
2.15k
      value *= 10;
53
2.15k
    }
54
4.78k
  } else {
55
15.5k
    for (i = 0; i < precision; i++) {
56
10.7k
      value *= 10;
57
10.7k
    }
58
4.78k
  }
59
7.31k
  if (*e != 0 && *e == units) {
60
556
    e++;
61
556
  }
62
7.31k
  if (!ok || *e != 0) {
63
33
    return DNS_R_SYNTAX;
64
33
  }
65
7.27k
  *valuep = value;
66
7.27k
  return ISC_R_SUCCESS;
67
7.31k
}
68
69
static isc_result_t
70
6.76k
loc_getprecision(const char *str, unsigned char *valuep) {
71
6.76k
  unsigned long poweroften[8] = { 1,     10,     100, 1000,
72
6.76k
          10000, 100000, 1000000, 10000000 };
73
6.76k
  unsigned long m, cm;
74
6.76k
  bool ok;
75
6.76k
  char *e;
76
6.76k
  size_t i;
77
6.76k
  long tmp;
78
6.76k
  int man;
79
6.76k
  int exp;
80
81
6.76k
  m = strtoul(str, &e, 10);
82
6.76k
  if (*e != 0 && *e != '.' && *e != 'm') {
83
44
    return DNS_R_SYNTAX;
84
44
  }
85
6.71k
  if (m > 90000000) {
86
120
    return ISC_R_RANGE;
87
120
  }
88
6.59k
  cm = 0;
89
6.59k
  ok = e != str;
90
6.59k
  if (*e == '.') {
91
2.07k
    e++;
92
4.13k
    for (i = 0; i < 2; i++) {
93
3.38k
      if (*e == 0 || *e == 'm') {
94
1.31k
        break;
95
1.31k
      }
96
2.07k
      if ((tmp = decvalue(*e++)) < 0) {
97
18
        return DNS_R_SYNTAX;
98
18
      }
99
2.05k
      ok = true;
100
2.05k
      cm *= 10;
101
2.05k
      cm += tmp;
102
2.05k
    }
103
4.12k
    for (; i < 2; i++) {
104
2.06k
      cm *= 10;
105
2.06k
    }
106
2.05k
  }
107
6.58k
  if (*e == 'm') {
108
1.49k
    e++;
109
1.49k
  }
110
6.58k
  if (!ok || *e != 0) {
111
28
    return DNS_R_SYNTAX;
112
28
  }
113
114
  /*
115
   * We don't just multiply out as we will overflow.
116
   */
117
6.55k
  if (m > 0) {
118
10.8k
    for (exp = 0; exp < 7; exp++) {
119
10.4k
      if (m < poweroften[exp + 1]) {
120
3.16k
        break;
121
3.16k
      }
122
10.4k
    }
123
3.54k
    man = m / poweroften[exp];
124
3.54k
    exp += 2;
125
3.54k
  } else if (cm >= 10) {
126
502
    man = cm / 10;
127
502
    exp = 1;
128
2.50k
  } else {
129
2.50k
    man = cm;
130
2.50k
    exp = 0;
131
2.50k
  }
132
6.55k
  *valuep = (man << 4) + exp;
133
6.55k
  return ISC_R_SUCCESS;
134
6.58k
}
135
136
static isc_result_t
137
11.1k
get_degrees(isc_lex_t *lexer, isc_token_t *token, unsigned long *d) {
138
11.1k
  RETERR(isc_lex_getmastertoken(lexer, token, isc_tokentype_number,
139
11.1k
              false));
140
11.0k
  *d = token->value.as_ulong;
141
142
11.0k
  return ISC_R_SUCCESS;
143
11.1k
}
144
145
static isc_result_t
146
check_coordinate(unsigned long d, unsigned long m, unsigned long s,
147
18.2k
     unsigned long maxd) {
148
18.2k
  if (d > maxd || m > 59U) {
149
125
    return ISC_R_RANGE;
150
125
  }
151
18.1k
  if (d == maxd && (m != 0 || s != 0)) {
152
9
    return ISC_R_RANGE;
153
9
  }
154
155
18.1k
  return ISC_R_SUCCESS;
156
18.1k
}
157
158
static isc_result_t
159
5.16k
get_minutes(isc_lex_t *lexer, isc_token_t *token, unsigned long *m) {
160
5.16k
  RETERR(isc_lex_getmastertoken(lexer, token, isc_tokentype_number,
161
5.16k
              false));
162
163
5.12k
  *m = token->value.as_ulong;
164
165
5.12k
  return ISC_R_SUCCESS;
166
5.16k
}
167
168
static isc_result_t
169
2.33k
get_seconds(isc_lex_t *lexer, isc_token_t *token, unsigned long *s) {
170
2.33k
  RETERR(isc_lex_getmastertoken(lexer, token, isc_tokentype_string,
171
2.33k
              false));
172
2.33k
  RETERR(loc_getdecimal(DNS_AS_STR(*token), 59, 3, '\0', s));
173
174
2.07k
  return ISC_R_SUCCESS;
175
2.33k
}
176
177
static isc_result_t
178
get_direction(isc_lex_t *lexer, isc_token_t *token, const char *directions,
179
18.1k
        int *direction) {
180
18.1k
  RETERR(isc_lex_getmastertoken(lexer, token, isc_tokentype_string,
181
18.1k
              false));
182
183
18.0k
  if (DNS_AS_STR(*token)[0] == directions[1] &&
184
5.42k
      token->value.as_textregion.length == 1)
185
5.41k
  {
186
5.41k
    *direction = DNS_AS_STR(*token)[0];
187
5.41k
    return ISC_R_SUCCESS;
188
5.41k
  }
189
190
12.6k
  if (DNS_AS_STR(*token)[0] == directions[0] &&
191
5.16k
      token->value.as_textregion.length == 1)
192
5.14k
  {
193
5.14k
    *direction = DNS_AS_STR(*token)[0];
194
5.14k
    return ISC_R_SUCCESS;
195
5.14k
  }
196
197
7.52k
  *direction = 0;
198
7.52k
  isc_lex_ungettoken(lexer, token);
199
7.52k
  return ISC_R_SUCCESS;
200
12.6k
}
201
202
static isc_result_t
203
loc_getcoordinate(isc_lex_t *lexer, unsigned long *dp, unsigned long *mp,
204
      unsigned long *sp, const char *directions, int *directionp,
205
11.1k
      unsigned long maxd) {
206
11.1k
  isc_result_t result = ISC_R_SUCCESS;
207
11.1k
  isc_token_t token;
208
11.1k
  unsigned long d, m, s;
209
11.1k
  int direction = 0;
210
211
11.1k
  m = 0;
212
11.1k
  s = 0;
213
214
  /*
215
   * Degrees.
216
   */
217
11.1k
  RETERR(get_degrees(lexer, &token, &d));
218
11.0k
  RETTOK(check_coordinate(d, m, s, maxd));
219
220
  /*
221
   * Minutes.
222
   */
223
11.0k
  RETERR(get_direction(lexer, &token, directions, &direction));
224
10.9k
  if (direction > 0) {
225
5.82k
    goto done;
226
5.82k
  }
227
228
5.16k
  RETERR(get_minutes(lexer, &token, &m));
229
5.12k
  RETTOK(check_coordinate(d, m, s, maxd));
230
231
  /*
232
   * Seconds.
233
   */
234
5.08k
  RETERR(get_direction(lexer, &token, directions, &direction));
235
5.06k
  if (direction > 0) {
236
2.73k
    goto done;
237
2.73k
  }
238
239
2.33k
  result = get_seconds(lexer, &token, &s);
240
2.33k
  if (result == ISC_R_RANGE || result == DNS_R_SYNTAX) {
241
260
    RETTOK(result);
242
260
  }
243
2.07k
  RETERR(result);
244
2.07k
  RETTOK(check_coordinate(d, m, s, maxd));
245
246
  /*
247
   * Direction.
248
   */
249
2.06k
  RETERR(get_direction(lexer, &token, directions, &direction));
250
2.03k
  if (direction == 0) {
251
25
    RETERR(DNS_R_SYNTAX);
252
0
  }
253
10.5k
done:
254
255
10.5k
  *directionp = direction;
256
10.5k
  *dp = d;
257
10.5k
  *mp = m;
258
10.5k
  *sp = s;
259
260
10.5k
  return ISC_R_SUCCESS;
261
2.03k
}
262
263
static isc_result_t
264
5.81k
loc_getlatitude(isc_lex_t *lexer, unsigned long *latitude) {
265
5.81k
  unsigned long d1 = 0, m1 = 0, s1 = 0;
266
5.81k
  int direction = 0;
267
268
5.81k
  RETERR(loc_getcoordinate(lexer, &d1, &m1, &s1, "SN", &direction, 90U));
269
270
5.30k
  switch (direction) {
271
4.54k
  case 'N':
272
4.54k
    *latitude = 0x80000000 + (d1 * 3600 + m1 * 60) * 1000 + s1;
273
4.54k
    break;
274
766
  case 'S':
275
766
    *latitude = 0x80000000 - (d1 * 3600 + m1 * 60) * 1000 - s1;
276
766
    break;
277
0
  default:
278
0
    UNREACHABLE();
279
5.30k
  }
280
281
5.30k
  return ISC_R_SUCCESS;
282
5.30k
}
283
284
static isc_result_t
285
5.30k
loc_getlongitude(isc_lex_t *lexer, unsigned long *longitude) {
286
5.30k
  unsigned long d2 = 0, m2 = 0, s2 = 0;
287
5.30k
  int direction = 0;
288
289
5.30k
  RETERR(loc_getcoordinate(lexer, &d2, &m2, &s2, "WE", &direction, 180U));
290
291
5.25k
  switch (direction) {
292
871
  case 'E':
293
871
    *longitude = 0x80000000 + (d2 * 3600 + m2 * 60) * 1000 + s2;
294
871
    break;
295
4.38k
  case 'W':
296
4.38k
    *longitude = 0x80000000 - (d2 * 3600 + m2 * 60) * 1000 - s2;
297
4.38k
    break;
298
0
  default:
299
0
    UNREACHABLE();
300
5.25k
  }
301
302
5.25k
  return ISC_R_SUCCESS;
303
5.25k
}
304
305
static isc_result_t
306
5.25k
loc_getaltitude(isc_lex_t *lexer, unsigned long *altitude) {
307
5.25k
  isc_token_t token;
308
5.25k
  unsigned long cm;
309
5.25k
  const char *str;
310
311
5.25k
  RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
312
5.25k
              false));
313
5.23k
  str = DNS_AS_STR(token);
314
5.23k
  if (DNS_AS_STR(token)[0] == '-') {
315
425
    RETTOK(loc_getdecimal(str + 1, 100000, 2, 'm', &cm));
316
422
    if (cm > 10000000UL) {
317
1
      RETTOK(ISC_R_RANGE);
318
1
    }
319
421
    *altitude = 10000000 - cm;
320
4.81k
  } else {
321
4.81k
    RETTOK(loc_getdecimal(str, 42849672, 2, 'm', &cm));
322
4.78k
    if (cm > 4284967295UL) {
323
0
      RETTOK(ISC_R_RANGE);
324
0
    }
325
4.78k
    *altitude = 10000000 + cm;
326
4.78k
  }
327
328
5.20k
  return ISC_R_SUCCESS;
329
5.23k
}
330
331
static isc_result_t
332
10.4k
loc_getoptionalprecision(isc_lex_t *lexer, unsigned char *valuep) {
333
10.4k
  isc_token_t token;
334
335
10.4k
  RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
336
10.4k
              true));
337
10.3k
  if (token.type == isc_tokentype_eol || token.type == isc_tokentype_eof)
338
3.61k
  {
339
3.61k
    isc_lex_ungettoken(lexer, &token);
340
3.61k
    return ISC_R_NOMORE;
341
3.61k
  }
342
6.76k
  RETTOK(loc_getprecision(DNS_AS_STR(token), valuep));
343
344
6.55k
  return ISC_R_SUCCESS;
345
6.76k
}
346
347
static isc_result_t
348
5.20k
loc_getsize(isc_lex_t *lexer, unsigned char *sizep) {
349
5.20k
  return loc_getoptionalprecision(lexer, sizep);
350
5.20k
}
351
352
static isc_result_t
353
2.90k
loc_gethorizontalprecision(isc_lex_t *lexer, unsigned char *hpp) {
354
2.90k
  return loc_getoptionalprecision(lexer, hpp);
355
2.90k
}
356
357
static isc_result_t
358
2.36k
loc_getverticalprecision(isc_lex_t *lexer, unsigned char *vpp) {
359
2.36k
  return loc_getoptionalprecision(lexer, vpp);
360
2.36k
}
361
362
/* The LOC record is expressed in a master file in the following format:
363
 *
364
 * <owner> <TTL> <class> LOC ( d1 [m1 [s1]] {"N"|"S"} d2 [m2 [s2]]
365
 *                             {"E"|"W"} alt["m"] [siz["m"] [hp["m"]
366
 *                             [vp["m"]]]] )
367
 *
368
 * (The parentheses are used for multi-line data as specified in [RFC
369
 * 1035] section 5.1.)
370
 *
371
 * where:
372
 *
373
 *     d1:     [0 .. 90]            (degrees latitude)
374
 *     d2:     [0 .. 180]           (degrees longitude)
375
 *     m1, m2: [0 .. 59]            (minutes latitude/longitude)
376
 *     s1, s2: [0 .. 59.999]        (seconds latitude/longitude)
377
 *     alt:    [-100000.00 .. 42849672.95] BY .01 (altitude in meters)
378
 *     siz, hp, vp: [0 .. 90000000.00] (size/precision in meters)
379
 *
380
 * If omitted, minutes and seconds default to zero, size defaults to 1m,
381
 * horizontal precision defaults to 10000m, and vertical precision
382
 * defaults to 10m.  These defaults are chosen to represent typical
383
 * ZIP/postal code area sizes, since it is often easy to find
384
 * approximate geographical location by ZIP/postal code.
385
 */
386
static isc_result_t
387
5.81k
fromtext_loc(ARGS_FROMTEXT) {
388
5.81k
  isc_result_t result = ISC_R_SUCCESS;
389
5.81k
  unsigned long latitude = 0;
390
5.81k
  unsigned long longitude = 0;
391
5.81k
  unsigned long altitude = 0;
392
5.81k
  unsigned char size = 0x12; /* Default: 1.00m */
393
5.81k
  unsigned char hp = 0x16;   /* Default: 10000.00 m */
394
5.81k
  unsigned char vp = 0x13;   /* Default: 10.00 m */
395
5.81k
  unsigned char version = 0;
396
397
5.81k
  REQUIRE(type == dns_rdatatype_loc);
398
399
5.81k
  UNUSED(type);
400
5.81k
  UNUSED(rdclass);
401
5.81k
  UNUSED(origin);
402
5.81k
  UNUSED(options);
403
5.81k
  UNUSED(callbacks);
404
405
5.81k
  RETERR(loc_getlatitude(lexer, &latitude));
406
5.30k
  RETERR(loc_getlongitude(lexer, &longitude));
407
5.25k
  RETERR(loc_getaltitude(lexer, &altitude));
408
5.20k
  result = loc_getsize(lexer, &size);
409
5.20k
  if (result == ISC_R_NOMORE) {
410
2.07k
    result = ISC_R_SUCCESS;
411
2.07k
    goto encode;
412
2.07k
  }
413
3.12k
  RETERR(result);
414
2.90k
  result = loc_gethorizontalprecision(lexer, &hp);
415
2.90k
  if (result == ISC_R_NOMORE) {
416
495
    result = ISC_R_SUCCESS;
417
495
    goto encode;
418
495
  }
419
2.41k
  RETERR(result);
420
2.36k
  result = loc_getverticalprecision(lexer, &vp);
421
2.36k
  if (result == ISC_R_NOMORE) {
422
1.04k
    result = ISC_R_SUCCESS;
423
1.04k
    goto encode;
424
1.04k
  }
425
1.31k
  RETERR(result);
426
4.90k
encode:
427
4.90k
  RETERR(mem_tobuffer(target, &version, 1));
428
4.90k
  RETERR(mem_tobuffer(target, &size, 1));
429
4.90k
  RETERR(mem_tobuffer(target, &hp, 1));
430
4.90k
  RETERR(mem_tobuffer(target, &vp, 1));
431
432
4.90k
  RETERR(uint32_tobuffer(latitude, target));
433
4.90k
  RETERR(uint32_tobuffer(longitude, target));
434
4.90k
  RETERR(uint32_tobuffer(altitude, target));
435
436
4.90k
  return result;
437
4.90k
}
438
439
static isc_result_t
440
4.53k
totext_loc(ARGS_TOTEXT) {
441
4.53k
  int d1, m1, s1, fs1;
442
4.53k
  int d2, m2, s2, fs2;
443
4.53k
  unsigned long latitude;
444
4.53k
  unsigned long longitude;
445
4.53k
  unsigned long altitude;
446
4.53k
  bool north;
447
4.53k
  bool east;
448
4.53k
  bool below;
449
4.53k
  isc_region_t sr;
450
4.53k
  char sbuf[sizeof("90000000m")];
451
4.53k
  char hbuf[sizeof("90000000m")];
452
4.53k
  char vbuf[sizeof("90000000m")];
453
  /* "89 59 59.999 N 179 59 59.999 E " */
454
  /* "-42849672.95m 90000000m 90000000m 90000000m"; */
455
4.53k
  char buf[8 * 6 + 12 * 1 + 2 * 10 + sizeof(sbuf) + sizeof(hbuf) +
456
4.53k
     sizeof(vbuf)];
457
4.53k
  unsigned char size, hp, vp;
458
4.53k
  unsigned long poweroften[8] = { 1,     10,     100, 1000,
459
4.53k
          10000, 100000, 1000000, 10000000 };
460
461
4.53k
  UNUSED(tctx);
462
463
4.53k
  REQUIRE(rdata->type == dns_rdatatype_loc);
464
4.53k
  REQUIRE(rdata->length != 0);
465
466
4.53k
  dns_rdata_toregion(rdata, &sr);
467
468
4.53k
  if (sr.base[0] != 0) {
469
1.03k
    return ISC_R_NOTIMPLEMENTED;
470
1.03k
  }
471
472
3.50k
  REQUIRE(rdata->length == 16);
473
474
3.50k
  size = sr.base[1];
475
3.50k
  INSIST((size & 0x0f) < 10 && (size >> 4) < 10);
476
3.50k
  if ((size & 0x0f) > 1) {
477
827
    snprintf(sbuf, sizeof(sbuf), "%lum",
478
827
       (size >> 4) * poweroften[(size & 0x0f) - 2]);
479
2.67k
  } else {
480
2.67k
    snprintf(sbuf, sizeof(sbuf), "0.%02lum",
481
2.67k
       (size >> 4) * poweroften[(size & 0x0f)]);
482
2.67k
  }
483
3.50k
  hp = sr.base[2];
484
3.50k
  INSIST((hp & 0x0f) < 10 && (hp >> 4) < 10);
485
3.50k
  if ((hp & 0x0f) > 1) {
486
2.36k
    snprintf(hbuf, sizeof(hbuf), "%lum",
487
2.36k
       (hp >> 4) * poweroften[(hp & 0x0f) - 2]);
488
2.36k
  } else {
489
1.13k
    snprintf(hbuf, sizeof(hbuf), "0.%02lum",
490
1.13k
       (hp >> 4) * poweroften[(hp & 0x0f)]);
491
1.13k
  }
492
3.50k
  vp = sr.base[3];
493
3.50k
  INSIST((vp & 0x0f) < 10 && (vp >> 4) < 10);
494
3.50k
  if ((vp & 0x0f) > 1) {
495
916
    snprintf(vbuf, sizeof(vbuf), "%lum",
496
916
       (vp >> 4) * poweroften[(vp & 0x0f) - 2]);
497
2.58k
  } else {
498
2.58k
    snprintf(vbuf, sizeof(vbuf), "0.%02lum",
499
2.58k
       (vp >> 4) * poweroften[(vp & 0x0f)]);
500
2.58k
  }
501
3.50k
  isc_region_consume(&sr, 4);
502
503
3.50k
  latitude = uint32_fromregion(&sr);
504
3.50k
  isc_region_consume(&sr, 4);
505
3.50k
  if (latitude >= 0x80000000) {
506
2.13k
    north = true;
507
2.13k
    latitude -= 0x80000000;
508
2.13k
  } else {
509
1.36k
    north = false;
510
1.36k
    latitude = 0x80000000 - latitude;
511
1.36k
  }
512
3.50k
  fs1 = (int)(latitude % 1000);
513
3.50k
  latitude /= 1000;
514
3.50k
  s1 = (int)(latitude % 60);
515
3.50k
  latitude /= 60;
516
3.50k
  m1 = (int)(latitude % 60);
517
3.50k
  latitude /= 60;
518
3.50k
  d1 = (int)latitude;
519
3.50k
  INSIST(latitude <= 90U);
520
521
3.50k
  longitude = uint32_fromregion(&sr);
522
3.50k
  isc_region_consume(&sr, 4);
523
3.50k
  if (longitude >= 0x80000000) {
524
1.02k
    east = true;
525
1.02k
    longitude -= 0x80000000;
526
2.47k
  } else {
527
2.47k
    east = false;
528
2.47k
    longitude = 0x80000000 - longitude;
529
2.47k
  }
530
3.50k
  fs2 = (int)(longitude % 1000);
531
3.50k
  longitude /= 1000;
532
3.50k
  s2 = (int)(longitude % 60);
533
3.50k
  longitude /= 60;
534
3.50k
  m2 = (int)(longitude % 60);
535
3.50k
  longitude /= 60;
536
3.50k
  d2 = (int)longitude;
537
3.50k
  INSIST(longitude <= 180U);
538
539
3.50k
  altitude = uint32_fromregion(&sr);
540
3.50k
  isc_region_consume(&sr, 4);
541
3.50k
  if (altitude < 10000000U) {
542
404
    below = true;
543
404
    altitude = 10000000 - altitude;
544
3.09k
  } else {
545
3.09k
    below = false;
546
3.09k
    altitude -= 10000000;
547
3.09k
  }
548
549
3.50k
  snprintf(buf, sizeof(buf),
550
3.50k
     "%d %d %d.%03d %s %d %d %d.%03d %s %s%lu.%02lum %s %s %s", d1,
551
3.50k
     m1, s1, fs1, north ? "N" : "S", d2, m2, s2, fs2,
552
3.50k
     east ? "E" : "W", below ? "-" : "", altitude / 100,
553
3.50k
     altitude % 100, sbuf, hbuf, vbuf);
554
555
3.50k
  return str_totext(buf, target);
556
4.53k
}
557
558
static isc_result_t
559
6.02k
fromwire_loc(ARGS_FROMWIRE) {
560
6.02k
  isc_region_t sr;
561
6.02k
  unsigned char c;
562
6.02k
  unsigned long latitude;
563
6.02k
  unsigned long longitude;
564
565
6.02k
  REQUIRE(type == dns_rdatatype_loc);
566
567
6.02k
  UNUSED(type);
568
6.02k
  UNUSED(rdclass);
569
6.02k
  UNUSED(dctx);
570
571
6.02k
  isc_buffer_activeregion(source, &sr);
572
6.02k
  if (sr.length < 1) {
573
5
    return ISC_R_UNEXPECTEDEND;
574
5
  }
575
6.02k
  if (sr.base[0] != 0) {
576
    /* Treat as unknown. */
577
2.20k
    isc_buffer_forward(source, sr.length);
578
2.20k
    return mem_tobuffer(target, sr.base, sr.length);
579
2.20k
  }
580
3.82k
  if (sr.length < 16) {
581
14
    return ISC_R_UNEXPECTEDEND;
582
14
  }
583
584
  /*
585
   * Size.
586
   */
587
3.80k
  c = sr.base[1];
588
3.80k
  if (c != 0) {
589
1.41k
    if ((c & 0xf) > 9 || ((c >> 4) & 0xf) > 9 ||
590
1.39k
        ((c >> 4) & 0xf) == 0)
591
20
    {
592
20
      return ISC_R_RANGE;
593
594
      /*
595
       * Horizontal precision.
596
       */
597
20
    }
598
1.41k
  }
599
600
  /*
601
   * Horizontal precision.
602
   */
603
3.78k
  c = sr.base[2];
604
3.78k
  if (c != 0) {
605
2.92k
    if ((c & 0xf) > 9 || ((c >> 4) & 0xf) > 9 ||
606
2.91k
        ((c >> 4) & 0xf) == 0)
607
15
    {
608
15
      return ISC_R_RANGE;
609
610
      /*
611
       * Vertical precision.
612
       */
613
15
    }
614
2.92k
  }
615
616
  /*
617
   * Vertical precision.
618
   */
619
3.77k
  c = sr.base[3];
620
3.77k
  if (c != 0) {
621
2.80k
    if ((c & 0xf) > 9 || ((c >> 4) & 0xf) > 9 ||
622
2.78k
        ((c >> 4) & 0xf) == 0)
623
21
    {
624
21
      return ISC_R_RANGE;
625
21
    }
626
2.80k
  }
627
3.75k
  isc_region_consume(&sr, 4);
628
629
  /*
630
   * Latitude.
631
   */
632
3.75k
  latitude = uint32_fromregion(&sr);
633
3.75k
  if (latitude < (0x80000000UL - 90 * 3600000) ||
634
3.67k
      latitude > (0x80000000UL + 90 * 3600000))
635
81
  {
636
81
    return ISC_R_RANGE;
637
81
  }
638
3.67k
  isc_region_consume(&sr, 4);
639
640
  /*
641
   * Longitude.
642
   */
643
3.67k
  longitude = uint32_fromregion(&sr);
644
3.67k
  if (longitude < (0x80000000UL - 180 * 3600000) ||
645
3.55k
      longitude > (0x80000000UL + 180 * 3600000))
646
146
  {
647
146
    return ISC_R_RANGE;
648
146
  }
649
650
  /*
651
   * Altitude.
652
   * All values possible.
653
   */
654
655
3.52k
  isc_buffer_activeregion(source, &sr);
656
3.52k
  isc_buffer_forward(source, 16);
657
3.52k
  return mem_tobuffer(target, sr.base, 16);
658
3.67k
}
659
660
static isc_result_t
661
2.34k
towire_loc(ARGS_TOWIRE) {
662
2.34k
  UNUSED(cctx);
663
664
2.34k
  REQUIRE(rdata->type == dns_rdatatype_loc);
665
2.34k
  REQUIRE(rdata->length != 0);
666
667
2.34k
  return mem_tobuffer(target, rdata->data, rdata->length);
668
2.34k
}
669
670
static int
671
9.62k
compare_loc(ARGS_COMPARE) {
672
9.62k
  isc_region_t r1;
673
9.62k
  isc_region_t r2;
674
675
9.62k
  REQUIRE(rdata1->type == rdata2->type);
676
9.62k
  REQUIRE(rdata1->rdclass == rdata2->rdclass);
677
9.62k
  REQUIRE(rdata1->type == dns_rdatatype_loc);
678
9.62k
  REQUIRE(rdata1->length != 0);
679
9.62k
  REQUIRE(rdata2->length != 0);
680
681
9.62k
  dns_rdata_toregion(rdata1, &r1);
682
9.62k
  dns_rdata_toregion(rdata2, &r2);
683
9.62k
  return isc_region_compare(&r1, &r2);
684
9.62k
}
685
686
static isc_result_t
687
0
fromstruct_loc(ARGS_FROMSTRUCT) {
688
0
  dns_rdata_loc_t *loc = source;
689
0
  uint8_t c;
690
691
0
  REQUIRE(type == dns_rdatatype_loc);
692
0
  REQUIRE(loc != NULL);
693
0
  REQUIRE(loc->common.rdtype == type);
694
0
  REQUIRE(loc->common.rdclass == rdclass);
695
696
0
  UNUSED(type);
697
0
  UNUSED(rdclass);
698
699
0
  if (loc->v.v0.version != 0) {
700
0
    return ISC_R_NOTIMPLEMENTED;
701
0
  }
702
0
  RETERR(uint8_tobuffer(loc->v.v0.version, target));
703
704
0
  c = loc->v.v0.size;
705
0
  if ((c & 0xf) > 9 || ((c >> 4) & 0xf) > 9 || ((c >> 4) & 0xf) == 0) {
706
0
    return ISC_R_RANGE;
707
0
  }
708
0
  RETERR(uint8_tobuffer(loc->v.v0.size, target));
709
710
0
  c = loc->v.v0.horizontal;
711
0
  if ((c & 0xf) > 9 || ((c >> 4) & 0xf) > 9 || ((c >> 4) & 0xf) == 0) {
712
0
    return ISC_R_RANGE;
713
0
  }
714
0
  RETERR(uint8_tobuffer(loc->v.v0.horizontal, target));
715
716
0
  c = loc->v.v0.vertical;
717
0
  if ((c & 0xf) > 9 || ((c >> 4) & 0xf) > 9 || ((c >> 4) & 0xf) == 0) {
718
0
    return ISC_R_RANGE;
719
0
  }
720
0
  RETERR(uint8_tobuffer(loc->v.v0.vertical, target));
721
722
0
  if (loc->v.v0.latitude < (0x80000000UL - 90 * 3600000) ||
723
0
      loc->v.v0.latitude > (0x80000000UL + 90 * 3600000))
724
0
  {
725
0
    return ISC_R_RANGE;
726
0
  }
727
0
  RETERR(uint32_tobuffer(loc->v.v0.latitude, target));
728
729
0
  if (loc->v.v0.longitude < (0x80000000UL - 180 * 3600000) ||
730
0
      loc->v.v0.longitude > (0x80000000UL + 180 * 3600000))
731
0
  {
732
0
    return ISC_R_RANGE;
733
0
  }
734
0
  RETERR(uint32_tobuffer(loc->v.v0.longitude, target));
735
0
  return uint32_tobuffer(loc->v.v0.altitude, target);
736
0
}
737
738
static isc_result_t
739
0
tostruct_loc(ARGS_TOSTRUCT) {
740
0
  dns_rdata_loc_t *loc = target;
741
0
  isc_region_t r;
742
0
  uint8_t version;
743
744
0
  REQUIRE(rdata->type == dns_rdatatype_loc);
745
0
  REQUIRE(loc != NULL);
746
0
  REQUIRE(rdata->length != 0);
747
748
0
  UNUSED(mctx);
749
750
0
  dns_rdata_toregion(rdata, &r);
751
0
  version = uint8_fromregion(&r);
752
0
  if (version != 0) {
753
0
    return ISC_R_NOTIMPLEMENTED;
754
0
  }
755
756
0
  DNS_RDATACOMMON_INIT(loc, rdata->type, rdata->rdclass);
757
758
0
  loc->v.v0.version = version;
759
0
  isc_region_consume(&r, 1);
760
0
  loc->v.v0.size = uint8_fromregion(&r);
761
0
  isc_region_consume(&r, 1);
762
0
  loc->v.v0.horizontal = uint8_fromregion(&r);
763
0
  isc_region_consume(&r, 1);
764
0
  loc->v.v0.vertical = uint8_fromregion(&r);
765
0
  isc_region_consume(&r, 1);
766
0
  loc->v.v0.latitude = uint32_fromregion(&r);
767
0
  isc_region_consume(&r, 4);
768
0
  loc->v.v0.longitude = uint32_fromregion(&r);
769
0
  isc_region_consume(&r, 4);
770
0
  loc->v.v0.altitude = uint32_fromregion(&r);
771
0
  isc_region_consume(&r, 4);
772
0
  return ISC_R_SUCCESS;
773
0
}
774
775
static void
776
0
freestruct_loc(ARGS_FREESTRUCT) {
777
0
  dns_rdata_loc_t *loc = source;
778
779
0
  REQUIRE(loc != NULL);
780
0
  REQUIRE(loc->common.rdtype == dns_rdatatype_loc);
781
782
0
  UNUSED(source);
783
0
  UNUSED(loc);
784
0
}
785
786
static isc_result_t
787
0
additionaldata_loc(ARGS_ADDLDATA) {
788
0
  REQUIRE(rdata->type == dns_rdatatype_loc);
789
790
0
  UNUSED(rdata);
791
0
  UNUSED(owner);
792
0
  UNUSED(add);
793
0
  UNUSED(arg);
794
795
0
  return ISC_R_SUCCESS;
796
0
}
797
798
static isc_result_t
799
0
digest_loc(ARGS_DIGEST) {
800
0
  isc_region_t r;
801
802
0
  REQUIRE(rdata->type == dns_rdatatype_loc);
803
804
0
  dns_rdata_toregion(rdata, &r);
805
806
0
  return (digest)(arg, &r);
807
0
}
808
809
static bool
810
0
checkowner_loc(ARGS_CHECKOWNER) {
811
0
  REQUIRE(type == dns_rdatatype_loc);
812
813
0
  UNUSED(name);
814
0
  UNUSED(type);
815
0
  UNUSED(rdclass);
816
0
  UNUSED(wildcard);
817
818
0
  return true;
819
0
}
820
821
static bool
822
0
checknames_loc(ARGS_CHECKNAMES) {
823
0
  REQUIRE(rdata->type == dns_rdatatype_loc);
824
825
0
  UNUSED(rdata);
826
0
  UNUSED(owner);
827
0
  UNUSED(bad);
828
829
0
  return true;
830
0
}
831
832
static int
833
0
casecompare_loc(ARGS_COMPARE) {
834
0
  return compare_loc(rdata1, rdata2);
835
0
}
836
837
#endif /* RDATA_GENERIC_LOC_29_C */