/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 | 32.6k | #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 | 8.37k | unsigned long *valuep) { |
24 | 8.37k | bool ok; |
25 | 8.37k | char *e; |
26 | 8.37k | size_t i; |
27 | 8.37k | long tmp; |
28 | 8.37k | unsigned long value; |
29 | | |
30 | 8.37k | value = strtoul(str, &e, 10); |
31 | 8.37k | if (*e != 0 && *e != '.' && *e != units) { |
32 | 64 | return DNS_R_SYNTAX; |
33 | 64 | } |
34 | 8.31k | if (value > max) { |
35 | 189 | return ISC_R_RANGE; |
36 | 189 | } |
37 | 8.12k | ok = e != str; |
38 | 8.12k | if (*e == '.') { |
39 | 1.75k | e++; |
40 | 4.98k | for (i = 0; i < precision; i++) { |
41 | 3.92k | if (*e == 0 || *e == units) { |
42 | 695 | break; |
43 | 695 | } |
44 | 3.23k | if ((tmp = decvalue(*e++)) < 0) { |
45 | 9 | return DNS_R_SYNTAX; |
46 | 9 | } |
47 | 3.22k | ok = true; |
48 | 3.22k | value *= 10; |
49 | 3.22k | value += tmp; |
50 | 3.22k | } |
51 | 2.69k | for (; i < precision; i++) { |
52 | 947 | value *= 10; |
53 | 947 | } |
54 | 6.36k | } else { |
55 | 19.9k | for (i = 0; i < precision; i++) { |
56 | 13.5k | value *= 10; |
57 | 13.5k | } |
58 | 6.36k | } |
59 | 8.11k | if (*e != 0 && *e == units) { |
60 | 757 | e++; |
61 | 757 | } |
62 | 8.11k | if (!ok || *e != 0) { |
63 | 21 | return DNS_R_SYNTAX; |
64 | 21 | } |
65 | 8.09k | *valuep = value; |
66 | 8.09k | return ISC_R_SUCCESS; |
67 | 8.11k | } |
68 | | |
69 | | static isc_result_t |
70 | 10.8k | loc_getprecision(const char *str, unsigned char *valuep) { |
71 | 10.8k | unsigned long poweroften[8] = { 1, 10, 100, 1000, |
72 | 10.8k | 10000, 100000, 1000000, 10000000 }; |
73 | 10.8k | unsigned long m, cm; |
74 | 10.8k | bool ok; |
75 | 10.8k | char *e; |
76 | 10.8k | size_t i; |
77 | 10.8k | long tmp; |
78 | 10.8k | int man; |
79 | 10.8k | int exp; |
80 | | |
81 | 10.8k | m = strtoul(str, &e, 10); |
82 | 10.8k | if (*e != 0 && *e != '.' && *e != 'm') { |
83 | 48 | return DNS_R_SYNTAX; |
84 | 48 | } |
85 | 10.8k | if (m > 90000000) { |
86 | 102 | return ISC_R_RANGE; |
87 | 102 | } |
88 | 10.7k | cm = 0; |
89 | 10.7k | ok = e != str; |
90 | 10.7k | if (*e == '.') { |
91 | 1.45k | e++; |
92 | 3.65k | for (i = 0; i < 2; i++) { |
93 | 2.69k | if (*e == 0 || *e == 'm') { |
94 | 487 | break; |
95 | 487 | } |
96 | 2.20k | if ((tmp = decvalue(*e++)) < 0) { |
97 | 8 | return DNS_R_SYNTAX; |
98 | 8 | } |
99 | 2.20k | ok = true; |
100 | 2.20k | cm *= 10; |
101 | 2.20k | cm += tmp; |
102 | 2.20k | } |
103 | 2.15k | for (; i < 2; i++) { |
104 | 701 | cm *= 10; |
105 | 701 | } |
106 | 1.45k | } |
107 | 10.7k | if (*e == 'm') { |
108 | 1.22k | e++; |
109 | 1.22k | } |
110 | 10.7k | if (!ok || *e != 0) { |
111 | 22 | return DNS_R_SYNTAX; |
112 | 22 | } |
113 | | |
114 | | /* |
115 | | * We don't just multiply out as we will overflow. |
116 | | */ |
117 | 10.7k | if (m > 0) { |
118 | 31.0k | for (exp = 0; exp < 7; exp++) { |
119 | 30.1k | if (m < poweroften[exp + 1]) { |
120 | 8.35k | break; |
121 | 8.35k | } |
122 | 30.1k | } |
123 | 9.20k | man = m / poweroften[exp]; |
124 | 9.20k | exp += 2; |
125 | 9.20k | } else if (cm >= 10) { |
126 | 772 | man = cm / 10; |
127 | 772 | exp = 1; |
128 | 772 | } else { |
129 | 722 | man = cm; |
130 | 722 | exp = 0; |
131 | 722 | } |
132 | 10.7k | *valuep = (man << 4) + exp; |
133 | 10.7k | return ISC_R_SUCCESS; |
134 | 10.7k | } |
135 | | |
136 | | static isc_result_t |
137 | 13.7k | get_degrees(isc_lex_t *lexer, isc_token_t *token, unsigned long *d) { |
138 | 13.7k | RETERR(isc_lex_getmastertoken(lexer, token, isc_tokentype_number, |
139 | 13.7k | false)); |
140 | 13.7k | *d = token->value.as_ulong; |
141 | | |
142 | 13.7k | return ISC_R_SUCCESS; |
143 | 13.7k | } |
144 | | |
145 | | static isc_result_t |
146 | | check_coordinate(unsigned long d, unsigned long m, unsigned long s, |
147 | 22.3k | unsigned long maxd) { |
148 | 22.3k | if (d > maxd || m > 59U) { |
149 | 112 | return ISC_R_RANGE; |
150 | 112 | } |
151 | 22.2k | if (d == maxd && (m != 0 || s != 0)) { |
152 | 7 | return ISC_R_RANGE; |
153 | 7 | } |
154 | | |
155 | 22.1k | return ISC_R_SUCCESS; |
156 | 22.2k | } |
157 | | |
158 | | static isc_result_t |
159 | 7.05k | get_minutes(isc_lex_t *lexer, isc_token_t *token, unsigned long *m) { |
160 | 7.05k | RETERR(isc_lex_getmastertoken(lexer, token, isc_tokentype_number, |
161 | 7.05k | false)); |
162 | | |
163 | 7.01k | *m = token->value.as_ulong; |
164 | | |
165 | 7.01k | return ISC_R_SUCCESS; |
166 | 7.05k | } |
167 | | |
168 | | static isc_result_t |
169 | 1.78k | get_seconds(isc_lex_t *lexer, isc_token_t *token, unsigned long *s) { |
170 | 1.78k | RETERR(isc_lex_getmastertoken(lexer, token, isc_tokentype_string, |
171 | 1.78k | false)); |
172 | 1.78k | RETERR(loc_getdecimal(DNS_AS_STR(*token), 59, 3, '\0', s)); |
173 | | |
174 | 1.52k | return ISC_R_SUCCESS; |
175 | 1.78k | } |
176 | | |
177 | | static isc_result_t |
178 | | get_direction(isc_lex_t *lexer, isc_token_t *token, const char *directions, |
179 | 22.1k | int *direction) { |
180 | 22.1k | RETERR(isc_lex_getmastertoken(lexer, token, isc_tokentype_string, |
181 | 22.1k | false)); |
182 | 22.1k | if (DNS_AS_STR(*token)[0] == directions[1] && |
183 | 22.1k | DNS_AS_STR(*token)[1] == 0) |
184 | 6.55k | { |
185 | 6.55k | *direction = DNS_AS_STR(*token)[0]; |
186 | 6.55k | return ISC_R_SUCCESS; |
187 | 6.55k | } |
188 | | |
189 | 15.5k | if (DNS_AS_STR(*token)[0] == directions[0] && |
190 | 15.5k | DNS_AS_STR(*token)[1] == 0) |
191 | 6.71k | { |
192 | 6.71k | *direction = DNS_AS_STR(*token)[0]; |
193 | 6.71k | return ISC_R_SUCCESS; |
194 | 6.71k | } |
195 | | |
196 | 8.85k | *direction = 0; |
197 | 8.85k | isc_lex_ungettoken(lexer, token); |
198 | 8.85k | return ISC_R_SUCCESS; |
199 | 15.5k | } |
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 | 13.7k | unsigned long maxd) { |
205 | 13.7k | isc_result_t result = ISC_R_SUCCESS; |
206 | 13.7k | isc_token_t token; |
207 | 13.7k | unsigned long d, m, s; |
208 | 13.7k | int direction = 0; |
209 | | |
210 | 13.7k | m = 0; |
211 | 13.7k | s = 0; |
212 | | |
213 | | /* |
214 | | * Degrees. |
215 | | */ |
216 | 13.7k | RETERR(get_degrees(lexer, &token, &d)); |
217 | 13.7k | RETTOK(check_coordinate(d, m, s, maxd)); |
218 | | |
219 | | /* |
220 | | * Minutes. |
221 | | */ |
222 | 13.7k | RETERR(get_direction(lexer, &token, directions, &direction)); |
223 | 13.6k | if (direction > 0) { |
224 | 6.64k | goto done; |
225 | 6.64k | } |
226 | | |
227 | 7.05k | RETERR(get_minutes(lexer, &token, &m)); |
228 | 7.01k | RETTOK(check_coordinate(d, m, s, maxd)); |
229 | | |
230 | | /* |
231 | | * Seconds. |
232 | | */ |
233 | 6.96k | RETERR(get_direction(lexer, &token, directions, &direction)); |
234 | 6.94k | if (direction > 0) { |
235 | 5.16k | goto done; |
236 | 5.16k | } |
237 | | |
238 | 1.78k | result = get_seconds(lexer, &token, &s); |
239 | 1.78k | if (result == ISC_R_RANGE || result == DNS_R_SYNTAX) { |
240 | 256 | RETTOK(result); |
241 | 256 | } |
242 | 1.52k | RETERR(result); |
243 | 1.52k | RETTOK(check_coordinate(d, m, s, maxd)); |
244 | | |
245 | | /* |
246 | | * Direction. |
247 | | */ |
248 | 1.52k | RETERR(get_direction(lexer, &token, directions, &direction)); |
249 | 1.48k | if (direction == 0) { |
250 | 10 | RETERR(DNS_R_SYNTAX); |
251 | 10 | } |
252 | 13.2k | done: |
253 | | |
254 | 13.2k | *directionp = direction; |
255 | 13.2k | *dp = d; |
256 | 13.2k | *mp = m; |
257 | 13.2k | *sp = s; |
258 | | |
259 | 13.2k | return ISC_R_SUCCESS; |
260 | 1.48k | } |
261 | | |
262 | | static isc_result_t |
263 | 7.13k | loc_getlatitude(isc_lex_t *lexer, unsigned long *latitude) { |
264 | 7.13k | unsigned long d1 = 0, m1 = 0, s1 = 0; |
265 | 7.13k | int direction = 0; |
266 | | |
267 | 7.13k | RETERR(loc_getcoordinate(lexer, &d1, &m1, &s1, "SN", &direction, 90U)); |
268 | | |
269 | 6.66k | switch (direction) { |
270 | 6.11k | case 'N': |
271 | 6.11k | *latitude = 0x80000000 + (d1 * 3600 + m1 * 60) * 1000 + s1; |
272 | 6.11k | break; |
273 | 554 | case 'S': |
274 | 554 | *latitude = 0x80000000 - (d1 * 3600 + m1 * 60) * 1000 - s1; |
275 | 554 | break; |
276 | 0 | default: |
277 | 0 | UNREACHABLE(); |
278 | 6.66k | } |
279 | | |
280 | 6.66k | return ISC_R_SUCCESS; |
281 | 6.66k | } |
282 | | |
283 | | static isc_result_t |
284 | 6.66k | loc_getlongitude(isc_lex_t *lexer, unsigned long *longitude) { |
285 | 6.66k | unsigned long d2 = 0, m2 = 0, s2 = 0; |
286 | 6.66k | int direction = 0; |
287 | | |
288 | 6.66k | RETERR(loc_getcoordinate(lexer, &d2, &m2, &s2, "WE", &direction, 180U)); |
289 | | |
290 | 6.60k | switch (direction) { |
291 | 446 | case 'E': |
292 | 446 | *longitude = 0x80000000 + (d2 * 3600 + m2 * 60) * 1000 + s2; |
293 | 446 | break; |
294 | 6.16k | case 'W': |
295 | 6.16k | *longitude = 0x80000000 - (d2 * 3600 + m2 * 60) * 1000 - s2; |
296 | 6.16k | break; |
297 | 0 | default: |
298 | 0 | UNREACHABLE(); |
299 | 6.60k | } |
300 | | |
301 | 6.60k | return ISC_R_SUCCESS; |
302 | 6.60k | } |
303 | | |
304 | | static isc_result_t |
305 | 6.60k | loc_getaltitude(isc_lex_t *lexer, unsigned long *altitude) { |
306 | 6.60k | isc_token_t token; |
307 | 6.60k | unsigned long cm; |
308 | 6.60k | const char *str; |
309 | | |
310 | 6.60k | RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, |
311 | 6.60k | false)); |
312 | 6.59k | str = DNS_AS_STR(token); |
313 | 6.59k | if (DNS_AS_STR(token)[0] == '-') { |
314 | 425 | RETTOK(loc_getdecimal(str + 1, 100000, 2, 'm', &cm)); |
315 | 423 | if (cm > 10000000UL) { |
316 | 1 | RETTOK(ISC_R_RANGE); |
317 | 1 | } |
318 | 422 | *altitude = 10000000 - cm; |
319 | 6.16k | } else { |
320 | 6.16k | RETTOK(loc_getdecimal(str, 42849672, 2, 'm', &cm)); |
321 | 6.14k | if (cm > 4284967295UL) { |
322 | 0 | RETTOK(ISC_R_RANGE); |
323 | 0 | } |
324 | 6.14k | *altitude = 10000000 + cm; |
325 | 6.14k | } |
326 | | |
327 | 6.56k | return ISC_R_SUCCESS; |
328 | 6.59k | } |
329 | | |
330 | | static isc_result_t |
331 | 15.4k | loc_getoptionalprecision(isc_lex_t *lexer, unsigned char *valuep) { |
332 | 15.4k | isc_token_t token; |
333 | | |
334 | 15.4k | RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, |
335 | 15.4k | true)); |
336 | 15.3k | if (token.type == isc_tokentype_eol || token.type == isc_tokentype_eof) |
337 | 4.43k | { |
338 | 4.43k | isc_lex_ungettoken(lexer, &token); |
339 | 4.43k | return ISC_R_NOMORE; |
340 | 4.43k | } |
341 | 10.8k | RETTOK(loc_getprecision(DNS_AS_STR(token), valuep)); |
342 | | |
343 | 10.7k | return ISC_R_SUCCESS; |
344 | 10.8k | } |
345 | | |
346 | | static isc_result_t |
347 | 6.56k | loc_getsize(isc_lex_t *lexer, unsigned char *sizep) { |
348 | 6.56k | return loc_getoptionalprecision(lexer, sizep); |
349 | 6.56k | } |
350 | | |
351 | | static isc_result_t |
352 | 4.72k | loc_gethorizontalprecision(isc_lex_t *lexer, unsigned char *hpp) { |
353 | 4.72k | return loc_getoptionalprecision(lexer, hpp); |
354 | 4.72k | } |
355 | | |
356 | | static isc_result_t |
357 | 4.11k | loc_getverticalprecision(isc_lex_t *lexer, unsigned char *vpp) { |
358 | 4.11k | return loc_getoptionalprecision(lexer, vpp); |
359 | 4.11k | } |
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 | 7.13k | fromtext_loc(ARGS_FROMTEXT) { |
387 | 7.13k | isc_result_t result = ISC_R_SUCCESS; |
388 | 7.13k | unsigned long latitude = 0; |
389 | 7.13k | unsigned long longitude = 0; |
390 | 7.13k | unsigned long altitude = 0; |
391 | 7.13k | unsigned char size = 0x12; /* Default: 1.00m */ |
392 | 7.13k | unsigned char hp = 0x16; /* Default: 10000.00 m */ |
393 | 7.13k | unsigned char vp = 0x13; /* Default: 10.00 m */ |
394 | 7.13k | unsigned char version = 0; |
395 | | |
396 | 7.13k | REQUIRE(type == dns_rdatatype_loc); |
397 | | |
398 | 7.13k | UNUSED(type); |
399 | 7.13k | UNUSED(rdclass); |
400 | 7.13k | UNUSED(origin); |
401 | 7.13k | UNUSED(options); |
402 | 7.13k | UNUSED(callbacks); |
403 | | |
404 | 7.13k | RETERR(loc_getlatitude(lexer, &latitude)); |
405 | 6.66k | RETERR(loc_getlongitude(lexer, &longitude)); |
406 | 6.60k | RETERR(loc_getaltitude(lexer, &altitude)); |
407 | 6.56k | result = loc_getsize(lexer, &size); |
408 | 6.56k | if (result == ISC_R_NOMORE) { |
409 | 1.65k | result = ISC_R_SUCCESS; |
410 | 1.65k | goto encode; |
411 | 1.65k | } |
412 | 4.90k | RETERR(result); |
413 | 4.72k | result = loc_gethorizontalprecision(lexer, &hp); |
414 | 4.72k | if (result == ISC_R_NOMORE) { |
415 | 556 | result = ISC_R_SUCCESS; |
416 | 556 | goto encode; |
417 | 556 | } |
418 | 4.16k | RETERR(result); |
419 | 4.11k | result = loc_getverticalprecision(lexer, &vp); |
420 | 4.11k | if (result == ISC_R_NOMORE) { |
421 | 2.22k | result = ISC_R_SUCCESS; |
422 | 2.22k | goto encode; |
423 | 2.22k | } |
424 | 1.89k | RETERR(result); |
425 | 6.30k | encode: |
426 | 6.30k | RETERR(mem_tobuffer(target, &version, 1)); |
427 | 6.30k | RETERR(mem_tobuffer(target, &size, 1)); |
428 | 6.30k | RETERR(mem_tobuffer(target, &hp, 1)); |
429 | 6.30k | RETERR(mem_tobuffer(target, &vp, 1)); |
430 | | |
431 | 6.30k | RETERR(uint32_tobuffer(latitude, target)); |
432 | 6.30k | RETERR(uint32_tobuffer(longitude, target)); |
433 | 6.30k | RETERR(uint32_tobuffer(altitude, target)); |
434 | | |
435 | 6.30k | return result; |
436 | 6.30k | } |
437 | | |
438 | | static isc_result_t |
439 | 5.73k | totext_loc(ARGS_TOTEXT) { |
440 | 5.73k | int d1, m1, s1, fs1; |
441 | 5.73k | int d2, m2, s2, fs2; |
442 | 5.73k | unsigned long latitude; |
443 | 5.73k | unsigned long longitude; |
444 | 5.73k | unsigned long altitude; |
445 | 5.73k | bool north; |
446 | 5.73k | bool east; |
447 | 5.73k | bool below; |
448 | 5.73k | isc_region_t sr; |
449 | 5.73k | char sbuf[sizeof("90000000m")]; |
450 | 5.73k | char hbuf[sizeof("90000000m")]; |
451 | 5.73k | char vbuf[sizeof("90000000m")]; |
452 | | /* "89 59 59.999 N 179 59 59.999 E " */ |
453 | | /* "-42849672.95m 90000000m 90000000m 90000000m"; */ |
454 | 5.73k | char buf[8 * 6 + 12 * 1 + 2 * 10 + sizeof(sbuf) + sizeof(hbuf) + |
455 | 5.73k | sizeof(vbuf)]; |
456 | 5.73k | unsigned char size, hp, vp; |
457 | 5.73k | unsigned long poweroften[8] = { 1, 10, 100, 1000, |
458 | 5.73k | 10000, 100000, 1000000, 10000000 }; |
459 | | |
460 | 5.73k | UNUSED(tctx); |
461 | | |
462 | 5.73k | REQUIRE(rdata->type == dns_rdatatype_loc); |
463 | 5.73k | REQUIRE(rdata->length != 0); |
464 | | |
465 | 5.73k | dns_rdata_toregion(rdata, &sr); |
466 | | |
467 | 5.73k | if (sr.base[0] != 0) { |
468 | 1.31k | return ISC_R_NOTIMPLEMENTED; |
469 | 1.31k | } |
470 | | |
471 | 4.41k | REQUIRE(rdata->length == 16); |
472 | | |
473 | 4.41k | size = sr.base[1]; |
474 | 4.41k | INSIST((size & 0x0f) < 10 && (size >> 4) < 10); |
475 | 4.41k | if ((size & 0x0f) > 1) { |
476 | 919 | snprintf(sbuf, sizeof(sbuf), "%lum", |
477 | 919 | (size >> 4) * poweroften[(size & 0x0f) - 2]); |
478 | 3.49k | } else { |
479 | 3.49k | snprintf(sbuf, sizeof(sbuf), "0.%02lum", |
480 | 3.49k | (size >> 4) * poweroften[(size & 0x0f)]); |
481 | 3.49k | } |
482 | 4.41k | hp = sr.base[2]; |
483 | 4.41k | INSIST((hp & 0x0f) < 10 && (hp >> 4) < 10); |
484 | 4.41k | if ((hp & 0x0f) > 1) { |
485 | 3.20k | snprintf(hbuf, sizeof(hbuf), "%lum", |
486 | 3.20k | (hp >> 4) * poweroften[(hp & 0x0f) - 2]); |
487 | 3.20k | } else { |
488 | 1.20k | snprintf(hbuf, sizeof(hbuf), "0.%02lum", |
489 | 1.20k | (hp >> 4) * poweroften[(hp & 0x0f)]); |
490 | 1.20k | } |
491 | 4.41k | vp = sr.base[3]; |
492 | 4.41k | INSIST((vp & 0x0f) < 10 && (vp >> 4) < 10); |
493 | 4.41k | if ((vp & 0x0f) > 1) { |
494 | 940 | snprintf(vbuf, sizeof(vbuf), "%lum", |
495 | 940 | (vp >> 4) * poweroften[(vp & 0x0f) - 2]); |
496 | 3.47k | } else { |
497 | 3.47k | snprintf(vbuf, sizeof(vbuf), "0.%02lum", |
498 | 3.47k | (vp >> 4) * poweroften[(vp & 0x0f)]); |
499 | 3.47k | } |
500 | 4.41k | isc_region_consume(&sr, 4); |
501 | | |
502 | 4.41k | latitude = uint32_fromregion(&sr); |
503 | 4.41k | isc_region_consume(&sr, 4); |
504 | 4.41k | if (latitude >= 0x80000000) { |
505 | 2.93k | north = true; |
506 | 2.93k | latitude -= 0x80000000; |
507 | 2.93k | } else { |
508 | 1.48k | north = false; |
509 | 1.48k | latitude = 0x80000000 - latitude; |
510 | 1.48k | } |
511 | 4.41k | fs1 = (int)(latitude % 1000); |
512 | 4.41k | latitude /= 1000; |
513 | 4.41k | s1 = (int)(latitude % 60); |
514 | 4.41k | latitude /= 60; |
515 | 4.41k | m1 = (int)(latitude % 60); |
516 | 4.41k | latitude /= 60; |
517 | 4.41k | d1 = (int)latitude; |
518 | 4.41k | INSIST(latitude <= 90U); |
519 | | |
520 | 4.41k | longitude = uint32_fromregion(&sr); |
521 | 4.41k | isc_region_consume(&sr, 4); |
522 | 4.41k | if (longitude >= 0x80000000) { |
523 | 1.16k | east = true; |
524 | 1.16k | longitude -= 0x80000000; |
525 | 3.24k | } else { |
526 | 3.24k | east = false; |
527 | 3.24k | longitude = 0x80000000 - longitude; |
528 | 3.24k | } |
529 | 4.41k | fs2 = (int)(longitude % 1000); |
530 | 4.41k | longitude /= 1000; |
531 | 4.41k | s2 = (int)(longitude % 60); |
532 | 4.41k | longitude /= 60; |
533 | 4.41k | m2 = (int)(longitude % 60); |
534 | 4.41k | longitude /= 60; |
535 | 4.41k | d2 = (int)longitude; |
536 | 4.41k | INSIST(longitude <= 180U); |
537 | | |
538 | 4.41k | altitude = uint32_fromregion(&sr); |
539 | 4.41k | isc_region_consume(&sr, 4); |
540 | 4.41k | if (altitude < 10000000U) { |
541 | 720 | below = true; |
542 | 720 | altitude = 10000000 - altitude; |
543 | 3.69k | } else { |
544 | 3.69k | below = false; |
545 | 3.69k | altitude -= 10000000; |
546 | 3.69k | } |
547 | | |
548 | 4.41k | snprintf(buf, sizeof(buf), |
549 | 4.41k | "%d %d %d.%03d %s %d %d %d.%03d %s %s%lu.%02lum %s %s %s", d1, |
550 | 4.41k | m1, s1, fs1, north ? "N" : "S", d2, m2, s2, fs2, |
551 | 4.41k | east ? "E" : "W", below ? "-" : "", altitude / 100, |
552 | 4.41k | altitude % 100, sbuf, hbuf, vbuf); |
553 | | |
554 | 4.41k | return str_totext(buf, target); |
555 | 5.73k | } |
556 | | |
557 | | static isc_result_t |
558 | 6.88k | fromwire_loc(ARGS_FROMWIRE) { |
559 | 6.88k | isc_region_t sr; |
560 | 6.88k | unsigned char c; |
561 | 6.88k | unsigned long latitude; |
562 | 6.88k | unsigned long longitude; |
563 | | |
564 | 6.88k | REQUIRE(type == dns_rdatatype_loc); |
565 | | |
566 | 6.88k | UNUSED(type); |
567 | 6.88k | UNUSED(rdclass); |
568 | 6.88k | UNUSED(dctx); |
569 | | |
570 | 6.88k | isc_buffer_activeregion(source, &sr); |
571 | 6.88k | if (sr.length < 1) { |
572 | 6 | return ISC_R_UNEXPECTEDEND; |
573 | 6 | } |
574 | 6.88k | if (sr.base[0] != 0) { |
575 | | /* Treat as unknown. */ |
576 | 2.14k | isc_buffer_forward(source, sr.length); |
577 | 2.14k | return mem_tobuffer(target, sr.base, sr.length); |
578 | 2.14k | } |
579 | 4.73k | if (sr.length < 16) { |
580 | 12 | return ISC_R_UNEXPECTEDEND; |
581 | 12 | } |
582 | | |
583 | | /* |
584 | | * Size. |
585 | | */ |
586 | 4.71k | c = sr.base[1]; |
587 | 4.71k | if (c != 0) { |
588 | 1.51k | if ((c & 0xf) > 9 || ((c >> 4) & 0xf) > 9 || |
589 | 1.51k | ((c >> 4) & 0xf) == 0) |
590 | 14 | { |
591 | 14 | return ISC_R_RANGE; |
592 | | |
593 | | /* |
594 | | * Horizontal precision. |
595 | | */ |
596 | 14 | } |
597 | 1.51k | } |
598 | | |
599 | | /* |
600 | | * Horizontal precision. |
601 | | */ |
602 | 4.70k | c = sr.base[2]; |
603 | 4.70k | if (c != 0) { |
604 | 3.71k | if ((c & 0xf) > 9 || ((c >> 4) & 0xf) > 9 || |
605 | 3.71k | ((c >> 4) & 0xf) == 0) |
606 | 18 | { |
607 | 18 | return ISC_R_RANGE; |
608 | | |
609 | | /* |
610 | | * Vertical precision. |
611 | | */ |
612 | 18 | } |
613 | 3.71k | } |
614 | | |
615 | | /* |
616 | | * Vertical precision. |
617 | | */ |
618 | 4.68k | c = sr.base[3]; |
619 | 4.68k | if (c != 0) { |
620 | 3.16k | if ((c & 0xf) > 9 || ((c >> 4) & 0xf) > 9 || |
621 | 3.16k | ((c >> 4) & 0xf) == 0) |
622 | 22 | { |
623 | 22 | return ISC_R_RANGE; |
624 | 22 | } |
625 | 3.16k | } |
626 | 4.66k | isc_region_consume(&sr, 4); |
627 | | |
628 | | /* |
629 | | * Latitude. |
630 | | */ |
631 | 4.66k | latitude = uint32_fromregion(&sr); |
632 | 4.66k | if (latitude < (0x80000000UL - 90 * 3600000) || |
633 | 4.66k | latitude > (0x80000000UL + 90 * 3600000)) |
634 | 96 | { |
635 | 96 | return ISC_R_RANGE; |
636 | 96 | } |
637 | 4.56k | isc_region_consume(&sr, 4); |
638 | | |
639 | | /* |
640 | | * Longitude. |
641 | | */ |
642 | 4.56k | longitude = uint32_fromregion(&sr); |
643 | 4.56k | if (longitude < (0x80000000UL - 180 * 3600000) || |
644 | 4.56k | longitude > (0x80000000UL + 180 * 3600000)) |
645 | 176 | { |
646 | 176 | return ISC_R_RANGE; |
647 | 176 | } |
648 | | |
649 | | /* |
650 | | * Altitude. |
651 | | * All values possible. |
652 | | */ |
653 | | |
654 | 4.39k | isc_buffer_activeregion(source, &sr); |
655 | 4.39k | isc_buffer_forward(source, 16); |
656 | 4.39k | return mem_tobuffer(target, sr.base, 16); |
657 | 4.56k | } |
658 | | |
659 | | static isc_result_t |
660 | 2.88k | towire_loc(ARGS_TOWIRE) { |
661 | 2.88k | UNUSED(cctx); |
662 | | |
663 | 2.88k | REQUIRE(rdata->type == dns_rdatatype_loc); |
664 | 2.88k | REQUIRE(rdata->length != 0); |
665 | | |
666 | 2.88k | return mem_tobuffer(target, rdata->data, rdata->length); |
667 | 2.88k | } |
668 | | |
669 | | static int |
670 | 16.4k | compare_loc(ARGS_COMPARE) { |
671 | 16.4k | isc_region_t r1; |
672 | 16.4k | isc_region_t r2; |
673 | | |
674 | 16.4k | REQUIRE(rdata1->type == rdata2->type); |
675 | 16.4k | REQUIRE(rdata1->rdclass == rdata2->rdclass); |
676 | 16.4k | REQUIRE(rdata1->type == dns_rdatatype_loc); |
677 | 16.4k | REQUIRE(rdata1->length != 0); |
678 | 16.4k | REQUIRE(rdata2->length != 0); |
679 | | |
680 | 16.4k | dns_rdata_toregion(rdata1, &r1); |
681 | 16.4k | dns_rdata_toregion(rdata2, &r2); |
682 | 16.4k | return isc_region_compare(&r1, &r2); |
683 | 16.4k | } |
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 | DNS_RDATACOMMON_INIT(loc, rdata->type, rdata->rdclass); |
756 | |
|
757 | 0 | loc->v.v0.version = version; |
758 | 0 | isc_region_consume(&r, 1); |
759 | 0 | loc->v.v0.size = uint8_fromregion(&r); |
760 | 0 | isc_region_consume(&r, 1); |
761 | 0 | loc->v.v0.horizontal = uint8_fromregion(&r); |
762 | 0 | isc_region_consume(&r, 1); |
763 | 0 | loc->v.v0.vertical = uint8_fromregion(&r); |
764 | 0 | isc_region_consume(&r, 1); |
765 | 0 | loc->v.v0.latitude = uint32_fromregion(&r); |
766 | 0 | isc_region_consume(&r, 4); |
767 | 0 | loc->v.v0.longitude = uint32_fromregion(&r); |
768 | 0 | isc_region_consume(&r, 4); |
769 | 0 | loc->v.v0.altitude = uint32_fromregion(&r); |
770 | 0 | isc_region_consume(&r, 4); |
771 | 0 | return ISC_R_SUCCESS; |
772 | 0 | } |
773 | | |
774 | | static void |
775 | 0 | freestruct_loc(ARGS_FREESTRUCT) { |
776 | 0 | dns_rdata_loc_t *loc = source; |
777 | |
|
778 | 0 | REQUIRE(loc != NULL); |
779 | 0 | REQUIRE(loc->common.rdtype == dns_rdatatype_loc); |
780 | |
|
781 | 0 | UNUSED(source); |
782 | 0 | UNUSED(loc); |
783 | 0 | } |
784 | | |
785 | | static isc_result_t |
786 | 0 | additionaldata_loc(ARGS_ADDLDATA) { |
787 | 0 | REQUIRE(rdata->type == dns_rdatatype_loc); |
788 | |
|
789 | 0 | UNUSED(rdata); |
790 | 0 | UNUSED(owner); |
791 | 0 | UNUSED(add); |
792 | 0 | UNUSED(arg); |
793 | |
|
794 | 0 | return ISC_R_SUCCESS; |
795 | 0 | } |
796 | | |
797 | | static isc_result_t |
798 | 0 | digest_loc(ARGS_DIGEST) { |
799 | 0 | isc_region_t r; |
800 | |
|
801 | 0 | REQUIRE(rdata->type == dns_rdatatype_loc); |
802 | |
|
803 | 0 | dns_rdata_toregion(rdata, &r); |
804 | |
|
805 | 0 | return (digest)(arg, &r); |
806 | 0 | } |
807 | | |
808 | | static bool |
809 | 0 | checkowner_loc(ARGS_CHECKOWNER) { |
810 | 0 | REQUIRE(type == dns_rdatatype_loc); |
811 | |
|
812 | 0 | UNUSED(name); |
813 | 0 | UNUSED(type); |
814 | 0 | UNUSED(rdclass); |
815 | 0 | UNUSED(wildcard); |
816 | |
|
817 | 0 | return true; |
818 | 0 | } |
819 | | |
820 | | static bool |
821 | 0 | checknames_loc(ARGS_CHECKNAMES) { |
822 | 0 | REQUIRE(rdata->type == dns_rdatatype_loc); |
823 | |
|
824 | 0 | UNUSED(rdata); |
825 | 0 | UNUSED(owner); |
826 | 0 | UNUSED(bad); |
827 | |
|
828 | 0 | return true; |
829 | 0 | } |
830 | | |
831 | | static int |
832 | 0 | casecompare_loc(ARGS_COMPARE) { |
833 | 0 | return compare_loc(rdata1, rdata2); |
834 | 0 | } |
835 | | |
836 | | #endif /* RDATA_GENERIC_LOC_29_C */ |