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