• Main Page
  • Data Structures
  • Files
  • File List
  • Globals

/build/buildd-opendnssec_1.3.2-1~bpo60+1-kfreebsd-i386-KuwQV_/opendnssec-1.3.2/signer/src/tools/zone_fetcher.c

Go to the documentation of this file.
00001 /*
00002  * $Id: zone_fetcher.c 5408 2011-08-16 08:15:16Z matthijs $
00003  *
00004  * Copyright (c) 2009 NLnet Labs. All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions
00008  * are met:
00009  * 1. Redistributions of source code must retain the above copyright
00010  *    notice, this list of conditions and the following disclaimer.
00011  * 2. Redistributions in binary form must reproduce the above copyright
00012  *    notice, this list of conditions and the following disclaimer in the
00013  *    documentation and/or other materials provided with the distribution.
00014  *
00015  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00016  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00017  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00018  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
00019  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00020  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
00021  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00022  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
00023  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
00024  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
00025  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00026  */
00027 
00028 #include "config.h"
00029 #include "shared/log.h"
00030 #include "shared/privdrop.h"
00031 #include "tools/toolutil.h"
00032 #include "tools/zone_fetcher.h"
00033 
00034 #include <arpa/inet.h>
00035 #include <errno.h>
00036 #include <fcntl.h>
00037 #include <getopt.h>
00038 #include <signal.h>
00039 #include <syslog.h>
00040 #include <unistd.h>
00041 #include <sys/types.h>
00042 #include <sys/socket.h>
00043 
00044 #include <libxml/tree.h>
00045 #include <libxml/parser.h>
00046 #include <libxml/xpath.h>
00047 #include <libxml/xpathInternals.h>
00048 #include <libxml/relaxng.h>
00049 #include <libxml/xmlreader.h>
00050 #include <libxml/xmlsave.h>
00051 
00052 #define DNS_SERIAL_GT(a, b) ((int)(((a) - (b)) & 0xFFFFFFFF) > 0)
00053 
00054 static int sig_quit = 0;
00055 static int sig_reload = 0;
00056 
00057 ldns_resolver*
00058 init_xfrd(config_type* config)
00059 {
00060     serverlist_type* servers;
00061     ldns_rdf* ns = NULL;
00062     ldns_status status = LDNS_STATUS_OK;
00063 
00064     ldns_resolver* xfrd = ldns_resolver_new();
00065     if (config) {
00066         if (config->use_tsig) {
00067             ldns_resolver_set_tsig_keyname(xfrd, config->tsig_name);
00068             if (strncmp(config->tsig_algo, "hmac-md5", 8) == 0) {
00069                 ldns_resolver_set_tsig_algorithm(xfrd, "hmac-md5.sig-alg.reg.int.");
00070             } else {
00071                 ldns_resolver_set_tsig_algorithm(xfrd, config->tsig_algo);
00072             }
00073             ldns_resolver_set_tsig_keydata(xfrd, config->tsig_secret);
00074         }
00075         if (config->serverlist && config->serverlist->port)
00076             ldns_resolver_set_port(xfrd, atoi(config->serverlist->port));
00077         else
00078             ldns_resolver_set_port(xfrd, atoi(DNS_PORT_STRING));
00079         ldns_resolver_set_recursive(xfrd, 0);
00080 
00081         servers = config->serverlist;
00082         while (servers) {
00083             if (servers->family == AF_INET6)
00084                 ns = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_AAAA, servers->ipaddr);
00085             else
00086                 ns = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_A, servers->ipaddr);
00087             if (ns) {
00088                 status = ldns_resolver_push_nameserver(xfrd, ns);
00089                 ldns_rdf_deep_free(ns);
00090                 ns = NULL;
00091             } else {
00092                 ods_log_error("zone fetcher could not use %s for transfer "
00093                     "request: could not parse ip address", servers->ipaddr);
00094             }
00095             if (status != LDNS_STATUS_OK) {
00096                 ods_log_error("zone fetcher could not use %s for transfer "
00097                     "request: %s", servers->ipaddr,
00098                     ldns_get_errorstr_by_id(status));
00099             }
00100             servers = servers->next;
00101         }
00102         if (ldns_resolver_nameserver_count(xfrd) <= 0) {
00103             ods_log_error("zone fetcher could not find any valid name "
00104                 "servers");
00105         }
00106 
00107     }
00108     return xfrd;
00109 }
00110 
00111 static zfzonelist_type*
00112 new_zone(char* zone_name, char* input_file)
00113 {
00114     zfzonelist_type* zlt = (zfzonelist_type*) malloc(sizeof(zfzonelist_type));
00115     zlt->name = strdup(zone_name);
00116     zlt->dname = ldns_dname_new_frm_str(zone_name);
00117     zlt->input_file = strdup(input_file);
00118     zlt->next = NULL;
00119     return zlt;
00120 }
00121 
00122 static void
00123 free_zonelist(zfzonelist_type* zlt)
00124 {
00125         zfzonelist_type* next = NULL;
00126 
00127     while (zlt) {
00128         next = zlt->next;
00129         free((void*) zlt->name);
00130         if (zlt->dname) {
00131             ldns_rdf_deep_free(zlt->dname);
00132         }
00133         free((void*) zlt->input_file);
00134         free((void*) zlt);
00135         zlt = next;
00136     }
00137 }
00138 
00139 static serverlist_type*
00140 new_server(char* ipv4, char* ipv6, char* port)
00141 {
00142     serverlist_type* slt = (serverlist_type*) malloc(sizeof(serverlist_type));
00143     slt->family = AF_UNSPEC;
00144     if (ipv4) {
00145         slt->family = AF_INET;
00146         slt->ipaddr = strdup(ipv4);
00147     }
00148     else if (ipv6) {
00149         slt->family = AF_INET6;
00150         slt->ipaddr = strdup(ipv6);
00151     }
00152     if (port)
00153         slt->port = strdup(port);
00154     else
00155         slt->port = NULL;
00156     memset(&slt->addr, 0, sizeof(union acl_addr_storage));
00157 
00158     if (slt->family == AF_INET6 && strlen(slt->ipaddr) > 0) {
00159         if (inet_pton(slt->family, slt->ipaddr, &slt->addr.addr6) != 1) {
00160             ods_log_error("zone fetcher encountered bad ip address '%s'",
00161                 slt->ipaddr);
00162         }
00163     }
00164     else if (slt->family == AF_INET && strlen(slt->ipaddr) > 0) {
00165         if (inet_pton(slt->family, slt->ipaddr, &slt->addr.addr) != 1) {
00166             ods_log_error("zone fetcher encountered bad ip address '%s'",
00167                 slt->ipaddr);
00168         }
00169     }
00170 
00171     slt->next = NULL;
00172     return slt;
00173 }
00174 
00175 static void
00176 free_serverlist(serverlist_type* slt)
00177 {
00178     if (slt) {
00179         free_serverlist(slt->next);
00180         if (slt->port)   free((void*) slt->port);
00181         if (slt->ipaddr) free((void*) slt->ipaddr);
00182         free((void*) slt);
00183     }
00184 }
00185 
00186 static config_type*
00187 new_config(void)
00188 {
00189     config_type* cfg = (config_type*) malloc(sizeof(config_type)); /* not freed */
00190     cfg->use_tsig = 0;
00191     cfg->pidfile = NULL;
00192     cfg->tsig_name = NULL;
00193     cfg->tsig_algo = NULL;
00194     cfg->tsig_secret = NULL;
00195     cfg->serverlist = NULL;
00196     cfg->notifylist = NULL;
00197     cfg->zonelist_file = NULL;
00198     cfg->zonelist = NULL;
00199     return cfg;
00200 }
00201 
00202 static void
00203 free_config(config_type* cfg)
00204 {
00205     if (cfg) {
00206         if (cfg->tsig_name)   free((void*) cfg->tsig_name);
00207         if (cfg->tsig_algo)   free((void*) cfg->tsig_algo);
00208         if (cfg->tsig_secret) free((void*) cfg->tsig_secret);
00209         if (cfg->pidfile)     free((void*) cfg->pidfile);
00210         if (cfg->zonelist_file) free((void*) cfg->zonelist_file);
00211         free_zonelist(cfg->zonelist);
00212         free_serverlist(cfg->serverlist);
00213         free_serverlist(cfg->notifylist);
00214         free((void*) cfg);
00215     }
00216 }
00217 
00218 static int
00219 read_axfr_config(const char* filename, config_type* cfg)
00220 {
00221     int ret, i, use_tsig = 0;
00222     char* tag_name, *tsig_name, *tsig_algo, *tsig_secret, *ipv4, *ipv6, *port;
00223     serverlist_type* serverlist = NULL;
00224     serverlist_type* notifylist = NULL;
00225 
00226     xmlTextReaderPtr reader = NULL;
00227     xmlDocPtr doc = NULL;
00228     xmlXPathContextPtr xpathCtx = NULL;
00229     xmlXPathObjectPtr xpathObj = NULL;
00230     xmlNode *curNode = NULL;
00231     xmlChar *tsig_expr = (unsigned char*) "//ZoneFetch/Default/TSIG";
00232     xmlChar *server_expr = (unsigned char*) "//ZoneFetch/Default/RequestTransfer";
00233     xmlChar *notify_expr = (unsigned char*) "//ZoneFetch/NotifyListen";
00234 
00235     if (filename == NULL) {
00236         ods_log_alert("no zone fetcher configfile provided");
00237         ods_log_info("zone fetcher exiting...");
00238         exit(EXIT_FAILURE);
00239     }
00240 
00241     /* In case zonelist is huge use the XmlTextReader API so that we don't
00242      * hold the whole file in memory */
00243     reader = xmlNewTextReaderFilename(filename); /* not properly freed */
00244     if (reader != NULL) {
00245         ret = xmlTextReaderRead(reader);
00246         while (ret == 1) {
00247             tag_name = (char*) xmlTextReaderLocalName(reader);
00248             /* Found <ZoneFetch> */
00249             if (strncmp(tag_name, "ZoneFetch", 8) == 0 &&
00250                 xmlTextReaderNodeType(reader) == 1) {
00251 
00252                 /* Expand this node and get the rest of the info with XPath */
00253                 xmlTextReaderExpand(reader);
00254                 doc = xmlTextReaderCurrentDoc(reader);
00255                 if (doc == NULL) {
00256                     ods_log_error("can not read zone fetcher configfile "
00257                         "%s", filename?filename:"(null)");
00258                     ods_log_info("zone fetcher exiting...");
00259                     exit(EXIT_FAILURE);
00260                 }
00261                 xpathCtx = xmlXPathNewContext(doc);
00262                 if (xpathCtx == NULL) {
00263                     ods_log_error("zone fetcher can not create XPath "
00264                         "context for %s", filename?filename:"(null)");
00265                     ods_log_info("zone fetcher exiting...");
00266                     exit(EXIT_FAILURE);
00267                 }
00268 
00269                 /* Extract the master server address */
00270                 xpathObj = xmlXPathEvalExpression(server_expr, xpathCtx);
00271                 if (xpathObj == NULL || !xpathObj->nodesetval) {
00272                     ods_log_error("zone fetcher can not locate master "
00273                         "server(s) in %s", filename?filename:"(null)");
00274                     ods_log_info("zone fetcher exiting...");
00275                     exit(EXIT_FAILURE);
00276                 }
00277                 else {
00278                     for (i=0; i < xpathObj->nodesetval->nodeNr; i++) {
00279                         ipv4 = NULL;
00280                         ipv6 = NULL;
00281                         port = NULL;
00282                         curNode = xpathObj->nodesetval->nodeTab[i]->xmlChildrenNode;
00283                         while (curNode) {
00284                             if (xmlStrEqual(curNode->name, (const xmlChar *)"IPv4"))
00285                                 ipv4 = (char *) xmlNodeGetContent(curNode);
00286                             if (xmlStrEqual(curNode->name, (const xmlChar *)"IPv6"))
00287                                 ipv6 = (char *) xmlNodeGetContent(curNode);
00288                             if (xmlStrEqual(curNode->name, (const xmlChar *)"Port"))
00289                                 port = (char *) xmlNodeGetContent(curNode);
00290                             curNode = curNode->next;
00291                        }
00292                        if (ipv4 || ipv6) {
00293                            if (serverlist == NULL) {
00294                                serverlist = new_server(ipv4, ipv6, port); /* not freed */
00295                                cfg->serverlist = serverlist;
00296                            }
00297                            else {
00298                                serverlist->next = new_server(ipv4, ipv6, port); /* not freed */
00299                                serverlist = serverlist->next;
00300                            }
00301                        }
00302 
00303                        if (ipv4) free((void*) ipv4);
00304                        if (ipv6) free((void*) ipv6);
00305                        if (port) free((void*) port);
00306                     }
00307                     xmlXPathFreeObject(xpathObj);
00308                 }
00309 
00310                 /* Extract the notify listen address */
00311                 xpathObj = xmlXPathEvalExpression(notify_expr, xpathCtx);
00312                 if (xpathObj != NULL && xpathObj->nodesetval) {
00313                     for (i=0; i < xpathObj->nodesetval->nodeNr; i++) {
00314                         ipv4 = NULL;
00315                         ipv6 = NULL;
00316                         port = NULL;
00317                         curNode = xpathObj->nodesetval->nodeTab[i]->xmlChildrenNode;
00318                         while (curNode) {
00319                             if (xmlStrEqual(curNode->name, (const xmlChar *)"IPv4"))
00320                                 ipv4 = (char *) xmlNodeGetContent(curNode);
00321                             if (xmlStrEqual(curNode->name, (const xmlChar *)"IPv6"))
00322                                 ipv6 = (char *) xmlNodeGetContent(curNode);
00323                             if (xmlStrEqual(curNode->name, (const xmlChar *)"Port"))
00324                                 port = (char *) xmlNodeGetContent(curNode);
00325                             curNode = curNode->next;
00326                        }
00327                        if (ipv4 || ipv6 || port) {
00328                            if (!ipv4 && !ipv6) {
00329                                if (notifylist == NULL) {
00330                                    notifylist = new_server(NULL, "", port);
00331                                    cfg->notifylist = notifylist;
00332 
00333                                    notifylist->next = new_server("", NULL, port);
00334                                    notifylist = notifylist->next;
00335                                }
00336                                else {
00337                                    notifylist->next = new_server("", NULL, port);
00338                                    notifylist = notifylist->next;
00339 
00340                                    notifylist->next = new_server(NULL, "", port);
00341                                    notifylist = notifylist->next;
00342                                }
00343                            }
00344                            else if (notifylist == NULL) {
00345                                notifylist = new_server(ipv4, ipv6, port);
00346                                cfg->notifylist = notifylist;
00347                            }
00348                            else {
00349                                notifylist->next = new_server(ipv4, ipv6, port);
00350                                notifylist = notifylist->next;
00351                            }
00352                        }
00353 
00354                        if (ipv4) free((void*) ipv4);
00355                        if (ipv6) free((void*) ipv6);
00356                        if (port) free((void*) port);
00357                     }
00358                     xmlXPathFreeObject(xpathObj);
00359                 }
00360 
00361                 /* Extract the tsig credentials */
00362                 xpathObj = xmlXPathEvalExpression(tsig_expr, xpathCtx);
00363                 if (xpathObj != NULL && xpathObj->nodesetval) {
00364                     for (i=0; i < xpathObj->nodesetval->nodeNr; i++) {
00365                         tsig_name = NULL;
00366                         tsig_algo = NULL;
00367                         tsig_secret = NULL;
00368                         curNode = xpathObj->nodesetval->nodeTab[i]->xmlChildrenNode;
00369                         while (curNode) {
00370                             if (xmlStrEqual(curNode->name, (const xmlChar *)"Name"))
00371                                 tsig_name = (char *) xmlNodeGetContent(curNode);
00372                             if (xmlStrEqual(curNode->name, (const xmlChar *)"Algorithm"))
00373                                 tsig_algo = (char *) xmlNodeGetContent(curNode);
00374                             if (xmlStrEqual(curNode->name, (const xmlChar *)"Secret"))
00375                                 tsig_secret = (char *) xmlNodeGetContent(curNode);
00376                             curNode = curNode->next;
00377                        }
00378                        if (tsig_name && tsig_algo && tsig_secret) {
00379                            use_tsig = 1;
00380                            if (cfg->tsig_name) {
00381                                free((void*) cfg->tsig_name);
00382                            }
00383                            if (cfg->tsig_algo) {
00384                                free((void*) cfg->tsig_algo);
00385                            }
00386                            if (cfg->tsig_secret) {
00387                                free((void*) cfg->tsig_secret);
00388                            }
00389                            cfg->tsig_name = strdup(tsig_name);
00390                            cfg->tsig_algo = strdup(tsig_algo);
00391                            cfg->tsig_secret = strdup(tsig_secret);
00392                        }
00393                        if (tsig_name) {
00394                            free((void*) tsig_name);
00395                        }
00396                        if (tsig_algo) {
00397                            free((void*) tsig_algo);
00398                        }
00399                        if (tsig_secret) {
00400                            free((void*) tsig_secret);
00401                        }
00402                    }
00403                    xmlXPathFreeObject(xpathObj);
00404                 }
00405                 xmlXPathFreeContext(xpathCtx);
00406             }
00407 
00408             /* Read the next line */
00409             ret = xmlTextReaderRead(reader);
00410             free((void*) tag_name);
00411         }
00412         xmlFreeTextReader(reader);
00413         xmlFreeDoc(doc);
00414         if (ret != 0) {
00415             ods_log_error("zone fetcher failed to parse config file %s",
00416                 filename?filename:"(null)");
00417             ods_log_info("zone fetcher exiting...");
00418             exit(EXIT_FAILURE);
00419         }
00420     } else {
00421         ods_log_error("zone fetcher was unable to open config file %s",
00422             filename?filename:"(null)");
00423         ods_log_info("zone fetcher exiting...");
00424         exit(EXIT_FAILURE);
00425     }
00426 
00427     cfg->use_tsig = use_tsig;
00428     return 0;
00429 }
00430 
00431 static zfzonelist_type*
00432 read_zonelist(const char* filename)
00433 {
00434     zfzonelist_type* zonelist = NULL, *zonelist_start = NULL;
00435     char* tag_name, *zone_name, *input_file;
00436     int ret;
00437 
00438     xmlTextReaderPtr reader = NULL;
00439     xmlDocPtr doc = NULL;
00440     xmlXPathContextPtr xpathCtx = NULL;
00441     xmlXPathObjectPtr xpathObj = NULL;
00442     xmlChar *name_expr = (unsigned char*) "name";
00443     xmlChar *adapter_expr = (unsigned char*) "//Zone/Adapters/Input/File";
00444 
00445     if (filename == NULL) {
00446         ods_log_error("no zonelist provided for zone fetcher");
00447         ods_log_info("zone fetcher exiting...");
00448         exit(EXIT_FAILURE);
00449     }
00450 
00451     /* In case zonelist is huge use the XmlTextReader API so that we don't hold the whole file in memory */
00452     reader = xmlNewTextReaderFilename(filename);
00453     if (reader != NULL) {
00454         ret = xmlTextReaderRead(reader);
00455         while (ret == 1) {
00456             tag_name = (char*) xmlTextReaderLocalName(reader);
00457             /* Found <Zone> */
00458             if (strncmp(tag_name, "Zone", 4) == 0 &&
00459                 strncmp(tag_name, "ZoneList", 8) != 0 &&
00460                 xmlTextReaderNodeType(reader) == 1) {
00461                 /* Get the zone name (TODO what if this is null?) */
00462                 zone_name = (char*) xmlTextReaderGetAttribute(reader, name_expr);
00463                 /* Make sure that we got something */
00464                 if (zone_name == NULL) {
00465                     /* error */
00466                     ods_log_error("zone fetcher failed to extract zone "
00467                         "name from %s", filename?filename:"(null)");
00468                     /* Don't return? try to parse the rest of the zones? */
00469                     ret = xmlTextReaderRead(reader);
00470                     continue;
00471                 }
00472                 /* Expand this node and get the rest of the info with XPath */
00473                 xmlTextReaderExpand(reader);
00474                 doc = xmlTextReaderCurrentDoc(reader);
00475                 if (doc == NULL) {
00476                     ods_log_error("zone fetcher could not read zone "
00477                         "%s; skipping", zone_name);
00478                     /* Don't return? try to parse the rest of the zones? */
00479                     ret = xmlTextReaderRead(reader);
00480                     continue;
00481                 }
00482                 xpathCtx = xmlXPathNewContext(doc);
00483                 if (xpathCtx == NULL) {
00484                     ods_log_error("zone fetcher can not create XPath "
00485                         "context for %s; skipping zone", zone_name);
00486                     /* Don't return? try to parse the rest of the zones? */
00487                     ret = xmlTextReaderRead(reader);
00488                     continue;
00489                 }
00490 
00491                 /* Extract the Input File Adapter filename */
00492                 xpathObj = xmlXPathEvalExpression(adapter_expr, xpathCtx);
00493                 if (xpathObj == NULL || !xpathObj->nodesetval) {
00494                     ods_log_error("zone fetcher was unable to evaluate "
00495                         "xpath expression: %s; skipping zone", adapter_expr);
00496                     /* Don't return? try to parse the rest of the zones? */
00497                     ret = xmlTextReaderRead(reader);
00498                     continue;
00499                 }
00500                 input_file = (char*) xmlXPathCastToString(xpathObj);
00501                 xmlXPathFreeObject(xpathObj);
00502 
00503                 if (zonelist == NULL) {
00504                     zonelist = new_zone(zone_name, input_file); /* not freed */
00505                     zonelist_start = zonelist;
00506                 }
00507                 else {
00508                     zonelist->next = new_zone(zone_name, input_file);
00509                     zonelist = zonelist->next;
00510                 }
00511                 free((void*) zone_name);
00512                 free((void*) input_file);
00513 
00514                 xmlXPathFreeContext(xpathCtx);
00515             }
00516 
00517             /* Read the next line */
00518             ret = xmlTextReaderRead(reader);
00519             free((void*) tag_name);
00520         }
00521         xmlFreeTextReader(reader);
00522         xmlFreeDoc(doc);
00523         if (ret != 0) {
00524             ods_log_error("zone fetcher failed to parse zonelist %s",
00525                 filename?filename:"(null)");
00526             ods_log_info("zone fetcher exiting...");
00527             exit(EXIT_FAILURE);
00528         }
00529     } else {
00530         ods_log_error("zone fetcher was unable to open zonelist %s",
00531             filename?filename:"(null)");
00532         ods_log_info("zone fetcher exiting...");
00533         exit(EXIT_FAILURE);
00534     }
00535 
00536     return zonelist_start;
00537 }
00538 
00540 static int
00541 writepid(char* pidfile, pid_t pid)
00542 {
00543     FILE * fd;
00544     char pidbuf[32];
00545     size_t result = 0, size = 0;
00546 
00547     snprintf(pidbuf, sizeof(pidbuf), "%lu\n", (unsigned long) pid);
00548     if ((fd = fopen(pidfile, "w")) ==  NULL ) {
00549         ods_log_error("zone fetcher could not open pidfile %s for "
00550             "writing: %s", pidfile?pidfile:"(null)", strerror(errno));
00551         return -1;
00552     }
00553     size = strlen(pidbuf);
00554     if (size == 0)
00555         result = 1;
00556     result = fwrite((const void*) pidbuf, 1, size, fd);
00557     if (result == 0) {
00558         ods_log_error("zone fetcher failed to write to pidfile: %s",
00559             strerror(errno));
00560     } else if (result < size) {
00561         ods_log_error("zone fetcher had short write to pidfile "
00562             "(disk full?)");
00563         result = 0;
00564     } else
00565         result = 1;
00566     if (!result) {
00567         ods_log_error("zone fetcher could not write pidfile %s: %s",
00568             pidfile?pidfile:"(null)", strerror(errno));
00569         fclose(fd);
00570         return -1;
00571     }
00572     fclose(fd);
00573     return 0;
00574 }
00575 
00577 static void
00578 sig_handler(int sig)
00579 {
00580     switch (sig)
00581     {
00582         case SIGTERM:
00583             sig_quit = 1;
00584             break;
00585         case SIGHUP:
00586             sig_reload = 1;
00587             break;
00588         default:
00589             break;
00590     }
00591     return;
00592 }
00593 
00594 static int
00595 init_sockets(sockets_type* sockets, serverlist_type* list)
00596 {
00597     int ret = 0, r, ip6_support = 1, on = 0;
00598     size_t i;
00599     struct addrinfo hints[MAX_INTERFACES];
00600     serverlist_type* walk = list;
00601     serverlist_type* new_list = NULL;
00602     const char* node = NULL;
00603     const char* port = NULL;
00604 #if defined(SO_REUSEADDR) || defined(IPV6_V6ONLY)
00605     on = 1;
00606 #endif
00607 
00608     for (i = 0; i < MAX_INTERFACES; i++) {
00609         memset(&hints[i], 0, sizeof(hints[i]));
00610         hints[i].ai_family = AF_UNSPEC;
00611         hints[i].ai_flags = AI_PASSIVE;
00612         sockets->udp[i].s = -1;
00613         sockets->tcp[i].s = -1;
00614     }
00615 
00616     /* if no NotifyListen was provided, we create the default IPv4/IPv6
00617      * address info structures */
00618     if (!walk) {
00619 #ifdef  IPV6_V6ONLY
00620         hints[0].ai_family = AF_INET6;
00621         hints[1].ai_family = AF_INET;
00622         new_list = new_server(NULL, "", NULL);
00623         new_list->next = new_server("", NULL, NULL);
00624 #else   /* !IPV6_V6ONLY */
00625         hints[0].ai_family = AF_INET6;
00626         new_list = new_server(NULL, "", NULL);
00627 #endif  /* IPV6_V6ONLY */
00628         walk = new_list;
00629     }
00630 
00631     i = 0;
00632     while (walk) {
00633         node = strlen(walk->ipaddr) > 0 ? walk->ipaddr : NULL;
00634         port = walk->port ? walk->port : DNS_PORT_STRING;
00635         if (node != NULL)
00636             hints[i].ai_flags |= AI_NUMERICHOST;
00637         else
00638             hints[i].ai_family = walk->family;
00639         /* UDP */
00640         hints[i].ai_socktype = SOCK_DGRAM;
00641         /* getaddrinfo */
00642         if ((r = getaddrinfo(node, port, &hints[i],
00643             &(sockets->udp[i].addr))) != 0) {
00644             if (hints[i].ai_family == AF_INET6 && errno == EAFNOSUPPORT) {
00645                 ods_log_error("zone fetcher udp fallback to ipv4, no ipv6: "
00646                     " not supported");
00647                 ip6_support = 0;
00648                 continue;
00649             }
00650             ods_log_error("zone fetcher cannot parse address %s:%s: "
00651                 "getaddrinfo (%i): %s %s", node?node:"(null)",
00652                 port?port:"(null)", walk->family,
00653                  gai_strerror(r), r==EAI_SYSTEM?strerror(errno):"");
00654         }
00655 
00656         /* socket */
00657         if ((sockets->udp[i].s = socket(sockets->udp[i].addr->ai_family,
00658             SOCK_DGRAM, 0)) == -1) {
00659             if (sockets->udp[i].addr->ai_family == AF_INET6 && errno == EAFNOSUPPORT) {
00660                 ods_log_error("zone fetcher udp fallback to ipv4, no ipv6: "
00661                     " not supported");
00662                 ip6_support = 0;
00663             }
00664             else {
00665                 ods_log_error("zone fetcher can't create udp/4 socket for "
00666                     "%s:%s (%s)", node?node:"(null)", port?port:"(null)",
00667                     strerror(errno));
00668                 ret = -1;
00669                 break;
00670             }
00671         }
00672 
00673         if (sockets->udp[i].addr->ai_family == AF_INET) {
00674             if (fcntl(sockets->udp[i].s, F_SETFL,
00675                 O_NONBLOCK) == -1) {
00676                 ods_log_error("zone fetcher cannot fcntl udp/4 socket for "
00677                     "%s:%s (%s)", node?node:"(null)", port?port:"(null)",
00678                     strerror(errno));
00679             }
00680             if (bind(sockets->udp[i].s,
00681                 (struct sockaddr *) sockets->udp[i].addr->ai_addr,
00682                 sockets->udp[i].addr->ai_addrlen) != 0)
00683             {
00684                 ods_log_error("zone fetcher can't bind udp/4 socket for "
00685                     "%s:%s (%s)", node?node:"(null)", port?port:"(null)",
00686                     strerror(errno));
00687                 ret = -1;
00688                 break;
00689             }
00690         }
00691         else if (ip6_support) {
00692 #ifdef IPV6_V6ONLY
00693 #if defined(IPPROTO_IPV6)
00694             ods_log_verbose("zone fetcher setsockopt ipv6_v6only...");
00695             if (setsockopt(sockets->udp[i].s, IPPROTO_IPV6, IPV6_V6ONLY, &on,
00696                 sizeof(on)) < 0)
00697             {
00698                 ods_log_error("zone fetcher setsockopt(..., IPV6_V6ONLY, "
00699                 "...) failed for "
00700                     "%s:%s (%s)", node?node:"(null)", port?port:"(null)",
00701                     strerror(errno));
00702                 ret = -1;
00703                 break;
00704             }
00705 #endif
00706 #endif /* IPV6_V6ONLY */
00707             if (fcntl(sockets->udp[i].s, F_SETFL, O_NONBLOCK) == -1) {
00708                 ods_log_error("zone fetcher cannot fcntl udp/6 socket for "
00709                     "%s:%s (%s)", node?node:"(null)", port?port:"(null)",
00710                     strerror(errno));
00711             }
00712             if (bind(sockets->udp[i].s,
00713                 (struct sockaddr *) sockets->udp[i].addr->ai_addr,
00714                 sockets->udp[i].addr->ai_addrlen) != 0) {
00715                 ods_log_error("zone fetcher can't bind udp/6 socket for "
00716                     "%s:%s (%s)", node?node:"(null)", port?port:"(null)",
00717                     strerror(errno));
00718                 ret = -1;
00719                 break;
00720             }
00721         }
00722 
00723         /* TCP */
00724         hints[i].ai_socktype = SOCK_STREAM;
00725         /* getaddrinfo */
00726         if ((r = getaddrinfo(node, port, &hints[i],
00727             &(sockets->tcp[i].addr))) != 0) {
00728             if (hints[i].ai_family == AF_INET6 && errno == EAFNOSUPPORT) {
00729                 ods_log_error("zone fetcher tcp fallback to ipv4, no ipv6: "
00730                     " not supported");
00731                 ip6_support = 0;
00732                 continue;
00733             }
00734             ods_log_error("zone fetcher cannot parse address %s:%s: "
00735                 "getaddrinfo (%i): %s %s", node?node:"(null)",
00736                  port?port:"(null)", walk->family,
00737                  gai_strerror(r), r==EAI_SYSTEM?strerror(errno):"");
00738         }
00739         /* socket */
00740         if ((sockets->tcp[i].s = socket(sockets->tcp[i].addr->ai_family,
00741             SOCK_STREAM, 0)) == -1) {
00742             if (sockets->tcp[i].addr->ai_family == AF_INET6 &&
00743                 errno == EAFNOSUPPORT) {
00744                 ods_log_error("zone fetcher tcp fallback to ipv4, no ipv6: "
00745                     " not supported");
00746                 ip6_support = 0;
00747             }
00748             else {
00749                 ods_log_error("zone fetcher can't create tcp socket for "
00750                     "%s:%s (%s)", node?node:"(null)", port?port:"(null)",
00751                     strerror(errno));
00752                 ret = -1;
00753                 break;
00754             }
00755         }
00756         /* setsockopt */
00757         if (sockets->tcp[i].addr->ai_family == AF_INET) {
00758             if (setsockopt(sockets->tcp[i].s, SOL_SOCKET, SO_REUSEADDR, &on,
00759                 sizeof(on)) < 0) {
00760                 ods_log_error("zone fetcher setsockopt(..., SO_REUSEADDR, ...) "
00761                     "failed for "
00762                     "%s:%s (%s)", node?node:"(null)", port?port:"(null)",
00763                     strerror(errno));
00764             }
00765             /* fcntl */
00766             if (fcntl(sockets->tcp[i].s, F_SETFL, O_NONBLOCK) == -1) {
00767                 ods_log_error("zone fetcher cannot fcntl tcp/4 for "
00768                     "%s:%s (%s)", node?node:"(null)", port?port:"(null)",
00769                     strerror(errno));
00770             }
00771             /* bind */
00772             if (bind(sockets->tcp[i].s,
00773                 (struct sockaddr *) sockets->tcp[i].addr->ai_addr,
00774                 sockets->tcp[i].addr->ai_addrlen) != 0) {
00775                 ods_log_error("zone fetcher can't bind tcp/4 socket for "
00776                     "%s:%s (%s)", node?node:"(null)", port?port:"(null)",
00777                     strerror(errno));
00778                 ret = -1;
00779                 break;
00780             }
00781             /* listen */
00782             if (listen(sockets->tcp[i].s, 5) == -1) {
00783                 ods_log_error("zone fetcher can't listen to tcp/4 socket for "
00784                     "%s:%s (%s)", node?node:"(null)", port?port:"(null)",
00785                     strerror(errno));
00786                 ret = -1;
00787                 break;
00788             }
00789         } else if (ip6_support) {
00790             /* setsockopt */
00791             if (sockets->tcp[i].addr->ai_family == AF_INET6 && ip6_support) {
00792 #ifdef IPV6_V6ONLY
00793 #if defined(IPPROTO_IPV6)
00794                 if (setsockopt(sockets->tcp[i].s, IPPROTO_IPV6, IPV6_V6ONLY, &on,
00795                     sizeof(on)) < 0)
00796                 {
00797                     ods_log_error("zone fetcher setsockopt(..., IPV6_V6ONLY, "
00798                         "...) failed for "
00799                     "%s:%s (%s)", node?node:"(null)", port?port:"(null)",
00800                     strerror(errno));
00801                     ret = -1;
00802                     break;
00803                 }
00804 #endif
00805 #endif /* IPV6_V6ONLY */
00806             }
00807             if (setsockopt(sockets->tcp[i].s, SOL_SOCKET, SO_REUSEADDR, &on,
00808                 sizeof(on)) < 0) {
00809                 ods_log_error("zone fetcher setsockopt(..., SO_REUSEADDR, ...) "
00810                     "failed for "
00811                     "%s:%s (%s)", node?node:"(null)", port?port:"(null)",
00812                     strerror(errno));
00813             }
00814             /* fcntl */
00815             if (fcntl(sockets->tcp[i].s, F_SETFL, O_NONBLOCK) == -1) {
00816                 ods_log_error("zone fetcher cannot fcntl tcp/6 for "
00817                     "%s:%s (%s)", node?node:"(null)", port?port:"(null)",
00818                     strerror(errno));
00819             }
00820             /* bind */
00821             if (bind(sockets->tcp[i].s,
00822                 (struct sockaddr *) sockets->tcp[i].addr->ai_addr,
00823                 sockets->tcp[i].addr->ai_addrlen) != 0) {
00824                 ods_log_error("zone fetcher can't bind tcp/6 socket for "
00825                     "%s:%s (%s)", node?node:"(null)", port?port:"(null)",
00826                     strerror(errno));
00827                 ret = -1;
00828                 break;
00829             }
00830             /* listen */
00831             if (listen(sockets->tcp[i].s, 5) == -1) {
00832                 ods_log_error("zone fetcher can't listen to tcp/6 socket for "
00833                     "%s:%s (%s)", node?node:"(null)", port?port:"(null)",
00834                     strerror(errno));
00835                 ret = -1;
00836                 break;
00837             }
00838         }
00839 
00840         walk = walk->next;
00841         i++;
00842     }
00843 
00844     if (new_list) {
00845         free_serverlist(new_list);
00846     }
00847 
00848     return ret;
00849 }
00850 
00851 static void
00852 free_sockets(sockets_type* sockets)
00853 {
00854     size_t i = 0;
00855 
00856     for (i=0; i < MAX_INTERFACES; i++) {
00857         if (sockets->udp[i].s != -1) {
00858             close(sockets->udp[i].s);
00859             freeaddrinfo((void*)sockets->udp[i].addr);
00860         }
00861         if (sockets->tcp[i].s != -1) {
00862             close(sockets->tcp[i].s);
00863             freeaddrinfo((void*)sockets->tcp[i].addr);
00864         }
00865     }
00866 }
00867 
00868 static int
00869 odd_xfer(zfzonelist_type* zone, uint32_t serial, config_type* config, int kick_signer)
00870 {
00871     ldns_status status = LDNS_STATUS_OK;
00872     ldns_rr* axfr_rr = NULL, *soa_rr = NULL;
00873     uint32_t new_serial = 0;
00874     ldns_pkt* qpkt = NULL, *apkt;
00875     FILE* fd = NULL;
00876     char lock_ext[32];
00877     char axfr_file[MAXPATHLEN];
00878     char dest_file[MAXPATHLEN];
00879     char lock_file[MAXPATHLEN];
00880     char engine_sign_cmd[MAXPATHLEN + 1024];
00881     int soa_seen = 0;
00882     ldns_resolver* xfrd = NULL;
00883 
00884     /* soa serial query */
00885     if (!zone || !zone->dname) {
00886         ods_log_error("zone fetcher failed to provide a zone for AXFR ");
00887         return -1;
00888     }
00889 /* Coverity comment:
00890    Event deref_ptr: Directly dereferenced pointer "zone"
00891 */
00892     qpkt = ldns_pkt_query_new(ldns_rdf_clone(zone->dname),
00893         LDNS_RR_TYPE_SOA, LDNS_RR_CLASS_IN, LDNS_RD);
00894     if (!qpkt) {
00895         ods_log_error("zone fetcher failed to create SOA query. "
00896             "Aborting AXFR");
00897         return -1;
00898     }
00899 
00900     /* Initialise LDNS resolver for AXFR */
00901     xfrd = init_xfrd(config);
00902 
00903     if (!xfrd) {
00904         ods_log_error("zone fetcher failed to initialise AXFR structure");
00905         return -1;
00906     }
00907 
00908     status = ldns_resolver_send_pkt(&apkt, xfrd, qpkt);
00909     ldns_pkt_free(qpkt);
00910 
00911     if (status != LDNS_STATUS_OK) {
00912         ods_log_error("zone fetcher failed to send SOA query: %s",
00913             ldns_get_errorstr_by_id(status));
00914         ldns_resolver_deep_free(xfrd);
00915         return -1;
00916     }
00917     if (ldns_pkt_ancount(apkt) == 1) {
00918         soa_rr = ldns_rr_list_rr(ldns_pkt_answer(apkt), 0);
00919         if (soa_rr && ldns_rr_get_type(soa_rr) == LDNS_RR_TYPE_SOA) {
00920             new_serial = ldns_rdf2native_int32(ldns_rr_rdf(soa_rr, 2));
00921         }
00922         ldns_pkt_free(apkt);
00923     } else {
00924         ods_log_error("zone fetcher saw SOA response with ANCOUNT != 1, "
00925             "Aborting AXFR");
00926         /* retry? */
00927         ldns_pkt_free(apkt);
00928         ldns_resolver_deep_free(xfrd);
00929         return -1;
00930     }
00931 
00932     if (DNS_SERIAL_GT(new_serial, serial)) {
00933         status = ldns_axfr_start(xfrd, zone->dname, LDNS_RR_CLASS_IN);
00934         if (status != LDNS_STATUS_OK) {
00935             ods_log_error("zone fetcher failed to start axfr: %s",
00936                 ldns_get_errorstr_by_id(status));
00937             ldns_resolver_deep_free(xfrd);
00938             return -1;
00939         }
00940 
00941 /* Coverity comment:
00942    Event check_after_deref: Pointer "zone" dereferenced before NULL check
00943 */
00944         if (zone && zone->input_file) {
00945             snprintf(lock_ext, sizeof(lock_ext), "axfr.%lu",
00946                 (unsigned long) getpid());
00947 
00948             snprintf(axfr_file, sizeof(axfr_file), "%s.%s", zone->input_file, lock_ext);
00949             fd = fopen(axfr_file, "w");
00950             if (!fd) {
00951                 ods_log_error("zone fetcher cannot store AXFR to file %s", axfr_file);
00952                 ldns_resolver_deep_free(xfrd);
00953                 return -1;
00954             }
00955         }
00956         assert(fd);
00957 
00958         axfr_rr = ldns_axfr_next(xfrd);
00959         if (!axfr_rr) {
00960             ods_log_error("zone fetcher AXFR for %s failed",
00961                 zone->name?zone->name:"(null)");
00962             fclose(fd);
00963             unlink(axfr_file);
00964             ldns_resolver_deep_free(xfrd);
00965             return -1;
00966         }
00967         else {
00968             while (axfr_rr) {
00969                 if (ldns_rr_get_type(axfr_rr) == LDNS_RR_TYPE_SOA) {
00970                     if (!soa_seen) {
00971                         soa_seen = 1;
00972                         ldns_rr_print(fd, axfr_rr);
00973                     }
00974                 } else {
00975                     ldns_rr_print(fd, axfr_rr);
00976                 }
00977                 ldns_rr_free(axfr_rr);
00978                 axfr_rr = ldns_axfr_next(xfrd);
00979             }
00980 
00981             /* RoRi:
00982              * We MUST now check if the AXFR was successful by verifying that
00983              * LDNS has seen the SOA record twice. Not doing this can result
00984              * in a half-transferred zone if the AXFR is interrupted.
00985              */
00986              if (!ldns_axfr_complete(xfrd)) {
00987                  /* The AXFR was not successful, we've received only a partial zone */
00988                  ods_log_error("zone fetcher AXFR for %s failed, received only a partial zone", zone->name);
00989                  fclose(fd);
00990                  unlink(axfr_file);
00991                  ldns_resolver_deep_free(xfrd);
00992                  return -1;
00993              }
00994 
00995             ods_log_info("zone fetcher transferred zone %s serial %u "
00996                 "successfully", zone->name?zone->name:"(null)", new_serial);
00997 
00998             /* Close file before moving it */
00999             fclose(fd);
01000 
01001             /* moving and kicking */
01002             snprintf(lock_file, sizeof(lock_file), "%s.lock",
01003                 zone->input_file?zone->input_file:"(null)");
01004 
01005 lock_axfr:
01006             if (access(lock_file, F_OK) == 0) {
01007                 ods_log_deeebug("zone fetcher axfr file %s is locked, "
01008                     "waiting...", dest_file);
01009                 sleep(1);
01010                 goto lock_axfr;
01011             } else {
01012                 fd = fopen(lock_file, "w");
01013                 if (!fd) {
01014                     ods_log_error("zone fetcher cannot lock AXFR file %s",
01015                         lock_file);
01016                     ldns_resolver_deep_free(xfrd);
01017                     return -1;
01018                 }
01019             }
01020             assert(fd); /* locked */
01021 
01022             snprintf(dest_file, sizeof(dest_file), "%s.axfr",
01023                 zone->input_file?zone->input_file:"(null)");
01024             if(rename(axfr_file, dest_file) == 0) {
01025                 fclose(fd);
01026                 (void) unlink(lock_file); /* unlocked */
01027 
01028                 if (kick_signer) {
01029                     snprintf(engine_sign_cmd, sizeof(engine_sign_cmd),
01030                         "%s sign %s > /dev/null 2>&1",
01031                         ODS_SE_CLI, zone->name?zone->name:"--all");
01032                     if (system(engine_sign_cmd) != 0) {
01033                         ods_log_error("zone fetcher could not kick "
01034                            "the signer engine to sign zone %s",
01035                             zone->name?zone->name:"--all");
01036                     }
01037                 }
01038             } else {
01039                 fclose(fd);
01040                 (void) unlink(lock_file); /* unlocked */
01041 
01042                 ods_log_error("zone fetcher could not move AXFR to %s",
01043                     dest_file);
01044             }
01045             ldns_resolver_deep_free(xfrd);
01046             return 0;
01047         }
01048     } else {
01049         ods_log_info("zone fetcher zone %s is already up to date, "
01050             "serial is %u", zone->name?zone->name:"(null)", serial);
01051     }
01052 
01053     ldns_resolver_deep_free(xfrd);
01054     return 0;
01055 }
01056 
01057 static void
01058 send_udp(uint8_t* buf, size_t len, void* data)
01059 {
01060     struct handle_udp_userdata *userdata = (struct handle_udp_userdata*)data;
01061     /* udp send reply */
01062     ssize_t nb;
01063     nb = sendto(userdata->udp_sock, buf, len, 0,
01064         (struct sockaddr*)&userdata->addr_him, userdata->hislen);
01065     if (nb == -1)
01066         ods_log_error("zone fetcher sendto() failed: %s", strerror(errno));
01067     else if ((size_t)nb != len)
01068         ods_log_error("zone fetcher sendto(): only sent %d of %d octets.",
01069             (int)nb, (int)len);
01070 }
01071 
01072 static void
01073 write_n_bytes(int sock, uint8_t* buf, size_t sz)
01074 {
01075     size_t count = 0;
01076     while(count < sz) {
01077         ssize_t nb = send(sock, buf+count, sz-count, 0);
01078         if(nb < 0) {
01079             ods_log_error("zone fetcher send() failed: %s",
01080                 strerror(errno));
01081             return;
01082         }
01083         count += nb;
01084     }
01085 }
01086 
01087 static void
01088 send_tcp(uint8_t* buf, size_t len, void* data)
01089 {
01090     struct handle_tcp_userdata *userdata = (struct handle_tcp_userdata*)data;
01091     uint16_t tcplen;
01092     /* tcp send reply */
01093     tcplen = htons(len);
01094     write_n_bytes(userdata->s, (uint8_t*)&tcplen, sizeof(tcplen));
01095     write_n_bytes(userdata->s, buf, len);
01096 }
01097 
01098 static void
01099 handle_query(uint8_t* inbuf, ssize_t inlen,
01100     void (*sendfunc)(uint8_t*, size_t, void*),
01101     void* userdata, config_type* config)
01102 {
01103     zfzonelist_type* zonelist = NULL;
01104     ldns_status status = LDNS_STATUS_OK;
01105     ldns_pkt *query_pkt = NULL;
01106     ldns_rr *query_rr = NULL;
01107     uint32_t serial = 0;
01108     char* owner_name = NULL;
01109     uint8_t *outbuf = NULL;
01110     size_t answer_size = 0;
01111     char dest_file[MAXPATHLEN];
01112     FILE* fd;
01113 
01114     /* packet parsing */
01115     status = ldns_wire2pkt(&query_pkt, inbuf, (size_t)inlen);
01116     if (status != LDNS_STATUS_OK) {
01117         ods_log_error("zone fetcher got bad packet: %s",
01118             ldns_get_errorstr_by_id(status));
01119         return;
01120     }
01121     query_rr = ldns_rr_list_rr(ldns_pkt_question(query_pkt), 0);
01122 
01123     if (ldns_pkt_get_opcode(query_pkt) != LDNS_PACKET_NOTIFY ||
01124         ldns_pkt_get_rcode(query_pkt)  != LDNS_RCODE_NOERROR ||
01125         ldns_pkt_qr(query_pkt) ||
01126         !ldns_pkt_aa(query_pkt) ||
01127         ldns_pkt_tc(query_pkt) ||
01128         ldns_pkt_rd(query_pkt) ||
01129         ldns_pkt_ra(query_pkt) ||
01130         ldns_pkt_cd(query_pkt) ||
01131         ldns_pkt_ad(query_pkt) ||
01132         ldns_pkt_qdcount(query_pkt) != 1 ||
01133         ldns_pkt_nscount(query_pkt) != 0 ||
01134         ldns_pkt_arcount(query_pkt) != 0 ||
01135         ldns_rr_get_type(query_rr) != LDNS_RR_TYPE_SOA ||
01136         ldns_rr_get_class(query_rr) != LDNS_RR_CLASS_IN)
01137     {
01138         ods_log_info("zone fetcher drop bad notify");
01139         return;
01140     }
01141 
01142     /* NOTIFY OK */
01143     if (config) {
01144         zonelist = config->zonelist;
01145     }
01146     ldns_pkt_set_qr(query_pkt, 1);
01147     status = ldns_pkt2wire(&outbuf, query_pkt, &answer_size);
01148     if (status != LDNS_STATUS_OK) {
01149         ods_log_error("zone fetcher error creating notify response: %s",
01150             ldns_get_errorstr_by_id(status));
01151     }
01152     sendfunc(outbuf, answer_size, userdata);
01153     LDNS_FREE(outbuf);
01154 
01155     /* send AXFR request */
01156     while (zonelist) {
01157         if (ldns_dname_compare(ldns_rr_owner(query_rr), zonelist->dname) == 0)
01158         {
01159             ods_log_info("zone fetcher received NOTIFY for zone %s",
01160                 zonelist->name?zonelist->name:"(null)");
01161             /* get latest serial */
01162             snprintf(dest_file, sizeof(dest_file), "%s.axfr",
01163                 zonelist->input_file?zonelist->input_file:"(null)");
01164             fd = fopen(dest_file, "r");
01165             if (!fd) {
01166                 serial = 0;
01167             } else {
01168                 serial = lookup_serial(fd);
01169                 fclose(fd);
01170             }
01171             if (odd_xfer(zonelist, serial, config, 1) != 0) {
01172                 ods_log_error("AXFR for zone %s failed",
01173                     zonelist->name?zonelist->name:"(null)");
01174             }
01175             ldns_pkt_free(query_pkt);
01176             return;
01177         }
01178         /* next */
01179         zonelist = zonelist->next;
01180     }
01181     owner_name = ldns_rdf2str(ldns_rr_owner(query_rr));
01182     ods_log_warning("zone fetcher notify received for unknown zone: %s",
01183         owner_name?owner_name:"(null)");
01184     free((void*)owner_name);
01185     ldns_pkt_free(query_pkt);
01186 }
01187 
01188 static void
01189 read_n_bytes(int sock, uint8_t* buf, size_t sz)
01190 {
01191     size_t count = 0;
01192     while(count < sz) {
01193         ssize_t nb = recv(sock, buf+count, sz-count, 0);
01194         if(nb < 0) {
01195             ods_log_error("zone fetcher recv() failed: %s",
01196                 strerror(errno));
01197             return;
01198         }
01199         count += nb;
01200     }
01201 }
01202 
01203 static char*
01204 addr2ip(struct sockaddr_storage addr, char* remote, size_t len)
01205 {
01206     if (addr.ss_family == AF_INET6) {
01207         if (!inet_ntop(AF_INET6, &((struct sockaddr_in6 *)&addr)->sin6_addr,
01208             remote, len)) {
01209             return NULL;
01210         }
01211     } else {
01212         if (!inet_ntop(AF_INET, &((struct sockaddr_in *)&addr)->sin_addr,
01213             remote, len))
01214             return NULL;
01215     }
01216 
01217     return remote;
01218 }
01219 
01220 static int
01221 acl_matches(struct sockaddr_storage* addr, config_type* config)
01222 {
01223     serverlist_type* serverlist = NULL;
01224 
01225     if (config && config->serverlist) {
01226         serverlist = config->serverlist;
01227         while (serverlist) {
01228             if (serverlist->family == AF_INET6) {
01229                 struct sockaddr_in6* addr6 = (struct sockaddr_in6*)addr;
01230                 if (serverlist->family == addr->ss_family &&
01231                     memcmp(&addr6->sin6_addr, &serverlist->addr.addr6,
01232                      sizeof(struct in6_addr)) == 0)
01233                 {
01234                     return 1;
01235                 }
01236             }
01237            else {
01238                 struct sockaddr_in* addr4 = (struct sockaddr_in*)addr;
01239                 if (serverlist->family == addr4->sin_family &&
01240                     memcmp(&addr4->sin_addr, &serverlist->addr.addr,
01241                      sizeof(struct in_addr)) == 0)
01242                 {
01243                     return 1;
01244                 }
01245             }
01246 
01247             serverlist = serverlist->next;
01248         }
01249     }
01250     return 0;
01251 }
01252 
01253 static void
01254 handle_udp(int udp_sock, config_type* config)
01255 {
01256     ssize_t nb;
01257     uint8_t inbuf[INBUF_SIZE];
01258     struct handle_udp_userdata userdata;
01259     char* remote;
01260 
01261     userdata.udp_sock = udp_sock;
01262     userdata.hislen = (socklen_t) sizeof(userdata.addr_him);
01263     nb = recvfrom(udp_sock, inbuf, INBUF_SIZE, 0,
01264         (struct sockaddr*) &userdata.addr_him, &userdata.hislen);
01265     if (nb < 1) {
01266         ods_log_error("zone fetcher recvfrom() failed: %s",
01267             strerror(errno));
01268         return;
01269     }
01270 
01271     /* acl */
01272     if (!acl_matches(&userdata.addr_him, config)) {
01273         remote = (char*) malloc(sizeof(char)*userdata.hislen);
01274         ods_log_warning("zone fetcher refused message from "
01275             "unauthoritative source: %s",
01276             addr2ip(userdata.addr_him, remote, userdata.hislen));
01277         free((void*)remote);
01278         return;
01279     }
01280     handle_query(inbuf, nb, send_udp, &userdata, config);
01281 }
01282 
01283 static void
01284 handle_tcp(int tcp_sock, config_type* config)
01285 {
01286     int s;
01287     struct sockaddr_storage addr_him;
01288     socklen_t hislen;
01289     uint8_t inbuf[INBUF_SIZE];
01290     uint16_t tcplen;
01291     struct handle_tcp_userdata userdata;
01292     char* remote;
01293 
01294     /* accept */
01295     hislen = (socklen_t)sizeof(addr_him);
01296     if((s = accept(tcp_sock, (struct sockaddr*)&addr_him, &hislen)) < 0) {
01297         ods_log_error("zone fetcher accept() failed: %s", strerror(errno));
01298         return;
01299     }
01300     userdata.s = s;
01301 
01302     /* tcp recv */
01303     read_n_bytes(s, (uint8_t*)&tcplen, sizeof(tcplen));
01304     tcplen = ntohs(tcplen);
01305     if(tcplen >= INBUF_SIZE) {
01306         ods_log_error("zone fetcher query %d bytes too large, "
01307             "buffer %d bytes.", tcplen, INBUF_SIZE);
01308         close(s);
01309         return;
01310     }
01311     read_n_bytes(s, inbuf, tcplen);
01312 
01313     /* acl */
01314     if (!acl_matches(&addr_him, config)) {
01315         remote = (char*) malloc(sizeof(char)*hislen);
01316         ods_log_warning("zone fetcher refused message from "
01317             "unauthoritative source: %s",
01318             addr2ip(addr_him, remote, hislen));
01319         free((void*)remote);
01320         close(s);
01321         return;
01322     }
01323     handle_query(inbuf, (ssize_t) tcplen, send_tcp, &userdata, config);
01324     close(s);
01325 }
01326 
01327 
01332 static void
01333 reload_zonelist(config_type *config) {
01334     zfzonelist_type *new_zonelist, **thisp;
01335     zfzonelist_type *added_zonelist = NULL, *kept_zonelist = NULL;
01336     int added_count = 0, changed_count = 0, kept_count = 0;
01337     /* Fail softly if the zonelist cannot be accessed for reloading */
01338     if (!config->zonelist_file) {
01339             ods_log_error("zone fetcher is unable to access the zonelist");
01340             return;
01341     } else {
01342             ods_log_verbose("zone fetcher will reload the zonelist");
01343     }
01344     /* Read the zonelist file and construct a new linked list of zonelist entries */
01345     new_zonelist = read_zonelist (config->zonelist_file);
01346     /* Iterate over the new zonelist file and compare it to previously configured zonelist entries */
01347     while (new_zonelist) {
01348             zfzonelist_type *next_zonelist = new_zonelist->next;
01349             zfzonelist_type *this = config->zonelist;
01350             int found = 0;
01351             while (this && !found) {
01352                 found = !strcmp (this->name, new_zonelist->name);
01353                 if (!found) {
01354                         this = this->next;
01355             }
01356         }
01357 
01358         /* If the zone name is found in the old zonelist, it is either a full match or a replacement */
01359             if (found) {
01360                 if (strcmp (new_zonelist->input_file, this->input_file)) {
01361                     /* the zonelist entry has changed -- treat as a replacement/new zonelist entry */
01362                     changed_count++;
01363                     new_zonelist->next = added_zonelist;
01364                     added_zonelist = new_zonelist;
01365             } else {
01366                 /* the zonelist entry is already configured -- treat as a kept zonelist entry */
01367                     kept_count++;
01368                     new_zonelist->next = kept_zonelist;
01369                     kept_zonelist = new_zonelist;
01370                 }
01371             } else {
01372                 /* new_zonelist introduces a new zonelist entry */
01373                 added_count++;
01374                 new_zonelist->next = added_zonelist;
01375                 added_zonelist = new_zonelist;
01376         }
01377             new_zonelist = next_zonelist;
01378     }
01379 
01380     /* Replace the configured zonelist with the added_zonelist and kept_zonelist */
01381     free_zonelist (config->zonelist);
01382     config->zonelist = kept_zonelist;
01383     thisp = &config->zonelist;
01384     while (*thisp) {
01385         thisp = &(*thisp)->next;
01386     }
01387     *thisp = added_zonelist;
01388 
01389     /* Perform an initial AXFR for the newly added zones (assume no present inputfile) */
01390     new_zonelist = added_zonelist;
01391     while (new_zonelist) {
01392         /* send the request -- assume no file is present so SOA is 0 */
01393             if (odd_xfer (new_zonelist, 0, config, 1) != 0) {
01394                 ods_log_error("AXFR for new zone %s failed", new_zonelist->name);
01395             }
01396             /* next */
01397             new_zonelist = new_zonelist->next;
01398     }
01399     ods_log_verbose("Reloaded zonelist -- kept %d, changed %d and added %d zones",
01400                 kept_count, changed_count, added_count);
01401     return;
01402 }
01403 
01404 
01405 static void
01406 xfrd_ns(sockets_type* sockets, config_type* cfg)
01407 {
01408     fd_set rset, wset, eset;
01409     struct timeval timeout;
01410     int count, maxfd = 0;
01411     size_t i;
01412 
01413     /* service */
01414     count = 0;
01415     timeout.tv_sec = 0;
01416     timeout.tv_usec = 0;
01417     while (!sig_quit) {
01418         if (sig_reload) {
01419             reload_zonelist(cfg);
01420             sig_reload = 0;
01421         }
01422         FD_ZERO(&rset);
01423         FD_ZERO(&wset);
01424         FD_ZERO(&eset);
01425         for (i=0; i < MAX_INTERFACES; i++) {
01426             if (sockets->udp[i].s != -1)
01427                 FD_SET(sockets->udp[i].s, &rset);
01428             if (sockets->tcp[i].s != -1)
01429                 FD_SET(sockets->tcp[i].s, &rset);
01430             if (sockets->udp[i].s > maxfd) maxfd = sockets->udp[i].s;
01431             if (sockets->tcp[i].s > maxfd) maxfd = sockets->tcp[i].s;
01432         }
01433 
01434         if (select(maxfd+1, &rset, &wset, &eset, NULL) < 0) {
01435             if (errno == EINTR)
01436                 continue;
01437             ods_log_error("zone fetcher select(): %s", strerror(errno));
01438         }
01439 
01440         for (i=0; i < MAX_INTERFACES; i++) {
01441             if (sockets->udp[i].s != -1 && FD_ISSET(sockets->udp[i].s, &rset))
01442                 handle_udp(sockets->udp[i].s, cfg);
01443             if (sockets->tcp[i].s != -1 && FD_ISSET(sockets->tcp[i].s, &rset))
01444                 handle_tcp(sockets->tcp[i].s, cfg);
01445         }
01446     }
01447 }
01448 
01449 static void
01450 list_settings(FILE* out, config_type* config, const char* filename)
01451 {
01452     zfzonelist_type* zones = NULL;
01453     serverlist_type* servers = NULL;
01454 
01455     if (config) {
01456         fprintf(out, "configuration settings:\n");
01457         fprintf(out, "filename: %s\n", filename?filename:"(null)");
01458         fprintf(out, "pidfile: %s\n",
01459             config->pidfile?config->pidfile:"(null)");
01460         fprintf(out, "tsig: %s\n", config->use_tsig?"yes":"no");
01461         if (config->use_tsig) {
01462             fprintf(out, "tsig name: %s\n",
01463                 config->tsig_name?config->tsig_name:"(null)");
01464             fprintf(out, "tsig algorithm: %s\n",
01465                 config->tsig_algo?config->tsig_algo:"(null)");
01466             fprintf(out, "tsig secret: ?\n");
01467         }
01468         fprintf(out, "zones: %s\n", config->zonelist?"":"none");
01469         zones = config->zonelist;
01470         while (zones) {
01471             fprintf(out, "\t%s\n", zones->name?zones->name:"(null)");
01472             zones = zones->next;
01473         }
01474         fprintf(out, "master servers: %s\n", config->serverlist?"":"none");
01475         servers = config->serverlist;
01476         while (servers) {
01477             fprintf(out, "\t%s\n", servers->ipaddr?servers->ipaddr:"(null)");
01478             servers = servers->next;
01479         }
01480         fprintf(out, "interfaces: %s\n", config->notifylist?"":"none");
01481         servers = config->notifylist;
01482         while (servers) {
01483             fprintf(out, "\t%s %s:%s\n",
01484                 servers->family==AF_INET6?"ipv6":"ipv4",
01485                 servers->ipaddr?servers->ipaddr:"(null)",
01486                 servers->port?servers->port:"(null)");
01487             servers = servers->next;
01488         }
01489         fprintf(out, "list zone fetcher settings done.\n");
01490     }
01491     else fprintf(out, "no config\n");
01492 }
01493 
01494 int
01495 tools_zone_fetcher(const char* config_file, const char* zonelist_file,
01496     const char* group, const char* user, const char* chroot, const char* log_file,
01497     int use_syslog, int verbosity)
01498 {
01499     zfzonelist_type *zonelist = NULL;
01500     config_type* config = NULL;
01501     uint32_t serial = 0;
01502     FILE* fd;
01503     sockets_type sockets;
01504     int c, info = 0;
01505     int error = 0;
01506     struct sigaction action;
01507     uid_t uid = -1;
01508     gid_t gid = -1;
01509 
01510     ods_log_init(log_file, use_syslog, verbosity);
01511 
01512     /* read transfer configuration */
01513     config = new_config();
01514     config->pidfile = strdup(ODS_ZF_PIDFILE); /* not freed */
01515     if (!config->pidfile) {
01516         ods_log_alert("zone fetcher error: no pidfile given");
01517         free_config(config);
01518         exit(EXIT_FAILURE);
01519     }
01520 
01521     c = read_axfr_config(config_file, config);
01522     config->zonelist = read_zonelist(zonelist_file);
01523     config->zonelist_file = strdup(zonelist_file);
01524 
01525     if (info) {
01526         list_settings(stdout, config, config_file);
01527     }
01528 
01529     if (config->serverlist == NULL) {
01530         ods_log_alert("zone fetcher error: no master servers configured "
01531             "with <RequestTransfer>");
01532         free_config(config);
01533         exit(EXIT_FAILURE);
01534     }
01535 
01536     /* setup signal handing */
01537     action.sa_handler = sig_handler;
01538     sigfillset(&action.sa_mask);
01539     action.sa_flags = 0;
01540     sigaction(SIGHUP, &action, NULL);
01541     sigaction(SIGTERM, &action, NULL);
01542 
01543     /* write pidfile */
01544     if (writepid(config->pidfile, getpid()) != 0) {
01545         ods_log_error("write pidfile %s failed", config->pidfile);
01546         ods_log_info("zone fetcher exiting...");
01547         exit(EXIT_FAILURE);
01548     }
01549 
01550     ods_log_info("zone fetcher started");
01551 
01552     /* foreach zone, do a single axfr request */
01553     zonelist = config->zonelist;
01554     while (zonelist != NULL) {
01555         /* get latest serial */
01556         fd = fopen(zonelist->input_file, "r");
01557         if (!fd) {
01558             serial = 0;
01559         } else {
01560             serial = lookup_serial(fd);
01561             fclose(fd);
01562         }
01563         /* send the request */
01564         if (odd_xfer(zonelist, serial, config, 1) != 0) {
01565             ods_log_error("AXFR for zone %s failed",
01566                 zonelist->name?zonelist->name:"(null)");
01567         }
01568         /* next */
01569         zonelist = zonelist->next;
01570     }
01571 
01572     /* listen to NOTIFY messages */
01573     c = init_sockets(&sockets, config->notifylist);
01574     if (c == -1) {
01575         ods_log_error("zone fetcher failed to initialize sockets");
01576         if (unlink(config->pidfile) == -1) {
01577             ods_log_error("unlink pidfile %s failed: %s",
01578                 config->pidfile?config->pidfile:"(null)",
01579                 strerror(errno));
01580         }
01581         ods_log_info("zone fetcher exiting...");
01582         exit(EXIT_FAILURE);
01583     }
01584 
01585     /* drop privileges */
01586     error = privdrop(user, group, chroot, &uid, &gid);
01587     privclose(user, group);
01588     if (error != 0) {
01589         ods_log_error("zone fetcher failed to drop privileges");
01590         if (unlink(config->pidfile) == -1) {
01591             ods_log_error("unlink pidfile %s failed: %s",
01592                 config->pidfile?config->pidfile:"(null)",
01593                 strerror(errno));
01594         }
01595         free_sockets(&sockets);
01596         ods_log_info("zone fetcher exiting...");
01597         exit(EXIT_FAILURE);
01598     }
01599 
01600     xfrd_ns(&sockets, config);
01601 
01602     if (unlink(config->pidfile) == -1) {
01603         ods_log_warning("unlink pidfile %s failed: %s",
01604             config->pidfile?config->pidfile:"(null)",
01605             strerror(errno));
01606     }
01607     free_sockets(&sockets);
01608 
01609     /* done */
01610     ods_log_debug("zone fetcher done");
01611     free_config(config);
01612     ods_log_close();
01613     return 0;
01614 }

Generated on Sun Dec 18 2011 10:32:16 for OpenDNSSEC-signer by  doxygen 1.7.1