/* * Getzone - Zone transfer client * * Copyright (C) Meilof Veeningen, 2003 */ #include const int tcp_timeout = 5000; void transfer_zone(_addr a, domainname znroot, FILE *out) { int sockid = tcpopen(&a), ilen, pos, n, t, l; DnsMessage *q = create_query(znroot, QTYPE_AXFR); message_buff buff = q->compile(TCP_MSG_SIZE); delete q; char len[2] = { buff.len/256, buff.len }; tcpsendall(sockid, len, 2, tcp_timeout / 4); tcpsendall(sockid, buff.msg, buff.len, tcp_timeout / 4); char *msg = NULL; _domain retdom = NULL; char *rdata = NULL; uint16_t rdlen; int soa = 0; try { while (soa != 2) { /* read message */ if (msg) { free(msg); msg = NULL; } tcpreadall(sockid, len, 2, tcp_timeout / 4); ilen = len[0] * 256 + len[1]; if (ilen < 12) throw PException("Incomplete answer message"); msg = (char *)malloc(ilen); tcpreadall(sockid, msg, ilen, tcp_timeout / 4); buff = message_buff(msg, ilen); /* interpret it */ if ((msg[3] & 15) != RCODE_NOERROR) throw PException(true, "Erroneous answer: %s", str_rcode(msg[3]&15).c_str()); n = msg[6] * 256 + msg[7]; pos = 12; for (t = 0; t < n && pos < ilen; t++) { /* read this RR */ if (retdom) { free(retdom); retdom = NULL; } if (rdata) { free(rdata); rdata = NULL; } retdom = dom_uncompress(buff, pos); pos += dom_comprlen(buff, pos); if (pos + 10 > ilen) throw PException(true, "Truncated answer message"); l = buff.msg[pos+8] * 256 + buff.msg[pos+9]; if (pos + 10 + l > ilen) throw PException(true, "Truncated answer message"); if (buff.msg[pos] * 256 + buff.msg[pos+1] == DNS_TYPE_SOA) { soa++; if (soa == 2) { /* done! */ break; } } rr_read(buff.msg[pos] * 256 + buff.msg[pos+1], rdata, rdlen, buff, pos + 10, l); fwrite(uint16_buff(domlen(retdom)) + l + 10, 1, 2, out); fwrite(retdom, 1, domlen(retdom), out); fwrite(buff.msg, 1, 10, out); fwrite(rdata, 1, rdlen, out); pos += 10 + l; } } } catch (PException p) { if (msg) free(msg); if (retdom) free(retdom); if (rdata) free(rdata); throw p; } if (msg) free(msg); if (retdom) free(retdom); if (rdata) free(rdata); } int main(int argc, char **argv) { _addr a; FILE *f; if (argc != 4) { printf("Usage: %s \n", argv[0]); return 1; } txt_to_addr(&a, argv[1]); f = try_fopen(argv[3], "w"); if (!f) { printf("*** Failed to open %s for writing!\n", argv[3]); return 1; } try { transfer_zone(a, argv[2], f); } catch (PException p) { printf("*** Zone transfer failed: %s\n", p.message); fclose(f); return 1; } fclose(f); return 0; }