/*
* dnsutl - utilities to make DNS easier to configure
* Copyright (C) 1996, 1999, 2000, 2006, 2007 Peter Miller
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see
* <http://www.gnu.org/licenses/>.
*/
#include <ac/ctype.h>
#include <ac/stdlib.h>
#include <ac/string.h>
#include <ac/time.h>
#include <error.h>
#include <mem.h>
#include <regu_expr.h>
#include <srrf.h>
#include <srrf/address.h>
#include <srrf/private.h>
#include <srrf/origin.h>
static int auto_time_stamp;
void
srrf_automatic_time_stamp(void)
{
auto_time_stamp = 1;
}
/* ---------- a ------------------------------------------------------------ */
static void
a_check(srrf_t *rp)
{
string_ty *s;
if (rp->arg.nstrings < 1)
return;
s = srrf_address_cannonicalize(rp->arg.string[0]);
if (!s)
{
srrf_lex_error
(
"the string \"%s\" is not a legal IP address",
rp->arg.string[0]->str_text
);
}
else
{
str_free(rp->arg.string[0]);
rp->arg.string[0] = s;
}
}
/* ---------- cname -------------------------------------------------------- */
static void
cname_check(srrf_t *rp)
{
string_ty *tmp;
string_ty *o;
if (rp->arg.nstrings != 1)
srrf_lex_error("exactly one argument required");
if (rp->arg.nstrings < 1)
return;
tmp = rp->arg.string[0];
rp->arg.string[0] = srrf_relative_to_absolute(tmp);
o = srrf_origin_get();
if (o && str_equal(rp->name, o))
srrf_lex_error("cname for $origin not allowed");
str_free(tmp);
}
static int
cname_local(srrf_t *rp)
{
return srrf_private_domain_member(rp->arg.string[0]);
}
static void
cname_a2r(srrf_t *rp)
{
string_ty *s;
s = rp->arg.string[0];
rp->arg.string[0] = srrf_absolute_to_relative(s);
str_free(s);
}
/* ---------- hinfo -------------------------------------------------------- */
static char *
first_word(const char *s)
{
const char *ep;
char *result;
char *op;
while (*s && isspace((unsigned char)*s))
++s;
ep = s;
while (*ep && !isspace(*ep))
++ep;
result = mem_alloc(ep - s + 1);
op = result;
while (s < ep)
{
if (isupper((unsigned char)*s))
*op++ = tolower((unsigned char)*s);
else
*op++ = *s;
++s;
}
*op = 0;
return result;
}
static const char *
contains_any(const char *s1, const char *s2)
{
while (*s1)
{
if (strchr(s2, *s1))
return s1;
++s1;
}
return 0;
}
static int
find_word(const char *w, const char *const *list, size_t length)
{
size_t j;
const char *pattern;
const char *yuck;
for (j = 0; j < length; ++j)
{
pattern = list[j];
/*
* see if there are no magic characters
* do a literal compare if none
*/
yuck = contains_any(pattern, ".[]*(){}^$\\|");
if (!yuck)
{
if (!strcmp(w, pattern))
return 1;
continue;
}
/*
* If there were some regex characters, compare the
* leading literal characters to try and generate a
* miss before the expensive regex calls.
*/
if (yuck > pattern)
{
if (memcmp(w, pattern, yuck - pattern) != 0)
continue;
}
if (regular_expression_match(pattern, w))
return 1;
}
return 0;
}
static char *
list_to_string(const char *const *list, size_t length)
{
size_t nbytes;
size_t j;
char *result;
char *cp;
nbytes = 0;
for (j = 0; j < length; ++j)
nbytes += 4 + strlen(list[j]);
result = mem_alloc(nbytes);
cp = result;
for (j = 0; j < length; ++j)
{
if (j)
{
*cp++ = ',';
*cp++ = ' ';
}
*cp++ = '"';
nbytes = strlen(list[j]);
memcpy(cp, list[j], nbytes);
cp += nbytes;
*cp++ = '"';
}
*cp = 0;
return result;
}
static void
hinfo_check(srrf_t *rp)
{
/*
* This is the hardware list from RFC-1010
*
* These are the Official Machine Names as they appear in the
* NIC Host Table. Their use is described in RFC 810 [39].
*
* A machine name or CPU type may be up to 40 characters taken
* from the set of uppercase letters, digits, and the two
* punctuation characters hyphen and slash. It must start with
* a letter, and end with a letter or digit.
*
* NOTE: each of these is treated as a regular expression,
* to facilitate multiple entries, e.g. SUN-.*
*/
static const char *const hardware[] =
{
"alto",
"amdahl-v7",
"apollo",
"att-3b20",
"bbn-c/60",
"burroughs-b/29",
"burroughs-b/4800",
"butterfly",
"c/30",
"c/70",
"cadlinc",
"cadr",
"cdc-170",
"cdc-170/750",
"cdc-173",
"celerity-1200",
"comten-3690",
"cp8040",
"cray-1",
"cray-x/mp",
"cray-2",
"ctiws-117",
"dandelion",
"dec-10",
"dec-1050",
"dec-1077",
"dec-1080",
"dec-1090",
"dec-1090b",
"dec-1090t",
"dec-2020t",
"dec-2040",
"dec-2040t",
"dec-2050t",
"dec-2060",
"dec-2060t",
"dec-2065",
"dec-falcon",
"dec-ks10",
"dec-.*",
"dorado",
"dps8/70m",
"elxsi-6400",
"foonly-f2",
"foonly-f3",
"foonly-f4",
"gould",
"gould-6050",
"gould-6080",
"gould-9050",
"gould-9080",
"h-316",
"h-60/68",
"h-68",
"h-68/80",
"h-89",
"honeywell-dps-6",
"honeywell-dps-8/70",
"hp3000",
"hp3000/64",
"ibm-158",
"ibm-360/67",
"ibm-370/3033",
"ibm-3081",
"ibm-3084qx",
"ibm-3101",
"ibm-4331",
"ibm-4341",
"ibm-4361",
"ibm-4381",
"ibm-4956",
"ibm-pc",
"ibm-pc/at",
"ibm-pc/xt",
"ibm-series/1",
"ibm-[1-9][0-9]*",
"ibm-[1-9][0-9]*/[1-9][0-9]*",
"imagen",
"imagen-8/300",
"imsai",
"integrated-solutions",
"integrated-solutions-68k",
"integrated-solutions-creator",
"integrated-solutions-creator-8",
"intel-ipsc",
"is-1",
"is-68010",
"lmi",
"lsi-11",
"lsi-11/2",
"lsi-11/23",
"lsi-11/73",
"m68000",
"masscomp",
"mc500",
"mc68000",
"microvax",
"microvax-i",
"mv/8000",
"nas3-5",
"ncr-comten-3690",
"now",
"onyx-z8000",
"pdp-11",
"pdp-11/3",
"pdp-11/23",
"pdp-11/24",
"pdp-11/34",
"pdp-11/40",
"pdp-11/44",
"pdp-11/45",
"pdp-11/50",
"pdp-11/70",
"pdp-11/73",
"pe-7/32",
"pe-3205",
"perq",
"plexus-p/60",
"pli",
"pluribus",
"prime-2350",
"prime-2450",
"prime-2755",
"prime-9655",
"prime-9755",
"prime-9955ii",
"prime-2250",
"prime-2655",
"prime-9955",
"prime-9950",
"prime-9650",
"prime-9750",
"prime-2250",
"prime-750",
"prime-850",
"prime-550ii",
"pyramid-90",
"pyramid-90mx",
"pyramid-90x",
"pyramid-.*",
"ridge",
"ridge-32",
"ridge-32c",
"rolm-1666",
"s1-mkiia",
"smi",
"sequent-balance-8000",
"siemens",
"silicon-graphics",
"silicon-graphics-iris",
"silicon-graphics-.*",
"sperry-dcp/10",
"sun",
"sun-2",
"sun-2/50",
"sun-2/100",
"sun-2/120",
"sun-2/140",
"sun-2/150",
"sun-2/160",
"sun-2/170",
"sun-3/160",
"sun-3/50",
"sun-3/75",
"sun-3/110",
"sun-50",
"sun-100",
"sun-120",
"sun-130",
"sun-150",
"sun-170",
"sun-68000",
"sun-[0-9][0-9]*/[0-9][0-9]*",
"symbolics-3600",
"symbolics-3670",
"tandem-txp",
"tek-6130",
"ti-explorer",
"tp-4000",
"trs-80",
"univac-1100",
"univac-1100/60",
"univac-1100/62",
"univac-1100/63",
"univac-1100/64",
"univac-1100/70",
"univac-1160",
"vax-11/725",
"vax-11/730",
"vax-11/750",
"vax-11/780",
"vax-11/785",
"vax-11/790",
"vax-11/8600",
"vax-8600",
"vax-.*",
"wang-pc002",
"wang-vs100",
"wang-vs400",
"xerox-1108",
"xerox-8010",
/*
* This entry is not part of the official set,
* but often very necessary in practice.
*/
"data-general-.*",
"dg-.*",
"hewlett-packard-.*",
"hp-.*",
"apple-macintosh",
"apple-2",
"other:",
/* x-term, term serv, bridges, etc. */
"unknown"
};
/*
* This is the Operating System list from RFC-1010
*
* These are the Official System Names as they appear in the
* NIC Host Table. Their use is described in RFC 810 [39].
*
* A system name may be up to 40 characters taken from the set
* of uppercase letters, digits, and the two punctuation
* characters hyphen and slash. It must start with a letter,
* and end with a letter or digit.
*
* NOTE: each of these is treated as a regular expression,
* to facilitate multiple entries.
*/
static const char *const system_name[] =
{
"aegis",
"apollo",
"bs-2000",
"cedar",
"cgw",
"chrysalis",
"cmos",
"cms",
"cos",
"cpix",
"ctos",
"ctss",
"dcn",
"ddnos",
"domain",
"edx",
"elf",
"embos",
"emmos",
"epos",
"foonex",
"fuzz",
"gcos",
"gpos",
"hdos",
"imagen",
"intercom",
"impress",
"interlisp",
"ios",
"its",
"lisp",
"lispm",
"locus",
"minos",
"mos",
"mpe5",
"msdos",
"multics",
"mvs",
"mvs/sp",
"nexus",
"nms",
"nonstop",
"nos-2",
"os/ddp",
"os4",
"os86",
"osx",
"pcdos",
"perq/os",
"pli",
"psdos/mit",
"primos",
"rmx/rdos",
"ros",
"rsx11m",
"satops",
"scs",
"simp",
"swift",
"tac",
"tandem",
"tenex",
"tops10",
"tops20",
"tp3010",
"trsdos",
"ultrix",
"unix",
"ut2d",
"v",
"vm",
"vm/370",
"vm/cms",
"vm/sp",
"vms",
"vms/eunice",
"vrtx",
"waits",
"wang",
"xde",
"xenix",
/*
* These entries are not part of the official set,
* but often very necessary in practice.
*/
"macos", /* MacOS, Apple Macintosh operating system */
"other:",
"unknown", /* don't know what the operating system is */
"none" /* device does not have an operating system */
};
char *w;
/*
* We are extemely lenient, we only check the first
* space-separated word for compliance. This allows us to
* piggy-back extra stuff into these fields.
*/
if (rp->arg.nstrings < 1)
return;
w = first_word(rp->arg.string[0]->str_text);
if (strlen(w) > 40)
srrf_lex_error("harware name too long (by %d)", strlen(w) - 40);
if (!find_word(w, hardware, SIZEOF(hardware)))
{
static int listed;
char *s;
srrf_lex_error("harware name \"%s\" unknown", w);
if (!listed)
{
listed = 1;
s = list_to_string(hardware, SIZEOF(hardware));
error("the harware list from rfc1010 defines %s", s);
mem_free(s);
}
}
mem_free(w);
if (rp->arg.nstrings < 2)
return;
w = first_word(rp->arg.string[1]->str_text);
if (strlen(w) > 40)
srrf_lex_error("system name too long (by %d)", strlen(w) - 40);
if (!find_word(w, system_name, SIZEOF(system_name)))
{
static int listed;
char *s;
srrf_lex_error("system name \"%s\" unknown", w);
if (!listed)
{
listed = 1;
s = list_to_string(system_name, SIZEOF(system_name));
error("the system list from rfc1010 defines %s", s);
mem_free(s);
}
}
mem_free(w);
}
/* ---------- loc ---------------------------------------------------------- */
enum loc_token_t
{
loc_token_end,
loc_token_integer,
loc_token_real,
loc_token_metres,
loc_token_ns,
loc_token_ew,
loc_token_junk
};
typedef enum loc_token_t loc_token_t;
typedef struct loc_lex_t loc_lex_t;
struct loc_lex_t
{
strlist_ty *line;
size_t pos;
loc_token_t curtok;
long value_long;
double value_double;
};
static loc_token_t
loc_lex(loc_lex_t *ctx)
{
string_ty *s;
const char *cp;
char *ep;
long n;
double d;
/*
* Once we get to the end, keep saying its the end.
*/
if (ctx->pos >= ctx->line->nstrings)
{
ctx->curtok = loc_token_end;
return ctx->curtok;
}
/*
* Get the next string for the argument list
*/
s = ctx->line->string[ctx->pos++];
cp = s->str_text;
/*
* Check for the easy stuff first.
*/
if (strcasecmp(cp, "n") == 0)
{
ctx->value_long = 1;
ctx->curtok = loc_token_ns;
return ctx->curtok;
}
if (strcasecmp(cp, "s") == 0)
{
ctx->value_long = -1;
ctx->curtok = loc_token_ns;
return ctx->curtok;
}
if (strcasecmp(cp, "e") == 0)
{
ctx->value_long = 1;
ctx->curtok = loc_token_ew;
return ctx->curtok;
}
if (strcasecmp(cp, "w") == 0)
{
ctx->value_long = -1;
ctx->curtok = loc_token_ew;
return ctx->curtok;
}
/*
* See if we can make it into an integer.
*/
n = strtol(cp, &ep, 10);
if (ep != cp && 0 == strcasecmp(ep, "m"))
{
ctx->value_double = n;
ctx->curtok = loc_token_metres;
return ctx->curtok;
}
if (ep != cp && *ep == '\0')
{
ctx->value_long = n;
ctx->curtok = loc_token_integer;
return ctx->curtok;
}
/*
* See if we can make it into an real.
*/
d = strtod(cp, &ep);
if (ep != cp && 0 == strcasecmp(ep, "m"))
{
ctx->value_double = d;
ctx->curtok = loc_token_metres;
return ctx->curtok;
}
if (ep != cp && *ep == '\0')
{
ctx->value_double = d;
ctx->curtok = loc_token_real;
return ctx->curtok;
}
/*
* Nope. Can't figure it out.
*/
ctx->curtok = loc_token_junk;
return ctx->curtok;
}
static string_ty *
three_sig_dig(double n)
{
double nn;
nn = (n < 0 ? -n : n);
if (nn < 10)
return str_format("%4.2fm", n);
if (nn < 100)
return str_format("%3.1fm", n);
return str_format("%.0fm", n);
}
static void
loc_check(srrf_t *rp)
{
/*
* Quoting RFC1876
*
* "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."
*/
loc_lex_t ctx;
strlist_ty canonical;
string_ty *s;
ctx.line = &rp->arg;
ctx.pos = 0;
strlist_zero(&canonical);
/*
* latitude
*/
loc_lex(&ctx);
if (ctx.curtok != loc_token_integer)
{
bad_lat:
srrf_lex_error
(
"LOC: arg %d: latitude must be defined as "
"\"deg [ min [ sec[.nnn] ]] { N | S }\"",
ctx.pos
);
return;
}
if (ctx.value_long < 0 || ctx.value_long > 90)
goto bad_lat;
s = str_format("%ld", ctx.value_long);
strlist_append(&canonical, s);
str_free(s);
loc_lex(&ctx);
if (ctx.curtok == loc_token_integer)
{
if (ctx.value_long < 0 || ctx.value_long >= 60)
goto bad_lat;
s = str_format("%ld", ctx.value_long);
strlist_append(&canonical, s);
str_free(s);
loc_lex(&ctx);
if (ctx.curtok == loc_token_integer)
{
if (ctx.value_long < 0 || ctx.value_long >= 60)
goto bad_lat;
s = str_format("%ld", ctx.value_long);
strlist_append(&canonical, s);
str_free(s);
loc_lex(&ctx);
}
else if (ctx.curtok == loc_token_real)
{
if (ctx.value_double < 0 || ctx.value_double >= 60)
goto bad_lat;
s = str_format("%g", ctx.value_double);
strlist_append(&canonical, s);
str_free(s);
loc_lex(&ctx);
}
}
else
{
s = str_from_c("0");
strlist_append(&canonical, s);
strlist_append(&canonical, s);
str_free(s);
}
if (ctx.curtok != loc_token_ns)
goto bad_lat;
s = str_from_c(ctx.value_long >= 0 ? "N" : "S");
strlist_append(&canonical, s);
str_free(s);
/*
* longitude
*/
loc_lex(&ctx);
if (ctx.curtok != loc_token_integer)
{
bad_lon:
srrf_lex_error
(
"LOC: arg %d: longitude must be defined as "
"\"deg [ min [ sec[.nnn] ]] { E | W }\"",
ctx.pos
);
return;
}
if (ctx.value_long < 0 || ctx.value_long > 180)
goto bad_lon;
s = str_format("%ld", ctx.value_long);
strlist_append(&canonical, s);
str_free(s);
loc_lex(&ctx);
if (ctx.curtok == loc_token_integer)
{
if (ctx.value_long < 0 || ctx.value_long >= 60)
goto bad_lon;
s = str_format("%ld", ctx.value_long);
strlist_append(&canonical, s);
str_free(s);
loc_lex(&ctx);
if (ctx.curtok == loc_token_integer)
{
if (ctx.value_long < 0 || ctx.value_long >= 60)
goto bad_lon;
s = str_format("%ld", ctx.value_long);
strlist_append(&canonical, s);
str_free(s);
loc_lex(&ctx);
}
else if (ctx.curtok == loc_token_real)
{
if (ctx.value_double < 0 || ctx.value_double >= 60)
goto bad_lon;
s = str_format("%g", ctx.value_double);
strlist_append(&canonical, s);
str_free(s);
loc_lex(&ctx);
}
}
else
{
s = str_from_c("0");
strlist_append(&canonical, s);
strlist_append(&canonical, s);
str_free(s);
}
if (ctx.curtok != loc_token_ew)
goto bad_lon;
s = str_from_c(ctx.value_long >= 0 ? "E" : "W");
strlist_append(&canonical, s);
str_free(s);
/*
* altitude
*/
loc_lex(&ctx);
if (ctx.curtok == loc_token_integer)
{
ctx.value_double = ctx.value_long;
ctx.curtok = loc_token_metres;
}
if (ctx.curtok == loc_token_real)
{
ctx.curtok = loc_token_metres;
}
if (ctx.curtok != loc_token_metres)
{
bad_alt:
srrf_lex_error
(
"LOC: arg %d: altitude must be defined as "
"\"[+|-]num[.nnn]['m']\"",
ctx.pos
);
return;
}
if (ctx.value_double < -100000.00 || ctx.value_double > 42849672.95)
goto bad_alt;
s = three_sig_dig(ctx.value_double);
strlist_append(&canonical, s);
str_free(s);
/*
* size
*/
loc_lex(&ctx);
if (ctx.curtok == loc_token_integer)
{
ctx.value_double = ctx.value_long;
ctx.curtok = loc_token_metres;
}
if (ctx.curtok == loc_token_real)
{
ctx.curtok = loc_token_metres;
}
if (ctx.curtok == loc_token_metres)
{
/* Optional size is present. */
if (ctx.value_double < 0 || ctx.value_double > 9e7)
{
srrf_lex_error
(
"LOC: arg %d: size must be defined as "
"\"num[.nnn]['m']\"",
ctx.pos
);
return;
}
s = three_sig_dig(ctx.value_double);
strlist_append(&canonical, s);
str_free(s);
loc_lex(&ctx);
}
else
{
s = three_sig_dig(1.);
strlist_append(&canonical, s);
str_free(s);
}
/*
* horizontal precision
*/
if (ctx.curtok == loc_token_integer)
{
ctx.value_double = ctx.value_long;
ctx.curtok = loc_token_metres;
}
if (ctx.curtok == loc_token_real)
{
ctx.curtok = loc_token_metres;
}
if (ctx.curtok == loc_token_metres)
{
/* Optional hp is present. */
if (ctx.value_double < 0 || ctx.value_double > 9e7)
{
srrf_lex_error
(
"LOC: arg %d: horizontal precision must "
"be defined as \"num[.nnn]['m']\"",
ctx.pos
);
return;
}
s = three_sig_dig(ctx.value_double);
strlist_append(&canonical, s);
str_free(s);
loc_lex(&ctx);
}
else
{
s = three_sig_dig(10000.);
strlist_append(&canonical, s);
str_free(s);
}
/*
* vertical precision
*/
if (ctx.curtok == loc_token_integer)
{
ctx.value_double = ctx.value_long;
ctx.curtok = loc_token_metres;
}
if (ctx.curtok == loc_token_real)
{
ctx.curtok = loc_token_metres;
}
if (ctx.curtok == loc_token_metres)
{
/* Optional hp is present. */
if (ctx.value_double < 0 || ctx.value_double > 9e7)
{
srrf_lex_error
(
"LOC: arg %d: vertical precision must "
"be defined as \"num[.nnn]['m']\"",
ctx.pos
);
return;
}
s = three_sig_dig(ctx.value_double);
strlist_append(&canonical, s);
str_free(s);
loc_lex(&ctx);
}
else
{
s = three_sig_dig(10.);
strlist_append(&canonical, s);
str_free(s);
}
/*
* Make sure we are done.
*/
if (ctx.curtok != loc_token_end)
{
srrf_lex_error("LOC: arg %d: junk on end of line", ctx.pos);
}
/*
* Replace the argument list we were given with the canonical
* one we constructed.
*/
strlist_free(&rp->arg);
rp->arg = canonical;
}
static void
indent_to(int n, int *col, FILE *fp)
{
if (*col >= n)
{
putc(' ', fp);
++*col;
}
else
{
while (*col < n)
{
putc(' ', fp);
++*col;
}
}
}
static int
loc_print(srrf_t *rp, FILE *fp)
{
int col;
const char *tmp;
/*
* print the name
*/
col = 0;
if (rp->name)
{
fprintf(fp, "%s", rp->name->str_text);
col += rp->name->str_length;
}
/*
* print the time to live
*/
if (rp->ttl)
{
char ttl[30];
indent_to(8, &col, fp);
sprintf(ttl, "%ld", rp->ttl);
fprintf(fp, "%s", ttl);
col += strlen(ttl);
}
/*
* print the class
*/
indent_to(16, &col, fp);
tmp = rp->class->name;
fprintf(fp, "%s", tmp);
col += strlen(tmp);
/*
* print the type
*/
indent_to(24, &col, fp);
tmp = rp->type->name;
fprintf(fp, "%s", tmp);
col += strlen(tmp);
/*
* print the other stuff
*/
indent_to(32, &col, fp);
fprintf
(
fp,
"( %s %s %s %s ; latitude\n",
rp->arg.string[0]->str_text,
rp->arg.string[1]->str_text,
rp->arg.string[2]->str_text,
rp->arg.string[3]->str_text
);
col = 0;
indent_to(32, &col, fp);
fprintf
(
fp,
"%s %s %s %s ; longitude\n",
rp->arg.string[4]->str_text,
rp->arg.string[5]->str_text,
rp->arg.string[6]->str_text,
rp->arg.string[7]->str_text
);
col = 0;
indent_to(32, &col, fp);
fprintf(fp, "%s ; altitude\n", rp->arg.string[8]->str_text);
col = 0;
indent_to(32, &col, fp);
fprintf(fp, "%s ; error size\n", rp->arg.string[9]->str_text);
col = 0;
indent_to(32, &col, fp);
fprintf
(
fp,
"%s ; horizontal precision\n",
rp->arg.string[10]->str_text
);
col = 0;
indent_to(32, &col, fp);
fprintf
(
fp,
"%s ) ; vertical precision\n",
rp->arg.string[11]->str_text
);
col = 0;
/*
* done
*/
return 6;
}
/* ---------- mx ----------------------------------------------------------- */
static int
mx_local(srrf_t *rp)
{
return srrf_private_domain_member(rp->arg.string[1]);
}
/* ---------- ns ----------------------------------------------------------- */
static void
ns_check(srrf_t *rp)
{
string_ty *tmp;
tmp = rp->arg.string[0];
rp->arg.string[0] = srrf_relative_to_absolute(tmp);
str_free(tmp);
}
static int
ns_local(srrf_t *rp)
{
return srrf_private_domain_member(rp->arg.string[0]);
}
/* ---------- ptr ---------------------------------------------------------- */
static int
ptr_local(srrf_t *rp)
{
return srrf_private_domain_member(rp->arg.string[0]);
}
/* ---------- soa ---------------------------------------------------------- */
static int
is_pos_int(const char *s)
{
if (!*s || *s == '0')
return 0;
while (*s)
{
if (!isdigit(*s))
return 0;
++s;
}
return 1;
}
static void
soa_check(srrf_t *rp)
{
size_t j;
if (auto_time_stamp && rp->arg.nstrings >= 3)
{
time_t now;
struct tm *tm;
/*
* Create a time stamp of the form YYMMDDnnn.
* The result must always be less than 2^31,
* which a 9-digit number will always be. This
* form has an 86 second granularity.
*
* It was possible to use the time_t value
* directly, and have a 1 second granularity,
* but this form is human readable.
*/
time(&now);
tm = localtime(&now);
str_free(rp->arg.string[2]);
rp->arg.string[2] =
str_format
(
"%2.2d%2.2d%2.2d%3.3d",
tm->tm_year % 100,
tm->tm_mon + 1,
tm->tm_mday,
(
(((tm->tm_hour * 60 + tm->tm_min) * 60 + tm->tm_sec) * 1000)
/
(24 * 60 * 60)
)
);
}
if (rp->arg.nstrings != 7)
{
srrf_lex_error("SOA requires 7 arguments");
}
for (j = 3; j < rp->arg.nstrings && j < 7; ++j)
{
if (!is_pos_int(rp->arg.string[j]->str_text))
{
srrf_lex_error
(
"SOA argument %ld (\"%s\") must be a positive integer",
(long)(j + 1),
rp->arg.string[j]->str_text
);
}
}
srrf_private_domain_set(rp->name);
}
static char *
time_string(const char *s)
{
long nsec;
static char buffer[100];
char *bp;
long n;
nsec = atol(s);
bp = buffer;
if (nsec >= 7L * 24L * 60L * 60L)
{
n = nsec / (7L * 24L * 60L * 60L);
sprintf(bp, "%ld week%s", n, (n == 1 ? "" : "s"));
bp += strlen(bp);
nsec %= (7L * 24L * 60L * 60L);
}
if (nsec >= 24L * 60L * 60L)
{
if (bp != buffer)
{
*bp++ = ',';
*bp++ = ' ';
}
n = nsec / (24L * 60L * 60L);
sprintf(bp, "%ld day%s", n, (n == 1 ? "" : "s"));
bp += strlen(bp);
nsec %= (24L * 60L * 60L);
}
if (nsec >= 60L * 60L)
{
if (bp != buffer)
{
*bp++ = ',';
*bp++ = ' ';
}
n = nsec / (60L * 60L);
sprintf(bp, "%ld hour%s", n, (n == 1 ? "" : "s"));
bp += strlen(bp);
nsec %= (60L * 60L);
}
if (nsec >= 60L)
{
if (bp != buffer)
{
*bp++ = ',';
*bp++ = ' ';
}
n = nsec / 60;
sprintf(bp, "%ld minute%s", n, (n == 1 ? "" : "s"));
bp += strlen(bp);
nsec %= 60;
}
if (nsec || bp == buffer)
{
if (bp != buffer)
{
*bp++ = ',';
*bp++ = ' ';
}
n = nsec;
sprintf(bp, "%ld second%s", n, (n == 1 ? "" : "s"));
}
return buffer;
}
static int
soa_print(srrf_t *rp, FILE *fp)
{
int col;
const char *tmp;
/*
* print the name
*/
col = 0;
if (rp->name)
{
fprintf(fp, "%s", rp->name->str_text);
col += rp->name->str_length;
}
/*
* print the time to live
*/
if (rp->ttl)
{
char ttl[30];
indent_to(8, &col, fp);
sprintf(ttl, "%ld", rp->ttl);
fprintf(fp, "%s", ttl);
col += strlen(ttl);
}
/*
* print the class
*/
indent_to(16, &col, fp);
tmp = rp->class->name;
fprintf(fp, "%s", tmp);
col += strlen(tmp);
/*
* print the type
*/
indent_to(24, &col, fp);
tmp = rp->type->name;
fprintf(fp, "%s", tmp);
col += strlen(tmp);
/*
* print the other stuff
*/
indent_to(32, &col, fp);
fprintf
(
fp,
"%s %s (\n", rp->arg.string[0]->str_text,
rp->arg.string[1]->str_text
);
col = 0;
indent_to(32, &col, fp);
fprintf(fp, "%s ; serial\n", rp->arg.string[2]->str_text);
col = 0;
indent_to(32, &col, fp);
fprintf
(
fp,
"%s ; refresh: %s\n",
rp->arg.string[3]->str_text,
time_string(rp->arg.string[3]->str_text)
);
col = 0;
indent_to(32, &col, fp);
fprintf
(
fp,
"%s ; retry: %s\n",
rp->arg.string[4]->str_text,
time_string(rp->arg.string[4]->str_text)
);
col = 0;
indent_to(32, &col, fp);
fprintf
(
fp,
"%s ; expire: %s\n",
rp->arg.string[5]->str_text,
time_string(rp->arg.string[5]->str_text)
);
col = 0;
indent_to(32, &col, fp);
fprintf
(
fp,
"%s ) ; minimum: %s\n",
rp->arg.string[6]->str_text,
time_string(rp->arg.string[6]->str_text)
);
col = 0;
/*
* done
*/
return 6;
}
/* ------------------------------------------------------------------------- */
static srrf_type_ty type[] =
{
{
"a",
1, /* number_of_arguments */
a_check, /* check_arguments */
0, /* local_test */
0, /* print */
0, /* abs_to_rel */
0,
0,
},
{
"cname",
1, /* number of arguments */
cname_check, /* check_arguments */
cname_local, /* local_test */
0, /* print */
cname_a2r, /* abs_to_rel */
0,
0,
},
{
"hinfo",
2, /* number of arguments */
hinfo_check, /* check_arguments */
0, /* local_test */
0, /* print */
0, /* abs_to_rel */
0,
0,
},
{
"loc",
0, /* number of arguments */
loc_check, /* check arguments */
0, /* local_test */
loc_print, /* print */
0, /* abs_to_rel */
0,
0,
},
{
"mx",
2, /* number of arguments */
0, /* check argukents */
mx_local, /* local_test */
0, /* print */
0, /* abs_to_rel */
0,
0,
},
{
"ns",
1, /* number of arguments */
ns_check, /* check arguments */
ns_local, /* local_test */
0, /* print */
0, /* abs_to_rel */
0,
0,
},
{
"ptr",
1, /* number of arguments */
0, /* check arguments */
ptr_local, /* local test */
0, /* print */
0, /* abs_to_rel */
0,
0,
},
{
"soa",
7, /* number of arguments */
soa_check, /* check arguments */
0, /* local test */
soa_print, /* print */
0, /* abs_to_rel */
0,
0,
},
{
"txt",
0, /* number of arguments */
0, /* check arguments */
0, /* local test */
0, /* print */
0, /* abs_to_rel */
0,
0,
},
};
/*
* This symbol describes the class.
* It should be the only symbol exported from this file.
*/
srrf_class_ty srrf_class_in =
{
"in",
type,
SIZEOF(type)
};
syntax highlighted by Code2HTML, v. 0.9.1