/* * 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 * 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 #include #include #include #include #include #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); }