/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 */ |