+17 July 2007: Wouter
+ - forward zone options in config file.
+ - forward per zone in iterator. takes precendence over stubs.
+
27 June 2007: Wouter
- delete of mesh does a postorder traverse of the tree.
- found and fixed a memory leak. For TTL=0 messages, that would
# Stub zones.
# Create entries like below, to make all queries for 'example.com' and
-# subdomains go to the given list of nameservers. list zero or more
+# 'example.org' go to the given list of nameservers. list zero or more
# nameservers by hostname or by ipaddress.
# stub-zone:
# name: "example.com"
# name: "example.org"
# stub-host: ns.example.com.
+# Forward zones
+# Create entries like below, to make all queries for 'example.com' and
+# 'example.org' go to the given list of servers. These servers have to handle
+# recursion to other nameservers. List zero or more nameservers by hostname
+# or by ipaddress. Use an entry with name "." to forward all queries.
+# forward-zone:
+# name: "example.com"
+# forward-addr: 192.0.2.68
+# forward-zone:
+# name: "example.org"
+# forward-host: fwd.example.com
.It \fBname:\fR <domain name>
Name of the stub zone.
.It \fBstub-host:\fR <domain name>
-Name of stub zone nameserver. Will need to be resolved before it can be used.
+Name of stub zone nameserver. Is itself resolved before it is used.
.It \fBstub-addr:\fR <IP address>
IP address of stub zone nameserver. Can be IP 4 or IP 6.
.El
+.Ss Forward Zone Options
+There may be multiple
+.Ic forward-zone:
+clauses. Each with a name: and zero or more hostnames or IP addresses.
+For the forward zone this list of nameservers is used to forward the queries
+to. The servers have to handle further recursion for the query. Class IN is
+assumed. A forward-zone entry with name "." and a forward-addr target will
+forward all queries to that other server (unless it can answer from the cache).
+.Bl -tag -width indent
+.It \fBname:\fR <domain name>
+Name of the forward zone.
+.It \fBforward-host:\fR <domain name>
+Name of server to forward to. Is itself resolved before it is used.
+.It \fBforward-addr:\fR <IP address>
+IP address of server to forward to. Can be IP 4 or IP 6.
+.El
+
.Sh FILES
.Bl -tag -width indent
.It Pa unbound.conf
--- /dev/null
+/*
+ * iterator/iter_fwd.c - iterative resolver module forward zones.
+ *
+ * Copyright (c) 2007, NLnet Labs. All rights reserved.
+ *
+ * This software is open source.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of the NLNET LABS nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * \file
+ *
+ * This file contains functions to assist the iterator module.
+ * Keep track of forward zones and config settings.
+ */
+#include "config.h"
+#include "iterator/iter_fwd.h"
+#include "iterator/iter_delegpt.h"
+#include "util/region-allocator.h"
+#include "util/log.h"
+#include "util/config_file.h"
+#include "util/net_help.h"
+#include "util/data/dname.h"
+
+/** compare two fwd entries */
+static int
+fwd_cmp(const void* k1, const void* k2)
+{
+ int m;
+ struct iter_forward_zone* n1 = (struct iter_forward_zone*)k1;
+ struct iter_forward_zone* n2 = (struct iter_forward_zone*)k2;
+ if(n1->dclass != n2->dclass) {
+ if(n1->dclass < n2->dclass)
+ return -1;
+ return 1;
+ }
+ return dname_lab_cmp(n1->name, n1->namelabs, n2->name, n2->namelabs,
+ &m);
+}
+
+struct iter_forwards*
+forwards_create()
+{
+ struct iter_forwards* fwd = (struct iter_forwards*)calloc(1,
+ sizeof(struct iter_forwards));
+ if(!fwd)
+ return NULL;
+ fwd->region = region_create(malloc, free);
+ if(!fwd->region) {
+ forwards_delete(fwd);
+ return NULL;
+ }
+ return fwd;
+}
+
+void
+forwards_delete(struct iter_forwards* fwd)
+{
+ if(!fwd)
+ return;
+ region_destroy(fwd->region);
+ free(fwd->tree);
+ free(fwd);
+}
+
+/** insert new info into forward structure */
+static int
+forwards_insert(struct iter_forwards* fwd, uint16_t c, struct delegpt* dp)
+{
+ struct iter_forward_zone* node = region_alloc(fwd->region,
+ sizeof(struct iter_forward_zone));
+ if(!node)
+ return 0;
+ node->node.key = node;
+ node->dclass = c;
+ node->name = region_alloc_init(fwd->region, dp->name, dp->namelen);
+ if(!node->name)
+ return 0;
+ node->namelen = dp->namelen;
+ node->namelabs = dp->namelabs;
+ node->dp = dp;
+ if(!rbtree_insert(fwd->tree, &node->node)) {
+ log_err("duplicate forward zone ignored.");
+ }
+ return 1;
+}
+
+/** initialise parent pointers in the tree */
+static void
+fwd_init_parents(struct iter_forwards* fwd)
+{
+ struct iter_forward_zone* node, *prev = NULL, *p;
+ int m;
+ RBTREE_FOR(node, struct iter_forward_zone*, fwd->tree) {
+ node->parent = NULL;
+ if(!prev || prev->dclass != node->dclass) {
+ prev = node;
+ continue;
+ }
+ (void)dname_lab_cmp(prev->name, prev->namelabs, node->name,
+ node->namelabs, &m); /* we know prev is smaller */
+ /* sort order like: . com. bla.com. zwb.com. net. */
+ /* find the previous, or parent-parent-parent */
+ for(p = prev; p; p = p->parent)
+ /* looking for name with few labels, a parent */
+ if(p->namelabs <= m) {
+ /* ==: since prev matched m, this is closest*/
+ /* <: prev matches more, but is not a parent,
+ * this one is a (grand)parent */
+ node->parent = p;
+ break;
+ }
+ prev = node;
+ }
+}
+
+/** set zone name */
+static int
+read_fwds_name(struct iter_forwards* fwd, struct config_stub* s,
+ struct delegpt* dp)
+{
+ ldns_rdf* rdf;
+ if(!s->name) {
+ log_err("forward zone without a name (use name \".\" to forward everything)");
+ return 0;
+ }
+ rdf = ldns_dname_new_frm_str(s->name);
+ if(!rdf) {
+ log_err("cannot parse forward zone name %s", s->name);
+ return 0;
+ }
+ if(!delegpt_set_name(dp, fwd->region, ldns_rdf_data(rdf))) {
+ ldns_rdf_deep_free(rdf);
+ log_err("out of memory");
+ return 0;
+ }
+ ldns_rdf_deep_free(rdf);
+ return 1;
+}
+
+/** set fwd host names */
+static int
+read_fwds_host(struct iter_forwards* fwd, struct config_stub* s,
+ struct delegpt* dp)
+{
+ struct config_strlist* p;
+ ldns_rdf* rdf;
+ for(p = s->hosts; p; p = p->next) {
+ log_assert(p->str);
+ rdf = ldns_dname_new_frm_str(p->str);
+ if(!rdf) {
+ log_err("cannot parse forward %s server name: '%s'",
+ s->name, p->str);
+ return 0;
+ }
+ if(!delegpt_add_ns(dp, fwd->region, ldns_rdf_data(rdf))) {
+ ldns_rdf_deep_free(rdf);
+ log_err("out of memory");
+ return 0;
+ }
+ ldns_rdf_deep_free(rdf);
+ }
+ return 1;
+}
+
+/** set fwd server addresses */
+static int
+read_fwds_addr(struct iter_forwards* fwd, struct config_stub* s,
+ struct delegpt* dp)
+{
+ struct config_strlist* p;
+ struct sockaddr_storage addr;
+ socklen_t addrlen;
+ for(p = s->addrs; p; p = p->next) {
+ log_assert(p->str);
+ if(!ipstrtoaddr(p->str, UNBOUND_DNS_PORT, &addr, &addrlen)) {
+ log_err("cannot parse forward %s ip address: '%s'",
+ s->name, p->str);
+ return 0;
+ }
+ if(!delegpt_add_addr(dp, fwd->region, &addr, addrlen)) {
+ log_err("out of memory");
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/** read forwards config */
+static int
+read_forwards(struct iter_forwards* fwd, struct config_file* cfg)
+{
+ struct config_stub* s;
+ for(s = cfg->forwards; s; s = s->next) {
+ struct delegpt* dp = delegpt_create(fwd->region);
+ if(!dp) {
+ log_err("out of memory");
+ return 0;
+ }
+ if(!read_fwds_name(fwd, s, dp) ||
+ !read_fwds_host(fwd, s, dp) ||
+ !read_fwds_addr(fwd, s, dp))
+ return 0;
+ if(!forwards_insert(fwd, LDNS_RR_CLASS_IN, dp))
+ return 0;
+ log_info("Forward zone server list:");
+ delegpt_log(dp);
+ }
+ return 1;
+}
+
+int
+forwards_apply_cfg(struct iter_forwards* fwd, struct config_file* cfg)
+{
+ free(fwd->tree);
+ fwd->tree = rbtree_create(fwd_cmp);
+ if(!fwd->tree)
+ return 0;
+
+ /* read forward zones */
+ if(!read_forwards(fwd, cfg))
+ return 0;
+ fwd_init_parents(fwd);
+ return 1;
+}
+
+struct delegpt*
+forwards_lookup(struct iter_forwards* fwd, uint8_t* qname, uint16_t qclass)
+{
+ /* lookup the forward zone in the tree */
+ rbnode_t* res = NULL;
+ struct iter_forward_zone *result;
+ struct iter_forward_zone key;
+ key.node.key = &key;
+ key.dclass = qclass;
+ key.name = qname;
+ key.namelabs = dname_count_size_labels(qname, &key.namelen);
+ if(rbtree_find_less_equal(fwd->tree, &key, &res)) {
+ /* exact */
+ result = (struct iter_forward_zone*)res;
+ } else {
+ /* smaller element (or no element) */
+ int m;
+ result = (struct iter_forward_zone*)res;
+ if(!result || result->dclass != qclass)
+ return NULL;
+ /* count number of labels matched */
+ (void)dname_lab_cmp(result->name, result->namelabs, key.name,
+ key.namelabs, &m);
+ while(result) { /* go up until qname is subdomain of stub */
+ if(result->namelabs <= m)
+ break;
+ result = result->parent;
+ }
+ }
+ if(result)
+ return result->dp;
+ return NULL;
+}
--- /dev/null
+/*
+ * iterator/iter_fwd.h - iterative resolver module forward zones.
+ *
+ * Copyright (c) 2007, NLnet Labs. All rights reserved.
+ *
+ * This software is open source.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of the NLNET LABS nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * \file
+ *
+ * This file contains functions to assist the iterator module.
+ * Keep track of forward zones, and read those from config.
+ */
+
+#ifndef ITERATOR_ITER_FWD_H
+#define ITERATOR_ITER_FWD_H
+#include "util/rbtree.h"
+struct iter_env;
+struct config_file;
+struct delegpt;
+struct region;
+
+/**
+ * Iterator forward zones structure
+ */
+struct iter_forwards {
+ /** region where forward zone server addresses are allocated */
+ struct region* region;
+ /**
+ * Zones are stored in this tree. Sort order is specially chosen.
+ * first sorted on qtype. Then on dname in nsec-like order, so that
+ * a lookup on class, name will return an exact match or the closest
+ * match which gives the ancestor needed.
+ * contents of type iter_forward_zone.
+ */
+ rbtree_t* tree;
+};
+
+/**
+ * Iterator forward servers for a particular zone.
+ */
+struct iter_forward_zone {
+ /** redblacktree node, key is this structure: class and name */
+ rbnode_t node;
+ /** name */
+ uint8_t* name;
+ /** length of name */
+ size_t namelen;
+ /** number of labels in name */
+ int namelabs;
+ /** delegation point with forward server information for this zone. */
+ struct delegpt* dp;
+ /** pointer to parent in tree (or NULL if none) */
+ struct iter_forward_zone* parent;
+ /** class. host order. */
+ uint16_t dclass;
+};
+
+/**
+ * Create forwards
+ * @return new forwards or NULL on error.
+ */
+struct iter_forwards* forwards_create();
+
+/**
+ * Delete forwards.
+ * @param fwd: to delete.
+ */
+void forwards_delete(struct iter_forwards* fwd);
+
+/**
+ * Process forwards config.
+ * @param fwd: where to store.
+ * @param cfg: config options.
+ * @return 0 on error.
+ */
+int forwards_apply_cfg(struct iter_forwards* fwd, struct config_file* cfg);
+
+/**
+ * Find a forward zone information
+ * For this qname/qclass find forward zone information, returns delegation
+ * point with server names and addresses, or NULL if no forwarding is needed.
+ *
+ * @param fwd: forward storage.
+ * @param qname: The qname of the query.
+ * @param qclass: The qclass of the query.
+ * @return: A delegation point if the query has to be forwarded to that list,
+ * otherwise null.
+ */
+struct delegpt* forwards_lookup(struct iter_forwards* fwd,
+ uint8_t* qname, uint16_t qclass);
+
+#endif /* ITERATOR_ITER_FWD_H */
#include "iterator/iter_utils.h"
#include "iterator/iterator.h"
#include "iterator/iter_hints.h"
+#include "iterator/iter_fwd.h"
#include "iterator/iter_delegpt.h"
#include "services/cache/infra.h"
#include "services/cache/dns.h"
log_err("Could not set root or stub hints");
return 0;
}
+ if(!iter_env->fwds)
+ iter_env->fwds = forwards_create();
+ if(!iter_env->fwds || !forwards_apply_cfg(iter_env->fwds, cfg)) {
+ log_err("Could not set forward zones");
+ return 0;
+ }
iter_env->supports_ipv6 = cfg->do_ip6;
/* forwarder address */
#include "iterator/iterator.h"
#include "iterator/iter_utils.h"
#include "iterator/iter_hints.h"
+#include "iterator/iter_fwd.h"
#include "iterator/iter_delegpt.h"
#include "iterator/iter_resptype.h"
#include "iterator/iter_scrub.h"
iter_env = (struct iter_env*)env->modinfo[id];
free(iter_env->target_fetch_policy);
hints_delete(iter_env->hints);
+ forwards_delete(iter_env->fwds);
if(iter_env)
free(iter_env);
}
return 1;
}
+/**
+ * See if the query needs forwarding.
+ *
+ * @param qstate: query state.
+ * @param iq: iterator query state.
+ * @param ie: iterator shared global environment.
+ * @return true if the request is forwarded, false if not.
+ * If returns true but, iq->dp is NULL then a malloc failure occurred.
+ */
+static int
+forward_request(struct module_qstate* qstate, struct iter_qstate* iq,
+ struct iter_env* ie)
+{
+ struct delegpt* dp = forwards_lookup(ie->fwds, iq->qchase.qname,
+ iq->qchase.qclass);
+ if(!dp)
+ return 0;
+ /* send recursion desired to forward addr */
+ iq->chase_flags |= BIT_RD;
+ iq->dp = delegpt_copy(dp, qstate->region);
+ /* iq->dp checked by caller */
+ verbose(VERB_ALGO, "forwarding request");
+ return 1;
+}
+
/**
* Process the initial part of the request handling. This state roughly
* corresponds to resolver algorithms steps 1 (find answer in cache) and 2
return final_state(iq);
}
- /* TODO attempt to forward the request */
- /* if (forwardRequest(event, state, req))
- {
- // the request has been forwarded.
- // forwarded requests need to be immediately sent to the
- // next state, QUERYTARGETS.
- return nextState(event, req, state,
- IterEventState.QUERYTARGETS_STATE);
- }
- */
-
- /* TODO attempt to find a covering DNAME in the cache */
- /* resp = mDNSCache.findDNAME(req.getQName(), req.getQType(), req
- .getQClass());
- if (resp != null)
+ /* attempt to forward the request */
+ if(forward_request(qstate, iq, ie))
{
-log.trace("returning synthesized CNAME response from cache: " + resp);
-Name cname = handleCNAMEResponse(state, req, resp);
-// At this point, we just initiate the query restart.
-// This might not be a query restart situation (e.g., qtype == CNAME),
-// but
-// the answer returned from findDNAME() is likely to be one that we
-// don't want to return.
-// Thus we allow the cache and other resolution mojo kick in regardless.
-req.setQName(cname);
-state.queryRestartCount++;
-return nextState(event, req, state, IterEventState.INIT_REQUEST_STATE);
-}
- */
+ if(!iq->dp) {
+ log_err("alloc failure for forward dp");
+ return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
+ }
+ /* the request has been forwarded.
+ * forwarded requests need to be immediately sent to the
+ * next state, QUERYTARGETS. */
+ return next_state(iq, QUERYTARGETS_STATE);
+ }
/* Resolver Algorithm Step 2 -- find the "best" servers. */
* they will not be show up again. */
if(tf_policy != 0) {
int extra = 0;
- verbose(VERB_ALGO, "query for extra %d targets", tf_policy);
+ verbose(VERB_ALGO, "attempt to get extra %d targets",
+ tf_policy);
if(!query_for_targets(qstate, iq, ie, id, tf_policy, &extra)) {
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
}
return next_state(iq, QUERYTARGETS_STATE);
}
type = response_type_from_server(iq->response, &iq->qchase, iq->dp);
+ if(type == RESPONSE_TYPE_REFERRAL && (iq->chase_flags&BIT_RD)) {
+ /* When forwarding (RD bit is set), we handle referrals
+ * differently. No queries should be sent elsewhere */
+ type = RESPONSE_TYPE_ANSWER;
+ }
+
+ /* handle each of the type cases */
if(type == RESPONSE_TYPE_ANSWER) {
/* ANSWER type responses terminate the query algorithm,
* so they sent on their */
struct module_func_block;
struct delegpt;
struct iter_hints;
+struct iter_forwards;
struct iter_prep_list;
/** max number of query restarts. Determines max number of CNAME chain. */
int supports_ipv6;
/** Mapping of forwarding zones to targets. */
- /* struct fwds fwd_map TODO */
+ struct iter_forwards* fwds;
/** A set of inetaddrs that should never be queried. */
/* struct bla donotquery_addrs TODO */
cfg->num_ifs = 0;
cfg->ifs = NULL;
cfg->stubs = NULL;
+ cfg->forwards = NULL;
cfg->harden_short_bufsize = 0;
cfg->harden_large_queries = 0;
return cfg;
}
}
+/** delete config stublist */
+static void
+config_delstubs(struct config_stub* p)
+{
+ struct config_stub* np;
+ while(p) {
+ np = p->next;
+ free(p->name);
+ config_delstrlist(p->hosts);
+ config_delstrlist(p->addrs);
+ free(p);
+ p = np;
+ }
+}
+
void
config_delete(struct config_file* cfg)
{
free(cfg->ifs[i]);
free(cfg->ifs);
}
- if(cfg->stubs) {
- struct config_stub* p = cfg->stubs, *np;
- while(p) {
- np = p->next;
- free(p->name);
- config_delstrlist(p->hosts);
- config_delstrlist(p->addrs);
- free(p);
- p = np;
- }
- }
+ config_delstubs(cfg->stubs);
+ config_delstubs(cfg->forwards);
free(cfg);
}
/** the stub definitions, linked list */
struct config_stub* stubs;
+ /** the forward definitions, linked list */
+ struct config_stub* forwards;
/** harden against very small edns buffer sizes */
int harden_short_bufsize;
name{COLON} { YDOUT; return VAR_NAME;}
stub-addr{COLON} { YDOUT; return VAR_STUB_ADDR;}
stub-host{COLON} { YDOUT; return VAR_STUB_HOST;}
+forward-zone{COLON} { YDOUT; return VAR_FORWARD_ZONE;}
+forward-addr{COLON} { YDOUT; return VAR_FORWARD_ADDR;}
+forward-host{COLON} { YDOUT; return VAR_FORWARD_HOST;}
{NEWLINE} { LEXOUT(("NL\n")); cfg_parser->line++;}
/* Quoted strings. Strip leading and ending quotes */
%token VAR_INFRA_CACHE_NUMHOSTS VAR_INFRA_CACHE_NUMLAME VAR_NAME
%token VAR_STUB_ZONE VAR_STUB_HOST VAR_STUB_ADDR VAR_TARGET_FETCH_POLICY
%token VAR_HARDEN_SHORT_BUFSIZE VAR_HARDEN_LARGE_QUERIES
+%token VAR_FORWARD_ZONE VAR_FORWARD_HOST VAR_FORWARD_ADDR
%%
toplevelvars: /* empty */ | toplevelvars toplevelvar ;
server_infra_cache_slabs | server_infra_cache_numhosts |
server_infra_cache_numlame | stubstart contents_stub |
server_target_fetch_policy | server_harden_short_bufsize |
- server_harden_large_queries
+ server_harden_large_queries | forwardstart contents_forward
;
stubstart: VAR_STUB_ZONE
{
| ;
content_stub: stub_name | stub_host | stub_addr
;
+forwardstart: VAR_FORWARD_ZONE
+ {
+ struct config_stub* s;
+ OUTYY(("\nP(forward_zone:)\n"));
+ s = (struct config_stub*)calloc(1, sizeof(struct config_stub));
+ if(s) {
+ s->next = cfg_parser->cfg->forwards;
+ cfg_parser->cfg->forwards = s;
+ } else
+ yyerror("out of memory");
+ }
+ ;
+contents_forward: contents_forward content_forward
+ | ;
+content_forward: forward_name | forward_host | forward_addr
+ ;
server_num_threads: VAR_NUM_THREADS STRING
{
OUTYY(("P(server_num_threads:%s)\n", $2));
stub_name: VAR_NAME STRING
{
OUTYY(("P(name:%s)\n", $2));
+ free(cfg_parser->cfg->stubs->name);
cfg_parser->cfg->stubs->name = $2;
}
;
yyerror("out of memory");
}
;
+forward_name: VAR_NAME STRING
+ {
+ OUTYY(("P(name:%s)\n", $2));
+ free(cfg_parser->cfg->forwards->name);
+ cfg_parser->cfg->forwards->name = $2;
+ }
+ ;
+forward_host: VAR_FORWARD_HOST STRING
+ {
+ struct config_strlist *s = (struct config_strlist*)calloc(1,
+ sizeof(struct config_strlist));
+ OUTYY(("P(forward-host:%s)\n", $2));
+ if(s) {
+ s->str = $2;
+ s->next = cfg_parser->cfg->forwards->hosts;
+ cfg_parser->cfg->forwards->hosts = s;
+ } else
+ yyerror("out of memory");
+ }
+ ;
+forward_addr: VAR_FORWARD_ADDR STRING
+ {
+ struct config_strlist *s = (struct config_strlist*)calloc(1,
+ sizeof(struct config_strlist));
+ OUTYY(("P(forward-addr:%s)\n", $2));
+ if(s) {
+ s->str = $2;
+ s->next = cfg_parser->cfg->forwards->addrs;
+ cfg_parser->cfg->forwards->addrs = s;
+ } else
+ yyerror("out of memory");
+ }
+ ;
%%
/* parse helper routines could be here */