limit auth-zone and rpz transfer amount and time taken.
Default is disabled. This hardens against unbounded
transfers. Thanks to Qifan Zhang, Palo Alto Networks,
for the report.
return 0;
}
+/** See if configuration has changed. */
+static int
+xfr_config_equal(struct auth_xfer* xfr1, struct auth_xfer* xfr2)
+{
+ if(xfr1 == NULL && xfr2 == NULL)
+ return 1;
+ if(xfr1 == NULL && xfr2 != NULL)
+ return 0;
+ if(xfr1 != NULL && xfr2 == NULL)
+ return 0;
+ if(xfr1->max_transfer_size != xfr2->max_transfer_size)
+ return 0;
+ if(xfr1->max_transfer_time != xfr2->max_transfer_time)
+ return 0;
+ return 1;
+}
+
/** See if the list of masters has changed. */
static int
xfr_masters_equal(struct auth_xfer* xfr1, struct auth_xfer* xfr2)
*/
if(have_old != have_new || old_serial != new_serial
|| !xfr_masters_equal(old_xfr, new_xfr)
+ || !xfr_config_equal(old_xfr, new_xfr)
|| old_z->zonemd_callback_env != NULL) {
/* The zone has been changed. */
if(!fr_add_auth_zone_change(fr, old_z, new_z,
log_assert(loadxfr->namelabs == xfr->namelabs);
log_assert(loadxfr->dclass == xfr->dclass);
+ xfr->max_transfer_size = loadxfr->max_transfer_size;
+ xfr->max_transfer_time = loadxfr->max_transfer_time;
+
/* The lists can be swapped in, the other xfr struct will be deleted
* afterwards. */
probe_masters = xfr->task_probe->masters;
+15 June 2026: Wouter
+ - Fix to add `max-transfer-size` and `max-transfer-time` that
+ limit auth-zone and rpz transfer amount and time taken.
+ Default is disabled. This hardens against unbounded
+ transfers. Thanks to Qifan Zhang, Palo Alto Networks,
+ for the report.
+
12 June 2026: Wouter
- Fix that for auth-zone and rpz zones the allow-notify
addresses and netblocks are available from start, and
# zonemd-check: no
# zonemd-reject-absence: no
# zonefile: "example.org.zone"
+# max-transfer-size: 0
+# max-transfer-time: 0
+
# Views
# Create named views. Name must be unique.
# rpz-signal-nxdomain-ra: no
# for-downstream: no
# tags: "example"
+# max-transfer-size: 0
+# max-transfer-time: 0
If the file does not exist or is empty, Unbound will attempt to fetch zone
data (eg. from the primary servers).
+
+@@UAHL@unbound.conf.auth@max-transfer-size@@: *<number>*
+ Number of bytes size of the maximum zone transfer size.
+ Larger transfers, over AXFR, IXFR and HTTP, are not allowed.
+ A plain number is in bytes, append 'k', 'm' or 'g' for kilobytes, megabytes
+ or gigabytes (1024*1024 bytes in a megabyte).
+ The value ``0`` disables the feature.
+
+ Only consider for untrusted/misbehaving primaries that could hog resources
+ and bring down the resolver.
+
+ Default: 0
+
+
+@@UAHL@unbound.conf.auth@max-transfer-time@@: *<msec>*
+ Maximum time in milliseconds that a zone transfer is allowed to take from
+ the start.
+ The value ``0`` disables the feature.
+
+ Only consider for untrusted/misbehaving primaries that could hog resources
+ and bring down the resolver.
+
+ Default: 0
+
+
.. _unbound.conf.view:
View Options
If no tags are specified the policies from this section will be applied for
all clients.
+
+@@UAHL@unbound.conf.rpz@max-transfer-size@@: *<number>*
+ Number of bytes size of the maximum zone transfer size.
+ Larger transfers, over AXFR, IXFR and HTTP, are not allowed.
+ A plain number is in bytes, append 'k', 'm' or 'g' for kilobytes, megabytes
+ or gigabytes (1024*1024 bytes in a megabyte).
+ The value ``0`` disables the feature.
+
+ Only consider for untrusted/misbehaving primaries that could hog resources
+ and bring down the resolver.
+
+ Default: 0
+
+
+@@UAHL@unbound.conf.rpz@max-transfer-time@@: *<msec>*
+ Maximum time in milliseconds that a zone transfer is allowed to take from
+ the start.
+ The value ``0`` disables the feature.
+
+ Only consider for untrusted/misbehaving primaries that could hog resources
+ and bring down the resolver.
+
+ Default: 0
+
+
Memory Control Example
----------------------
#include "util/log.h"
#include "util/module.h"
#include "util/random.h"
+#include "util/timeval_func.h"
#include "services/cache/dns.h"
#include "services/outside_network.h"
#include "services/listen_dnsport.h"
}
return 0;
}
+ /* Populate the xfer related options early since we may create one now */
+ z->max_transfer_size = c->max_transfer_size;
+ z->max_transfer_time = c->max_transfer_time;
if(c->masters || c->urls) {
if(!(x=auth_zones_find_or_add_xfer(az, z))) {
lock_rw_unlock(&az->lock);
}
at->chunks_first = NULL;
at->chunks_last = NULL;
+ at->chunks_total = 0;
}
/** free master addr list */
t.tv_sec = timeout/1000;
t.tv_usec = (timeout%1000)*1000;
#endif
+ xfr->task_transfer->start_time = *env->now_tv;
if(master->http) {
/* perform http fetch */
if(xfr->task_transfer->chunks_last)
xfr->task_transfer->chunks_last->next = e;
xfr->task_transfer->chunks_last = e;
+ xfr->task_transfer->chunks_total += e->len;
return 1;
}
xfr_transfer_nexttarget_or_end(xfr, env);
}
+/** return the time taken by the transfer */
+static int
+auth_xfer_transfer_time_taken(struct auth_xfer* xfr, struct module_env* env)
+{
+ struct timeval delta;
+ timeval_subtract(&delta, env->now_tv, &xfr->task_transfer->start_time);
+ return ((int)delta.tv_sec)*1000 + ((int)delta.tv_usec)/1000;
+}
+
/** callback for task_transfer tcp connections */
int
auth_xfer_transfer_tcp_callback(struct comm_point* c, void* arg, int err,
xfr->task_transfer->master->host);
goto failed;
}
+ if(xfr->max_transfer_size > 0 &&
+ xfr->task_transfer->chunks_total > xfr->max_transfer_size) {
+ char zname[LDNS_MAX_DOMAINLEN];
+ dname_str(xfr->name, zname);
+ log_err("auth zone %s transfer from %s exceeded %u bytes, aborting",
+ zname, xfr->task_transfer->master->host,
+ (unsigned)xfr->max_transfer_size);
+ goto failed;
+ }
/* if the transfer is done now, disconnect and process the list */
if(transferdone) {
comm_point_delete(xfr->task_transfer->cp);
return 0;
}
+ if(xfr->max_transfer_time > 0 &&
+ auth_xfer_transfer_time_taken(xfr, env) > xfr->max_transfer_time) {
+ char zname[LDNS_MAX_DOMAINLEN];
+ dname_str(xfr->name, zname);
+ log_err("auth zone %s transfer from %s exceeded %u msec total running time, aborting",
+ zname, xfr->task_transfer->master->host,
+ (unsigned)xfr->max_transfer_time);
+ goto failed;
+ }
+
/* if we want to read more messages, setup the commpoint to read
* a DNS packet, and the timeout */
lock_basic_unlock(&xfr->lock);
xfr->task_transfer->master->host);
goto failed;
}
+ if(xfr->max_transfer_size > 0 &&
+ xfr->task_transfer->chunks_total > xfr->max_transfer_size) {
+ char zname[LDNS_MAX_DOMAINLEN];
+ dname_str(xfr->name, zname);
+ log_err("auth zone %s http %s/%s exceeded %u bytes, aborting",
+ zname, xfr->task_transfer->master->host,
+ xfr->task_transfer->master->file,
+ (unsigned)xfr->max_transfer_size);
+ goto failed;
+ }
}
/* if the transfer is done now, disconnect and process the list */
if(err == NETEVENT_DONE) {
return 0;
}
+ if(xfr->max_transfer_time > 0 &&
+ auth_xfer_transfer_time_taken(xfr, env) > xfr->max_transfer_time) {
+ char zname[LDNS_MAX_DOMAINLEN];
+ dname_str(xfr->name, zname);
+ log_err("auth zone %s transfer http %s/%s exceeded %u msec total running time, aborting",
+ zname, xfr->task_transfer->master->host,
+ xfr->task_transfer->master->file,
+ (unsigned)xfr->max_transfer_time);
+ goto failed;
+ }
+
/* if we want to read more messages, setup the commpoint to read
* a DNS packet, and the timeout */
lock_basic_unlock(&xfr->lock);
xfr->namelen = z->namelen;
xfr->namelabs = z->namelabs;
xfr->dclass = z->dclass;
+ xfr->max_transfer_size = z->max_transfer_size;
+ xfr->max_transfer_time = z->max_transfer_time;
xfr->task_nextprobe = (struct auth_nextprobe*)calloc(1,
sizeof(struct auth_nextprobe));
struct auth_zone* rpz_az_next;
/** previous auth zone containing RPZ data, or NULL */
struct auth_zone* rpz_az_prev;
+ /** The maximum auth zone transfer size, in bytes. */
+ size_t max_transfer_size;
+ /** The maximum auth zone transfer time taken, in msec. */
+ int max_transfer_time;
};
/**
* this is renewed every SOA probe and transfer. On zone load
* from zonefile it is also set (with probe set soon to check) */
time_t lease_time;
+
+ /** The maximum auth zone transfer size, in bytes. */
+ size_t max_transfer_size;
+ /** The maximum auth zone transfer time taken, in msec. */
+ int max_transfer_time;
};
/**
struct auth_chunk* chunks_first;
/** last element in chunks list (to append new data at the end) */
struct auth_chunk* chunks_last;
+ /** running total of bytes held in chunks_first..chunks_last */
+ size_t chunks_total;
+ /** start time of the transfer */
+ struct timeval start_time;
/** list of upstream masters for this zone, from config */
struct auth_master* masters;
--- /dev/null
+server:
+ verbosity: 7
+ # num-threads: 1
+ interface: 127.0.0.1
+ port: @PORT@
+ use-syslog: no
+ directory: ""
+ pidfile: "unbound.pid"
+ chroot: ""
+ username: ""
+ do-not-query-localhost: no
+ use-caps-for-id: no
+
+auth-zone:
+ name: "example.com"
+ for-upstream: yes
+ for-downstream: yes
+ master: "127.0.0.1@@TOPORT@"
+ max-transfer-size: 512
+ max-transfer-time: 2000
+auth-zone:
+ name: "example2.com"
+ for-upstream: yes
+ for-downstream: yes
+ master: "127.0.0.1@@TOPORT@"
+ max-transfer-size: 512
+ max-transfer-time: 2000
+remote-control:
+ control-enable: yes
+ control-interface: @CONTROL_PATH@/controlpipe.@CONTROL_PID@
+ control-use-cert: no
+
--- /dev/null
+BaseName: auth_transfer_limit
+Version: 1.0
+Description: Test limit of authority zone transfer.
+CreationDate: Tue May 12 03:00:00 PM CEST 2026
+Maintainer: dr. W.C.A. Wijngaards
+Category:
+Component:
+CmdDepends:
+Depends:
+Help:
+Pre: auth_transfer_limit.pre
+Post: auth_transfer_limit.post
+Test: auth_transfer_limit.test
+AuxFiles:
+Passed:
+Failure:
--- /dev/null
+# #-- auth_transfer_limit.post --#
+# source the master var file when it's there
+[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
+# source the test var file when it's there
+[ -f .tpkg.var.test ] && source .tpkg.var.test
+#
+# do your teardown here
+. ../common.sh
+kill_pid $FWD_PID
+kill_pid $UNBOUND_PID
+rm -f $CONTROL_PATH/controlpipe.$CONTROL_PID
+echo "> cat logfiles"
+cat fwd.log
+cat unbound.log
--- /dev/null
+# #-- auth_transfer_limit.pre--#
+# source the master var file when it's there
+[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
+# use .tpkg.var.test for in test variable passing
+[ -f .tpkg.var.test ] && source .tpkg.var.test
+
+PRE="../.."
+. ../common.sh
+if grep -e "define HAVE_PTHREAD 1" -e "define HAVE_SOLARIS_THREADS 1" -e "define HAVE_WINDOWS_THREADS 1" $PRE/config.h; then
+ TEST_FAST_RELOAD="yes"
+else
+ TEST_FAST_RELOAD="no"
+fi
+echo "TEST_FAST_RELOAD=$TEST_FAST_RELOAD" >> .tpkg.var.test
+
+get_random_port 2
+UNBOUND_PORT=$RND_PORT
+FWD_PORT=$(($RND_PORT + 1))
+echo "UNBOUND_PORT=$UNBOUND_PORT" >> .tpkg.var.test
+echo "FWD_PORT=$FWD_PORT" >> .tpkg.var.test
+
+# start forwarder
+get_ldns_testns
+$LDNS_TESTNS -p $FWD_PORT auth_transfer_limit.testns >fwd.log 2>&1 &
+FWD_PID=$!
+echo "FWD_PID=$FWD_PID" >> .tpkg.var.test
+
+# make config file
+CONTROL_PATH=/tmp
+CONTROL_PID=$$
+sed -e 's/@PORT\@/'$UNBOUND_PORT'/' -e 's/@TOPORT\@/'$FWD_PORT'/' -e 's?@CONTROL_PATH\@?'$CONTROL_PATH'?' -e 's/@CONTROL_PID@/'$CONTROL_PID'/' < auth_transfer_limit.conf > ub.conf
+# start unbound in the background
+$PRE/unbound -d -c ub.conf >unbound.log 2>&1 &
+UNBOUND_PID=$!
+echo "UNBOUND_PID=$UNBOUND_PID" >> .tpkg.var.test
+echo "CONTROL_PATH=$CONTROL_PATH" >> .tpkg.var.test
+echo "CONTROL_PID=$CONTROL_PID" >> .tpkg.var.test
+
+cat .tpkg.var.test
+wait_ldns_testns_up fwd.log
+wait_unbound_up unbound.log
+
--- /dev/null
+# #-- auth_transfer_limit.test --#
+# source the master var file when it's there
+[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
+# use .tpkg.var.test for in test variable passing
+[ -f .tpkg.var.test ] && source .tpkg.var.test
+
+PRE="../.."
+. ../common.sh
+# do the test
+
+teststep "wait for unbound to transfer"
+sleep 3
+
+teststep "check log for max-transfer-size"
+if grep "auth zone example.com. transfer.*exceeded 512 bytes" unbound.log; then
+ echo "OK"
+else
+ echo "Not OK"
+ exit 1
+fi
+
+teststep "check log for max-transfer-time"
+if grep "auth zone example2.com. transfer.*exceeded 2000 msec" unbound.log; then
+ echo "OK"
+else
+ echo "Not OK"
+ exit 1
+fi
+
+if test "$TEST_FAST_RELOAD" == "yes"; then
+ teststep "Testing with fast_reload"
+ cp ub.conf ub.conf.old
+ sed -e 's/max-transfer-size: 512/max-transfer-size: 500/' -e 's/max-transfer-time: 2000/max-transfer-time: 1000/' < ub.conf.old > ub.conf
+
+ teststep "unbound-control status"
+ $PRE/unbound-control -c ub.conf status
+ if test $? -ne 0; then
+ echo "wrong exit value."
+ exit 1
+ else
+ echo "exit value: OK"
+ fi
+
+ teststep "unbound-control fast_reload +vvdp"
+ $PRE/unbound-control -c ub.conf fast_reload +vvdp 2>&1 | tee output
+ if test $? -ne 0; then
+ echo "wrong exit value."
+ exit 1
+ else
+ echo "exit value: OK"
+ fi
+ wait_logfile unbound.log "start fast reload thread" 60
+ wait_logfile unbound.log "stop fast reload thread" 60
+ wait_logfile unbound.log "joined with fastreload thread" 60
+
+ if grep "ok" output; then
+ echo "OK"
+ else
+ echo "output not correct"
+ exit 1
+ fi
+
+ teststep "wait for unbound to transfer"
+ sleep 3
+
+ $PRE/unbound-control -c ub.conf auth_zone_transfer example.com 2>&1
+ if test $? -ne 0; then
+ echo "wrong exit value."
+ exit 1
+ else
+ echo "exit value: OK"
+ fi
+ $PRE/unbound-control -c ub.conf auth_zone_transfer example2.com 2>&1
+ if test $? -ne 0; then
+ echo "wrong exit value."
+ exit 1
+ else
+ echo "exit value: OK"
+ fi
+ teststep "wait for unbound to transfer"
+ sleep 3
+
+ teststep "check log for max-transfer-size"
+ if grep "auth zone example.com. transfer.*exceeded 500 bytes" unbound.log; then
+ echo "OK"
+ else
+ echo "Not OK"
+ exit 1
+ fi
+
+ teststep "check log for max-transfer-time"
+ if grep "auth zone example2.com. transfer.*exceeded 1000 msec" unbound.log; then
+ echo "OK"
+ else
+ echo "Not OK"
+ exit 1
+ fi
+fi
+
+exit 0
--- /dev/null
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+example.com. IN SOA
+SECTION ANSWER
+example.com. IN SOA ns.example.com. hostmaster.example.com. 1 3600 900 86400 3600
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+example.com. IN AXFR
+SECTION ANSWER
+example.com. IN SOA ns.example.com. hostmaster.example.com. 1 3600 900 86400 3600
+example.com. IN NS ns.example.net.
+; too big!
+EXTRA_PACKET
+REPLY QR AA NOERROR
+SECTION QUESTION
+example.com. IN AXFR
+SECTION ANSWER
+large01.example.com. IN TXT "123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789"
+large02.example.com. IN TXT "123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789"
+large03.example.com. IN TXT "123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789"
+large04.example.com. IN TXT "123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789"
+large05.example.com. IN TXT "123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789"
+EXTRA_PACKET
+REPLY QR AA NOERROR
+SECTION QUESTION
+example.com. IN AXFR
+SECTION ANSWER
+www.example.com. IN A 1.2.3.4
+example.com. IN SOA ns.example.com. hostmaster.example.com. 1 3600 900 86400 3600
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+example2.com. IN SOA
+SECTION ANSWER
+example2.com. IN SOA ns.example2.com. hostmaster.example2.com. 1 3600 900 86400 3600
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+example2.com. IN AXFR
+SECTION ANSWER
+example2.com. IN SOA ns.example2.com. hostmaster.example2.com. 1 3600 900 86400 3600
+example2.com. IN NS ns.example2.net.
+EXTRA_PACKET
+REPLY QR AA NOERROR
+; too slow
+ADJUST packet_sleep=3
+SECTION QUESTION
+example2.com. IN AXFR
+SECTION ANSWER
+extra.example2.com. IN A 1.2.3.5
+EXTRA_PACKET
+REPLY QR AA NOERROR
+SECTION QUESTION
+example2.com. IN AXFR
+SECTION ANSWER
+www.example2.com. IN A 1.2.3.4
+example2.com. IN SOA ns.example2.com. hostmaster.example2.com. 1 3600 900 86400 3600
+ENTRY_END
int zonemd_check;
/** Reject absence of ZONEMD records, zone must have one */
int zonemd_reject_absence;
+ /** The maximum auth zone transfer size, in bytes. */
+ size_t max_transfer_size;
+ /** The maximum auth zone transfer time taken, in msec. */
+ int max_transfer_time;
};
/**
iter-scrub-cname{COLON} { YDVAR(1, VAR_ITER_SCRUB_CNAME) }
iter-scrub-rrsig{COLON} { YDVAR(1, VAR_ITER_SCRUB_RRSIG) }
max-global-quota{COLON} { YDVAR(1, VAR_MAX_GLOBAL_QUOTA) }
+max-transfer-size{COLON} { YDVAR(1, VAR_MAX_TRANSFER_SIZE) }
+max-transfer-time{COLON} { YDVAR(1, VAR_MAX_TRANSFER_TIME) }
iter-scrub-promiscuous{COLON} { YDVAR(1, VAR_ITER_SCRUB_PROMISCUOUS) }
<INITIAL,val>{NEWLINE} { LEXOUT(("NL\n")); cfg_parser->line++; }
%token VAR_LOG_DESTADDR VAR_CACHEDB_CHECK_WHEN_SERVE_EXPIRED
%token VAR_COOKIE_SECRET_FILE VAR_ITER_SCRUB_NS VAR_ITER_SCRUB_CNAME
%token VAR_ITER_SCRUB_RRSIG
+%token VAR_MAX_TRANSFER_SIZE VAR_MAX_TRANSFER_TIME
%token VAR_MAX_GLOBAL_QUOTA VAR_HARDEN_UNVERIFIED_GLUE VAR_LOG_TIME_ISO
%token VAR_ITER_SCRUB_PROMISCUOUS VAR_LOG_THREAD_ID
s->zonemd_check = 0;
s->zonemd_reject_absence = 0;
s->isrpz = 0;
+ s->max_transfer_size = 0;
+ s->max_transfer_time = 0;
} else {
yyerror("out of memory");
}
| ;
content_auth: auth_name | auth_zonefile | auth_master | auth_url |
auth_for_downstream | auth_for_upstream | auth_fallback_enabled |
- auth_allow_notify | auth_zonemd_check | auth_zonemd_reject_absence
+ auth_allow_notify | auth_zonemd_check | auth_zonemd_reject_absence |
+ auth_max_transfer_size | auth_max_transfer_time
;
rpz_tag: VAR_TAGS STRING_ARG
s->for_upstream = 0;
s->fallback_enabled = 0;
s->isrpz = 1;
+ s->max_transfer_size = 0;
+ s->max_transfer_time = 0;
} else {
yyerror("out of memory");
}
| ;
content_rpz: auth_name | auth_zonefile | rpz_tag | auth_master | auth_url |
auth_allow_notify | rpz_action_override | rpz_cname_override |
- rpz_log | rpz_log_name | rpz_signal_nxdomain_ra | auth_for_downstream
+ rpz_log | rpz_log_name | rpz_signal_nxdomain_ra | auth_for_downstream |
+ auth_max_transfer_size | auth_max_transfer_time
;
server_num_threads: VAR_NUM_THREADS STRING_ARG
{
free($2);
}
;
+auth_max_transfer_size: VAR_MAX_TRANSFER_SIZE STRING_ARG
+ {
+ OUTYY(("P(max-transfer-size:%s)\n", $2));
+ if(!cfg_parse_memsize($2, &cfg_parser->cfg->auths->max_transfer_size))
+ yyerror("memory size expected");
+ free($2);
+ }
+ ;
+auth_max_transfer_time: VAR_MAX_TRANSFER_TIME STRING_ARG
+ {
+ OUTYY(("P(max-transfer-time:%s)\n", $2));
+ if(atoi($2) == 0 && strcmp($2, "0") != 0)
+ yyerror("number expected");
+ else cfg_parser->cfg->auths->max_transfer_time = atoi($2);
+ free($2);
+ }
+ ;
view_name: VAR_NAME STRING_ARG
{
OUTYY(("P(name:%s)\n", $2));