memset(&d, 0, sizeof(d));
}
-const string& DNSPacket::getString()
+const string& DNSPacket::getString(bool throwsOnTruncation)
{
if(!d_wrapped)
- wrapup();
+ wrapup(throwsOnTruncation);
return d_rawpacket;
}
/** Must be called before attempting to access getData(). This function stuffs all resource
* records found in rrs into the data buffer. It also frees resource records queued for us.
*/
-void DNSPacket::wrapup()
+void DNSPacket::wrapup(bool throwsOnTruncation)
{
if(d_wrapped) {
return;
pw.startRecord(pos->dr.d_name, pos->dr.d_type, pos->dr.d_ttl, pos->dr.d_class, pos->dr.d_place);
pos->dr.d_content->toPacket(pw);
if(pw.size() + optsize > (d_tcp ? 65535 : getMaxReplyLen())) {
+ if (throwsOnTruncation) {
+ throw PDNSException("attempt to write an oversized chunk");
+ }
pw.rollback();
pw.truncate();
pw.getHeader()->tc=1;
int noparse(const char *mesg, size_t len); //!< just suck the data inward
int parse(const char *mesg, size_t len); //!< parse a raw UDP or TCP packet and suck the data inward
- const string& getString(); //!< for serialization - just passes the whole packet
+ const string& getString(bool throwsOnTruncation=false); //!< for serialization - just passes the whole packet. If throwsOnTruncation is set, an exception will be raised if the records are too large to fit inside a single DNS payload, instead of setting the TC bit
// address & socket manipulation
void setRemote(const ComboAddress*, std::optional<ComboAddress> = std::nullopt);
void setQuestion(int op, const DNSName &qdomain, int qtype); // wipes 'd', sets a random id, creates start of packet (domain, type, class etc)
DTime d_dt; //!< the time this packet was created. replyPacket() copies this in for you, so d_dt becomes the time spent processing the question+answer
- void wrapup(); // writes out queued rrs, and generates the binary packet. also shuffles. also rectifies dnsheader 'd', and copies it to the stringbuffer
+ void wrapup(bool throwsOnTruncation=false); // writes out queued rrs, and generates the binary packet. also shuffles. also rectifies dnsheader 'd', and copies it to the stringbuffer. If throwsOnTruncation is set, an exception will be raised if the records are too large to fit inside a single DNS payload, instead of setting the TC bit
void spoofQuestion(const DNSPacket& qd); //!< paste in the exact right case of the question. Useful for PacketCache
unsigned int getMinTTL(); //!< returns lowest TTL of any record in the packet
bool isEmpty(); //!< returns true if there are no rrs in the packet
#include "proxy-protocol.hh"
#include "noinitvector.hh"
#include "gss_context.hh"
+#include "pdnsexception.hh"
extern AuthPacketCache PC;
extern StatBag S;
void TCPNameserver::sendPacket(std::unique_ptr<DNSPacket>& p, int outsock, bool last)
{
+ uint16_t len=htons(p->getString(true).length());
+
+ // this also calls p->getString; call it after our explicit call so throwsOnTruncation=true is honoured
g_rs.submitResponse(*p, false, last);
- uint16_t len=htons(p->getString().length());
string buffer((const char*)&len, 2);
buffer.append(p->getString());
writenWithTimeout(outsock, buffer.c_str(), buffer.length(), d_idleTimeout);
if(!outpacket->getRRS().empty()) {
if(haveTSIGDetails && !tsigkeyname.empty())
outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac, true); // first answer is 'normal'
- sendPacket(outpacket, outsock, false);
+ try {
+ sendPacket(outpacket, outsock, false);
+ }
+ catch (PDNSException& pe) {
+ throw PDNSException("during axfr-out of "+target.toString()+", this happened: "+pe.reason);
+ }
trc.d_mac=outpacket->d_trc.d_mac;
outpacket=getFreshAXFRPacket(q);
}