838 lines
18 KiB
C
838 lines
18 KiB
C
/*
|
|
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
|
*
|
|
* SPDX-License-Identifier: MPL-2.0
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
|
*
|
|
* See the COPYRIGHT file distributed with this work for additional
|
|
* information regarding copyright ownership.
|
|
*/
|
|
|
|
/* RFC1876 */
|
|
|
|
#ifndef RDATA_GENERIC_LOC_29_C
|
|
#define RDATA_GENERIC_LOC_29_C
|
|
|
|
#define RRTYPE_LOC_ATTRIBUTES (0)
|
|
|
|
static isc_result_t
|
|
loc_getdecimal(const char *str, unsigned long max, size_t precision, char units,
|
|
unsigned long *valuep) {
|
|
bool ok;
|
|
char *e;
|
|
size_t i;
|
|
long tmp;
|
|
unsigned long value;
|
|
|
|
value = strtoul(str, &e, 10);
|
|
if (*e != 0 && *e != '.' && *e != units) {
|
|
return DNS_R_SYNTAX;
|
|
}
|
|
if (value > max) {
|
|
return ISC_R_RANGE;
|
|
}
|
|
ok = e != str;
|
|
if (*e == '.') {
|
|
e++;
|
|
for (i = 0; i < precision; i++) {
|
|
if (*e == 0 || *e == units) {
|
|
break;
|
|
}
|
|
if ((tmp = decvalue(*e++)) < 0) {
|
|
return DNS_R_SYNTAX;
|
|
}
|
|
ok = true;
|
|
value *= 10;
|
|
value += tmp;
|
|
}
|
|
for (; i < precision; i++) {
|
|
value *= 10;
|
|
}
|
|
} else {
|
|
for (i = 0; i < precision; i++) {
|
|
value *= 10;
|
|
}
|
|
}
|
|
if (*e != 0 && *e == units) {
|
|
e++;
|
|
}
|
|
if (!ok || *e != 0) {
|
|
return DNS_R_SYNTAX;
|
|
}
|
|
*valuep = value;
|
|
return ISC_R_SUCCESS;
|
|
}
|
|
|
|
static isc_result_t
|
|
loc_getprecision(const char *str, unsigned char *valuep) {
|
|
unsigned long poweroften[8] = { 1, 10, 100, 1000,
|
|
10000, 100000, 1000000, 10000000 };
|
|
unsigned long m, cm;
|
|
bool ok;
|
|
char *e;
|
|
size_t i;
|
|
long tmp;
|
|
int man;
|
|
int exp;
|
|
|
|
m = strtoul(str, &e, 10);
|
|
if (*e != 0 && *e != '.' && *e != 'm') {
|
|
return DNS_R_SYNTAX;
|
|
}
|
|
if (m > 90000000) {
|
|
return ISC_R_RANGE;
|
|
}
|
|
cm = 0;
|
|
ok = e != str;
|
|
if (*e == '.') {
|
|
e++;
|
|
for (i = 0; i < 2; i++) {
|
|
if (*e == 0 || *e == 'm') {
|
|
break;
|
|
}
|
|
if ((tmp = decvalue(*e++)) < 0) {
|
|
return DNS_R_SYNTAX;
|
|
}
|
|
ok = true;
|
|
cm *= 10;
|
|
cm += tmp;
|
|
}
|
|
for (; i < 2; i++) {
|
|
cm *= 10;
|
|
}
|
|
}
|
|
if (*e == 'm') {
|
|
e++;
|
|
}
|
|
if (!ok || *e != 0) {
|
|
return DNS_R_SYNTAX;
|
|
}
|
|
|
|
/*
|
|
* We don't just multiply out as we will overflow.
|
|
*/
|
|
if (m > 0) {
|
|
for (exp = 0; exp < 7; exp++) {
|
|
if (m < poweroften[exp + 1]) {
|
|
break;
|
|
}
|
|
}
|
|
man = m / poweroften[exp];
|
|
exp += 2;
|
|
} else if (cm >= 10) {
|
|
man = cm / 10;
|
|
exp = 1;
|
|
} else {
|
|
man = cm;
|
|
exp = 0;
|
|
}
|
|
*valuep = (man << 4) + exp;
|
|
return ISC_R_SUCCESS;
|
|
}
|
|
|
|
static isc_result_t
|
|
get_degrees(isc_lex_t *lexer, isc_token_t *token, unsigned long *d) {
|
|
RETERR(isc_lex_getmastertoken(lexer, token, isc_tokentype_number,
|
|
false));
|
|
*d = token->value.as_ulong;
|
|
|
|
return ISC_R_SUCCESS;
|
|
}
|
|
|
|
static isc_result_t
|
|
check_coordinate(unsigned long d, unsigned long m, unsigned long s,
|
|
unsigned long maxd) {
|
|
if (d > maxd || m > 59U) {
|
|
return ISC_R_RANGE;
|
|
}
|
|
if (d == maxd && (m != 0 || s != 0)) {
|
|
return ISC_R_RANGE;
|
|
}
|
|
|
|
return ISC_R_SUCCESS;
|
|
}
|
|
|
|
static isc_result_t
|
|
get_minutes(isc_lex_t *lexer, isc_token_t *token, unsigned long *m) {
|
|
RETERR(isc_lex_getmastertoken(lexer, token, isc_tokentype_number,
|
|
false));
|
|
|
|
*m = token->value.as_ulong;
|
|
|
|
return ISC_R_SUCCESS;
|
|
}
|
|
|
|
static isc_result_t
|
|
get_seconds(isc_lex_t *lexer, isc_token_t *token, unsigned long *s) {
|
|
RETERR(isc_lex_getmastertoken(lexer, token, isc_tokentype_string,
|
|
false));
|
|
RETERR(loc_getdecimal(DNS_AS_STR(*token), 59, 3, '\0', s));
|
|
|
|
return ISC_R_SUCCESS;
|
|
}
|
|
|
|
static isc_result_t
|
|
get_direction(isc_lex_t *lexer, isc_token_t *token, const char *directions,
|
|
int *direction) {
|
|
RETERR(isc_lex_getmastertoken(lexer, token, isc_tokentype_string,
|
|
false));
|
|
if (DNS_AS_STR(*token)[0] == directions[1] &&
|
|
DNS_AS_STR(*token)[1] == 0)
|
|
{
|
|
*direction = DNS_AS_STR(*token)[0];
|
|
return ISC_R_SUCCESS;
|
|
}
|
|
|
|
if (DNS_AS_STR(*token)[0] == directions[0] &&
|
|
DNS_AS_STR(*token)[1] == 0)
|
|
{
|
|
*direction = DNS_AS_STR(*token)[0];
|
|
return ISC_R_SUCCESS;
|
|
}
|
|
|
|
*direction = 0;
|
|
isc_lex_ungettoken(lexer, token);
|
|
return ISC_R_SUCCESS;
|
|
}
|
|
|
|
static isc_result_t
|
|
loc_getcoordinate(isc_lex_t *lexer, unsigned long *dp, unsigned long *mp,
|
|
unsigned long *sp, const char *directions, int *directionp,
|
|
unsigned long maxd) {
|
|
isc_result_t result = ISC_R_SUCCESS;
|
|
isc_token_t token;
|
|
unsigned long d, m, s;
|
|
int direction = 0;
|
|
|
|
m = 0;
|
|
s = 0;
|
|
|
|
/*
|
|
* Degrees.
|
|
*/
|
|
RETERR(get_degrees(lexer, &token, &d));
|
|
RETTOK(check_coordinate(d, m, s, maxd));
|
|
|
|
/*
|
|
* Minutes.
|
|
*/
|
|
RETERR(get_direction(lexer, &token, directions, &direction));
|
|
if (direction > 0) {
|
|
goto done;
|
|
}
|
|
|
|
RETERR(get_minutes(lexer, &token, &m));
|
|
RETTOK(check_coordinate(d, m, s, maxd));
|
|
|
|
/*
|
|
* Seconds.
|
|
*/
|
|
RETERR(get_direction(lexer, &token, directions, &direction));
|
|
if (direction > 0) {
|
|
goto done;
|
|
}
|
|
|
|
result = get_seconds(lexer, &token, &s);
|
|
if (result == ISC_R_RANGE || result == DNS_R_SYNTAX) {
|
|
RETTOK(result);
|
|
}
|
|
RETERR(result);
|
|
RETTOK(check_coordinate(d, m, s, maxd));
|
|
|
|
/*
|
|
* Direction.
|
|
*/
|
|
RETERR(get_direction(lexer, &token, directions, &direction));
|
|
if (direction == 0) {
|
|
RETERR(DNS_R_SYNTAX);
|
|
}
|
|
done:
|
|
|
|
*directionp = direction;
|
|
*dp = d;
|
|
*mp = m;
|
|
*sp = s;
|
|
|
|
return ISC_R_SUCCESS;
|
|
}
|
|
|
|
static isc_result_t
|
|
loc_getlatitude(isc_lex_t *lexer, unsigned long *latitude) {
|
|
unsigned long d1 = 0, m1 = 0, s1 = 0;
|
|
int direction = 0;
|
|
|
|
RETERR(loc_getcoordinate(lexer, &d1, &m1, &s1, "SN", &direction, 90U));
|
|
|
|
switch (direction) {
|
|
case 'N':
|
|
*latitude = 0x80000000 + (d1 * 3600 + m1 * 60) * 1000 + s1;
|
|
break;
|
|
case 'S':
|
|
*latitude = 0x80000000 - (d1 * 3600 + m1 * 60) * 1000 - s1;
|
|
break;
|
|
default:
|
|
UNREACHABLE();
|
|
}
|
|
|
|
return ISC_R_SUCCESS;
|
|
}
|
|
|
|
static isc_result_t
|
|
loc_getlongitude(isc_lex_t *lexer, unsigned long *longitude) {
|
|
unsigned long d2 = 0, m2 = 0, s2 = 0;
|
|
int direction = 0;
|
|
|
|
RETERR(loc_getcoordinate(lexer, &d2, &m2, &s2, "WE", &direction, 180U));
|
|
|
|
switch (direction) {
|
|
case 'E':
|
|
*longitude = 0x80000000 + (d2 * 3600 + m2 * 60) * 1000 + s2;
|
|
break;
|
|
case 'W':
|
|
*longitude = 0x80000000 - (d2 * 3600 + m2 * 60) * 1000 - s2;
|
|
break;
|
|
default:
|
|
UNREACHABLE();
|
|
}
|
|
|
|
return ISC_R_SUCCESS;
|
|
}
|
|
|
|
static isc_result_t
|
|
loc_getaltitude(isc_lex_t *lexer, unsigned long *altitude) {
|
|
isc_token_t token;
|
|
unsigned long cm;
|
|
const char *str;
|
|
|
|
RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
|
|
false));
|
|
str = DNS_AS_STR(token);
|
|
if (DNS_AS_STR(token)[0] == '-') {
|
|
RETTOK(loc_getdecimal(str + 1, 100000, 2, 'm', &cm));
|
|
if (cm > 10000000UL) {
|
|
RETTOK(ISC_R_RANGE);
|
|
}
|
|
*altitude = 10000000 - cm;
|
|
} else {
|
|
RETTOK(loc_getdecimal(str, 42849672, 2, 'm', &cm));
|
|
if (cm > 4284967295UL) {
|
|
RETTOK(ISC_R_RANGE);
|
|
}
|
|
*altitude = 10000000 + cm;
|
|
}
|
|
|
|
return ISC_R_SUCCESS;
|
|
}
|
|
|
|
static isc_result_t
|
|
loc_getoptionalprecision(isc_lex_t *lexer, unsigned char *valuep) {
|
|
isc_token_t token;
|
|
|
|
RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
|
|
true));
|
|
if (token.type == isc_tokentype_eol || token.type == isc_tokentype_eof)
|
|
{
|
|
isc_lex_ungettoken(lexer, &token);
|
|
return ISC_R_NOMORE;
|
|
}
|
|
RETTOK(loc_getprecision(DNS_AS_STR(token), valuep));
|
|
|
|
return ISC_R_SUCCESS;
|
|
}
|
|
|
|
static isc_result_t
|
|
loc_getsize(isc_lex_t *lexer, unsigned char *sizep) {
|
|
return loc_getoptionalprecision(lexer, sizep);
|
|
}
|
|
|
|
static isc_result_t
|
|
loc_gethorizontalprecision(isc_lex_t *lexer, unsigned char *hpp) {
|
|
return loc_getoptionalprecision(lexer, hpp);
|
|
}
|
|
|
|
static isc_result_t
|
|
loc_getverticalprecision(isc_lex_t *lexer, unsigned char *vpp) {
|
|
return loc_getoptionalprecision(lexer, vpp);
|
|
}
|
|
|
|
/* The LOC record is expressed in a master file in the following format:
|
|
*
|
|
* <owner> <TTL> <class> LOC ( d1 [m1 [s1]] {"N"|"S"} d2 [m2 [s2]]
|
|
* {"E"|"W"} alt["m"] [siz["m"] [hp["m"]
|
|
* [vp["m"]]]] )
|
|
*
|
|
* (The parentheses are used for multi-line data as specified in [RFC
|
|
* 1035] section 5.1.)
|
|
*
|
|
* where:
|
|
*
|
|
* d1: [0 .. 90] (degrees latitude)
|
|
* d2: [0 .. 180] (degrees longitude)
|
|
* m1, m2: [0 .. 59] (minutes latitude/longitude)
|
|
* s1, s2: [0 .. 59.999] (seconds latitude/longitude)
|
|
* alt: [-100000.00 .. 42849672.95] BY .01 (altitude in meters)
|
|
* siz, hp, vp: [0 .. 90000000.00] (size/precision in meters)
|
|
*
|
|
* If omitted, minutes and seconds default to zero, size defaults to 1m,
|
|
* horizontal precision defaults to 10000m, and vertical precision
|
|
* defaults to 10m. These defaults are chosen to represent typical
|
|
* ZIP/postal code area sizes, since it is often easy to find
|
|
* approximate geographical location by ZIP/postal code.
|
|
*/
|
|
static isc_result_t
|
|
fromtext_loc(ARGS_FROMTEXT) {
|
|
isc_result_t result = ISC_R_SUCCESS;
|
|
unsigned long latitude = 0;
|
|
unsigned long longitude = 0;
|
|
unsigned long altitude = 0;
|
|
unsigned char size = 0x12; /* Default: 1.00m */
|
|
unsigned char hp = 0x16; /* Default: 10000.00 m */
|
|
unsigned char vp = 0x13; /* Default: 10.00 m */
|
|
unsigned char version = 0;
|
|
|
|
REQUIRE(type == dns_rdatatype_loc);
|
|
|
|
UNUSED(type);
|
|
UNUSED(rdclass);
|
|
UNUSED(origin);
|
|
UNUSED(options);
|
|
UNUSED(callbacks);
|
|
|
|
RETERR(loc_getlatitude(lexer, &latitude));
|
|
RETERR(loc_getlongitude(lexer, &longitude));
|
|
RETERR(loc_getaltitude(lexer, &altitude));
|
|
result = loc_getsize(lexer, &size);
|
|
if (result == ISC_R_NOMORE) {
|
|
result = ISC_R_SUCCESS;
|
|
goto encode;
|
|
}
|
|
RETERR(result);
|
|
result = loc_gethorizontalprecision(lexer, &hp);
|
|
if (result == ISC_R_NOMORE) {
|
|
result = ISC_R_SUCCESS;
|
|
goto encode;
|
|
}
|
|
RETERR(result);
|
|
result = loc_getverticalprecision(lexer, &vp);
|
|
if (result == ISC_R_NOMORE) {
|
|
result = ISC_R_SUCCESS;
|
|
goto encode;
|
|
}
|
|
RETERR(result);
|
|
encode:
|
|
RETERR(mem_tobuffer(target, &version, 1));
|
|
RETERR(mem_tobuffer(target, &size, 1));
|
|
RETERR(mem_tobuffer(target, &hp, 1));
|
|
RETERR(mem_tobuffer(target, &vp, 1));
|
|
|
|
RETERR(uint32_tobuffer(latitude, target));
|
|
RETERR(uint32_tobuffer(longitude, target));
|
|
RETERR(uint32_tobuffer(altitude, target));
|
|
|
|
return result;
|
|
}
|
|
|
|
static isc_result_t
|
|
totext_loc(ARGS_TOTEXT) {
|
|
int d1, m1, s1, fs1;
|
|
int d2, m2, s2, fs2;
|
|
unsigned long latitude;
|
|
unsigned long longitude;
|
|
unsigned long altitude;
|
|
bool north;
|
|
bool east;
|
|
bool below;
|
|
isc_region_t sr;
|
|
char sbuf[sizeof("90000000m")];
|
|
char hbuf[sizeof("90000000m")];
|
|
char vbuf[sizeof("90000000m")];
|
|
/* "89 59 59.999 N 179 59 59.999 E " */
|
|
/* "-42849672.95m 90000000m 90000000m 90000000m"; */
|
|
char buf[8 * 6 + 12 * 1 + 2 * 10 + sizeof(sbuf) + sizeof(hbuf) +
|
|
sizeof(vbuf)];
|
|
unsigned char size, hp, vp;
|
|
unsigned long poweroften[8] = { 1, 10, 100, 1000,
|
|
10000, 100000, 1000000, 10000000 };
|
|
|
|
UNUSED(tctx);
|
|
|
|
REQUIRE(rdata->type == dns_rdatatype_loc);
|
|
REQUIRE(rdata->length != 0);
|
|
|
|
dns_rdata_toregion(rdata, &sr);
|
|
|
|
if (sr.base[0] != 0) {
|
|
return ISC_R_NOTIMPLEMENTED;
|
|
}
|
|
|
|
REQUIRE(rdata->length == 16);
|
|
|
|
size = sr.base[1];
|
|
INSIST((size & 0x0f) < 10 && (size >> 4) < 10);
|
|
if ((size & 0x0f) > 1) {
|
|
snprintf(sbuf, sizeof(sbuf), "%lum",
|
|
(size >> 4) * poweroften[(size & 0x0f) - 2]);
|
|
} else {
|
|
snprintf(sbuf, sizeof(sbuf), "0.%02lum",
|
|
(size >> 4) * poweroften[(size & 0x0f)]);
|
|
}
|
|
hp = sr.base[2];
|
|
INSIST((hp & 0x0f) < 10 && (hp >> 4) < 10);
|
|
if ((hp & 0x0f) > 1) {
|
|
snprintf(hbuf, sizeof(hbuf), "%lum",
|
|
(hp >> 4) * poweroften[(hp & 0x0f) - 2]);
|
|
} else {
|
|
snprintf(hbuf, sizeof(hbuf), "0.%02lum",
|
|
(hp >> 4) * poweroften[(hp & 0x0f)]);
|
|
}
|
|
vp = sr.base[3];
|
|
INSIST((vp & 0x0f) < 10 && (vp >> 4) < 10);
|
|
if ((vp & 0x0f) > 1) {
|
|
snprintf(vbuf, sizeof(vbuf), "%lum",
|
|
(vp >> 4) * poweroften[(vp & 0x0f) - 2]);
|
|
} else {
|
|
snprintf(vbuf, sizeof(vbuf), "0.%02lum",
|
|
(vp >> 4) * poweroften[(vp & 0x0f)]);
|
|
}
|
|
isc_region_consume(&sr, 4);
|
|
|
|
latitude = uint32_fromregion(&sr);
|
|
isc_region_consume(&sr, 4);
|
|
if (latitude >= 0x80000000) {
|
|
north = true;
|
|
latitude -= 0x80000000;
|
|
} else {
|
|
north = false;
|
|
latitude = 0x80000000 - latitude;
|
|
}
|
|
fs1 = (int)(latitude % 1000);
|
|
latitude /= 1000;
|
|
s1 = (int)(latitude % 60);
|
|
latitude /= 60;
|
|
m1 = (int)(latitude % 60);
|
|
latitude /= 60;
|
|
d1 = (int)latitude;
|
|
INSIST(latitude <= 90U);
|
|
|
|
longitude = uint32_fromregion(&sr);
|
|
isc_region_consume(&sr, 4);
|
|
if (longitude >= 0x80000000) {
|
|
east = true;
|
|
longitude -= 0x80000000;
|
|
} else {
|
|
east = false;
|
|
longitude = 0x80000000 - longitude;
|
|
}
|
|
fs2 = (int)(longitude % 1000);
|
|
longitude /= 1000;
|
|
s2 = (int)(longitude % 60);
|
|
longitude /= 60;
|
|
m2 = (int)(longitude % 60);
|
|
longitude /= 60;
|
|
d2 = (int)longitude;
|
|
INSIST(longitude <= 180U);
|
|
|
|
altitude = uint32_fromregion(&sr);
|
|
isc_region_consume(&sr, 4);
|
|
if (altitude < 10000000U) {
|
|
below = true;
|
|
altitude = 10000000 - altitude;
|
|
} else {
|
|
below = false;
|
|
altitude -= 10000000;
|
|
}
|
|
|
|
snprintf(buf, sizeof(buf),
|
|
"%d %d %d.%03d %s %d %d %d.%03d %s %s%lu.%02lum %s %s %s", d1,
|
|
m1, s1, fs1, north ? "N" : "S", d2, m2, s2, fs2,
|
|
east ? "E" : "W", below ? "-" : "", altitude / 100,
|
|
altitude % 100, sbuf, hbuf, vbuf);
|
|
|
|
return str_totext(buf, target);
|
|
}
|
|
|
|
static isc_result_t
|
|
fromwire_loc(ARGS_FROMWIRE) {
|
|
isc_region_t sr;
|
|
unsigned char c;
|
|
unsigned long latitude;
|
|
unsigned long longitude;
|
|
|
|
REQUIRE(type == dns_rdatatype_loc);
|
|
|
|
UNUSED(type);
|
|
UNUSED(rdclass);
|
|
UNUSED(dctx);
|
|
|
|
isc_buffer_activeregion(source, &sr);
|
|
if (sr.length < 1) {
|
|
return ISC_R_UNEXPECTEDEND;
|
|
}
|
|
if (sr.base[0] != 0) {
|
|
/* Treat as unknown. */
|
|
isc_buffer_forward(source, sr.length);
|
|
return mem_tobuffer(target, sr.base, sr.length);
|
|
}
|
|
if (sr.length < 16) {
|
|
return ISC_R_UNEXPECTEDEND;
|
|
}
|
|
|
|
/*
|
|
* Size.
|
|
*/
|
|
c = sr.base[1];
|
|
if (c != 0) {
|
|
if ((c & 0xf) > 9 || ((c >> 4) & 0xf) > 9 ||
|
|
((c >> 4) & 0xf) == 0)
|
|
{
|
|
return ISC_R_RANGE;
|
|
|
|
/*
|
|
* Horizontal precision.
|
|
*/
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Horizontal precision.
|
|
*/
|
|
c = sr.base[2];
|
|
if (c != 0) {
|
|
if ((c & 0xf) > 9 || ((c >> 4) & 0xf) > 9 ||
|
|
((c >> 4) & 0xf) == 0)
|
|
{
|
|
return ISC_R_RANGE;
|
|
|
|
/*
|
|
* Vertical precision.
|
|
*/
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Vertical precision.
|
|
*/
|
|
c = sr.base[3];
|
|
if (c != 0) {
|
|
if ((c & 0xf) > 9 || ((c >> 4) & 0xf) > 9 ||
|
|
((c >> 4) & 0xf) == 0)
|
|
{
|
|
return ISC_R_RANGE;
|
|
}
|
|
}
|
|
isc_region_consume(&sr, 4);
|
|
|
|
/*
|
|
* Latitude.
|
|
*/
|
|
latitude = uint32_fromregion(&sr);
|
|
if (latitude < (0x80000000UL - 90 * 3600000) ||
|
|
latitude > (0x80000000UL + 90 * 3600000))
|
|
{
|
|
return ISC_R_RANGE;
|
|
}
|
|
isc_region_consume(&sr, 4);
|
|
|
|
/*
|
|
* Longitude.
|
|
*/
|
|
longitude = uint32_fromregion(&sr);
|
|
if (longitude < (0x80000000UL - 180 * 3600000) ||
|
|
longitude > (0x80000000UL + 180 * 3600000))
|
|
{
|
|
return ISC_R_RANGE;
|
|
}
|
|
|
|
/*
|
|
* Altitude.
|
|
* All values possible.
|
|
*/
|
|
|
|
isc_buffer_activeregion(source, &sr);
|
|
isc_buffer_forward(source, 16);
|
|
return mem_tobuffer(target, sr.base, 16);
|
|
}
|
|
|
|
static isc_result_t
|
|
towire_loc(ARGS_TOWIRE) {
|
|
UNUSED(cctx);
|
|
|
|
REQUIRE(rdata->type == dns_rdatatype_loc);
|
|
REQUIRE(rdata->length != 0);
|
|
|
|
return mem_tobuffer(target, rdata->data, rdata->length);
|
|
}
|
|
|
|
static int
|
|
compare_loc(ARGS_COMPARE) {
|
|
isc_region_t r1;
|
|
isc_region_t r2;
|
|
|
|
REQUIRE(rdata1->type == rdata2->type);
|
|
REQUIRE(rdata1->rdclass == rdata2->rdclass);
|
|
REQUIRE(rdata1->type == dns_rdatatype_loc);
|
|
REQUIRE(rdata1->length != 0);
|
|
REQUIRE(rdata2->length != 0);
|
|
|
|
dns_rdata_toregion(rdata1, &r1);
|
|
dns_rdata_toregion(rdata2, &r2);
|
|
return isc_region_compare(&r1, &r2);
|
|
}
|
|
|
|
static isc_result_t
|
|
fromstruct_loc(ARGS_FROMSTRUCT) {
|
|
dns_rdata_loc_t *loc = source;
|
|
uint8_t c;
|
|
|
|
REQUIRE(type == dns_rdatatype_loc);
|
|
REQUIRE(loc != NULL);
|
|
REQUIRE(loc->common.rdtype == type);
|
|
REQUIRE(loc->common.rdclass == rdclass);
|
|
|
|
UNUSED(type);
|
|
UNUSED(rdclass);
|
|
|
|
if (loc->v.v0.version != 0) {
|
|
return ISC_R_NOTIMPLEMENTED;
|
|
}
|
|
RETERR(uint8_tobuffer(loc->v.v0.version, target));
|
|
|
|
c = loc->v.v0.size;
|
|
if ((c & 0xf) > 9 || ((c >> 4) & 0xf) > 9 || ((c >> 4) & 0xf) == 0) {
|
|
return ISC_R_RANGE;
|
|
}
|
|
RETERR(uint8_tobuffer(loc->v.v0.size, target));
|
|
|
|
c = loc->v.v0.horizontal;
|
|
if ((c & 0xf) > 9 || ((c >> 4) & 0xf) > 9 || ((c >> 4) & 0xf) == 0) {
|
|
return ISC_R_RANGE;
|
|
}
|
|
RETERR(uint8_tobuffer(loc->v.v0.horizontal, target));
|
|
|
|
c = loc->v.v0.vertical;
|
|
if ((c & 0xf) > 9 || ((c >> 4) & 0xf) > 9 || ((c >> 4) & 0xf) == 0) {
|
|
return ISC_R_RANGE;
|
|
}
|
|
RETERR(uint8_tobuffer(loc->v.v0.vertical, target));
|
|
|
|
if (loc->v.v0.latitude < (0x80000000UL - 90 * 3600000) ||
|
|
loc->v.v0.latitude > (0x80000000UL + 90 * 3600000))
|
|
{
|
|
return ISC_R_RANGE;
|
|
}
|
|
RETERR(uint32_tobuffer(loc->v.v0.latitude, target));
|
|
|
|
if (loc->v.v0.longitude < (0x80000000UL - 180 * 3600000) ||
|
|
loc->v.v0.longitude > (0x80000000UL + 180 * 3600000))
|
|
{
|
|
return ISC_R_RANGE;
|
|
}
|
|
RETERR(uint32_tobuffer(loc->v.v0.longitude, target));
|
|
return uint32_tobuffer(loc->v.v0.altitude, target);
|
|
}
|
|
|
|
static isc_result_t
|
|
tostruct_loc(ARGS_TOSTRUCT) {
|
|
dns_rdata_loc_t *loc = target;
|
|
isc_region_t r;
|
|
uint8_t version;
|
|
|
|
REQUIRE(rdata->type == dns_rdatatype_loc);
|
|
REQUIRE(loc != NULL);
|
|
REQUIRE(rdata->length != 0);
|
|
|
|
UNUSED(mctx);
|
|
|
|
dns_rdata_toregion(rdata, &r);
|
|
version = uint8_fromregion(&r);
|
|
if (version != 0) {
|
|
return ISC_R_NOTIMPLEMENTED;
|
|
}
|
|
|
|
loc->common.rdclass = rdata->rdclass;
|
|
loc->common.rdtype = rdata->type;
|
|
ISC_LINK_INIT(&loc->common, link);
|
|
|
|
loc->v.v0.version = version;
|
|
isc_region_consume(&r, 1);
|
|
loc->v.v0.size = uint8_fromregion(&r);
|
|
isc_region_consume(&r, 1);
|
|
loc->v.v0.horizontal = uint8_fromregion(&r);
|
|
isc_region_consume(&r, 1);
|
|
loc->v.v0.vertical = uint8_fromregion(&r);
|
|
isc_region_consume(&r, 1);
|
|
loc->v.v0.latitude = uint32_fromregion(&r);
|
|
isc_region_consume(&r, 4);
|
|
loc->v.v0.longitude = uint32_fromregion(&r);
|
|
isc_region_consume(&r, 4);
|
|
loc->v.v0.altitude = uint32_fromregion(&r);
|
|
isc_region_consume(&r, 4);
|
|
return ISC_R_SUCCESS;
|
|
}
|
|
|
|
static void
|
|
freestruct_loc(ARGS_FREESTRUCT) {
|
|
dns_rdata_loc_t *loc = source;
|
|
|
|
REQUIRE(loc != NULL);
|
|
REQUIRE(loc->common.rdtype == dns_rdatatype_loc);
|
|
|
|
UNUSED(source);
|
|
UNUSED(loc);
|
|
}
|
|
|
|
static isc_result_t
|
|
additionaldata_loc(ARGS_ADDLDATA) {
|
|
REQUIRE(rdata->type == dns_rdatatype_loc);
|
|
|
|
UNUSED(rdata);
|
|
UNUSED(owner);
|
|
UNUSED(add);
|
|
UNUSED(arg);
|
|
|
|
return ISC_R_SUCCESS;
|
|
}
|
|
|
|
static isc_result_t
|
|
digest_loc(ARGS_DIGEST) {
|
|
isc_region_t r;
|
|
|
|
REQUIRE(rdata->type == dns_rdatatype_loc);
|
|
|
|
dns_rdata_toregion(rdata, &r);
|
|
|
|
return (digest)(arg, &r);
|
|
}
|
|
|
|
static bool
|
|
checkowner_loc(ARGS_CHECKOWNER) {
|
|
REQUIRE(type == dns_rdatatype_loc);
|
|
|
|
UNUSED(name);
|
|
UNUSED(type);
|
|
UNUSED(rdclass);
|
|
UNUSED(wildcard);
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool
|
|
checknames_loc(ARGS_CHECKNAMES) {
|
|
REQUIRE(rdata->type == dns_rdatatype_loc);
|
|
|
|
UNUSED(rdata);
|
|
UNUSED(owner);
|
|
UNUSED(bad);
|
|
|
|
return true;
|
|
}
|
|
|
|
static int
|
|
casecompare_loc(ARGS_COMPARE) {
|
|
return compare_loc(rdata1, rdata2);
|
|
}
|
|
|
|
#endif /* RDATA_GENERIC_LOC_29_C */
|