/* Posadis - A DNS Server SQL-based dns server Copyright (C) 2002 Meilof Veeningen 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 2 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, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #define POS_DEFAULTLOG #define POS_DEFAULTLOG_STDOUT #define POS_DEFAULTLOG_SYSLOG #include #include #include #include #include #include #include #include #include void cleanup(int sig) { pos_setquitflag(); } _addr them; dbconn driver(dbconn::MYSQL); DnsMessage *my_handle_query(pending_query *query); int main(int argc, char **argv) { _addr we; handle_query = my_handle_query; try { /* get command-line arguments */ if (argc == 2 && argv[1][0] == '@') { txt_to_addr(&we, argv[1] + 1); } else if (argc == 1) { txt_to_addr(&we, "0.0.0.0"); } else { printf("Usage: sqldns [@interface]\n"); return 1; } /* at first, connect to the sql database */ if (!driver.connect("localhost", "possql", "possql", "possql")) throw PException(true, "Could not connect to database: %s", driver.errorMsg()); /* bring up posadis */ servers.push_front(ServerSocket(ss_udp, udpcreateserver(&we))); servers.push_front(ServerSocket(ss_tcp, tcpcreateserver(&we))); pos_log(context_none, log_info, "Posadis sqldns starting up..."); signal(SIGINT, cleanup); signal(SIGTERM, cleanup); posserver_run(); driver.disconnect(); } catch (PException p) { printf("Fatal exception: %s\n", p.message); return 1; } return 0; } domainname lookup_zone(domainname dname) { int x = dname.nlabels(); domainname dom; for (int t = 0; t < x; t++) { dom = dname.from(t); char sqlquery[1024]; sprintf(sqlquery, "SELECT ttl, domain, ns, mailbox, snum, refresh, retry, expire, nttl FROM zones WHERE domain = \"%s\";", dom.tocstr()); if (!driver.execute(sqlquery)) { pos_log(context_server, log_error, "Could not execute SQL query: %s", driver.errorMsg()); throw PException("Could not execute query"); } if (!driver.eof) return dom; } throw PException("No zone found"); } /* the entry function which will handle all queries */ DnsMessage *my_handle_query(pending_query *query) { DnsQuestion q; DnsMessage *a = new DnsMessage(); domainname zone; a->ID = query->message->ID; bool done = false; if (query->message->OPCODE != OPCODE_QUERY) { a->RCODE = RCODE_NOTIMP; return a; } if (query->message->questions.begin() == query->message->questions.end()) { a->RCODE = RCODE_QUERYERR; return a; } q = *query->message->questions.begin(); try { zone = lookup_zone(q.QNAME); } catch (PException p) { /* we should do root hints or something */ a->RCODE = RCODE_SRVFAIL; return a; } a->AA = true; if (q.QNAME == zone && (q.QTYPE == DNS_TYPE_SOA || q.QTYPE == QTYPE_ANY)) { /* add the zone information */ string rrdata; domainname dom; DnsRR rr; dom = domainname(driver.getFieldByColumn(2)->asString()); rrdata.append(dom.c_str(), dom.len()); dom = domainname(driver.getFieldByColumn(3)->asString()); rrdata.append(dom.c_str(), dom.len()); rrdata.append(uint32_buff((u_int32)driver.getFieldByColumn(4)->asInteger()), 4); rrdata.append(uint32_buff((u_int32)driver.getFieldByColumn(5)->asInteger()), 4); rrdata.append(uint32_buff((u_int32)driver.getFieldByColumn(6)->asInteger()), 4); rrdata.append(uint32_buff((u_int32)driver.getFieldByColumn(7)->asInteger()), 4); rrdata.append(uint32_buff((u_int32)driver.getFieldByColumn(8)->asInteger()), 4); rr = DnsRR(q.QNAME, DNS_TYPE_SOA, CLASS_IN, (u_int32)driver.getFieldByColumn(0)->asInteger()); rr.RDLENGTH = rrdata.size(); rr.RDATA = (char *)memdup((void *)rrdata.c_str(), rr.RDLENGTH); a->answers.push_front(rr); done = true; } /* now query for rrs */ char sqlquery[1024]; sprintf(sqlquery, "SELECT domain, ttl, type, data FROM rrs WHERE domain = \"%s\";", q.QNAME.tocstr()); if (!driver.execute(sqlquery)) { pos_log(context_server, log_error, "Could not execute SQL query: %s", driver.errorMsg()); a->RCODE = RCODE_SRVFAIL; return a; } if (driver.eof) { /* apparently, not a domain */ if (!done) a->RCODE = RCODE_NXDOMAIN; return a; } else { domainname dom; u_int32 ttl; char *type; char *data; char *querytype = rrtype_getinfo(q.QTYPE)->name; if (querytype == NULL) querytype = ""; int rrtype; DnsRR rr; /* enumerate through data */ while (!driver.eof) { dom = domainname(driver.getFieldByColumn(0)->asString()); ttl = (u_int32)driver.getFieldByColumn(1)->asInteger(); type = driver.getFieldByColumn(2)->asString(); data = driver.getFieldByColumn(3)->asString(); if (rrtype_getinfo(type)) rrtype = rrtype_getinfo(type)->type; else rrtype = 0; if (q.QTYPE == QTYPE_ALL || (strcmpi(type, querytype) == 0) && rrtype) { /* this is what we need! */ try { string str = rr_fromstring(rrtype_getinfo(type)->type, data); rr = DnsRR(q.QNAME, rrtype, CLASS_IN, ttl); rr.RDLENGTH = str.size(); rr.RDATA = (char *)memdup((void *)str.c_str(), rr.RDLENGTH); a->answers.push_front(rr); } catch (PException p) { pos_log(context_server, log_error, "Could not convert RR: %s", p.message); a->RCODE = RCODE_SRVFAIL; return a; } } driver.next(); } } return a; }