/** send Update Message to server*/ void DNSUpdate::sendMsgTCP(unsigned int timeout){ DnsMessage *a = NULL; int sockid = -1; try { pos_cliresolver res; res.tcp_timeout = timeout; sockid = res.tcpconnect(&server); res.tcpsendmessage(message, sockid); res.tcpwaitanswer(a, sockid); if (a->RCODE != RCODE_NOERROR) { throw PException((char*)str_rcode(a->RCODE).c_str()); } } catch (PException p) { if (a) delete a; if (sockid != -1) tcpclose(sockid); throw PException(p.message); } if (a) delete a; if (sockid != -1) tcpclose(sockid); }
void tcpreadall(int sockid, const char *buff, int len, int maxtime) { smallset_t set; postime_t end = getcurtime() + maxtime, cur; int ret, x; set.init(1); set.set(0, sockid); while (len > 0) { while ((cur = getcurtime()) <= end) { set.init(1); set.set(0, sockid); x = end.after(cur); if (x > 1000) x = 1000; set.wait(x); if (set.isdata(0) || posclient_quitflag) break; } // set.check(); if (!set.isdata(0)) { throw PException("Could not read TCP message: no data"); } ret = tcpread(sockid, buff, len); if (ret == 0) throw PException("TCP client hung up!"); buff += ret; len -= ret; } }
int tcpopen(_addr *addr) { int sockid; if ((sockid = socket(struct_pf(addr), SOCK_STREAM, IPPROTO_TCP)) < 0) throw PException("Could not create TCP socket"); if (connect(sockid, (sockaddr *)addr, struct_len(addr)) < 0) { closesocket(sockid); std::string txt = addr_to_string(addr, false); throw PException(true, "Could not connect TCP socket to dst addr=%s", txt.c_str()); } return sockid; }
int tcpopen_from(_addr *to, _addr *source) { int sockid; if ((sockid = socket(struct_pf(to), SOCK_STREAM, IPPROTO_TCP)) < 0) throw PException("Could not create TCP socket"); if (bind(sockid, (sockaddr *)source, struct_len(source)) < 0) { closesocket(sockid); throw PException("Could not bind TCP socket"); } if (connect(sockid, (sockaddr *)to, struct_len(to)) < 0) { closesocket(sockid); throw PException("Could not connect TCP socket"); } return sockid; }
int udpcreateserver(_addr* socketaddr) { int sockid; int one = 1; if ((sockid = socket(struct_pf(socketaddr), SOCK_DGRAM, IPPROTO_UDP)) < 0) throw PException("Could not create UDP socket!"); if (bind(sockid, (sockaddr *)(socketaddr), struct_len(socketaddr)) < 0) { closesocket(sockid); throw PException("Could not bind to socket!"); } setsockopt(sockid, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one)); setnonblock(sockid); return sockid; }
void tsig_from_string (DnsRR*& tsig_rr, stl_string& sign_key, const char* keystring) { stl_string keyname, key; const char *ptr; ptr = strchr (keystring, ':'); if (!ptr) throw PException (true, "%s is not a valid key string (should be keyname:key)", keystring); keyname.append (keystring, (int)(ptr - keystring)); keystring = ptr + 1; ptr = strchr (keystring, ':'); key.append (keystring, ptr ? (int)(ptr - keystring) : strlen (keystring)); if (tsig_rr) { delete tsig_rr; tsig_rr = NULL; } if (ptr) { int fudge = txt_to_int (ptr + 1); tsig_rr = tsig_record (keyname.c_str (), fudge); } else { tsig_rr = tsig_record (keyname.c_str ()); } sign_key = base64_decode (key.c_str ()); }
int udpread(int sockid, const char *buff, int len, _addr *addr) { socklen_t addr_size = sizeof(_addr); int ret = recvfrom(sockid, (char*)buff, len, 0, (sockaddr *) addr, &addr_size); if (ret <= 0) throw PException("Could not receive data from UDP socket"); return ret; }
/** get old RR entry from Dns Server */ DnsRR* DNSUpdate::get_oldDnsRR(){ DnsRR* RemoteDnsRR= NULL; DnsMessage *q = NULL, *a = NULL; int sockid = -1; try { q = create_query(*zoneroot, QTYPE_AXFR); pos_cliresolver res; sockid = res.tcpconnect(&server); res.tcpsendmessage(q, sockid); res.tcpwaitanswer(a, sockid); if (a->RCODE != RCODE_NOERROR){ throw PException((char*)str_rcode(a->RCODE).c_str()); } if (!a->answers.empty()) { RemoteDnsRR = new DnsRR(); if (this->DnsRR_avail(a,*RemoteDnsRR) == false) { delete RemoteDnsRR; RemoteDnsRR = NULL; } } if (a) { // delete a; // FIXME: Why is this commented out? Memory leak! a = 0; } if (q) { delete q; q = 0; } if (sockid != -1) tcpclose(sockid); return RemoteDnsRR; } catch (PException p) { if (q) { delete q; q = NULL; } if (a) { delete a; a = NULL; } if (sockid != -1) tcpclose(sockid); if (RemoteDnsRR) delete RemoteDnsRR; Log(Error) << "DDNS: Attempt to get old DNS record failed." << LogEnd; return 0; } }
int tcpread(int socket, const char *buff, int bufflen) { int ret = recv(socket, (char*)buff, bufflen, 0); if (ret < 0) { if (errno == EAGAIN) return 0; throw PException(true, "Could not read TCP message"); } return ret; }
int tcpaccept(int socket, _addr *askaddr) { _addr querier; socklen_t len = sizeof(_addr); int ret = accept(socket, (sockaddr *)&querier, &len); if (ret < 0) throw PException("Could not accept TCP connection"); if (askaddr) memcpy(askaddr, &querier, len); return ret; }
int getserviceportbyname(const char *name) { struct servent *service; try { int t = txt_to_int(name); return t; } catch (PException p) { } if ((service = getservbyname(name, NULL)) == NULL) throw PException(true, "Unknown service %s", name); return ntohs(service->s_port); }
int getprotocolbyname(const char *name) { struct protoent *protocol; try { int t = txt_to_int(name); return t; } catch (PException p) { } if ((protocol = getprotobyname(name)) == NULL) throw PException(true, "Unknown protocol %s", name); return protocol->p_proto; }
int tcpcreateserver(_addr *socketaddr) { int sockid; int one = 1; if ((sockid = socket(struct_pf(socketaddr), SOCK_STREAM, IPPROTO_TCP)) < 0) throw PException("Could not create TCP socket"); if (bind(sockid, (sockaddr *)socketaddr, struct_len(socketaddr)) < 0) { closesocket(sockid); throw PException("Could not bind TCP socket"); } setsockopt(sockid, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one)); setnonblock(sockid); if (listen(sockid, 5) < 0) { closesocket(sockid); throw PException("Could not listen to TCP socket"); } return sockid; }
uint16_t qtype_getcode(const char *name, bool allow_qtype) { try { uint16_t ret = txt_to_int(name); if (!is_common_rr(ret)) throw PException(); return ret; } catch (PException p) { if (allow_qtype) { if (strcmpi(name, "maila") == 0) return QTYPE_MAILA; if (strcmpi(name, "mailb") == 0) return QTYPE_MAILB; if (strcmpi(name, "ixfr") == 0) return QTYPE_IXFR; if (strcmpi(name, "axfr") == 0) return QTYPE_AXFR; if (strcmpi(name, "any") == 0) return QTYPE_ANY; if (strcmpi(name, "all") == 0) return QTYPE_ANY; } rr_type *t = rrtype_getinfo(name); if (!t) throw PException(true, "Qtype %s not supported", name); return t->type; } }
void rr_read(u_int16 RRTYPE, unsigned char*& RDATA, uint16_t &RDLEN, message_buff &buff, int ix, int len) { rr_type *info = rrtype_getinfo(RRTYPE); char *ptr; stl_string res; _domain dom; if (ix + len > buff.len) throw PException("RR doesn't fit in DNS message"); if (info) { /* we support the RR type */ try { ptr = info->properties; while (*ptr) { int x; x = rr_len(*ptr, buff, ix, len); if (x > len) throw PException("RR item too long!"); if (*ptr == 'd' || *ptr == 'm') { /* domain name: needs to be decompressed */ dom = dom_uncompress(buff, ix); res.append((char*)dom, domlen(dom)); free(dom); } else { res.append((char*)buff.msg + ix, x); } ix += x; len -= x; ptr++; } if (len != 0) throw PException("extra data in RR"); } catch(PException p) { throw PException("Parsing RR failed: ", p); } if (len != 0) throw PException("RR length too long"); } else { /* we do not support the RR type: just copy it altogether */ res.append((char*)buff.msg + ix, len); } RDLEN = res.length(); RDATA = (unsigned char *)memdup((void *)res.c_str(), res.length()); }
void DNSUpdate::sendMsgUDP(unsigned int timeout) { DnsMessage *a = NULL; try { pos_cliresolver res; res.udp_tries[0] = timeout; res.n_udp_tries = 1; // just one timeout res.query(message, a, &server, Q_NOTCP); if (a->RCODE != RCODE_NOERROR) { throw PException((char*)str_rcode(a->RCODE).c_str()); } } catch (PException p) { if (a) delete a; throw PException(p.message); } if (a) delete a; }
void setnonblock(int sockid) { #ifdef _WIN32 long int val = 1; u_long req = FIONBIO; ioctlsocket(sockid, val, &req); #else if (fcntl(sockid, F_SETFL, O_NONBLOCK) < 0) { closesocket(sockid); throw PException("Could not set socket to non-blocking"); } #endif }
int rr_len(char prop, message_buff &buff, int ix, int len) { unsigned char *ptr; int x; switch (prop) { case 'd': /* a domain name */ case 'm': /* email address */ return dom_comprlen(buff, ix); case 'i': /* ipv4 number */ case 'l': /* 32-bit number */ case 't': return 4; case 's': /* 16-bit number */ return 2; case 'c': /* character string */ return buff.msg[ix] + 1; case 'h': /* character strings */ ptr = buff.msg + ix; while (ptr - buff.msg - ix < len) ptr += *ptr + 1; if (ptr != buff.msg + ix + len) throw PException("Character strings too long for RR"); return len; case 'n': /* NULL rdata */ return len; case 'w': /* well-known services */ if (len < 5) throw PException("WKS RR too long for RR"); return len; case '6': /* ipv6 address */ return 16; case '7': /* ipv6 address + prefix */ x = ((135 - buff.msg[ix]) / 8); /* prefix length in bytes */ if (ix + x + 1 >= len) throw PException("A6 too long for RR"); if (buff.msg[ix] != 0) /* domain name nessecary */ x += dom_comprlen(buff, ix + x + 1); return x + 1; case 'o': /* DNS LOC */ if (buff.msg[ix] != 0) throw PException("Unsupported LOC version"); return 16; } throw PException(true, "Unknown RR item type %c", prop); }
void copyObjectProperties(const Object *from, Object *to) { if (from == NULL || to == NULL) return; const MetaClass *fromMC = from->getInstanceClass(); const MetaClass *toMC = to->getInstanceClass(); if (!(toMC->inheritsFrom(fromMC))) { throw PException("copyObjectProperties - type mismatch"); } const card32 n = fromMC->getNumProperties(); for (card32 i=0; i<n; i++) { fromMC->getProperty(i)->assignProperty(from, to, 0); } }
void smallset_t::runpoll(int msecs) { int ret; while (1) { ret = poll(items, nitems, (msecs >= 1000) ? 1000 : msecs); if (ret < 0 && errno != EINTR) { throw PException(true, "Error during poll: %d->%d", ret, errno); } if (ret > 0) return; if (posclient_quitflag) return; if (msecs <= 1000) return; msecs -= 1000; // if (msecs == 0) return; } }
domainname guess_zone_name(const char *file) { const char *ptr = file + strlen(file) - 1; char tmp[256]; int t; while (ptr >= file) { if (*ptr == pathdelim) { ptr++; break; } ptr--; } t = strlen(ptr); if (tolower(ptr[0]) == 'd' && tolower(ptr[1]) == 'b' && ptr[2] == '.') { return ptr + 3; } else if (t >= 4 && (strncmpi(ptr + t - 4, ".prm", 4) == 0 || strncmpi(ptr + t - 4, ".dns", 4) == 0)) { if (strlen(ptr) - 4 >= 256) throw PException("File name too long!"); memcpy(tmp, ptr, t - 4); tmp[t - 4] = '\0'; return domainname((char*)tmp); } else return ptr; }
void tcpsendall(int sockid, const char *buff, int len, int maxtime) { smallset_t set; postime_t end = getcurtime() + maxtime, cur; int ret, x; set.init(1); set.set(0, sockid); while (len > 0) { while ((cur = getcurtime()) <= end) { set.init(1); set.set(0, sockid); x = end.after(cur); if (x > 1000) x = 1000; set.waitwrite(x); if (set.canwrite(0) || posclient_quitflag) break; } if (!set.canwrite(0)) throw PException("Could not send buffer"); ret = tcpsend(sockid, buff, len); buff += ret; len -= ret; } }
void read_master_file(const char *file, domainname &znroot, void *userdat, error_callback err, rr_callback rr_cb, rr_literal_callback rrl_cb, comment_callback comm_cb, int flags) { bool has_znroot = !(flags&POSLIB_MF_AUTOPROBE), has_soa = false; char buff[1024]; char *ptr, *p2; int c; bool ttl_given = false; stl_string ttl = "3600"; domainname origin, nam; int linenum = 1, linenum2; stl_string str, tmp, t2, t3, nm; DnsRR rr; rr_type *type = NULL; FILE *f = try_fopen_r(file); if (!f) throw PException(true, "Could not open %s", file); c = fgetc(f); if (c != EOF) ungetc(c, f); if (has_znroot) origin = znroot; try { begin: while (!feof(f)) { /* since the poslib functions will filter out comments, let's do them ourselves */ if (comm_cb) { c = fgetc(f); if (c == ';') { fgets(buff, 1024, f); ptr = buff + strlen(buff) - 1; while (ptr >= buff && (*ptr == '\n' || *ptr == '\r')) *ptr = '\0'; comm_cb(userdat, buff); continue; } ungetc(c, f); } try { read_line(buff, f, &linenum, &linenum2); } catch (PException p) { break; } if (buff[0] == 0) goto begin; ptr = buff; while (*ptr == ' ' || *ptr == '\t') ptr++; if (*ptr == '\0') continue; if (buff[0] == '$') { if (strncmpi(buff, "$ttl ", 4) == 0) { ttl = buff + 5; ttl_given = true; } else if (strncmpi(buff, "$origin ", 8) == 0) { /* origin */ origin = domainname(buff + 8, znroot); if (!has_znroot) { /* first entry. this is the zone root */ znroot = origin; has_znroot = true; } } else err(userdat, file, linenum2, PException(true, "Unknown directive %s", buff).message); continue; } if (!has_znroot) { znroot = guess_zone_name(file); origin = znroot; has_znroot = true; } if (buff[0] != ' ' && buff[0] != '\t') { nam = domainname(read_entry(ptr).c_str(), origin); } else if (!has_soa) { err(userdat, file, linenum2, "First record in zone should have a domain name! Using origin instead."); nam = origin; } /* can be class or ttl or rrtype */ while (1) { str = read_entry(ptr); if (str == "IN" || str == "HS" || str == "CH" || str == "HS" || str == "in" || str == "hs" || str == "ch" || str == "hs") { /* class */ continue; } else if ((type = rrtype_getinfo(str.c_str())) != NULL) { break; } else { try { txt_to_int(str.c_str()); ttl_given = true; } catch (PException p) { err(userdat, file, linenum2, PException(true, "Invalid TTL/RR type %s!", str.c_str()).message); goto begin; } ttl = str.c_str(); } } if (!has_soa) { if (type->type != DNS_TYPE_SOA) { if (!(flags & POSLIB_MF_NOSOA)) { err(userdat, file, linenum2, "First record was no SOA record; using default SOA record instead."); if (rr_cb) { rr.NAME = znroot; rr.TYPE = DNS_TYPE_SOA; rr.TTL = 3600; tmp = rr_fromstring(DNS_TYPE_SOA, "ns1 hostmaster 1 2h 1h 1d 2h", znroot); rr.RDLENGTH = tmp.size(); rr.RDATA = (unsigned char *)memdup(tmp.c_str(), tmp.size()); rr_cb(userdat, &rr); } if (rrl_cb) rrl_cb(userdat, "@", "1h", "SOA", "ns1 hostmaster 1 2h 1h 1d 2h", znroot); } else if (!ttl_given) { err(userdat, file, linenum2, "First record should have TTL value; using 1h for now."); ttl = "3600"; ttl_given = true; } } else { if (!ttl_given) { p2 = ptr; read_entry(p2); read_entry(p2); read_entry(p2); read_entry(p2); read_entry(p2); read_entry(p2); t3 = read_entry(p2); if (strlen(t3.c_str()) < 32) ttl = t3; } } has_soa = true; } else if (type->type == DNS_TYPE_SOA && !(flags & POSLIB_MF_NOSOA)) { err(userdat, file, linenum2, "Non-initial SOA record ignored"); continue; } if (!(nam >= znroot)) { err(userdat, file, linenum2, PException(true, "Ignoring domain name %s outside of zone %s!", nam.tocstr(), znroot.tocstr()).message); continue; } if (rr_cb) { try { rr.NAME = nam; rr.TYPE = type->type; rr.TTL = txt_to_int(ttl.c_str()); tmp = rr_fromstring(type->type, ptr, origin); rr.RDLENGTH = tmp.size(); rr.RDATA = (unsigned char *)memdup(tmp.c_str(), tmp.size()); rr_cb(userdat, &rr); } catch (PException p) { err(userdat, file, linenum2, p.message); } } if (rrl_cb) { try { t2 = ptr; nm = nam.torelstring(znroot); tmp = rr_fromstring(type->type, ptr, origin); if (origin != znroot) t2 = rrdata_convertdoms(type, znroot, origin, ptr); } catch (PException p) { err(userdat, file, linenum2, p.message); } rrl_cb(userdat, nm.c_str(), ttl.c_str(), type->name, t2.c_str(), znroot); } } } catch (PException p) { fclose(f); throw p; } fclose(f); }
void udpsend(int sockid, const char *buff, int len, _addr *addr) { if (sendto(sockid, (char*)buff, len, 0, (sockaddr *)addr, struct_len(addr)) < 0) throw PException(true, "Could not send UDP packet: sock %d, err %d", sockid, errno); }
int tcpsend(int socket, const char *buff, int bufflen) { int ret = send(socket, buff, bufflen, 0); if (ret < 0 && errno != EAGAIN) throw PException("Could not send TCP message"); return ret; }
/// @brief verifies TSIG of received response /// /// Make sure that message_buff is trimmed down to not include TSIG /// record, as it must be passed in message_tsig. /// /// @param check_tsig TSIG RR from the original message /// @param message_tsig TSIR RR from the response message that we are validating /// @param key the key used for signing /// @param message received message (without TSIG record) void verify_signature (DnsRR *check_tsig, DnsRR *message_tsig, stl_string key, message_buff message) { if (!message_tsig) throw PException (true, "Unsigned answer to a signed message (key %s)", check_tsig->NAME.tocstr ()); unsigned char *errorptr = rr_getdata (check_tsig->RDATA, DNS_TYPE_TSIG, 5); domainname alg_name = rr_getdomain (check_tsig->RDATA, DNS_TYPE_TSIG), rr_alg_name = rr_getdomain (message_tsig->RDATA, DNS_TYPE_TSIG); if (rr_alg_name != alg_name || check_tsig->NAME != message_tsig->NAME) { memcpy (errorptr, uint16_buff (RCODE_BADKEY), 2); throw PException (true, "Key name/algorithm does not match: question signed with %s, answer " "signed with %s", check_tsig->NAME.tocstr(), message_tsig->NAME.tocstr()); } unsigned char *rr_macpos = rr_getdata (message_tsig->RDATA, DNS_TYPE_TSIG, 3), *macpos = rr_getdata (check_tsig->RDATA, DNS_TYPE_TSIG, 3); uint16_t rr_maclen = uint16_value (rr_macpos), maclen = uint16_value (macpos); if ((message.msg[3] & 15) == RCODE_NOTAUTH) { /* error! */ uint16_t err = rr_getshort (message_tsig->RDATA, DNS_TYPE_TSIG, 5); if (err == RCODE_BADSIG) throw PException (true, "Question signed with %s had bad signature", check_tsig->NAME.tocstr()); else if (err == RCODE_BADKEY) throw PException (true, "Question was signed with bad key (%s)", check_tsig->NAME.tocstr()); else if (err == RCODE_BADTIME) throw PException (true, "Question sign time invalid (query time %d, answer time %d)", uint48_value (rr_getdata (check_tsig->RDATA, DNS_TYPE_TSIG, 1)), uint48_value (rr_getdata (message_tsig->RDATA, DNS_TYPE_TSIG, 1))); else throw PException (true, "Unknown sign error: %d", err); } time_t clienttime = time (NULL); u_int48 servertime = uint48_value (rr_getdata (check_tsig->RDATA, DNS_TYPE_TSIG, 1)); uint16_t fudge = rr_getshort (check_tsig->RDATA, DNS_TYPE_TSIG, 2); if ( (clienttime > servertime && clienttime - servertime > fudge) || (servertime > clienttime && servertime - clienttime > fudge) ) { throw PException (true, "Answer sign time invalid (answer time %d, real time %d)", uint48_value (rr_getdata (message_tsig->RDATA, DNS_TYPE_TSIG, 1)), clienttime); // TODO: set TSIG error of check_tsig for servers } if (rr_maclen != MD5_DIGEST_SIZE) { memcpy (errorptr, uint16_buff (RCODE_BADSIG), 2); throw PException (true, "Incorrect MAC size: %d", rr_maclen); } /* calculate MAC */ message_buff ext; /* TODO: document: if this is from a message, it actually means that the message was unsigned, but we should still include the two length */ if (maclen) ext = message_buff (macpos, maclen + 2); stl_string mac = calc_mac (*message_tsig, message, key, &ext); if (memcmp (mac.c_str(), rr_macpos + 2, MD5_DIGEST_SIZE) != 0) { memcpy (errorptr, uint16_buff (RCODE_BADSIG), 2); throw PException (true, "Message signed with key %s has bad signature", message_tsig->NAME.tocstr ()); } }