jehanne/sys/src/cmd/ndb/inform.c

236 lines
4.8 KiB
C

/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
/* Portions of this file are Copyright (C) 2015-2018 Giacomo Tesio <giacomo@tesio.it>
* See /doc/license/gpl-2.0.txt for details about the licensing.
*/
/* Portions of this file are Copyright (C) 9front's team.
* See /doc/license/9front-mit for details about the licensing.
* See http://git.9front.org/plan9front/plan9front/HEAD/info.html for a list of authors.
*/
/* RFC2136 DNS inform - necessary for Win2k3 DNS servers */
#include <u.h>
#include <lib9.h>
#include <envvars.h>
#include <bio.h>
#include <ndb.h>
#include <ip.h>
#include "dns.h"
enum {
FQDNMAX = 255,
};
char *errmsgs[] = {
[0] "ok",
[1] "request format error",
[2] "internal server error",
[3] "domain name does not exist",
[4] "request not supported",
[5] "permission denied",
[6] "domain name already exists",
[7] "resource record already exists",
[8] "resource record does not exist",
[9] "server not authoritative",
[10] "domain name not in zone",
};
void
usage(void)
{
fprint(2, "usage: %s [-x netmtpt]\n", argv0);
exits("usage");
}
void
ding(void * _1, char *msg)
{
if(strstr(msg, "alarm") != nil)
sys_noted(NCONT);
sys_noted(NDFLT);
}
int
g16(uint8_t **p)
{
int n;
n = *(*p)++ << 8;
n |= *(*p)++;
return n;
}
void
p16(uint8_t **p, int n)
{
*(*p)++ = n >> 8;
*(*p)++ = n;
}
void
p32(uint8_t **p, int n)
{
*(*p)++ = n >> 24;
*(*p)++ = n >> 16;
*(*p)++ = n >> 8;
*(*p)++ = n;
}
void
pmem(uint8_t **p, void *v, int len)
{
memmove(*p, v, len);
*p += len;
}
void
pname(uint8_t **p, char *s)
{
uint8_t *len;
while (*s){
len = (*p)++;
while(*s && *s != '.')
*(*p)++ = *s++;
*len = *p - len - 1;
if(*s == '.')
s++;
}
*(*p)++ = 0;
}
void
main(int argc, char *argv[])
{
int debug, len, fd;
uint err;
char *sysname, *dnsdomain, *dom, *inform, *ns, net[32];
uint8_t *p, buf[4096], addr[IPv4addrlen], v6addr[IPaddrlen];
uint16_t txid;
Ndb *db;
Ndbtuple *t, *tt;
static char *query[] = { "dom", "dnsdomain", "ns", "inform" };
fmtinstall('I', eipfmt);
fmtinstall('V', eipfmt);
setnetmtpt(net, sizeof net, nil);
debug = 0;
ns = nil;
dom = nil;
inform = nil;
dnsdomain = nil;
ARGBEGIN{
case 'd':
debug = 1;
break;
case 'x':
setnetmtpt(net, sizeof net, EARGF(usage()));
break;
default:
usage();
}ARGEND;
if(argc != 0)
usage();
if((sysname = getenv(ENV_SYSNAME)) == nil)
sysfatal("$%s not set", ENV_SYSNAME);
if((db = ndbopen(nil)) == nil)
sysfatal("can't open ndb: %r");
tt = ndbipinfo(db, "sys", sysname, query, nelem(query));
for(t = tt; t; t = t->entry){
if(strcmp(t->attr, "ns") == 0)
ns = t->val;
else if(strcmp(t->attr, "dom") == 0)
dom = t->val;
else if(strcmp(t->attr, "dnsdomain") == 0)
dnsdomain = t->val;
else if(strcmp(t->attr, "inform") == 0)
inform = t->val;
}
ndbfree(tt);
ndbclose(db);
if(inform)
dom = inform;
if(!ns)
sysfatal("no relevant ns=");
if(!dom)
sysfatal("no relevant dom=");
if(!dnsdomain)
sysfatal("no relevant dnsdomain=");
myipaddr(v6addr, net);
memmove(addr, v6addr + IPaddrlen - IPv4addrlen, IPv4addrlen);
if(debug){
print("ip=%V\n", addr);
print("ns=%s\n", ns);
print("dnsdomain=%s\n", dnsdomain);
print("dom=%s\n", dom);
}
if((fd = dial(netmkaddr(ns, "udp", "dns"), 0, 0, 0)) < 0)
sysfatal("can't dial %s: %r", ns);
txid = time(nil) + getpid();
p = buf;
p16(&p, txid); /* ID */
p16(&p, 5<<11); /* flags */
p16(&p, 1); /* # Zones */
p16(&p, 0); /* # prerequisites */
p16(&p, 2); /* # updates */
p16(&p, 0); /* # additionals */
pname(&p, dnsdomain); /* zone */
p16(&p, Tsoa); /* zone type */
p16(&p, Cin); /* zone class */
/* delete old name */
pname(&p, dom); /* name */
p16(&p, Ta); /* type: v4 addr */
p16(&p, Call); /* class */
p32(&p, 0); /* TTL */
p16(&p, 0); /* data len */
/* add new A record */
pname(&p, dom); /* name */
p16(&p, Ta); /* type: v4 addr */
p16(&p, Cin); /* class */
p32(&p, 60*60*25); /* TTL (25 hours) */
p16(&p, IPv4addrlen); /* data len */
pmem(&p, addr, IPv4addrlen); /* v4 address */
len = p - buf;
if(jehanne_write(fd, buf, len) != len)
sysfatal("write failed: %r");
sys_notify(ding);
sys_alarm(3000);
do{
if(jehanne_read(fd, buf, sizeof buf) < 0)
sysfatal("timeout");
p = buf;
}while(g16(&p) != txid);
sys_alarm(0);
sys_close(fd);
err = g16(&p) & 7;
if(err != 0 && err != 7) /* err==7 is just a "yes, I know" warning */
if(err < nelem(errmsgs))
sysfatal("%s", errmsgs[err]);
else
sysfatal("unknown dns server error %d", err);
exits(0);
}