]> granicus.if.org Git - pdns/commitdiff
almost there
authorBert Hubert <bert.hubert@netherlabs.nl>
Mon, 13 Aug 2007 14:40:02 +0000 (14:40 +0000)
committerBert Hubert <bert.hubert@netherlabs.nl>
Mon, 13 Aug 2007 14:40:02 +0000 (14:40 +0000)
git-svn-id: svn://svn.powerdns.com/pdns/trunk/pdns@1082 d19b8d6e-7fed-0310-83ef-9ca221ded41b

pdns/nproxy.cc

index a4a569219a5716a4b35e9c39a3a777a388e155cc..0d06ca5f74e2803fa04fd9d8ff090bd7647a66e4 100644 (file)
@@ -9,6 +9,10 @@
 #include <boost/multi_index_container.hpp>
 #include <boost/multi_index/ordered_index.hpp>
 #include <boost/multi_index/key_extractors.hpp>
+#include <boost/algorithm/string.hpp>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
 
 #include "mplexer.hh"
 
@@ -21,6 +25,7 @@ po::variables_map g_vm;
 
 SelectFDMultiplexer g_fdm;
 int g_pdnssocket;
+bool g_verbose;
 
 struct NotificationInFlight
 {
@@ -31,7 +36,8 @@ struct NotificationInFlight
   int origSocket;
 };
 
-map<uint16_t, NotificationInFlight> g_nifs;
+typedef map<uint16_t, NotificationInFlight> nifs_t;
+nifs_t g_nifs;
 
 void handleOutsideUDPPacket(int fd, boost::any&)
 try
@@ -54,7 +60,7 @@ try
   nif.domain = mdp.d_qname;
   nif.origID = mdp.d_header.id;
 
-  cerr<<"Packet for: "<< nif.domain << endl;
+  cerr<<"External notification received for: "<< nif.domain << endl;
 
   if(mdp.d_header.opcode != Opcode::Notify || mdp.d_qtype != QType::SOA) {
     cerr<<"Opcode: "<<mdp.d_header.opcode<<", != notify\n";
@@ -88,17 +94,17 @@ try
 
   socklen_t socklen=sizeof(nif.source);
 
-  int res=recvfrom(fd, buffer, sizeof(buffer), 0, (struct sockaddr*)&nif.source, &socklen);
-  if(!res)
+  int len=recvfrom(fd, buffer, sizeof(buffer), 0, (struct sockaddr*)&nif.source, &socklen);
+  if(!len)
     return;
 
-  if(res < 0) 
+  if(len < 0) 
     throw runtime_error("reading packet from remote: "+stringerror());
     
-  string packet(buffer, res);
+  string packet(buffer, len);
   MOADNSParser mdp(packet);
 
-  cerr<<"Inside packet for: "<<mdp.d_qname<<endl;
+  cerr<<"Inside notification response for: "<<mdp.d_qname<<endl;
 
   if(!g_nifs.count(mdp.d_header.id)) {
     cerr<<"Response from inner PowerDNS with unknown ID "<<mdp.d_header.id<<endl;
@@ -107,15 +113,18 @@ try
   
   nif=g_nifs[mdp.d_header.id];
 
-  vector<uint8_t> outpacket;
-  DNSPacketWriter pw(outpacket, mdp.d_qname, mdp.d_qtype, 1, Opcode::Notify);
-
-  static uint16_t s_idpool;
-  pw.getHeader()->id = nif.resentID = s_idpool++;
-  
-  if(send(g_pdnssocket, &outpacket[0], outpacket.size(), 0) < 0) {
-    throw runtime_error("Unable to send notify to PowerDNS: "+stringerror());
+  if(!iequals(nif.domain,mdp.d_qname)) {
+    cerr<<"Response from inner PowerDNS for different domain '"<<mdp.d_qname<<"' than original notification '"<<nif.domain<<"'"<<endl;
+  } else {
+    struct dnsheader dh;
+    memcpy(&dh, buffer, sizeof(dh));
+    dh.id = nif.origID;
+    
+    if(sendto(nif.origSocket, buffer, len, 0, (sockaddr*) &nif.source, nif.source.getSocklen()) < 0) {
+      throw runtime_error("Unable to send notify to PowerDNS: "+stringerror());
+    }
   }
+  g_nifs.erase(mdp.d_header.id);
 
 }
 catch(exception &e)
@@ -123,7 +132,20 @@ catch(exception &e)
   cerr<<"Error parsing incoming packet: "<<e.what()<<endl;
 }
 
+void expireOldNotifications()
+{
+  time_t limit = time(0) - 10;
+  for(nifs_t::iterator iter = g_nifs.begin(); iter != g_nifs.end(); ) {
+    if(iter->second.resentTime < limit) {
+      cerr<<"Removing notification proxy entry for '"<<iter->second.domain<<"', expired"<<endl;
+      g_nifs.erase(iter++);
+    }
+    else
+      ++iter;
+  }
+}
 
+void daemonize();
 
 int main(int argc, char** argv)
 try
@@ -131,8 +153,11 @@ try
   po::options_description desc("Allowed options");
   desc.add_options()
     ("help,h", "produce help message")
-    ("powerdns-ip", po::value<string>(), "IP address of PowerDNS server")
-    ("local-address", po::value<vector<string> >(), "IP addresses to listen on");
+    ("powerdns-address", po::value<string>(), "IP address of PowerDNS server")
+    ("origin-address", po::value<string>()->default_value("::"), "Source address for notifications to PowerDNS")
+    ("listen-address", po::value<vector<string> >(), "IP addresses to listen on")
+    ("daemon,d", po::value<bool>()->default_value(true), "operate in the background")
+    ("verbose,v", "be verbose");
 
   po::store(po::command_line_parser(argc, argv).options(desc).run(), g_vm);
   po::notify(g_vm);
@@ -142,14 +167,18 @@ try
     return EXIT_SUCCESS;
   }
 
-  if(!g_vm.count("powerdns-ip")) {
-    cerr<<"Mandatory setting 'powerdns-ip' unset:\n"<<desc<<endl;
+  if(!g_vm.count("powerdns-address")) {
+    cerr<<"Mandatory setting 'powerdns-address' unset:\n"<<desc<<endl;
     return EXIT_FAILURE;
   }
+
+  if(!g_vm.count("verbose")) {
+    g_verbose=true;
+  }
   
   vector<string> addresses;
-  if(g_vm.count("local-address"))
-    addresses=g_vm["local-address"].as<vector<string> >();
+  if(g_vm.count("listen-address"))
+    addresses=g_vm["listen-address"].as<vector<string> >();
   else
     addresses.push_back("::");
 
@@ -163,7 +192,7 @@ try
       throw runtime_error("Creating socket for incoming packets: "+stringerror());
 
     if(::bind(sock,(sockaddr*) &local, local.getSocklen()) < 0)
-      throw runtime_error("Binding socket for incoming packets: "+stringerror());
+      throw runtime_error("Binding socket for incoming packets to '"+ local.toStringWithPort()+"': "+stringerror());
 
     g_fdm.addReadFD(sock, handleOutsideUDPPacket); // add to fdmultiplexer for each socket
   }
@@ -174,7 +203,12 @@ try
   if(g_pdnssocket < 0)
     throw runtime_error("Creating socket for packets to PowerDNS: "+stringerror());
 
-  ComboAddress pdns(g_vm["powerdns-ip"].as<string>(), 53);
+  ComboAddress originAddress(g_vm["origin-address"].as<string>(), 0);
+  if(::bind(g_pdnssocket,(sockaddr*) &originAddress, originAddress.getSocklen()) < 0)
+      throw runtime_error("Binding local address of inward socket to '"+ originAddress.toStringWithPort()+"': "+stringerror());
+  
+
+  ComboAddress pdns(g_vm["powerdns-address"].as<string>(), 53);
   if(connect(g_pdnssocket, (struct sockaddr*) &pdns, pdns.getSocklen()) < 0) 
     throw runtime_error("Failed to connect PowerDNS socket to address "+pdns.toString()+": "+stringerror());
 
@@ -185,22 +219,28 @@ try
       throw runtime_error("while chrooting to "+g_vm["chroot"].as<string>());
   }
 
+  if(g_vm["daemon"].as<bool>()) {
+    daemonize();
+  }
+
+
   // start loop
   struct timeval now;
   for(;;) {
     gettimeofday(&now, 0);
     g_fdm.run(&now);
     // check for notifications that have been outstanding for more than 10 seconds
-    cerr<<".\n";
+    expireOldNotifications();
   }
-
-  
-
 }
 catch(exception& e)
 {
   cerr<<"Fatal: "<<e.what()<<endl;
 }
+catch(AhuException& e)
+{
+  cerr<<"Fatal: "<<e.reason<<endl;
+}
 
 /* added so we don't have to link in most of powerdns */
 
@@ -246,3 +286,21 @@ bool IpToU32(const string &str, uint32_t *ip)
   }
   return false;
 }
+
+void daemonize(void)
+{
+  if(fork())
+    exit(0); // bye bye
+  
+  setsid(); 
+
+  int i=open("/dev/null",O_RDWR); /* open stdin */
+  if(i < 0) 
+    cerr<<"Unable to open /dev/null: "<<stringerror()<<endl;
+  else {
+    dup2(i,0); /* stdin */
+    dup2(i,1); /* stderr */
+    dup2(i,2); /* stderr */
+    close(i);
+  }
+}