/src/kamailio/src/core/dns_cache.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * resolver/dns related functions, dns cache and failover |
3 | | * |
4 | | * Copyright (C) 2006 iptelorg GmbH |
5 | | * |
6 | | * This file is part of Kamailio, a free SIP server. |
7 | | * |
8 | | * Kamailio is free software; you can redistribute it and/or modify |
9 | | * it under the terms of the GNU General Public License as published by |
10 | | * the Free Software Foundation; either version 2 of the License, or |
11 | | * (at your option) any later version |
12 | | * |
13 | | * Kamailio is distributed in the hope that it will be useful, |
14 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | | * GNU General Public License for more details. |
17 | | * |
18 | | * You should have received a copy of the GNU General Public License |
19 | | * along with this program; if not, write to the Free Software |
20 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
21 | | */ |
22 | | |
23 | | |
24 | | /** |
25 | | * @file |
26 | | * @brief Kamailio core :: resolver/dns related functions, dns cache and failover |
27 | | * @author andrei |
28 | | * @ingroup core |
29 | | * Module: @ref core |
30 | | */ |
31 | | |
32 | | |
33 | | #ifndef __dns_cache_h |
34 | | #define __dns_cache_h |
35 | | |
36 | | #include "str.h" |
37 | | #include "config.h" /* MAX_BRANCHES */ |
38 | | #include "timer.h" |
39 | | #include "ip_addr.h" |
40 | | #include "atomic_ops.h" |
41 | | #include "resolve.h" |
42 | | |
43 | | |
44 | | #if defined(USE_DNS_FAILOVER) && !defined(USE_DNS_CACHE) |
45 | | #error "DNS FAILOVER requires DNS CACHE support (define USE_DNS_CACHE)" |
46 | | #endif |
47 | | |
48 | | #if defined(DNS_WATCHDOG_SUPPORT) && !defined(USE_DNS_CACHE) |
49 | | #error "DNS WATCHDOG requires DNS CACHE support (define USE_DNS_CACHE)" |
50 | | #endif |
51 | | |
52 | | #define DEFAULT_DNS_NEG_CACHE_TTL 60 /* 1 min. */ |
53 | | #define DEFAULT_DNS_CACHE_MIN_TTL 0 /* (disabled) */ |
54 | | #define DEFAULT_DNS_CACHE_MAX_TTL ((unsigned int)(-1)) /* (maxint) */ |
55 | | #define DEFAULT_DNS_MAX_MEM 500 /* 500 Kb */ |
56 | | |
57 | | /** @brief uncomment the define below for SRV weight based load balancing */ |
58 | | #define DNS_SRV_LB |
59 | | |
60 | | |
61 | | /** @brief dns functions return them as negative values (e.g. return -E_DNS_NO_IP) |
62 | | * |
63 | | * listed in the order of importance ( if more errors, only the most important |
64 | | * is returned) |
65 | | */ |
66 | | enum dns_errors |
67 | | { |
68 | | E_DNS_OK = 0, |
69 | | E_DNS_EOR, /**< no more records (not an error) |
70 | | -- returned only by the dns_resolve* |
71 | | functions when called iteratively,; it |
72 | | signals the end of the ip/records list */ |
73 | | E_DNS_UNKNOWN /**< unknown error */, |
74 | | E_DNS_INTERNAL_ERR /**< internal error */, |
75 | | E_DNS_BAD_SRV_ENTRY, |
76 | | E_DNS_NO_SRV /**< unresolvable srv record */, |
77 | | E_DNS_BAD_IP_ENTRY, |
78 | | E_DNS_NO_IP /**< unresolvable a or aaaa records*/, |
79 | | E_DNS_BAD_IP /**< the ip is invalid */, |
80 | | E_DNS_BLOCKLIST_IP /**< the ip is blocklisted */, |
81 | | E_DNS_NAME_TOO_LONG /**< try again with a shorter name */, |
82 | | E_DNS_AF_MISMATCH /**< ipv4 or ipv6 only requested, but |
83 | | name contains an ip addr. of the |
84 | | opossite type */ |
85 | | , |
86 | | E_DNS_NO_NAPTR /**< unresolvable naptr record */, |
87 | | E_DNS_CRITICAL /**< critical error, marks the end |
88 | | of the error table (always last) */ |
89 | | }; |
90 | | |
91 | | |
92 | | /** @brief return a short string, printable error description (err <=0) */ |
93 | | const char *dns_strerror(int err); |
94 | | |
95 | | /** @brief dns entry flags, |
96 | | * shall be on the power of 2 */ |
97 | | /*@{ */ |
98 | 0 | #define DNS_FLAG_BAD_NAME 1 /**< error flag: unresolvable */ |
99 | | #define DNS_FLAG_PERMANENT \ |
100 | 0 | 2 /**< permanent record, never times out, |
101 | | never deleted, never overwritten |
102 | | unless explicitely requested */ |
103 | | /*@} */ |
104 | | |
105 | | /** @name dns requests flags */ |
106 | | /*@{ */ |
107 | | #define DNS_NO_FLAGS 0 |
108 | 0 | #define DNS_IPV4_ONLY 1 |
109 | 0 | #define DNS_IPV6_ONLY 2 |
110 | 0 | #define DNS_IPV6_FIRST 4 |
111 | 0 | #define DNS_SRV_RR_LB 8 /**< SRV RR weight based load balancing */ |
112 | 0 | #define DNS_TRY_NAPTR 16 /**< enable naptr lookup */ |
113 | | /*@} */ |
114 | | |
115 | | |
116 | | /** @name ip blocklist error flags */ |
117 | | /*@{ */ |
118 | | #define IP_ERR_BAD_DST 2 /* destination is marked as bad (e.g. bad ip) */ |
119 | | #define IP_ERR_SND 3 /* send error while using this as destination */ |
120 | | #define IP_ERR_TIMEOUT 4 /* timeout waiting for a response */ |
121 | | #define IP_ERR_TCP_CON 5 /* could not establish tcp connection */ |
122 | | /*@} */ |
123 | | |
124 | | |
125 | | /** @brief stripped down dns rr |
126 | | @note name, type and class are not needed, contained in struct dns_query */ |
127 | | struct dns_rr |
128 | | { |
129 | | struct dns_rr *next; |
130 | | void *rdata; /**< depends on the type */ |
131 | | ticks_t expire; /**< = ttl + crt_time */ |
132 | | }; |
133 | | |
134 | | |
135 | | struct dns_lu_lst |
136 | | { /* last used ordered list */ |
137 | | struct dns_lu_lst *next; |
138 | | struct dns_lu_lst *prev; |
139 | | }; |
140 | | |
141 | | struct dns_hash_entry |
142 | | { |
143 | | /* hash table links */ |
144 | | struct dns_hash_entry *next; |
145 | | struct dns_hash_entry *prev; |
146 | | struct dns_lu_lst last_used_lst; |
147 | | struct dns_rr *rr_lst; |
148 | | atomic_t refcnt; |
149 | | ticks_t last_used; |
150 | | ticks_t expire; /* when the whole entry will expire */ |
151 | | int total_size; |
152 | | unsigned short type; |
153 | | unsigned char ent_flags; /* entry flags: unresolvable/permanent */ |
154 | | unsigned char name_len; /* can be maximum 255 bytes */ |
155 | | char name[1]; /* variable length, name, null terminated |
156 | | (actual length = name_len +1)*/ |
157 | | }; |
158 | | |
159 | | |
160 | | /* to fit in the limit of MAX_BRANCHES */ |
161 | | #if MAX_BRANCHES_LIMIT < 32 |
162 | | typedef unsigned int srv_flags_t; |
163 | | #else |
164 | | typedef unsigned long long srv_flags_t; |
165 | | #endif |
166 | | |
167 | | struct dns_srv_handle |
168 | | { |
169 | | struct dns_hash_entry *srv; /**< srv entry */ |
170 | | struct dns_hash_entry *a; /**< a or aaaa current entry */ |
171 | | #ifdef DNS_SRV_LB |
172 | | srv_flags_t srv_tried_rrs; |
173 | | #endif |
174 | | unsigned short port; /**< current port */ |
175 | | unsigned char srv_no; /**< current record no. in the srv entry */ |
176 | | unsigned char ip_no; /**< current record no. in the a/aaaa entry */ |
177 | | unsigned char proto; /**< protocol number */ |
178 | | }; |
179 | | |
180 | | |
181 | | const char *dns_strerror(int err); |
182 | | |
183 | | void fix_dns_flags(str *gname, str *name); |
184 | | int use_dns_failover_fixup(void *handle, str *gname, str *name, void **val); |
185 | | int use_dns_cache_fixup(void *handle, str *gname, str *name, void **val); |
186 | | int dns_cache_max_mem_fixup(void *handle, str *gname, str *name, void **val); |
187 | | int init_dns_cache(void); |
188 | | #ifdef USE_DNS_CACHE_STATS |
189 | | int init_dns_cache_stats(int iproc_num); |
190 | | #define DNS_CACHE_ALL_STATS "dc_all_stats" |
191 | | #endif |
192 | | void destroy_dns_cache(void); |
193 | | |
194 | | |
195 | | void dns_hash_put(struct dns_hash_entry *e); |
196 | | void dns_hash_put_shm_unsafe(struct dns_hash_entry *e); |
197 | | |
198 | | inline static void dns_srv_handle_put(struct dns_srv_handle *h) |
199 | 0 | { |
200 | 0 | if(h) { |
201 | 0 | if(h->srv) { |
202 | 0 | dns_hash_put(h->srv); |
203 | 0 | h->srv = 0; |
204 | 0 | } |
205 | 0 | if(h->a) { |
206 | 0 | dns_hash_put(h->a); |
207 | 0 | h->a = 0; |
208 | 0 | } |
209 | 0 | } |
210 | 0 | } Unexecuted instantiation: main.c:dns_srv_handle_put Unexecuted instantiation: resolve.c:dns_srv_handle_put Unexecuted instantiation: cfg_core.c:dns_srv_handle_put Unexecuted instantiation: dns_cache.c:dns_srv_handle_put Unexecuted instantiation: forward.c:dns_srv_handle_put |
211 | | |
212 | | |
213 | | /** @brief use it when copying, it manually increases the ref cound */ |
214 | | inline static void dns_srv_handle_ref(struct dns_srv_handle *h) |
215 | 0 | { |
216 | 0 | if(h) { |
217 | 0 | if(h->srv) |
218 | 0 | atomic_inc(&h->srv->refcnt); |
219 | 0 | if(h->a) |
220 | 0 | atomic_inc(&h->a->refcnt); |
221 | 0 | } |
222 | 0 | } Unexecuted instantiation: main.c:dns_srv_handle_ref Unexecuted instantiation: resolve.c:dns_srv_handle_ref Unexecuted instantiation: cfg_core.c:dns_srv_handle_ref Unexecuted instantiation: dns_cache.c:dns_srv_handle_ref Unexecuted instantiation: forward.c:dns_srv_handle_ref |
223 | | |
224 | | |
225 | | /** @brief safe copy increases the refcnt, src must not change while in this function |
226 | | * WARNING: the copy must be dns_srv_handle_put ! */ |
227 | | inline static void dns_srv_handle_cpy( |
228 | | struct dns_srv_handle *dst, struct dns_srv_handle *src) |
229 | 0 | { |
230 | 0 | dns_srv_handle_ref(src); |
231 | 0 | *dst = *src; |
232 | 0 | } Unexecuted instantiation: main.c:dns_srv_handle_cpy Unexecuted instantiation: resolve.c:dns_srv_handle_cpy Unexecuted instantiation: cfg_core.c:dns_srv_handle_cpy Unexecuted instantiation: dns_cache.c:dns_srv_handle_cpy Unexecuted instantiation: forward.c:dns_srv_handle_cpy |
233 | | |
234 | | |
235 | | /** @brief same as above but assume shm_lock held (for internal tm use only) */ |
236 | | inline static void dns_srv_handle_put_shm_unsafe(struct dns_srv_handle *h) |
237 | 0 | { |
238 | 0 | if(h) { |
239 | 0 | if(h->srv) { |
240 | 0 | dns_hash_put_shm_unsafe(h->srv); |
241 | 0 | h->srv = 0; |
242 | 0 | } |
243 | 0 | if(h->a) { |
244 | 0 | dns_hash_put_shm_unsafe(h->a); |
245 | 0 | h->a = 0; |
246 | 0 | } |
247 | 0 | } |
248 | 0 | } Unexecuted instantiation: main.c:dns_srv_handle_put_shm_unsafe Unexecuted instantiation: resolve.c:dns_srv_handle_put_shm_unsafe Unexecuted instantiation: cfg_core.c:dns_srv_handle_put_shm_unsafe Unexecuted instantiation: dns_cache.c:dns_srv_handle_put_shm_unsafe Unexecuted instantiation: forward.c:dns_srv_handle_put_shm_unsafe |
249 | | |
250 | | |
251 | | /** @brief get "next" ip next time a dns_srv_handle function is called |
252 | | * params: h - struct dns_srv_handler |
253 | | * err - return code of the last dns_*_resolve* call |
254 | | * returns: 0 if it doesn't make sense to try another record, |
255 | | * 1 otherwise |
256 | | */ |
257 | | inline static int dns_srv_handle_next(struct dns_srv_handle *h, int err) |
258 | 0 | { |
259 | 0 | if(err < 0) |
260 | 0 | return 0; |
261 | 0 | h->ip_no++; |
262 | 0 | return (h->srv || h->a); |
263 | 0 | } Unexecuted instantiation: main.c:dns_srv_handle_next Unexecuted instantiation: resolve.c:dns_srv_handle_next Unexecuted instantiation: cfg_core.c:dns_srv_handle_next Unexecuted instantiation: dns_cache.c:dns_srv_handle_next Unexecuted instantiation: forward.c:dns_srv_handle_next |
264 | | |
265 | | |
266 | | inline static void dns_srv_handle_init(struct dns_srv_handle *h) |
267 | 0 | { |
268 | 0 | h->srv = h->a = 0; |
269 | 0 | h->srv_no = h->ip_no = 0; |
270 | 0 | h->port = 0; |
271 | 0 | h->proto = 0; |
272 | 0 | #ifdef DNS_SRV_LB |
273 | 0 | h->srv_tried_rrs = 0; |
274 | 0 | #endif |
275 | 0 | } Unexecuted instantiation: main.c:dns_srv_handle_init Unexecuted instantiation: resolve.c:dns_srv_handle_init Unexecuted instantiation: cfg_core.c:dns_srv_handle_init Unexecuted instantiation: dns_cache.c:dns_srv_handle_init Unexecuted instantiation: forward.c:dns_srv_handle_init |
276 | | |
277 | | |
278 | | /** @brief performes a srv query on name |
279 | | * Params: name - srv query target (e.g. _sip._udp.foo.bar) |
280 | | * ip - result: first good ip found |
281 | | * port - result: corresponding port number |
282 | | * flags - resolve options (like ipv4 only, ipv6 prefered a.s.o) |
283 | | * Returns: < 0 on error (can be passed to dns_strerror(), 0 on success |
284 | | */ |
285 | | int dns_srv_get_ip( |
286 | | str *name, struct ip_addr *ip, unsigned short *port, int flags); |
287 | | |
288 | | /** @brief performs an A, AAAA (or both) query/queries |
289 | | * Params: name - query target (e.g. foo.bar) |
290 | | * ip - result: first good ip found |
291 | | * flags - resolve options (like ipv4 only, ipv6 prefered a.s.o) |
292 | | * Returns: < 0 on error (can be passed to dns_strerror(), 0 on success |
293 | | */ |
294 | | int dns_get_ip(str *name, struct ip_addr *ip, int flags); |
295 | | |
296 | | struct hostent *dns_srv_get_he(str *name, unsigned short *port, int flags); |
297 | | struct hostent *dns_get_he(str *name, int flags); |
298 | | |
299 | | |
300 | | /** @brief resolve name to an ip, using srv record. Can be called multiple times |
301 | | * to iterate on all the possible ips, e.g : |
302 | | * dns_srv_handle_init(h); |
303 | | * ret_code=dns_sip_resolve(h,...); |
304 | | * while( dns_srv_handle_next(h, ret_code){ ret_code=dns_sip_resolve(h...); } |
305 | | * dns_srv_handle_put(h); |
306 | | * WARNING: dns_srv_handle_init() must be called to initialize h and |
307 | | * dns_srv_handle_put(h) must be called when h is no longer needed |
308 | | */ |
309 | | int dns_sip_resolve(struct dns_srv_handle *h, str *name, struct ip_addr *ip, |
310 | | unsigned short *port, char *proto, int flags); |
311 | | |
312 | | /** @brief same as above, but fills su instead of changing port and filling an ip */ |
313 | | inline static int dns_sip_resolve2su(struct dns_srv_handle *h, |
314 | | union sockaddr_union *su, str *name, unsigned short port, char *proto, |
315 | | int flags) |
316 | 0 | { |
317 | 0 | struct ip_addr ip; |
318 | 0 | int ret; |
319 | |
|
320 | 0 | ret = dns_sip_resolve(h, name, &ip, &port, proto, flags); |
321 | 0 | if(ret >= 0) |
322 | 0 | init_su(su, &ip, port); |
323 | 0 | return ret; |
324 | 0 | } Unexecuted instantiation: main.c:dns_sip_resolve2su Unexecuted instantiation: resolve.c:dns_sip_resolve2su Unexecuted instantiation: cfg_core.c:dns_sip_resolve2su Unexecuted instantiation: dns_cache.c:dns_sip_resolve2su Unexecuted instantiation: forward.c:dns_sip_resolve2su |
325 | | |
326 | | /** @brief Delete all the entries from the cache. |
327 | | * If del_permanent is 0, then only the |
328 | | * non-permanent entries are deleted. |
329 | | */ |
330 | | void dns_cache_flush(int del_permanent); |
331 | | |
332 | | #ifdef DNS_WATCHDOG_SUPPORT |
333 | | /** @brief sets the state of the DNS servers: |
334 | | * 1: at least one server is up |
335 | | * 0: all the servers are down |
336 | | */ |
337 | | void dns_set_server_state(int state); |
338 | | |
339 | | /** @brief returns the state of the DNS servers */ |
340 | | int dns_get_server_state(void); |
341 | | #endif /* DNS_WATCHDOG_SUPPORT */ |
342 | | |
343 | | /** @brief Adds a new record to the cache. |
344 | | * If there is an existing record with the same name and value |
345 | | * (ip address in case of A/AAAA record, name in case of SRV record) |
346 | | * only the remaining fields are updated. |
347 | | * |
348 | | * Note that permanent records cannot be overwritten unless |
349 | | * the new record is also permanent. A permanent record |
350 | | * completely replaces a non-permanent one. |
351 | | * |
352 | | * Currently only A, AAAA, and SRV records are supported. |
353 | | */ |
354 | | int dns_cache_add_record(unsigned short type, str *name, int ttl, str *value, |
355 | | int priority, int weight, int port, int flags); |
356 | | |
357 | | /** @brief Delete a single record from the cache, |
358 | | * i.e. the record with the same name and value |
359 | | * (ip address in case of A/AAAA record, name in case of SRV record). |
360 | | * |
361 | | * Currently only A, AAAA, and SRV records are supported. |
362 | | */ |
363 | | int dns_cache_delete_single_record( |
364 | | unsigned short type, str *name, str *value, int flags); |
365 | | |
366 | | void dns_set_local_ttl(int ttl); |
367 | | |
368 | | #endif |