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