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.)
... | ... |
@@ -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, |