Browse code

dns_cache: added support for permanent entries

Permanent entries are intended to be used for management
purposes, i.e. they are useful if there is no DNS server
available for instance. Such entries never expire, and overwrite
any existing entry that was added by the resolver.
They can be added to the cache from modules or over the RPC calls
dns.add_a, dns.add_aaaa and dns.add_srv with the flag value of 2.
(or 3 in case of negative permanent entry)

- err_flags in struct dns_hash_entry is changed to be a general
purpose flag, and renamed to ent_flag.
- DNS_BAD_NAME is renamed to DNS_FLAG_BAD_NAME
- DNS_FLAG_PERMANENT value is added.
- new rpc call to force deleting the permanent entries from the
cache: dns.delete_all_force. (dns.delete_all deletes only
the non-permanent entries.)

Miklos Tirpak authored on 16/06/2010 13:49:24
Showing 3 changed files
... ...
@@ -56,6 +56,7 @@ void dns_cache_mem_info(rpc_t* rpc, void* ctx);
56 56
 void dns_cache_view(rpc_t* rpc, void* ctx);
57 57
 void dns_cache_rpc_lookup(rpc_t* rpc, void* ctx);
58 58
 void dns_cache_delete_all(rpc_t* rpc, void* ctx);
59
+void dns_cache_delete_all_force(rpc_t* rpc, void* ctx);
59 60
 void dns_cache_add_a(rpc_t* rpc, void* ctx);
60 61
 void dns_cache_add_aaaa(rpc_t* rpc, void* ctx);
61 62
 void dns_cache_add_srv(rpc_t* rpc, void* ctx);
... ...
@@ -94,7 +95,12 @@ static const char* dns_cache_rpc_lookup_doc[] = {
94 95
 };
95 96
 
96 97
 static const char* dns_cache_delete_all_doc[] = {
97
-	"deletes all the entries from the DNS cache",
98
+	"deletes all the non-permanent entries from the DNS cache",
99
+	0
100
+};
101
+
102
+static const char* dns_cache_delete_all_force_doc[] = {
103
+	"deletes all the entries from the DNS cache including the permanent ones",
98 104
 	0
99 105
 };
100 106
 
... ...
@@ -848,6 +854,8 @@ static rpc_export_t core_rpc_methods[] = {
848 854
 		0	},
849 855
 	{"dns.delete_all",         dns_cache_delete_all,  dns_cache_delete_all_doc,
850 856
 		0	},
857
+	{"dns.delete_all_force",   dns_cache_delete_all_force, dns_cache_delete_all_force_doc,
858
+		0	},
851 859
 	{"dns.add_a",              dns_cache_add_a,       dns_cache_add_a_doc,
852 860
 		0	},
853 861
 	{"dns.add_aaaa",           dns_cache_add_aaaa,    dns_cache_add_aaaa_doc,
... ...
@@ -573,6 +573,7 @@ again:
573 573
 			servers_up &&
574 574
 #endif
575 575
 			/* automatically remove expired elements */
576
+			((e->ent_flags & DNS_FLAG_PERMANENT) == 0) &&
576 577
 			((s_ticks_t)(now-e->expire)>=0)
577 578
 		) {
578 579
 				_dns_hash_remove(e);
... ...
@@ -591,7 +592,8 @@ again:
591 592
 #endif
592 593
 #endif
593 594
 			return e;
594
-		}else if ((e->type==T_CNAME) && !((e->rr_lst==0) || e->err_flags) &&
595
+		}else if ((e->type==T_CNAME) &&
596
+					!((e->rr_lst==0) || (e->ent_flags & DNS_FLAG_BAD_NAME)) &&
595 597
 					(e->name_len==name->len) &&
596 598
 					(strncasecmp(e->name, name->s, e->name_len)==0)){
597 599
 			/*if CNAME matches and CNAME is entry is not a neg. cache entry
... ...
@@ -659,7 +661,9 @@ inline static int dns_cache_clean(unsigned int no, int expired_only)
659 661
 	clist_foreach_safe(dns_last_used_lst, l, tmp, next){
660 662
 		e=(struct dns_hash_entry*)(((char*)l)-
661 663
 				(char*)&((struct dns_hash_entry*)(0))->last_used_lst);
662
-		if (!expired_only || ((s_ticks_t)(now-e->expire)>=0)){
664
+		if (((e->ent_flags & DNS_FLAG_PERMANENT) == 0)
665
+			&& (!expired_only || ((s_ticks_t)(now-e->expire)>=0))
666
+		) {
663 667
 				_dns_hash_remove(e);
664 668
 				deleted++;
665 669
 		}
... ...
@@ -669,7 +673,9 @@ inline static int dns_cache_clean(unsigned int no, int expired_only)
669 673
 #else
670 674
 	for(h=start; h!=(start+DNS_HASH_SIZE); h++){
671 675
 		clist_foreach_safe(&dns_hash[h%DNS_HASH_SIZE], e, t, next){
672
-			if  ((s_ticks_t)(now-e->expire)>=0){
676
+			if (((e->ent_flags & DNS_FLAG_PERMANENT) == 0)
677
+				&& ((s_ticks_t)(now-e->expire)>=0)
678
+			) {
673 679
 				_dns_hash_remove(e);
674 680
 				deleted++;
675 681
 			}
... ...
@@ -681,8 +687,10 @@ inline static int dns_cache_clean(unsigned int no, int expired_only)
681 687
 	if (!expired_only){
682 688
 		for(h=start; h!=(start+DNS_HASH_SIZE); h++){
683 689
 			clist_foreach_safe(&dns_hash[h%DNS_HASH_SIZE], e, t, next){
684
-				_dns_hash_remove(e);
685
-				deleted++;
690
+				if ((e->ent_flags & DNS_FLAG_PERMANENT) == 0) {
691
+					_dns_hash_remove(e);
692
+					deleted++;
693
+				}
686 694
 				n++;
687 695
 				if (n>=no) goto skip;
688 696
 			}
... ...
@@ -724,7 +732,9 @@ inline static int dns_cache_free_mem(unsigned int target, int expired_only)
724 732
 		if (*dns_cache_mem_used<=target) break;
725 733
 		e=(struct dns_hash_entry*)(((char*)l)-
726 734
 				(char*)&((struct dns_hash_entry*)(0))->last_used_lst);
727
-		if (!expired_only || ((s_ticks_t)(now-e->expire)>=0)){
735
+		if (((e->ent_flags & DNS_FLAG_PERMANENT) == 0)
736
+			&& (!expired_only || ((s_ticks_t)(now-e->expire)>=0))
737
+		) {
728 738
 				_dns_hash_remove(e);
729 739
 				deleted++;
730 740
 		}
... ...
@@ -734,7 +744,9 @@ inline static int dns_cache_free_mem(unsigned int target, int expired_only)
734 744
 		clist_foreach_safe(&dns_hash[h%DNS_HASH_SIZE], e, t, next){
735 745
 			if (*dns_cache_mem_used<=target)
736 746
 				goto skip;
737
-			if  ((s_ticks_t)(now-e->expire)>=0){
747
+			if (((e->ent_flags & DNS_FLAG_PERMANENT) == 0)
748
+				&& ((s_ticks_t)(now-e->expire)>=0)
749
+			) {
738 750
 				_dns_hash_remove(e);
739 751
 				deleted++;
740 752
 			}
... ...
@@ -746,7 +758,9 @@ inline static int dns_cache_free_mem(unsigned int target, int expired_only)
746 758
 			clist_foreach_safe(&dns_hash[h%DNS_HASH_SIZE], e, t, next){
747 759
 				if (*dns_cache_mem_used<=target)
748 760
 					goto skip;
749
-				if  ((s_ticks_t)(now-e->expire)>=0){
761
+				if (((e->ent_flags & DNS_FLAG_PERMANENT) == 0)
762
+					&& ((s_ticks_t)(now-e->expire)>=0)
763
+				) {
750 764
 					_dns_hash_remove(e);
751 765
 					deleted++;
752 766
 				}
... ...
@@ -811,7 +825,7 @@ inline static int dns_cache_add(struct dns_hash_entry* e)
811 825
 	h=dns_hash_no(e->name, e->name_len, e->type);
812 826
 #ifdef DNS_CACHE_DEBUG
813 827
 	DBG("dns_cache_add: adding %.*s(%d) %d (flags=%0x) at %d\n",
814
-			e->name_len, e->name, e->name_len, e->type, e->err_flags, h);
828
+			e->name_len, e->name, e->name_len, e->type, e->ent_flags, h);
815 829
 #endif
816 830
 	LOCK_DNS_HASH();
817 831
 		*dns_cache_mem_used+=e->total_size; /* no need for atomic ops, written
... ...
@@ -853,7 +867,7 @@ inline static int dns_cache_add_unsafe(struct dns_hash_entry* e)
853 867
 	h=dns_hash_no(e->name, e->name_len, e->type);
854 868
 #ifdef DNS_CACHE_DEBUG
855 869
 	DBG("dns_cache_add: adding %.*s(%d) %d (flags=%0x) at %d\n",
856
-			e->name_len, e->name, e->name_len, e->type, e->err_flags, h);
870
+			e->name_len, e->name, e->name_len, e->type, e->ent_flags, h);
857 871
 #endif
858 872
 	*dns_cache_mem_used+=e->total_size; /* no need for atomic ops, written
859 873
 										 only from within a lock */
... ...
@@ -883,7 +897,7 @@ inline static struct dns_hash_entry* dns_cache_mk_bad_entry(str* name,
883 897
 	size=sizeof(struct dns_hash_entry)+name->len-1+1;
884 898
 	e=shm_malloc(size);
885 899
 	if (e==0){
886
-		LOG(L_ERR, "ERROR: dns_cache_mk_ip_entry: out of memory\n");
900
+		LOG(L_ERR, "ERROR: dns_cache_mk_bad_entry: out of memory\n");
887 901
 		return 0;
888 902
 	}
889 903
 	memset(e, 0, size); /* init with 0*/
... ...
@@ -894,7 +908,7 @@ inline static struct dns_hash_entry* dns_cache_mk_bad_entry(str* name,
894 908
 	e->last_used=now;
895 909
 	e->expire=now+S_TO_TICKS(ttl);
896 910
 	memcpy(e->name, name->s, name->len);
897
-	e->err_flags=flags;
911
+	e->ent_flags=flags;
898 912
 	return e;
899 913
 }
900 914
 
... ...
@@ -1234,7 +1248,7 @@ inline static struct dns_hash_entry* dns_cache_mk_rd_entry(str* name, int type,
1234 1248
 	size+=ROUND_POINTER(sizeof(struct dns_hash_entry)+name->len-1+1);
1235 1249
 	e=shm_malloc(size);
1236 1250
 	if (e==0){
1237
-		LOG(L_ERR, "ERROR: dns_cache_mk_ip_entry: out of memory\n");
1251
+		LOG(L_ERR, "ERROR: dns_cache_mk_rd_entry: out of memory\n");
1238 1252
 		return 0;
1239 1253
 	}
1240 1254
 	memset(e, 0, size); /* init with 0 */
... ...
@@ -1544,7 +1558,7 @@ found:
1544 1558
 	for (r=0; r<no_records; r++){
1545 1559
 		rec[r].e=shm_malloc(rec[r].size);
1546 1560
 		if (rec[r].e==0){
1547
-			LOG(L_ERR, "ERROR: dns_cache_mk_ip_entry: out of memory\n");
1561
+			LOG(L_ERR, "ERROR: dns_cache_mk_rd_entry: out of memory\n");
1548 1562
 			goto error;
1549 1563
 		}
1550 1564
 		memset(rec[r].e, 0, rec[r].size); /* init with 0*/
... ...
@@ -1951,7 +1965,7 @@ inline static struct dns_hash_entry* dns_cache_do_request(str* name, int type)
1951 1965
 		free_rdata_list(records);
1952 1966
 	}else if (cfg_get(core, core_cfg, dns_neg_cache_ttl)){
1953 1967
 		e=dns_cache_mk_bad_entry(name, type, 
1954
-				cfg_get(core, core_cfg, dns_neg_cache_ttl), DNS_BAD_NAME);
1968
+				cfg_get(core, core_cfg, dns_neg_cache_ttl), DNS_FLAG_BAD_NAME);
1955 1969
 		if (likely(e)) {
1956 1970
 			atomic_set(&e->refcnt, 1); /* 1 because we return a ref. to it */
1957 1971
 			dns_cache_add(e); /* refcnt++ inside*/
... ...
@@ -2028,10 +2042,12 @@ inline static struct dns_hash_entry* dns_get_entry(str* name, int type)
2028 2042
 	e=dns_hash_get(name, type, &h, &err);
2029 2043
 #ifdef USE_DNS_CACHE_STATS
2030 2044
 	if (e) {
2031
-		if (e->err_flags==DNS_BAD_NAME && dns_cache_stats)
2045
+		if ((e->ent_flags & DNS_FLAG_BAD_NAME) && dns_cache_stats)
2032 2046
 			/* negative DNS cache hit */
2033 2047
 			dns_cache_stats[process_no].dc_neg_hits_cnt++;
2034
-		else if (!e->err_flags && dns_cache_stats) /* DNS cache hit */
2048
+		else if (((e->ent_flags & DNS_FLAG_BAD_NAME) == 0)
2049
+				&& dns_cache_stats
2050
+		) /* DNS cache hit */
2035 2051
 			dns_cache_stats[process_no].dc_hits_cnt++;
2036 2052
 
2037 2053
 		if (dns_cache_stats)
... ...
@@ -2053,7 +2069,7 @@ inline static struct dns_hash_entry* dns_get_entry(str* name, int type)
2053 2069
 			goto error; /* could not resolve cname */
2054 2070
 	}
2055 2071
 	/* found */
2056
-	if ((e->rr_lst==0) || e->err_flags){
2072
+	if ((e->rr_lst==0) || (e->ent_flags & DNS_FLAG_BAD_NAME)){
2057 2073
 		/* negative cache => not resolvable */
2058 2074
 		dns_hash_put(e);
2059 2075
 		e=0;
... ...
@@ -2106,6 +2122,7 @@ inline static struct dns_rr* dns_entry_get_rr(	struct dns_hash_entry* e,
2106 2122
 			/* check the expiration time only when the servers are up */
2107 2123
 			servers_up &&
2108 2124
 #endif
2125
+			((e->ent_flags & DNS_FLAG_PERMANENT) == 0) &&
2109 2126
 			((s_ticks_t)(now-rr->expire)>=0) /* expired rr */
2110 2127
 		)
2111 2128
 			continue;
... ...
@@ -2208,6 +2225,7 @@ retry:
2208 2225
 			/* check the expiration time only when the servers are up */
2209 2226
 			servers_up &&
2210 2227
 #endif
2228
+			((e->ent_flags & DNS_FLAG_PERMANENT) == 0) &&
2211 2229
 			((s_ticks_t)(now-rr->expire)>=0) /* expired entry */) ||
2212 2230
 				(rr->err_flags) /* bad rr */ ||
2213 2231
 				(srv_marked(tried, idx)) ) /* already tried */{
... ...
@@ -3516,7 +3534,7 @@ void dns_cache_debug(rpc_t* rpc, void* ctx)
3516 3534
 								(s_ticks_t)(e->expire-now)<0?-1:
3517 3535
 									TICKS_TO_S(e->expire-now),
3518 3536
 								TICKS_TO_S(now-e->last_used),
3519
-								e->err_flags);
3537
+								e->ent_flags);
3520 3538
 			}
3521 3539
 		}
3522 3540
 	UNLOCK_DNS_HASH();
... ...
@@ -3632,7 +3650,7 @@ void dns_cache_debug_all(rpc_t* rpc, void* ctx)
3632 3650
 								(int)(s_ticks_t)(e->expire-now)<0?-1:
3633 3651
 									TICKS_TO_S(e->expire-now),
3634 3652
 								(int)TICKS_TO_S(now-e->last_used),
3635
-								(int)e->err_flags);
3653
+								(int)e->ent_flags);
3636 3654
 					switch(e->type){
3637 3655
 						case T_A:
3638 3656
 						case T_AAAA:
... ...
@@ -3773,10 +3791,16 @@ void dns_cache_print_entry(rpc_t* rpc, void* ctx, struct dns_hash_entry* e)
3773 3791
 						e->total_size);
3774 3792
 	rpc->printf(ctx, "%sreference counter: %d", SPACE_FORMAT,
3775 3793
 						e->refcnt.val);
3776
-	rpc->printf(ctx, "%sexpires in (s): %d", SPACE_FORMAT, expires);
3794
+	if (e->ent_flags & DNS_FLAG_PERMANENT) {
3795
+		rpc->printf(ctx, "%spermanent: yes", SPACE_FORMAT);
3796
+	} else {
3797
+		rpc->printf(ctx, "%spermanent: no", SPACE_FORMAT);
3798
+		rpc->printf(ctx, "%sexpires in (s): %d", SPACE_FORMAT, expires);
3799
+	}
3777 3800
 	rpc->printf(ctx, "%slast used (s): %d", SPACE_FORMAT,
3778 3801
 						TICKS_TO_S(now-e->last_used));
3779
-	rpc->printf(ctx, "%serror flags: %d", SPACE_FORMAT, e->err_flags);
3802
+	rpc->printf(ctx, "%snegative entry: %s", SPACE_FORMAT,
3803
+						(e->ent_flags & DNS_FLAG_BAD_NAME) ? "yes" : "no");
3780 3804
 	
3781 3805
 	for (rr=e->rr_lst; rr; rr=rr->next) {
3782 3806
 		switch(e->type) {
... ...
@@ -3874,7 +3898,9 @@ void dns_cache_view(rpc_t* rpc, void* ctx)
3874 3898
 	LOCK_DNS_HASH();
3875 3899
 	for (h=0; h<DNS_HASH_SIZE; h++){
3876 3900
 		clist_foreach(&dns_hash[h], e, next){
3877
-			if (TICKS_LT(e->expire, now)) {
3901
+			if (((e->ent_flags & DNS_FLAG_PERMANENT) == 0)
3902
+				&& TICKS_LT(e->expire, now)
3903
+			) {
3878 3904
 				continue;
3879 3905
 			}
3880 3906
 			rpc->printf(ctx, "{\n");
... ...
@@ -3886,8 +3912,11 @@ void dns_cache_view(rpc_t* rpc, void* ctx)
3886 3912
 }
3887 3913
 
3888 3914
 
3889
-/* deletes all the entries from the cache */
3890
-void dns_cache_flush(void)
3915
+/* Delete all the entries from the cache.
3916
+ * If del_permanent is 0, then only the
3917
+ * non-permanent entries are deleted.
3918
+ */
3919
+void dns_cache_flush(int del_permanent)
3891 3920
 {
3892 3921
 	int h;
3893 3922
 	struct dns_hash_entry* e;
... ...
@@ -3897,20 +3926,32 @@ void dns_cache_flush(void)
3897 3926
 	LOCK_DNS_HASH();
3898 3927
 		for (h=0; h<DNS_HASH_SIZE; h++){
3899 3928
 			clist_foreach_safe(&dns_hash[h], e, tmp, next){
3900
-				_dns_hash_remove(e);
3929
+				if (del_permanent || ((e->ent_flags & DNS_FLAG_PERMANENT) == 0))
3930
+					_dns_hash_remove(e);
3901 3931
 			}
3902 3932
 		}
3903 3933
 	UNLOCK_DNS_HASH();
3904 3934
 }
3905 3935
 
3906
-/* deletes all the entries from the cache */
3936
+/* deletes all the non-permanent entries from the cache */
3907 3937
 void dns_cache_delete_all(rpc_t* rpc, void* ctx)
3908 3938
 {
3909 3939
 	if (!cfg_get(core, core_cfg, use_dns_cache)){
3910 3940
 		rpc->fault(ctx, 500, "dns cache support disabled (see use_dns_cache)");
3911 3941
 		return;
3912 3942
 	}
3913
-	dns_cache_flush();
3943
+	dns_cache_flush(0);
3944
+}
3945
+
3946
+/* deletes all the entries from the cache,
3947
+ * even the permanent ones */
3948
+void dns_cache_delete_all_force(rpc_t* rpc, void* ctx)
3949
+{
3950
+	if (!cfg_get(core, core_cfg, use_dns_cache)){
3951
+		rpc->fault(ctx, 500, "dns cache support disabled (see use_dns_cache)");
3952
+		return;
3953
+	}
3954
+	dns_cache_flush(1);
3914 3955
 }
3915 3956
 
3916 3957
 /* clones an entry and extends its memory area to hold a new rr.
... ...
@@ -4063,6 +4104,10 @@ static struct dns_hash_entry *dns_cache_clone_entry(struct dns_hash_entry *e,
4063 4104
  * If there is an existing record with the same name and value
4064 4105
  * (ip address in case of A/AAAA record, name in case of SRV record)
4065 4106
  * only the remaining fields are updated.
4107
+ * 
4108
+ * Note that permanent records cannot be overwritten unless
4109
+ * the new record is also permanent. A permanent record
4110
+ * completely replaces a non-permanent one.
4066 4111
  *
4067 4112
  * Currently only A, AAAA, and SRV records are supported.
4068 4113
  */
... ...
@@ -4100,7 +4145,7 @@ int dns_cache_add_record(unsigned short type,
4100 4145
 		return -1;
4101 4146
 	}
4102 4147
 
4103
-	if (!flags) {
4148
+	if ((flags & DNS_FLAG_BAD_NAME) == 0) {
4104 4149
 		/* fix-up the values */
4105 4150
 		switch(type) {
4106 4151
 		case T_A:
... ...
@@ -4139,8 +4184,16 @@ int dns_cache_add_record(unsigned short type,
4139 4184
 		old=NULL;
4140 4185
 	}
4141 4186
 
4187
+	if (old
4188
+		&& (old->ent_flags & DNS_FLAG_PERMANENT)
4189
+		&& ((flags & DNS_FLAG_PERMANENT) == 0)
4190
+	) {
4191
+		LOG(L_ERR, "ERROR: A non-permanent record cannot overwrite "
4192
+				"a permanent entry\n");
4193
+		goto error;
4194
+	}
4142 4195
 	/* prepare the entry */
4143
-	if (flags) {
4196
+	if (flags & DNS_FLAG_BAD_NAME) {
4144 4197
 		/* negative entry */
4145 4198
 		new = dns_cache_mk_bad_entry(name, type, ttl, flags);
4146 4199
 		if (!new) {
... ...
@@ -4149,10 +4202,16 @@ int dns_cache_add_record(unsigned short type,
4149 4202
 			goto error;
4150 4203
 		}
4151 4204
 	} else {
4152
-		if (!old || old->err_flags) {
4153
-			/* there was no matching entry in the hash table,
4154
-			or the entry is a negative record with inefficient space,
4155
-			let us create a new one */
4205
+		if (!old
4206
+			|| (old->ent_flags & DNS_FLAG_BAD_NAME)
4207
+			|| (((old->ent_flags & DNS_FLAG_PERMANENT) == 0)
4208
+				&& (flags & DNS_FLAG_PERMANENT))
4209
+		) {
4210
+			/* There was no matching entry in the hash table,
4211
+			 * the entry is a negative record with inefficient space,
4212
+			 * or a permanent entry overwrites a non-permanent one.
4213
+			 * Let us create a new one.
4214
+			 */
4156 4215
 			switch(type) {
4157 4216
 			case T_A:
4158 4217
 			case T_AAAA:
... ...
@@ -4175,6 +4234,7 @@ int dns_cache_add_record(unsigned short type,
4175 4234
 					goto error;
4176 4235
 				}
4177 4236
 			}
4237
+			new->ent_flags = flags;
4178 4238
 		} else {
4179 4239
 			/* we must modify the entry, so better to clone it, modify the new 
4180 4240
 			 * one, and replace the old with the new entry in the hash table,
... ...
@@ -4289,7 +4349,7 @@ static void dns_cache_delete_record(rpc_t* rpc, void* ctx, unsigned short type)
4289 4349
 {
4290 4350
 	struct dns_hash_entry *e;
4291 4351
 	str name;
4292
-	int err, h, found=0;
4352
+	int err, h, found=0, permanent=0;
4293 4353
 
4294 4354
 	if (!cfg_get(core, core_cfg, use_dns_cache)){
4295 4355
 		rpc->fault(ctx, 500, "dns cache support disabled (see use_dns_cache)");
... ...
@@ -4303,12 +4363,17 @@ static void dns_cache_delete_record(rpc_t* rpc, void* ctx, unsigned short type)
4303 4363
 
4304 4364
 	e=_dns_hash_find(&name, type, &h, &err);
4305 4365
 	if (e && (e->type==type)) {
4306
-		_dns_hash_remove(e);
4366
+		if ((e->ent_flags & DNS_FLAG_PERMANENT) == 0)
4367
+			_dns_hash_remove(e);
4368
+		else
4369
+			permanent = 1;
4307 4370
 		found = 1;
4308 4371
 	}
4309 4372
 
4310 4373
 	UNLOCK_DNS_HASH();
4311 4374
 
4375
+	if (permanent)
4376
+		rpc->fault(ctx, 400, "Permanent entries cannot be deleted");
4312 4377
 	if (!found)
4313 4378
 		rpc->fault(ctx, 400, "Not found");
4314 4379
 }
... ...
@@ -4346,7 +4411,7 @@ int dns_cache_delete_single_record(unsigned short type,
4346 4411
 		return -1;
4347 4412
 	}
4348 4413
 
4349
-	if (!flags) {
4414
+	if ((flags & DNS_FLAG_BAD_NAME) == 0) {
4350 4415
 		/* fix-up the values */
4351 4416
 		switch(type) {
4352 4417
 		case T_A:
... ...
@@ -4381,11 +4446,11 @@ int dns_cache_delete_single_record(unsigned short type,
4381 4446
 		goto not_found;
4382 4447
 
4383 4448
 	if ((old->type != type) /* may be CNAME */
4384
-		|| (old->err_flags != flags)
4449
+		|| (old->ent_flags != flags)
4385 4450
 	)
4386 4451
 		goto not_found;
4387 4452
 
4388
-	if (flags) /* negative record, there is no value */
4453
+	if (flags && DNS_FLAG_BAD_NAME) /* negative record, there is no value */
4389 4454
 		goto delete;
4390 4455
 
4391 4456
 	/* check whether there is an rr with the same value */
... ...
@@ -100,8 +100,14 @@ enum dns_errors{
100 100
 /** @brief return a short string, printable error description (err <=0) */
101 101
 const char* dns_strerror(int err);
102 102
 
103
-/** @brief dns entry error flags */
104
-#define DNS_BAD_NAME     1 /* unresolvable */
103
+/** @brief dns entry flags,
104
+ * shall be on the power of 2 */
105
+/*@{ */
106
+#define DNS_FLAG_BAD_NAME	1 /**< error flag: unresolvable */
107
+#define DNS_FLAG_PERMANENT	2 /**< permanent record, never times out,
108
+					never deleted, never overwritten
109
+					unless explicitely requested */
110
+/*@} */
105 111
 
106 112
 /** @name dns requests flags */
107 113
 /*@{ */
... ...
@@ -155,7 +161,7 @@ struct dns_hash_entry{
155 161
 	ticks_t expire; /* when the whole entry will expire */
156 162
 	int total_size;
157 163
 	unsigned short type;
158
-	unsigned char err_flags;
164
+	unsigned char ent_flags; /* entry flags: unresolvable/permanent */
159 165
 	unsigned char name_len; /* can be maximum 255 bytes */
160 166
 	char name[1]; /* variable length, name, null terminated
161 167
 	                 (actual lenght = name_len +1)*/
... ...
@@ -336,8 +342,11 @@ inline static int dns_sip_resolve2su(struct dns_srv_handle* h,
336 342
 	return ret;
337 343
 }
338 344
 
339
-/** @brief deletes all the entries from the cache */
340
-void dns_cache_flush(void);
345
+/** @brief Delete all the entries from the cache.
346
+ * If del_permanent is 0, then only the
347
+ * non-permanent entries are deleted.
348
+ */
349
+void dns_cache_flush(int del_permanent);
341 350
 
342 351
 #ifdef DNS_WATCHDOG_SUPPORT
343 352
 /** @brief sets the state of the DNS servers:
... ...
@@ -355,6 +364,10 @@ int dns_get_server_state(void);
355 364
  * (ip address in case of A/AAAA record, name in case of SRV record)
356 365
  * only the remaining fields are updated.
357 366
  *
367
+ * Note that permanent records cannot be overwritten unless
368
+ * the new record is also permanent. A permanent record
369
+ * completely replaces a non-permanent one.
370
+ *
358 371
  * Currently only A, AAAA, and SRV records are supported.
359 372
  */
360 373
 int dns_cache_add_record(unsigned short type,