Exemplo n.º 1
0
/** 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);
}
Exemplo n.º 2
0
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;
  }
}
Exemplo n.º 3
0
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;
}
Exemplo n.º 4
0
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;
}
Exemplo n.º 5
0
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;
}
Exemplo n.º 6
0
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 ());
}
Exemplo n.º 7
0
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;
}
Exemplo n.º 8
0
/** 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;
    } 
}
Exemplo n.º 9
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;
}
Exemplo n.º 10
0
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;
}
Exemplo n.º 11
0
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);
}
Exemplo n.º 12
0
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;
}
Exemplo n.º 13
0
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;
}
Exemplo n.º 14
0
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;
  }
}
Exemplo n.º 15
0
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());
}
Exemplo n.º 16
0
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;
}
Exemplo n.º 17
0
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
}
Exemplo n.º 18
0
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);
}
Exemplo n.º 19
0
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);
   }
}
Exemplo n.º 20
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;
  }
}
Exemplo n.º 21
0
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;
}
Exemplo n.º 22
0
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;
  }
}
Exemplo n.º 23
0
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);
}
Exemplo n.º 24
0
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);
}
Exemplo n.º 25
0
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;
}
Exemplo n.º 26
0
/// @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 ());
  }
}