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