/* * NAME: dns.c * DESCRIPTION: domain name translation system */ inherit "/std/string"; private mapping addrs; /* hostname -> IP mapping */ private mapping names; /* IP -> hostname mapping */ private object server; /* connection to server process */ private int reset_handle; /* for remove_call_out */ # define CYCLE (60 * 60 * 24) /* how often to clear the cache */ /* * NAME: create() * DESCRIPTION: initialize data */ static void create(void) { addrs = ([ ]); names = ([ ]); reset_handle = call_out("reset", CYCLE); } /* * NAME: reset() * DESCRIPTION: clear cache */ void reset(void) { int i; string *keys; remove_call_out(reset_handle); /* leave pending requests intact */ keys = map_indices(addrs); for (i = sizeof(keys); i--; ) if (stringp(addrs[keys[i]])) addrs[keys[i]] = 0; keys = map_indices(names); for (i = sizeof(keys); i--; ) if (stringp(names[keys[i]])) names[keys[i]] = 0; reset_handle = call_out("reset", CYCLE); } /* * NAME: open() * DESCRIPTION: designate the DNS server object */ void open(void) { server = previous_object(); } /* * NAME: call() * DESCRIPTION: invoke a function (via delayed call_out) */ static varargs void call(object obj, string func, mixed args...) { if (obj != 0) call_other(obj, func, args...); } /* * NAME: answer() * DESCRIPTION: return a result via callback */ static void answer(mixed *list, string reply) { int i; for (i = sizeof(list); i--; ) call_out("call", 0, list[i][0], list[i][1], reply); } /* * NAME: receive_message() * DESCRIPTION: the server has sent a reply */ void receive_message(string line) { string name, canon, addr; mixed list; if (sscanf(line, "HOST %s = %s = %s", name, canon, addr) == 3) { list = addrs[tolower(name)]; addrs[tolower(name)] = addrs[tolower(canon)] = addr; if (arrayp(list)) answer(list, addr); list = names[addr]; names[addr] = canon; if (arrayp(list)) answer(list, canon); } else if (sscanf(line, "NONAME %s", addr) == 1) { list = names[addr]; names[addr] = 0; if (arrayp(list)) answer(list, 0); } else if (sscanf(line, "NOADDR %s", name) == 1) { list = addrs[tolower(name)]; addrs[tolower(name)] = 0; if (arrayp(list)) answer(list, 0); } } /* * NAME: add_request() * DESCRIPTION: append a request for notification */ static void add_request(mapping where, string what, object obj, string func) { if (arrayp(where[what])) where[what] += ({ ({ obj, func }) }); else where[what] = ({ ({ obj, func }) }); } /* * NAME: get_name() * DESCRIPTION: return the hostname for an IP address, if any */ varargs string get_name(string addr, string func) { mixed name; if (sscanf(addr, "%*d.%*d.%*d.%*d") != 4) return addr; /* lookup canonical name? */ if (stringp(name = names[addr])) return name; else { if (server == 0) return 0; server->notify("NAME? " + addr); if (func != 0) add_request(names, addr, previous_object(), func); return ""; } } /* * NAME: get_addr() * DESCRIPTION: return the IP address for a hostname, if any */ varargs string get_addr(string name, string func) { mixed addr; if (sscanf(name, "%*d.%*d.%*d.%*d") == 4) return name; if (stringp(addr = addrs[tolower(name)])) return addr; else { if (server == 0) return 0; server->notify("ADDR? " + name); if (func != 0) add_request(addrs, tolower(name), previous_object(), func); return ""; } } mapping dump_names(void) { return names; } mapping dump_addrs(void) { return addrs; }