WARNING: there are a lot of changes in tm
... | ... |
@@ -66,7 +66,7 @@ MAIN_NAME=ser |
66 | 66 |
VERSION = 0 |
67 | 67 |
PATCHLEVEL = 10 |
68 | 68 |
SUBLEVEL = 99 |
69 |
-EXTRAVERSION = -dev42 |
|
69 |
+EXTRAVERSION = -dev43-dns_cache |
|
70 | 70 |
|
71 | 71 |
SER_VER = $(shell expr $(VERSION) \* 1000000 + $(PATCHLEVEL) \* 1000 + \ |
72 | 72 |
$(SUBLEVEL) ) |
... | ... |
@@ -339,6 +339,14 @@ endif |
339 | 339 |
# compiles in checks and use for maddr parameter in uri. |
340 | 340 |
# Required to support Windows Messenger 5.x over TCP connection |
341 | 341 |
# which (mis)uses this parameter. |
342 |
+# -DUSE_DNS_CACHE |
|
343 |
+# use an internal dns cache instead of making dns requests each time |
|
344 |
+# -DUSE_DNS_FAILOVER |
|
345 |
+# if the destination resolves to multiple ips, on send error fall back |
|
346 |
+# to the others |
|
347 |
+# -DUSE_DST_BLACKLIST |
|
348 |
+# blacklist bad destination (timeout, failed to connect, error sending |
|
349 |
+# a.s.o) |
|
342 | 350 |
|
343 | 351 |
# Sometimes is needes correct non-quoted $OS. HACK: gcc translates known OS to number ('linux'), so there is added underscore |
344 | 352 |
|
... | ... |
@@ -356,6 +364,9 @@ DEFS+= $(extra_defs) \ |
356 | 364 |
-DDISABLE_NAGLE \ |
357 | 365 |
-DHAVE_RESOLV_RES \ |
358 | 366 |
-DDBG_QM_MALLOC \ |
367 |
+ -DUSE_DNS_CACHE \ |
|
368 |
+ -DUSE_DNS_FAILOVER \ |
|
369 |
+ -DUSE_DST_BLACKLIST \ |
|
359 | 370 |
#-DF_MALLOC \ |
360 | 371 |
#-DDBG_F_MALLOC \ |
361 | 372 |
#-DNO_DEBUG \ |
... | ... |
@@ -1092,7 +1103,6 @@ $(error Unsupported compiler ($(CC):$(CC_NAME)), try gcc) |
1092 | 1103 |
endif #CC_NAME, gcc |
1093 | 1104 |
endif #ARCH, ppc |
1094 | 1105 |
|
1095 |
-CFLAGS+= $(CC_EXTRA_OPTS) |
|
1096 | 1106 |
|
1097 | 1107 |
|
1098 | 1108 |
# setting LDFLAGS |
... | ... |
@@ -1122,6 +1132,7 @@ endif |
1122 | 1132 |
else #mode,release |
1123 | 1133 |
ifeq ($(CC_NAME), gcc) |
1124 | 1134 |
CFLAGS=-g -Wcast-align $(PROFILE) |
1135 |
+ DEFS+=-DCC_GCC_LIKE_ASM |
|
1125 | 1136 |
ifeq ($(ARCH), sparc64) |
1126 | 1137 |
DEFS+=SPARC64_MODE |
1127 | 1138 |
CFLAGS+= -mcpu=ultrasparc -m64 |
... | ... |
@@ -1138,6 +1149,7 @@ else |
1138 | 1149 |
endif |
1139 | 1150 |
endif |
1140 | 1151 |
ifeq ($(CC_NAME), icc) |
1152 |
+ DEFS+=-DCC_GCC_LIKE_ASM |
|
1141 | 1153 |
CFLAGS=-g $(PROFILE) |
1142 | 1154 |
LDFLAGS+=-g -Wl,-E $(PROFILE) |
1143 | 1155 |
MOD_LDFLAGS=-shared $(LDFLAGS) |
... | ... |
@@ -1150,6 +1162,7 @@ endif |
1150 | 1162 |
|
1151 | 1163 |
endif #mode=release |
1152 | 1164 |
|
1165 |
+CFLAGS+= $(CC_EXTRA_OPTS) |
|
1153 | 1166 |
|
1154 | 1167 |
#*FLAGS used for compiling the modules |
1155 | 1168 |
ifeq ($(CC_NAME), gcc) |
... | ... |
@@ -24,7 +24,8 @@ modules: |
24 | 24 |
hashing after an uri (to, from or request uri) |
25 | 25 |
- improved uri hashing (password is ignored, port is used only |
26 | 26 |
if != 5060 or 5061) |
27 |
- - tm - migrated to the new timers (tm timers completely rewritten) |
|
27 |
+ - tm - dns failover and dst blacklist support |
|
28 |
+ - migrated to the new timers (tm timers completely rewritten) |
|
28 | 29 |
- improved speed and less memory usage |
29 | 30 |
- much more precise reptransmissions timing |
30 | 31 |
- params: - retr_timer1p1, retr_timer1p2, retr_timer1p3 removed |
... | ... |
@@ -49,6 +50,11 @@ modules: |
49 | 50 |
Vias a.s.o) and not on the original message |
50 | 51 |
|
51 | 52 |
core: |
53 |
+ - dns cache and dns failover support added (see doc/dns.txt) |
|
54 |
+ - destination blacklist added -- destinations to which forwarding fails |
|
55 |
+ (send error, tm timeout a.s.o) are temporarily added to a blacklist which |
|
56 |
+ is consulted before each send => faster send error detection |
|
57 |
+ in the near future (see doc/dst_blacklist.txt) |
|
52 | 58 |
- default log level switched to 0 (only messages < L_WARN will be printed |
53 | 59 |
by default) |
54 | 60 |
- separate memdbg log level which controls the memory/malloc related |
... | ... |
@@ -113,7 +119,7 @@ core: |
113 | 119 |
- tcp: - improved performance (io event handling), using OS specific |
114 | 120 |
optimizations |
115 | 121 |
- 1024 connections limit removed (see tcp_max_connections) |
116 |
-- resolver: - timeouts, retries a.s.o can no be set from ser.cfg |
|
122 |
+- resolver: - timeouts, retries a.s.o can now be set from ser.cfg |
|
117 | 123 |
(see below dns_* and man resolv.conf(6)). |
118 | 124 |
The maximum time a dns request can take (before failing) is: |
119 | 125 |
(dns_retr_time*dns_retr_no)*(search_list_domains) |
... | ... |
@@ -130,6 +136,21 @@ core: |
130 | 136 |
are available (see tm docs) |
131 | 137 |
- avps directly accessible from script with %avp_name (variable style) |
132 | 138 |
new config variables: |
139 |
+ use_dns_cache = on | off (default on) |
|
140 |
+ use_dns_failover = on | off (default off) |
|
141 |
+ dns_cache_flags = number (default 0) |
|
142 |
+ dns_cache_negative_ttl = number in seconds (default 60) |
|
143 |
+ dns_cache_min_ttl = time in seconds (default 0) |
|
144 |
+ dns_cache_max_ttl = time in seconds (default MAXINT) |
|
145 |
+ dns_cache_mem = maximum memory used for the dns cache in Kb (default 500 K) |
|
146 |
+ dns_cache_gc_interval = interval in seconds after which the dns cache is |
|
147 |
+ garbage collected (default: 120 s) |
|
148 |
+ use_dst_blacklist = on | off (default off) |
|
149 |
+ dst_blacklist_expire = time in s (default 60) |
|
150 |
+ dst_blacklist_mem = maximum memory used for the blacklist in Kb (default 250 |
|
151 |
+ K) |
|
152 |
+ dst_blacklist_gc_interval = interval in seconds after which the destination |
|
153 |
+ blacklist is garbage collected (default 60) |
|
133 | 154 |
tos = number - ip type of service (TOS) value |
134 | 155 |
dns_try_ipv6 = yes/no - if yes and a dns lookup fails, it will retry it |
135 | 156 |
for ipv6 (AAAA record). Default: yes |
... | ... |
@@ -138,7 +159,7 @@ new config variables: |
138 | 159 |
(usually 5s). |
139 | 160 |
dns_retr_no = no. - number of dns retransmissions before giving up. |
140 | 161 |
Default: see above (usually 4) |
141 |
- dns_server_no = no. - how many dns servers from the ones defined in |
|
162 |
+ dns_servers_no = no. - how many dns servers from the ones defined in |
|
142 | 163 |
/etc/resolv.conf will be used. Default: all of them. |
143 | 164 |
dns_use_search_list= yes/no - if no, the search list in /etc/resolv.conf |
144 | 165 |
will be ignored (=> fewer lookups => gives up faster). Default: yes. |
... | ... |
@@ -41,6 +41,7 @@ |
41 | 41 |
* 2005-12-12 return & drop/exit differentiation (andrei) |
42 | 42 |
* 2005-12-19 select framework (mma) |
43 | 43 |
* 2006-04-12 updated *_send() calls to use a struct dest_info (andrei) |
44 |
+ * 2006-07-27 dns cache and dns based send address failover support (andrei) |
|
44 | 45 |
*/ |
45 | 46 |
|
46 | 47 |
|
... | ... |
@@ -107,6 +108,7 @@ int do_action(struct action* a, struct sip_msg* msg) |
107 | 108 |
unsigned short port; |
108 | 109 |
unsigned short flags; |
109 | 110 |
int_str name, value; |
111 |
+ str* dst_host; |
|
110 | 112 |
|
111 | 113 |
/* reset the value of error to E_UNSPEC so avoid unknowledgable |
112 | 114 |
functions to return with error (status<0) and not setting it |
... | ... |
@@ -208,32 +210,24 @@ int do_action(struct action* a, struct sip_msg* msg) |
208 | 210 |
#endif |
209 | 211 |
} |
210 | 212 |
|
211 |
-#ifdef HONOR_MADDR |
|
212 |
- if (u->maddr_val.s && u->maddr_val.len) { |
|
213 |
- if (sip_hostport2su(&dst.to, &u->maddr_val, port, dst.proto)<0){ |
|
214 |
- LOG(L_ERR, "ERROR: bad maddr param in uri," |
|
215 |
- " dropping packet\n"); |
|
216 |
- ret=E_BAD_ADDRESS; |
|
217 |
- goto error_fwd_uri; |
|
218 |
- } |
|
219 |
- } else |
|
213 |
+#ifdef HONOR_MADDR |
|
214 |
+ if (u->maddr_val.s && u->maddr_val.len) |
|
215 |
+ dst_host=&u->maddr_val; |
|
216 |
+ else |
|
220 | 217 |
#endif |
221 |
- if (sip_hostport2su(&dst.to, &u->host, port, dst.proto)<0){ |
|
222 |
- LOG(L_ERR, "ERROR: bad host name in uri," |
|
223 |
- " dropping packet\n"); |
|
224 |
- ret=E_BAD_ADDRESS; |
|
225 |
- goto error_fwd_uri; |
|
226 |
- } |
|
218 |
+ dst_host=&u->host; |
|
227 | 219 |
#ifdef USE_COMP |
228 | 220 |
dst.comp=u->comp; |
229 | 221 |
#endif |
230 |
- ret=forward_request(msg, &dst); |
|
231 |
- if (ret>=0) ret=1; |
|
222 |
+ ret=forward_request(msg, dst_host, port, &dst); |
|
223 |
+ if (ret>=0){ |
|
224 |
+ ret=1; |
|
225 |
+ } |
|
232 | 226 |
}else if ((a->val[0].type==PROXY_ST) && (a->val[1].type==NUMBER_ST)){ |
233 | 227 |
if (dst.proto==PROTO_NONE) |
234 | 228 |
dst.proto=msg->rcv.proto; |
235 | 229 |
proxy2su(&dst.to, (struct proxy_l*)a->val[0].u.data); |
236 |
- ret=forward_request(msg, &dst); |
|
230 |
+ ret=forward_request(msg, 0, 0, &dst); |
|
237 | 231 |
if (ret>=0){ |
238 | 232 |
ret=1; |
239 | 233 |
proxy_mark((struct proxy_l*)a->val[0].u.data, ret); |
... | ... |
@@ -60,6 +60,8 @@ |
60 | 60 |
* to_{ip,port} (andrei) |
61 | 61 |
* 2005-12-12 separated drop, exit, break, return, added RETCODE (andrei) |
62 | 62 |
* 2005-12-19 select framework (mma) |
63 |
+ * 2006-09-11 added dns cache (use, flags, ttls, mem ,gc) & dst blacklist |
|
64 |
+ * options (andrei) |
|
63 | 65 |
*/ |
64 | 66 |
|
65 | 67 |
|
... | ... |
@@ -228,6 +230,22 @@ DNS_RETR_TIME dns_retr_time |
228 | 230 |
DNS_RETR_NO dns_retr_no |
229 | 231 |
DNS_SERVERS_NO dns_servers_no |
230 | 232 |
DNS_USE_SEARCH dns_use_search_list |
233 |
+/* dns cache */ |
|
234 |
+DNS_USE_CACHE use_dns_cache |
|
235 |
+DNS_USE_FAILOVER use_dns_failover |
|
236 |
+DNS_CACHE_FLAGS dns_cache_flags |
|
237 |
+DNS_CACHE_NEG_TTL dns_cache_negative_ttl |
|
238 |
+DNS_CACHE_MIN_TTL dns_cache_min_ttl |
|
239 |
+DNS_CACHE_MAX_TTL dns_cache_max_ttl |
|
240 |
+DNS_CACHE_MEM dns_cache_mem |
|
241 |
+DNS_CACHE_GC_INT dns_cache_gc_interval |
|
242 |
+/* blacklist */ |
|
243 |
+USE_DST_BLST use_dst_blacklist |
|
244 |
+DST_BLST_MEM dst_blacklist_mem |
|
245 |
+DST_BLST_TTL dst_blacklist_expire|dst_blacklist_ttl |
|
246 |
+DST_BLST_GC_INT dst_blacklist_gc_interval |
|
247 |
+ |
|
248 |
+ |
|
231 | 249 |
PORT port |
232 | 250 |
STAT statistics |
233 | 251 |
MAXBUFFER maxbuffer |
... | ... |
@@ -422,6 +440,30 @@ EAT_ABLE [\ \t\b\r] |
422 | 440 |
return DNS_SERVERS_NO; } |
423 | 441 |
<INITIAL>{DNS_USE_SEARCH} { count(); yylval.strval=yytext; |
424 | 442 |
return DNS_USE_SEARCH; } |
443 |
+<INITIAL>{DNS_USE_CACHE} { count(); yylval.strval=yytext; |
|
444 |
+ return DNS_USE_CACHE; } |
|
445 |
+<INITIAL>{DNS_USE_FAILOVER} { count(); yylval.strval=yytext; |
|
446 |
+ return DNS_USE_FAILOVER; } |
|
447 |
+<INITIAL>{DNS_CACHE_FLAGS} { count(); yylval.strval=yytext; |
|
448 |
+ return DNS_CACHE_FLAGS; } |
|
449 |
+<INITIAL>{DNS_CACHE_NEG_TTL} { count(); yylval.strval=yytext; |
|
450 |
+ return DNS_CACHE_NEG_TTL; } |
|
451 |
+<INITIAL>{DNS_CACHE_MIN_TTL} { count(); yylval.strval=yytext; |
|
452 |
+ return DNS_CACHE_MIN_TTL; } |
|
453 |
+<INITIAL>{DNS_CACHE_MAX_TTL} { count(); yylval.strval=yytext; |
|
454 |
+ return DNS_CACHE_MAX_TTL; } |
|
455 |
+<INITIAL>{DNS_CACHE_MEM} { count(); yylval.strval=yytext; |
|
456 |
+ return DNS_CACHE_MEM; } |
|
457 |
+<INITIAL>{DNS_CACHE_GC_INT} { count(); yylval.strval=yytext; |
|
458 |
+ return DNS_CACHE_GC_INT; } |
|
459 |
+<INITIAL>{USE_DST_BLST} { count(); yylval.strval=yytext; |
|
460 |
+ return USE_DST_BLST; } |
|
461 |
+<INITIAL>{DST_BLST_MEM} { count(); yylval.strval=yytext; |
|
462 |
+ return DST_BLST_MEM; } |
|
463 |
+<INITIAL>{DST_BLST_TTL} { count(); yylval.strval=yytext; |
|
464 |
+ return DST_BLST_TTL; } |
|
465 |
+<INITIAL>{DST_BLST_GC_INT} { count(); yylval.strval=yytext; |
|
466 |
+ return DST_BLST_GC_INT; } |
|
425 | 467 |
<INITIAL>{PORT} { count(); yylval.strval=yytext; return PORT; } |
426 | 468 |
<INITIAL>{STAT} { count(); yylval.strval=yytext; return STAT; } |
427 | 469 |
<INITIAL>{MAXBUFFER} { count(); yylval.strval=yytext; return MAXBUFFER; } |
... | ... |
@@ -72,6 +72,8 @@ |
72 | 72 |
* 2006-02-02 named flags support (andrei) |
73 | 73 |
* 2006-02-06 named routes support (andrei) |
74 | 74 |
* 2006-05-30 avp flags (tma) |
75 |
+ * 2006-09-11 added dns cache (use, flags, ttls, mem ,gc) & dst blacklist |
|
76 |
+ * options (andrei) |
|
75 | 77 |
*/ |
76 | 78 |
|
77 | 79 |
%{ |
... | ... |
@@ -117,6 +119,26 @@ |
117 | 119 |
if (rt!=ONSEND_ROUTE) yyerror( s " allowed only in onsend_routes");\ |
118 | 120 |
}while(0) |
119 | 121 |
|
122 |
+ |
|
123 |
+#ifdef USE_DNS_CACHE |
|
124 |
+ #define IF_DNS_CACHE(x) x |
|
125 |
+#else |
|
126 |
+ #define IF_DNS_CACHE(x) warn("dns cache support not compiled in") |
|
127 |
+#endif |
|
128 |
+ |
|
129 |
+#ifdef USE_DNS_FAILOVER |
|
130 |
+ #define IF_DNS_FAILOVER(x) x |
|
131 |
+#else |
|
132 |
+ #define IF_DNS_FAILOVER(x) warn("dns failover support not compiled in") |
|
133 |
+#endif |
|
134 |
+ |
|
135 |
+#ifdef USE_DST_BLACKLIST |
|
136 |
+ #define IF_DST_BLACKLIST(x) x |
|
137 |
+#else |
|
138 |
+ #define IF_DST_BLACKLIST(x) warn("dst blacklist support not compiled in") |
|
139 |
+#endif |
|
140 |
+ |
|
141 |
+ |
|
120 | 142 |
extern int yylex(); |
121 | 143 |
static void yyerror(char* s); |
122 | 144 |
static char* tmp; |
... | ... |
@@ -234,6 +256,20 @@ static struct socket_id* mk_listen_id(char*, int, int); |
234 | 256 |
%token DNS_RETR_NO |
235 | 257 |
%token DNS_SERVERS_NO |
236 | 258 |
%token DNS_USE_SEARCH |
259 |
+%token DNS_USE_CACHE |
|
260 |
+%token DNS_USE_FAILOVER |
|
261 |
+%token DNS_CACHE_FLAGS |
|
262 |
+%token DNS_CACHE_NEG_TTL |
|
263 |
+%token DNS_CACHE_MIN_TTL |
|
264 |
+%token DNS_CACHE_MAX_TTL |
|
265 |
+%token DNS_CACHE_MEM |
|
266 |
+%token DNS_CACHE_GC_INT |
|
267 |
+/*blacklist*/ |
|
268 |
+%token USE_DST_BLST |
|
269 |
+%token DST_BLST_MEM |
|
270 |
+%token DST_BLST_TTL |
|
271 |
+%token DST_BLST_GC_INT |
|
272 |
+ |
|
237 | 273 |
%token PORT |
238 | 274 |
%token STAT |
239 | 275 |
%token CHILDREN |
... | ... |
@@ -512,6 +548,30 @@ assign_stm: |
512 | 548 |
| DNS_SERVERS_NO error { yyerror("number expected"); } |
513 | 549 |
| DNS_USE_SEARCH EQUAL NUMBER { dns_search_list=$3; } |
514 | 550 |
| DNS_USE_SEARCH error { yyerror("boolean value expected"); } |
551 |
+ | DNS_USE_CACHE EQUAL NUMBER { IF_DNS_CACHE(use_dns_cache=$3); } |
|
552 |
+ | DNS_USE_CACHE error { yyerror("boolean value expected"); } |
|
553 |
+ | DNS_USE_FAILOVER EQUAL NUMBER { IF_DNS_FAILOVER(use_dns_failover=$3);} |
|
554 |
+ | DNS_USE_FAILOVER error { yyerror("boolean value expected"); } |
|
555 |
+ | DNS_CACHE_FLAGS EQUAL NUMBER { IF_DNS_CACHE(dns_flags=$3); } |
|
556 |
+ | DNS_CACHE_FLAGS error { yyerror("boolean value expected"); } |
|
557 |
+ | DNS_CACHE_NEG_TTL EQUAL NUMBER { IF_DNS_CACHE(dns_neg_cache_ttl=$3); } |
|
558 |
+ | DNS_CACHE_NEG_TTL error { yyerror("boolean value expected"); } |
|
559 |
+ | DNS_CACHE_MAX_TTL EQUAL NUMBER { IF_DNS_CACHE(dns_cache_max_ttl=$3); } |
|
560 |
+ | DNS_CACHE_MAX_TTL error { yyerror("boolean value expected"); } |
|
561 |
+ | DNS_CACHE_MIN_TTL EQUAL NUMBER { IF_DNS_CACHE(dns_cache_min_ttl=$3); } |
|
562 |
+ | DNS_CACHE_MIN_TTL error { yyerror("boolean value expected"); } |
|
563 |
+ | DNS_CACHE_MEM EQUAL NUMBER { IF_DNS_CACHE(dns_cache_max_mem=$3); } |
|
564 |
+ | DNS_CACHE_MEM error { yyerror("boolean value expected"); } |
|
565 |
+ | DNS_CACHE_GC_INT EQUAL NUMBER { IF_DNS_CACHE(dns_timer_interval=$3); } |
|
566 |
+ | DNS_CACHE_GC_INT error { yyerror("boolean value expected"); } |
|
567 |
+ | USE_DST_BLST EQUAL NUMBER { IF_DST_BLACKLIST(use_dst_blacklist=$3); } |
|
568 |
+ | USE_DST_BLST error { yyerror("boolean value expected"); } |
|
569 |
+ | DST_BLST_MEM EQUAL NUMBER { IF_DST_BLACKLIST(blst_max_mem=$3); } |
|
570 |
+ | DST_BLST_MEM error { yyerror("boolean value expected"); } |
|
571 |
+ | DST_BLST_TTL EQUAL NUMBER { IF_DST_BLACKLIST(blst_timeout=$3); } |
|
572 |
+ | DST_BLST_TTL error { yyerror("boolean value expected"); } |
|
573 |
+ | DST_BLST_GC_INT EQUAL NUMBER { IF_DST_BLACKLIST(blst_timer_interval=$3);} |
|
574 |
+ | DST_BLST_GC_INT error { yyerror("boolean value expected"); } |
|
515 | 575 |
| PORT EQUAL NUMBER { port_no=$3; } |
516 | 576 |
| STAT EQUAL STRING { |
517 | 577 |
#ifdef STATS |
... | ... |
@@ -1828,7 +1888,7 @@ static void warn(char* s) |
1828 | 1888 |
{ |
1829 | 1889 |
LOG(L_WARN, "cfg. warning: (%d,%d-%d): %s\n", line, startcolumn, |
1830 | 1890 |
column, s); |
1831 |
- cfg_errors++; |
|
1891 |
+ cfg_warnings++; |
|
1832 | 1892 |
} |
1833 | 1893 |
|
1834 | 1894 |
static void yyerror(char* s) |
... | ... |
@@ -46,6 +46,10 @@ |
46 | 46 |
|
47 | 47 |
/* adds an entire sublist { s,e } (including s & e ) |
48 | 48 |
* after head |
49 |
+ * WARNING: clist_insert_sublist(head, n, n->prev) won't work, |
|
50 |
+ * same for clist_insert_sublist(head, n->next, n) |
|
51 |
+ * (macro!), use e=n->prev; clist_insert_sublist(head, n, e, ...) |
|
52 |
+ * instead! |
|
49 | 53 |
*/ |
50 | 54 |
#define clist_insert_sublist(head, s, e, next, prev) \ |
51 | 55 |
do{ \ |
... | ... |
@@ -59,6 +63,9 @@ |
59 | 63 |
|
60 | 64 |
/* appends an entire sublist { s,e } (including s & e ) |
61 | 65 |
* at the end of the list |
66 |
+ * WARNING: clist_append_sublist(head, n, n->prev, ...) won't work, |
|
67 |
+ * (macro!), use e=n->prev; clist_append_sublist(head, n, e, ...) |
|
68 |
+ * instead! |
|
62 | 69 |
*/ |
63 | 70 |
#define clist_append_sublist(head, s, e, next, prev) \ |
64 | 71 |
do{ \ |
... | ... |
@@ -70,9 +77,13 @@ |
70 | 77 |
|
71 | 78 |
|
72 | 79 |
|
80 |
+ |
|
73 | 81 |
/* remove sublist { s,e } (including s & e ) |
74 | 82 |
* always, if start is the beginning of the list use |
75 |
- * clist_rm_sublist(head->next, e, next, prev ) */ |
|
83 |
+ * clist_rm_sublist(head->next, e, next, prev ) |
|
84 |
+ * WARNING: clist_rm_sublist(n, n->prev, ...) won't work, |
|
85 |
+ * (macro!), use e=n->prev; clist_rm_sublist(n, e, ...) |
|
86 |
+ * instead! */ |
|
76 | 87 |
#define clist_rm_sublist(s, e, next, prev) \ |
77 | 88 |
do{\ |
78 | 89 |
(s)->prev->next=(e)->next; \ |
... | ... |
@@ -39,6 +39,40 @@ |
39 | 39 |
#include "tcp_info.h" |
40 | 40 |
#include "core_cmd.h" |
41 | 41 |
|
42 |
+#ifdef USE_DNS_CACHE |
|
43 |
+void dns_cache_debug(rpc_t* rpc, void* ctx); |
|
44 |
+void dns_cache_debug_all(rpc_t* rpc, void* ctx); |
|
45 |
+void dns_cache_mem_info(rpc_t* rpc, void* ctx); |
|
46 |
+ |
|
47 |
+static const char* dns_cache_mem_info_doc[] = { |
|
48 |
+ "dns cache memory info.", /* Documentation string */ |
|
49 |
+ 0 /* Method signature(s) */ |
|
50 |
+}; |
|
51 |
+static const char* dns_cache_debug_doc[] = { |
|
52 |
+ "dns debug info.", /* Documentation string */ |
|
53 |
+ 0 /* Method signature(s) */ |
|
54 |
+}; |
|
55 |
+ |
|
56 |
+static const char* dns_cache_debug_all_doc[] = { |
|
57 |
+ "complete dns debug dump", /* Documentation string */ |
|
58 |
+ 0 /* Method signature(s) */ |
|
59 |
+}; |
|
60 |
+#endif |
|
61 |
+#ifdef USE_DST_BLACKLIST |
|
62 |
+void dst_blst_debug(rpc_t* rpc, void* ctx); |
|
63 |
+void dst_blst_mem_info(rpc_t* rpc, void* ctx); |
|
64 |
+ |
|
65 |
+static const char* dst_blst_mem_info_doc[] = { |
|
66 |
+ "dst blacklist memory usage info.", /* Documentation string */ |
|
67 |
+ 0 /* Method signature(s) */ |
|
68 |
+}; |
|
69 |
+static const char* dst_blst_debug_doc[] = { |
|
70 |
+ "dst blacklist debug info.", /* Documentation string */ |
|
71 |
+ 0 /* Method signature(s) */ |
|
72 |
+}; |
|
73 |
+#endif |
|
74 |
+ |
|
75 |
+ |
|
42 | 76 |
|
43 | 77 |
#define MAX_CTIME_LEN 128 |
44 | 78 |
|
... | ... |
@@ -312,6 +346,15 @@ rpc_export_t core_rpc_methods[] = { |
312 | 346 |
{"core.kill", core_kill, core_kill_doc, 0 }, |
313 | 347 |
{"core.shmmem", core_shmmem, core_shmmem_doc, 0 }, |
314 | 348 |
{"core.tcp_info", core_tcpinfo, core_tcpinfo_doc, 0 }, |
349 |
+#ifdef USE_DNS_CACHE |
|
350 |
+ {"dns.mem_info", dns_cache_mem_info, dns_cache_mem_info_doc, 0 }, |
|
351 |
+ {"dns.debug", dns_cache_debug, dns_cache_debug_doc, 0 }, |
|
352 |
+ {"dns.debug_all", dns_cache_debug_all, dns_cache_debug_all_doc, 0 }, |
|
353 |
+#endif |
|
354 |
+#ifdef USE_DST_BLACKLIST |
|
355 |
+ {"dst_blacklist.mem_info", dst_blst_mem_info, dst_blst_mem_info_doc, 0 }, |
|
356 |
+ {"dst_blacklist.debug", dst_blst_debug, dst_blst_debug_doc, 0 }, |
|
357 |
+#endif |
|
315 | 358 |
{0, 0, 0, 0} |
316 | 359 |
}; |
317 | 360 |
|
318 | 361 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,2436 @@ |
1 |
+/* |
|
2 |
+ * $Id$ |
|
3 |
+ * |
|
4 |
+ * resolver related functions |
|
5 |
+ * |
|
6 |
+ * Copyright (C) 2006 iptelorg GmbH |
|
7 |
+ * |
|
8 |
+ * This file is part of ser, a free SIP server. |
|
9 |
+ * |
|
10 |
+ * ser is free software; you can redistribute it and/or modify |
|
11 |
+ * it under the terms of the GNU General Public License as published by |
|
12 |
+ * the Free Software Foundation; either version 2 of the License, or |
|
13 |
+ * (at your option) any later version |
|
14 |
+ * |
|
15 |
+ * For a license to use the ser software under conditions |
|
16 |
+ * other than those described here, or to purchase support for this |
|
17 |
+ * software, please contact iptel.org by e-mail at the following addresses: |
|
18 |
+ * info@iptel.org |
|
19 |
+ * |
|
20 |
+ * ser is distributed in the hope that it will be useful, |
|
21 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
22 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
23 |
+ * GNU General Public License for more details. |
|
24 |
+ * |
|
25 |
+ * You should have received a copy of the GNU General Public License |
|
26 |
+ * along with this program; if not, write to the Free Software |
|
27 |
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
28 |
+ */ |
|
29 |
+/* History: |
|
30 |
+ * -------- |
|
31 |
+ * 2006-07-13 created by andrei |
|
32 |
+ */ |
|
33 |
+ |
|
34 |
+#ifdef USE_DNS_CACHE |
|
35 |
+ |
|
36 |
+#include "globals.h" |
|
37 |
+#include "dns_cache.h" |
|
38 |
+#include "dns_wrappers.h" |
|
39 |
+#include "mem/shm_mem.h" |
|
40 |
+#include "hashes.h" |
|
41 |
+#include "clist.h" |
|
42 |
+#include "locking.h" |
|
43 |
+#include "atomic_ops.h" |
|
44 |
+#include "ut.h" |
|
45 |
+#include "timer.h" |
|
46 |
+#include "timer_ticks.h" |
|
47 |
+#include "error.h" |
|
48 |
+#include "rpc.h" |
|
49 |
+ |
|
50 |
+ |
|
51 |
+ |
|
52 |
+#define DNS_CACHE_DEBUG /* extra sanity checks and debugging */ |
|
53 |
+ |
|
54 |
+ |
|
55 |
+#ifndef MAX |
|
56 |
+ #define MAX(a,b) ( ((a)>(b))?(a):(b)) |
|
57 |
+#endif |
|
58 |
+ |
|
59 |
+#define MAX_DNS_RECORDS 255 /* maximum dns records number received in a |
|
60 |
+ dns answer*/ |
|
61 |
+ |
|
62 |
+#define DNS_HASH_SIZE 1024 /* must be <= 65535 */ |
|
63 |
+#define DEFAULT_DNS_NEG_CACHE_TTL 60 /* 1 min. */ |
|
64 |
+#define DEFAULT_DNS_CACHE_MIN_TTL 0 /* (disabled) */ |
|
65 |
+#define DEFAULT_DNS_CACHE_MAX_TTL ((unsigned int)(-1)) /* (maxint) */ |
|
66 |
+#define DEFAULT_DNS_MAX_MEM 500 /* 500 Kb */ |
|
67 |
+#define DEFAULT_DNS_TIMER_INTERVAL 120 /* 2 min. */ |
|
68 |
+#define DNS_HE_MAX_ADDR 10 /* maxium addresses returne in a hostent struct */ |
|
69 |
+#define MAX_CNAME_CHAIN 10 |
|
70 |
+ |
|
71 |
+ |
|
72 |
+static gen_lock_t* dns_hash_lock=0; |
|
73 |
+static volatile unsigned int *dns_cache_mem_used=0; /* current mem. use */ |
|
74 |
+unsigned int dns_cache_max_mem=DEFAULT_DNS_MAX_MEM; /* maximum memory used for |
|
75 |
+ the cached entries */ |
|
76 |
+unsigned int dns_neg_cache_ttl=DEFAULT_DNS_NEG_CACHE_TTL; /* neg. cache ttl */ |
|
77 |
+unsigned int dns_cache_max_ttl=DEFAULT_DNS_CACHE_MAX_TTL; /* maximum ttl */ |
|
78 |
+unsigned int dns_cache_min_ttl=DEFAULT_DNS_CACHE_MIN_TTL; /* minimum ttl */ |
|
79 |
+unsigned int dns_timer_interval=DEFAULT_DNS_TIMER_INTERVAL; /* in s */ |
|
80 |
+int dns_flags=0; /* default flags used for the dns_*resolvehost |
|
81 |
+ (compatibility wrappers) */ |
|
82 |
+ |
|
83 |
+#define LOCK_DNS_HASH() lock_get(dns_hash_lock) |
|
84 |
+#define UNLOCK_DNS_HASH() lock_release(dns_hash_lock) |
|
85 |
+ |
|
86 |
+#define FIX_TTL(t) (((t)<dns_cache_min_ttl)?dns_cache_min_ttl: \ |
|
87 |
+ (((t)>dns_cache_max_ttl)?dns_cache_max_ttl:(t))) |
|
88 |
+ |
|
89 |
+ |
|
90 |
+struct dns_hash_head{ |
|
91 |
+ struct dns_hash_entry* next; |
|
92 |
+ struct dns_hash_entry* prev; |
|
93 |
+}; |
|
94 |
+ |
|
95 |
+#ifdef DNS_LU_LST |
|
96 |
+struct dns_lu_lst* dns_last_used_lst=0; |
|
97 |
+#endif |
|
98 |
+ |
|
99 |
+static struct dns_hash_head* dns_hash=0; |
|
100 |
+ |
|
101 |
+ |
|
102 |
+static struct timer_ln* dns_timer_h=0; |
|
103 |
+ |
|
104 |
+ |
|
105 |
+ |
|
106 |
+static const char* dns_str_errors[]={ |
|
107 |
+ "no error", |
|
108 |
+ "no more records", /* not an error, but and end condition */ |
|
109 |
+ "unknown error", |
|
110 |
+ "internal error", |
|
111 |
+ "bad SRV entry", |
|
112 |
+ "unresolvable SRV request", |
|
113 |
+ "bad A or AAAA entry", |
|
114 |
+ "unresovlable A or AAAA request", |
|
115 |
+ "invalid ip in A or AAAA record", |
|
116 |
+ "blacklisted ip", |
|
117 |
+ "name too long ", /* try again with a shorter name */ |
|
118 |
+ "ip AF mismatch", /* address family mismatch */ |
|
119 |
+ "bug - critical error" |
|
120 |
+}; |
|
121 |
+ |
|
122 |
+ |
|
123 |
+ |
|
124 |
+/* param: err (negative error number) */ |
|
125 |
+const char* dns_strerror(int err) |
|
126 |
+{ |
|
127 |
+ err=-err; |
|
128 |
+ if ((err>=0) && (err<sizeof(dns_str_errors)/sizeof(char*))) |
|
129 |
+ return dns_str_errors[err]; |
|
130 |
+ return "bug -- bad error number"; |
|
131 |
+} |
|
132 |
+ |
|
133 |
+ |
|
134 |
+ |
|
135 |
+/* "internal" only, don't use unless you really know waht you're doing */ |
|
136 |
+inline static void dns_destroy_entry(struct dns_hash_entry* e) |
|
137 |
+{ |
|
138 |
+#ifdef DNS_CACHE_DEBUG |
|
139 |
+ memset(e, 0, e->total_size); |
|
140 |
+#endif |
|
141 |
+ shm_free(e); /* nice having it in one block isn't it? :-) */ |
|
142 |
+} |
|
143 |
+ |
|
144 |
+ |
|
145 |
+/* "internal" only, same as above, asumes shm_lock() held (tm optimization) */ |
|
146 |
+inline static void dns_destroy_entry_shm_unsafe(struct dns_hash_entry* e) |
|
147 |
+{ |
|
148 |
+#ifdef DNS_CACHE_DEBUG |
|
149 |
+ memset(e, 0, e->total_size); |
|
150 |
+#endif |
|
151 |
+ shm_free_unsafe(e); /* nice having it in one block isn't it? :-) */ |
|
152 |
+} |
|
153 |
+ |
|
154 |
+ |
|
155 |
+ |
|
156 |
+/* dec. the internal refcnt and if 0 deletes the entry */ |
|
157 |
+void dns_hash_put(struct dns_hash_entry* e) |
|
158 |
+{ |
|
159 |
+ if(e && atomic_dec_and_test(&e->refcnt)){ |
|
160 |
+ /* atomic_sub_long(dns_cache_total_used, e->total_size); */ |
|
161 |
+ dns_destroy_entry(e); |
|
162 |
+ } |
|
163 |
+} |
|
164 |
+ |
|
165 |
+ |
|
166 |
+ |
|
167 |
+/* same as above but uses dns_destroy_unsafe (assumes shm_lock held -- tm |
|
168 |
+ * optimization) */ |
|
169 |
+void dns_hash_put_shm_unsafe(struct dns_hash_entry* e) |
|
170 |
+{ |
|
171 |
+ if(e && atomic_dec_and_test(&e->refcnt)){ |
|
172 |
+ /* atomic_sub_long(dns_cache_total_used, e->total_size); */ |
|
173 |
+ dns_destroy_entry_shm_unsafe(e); |
|
174 |
+ } |
|
175 |
+} |
|
176 |
+ |
|
177 |
+ |
|
178 |
+inline static int dns_cache_clean(unsigned int no, int expired_only); |
|
179 |
+inline static int dns_cache_free_mem(unsigned int target, int expired_only); |
|
180 |
+ |
|
181 |
+static ticks_t dns_timer(ticks_t ticks, struct timer_ln* tl, void* data) |
|
182 |
+{ |
|
183 |
+ if (*dns_cache_mem_used>12*(dns_cache_max_mem/16)){ /* ~ 75% used */ |
|
184 |
+ dns_cache_free_mem(dns_cache_max_mem/2, 1); |
|
185 |
+ }else{ |
|
186 |
+ dns_cache_clean(-1, 1); /* all the table, only expired entries */ |
|
187 |
+ /* TODO: better strategy? */ |
|
188 |
+ } |
|
189 |
+ return (ticks_t)(-1); |
|
190 |
+} |
|
191 |
+ |
|
192 |
+ |
|
193 |
+ |
|
194 |
+void destroy_dns_cache() |
|
195 |
+{ |
|
196 |
+ if (dns_timer_h){ |
|
197 |
+ timer_del(dns_timer_h); |
|
198 |
+ timer_free(dns_timer_h); |
|
199 |
+ dns_timer_h=0; |
|
200 |
+ } |
|
201 |
+ if (dns_hash_lock){ |
|
202 |
+ lock_destroy(dns_hash_lock); |
|
203 |
+ lock_dealloc(dns_hash_lock); |
|
204 |
+ dns_hash_lock=0; |
|
205 |
+ } |
|
206 |
+ if (dns_hash){ |
|
207 |
+ shm_free(dns_hash); |
|
208 |
+ dns_hash=0; |
|
209 |
+ } |
|
210 |
+#ifdef DNS_LU_LST |
|
211 |
+ if (dns_last_used_lst){ |
|
212 |
+ shm_free(dns_last_used_lst); |
|
213 |
+ dns_last_used_lst=0; |
|
214 |
+ } |
|
215 |
+#endif |
|
216 |
+ if (dns_cache_mem_used){ |
|
217 |
+ shm_free((void*)dns_cache_mem_used); |
|
218 |
+ dns_cache_mem_used=0; |
|
219 |
+ } |
|
220 |
+} |
|
221 |
+ |
|
222 |
+ |
|
223 |
+ |
|
224 |
+int init_dns_cache() |
|
225 |
+{ |
|
226 |
+ int r; |
|
227 |
+ int ret; |
|
228 |
+ |
|
229 |
+ ret=0; |
|
230 |
+ /* sanity check */ |
|
231 |
+ if (E_DNS_CRITICAL>=sizeof(dns_str_errors)/sizeof(char*)){ |
|
232 |
+ LOG(L_CRIT, "BUG: dns_cache_init: bad dns error table\n"); |
|
233 |
+ ret=E_BUG; |
|
234 |
+ goto error; |
|
235 |
+ } |
|
236 |
+ dns_cache_mem_used=shm_malloc(sizeof(*dns_cache_mem_used)); |
|
237 |
+ if (dns_cache_mem_used==0){ |
|
238 |
+ ret=E_OUT_OF_MEM; |
|
239 |
+ goto error; |
|
240 |
+ } |
|
241 |
+#ifdef DNS_LU_LST |
|
242 |
+ dns_last_used_lst=shm_malloc(sizeof(*dns_last_used_lst)); |
|
243 |
+ if (dns_last_used_lst==0){ |
|
244 |
+ ret=E_OUT_OF_MEM; |
|
245 |
+ goto error; |
|
246 |
+ } |
|
247 |
+ clist_init(dns_last_used_lst, next, prev); |
|
248 |
+#endif |
|
249 |
+ dns_hash=shm_malloc(sizeof(struct dns_hash_head)*DNS_HASH_SIZE); |
|
250 |
+ if (dns_hash==0){ |
|
251 |
+ ret=E_OUT_OF_MEM; |
|
252 |
+ goto error; |
|
253 |
+ } |
|
254 |
+ for (r=0; r<DNS_HASH_SIZE; r++) |
|
255 |
+ clist_init(&dns_hash[r], next, prev); |
|
256 |
+ |
|
257 |
+ dns_hash_lock=lock_alloc(); |
|
258 |
+ if (dns_hash_lock==0){ |
|
259 |
+ ret=E_OUT_OF_MEM; |
|
260 |
+ goto error; |
|
261 |
+ } |
|
262 |
+ if (lock_init(dns_hash_lock)==0){ |
|
263 |
+ lock_dealloc(dns_hash_lock); |
|
264 |
+ dns_hash_lock=0; |
|
265 |
+ ret=-1; |
|
266 |
+ goto error; |
|
267 |
+ } |
|
268 |
+ |
|
269 |
+ /* fix options */ |
|
270 |
+ dns_cache_max_mem<<=10; /* Kb */ /* TODO: test with 0 */ |
|
271 |
+ /* fix flags */ |
|
272 |
+ if (dns_try_ipv6==0){ |
|
273 |
+ dns_flags|=DNS_IPV4_ONLY; |
|
274 |
+ } |
|
275 |
+ if (dns_flags & DNS_IPV4_ONLY){ |
|
276 |
+ dns_flags&=~(DNS_IPV6_ONLY|DNS_IPV6_FIRST); |
|
277 |
+ } |
|
278 |
+ ; |
|
279 |
+ dns_timer_h=timer_alloc(); |
|
280 |
+ if (dns_timer_h==0){ |
|
281 |
+ ret=E_OUT_OF_MEM; |
|
282 |
+ goto error; |
|
283 |
+ } |
|
284 |
+ if (dns_timer_interval){ |
|
285 |
+ timer_init(dns_timer_h, dns_timer, 0, 0); /* "slow" timer */ |
|
286 |
+ if (timer_add(dns_timer_h, S_TO_TICKS(dns_timer_interval))<0){ |
|
287 |
+ LOG(L_CRIT, "BUG: dns_cache_init: failed to add the timer\n"); |
|
288 |
+ timer_free(dns_timer_h); |
|
289 |
+ dns_timer_h=0; |
|
290 |
+ goto error; |
|
291 |
+ } |
|
292 |
+ } |
|
293 |
+ |
|
294 |
+ return 0; |
|
295 |
+error: |
|
296 |
+ destroy_dns_cache(); |
|
297 |
+ return ret; |
|
298 |
+} |
|
299 |
+ |
|
300 |
+ |
|
301 |
+/* hash function, based on get_hash1_raw, but case insensitive |
|
302 |
+ * type is not used (obsolete) |
|
303 |
+ * returns the hash value |
|
304 |
+ */ |
|
305 |
+inline static unsigned int dns_hash_no(char* s, int len, int type) |
|
306 |
+{ |
|
307 |
+ char* p; |
|
308 |
+ char* end; |
|
309 |
+ |
|
310 |
+ register unsigned v; |
|
311 |
+ register unsigned h; |
|
312 |
+ |
|
313 |
+ h=0; |
|
314 |
+ |
|
315 |
+ hash_update_str(s, s+len, p, v, h); |
|
316 |
+ end=s+len; |
|
317 |
+ for (p=s; p<=(end-4); p+=4){ |
|
318 |
+ v=((p[0]<<24)+(p[1]<<16)+(p[2]<<8)+p[3])|0x20202020; |
|
319 |
+ h+=v^(v>>3); |
|
320 |
+ } |
|
321 |
+ v=0; |
|
322 |
+ for (;p<end; p++){ v<<=8; v+=*p|0x20;} |
|
323 |
+ h+=v^(v>>3); |
|
324 |
+ return hash_finish(h) % DNS_HASH_SIZE; |
|
325 |
+} |
|
326 |
+ |
|
327 |
+ |
|
328 |
+ |
|
329 |
+#ifdef DNS_CACHE_DEBUG |
|
330 |
+#define DEBUG_LU_LST |
|
331 |
+#ifdef DEBUG_LU_LST |
|
332 |
+ |
|
333 |
+#include <stdlib.h> /* abort() */ |
|
334 |
+#define check_lu_lst(l) ((((l)->next==(l)) || ((l)->prev==(l))) && \ |
|
335 |
+ ((l)!=dns_last_used_lst)) |
|
336 |
+ |
|
337 |
+#define dbg_lu_lst(txt, l) \ |
|
338 |
+ LOG(L_CRIT, "BUG: %s: crt(%p, %p, %p)," \ |
|
339 |
+ " prev(%p, %p, %p), next(%p, %p, %p)\n", txt, \ |
|
340 |
+ (l), (l)->next, (l)->prev, \ |
|
341 |
+ (l)->prev, (l)->prev->next, (l)->prev->prev, \ |
|
342 |
+ (l)->next, (l)->next->next, (l)->next->prev \ |
|
343 |
+ ) |
|
344 |
+ |
|
345 |
+#define debug_lu_lst( txt, l) \ |
|
346 |
+ do{ \ |
|
347 |
+ if (check_lu_lst((l))){ \ |
|
348 |
+ dbg_lu_lst(txt " crt:", (l)); \ |
|
349 |
+ abort(); \ |
|
350 |
+ } \ |
|
351 |
+ if (check_lu_lst((l)->next)){ \ |
|
352 |
+ dbg_lu_lst(txt " next:", (l)); \ |
|
353 |
+ abort(); \ |
|
354 |
+ } \ |
|
355 |
+ if (check_lu_lst((l)->prev)){ \ |
|
356 |
+ dbg_lu_lst(txt " prev:", (l)); \ |
|
357 |
+ abort(); \ |
|
358 |
+ } \ |
|
359 |
+ }while(0) |
|
360 |
+ |
|
361 |
+#endif |
|
362 |
+#endif /* DNS_CACHE_DEBUG */ |
|
363 |
+ |
|
364 |
+ |
|
365 |
+/* must be called with the DNS_LOCK hold |
|
366 |
+ * remove and entry from the hash, dec. its refcnt and if not referenced |
|
367 |
+ * anymore deletes it */ |
|
368 |
+void _dns_hash_remove(struct dns_hash_entry* e) |
|
369 |
+{ |
|
370 |
+ clist_rm(e, next, prev); |
|
371 |
+#ifdef DNS_CACHE_DEBUG |
|
372 |
+ e->next=e->prev=0; |
|
373 |
+#endif |
|
374 |
+#ifdef DNS_LU_LST |
|
375 |
+#ifdef DEBUG_LU_LST |
|
376 |
+ debug_lu_lst("_dns_hash_remove: pre rm:", &e->last_used_lst); |
|
377 |
+#endif |
|
378 |
+ clist_rm(&e->last_used_lst, next, prev); |
|
379 |
+#ifdef DEBUG_LU_LST |
|
380 |
+ debug_lu_lst("_dns_hash_remove: post rm:", &e->last_used_lst); |
|
381 |
+#endif |
|
382 |
+#ifdef DNS_CACHE_DEBUG |
|
383 |
+ e->last_used_lst.next=e->last_used_lst.prev=0; |
|
384 |
+#endif |
|
385 |
+#endif |
|
386 |
+ *dns_cache_mem_used-=e->total_size; |
|
387 |
+ dns_hash_put(e); |
|
388 |
+} |
|
389 |
+ |
|
390 |
+ |
|
391 |
+ |
|
392 |
+/* non locking version (the dns hash must _be_ locked externally) |
|
393 |
+ * returns 0 when not found, or the entry on success (an entry with a |
|
394 |
+ * similar name but with a CNAME type will always match). |
|
395 |
+ * it doesn't increase the internal refcnt |
|
396 |
+ * returns the entry when found, 0 when not found and sets *err to !=0 |
|
397 |
+ * on error (e.g. recursive cnames) |
|
398 |
+ * WARNING: - internal use only |
|
399 |
+ * - always check if the returned entry type is CNAME */ |
|
400 |
+inline static struct dns_hash_entry* _dns_hash_find(str* name, int type, |
|
401 |
+ int* h, int* err) |
|
402 |
+{ |
|
403 |
+ struct dns_hash_entry* e; |
|
404 |
+ struct dns_hash_entry* tmp; |
|
405 |
+ struct dns_hash_entry* ret; |
|
406 |
+ ticks_t now; |
|
407 |
+ int cname_chain; |
|
408 |
+ str cname; |
|
409 |
+ |
|
410 |
+ cname_chain=0; |
|
411 |
+ ret=0; |
|
412 |
+ now=get_ticks_raw(); |
|
413 |
+ *err=0; |
|
414 |
+again: |
|
415 |
+ *h=dns_hash_no(name->s, name->len, type); |
|
416 |
+ DBG("dns_hash_find(%.*s(%d), %d), h=%d\n", name->len, name->s, |
|
417 |
+ name->len, type, *h); |
|
418 |
+ clist_foreach_safe(&dns_hash[*h], e, tmp, next){ |
|
419 |
+ /* automatically remove expired elements */ |
|
420 |
+ if ((s_ticks_t)(now-e->expire)>=0){ |
|
421 |
+ _dns_hash_remove(e); |
|
422 |
+ }else if ((e->type==type) && (e->name_len==name->len) && |
|
423 |
+ (strncasecmp(e->name, name->s, e->name_len)==0)){ |
|
424 |
+ e->last_used=now; |
|
425 |
+#ifdef DNS_LU_LST |
|
426 |
+ /* add it at the end */ |
|
427 |
+#ifdef DEBUG_LU_LST |
|
428 |
+ debug_lu_lst("_dns_hash_find: pre rm:", &e->last_used_lst); |
|
429 |
+#endif |
|
430 |
+ clist_rm(&e->last_used_lst, next, prev); |
|
431 |
+ clist_append(dns_last_used_lst, &e->last_used_lst, next, prev); |
|
432 |
+#ifdef DEBUG_LU_LST |
|
433 |
+ debug_lu_lst("_dns_hash_find: post append:", &e->last_used_lst); |
|
434 |
+#endif |
|
435 |
+#endif |
|
436 |
+ return e; |
|
437 |
+ }else if ((e->type==T_CNAME) && (e->name_len==name->len) && |
|
438 |
+ (strncasecmp(e->name, name->s, e->name_len)==0)){ |
|
439 |
+ e->last_used=now; |
|
440 |
+#ifdef DNS_LU_LST |
|
441 |
+ /* add it at the end */ |
|
442 |
+#ifdef DEBUG_LU_LST |
|
443 |
+ debug_lu_lst("_dns_hash_find: cname: pre rm:", &e->last_used_lst); |
|
444 |
+#endif |
|
445 |
+ clist_rm(&e->last_used_lst, next, prev); |
|
446 |
+ clist_append(dns_last_used_lst, &e->last_used_lst, next, prev); |
|
447 |
+#ifdef DEBUG_LU_LST |
|
448 |
+ debug_lu_lst("_dns_hash_find: cname: post append:", |
|
449 |
+ &e->last_used_lst); |
|
450 |
+#endif |
|
451 |
+#endif |
|
452 |
+ ret=e; /* if this is an unfinished cname chain, we try to |
|
453 |
+ return the last cname */ |
|
454 |
+ /* this is a cname => retry using its value */ |
|
455 |
+ if (cname_chain> MAX_CNAME_CHAIN){ |
|
456 |
+ LOG(L_ERR, "ERROR: _dns_hash_find: cname chain too long " |
|
457 |
+ "or recursive (\"%.*s\")\n", name->len, name->s); |
|
458 |
+ ret=0; /* error*/ |
|
459 |
+ *err=-1; |
|
460 |
+ break; |
|
461 |
+ } |
|
462 |
+ cname_chain++; |
|
463 |
+ cname.s=((struct cname_rdata*)e->rr_lst->rdata)->name; |
|
464 |
+ cname.len= ((struct cname_rdata*)e->rr_lst->rdata)->name_len; |
|
465 |
+ name=&cname; |
|
466 |
+ goto again; |
|
467 |
+ } |
|
468 |
+ } |
|
469 |
+ return ret; |
|
470 |
+} |
|
471 |
+ |
|
472 |
+ |
|
473 |
+ |
|
474 |
+/* frees cache entries, if expired_only=0 only expired entries will be |
|
475 |
+ * removed, else all of them |
|
476 |
+ * it will process maximum no entries (to process all of them use -1) |
|
477 |
+ * returns the number of deleted entries |
|
478 |
+ * This should be called from a timer process*/ |
|
479 |
+inline static int dns_cache_clean(unsigned int no, int expired_only) |
|
480 |
+{ |
|
481 |
+ struct dns_hash_entry* e; |
|
482 |
+ ticks_t now; |
|
483 |
+ unsigned int n; |
|
484 |
+ unsigned int deleted; |
|
485 |
+#ifdef DNS_LU_LST |
|
486 |
+ struct dns_lu_lst* l; |
|
487 |
+ struct dns_lu_lst* tmp; |
|
488 |
+#else |
|
489 |
+ struct dns_hash_entry* t; |
|
490 |
+ unsigned int h; |
|
491 |
+ static unsigned int start=0; |
|
492 |
+#endif |
|
493 |
+ |
|
494 |
+ n=0; |
|
495 |
+ deleted=0; |
|
496 |
+ now=get_ticks_raw(); |
|
497 |
+ LOCK_DNS_HASH(); |
|
498 |
+#ifdef DNS_LU_LST |
|
499 |
+ clist_foreach_safe(dns_last_used_lst, l, tmp, next){ |
|
500 |
+ e=(struct dns_hash_entry*)(((char*)l)- |
|
501 |
+ (char*)&((struct dns_hash_entry*)(0))->last_used_lst); |
|
502 |
+ if (!expired_only || ((s_ticks_t)(now-e->expire)>=0)){ |
|
503 |
+ _dns_hash_remove(e); |
|
504 |
+ deleted++; |
|
505 |
+ } |
|
506 |
+ n++; |
|
507 |
+ if (n>=no) break; |
|
508 |
+ } |
|
509 |
+#else |
|
510 |
+ for(h=start; h!=(start+DNS_HASH_SIZE); h++){ |
|
511 |
+ clist_foreach_safe(&dns_hash[h%DNS_HASH_SIZE], e, t, next){ |
|
512 |
+ if ((s_ticks_t)(now-e->expire)>=0){ |
|
513 |
+ _dns_hash_remove(e); |
|
514 |
+ deleted++; |
|
515 |
+ } |
|
516 |
+ n++; |
|
517 |
+ if (n>=no) break; |
|
518 |
+ } |
|
519 |
+ } |
|
520 |
+ /* not fair, but faster then random() */ |
|
521 |
+ if (!expired_only){ |
|
522 |
+ for(h=start; h!=(start+DNS_HASH_SIZE); h++){ |
|
523 |
+ clist_foreach_safe(&dns_hash[h%DNS_HASH_SIZE], e, t, next){ |
|
524 |
+ if ((s_ticks_t)(now-e->expire)>=0){ |
|
525 |
+ _dns_hash_remove(e); |
|
526 |
+ deleted++; |
|
527 |
+ } |
|
528 |
+ n++; |
|
529 |
+ if (n>=no) goto skip; |
|
530 |
+ } |
|
531 |
+ } |
|
532 |
+ } |
|
533 |
+skip: |
|
534 |
+ start=h; |
|
535 |
+#endif |
|
536 |
+ UNLOCK_DNS_HASH(); |
|
537 |
+ return deleted; |
|
538 |
+} |
|
539 |
+ |
|
540 |
+ |
|
541 |
+ |
|
542 |
+/* frees cache entries, if expired_only=0 only expired entries will be |
|
543 |
+ * removed, else all of them |
|
544 |
+ * it will stop when the dns cache used memory reaches target (to process all |
|
545 |
+ * of them use 0) |
|
546 |
+ * returns the number of deleted entries */ |
|
547 |
+inline static int dns_cache_free_mem(unsigned int target, int expired_only) |
|
548 |
+{ |
|
549 |
+ struct dns_hash_entry* e; |
|
550 |
+ ticks_t now; |
|
551 |
+ unsigned int deleted; |
|
552 |
+#ifdef DNS_LU_LST |
|
553 |
+ struct dns_lu_lst* l; |
|
554 |
+ struct dns_lu_lst* tmp; |
|
555 |
+#else |
|
556 |
+ struct dns_hash_entry* t; |
|
557 |
+ unsigned int h; |
|
558 |
+ static unsigned int start=0; |
|
559 |
+#endif |
|
560 |
+ |
|
561 |
+ deleted=0; |
|
562 |
+ now=get_ticks_raw(); |
|
563 |
+ LOCK_DNS_HASH(); |
|
564 |
+#ifdef DNS_LU_LST |
|
565 |
+ clist_foreach_safe(dns_last_used_lst, l, tmp, next){ |
|
566 |
+ if (*dns_cache_mem_used<=target) break; |
|
567 |
+ e=(struct dns_hash_entry*)(((char*)l)- |
|
568 |
+ (char*)&((struct dns_hash_entry*)(0))->last_used_lst); |
|
569 |
+ if (!expired_only || ((s_ticks_t)(now-e->expire)>=0)){ |
|
570 |
+ _dns_hash_remove(e); |
|
571 |
+ deleted++; |
|
572 |
+ } |
|
573 |
+ } |
|
574 |
+#else |
|
575 |
+ for(h=start; h!=(start+DNS_HASH_SIZE); h++){ |
|
576 |
+ clist_foreach_safe(&dns_hash[h%DNS_HASH_SIZE], e, t, next){ |
|
577 |
+ if (*dns_cache_mem_used<=target) |
|
578 |
+ goto skip; |
|
579 |
+ if ((s_ticks_t)(now-e->expire)>=0){ |
|
580 |
+ _dns_hash_remove(e); |
|
581 |
+ deleted++; |
|
582 |
+ } |
|
583 |
+ } |
|
584 |
+ } |
|
585 |
+ /* not fair, but faster then random() */ |
|
586 |
+ if (!expired_only){ |
|
587 |
+ for(h=start; h!=(start+DNS_HASH_SIZE); h++){ |
|
588 |
+ clist_foreach_safe(&dns_hash[h%DNS_HASH_SIZE], e, t, next){ |
|
589 |
+ if (*dns_cache_mem_used<=target) |
|
590 |
+ goto skip; |
|
591 |
+ if ((s_ticks_t)(now-e->expire)>=0){ |
|
592 |
+ _dns_hash_remove(e); |
|
593 |
+ deleted++; |
|
594 |
+ } |
|
595 |
+ } |
|
596 |
+ } |
|
597 |
+ } |
|
598 |
+skip: |
|
599 |
+ start=h; |
|
600 |
+#endif |
|
601 |
+ UNLOCK_DNS_HASH(); |
|
602 |
+ return deleted; |
|
603 |
+} |
|
604 |
+ |
|
605 |
+ |
|
606 |
+ |
|
607 |
+/* locking version (the dns hash must _not_be locked externally) |
|
608 |
+ * returns 0 when not found, the searched entry on success (with CNAMEs |
|
609 |
+ * followed) or the last CNAME entry from an unfinished CNAME chain, |
|
610 |
+ * if the search matches a CNAME. On error sets *err (e.g. recursive CNAMEs). |
|
611 |
+ * it increases the internal refcnt => when finished dns_hash_put() must |
|
612 |
+ * be called on the returned entry |
|
613 |
+ * WARNING: - the return might be a CNAME even if type!=CNAME, see above */ |
|
614 |
+inline static struct dns_hash_entry* dns_hash_get(str* name, int type, int* h, |
|
615 |
+ int* err) |
|
616 |
+{ |
|
617 |
+ struct dns_hash_entry* e; |
|
618 |
+ |
|
619 |
+ LOCK_DNS_HASH(); |
|
620 |
+ e=_dns_hash_find(name, type, h, err); |
|
621 |
+ if (e){ |
|
622 |
+ atomic_inc(&e->refcnt); |
|
623 |
+ } |
|
624 |
+ UNLOCK_DNS_HASH(); |
|
625 |
+ return e; |
|
626 |
+} |
|
627 |
+ |
|
628 |
+ |
|
629 |
+ |
|
630 |
+/* adds a fully created and init. entry (see dns_cache_mk_entry()) to the hash |
|
631 |
+ * table |
|
632 |
+ * returns 0 on success, -1 on error */ |
|
633 |
+inline static int dns_cache_add(struct dns_hash_entry* e) |
|
634 |
+{ |
|
635 |
+ int h; |
|
636 |
+ |
|
637 |
+ /* check space */ |
|
638 |
+ /* atomic_add_long(dns_cache_total_used, e->size); */ |
|
639 |
+ if ((*dns_cache_mem_used+e->total_size)>=dns_cache_max_mem){ |
|
640 |
+ LOG(L_WARN, "WARNING: dns_cache_add: cache full, trying to free...\n"); |
|
641 |
+ /* free ~ 12% of the cache */ |
|
642 |
+ dns_cache_free_mem(*dns_cache_mem_used/16*14, 1); |
|
643 |
+ if ((*dns_cache_mem_used+e->total_size)>=dns_cache_max_mem){ |
|
644 |
+ LOG(L_ERR, "ERROR: dns_cache_add: max. cache mem size exceeded\n"); |
|
645 |
+ return -1; |
|
646 |
+ } |
|
647 |
+ } |
|
648 |
+ atomic_inc(&e->refcnt); |
|
649 |
+ h=dns_hash_no(e->name, e->name_len, e->type); |
|
650 |
+ DBG("dns_cache_add: adding %.*s(%d) %d (flags=%0x) at %d\n", |
|
651 |
+ e->name_len, e->name, e->name_len, e->type, e->err_flags, h); |
|
652 |
+ LOCK_DNS_HASH(); |
|
653 |
+ *dns_cache_mem_used+=e->total_size; /* no need for atomic ops, written |
|
654 |
+ only from within a lock */ |
|
655 |
+ clist_append(&dns_hash[h], e, next, prev); |
|
656 |
+#ifdef DNS_LU_LST |
|
657 |
+ clist_append(dns_last_used_lst, &e->last_used_lst, next, prev); |
|
658 |
+#endif |
|
659 |
+ UNLOCK_DNS_HASH(); |
|
660 |
+ return 0; |
|
661 |
+} |
|
662 |
+ |
|
663 |
+ |
|
664 |
+ |
|
665 |
+/* same as above, but it must be called with the dns hash lock held |
|
666 |
+ * returns 0 on success, -1 on error */ |
|
667 |
+inline static int dns_cache_add_unsafe(struct dns_hash_entry* e) |
|
668 |
+{ |
|
669 |
+ int h; |
|
670 |
+ |
|
671 |
+ /* check space */ |
|
672 |
+ /* atomic_add_long(dns_cache_total_used, e->size); */ |
|
673 |
+ if ((*dns_cache_mem_used+e->total_size)>=dns_cache_max_mem){ |
|
674 |
+ LOG(L_WARN, "WARNING: dns_cache_add: cache full, trying to free...\n"); |
|
675 |
+ /* free ~ 12% of the cache */ |
|
676 |
+ UNLOCK_DNS_HASH(); |
|
677 |
+ dns_cache_free_mem(*dns_cache_mem_used/16*14, 1); |
|
678 |
+ LOCK_DNS_HASH(); |
|
679 |
+ if ((*dns_cache_mem_used+e->total_size)>=dns_cache_max_mem){ |
|
680 |
+ LOG(L_ERR, "ERROR: dns_cache_add: max. cache mem size exceeded\n"); |
|
681 |
+ return -1; |
|
682 |
+ } |
|
683 |
+ } |
|
684 |
+ atomic_inc(&e->refcnt); |
|
685 |
+ h=dns_hash_no(e->name, e->name_len, e->type); |
|
686 |
+ DBG("dns_cache_add: adding %.*s(%d) %d (flags=%0x) at %d\n", |
|
687 |
+ e->name_len, e->name, e->name_len, e->type, e->err_flags, h); |
|
688 |
+ *dns_cache_mem_used+=e->total_size; /* no need for atomic ops, written |
|
689 |
+ only from within a lock */ |
|
690 |
+ clist_append(&dns_hash[h], e, next, prev); |
|
691 |
+#ifdef DNS_LU_LST |
|
692 |
+ clist_append(dns_last_used_lst, &e->last_used_lst, next, prev); |
|
693 |
+#endif |
|
694 |
+ return 0; |
|
695 |
+} |
|
696 |
+ |
|
697 |
+ |
|
698 |
+ |
|
699 |
+/* creates a "negative" entry which will be valid for ttl seconds */ |
|
700 |
+inline static struct dns_hash_entry* dns_cache_mk_bad_entry(str* name, |
|
701 |
+ int type, |
|
702 |
+ int ttl, |
|
703 |
+ int flags) |
|
704 |
+{ |
|
705 |
+ struct dns_hash_entry* e; |
|
706 |
+ int size; |
|
707 |
+ ticks_t now; |
|
708 |
+ |
|
709 |
+ DBG("dns_cache_mk_bad_entry(%.*s, %d, %d, %d)\n", name->len, name->s, |
|
710 |
+ type, ttl, flags); |
|
711 |
+ size=sizeof(struct dns_hash_entry)+name->len-1+1; |
|
712 |
+ e=shm_malloc(size); |
|
713 |
+ if (e==0){ |
|
714 |
+ LOG(L_ERR, "ERROR: dns_cache_mk_ip_entry: out of memory\n"); |
|
715 |
+ return 0; |
|
716 |
+ } |
|
717 |
+ memset(e, 0, size); /* init with 0*/ |
|
718 |
+ e->total_size=size; |
|
719 |
+ e->name_len=name->len; |
|
720 |
+ e->type=type; |
|
721 |
+ now=get_ticks_raw(); |
|
722 |
+ e->last_used=now; |
|
723 |
+ e->expire=now+S_TO_TICKS(ttl); |
|
724 |
+ memcpy(e->name, name->s, name->len); |
|
725 |
+ e->err_flags=flags; |
|
726 |
+ return e; |
|
727 |
+} |
|
728 |
+ |
|
729 |
+ |
|
730 |
+ |
|
731 |
+/* create a a/aaaa hash entry from a name and ip address |
|
732 |
+ * returns 0 on error */ |
|
733 |
+inline static struct dns_hash_entry* dns_cache_mk_ip_entry(str* name, |
|
734 |
+ struct ip_addr* ip) |
|
735 |
+{ |
|
736 |
+ struct dns_hash_entry* e; |
|
737 |
+ int size; |
|
738 |
+ ticks_t now; |
|
739 |
+ |
|
740 |
+ /* everything is allocated in one block: dns_hash_entry + name + |
|
741 |
+ * + dns_rr + rdata; dns_rr must start at an aligned adress, |
|
742 |
+ * hence we need to round dns_hash_entry+name size to a sizeof(long) |
|
743 |
+ * multiple. |
|
744 |
+ * Memory image: |
|
745 |
+ * struct dns_hash_entry |
|
746 |
+ * name (name_len+1 bytes) |
|
747 |
+ * padding to multiple of sizeof(long) |
|
748 |
+ * dns_rr |
|
749 |
+ * rdata (no padding needed, since for ip is just an array of chars) |
|
750 |
+ */ |
|
751 |
+ size=ROUND_POINTER(sizeof(struct dns_hash_entry)+name->len-1+1)+ |
|
752 |
+ sizeof(struct dns_rr)+ ip->len; |
|
753 |
+ e=shm_malloc(size); |
|
754 |
+ if (e==0){ |
|
755 |
+ LOG(L_ERR, "ERROR: dns_cache_mk_ip_entry: out of memory\n"); |
|
756 |
+ return 0; |
|
757 |
+ } |
|
758 |
+ memset(e, 0, size); /* init with 0*/ |
|
759 |
+ e->total_size=size; |
|
760 |
+ e->name_len=name->len; |
|
761 |
+ e->type=(ip->af==AF_INET)?T_A:T_AAAA; |
|
762 |
+ now=get_ticks_raw(); |
|
763 |
+ e->last_used=now; |
|
764 |
+ e->expire=now-1; /* maximum expire */ |
|
765 |
+ memcpy(e->name, name->s, name->len); /* memset makes sure is 0-term. */ |
|
766 |
+ e->rr_lst=(void*)((char*)e+ |
|
767 |
+ ROUND_POINTER(sizeof(struct dns_hash_entry)+name->len-1+1)); |
|
768 |
+ e->rr_lst->rdata=(void*)((char*)e->rr_lst+sizeof(struct dns_rr)); |
|
769 |
+ e->rr_lst->expire=now-1; /* maximum expire */ |
|
770 |
+ /* no need to align rr_lst->rdata for a or aaaa records */ |
|
771 |
+ memcpy(e->rr_lst->rdata, ip->u.addr, ip->len); |
|
772 |
+ return e; |
|
773 |
+} |
|
774 |
+ |
|
775 |
+ |
|
776 |
+ |
|
777 |
+/* create a dns hash entry from a name and a rdata list (pkg_malloc'ed) |
|
778 |
+ * (it will use only the type records with the name "name" from the |
|
779 |
+ * rdata list with one exception: if a matching CNAME with the same |
|
780 |
+ * name is found, the search will stop and this will be the record used) |
|
781 |
+ * returns 0 on error and removes the used elements from the rdata list*/ |
|
782 |
+inline static struct dns_hash_entry* dns_cache_mk_rd_entry(str* name, int type, |
|
783 |
+ struct rdata** rd_lst) |
|
784 |
+{ |
|
785 |
+ struct dns_hash_entry* e; |
|
786 |
+ struct dns_rr* rr; |
|
787 |
+ struct dns_rr** tail_rr; |
|
788 |
+ struct rdata** p; |
|
789 |
+ struct rdata* tmp_lst; |
|
790 |
+ struct rdata** tail; |
|
791 |
+ struct rdata* l; |
|
792 |
+ int size; |
|
793 |
+ ticks_t now; |
|
794 |
+ unsigned int max_ttl; |
|
795 |
+ unsigned int ttl; |
|
796 |
+ |
|
797 |
+#define rec_matches(rec, t, n) /*(struct rdata* record, int type, str* name)*/\ |
|
798 |
+ ( ((rec)->name_len==(n)->len) && ((rec)->type==(t)) && \ |
|
799 |
+ (strncasecmp((rec)->name, (n)->s, (n)->len)==0)) |
|
800 |
+ /* init */ |
|
801 |
+ tmp_lst=0; |
|
802 |
+ tail=&tmp_lst; |
|
803 |
+ |
|
804 |
+ |
|
805 |
+ /* everything is allocated in one block: dns_hash_entry + name + |
|
806 |
+ * + dns_rr + rdata_raw+ ....; dns_rr must start at an aligned adress, |
|
807 |
+ * hence we need to round dns_hash_entry+name size to a sizeof(long) |
|
808 |
+ * multiple. If rdata type requires it, rdata_raw might need to be also |
|
809 |
+ * aligned. |
|
810 |
+ * Memory image: |
|
811 |
+ * struct dns_hash_entry (e) |
|
812 |
+ * name (name_len+1 bytes) (&e->name[0]) |
|
813 |
+ * padding to multiple of sizeof(char*) |
|
814 |
+ * dns_rr1 (e->rr_lst) |
|
815 |
+ * possible padding: no padding for a_rdata or aaaa_rdata, |
|
816 |
+ * multipe of sizeof(short) for srv_rdata, |
|
817 |
+ * multiple of sizeof(long) for naptr_rdata and others |
|
818 |
+ * dns_rr1->rdata (e->rr_lst->rdata) |
|
819 |
+ * padding to multipe of sizeof long |
|
820 |
+ * dns_rr2 (e->rr_lst->next) |
|
821 |
+ * .... |
|
822 |
+ * |
|
823 |
+ */ |
|
824 |
+ size=0; |
|
825 |
+ if (*rd_lst==0) |
|
826 |
+ return 0; |
|
827 |
+ /* find the first matching rr, if it's a CNAME use CNAME as type, |
|
828 |
+ * if not continue with the original type */ |
|
829 |
+ for(p=rd_lst; *p; p=&(*p)->next){ |
|
830 |
+ if (((*p)->name_len==name->len) && |
|
831 |
+ (((*p)->type==type) || ((*p)->type==T_CNAME)) && |
|
832 |
+ (strncasecmp((*p)->name, name->s, name->len)==0)){ |
|
833 |
+ type=(*p)->type; |
|
834 |
+ break; |
|
835 |
+ } |
|
836 |
+ } |
|
837 |
+ /* continue, we found the type we are looking for */ |
|
838 |
+ switch(type){ |
|
839 |
+ case T_A: |
|
840 |
+ for(; *p;){ |
|
841 |
+ if (!rec_matches((*p), type, name)){ |
|
842 |
+ /* skip this record */ |
|
843 |
+ p=&(*p)->next; /* advance */ |
|
844 |
+ continue; |
|
845 |
+ } |
|
846 |
+ size+=ROUND_POINTER(sizeof(struct dns_rr)+ |
|
847 |
+ sizeof(struct a_rdata)); |
|
848 |
+ /* add it to our tmp. lst */ |
|
849 |
+ *tail=*p; |
|
850 |
+ tail=&(*p)->next; |
|
851 |
+ /* detach it from the rd list */ |
|
852 |
+ *p=(*p)->next; |
|
853 |
+ /* don't advance p, because the crt. elem. has |
|
854 |
+ * just been elimintated */ |
|
855 |
+ } |
|
856 |
+ break; |
|
857 |
+ case T_AAAA: |
|
858 |
+ for(; *p;){ |
|
859 |
+ if (!rec_matches((*p), type, name)){ |
|
860 |
+ /* skip this record */ |
|
861 |
+ p=&(*p)->next; /* advance */ |
|
862 |
+ continue; |
|
863 |
+ } |
|
864 |
+ /* no padding */ |
|
865 |
+ size+=ROUND_POINTER(sizeof(struct dns_rr)+ |
|
866 |
+ sizeof(struct aaaa_rdata)); |
|
867 |
+ /* add it to our tmp. lst */ |
|
868 |
+ *tail=*p; |
|
869 |
+ tail=&(*p)->next; |
|
870 |
+ /* detach it from the rd list */ |
|
871 |
+ *p=(*p)->next; |
|
872 |
+ /* don't advance p, because the crt. elem. has |
|
873 |
+ * just been elimintated */ |
|
874 |
+ } |
|
875 |
+ break; |
|
876 |
+ case T_SRV: |
|
877 |
+ for(; *p;){ |
|
878 |
+ if (!rec_matches((*p), type, name)){ |
|
879 |
+ /* skip this record */ |
|
880 |
+ p=&(*p)->next; /* advance */ |
|
881 |
+ continue; |
|
882 |
+ } |
|
883 |
+ /* padding to short */ |
|
884 |
+ size+=ROUND_POINTER(ROUND_SHORT(sizeof(struct dns_rr))+ |
|
885 |
+ SRV_RDATA_SIZE(*(struct srv_rdata*)(*p)->rdata)); |
|
886 |
+ /* add it to our tmp. lst */ |
|
887 |
+ *tail=*p; |
|
888 |
+ tail=&(*p)->next; |
|
889 |
+ /* detach it from the rd list */ |
|
890 |
+ *p=(*p)->next; |
|
891 |
+ /* don't advance p, because the crt. elem. has |
|
892 |
+ * just been elimintated */ |
|
893 |
+ } |
|
894 |
+ break; |
|
895 |
+ case T_NAPTR: |
|
896 |
+ for(; *p;){ |
|
897 |
+ if (!rec_matches((*p), type, name)){ |
|
898 |
+ /* skip this record */ |
|
899 |
+ p=&(*p)->next; /* advance */ |
|
900 |
+ continue; |
|
901 |
+ } |
|
902 |
+ /* padding to char* */ |
|
903 |
+ size+=ROUND_POINTER(ROUND_POINTER(sizeof(struct dns_rr))+ |
|
904 |
+ NAPTR_RDATA_SIZE(*(struct naptr_rdata*)(*p)->rdata)); |
|
905 |
+ /* add it to our tmp. lst */ |
|
906 |
+ *tail=*p; |
|
907 |
+ tail=&(*p)->next; |
|
908 |
+ /* detach it from the rd list */ |
|
909 |
+ *p=(*p)->next; |
|
910 |
+ /* don't advance p, because the crt. elem. has |
|
911 |
+ * just been elimintated */ |
|
912 |
+ } |
|
913 |
+ break; |
|
914 |
+ case T_CNAME: |
|
915 |
+ for(; *p;){ |
|
916 |
+ if (!rec_matches((*p), type, name)){ |
|
917 |
+ /* skip this record */ |
|
918 |
+ p=&(*p)->next; /* advance */ |
|
919 |
+ continue; |
|
920 |
+ } |
|
921 |
+ /* no padding */ |
|
922 |
+ size+=ROUND_POINTER(sizeof(struct dns_rr)+ |
|
923 |
+ CNAME_RDATA_SIZE(*(struct cname_rdata*)(*p)->rdata)); |
|
924 |
+ /* add it to our tmp. lst */ |
|
925 |
+ *tail=*p; |
|
926 |
+ tail=&(*p)->next; |
|
927 |
+ /* detach it from the rd list */ |
|
928 |
+ *p=(*p)->next; |
|
929 |
+ /* don't advance p, because the crt. elem. has |
|
930 |
+ * just been elimintated */ |
|
931 |
+ } |
|
932 |
+ break; |
|
933 |
+ default: |
|
934 |
+ LOG(L_CRIT, "BUG: dns_cache_mk_rd_entry: type %d not " |
|
935 |
+ "supported\n", type); |
|
936 |
+ /* we don't know what to do with it, so don't |
|
937 |
+ * add it to the tmp_lst */ |
|
938 |
+ return 0; /* error */ |
|
939 |
+ } |
|
940 |
+ *tail=0; /* mark the end of our tmp_lst */ |
|
941 |
+ if (size==0){ |
|
942 |
+ DBG("dns_cache_mk_rd_entry: entry %.*s (%d) not found\n", |
|
943 |
+ name->len, name->s, type); |
|
944 |
+ return 0; |
|
945 |
+ } |
|
946 |
+ /* compute size */ |
|
947 |
+ size+=ROUND_POINTER(sizeof(struct dns_hash_entry)+name->len-1+1); |
|
948 |
+ e=shm_malloc(size); |
|
949 |
+ if (e==0){ |
|
950 |
+ LOG(L_ERR, "ERROR: dns_cache_mk_ip_entry: out of memory\n"); |
|
951 |
+ return 0; |
|
952 |
+ } |
|
953 |
+ memset(e, 0, size); /* init with 0 */ |
|
954 |
+ e->total_size=size; |
|
955 |
+ e->name_len=name->len; |
|
956 |
+ e->type=type; |
|
957 |
+ now=get_ticks_raw(); |
|
958 |
+ e->last_used=now; |
|
959 |
+ memcpy(e->name, name->s, name->len); /* memset makes sure is 0-term. */ |
|
960 |
+ e->rr_lst=(struct dns_rr*)((char*)e+ |
|
961 |
+ ROUND_POINTER(sizeof(struct dns_hash_entry)+name->len-1+1)); |
|
962 |
+ tail_rr=&(e->rr_lst); |
|
963 |
+ rr=e->rr_lst; |
|
964 |
+ max_ttl=0; |
|
965 |
+ /* copy the actual data */ |
|
966 |
+ switch(type){ |
|
967 |
+ case T_A: |
|
968 |
+ for(l=tmp_lst; l; l=l->next){ |
|
969 |
+ ttl=FIX_TTL(l->ttl); |
|