diff -ur trunk/daemon/worker.c trunk.new/daemon/worker.c
--- trunk/daemon/worker.c	2013-04-19 21:23:01.000000000 +0900
+++ trunk.new/daemon/worker.c	2013-04-19 21:27:32.000000000 +0900
@@ -830,6 +830,13 @@
 			(int)edns.udp_size);
 		log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
 		edns.udp_size = NORMAL_UDP_SIZE;
+	} else if(edns.edns_present &&
+		edns.udp_size > worker->daemon->cfg->max_udp_size &&
+		c->type == comm_udp) {
+		verbose(VERB_QUERY, "worker request: EDNS bufsize %d exceeds "
+			"max-udp-size, fixed", (int)edns.udp_size);
+		log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
+		edns.udp_size = worker->daemon->cfg->max_udp_size;
 	}
 	if(edns.edns_present && edns.udp_size < LDNS_HEADER_SIZE) {
 		verbose(VERB_ALGO, "worker request: edns is too small.");
diff -ur trunk/doc/example.conf.in trunk.new/doc/example.conf.in
--- trunk/doc/example.conf.in	2013-04-19 21:23:05.000000000 +0900
+++ trunk.new/doc/example.conf.in	2013-04-19 21:28:23.000000000 +0900
@@ -89,6 +89,10 @@
 	# is set with msg-buffer-size). 1480 can solve fragmentation (timeouts).
 	# edns-buffer-size: 4096
 
+	# Maximum UDP response size (not applied to TCP response).
+	# Valid values are 512 to 4096. Default is 4096.
+	# max-udp-size: 4096
+
 	# buffer size for handling DNS data. No messages larger than this
 	# size can be sent or received, by UDP or TCP. In bytes.
 	# msg-buffer-size: 65552
diff -ur trunk/doc/unbound-control.8.in trunk.new/doc/unbound-control.8.in
--- trunk/doc/unbound-control.8.in	2013-04-19 21:23:05.000000000 +0900
+++ trunk.new/doc/unbound-control.8.in	2013-04-19 22:07:53.000000000 +0900
@@ -170,7 +170,7 @@
 harden\-referral\-path, prefetch, prefetch\-key, log\-queries,
 hide\-identity, hide\-version, identity, version, val\-log\-level,
 val\-log\-squelch, ignore\-cd\-flag, add\-holddown, del\-holddown,
-keep\-missing, tcp\-upstream, ssl\-upstream.
+keep\-missing, tcp\-upstream, ssl\-upstream, max\-udp\-size.
 .TP
 .B get_option \fIopt
 Get the value of the option.  Give the option name without a trailing ':'.
diff -ur trunk/doc/unbound.conf.5.in trunk.new/doc/unbound.conf.5.in
--- trunk/doc/unbound.conf.5.in	2013-04-19 21:23:05.000000000 +0900
+++ trunk.new/doc/unbound.conf.5.in	2013-04-19 21:29:44.000000000 +0900
@@ -183,6 +183,10 @@
 of TCP fallback generated is excessive (probably also for this resolver,
 consider tuning the outgoing tcp number).
 .TP
+.B max-udp-size: \fI<number>
+Maximum UDP response size (not applied to TCP response).
+Valid values are 512 to 4096. Default is 4096. 
+.TP
 .B msg\-buffer\-size: \fI<number>
 Number of bytes size of the message buffers. Default is 65552 bytes, enough
 for 64 Kb packets, the maximum DNS message size. No message larger than this
diff -ur trunk/util/config_file.c trunk.new/util/config_file.c
--- trunk/util/config_file.c	2013-04-19 21:23:15.000000000 +0900
+++ trunk.new/util/config_file.c	2013-04-19 22:19:49.000000000 +0900
@@ -201,6 +201,7 @@
 	cfg->control_port = UNBOUND_CONTROL_PORT;
 	cfg->minimal_responses = 0;
 	cfg->rrset_roundrobin = 0;
+	cfg->max_udp_size = 4096;
 	if(!(cfg->server_key_file = strdup(RUN_DIR"/unbound_server.key"))) 
 		goto error_exit;
 	if(!(cfg->server_cert_file = strdup(RUN_DIR"/unbound_server.pem"))) 
@@ -327,7 +328,10 @@
 		cfg->use_syslog = 0;
 		free(cfg->logfile);
 		return (cfg->logfile = strdup(val)) != NULL;
-	} 
+	} else if(strcmp(opt, "max-udp-size:") == 0) {
+		if(atoi(val) < 512 || atoi(val) > 4096) return 0;
+		cfg->max_udp_size = atoi(val);
+	}
 	else S_YNO("use-syslog:", use_syslog)
 	else S_YNO("extended-statistics:", stat_extended)
 	else S_YNO("statistics-cumulative:", stat_cumulative)
@@ -662,6 +666,7 @@
 	else O_UNS(opt, "val-override-date", val_date_override)
 	else O_YNO(opt, "minimal-responses", minimal_responses)
 	else O_YNO(opt, "rrset-roundrobin", rrset_roundrobin)
+	else O_DEC(opt, "max-udp-size", max_udp_size)
 	/* not here:
 	 * outgoing-permit, outgoing-avoid - have list of ports
 	 * local-zone - zones and nodefault variables
diff -ur trunk/util/config_file.h trunk.new/util/config_file.h
--- trunk/util/config_file.h	2013-04-19 21:23:15.000000000 +0900
+++ trunk.new/util/config_file.h	2013-04-19 21:33:01.000000000 +0900
@@ -296,6 +296,9 @@
 
 	/* RRSet roundrobin */
 	int rrset_roundrobin;
+
+	/* maximum UDP response size */
+	size_t max_udp_size;
 };
 
 /**
diff -ur trunk/util/configlexer.lex trunk.new/util/configlexer.lex
--- trunk/util/configlexer.lex	2013-04-19 21:23:15.000000000 +0900
+++ trunk.new/util/configlexer.lex	2013-04-19 21:33:38.000000000 +0900
@@ -293,6 +293,7 @@
 domain-insecure{COLON}		{ YDVAR(1, VAR_DOMAIN_INSECURE) }
 minimal-responses{COLON}	{ YDVAR(1, VAR_MINIMAL_RESPONSES) }
 rrset-roundrobin{COLON}		{ YDVAR(1, VAR_RRSET_ROUNDROBIN) }
+max-udp-size{COLON}		{ YDVAR(1, VAR_MAX_UDP_SIZE) }
 <INITIAL,val>{NEWLINE}		{ LEXOUT(("NL\n")); cfg_parser->line++; }
 
 	/* Quoted strings. Strip leading and ending quotes */
diff -ur trunk/util/configparser.y trunk.new/util/configparser.y
--- trunk/util/configparser.y	2013-04-19 21:23:15.000000000 +0900
+++ trunk.new/util/configparser.y	2013-04-19 21:36:42.000000000 +0900
@@ -105,6 +105,7 @@
 %token VAR_IGNORE_CD_FLAG VAR_LOG_QUERIES VAR_TCP_UPSTREAM VAR_SSL_UPSTREAM
 %token VAR_SSL_SERVICE_KEY VAR_SSL_SERVICE_PEM VAR_SSL_PORT VAR_FORWARD_FIRST
 %token VAR_STUB_FIRST VAR_MINIMAL_RESPONSES VAR_RRSET_ROUNDROBIN
+%token VAR_MAX_UDP_SIZE
 
 %%
 toplevelvars: /* empty */ | toplevelvars toplevelvar ;
@@ -161,7 +162,7 @@
 	server_so_sndbuf | server_harden_below_nxdomain | server_ignore_cd_flag |
 	server_log_queries | server_tcp_upstream | server_ssl_upstream |
 	server_ssl_service_key | server_ssl_service_pem | server_ssl_port |
-	server_minimal_responses | server_rrset_roundrobin
+	server_minimal_responses | server_rrset_roundrobin | server_max_udp_size
 	;
 stubstart: VAR_STUB_ZONE
 	{
@@ -1117,6 +1118,14 @@
 		free($2);
 	}
 	;
+server_max_udp_size: VAR_MAX_UDP_SIZE STRING_ARG
+	{
+		OUTYY(("P(server_max_udp_size:%s)\n", $2));
+		if(atoi($2) < 512 || atoi($2) > 4096)
+			yyerror("number from 512 to 4096 expected");
+		else cfg_parser->cfg->max_udp_size = atoi($2);
+	}
+	;
 stub_name: VAR_NAME STRING_ARG
 	{
 		OUTYY(("P(name:%s)\n", $2));
