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 94
 };
95 95
 
96 96
 static const char* dns_cache_delete_all_doc[] = {
97
-	"deletes all the entries from the DNS cache",
97
+	"deletes all the non-permanent entries from the DNS cache",
98
+	0
99
+};
100
+
101
+static const char* dns_cache_delete_all_force_doc[] = {
102
+	"deletes all the entries from the DNS cache including the permanent ones",
98 103
 	0
99 104
 };
100 105
 
... ...
@@ -848,6 +854,8 @@ static rpc_export_t core_rpc_methods[] = {
848 848
 		0	},
849 849
 	{"dns.delete_all",         dns_cache_delete_all,  dns_cache_delete_all_doc,
850 850
 		0	},
851
+	{"dns.delete_all_force",   dns_cache_delete_all_force, dns_cache_delete_all_force_doc,
852
+		0	},
851 853
 	{"dns.add_a",              dns_cache_add_a,       dns_cache_add_a_doc,
852 854
 		0	},
853 855
 	{"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 591
 #endif
592 592
 #endif
593 593
 			return e;
594
-		}else if ((e->type==T_CNAME) && !((e->rr_lst==0) || e->err_flags) &&
594
+		}else if ((e->type==T_CNAME) &&
595
+					!((e->rr_lst==0) || (e->ent_flags & DNS_FLAG_BAD_NAME)) &&
595 596
 					(e->name_len==name->len) &&
596 597
 					(strncasecmp(e->name, name->s, e->name_len)==0)){
597 598
 			/*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 659
 	clist_foreach_safe(dns_last_used_lst, l, tmp, next){
660 660
 		e=(struct dns_hash_entry*)(((char*)l)-
661 661
 				(char*)&((struct dns_hash_entry*)(0))->last_used_lst);
662
-		if (!expired_only || ((s_ticks_t)(now-e->expire)>=0)){
662
+		if (((e->ent_flags & DNS_FLAG_PERMANENT) == 0)
663
+			&& (!expired_only || ((s_ticks_t)(now-e->expire)>=0))
664
+		) {
663 665
 				_dns_hash_remove(e);
664 666
 				deleted++;
665 667
 		}
... ...
@@ -669,7 +673,9 @@ inline static int dns_cache_clean(unsigned int no, int expired_only)
669 669
 #else
670 670
 	for(h=start; h!=(start+DNS_HASH_SIZE); h++){
671 671
 		clist_foreach_safe(&dns_hash[h%DNS_HASH_SIZE], e, t, next){
672
-			if  ((s_ticks_t)(now-e->expire)>=0){
672
+			if (((e->ent_flags & DNS_FLAG_PERMANENT) == 0)
673
+				&& ((s_ticks_t)(now-e->expire)>=0)
674
+			) {
673 675
 				_dns_hash_remove(e);
674 676
 				deleted++;
675 677
 			}
... ...
@@ -681,8 +687,10 @@ inline static int dns_cache_clean(unsigned int no, int expired_only)
681 681
 	if (!expired_only){
682 682
 		for(h=start; h!=(start+DNS_HASH_SIZE); h++){
683 683
 			clist_foreach_safe(&dns_hash[h%DNS_HASH_SIZE], e, t, next){
684
-				_dns_hash_remove(e);
685
-				deleted++;
684
+				if ((e->ent_flags & DNS_FLAG_PERMANENT) == 0) {
685
+					_dns_hash_remove(e);
686
+					deleted++;
687
+				}
686 688
 				n++;
687 689
 				if (n>=no) goto skip;
688 690
 			}
... ...
@@ -724,7 +732,9 @@ inline static int dns_cache_free_mem(unsigned int target, int expired_only)
724 724
 		if (*dns_cache_mem_used<=target) break;
725 725
 		e=(struct dns_hash_entry*)(((char*)l)-
726 726
 				(char*)&((struct dns_hash_entry*)(0))->last_used_lst);
727
-		if (!expired_only || ((s_ticks_t)(now-e->expire)>=0)){
727
+		if (((e->ent_flags & DNS_FLAG_PERMANENT) == 0)
728
+			&& (!expired_only || ((s_ticks_t)(now-e->expire)>=0))
729
+		) {
728 730
 				_dns_hash_remove(e);
729 731
 				deleted++;
730 732
 		}
... ...
@@ -734,7 +744,9 @@ inline static int dns_cache_free_mem(unsigned int target, int expired_only)
734 734
 		clist_foreach_safe(&dns_hash[h%DNS_HASH_SIZE], e, t, next){
735 735
 			if (*dns_cache_mem_used<=target)
736 736
 				goto skip;
737
-			if  ((s_ticks_t)(now-e->expire)>=0){
737
+			if (((e->ent_flags & DNS_FLAG_PERMANENT) == 0)
738
+				&& ((s_ticks_t)(now-e->expire)>=0)
739
+			) {
738 740
 				_dns_hash_remove(e);
739 741
 				deleted++;
740 742
 			}
... ...
@@ -746,7 +758,9 @@ inline static int dns_cache_free_mem(unsigned int target, int expired_only)
746 746
 			clist_foreach_safe(&dns_hash[h%DNS_HASH_SIZE], e, t, next){
747 747
 				if (*dns_cache_mem_used<=target)
748 748
 					goto skip;
749
-				if  ((s_ticks_t)(now-e->expire)>=0){
749
+				if (((e->ent_flags & DNS_FLAG_PERMANENT) == 0)
750
+					&& ((s_ticks_t)(now-e->expire)>=0)
751
+				) {
750 752
 					_dns_hash_remove(e);
751 753
 					deleted++;
752 754
 				}
... ...
@@ -811,7 +825,7 @@ inline static int dns_cache_add(struct dns_hash_entry* e)
811 811
 	h=dns_hash_no(e->name, e->name_len, e->type);
812 812
 #ifdef DNS_CACHE_DEBUG
813 813
 	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);
814
+			e->name_len, e->name, e->name_len, e->type, e->ent_flags, h);
815 815
 #endif
816 816
 	LOCK_DNS_HASH();
817 817
 		*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 853
 	h=dns_hash_no(e->name, e->name_len, e->type);
854 854
 #ifdef DNS_CACHE_DEBUG
855 855
 	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);
856
+			e->name_len, e->name, e->name_len, e->type, e->ent_flags, h);
857 857
 #endif
858 858
 	*dns_cache_mem_used+=e->total_size; /* no need for atomic ops, written
859 859
 										 only from within a lock */
... ...
@@ -883,7 +897,7 @@ inline static struct dns_hash_entry* dns_cache_mk_bad_entry(str* name,
883 883
 	size=sizeof(struct dns_hash_entry)+name->len-1+1;
884 884
 	e=shm_malloc(size);
885 885
 	if (e==0){
886
-		LOG(L_ERR, "ERROR: dns_cache_mk_ip_entry: out of memory\n");
886
+		LOG(L_ERR, "ERROR: dns_cache_mk_bad_entry: out of memory\n");
887 887
 		return 0;
888 888
 	}
889 889
 	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 894
 	e->last_used=now;
895 895
 	e->expire=now+S_TO_TICKS(ttl);
896 896
 	memcpy(e->name, name->s, name->len);
897
-	e->err_flags=flags;
897
+	e->ent_flags=flags;
898 898
 	return e;
899 899
 }
900 900
 
... ...
@@ -1234,7 +1248,7 @@ inline static struct dns_hash_entry* dns_cache_mk_rd_entry(str* name, int type,
1234 1234
 	size+=ROUND_POINTER(sizeof(struct dns_hash_entry)+name->len-1+1);
1235 1235
 	e=shm_malloc(size);
1236 1236
 	if (e==0){
1237
-		LOG(L_ERR, "ERROR: dns_cache_mk_ip_entry: out of memory\n");
1237
+		LOG(L_ERR, "ERROR: dns_cache_mk_rd_entry: out of memory\n");
1238 1238
 		return 0;
1239 1239
 	}
1240 1240
 	memset(e, 0, size); /* init with 0 */
... ...
@@ -1544,7 +1558,7 @@ found:
1544 1544
 	for (r=0; r<no_records; r++){
1545 1545
 		rec[r].e=shm_malloc(rec[r].size);
1546 1546
 		if (rec[r].e==0){
1547
-			LOG(L_ERR, "ERROR: dns_cache_mk_ip_entry: out of memory\n");
1547
+			LOG(L_ERR, "ERROR: dns_cache_mk_rd_entry: out of memory\n");
1548 1548
 			goto error;
1549 1549
 		}
1550 1550
 		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 1951
 		free_rdata_list(records);
1952 1952
 	}else if (cfg_get(core, core_cfg, dns_neg_cache_ttl)){
1953 1953
 		e=dns_cache_mk_bad_entry(name, type, 
1954
-				cfg_get(core, core_cfg, dns_neg_cache_ttl), DNS_BAD_NAME);
1954
+				cfg_get(core, core_cfg, dns_neg_cache_ttl), DNS_FLAG_BAD_NAME);
1955 1955
 		if (likely(e)) {
1956 1956
 			atomic_set(&e->refcnt, 1); /* 1 because we return a ref. to it */
1957 1957
 			dns_cache_add(e); /* refcnt++ inside*/
... ...
@@ -2028,10 +2042,12 @@ inline static struct dns_hash_entry* dns_get_entry(str* name, int type)
2028 2028
 	e=dns_hash_get(name, type, &h, &err);
2029 2029
 #ifdef USE_DNS_CACHE_STATS
2030 2030
 	if (e) {
2031
-		if (e->err_flags==DNS_BAD_NAME && dns_cache_stats)
2031
+		if ((e->ent_flags & DNS_FLAG_BAD_NAME) && dns_cache_stats)
2032 2032
 			/* negative DNS cache hit */
2033 2033
 			dns_cache_stats[process_no].dc_neg_hits_cnt++;
2034
-		else if (!e->err_flags && dns_cache_stats) /* DNS cache hit */
2034
+		else if (((e->ent_flags & DNS_FLAG_BAD_NAME) == 0)
2035
+				&& dns_cache_stats
2036
+		) /* DNS cache hit */
2035 2037
 			dns_cache_stats[process_no].dc_hits_cnt++;
2036 2038
 
2037 2039
 		if (dns_cache_stats)
... ...
@@ -2053,7 +2069,7 @@ inline static struct dns_hash_entry* dns_get_entry(str* name, int type)
2053 2053
 			goto error; /* could not resolve cname */
2054 2054
 	}
2055 2055
 	/* found */
2056
-	if ((e->rr_lst==0) || e->err_flags){
2056
+	if ((e->rr_lst==0) || (e->ent_flags & DNS_FLAG_BAD_NAME)){
2057 2057
 		/* negative cache => not resolvable */
2058 2058
 		dns_hash_put(e);
2059 2059
 		e=0;
... ...
@@ -2106,6 +2122,7 @@ inline static struct dns_rr* dns_entry_get_rr(	struct dns_hash_entry* e,
2106 2106
 			/* check the expiration time only when the servers are up */
2107 2107
 			servers_up &&
2108 2108
 #endif
2109
+			((e->ent_flags & DNS_FLAG_PERMANENT) == 0) &&
2109 2110
 			((s_ticks_t)(now-rr->expire)>=0) /* expired rr */
2110 2111
 		)
2111 2112
 			continue;
... ...
@@ -2208,6 +2225,7 @@ retry:
2208 2208
 			/* check the expiration time only when the servers are up */
2209 2209
 			servers_up &&
2210 2210
 #endif
2211
+			((e->ent_flags & DNS_FLAG_PERMANENT) == 0) &&
2211 2212
 			((s_ticks_t)(now-rr->expire)>=0) /* expired entry */) ||
2212 2213
 				(rr->err_flags) /* bad rr */ ||
2213 2214
 				(srv_marked(tried, idx)) ) /* already tried */{
... ...
@@ -3516,7 +3534,7 @@ void dns_cache_debug(rpc_t* rpc, void* ctx)
3516 3516
 								(s_ticks_t)(e->expire-now)<0?-1:
3517 3517
 									TICKS_TO_S(e->expire-now),
3518 3518
 								TICKS_TO_S(now-e->last_used),
3519
-								e->err_flags);
3519
+								e->ent_flags);
3520 3520
 			}
3521 3521
 		}
3522 3522
 	UNLOCK_DNS_HASH();
... ...
@@ -3632,7 +3650,7 @@ void dns_cache_debug_all(rpc_t* rpc, void* ctx)
3632 3632
 								(int)(s_ticks_t)(e->expire-now)<0?-1:
3633 3633
 									TICKS_TO_S(e->expire-now),
3634 3634
 								(int)TICKS_TO_S(now-e->last_used),
3635
-								(int)e->err_flags);
3635
+								(int)e->ent_flags);
3636 3636
 					switch(e->type){
3637 3637
 						case T_A:
3638 3638
 						case T_AAAA:
... ...
@@ -3773,10 +3791,16 @@ void dns_cache_print_entry(rpc_t* rpc, void* ctx, struct dns_hash_entry* e)
3773 3773
 						e->total_size);
3774 3774
 	rpc->printf(ctx, "%sreference counter: %d", SPACE_FORMAT,
3775 3775
 						e->refcnt.val);
3776
-	rpc->printf(ctx, "%sexpires in (s): %d", SPACE_FORMAT, expires);
3776
+	if (e->ent_flags & DNS_FLAG_PERMANENT) {
3777
+		rpc->printf(ctx, "%spermanent: yes", SPACE_FORMAT);
3778
+	} else {
3779
+		rpc->printf(ctx, "%spermanent: no", SPACE_FORMAT);
3780
+		rpc->printf(ctx, "%sexpires in (s): %d", SPACE_FORMAT, expires);
3781
+	}
3777 3782
 	rpc->printf(ctx, "%slast used (s): %d", SPACE_FORMAT,
3778 3783
 						TICKS_TO_S(now-e->last_used));
3779
-	rpc->printf(ctx, "%serror flags: %d", SPACE_FORMAT, e->err_flags);
3784
+	rpc->printf(ctx, "%snegative entry: %s", SPACE_FORMAT,
3785
+						(e->ent_flags & DNS_FLAG_BAD_NAME) ? "yes" : "no");
3780 3786
 	
3781 3787
 	for (rr=e->rr_lst; rr; rr=rr->next) {
3782 3788
 		switch(e->type) {
... ...
@@ -3874,7 +3898,9 @@ void dns_cache_view(rpc_t* rpc, void* ctx)
3874 3874
 	LOCK_DNS_HASH();
3875 3875
 	for (h=0; h<DNS_HASH_SIZE; h++){
3876 3876
 		clist_foreach(&dns_hash[h], e, next){
3877
-			if (TICKS_LT(e->expire, now)) {
3877
+			if (((e->ent_flags & DNS_FLAG_PERMANENT) == 0)
3878
+				&& TICKS_LT(e->expire, now)
3879
+			) {
3878 3880
 				continue;
3879 3881
 			}
3880 3882
 			rpc->printf(ctx, "{\n");
... ...
@@ -3886,8 +3912,11 @@ void dns_cache_view(rpc_t* rpc, void* ctx)
3886 3886
 }
3887 3887
 
3888 3888
 
3889
-/* deletes all the entries from the cache */
3890
-void dns_cache_flush(void)
3889
+/* Delete all the entries from the cache.
3890
+ * If del_permanent is 0, then only the
3891
+ * non-permanent entries are deleted.
3892
+ */
3893
+void dns_cache_flush(int del_permanent)
3891 3894
 {
3892 3895
 	int h;
3893 3896
 	struct dns_hash_entry* e;
... ...
@@ -3897,20 +3926,32 @@ void dns_cache_flush(void)
3897 3897
 	LOCK_DNS_HASH();
3898 3898
 		for (h=0; h<DNS_HASH_SIZE; h++){
3899 3899
 			clist_foreach_safe(&dns_hash[h], e, tmp, next){
3900
-				_dns_hash_remove(e);
3900
+				if (del_permanent || ((e->ent_flags & DNS_FLAG_PERMANENT) == 0))
3901
+					_dns_hash_remove(e);
3901 3902
 			}
3902 3903
 		}
3903 3904
 	UNLOCK_DNS_HASH();
3904 3905
 }
3905 3906
 
3906
-/* deletes all the entries from the cache */
3907
+/* deletes all the non-permanent entries from the cache */
3907 3908
 void dns_cache_delete_all(rpc_t* rpc, void* ctx)
3908 3909
 {
3909 3910
 	if (!cfg_get(core, core_cfg, use_dns_cache)){
3910 3911
 		rpc->fault(ctx, 500, "dns cache support disabled (see use_dns_cache)");
3911 3912
 		return;
3912 3913
 	}
3913
-	dns_cache_flush();
3914
+	dns_cache_flush(0);
3915
+}
3916
+
3917
+/* deletes all the entries from the cache,
3918
+ * even the permanent ones */
3919
+void dns_cache_delete_all_force(rpc_t* rpc, void* ctx)
3920
+{
3921
+	if (!cfg_get(core, core_cfg, use_dns_cache)){
3922
+		rpc->fault(ctx, 500, "dns cache support disabled (see use_dns_cache)");
3923
+		return;
3924
+	}
3925
+	dns_cache_flush(1);
3914 3926
 }
3915 3927
 
3916 3928
 /* 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 4063
  * If there is an existing record with the same name and value
4064 4064
  * (ip address in case of A/AAAA record, name in case of SRV record)
4065 4065
  * only the remaining fields are updated.
4066
+ * 
4067
+ * Note that permanent records cannot be overwritten unless
4068
+ * the new record is also permanent. A permanent record
4069
+ * completely replaces a non-permanent one.
4066 4070
  *
4067 4071
  * Currently only A, AAAA, and SRV records are supported.
4068 4072
  */
... ...
@@ -4100,7 +4145,7 @@ int dns_cache_add_record(unsigned short type,
4100 4100
 		return -1;
4101 4101
 	}
4102 4102
 
4103
-	if (!flags) {
4103
+	if ((flags & DNS_FLAG_BAD_NAME) == 0) {
4104 4104
 		/* fix-up the values */
4105 4105
 		switch(type) {
4106 4106
 		case T_A:
... ...
@@ -4139,8 +4184,16 @@ int dns_cache_add_record(unsigned short type,
4139 4139
 		old=NULL;
4140 4140
 	}
4141 4141
 
4142
+	if (old
4143
+		&& (old->ent_flags & DNS_FLAG_PERMANENT)
4144
+		&& ((flags & DNS_FLAG_PERMANENT) == 0)
4145
+	) {
4146
+		LOG(L_ERR, "ERROR: A non-permanent record cannot overwrite "
4147
+				"a permanent entry\n");
4148
+		goto error;
4149
+	}
4142 4150
 	/* prepare the entry */
4143
-	if (flags) {
4151
+	if (flags & DNS_FLAG_BAD_NAME) {
4144 4152
 		/* negative entry */
4145 4153
 		new = dns_cache_mk_bad_entry(name, type, ttl, flags);
4146 4154
 		if (!new) {
... ...
@@ -4149,10 +4202,16 @@ int dns_cache_add_record(unsigned short type,
4149 4149
 			goto error;
4150 4150
 		}
4151 4151
 	} 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 */
4152
+		if (!old
4153
+			|| (old->ent_flags & DNS_FLAG_BAD_NAME)
4154
+			|| (((old->ent_flags & DNS_FLAG_PERMANENT) == 0)
4155
+				&& (flags & DNS_FLAG_PERMANENT))
4156
+		) {
4157
+			/* There was no matching entry in the hash table,
4158
+			 * the entry is a negative record with inefficient space,
4159
+			 * or a permanent entry overwrites a non-permanent one.
4160
+			 * Let us create a new one.
4161
+			 */
4156 4162
 			switch(type) {
4157 4163
 			case T_A:
4158 4164
 			case T_AAAA:
... ...
@@ -4175,6 +4234,7 @@ int dns_cache_add_record(unsigned short type,
4175 4175
 					goto error;
4176 4176
 				}
4177 4177
 			}
4178
+			new->ent_flags = flags;
4178 4179
 		} else {
4179 4180
 			/* we must modify the entry, so better to clone it, modify the new 
4180 4181
 			 * 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 4289
 {
4290 4290
 	struct dns_hash_entry *e;
4291 4291
 	str name;
4292
-	int err, h, found=0;
4292
+	int err, h, found=0, permanent=0;
4293 4293
 
4294 4294
 	if (!cfg_get(core, core_cfg, use_dns_cache)){
4295 4295
 		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 4303
 
4304 4304
 	e=_dns_hash_find(&name, type, &h, &err);
4305 4305
 	if (e && (e->type==type)) {
4306
-		_dns_hash_remove(e);
4306
+		if ((e->ent_flags & DNS_FLAG_PERMANENT) == 0)
4307
+			_dns_hash_remove(e);
4308
+		else
4309
+			permanent = 1;
4307 4310
 		found = 1;
4308 4311
 	}
4309 4312
 
4310 4313
 	UNLOCK_DNS_HASH();
4311 4314
 
4315
+	if (permanent)
4316
+		rpc->fault(ctx, 400, "Permanent entries cannot be deleted");
4312 4317
 	if (!found)
4313 4318
 		rpc->fault(ctx, 400, "Not found");
4314 4319
 }
... ...
@@ -4346,7 +4411,7 @@ int dns_cache_delete_single_record(unsigned short type,
4346 4346
 		return -1;
4347 4347
 	}
4348 4348
 
4349
-	if (!flags) {
4349
+	if ((flags & DNS_FLAG_BAD_NAME) == 0) {
4350 4350
 		/* fix-up the values */
4351 4351
 		switch(type) {
4352 4352
 		case T_A:
... ...
@@ -4381,11 +4446,11 @@ int dns_cache_delete_single_record(unsigned short type,
4381 4381
 		goto not_found;
4382 4382
 
4383 4383
 	if ((old->type != type) /* may be CNAME */
4384
-		|| (old->err_flags != flags)
4384
+		|| (old->ent_flags != flags)
4385 4385
 	)
4386 4386
 		goto not_found;
4387 4387
 
4388
-	if (flags) /* negative record, there is no value */
4388
+	if (flags && DNS_FLAG_BAD_NAME) /* negative record, there is no value */
4389 4389
 		goto delete;
4390 4390
 
4391 4391
 	/* 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 155
 	ticks_t expire; /* when the whole entry will expire */
156 156
 	int total_size;
157 157
 	unsigned short type;
158
-	unsigned char err_flags;
158
+	unsigned char ent_flags; /* entry flags: unresolvable/permanent */
159 159
 	unsigned char name_len; /* can be maximum 255 bytes */
160 160
 	char name[1]; /* variable length, name, null terminated
161 161
 	                 (actual lenght = name_len +1)*/
... ...
@@ -336,8 +342,11 @@ inline static int dns_sip_resolve2su(struct dns_srv_handle* h,
336 336
 	return ret;
337 337
 }
338 338
 
339
-/** @brief deletes all the entries from the cache */
340
-void dns_cache_flush(void);
339
+/** @brief Delete all the entries from the cache.
340
+ * If del_permanent is 0, then only the
341
+ * non-permanent entries are deleted.
342
+ */
343
+void dns_cache_flush(int del_permanent);
341 344
 
342 345
 #ifdef DNS_WATCHDOG_SUPPORT
343 346
 /** @brief sets the state of the DNS servers:
... ...
@@ -355,6 +364,10 @@ int dns_get_server_state(void);
355 355
  * (ip address in case of A/AAAA record, name in case of SRV record)
356 356
  * only the remaining fields are updated.
357 357
  *
358
+ * Note that permanent records cannot be overwritten unless
359
+ * the new record is also permanent. A permanent record
360
+ * completely replaces a non-permanent one.
361
+ *
358 362
  * Currently only A, AAAA, and SRV records are supported.
359 363
  */
360 364
 int dns_cache_add_record(unsigned short type,