logger.conf.sample: add missing comment mark
[asterisk/asterisk.git] / pbx / pbx_dundi.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2006, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20  *
21  * \brief Distributed Universal Number Discovery (DUNDi)
22  */
23
24 /*! \li \ref pbx_dundi.c uses configuration file \ref dundi.conf
25  * \addtogroup configuration_file Configuration Files
26  */
27
28 /*!
29  * \page dundi.conf dundi.conf
30  * \verbinclude dundi.conf.sample
31  */
32
33 /*** MODULEINFO
34         <depend>zlib</depend>
35         <use type="module">res_crypto</use>
36         <use type="external">crypto</use>
37         <support_level>extended</support_level>
38  ***/
39
40 #include "asterisk.h"
41
42 #include "asterisk/network.h"
43 #include <sys/ioctl.h>
44 #include <zlib.h>
45 #include <signal.h>
46 #include <pthread.h>
47 #include <net/if.h>
48
49 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__Darwin__)
50 #include <net/if_dl.h>
51 #include <ifaddrs.h>
52 #include <signal.h>
53 #endif
54
55 #include "asterisk/file.h"
56 #include "asterisk/logger.h"
57 #include "asterisk/channel.h"
58 #include "asterisk/config.h"
59 #include "asterisk/pbx.h"
60 #include "asterisk/module.h"
61 #include "asterisk/frame.h"
62 #include "asterisk/cli.h"
63 #include "asterisk/lock.h"
64 #include "asterisk/md5.h"
65 #include "asterisk/dundi.h"
66 #include "asterisk/sched.h"
67 #include "asterisk/io.h"
68 #include "asterisk/utils.h"
69 #include "asterisk/netsock2.h"
70 #include "asterisk/crypto.h"
71 #include "asterisk/astdb.h"
72 #include "asterisk/acl.h"
73 #include "asterisk/app.h"
74
75 #include "dundi-parser.h"
76
77 /*** DOCUMENTATION
78         <function name="DUNDILOOKUP" language="en_US">
79                 <synopsis>
80                         Do a DUNDi lookup of a phone number.
81                 </synopsis>
82                 <syntax>
83                         <parameter name="number" required="true"/>
84                         <parameter name="context">
85                                 <para>If not specified the default will be <literal>e164</literal>.</para>
86                         </parameter>
87                         <parameter name="options">
88                                 <optionlist>
89                                         <option name="b">
90                                                 <para>Bypass the internal DUNDi cache</para>
91                                         </option>
92                                 </optionlist>
93                         </parameter>
94                 </syntax>
95                 <description>
96                         <para>This will do a DUNDi lookup of the given phone number.</para>
97                         <para>This function will return the Technology/Resource found in the first result
98                         in the DUNDi lookup. If no results were found, the result will be blank.</para>
99                 </description>
100         </function>
101
102
103         <function name="DUNDIQUERY" language="en_US">
104                 <synopsis>
105                         Initiate a DUNDi query.
106                 </synopsis>
107                 <syntax>
108                         <parameter name="number" required="true"/>
109                         <parameter name="context">
110                                 <para>If not specified the default will be <literal>e164</literal>.</para>
111                         </parameter>
112                         <parameter name="options">
113                                 <optionlist>
114                                         <option name="b">
115                                                 <para>Bypass the internal DUNDi cache</para>
116                                         </option>
117                                 </optionlist>
118                         </parameter>
119                 </syntax>
120                 <description>
121                         <para>This will do a DUNDi lookup of the given phone number.</para>
122                         <para>The result of this function will be a numeric ID that can be used to retrieve
123                         the results with the <literal>DUNDIRESULT</literal> function.</para>
124                 </description>
125         </function>
126
127         <function name="DUNDIRESULT" language="en_US">
128                 <synopsis>
129                         Retrieve results from a DUNDIQUERY.
130                 </synopsis>
131                 <syntax>
132                         <parameter name="id" required="true">
133                                 <para>The identifier returned by the <literal>DUNDIQUERY</literal> function.</para>
134                         </parameter>
135                         <parameter name="resultnum">
136                                 <optionlist>
137                                         <option name="number">
138                                                 <para>The number of the result that you want to retrieve, this starts at <literal>1</literal></para>
139                                         </option>
140                                         <option name="getnum">
141                                                 <para>The total number of results that are available.</para>
142                                         </option>
143                                 </optionlist>
144                         </parameter>
145                 </syntax>
146                 <description>
147                         <para>This function will retrieve results from a previous use\n"
148                         of the <literal>DUNDIQUERY</literal> function.</para>
149                 </description>
150         </function>
151  ***/
152
153 #define MAX_RESULTS     64
154
155 #define MAX_PACKET_SIZE 8192
156
157 #define MAX_WEIGHT 59999
158
159 #define DUNDI_MODEL_INBOUND             (1 << 0)
160 #define DUNDI_MODEL_OUTBOUND    (1 << 1)
161 #define DUNDI_MODEL_SYMMETRIC   (DUNDI_MODEL_INBOUND | DUNDI_MODEL_OUTBOUND)
162
163 /*! Keep times of last 10 lookups */
164 #define DUNDI_TIMING_HISTORY    10
165
166 enum {
167         FLAG_ISREG =       (1 << 0),  /*!< Transaction is register request */
168         FLAG_DEAD =        (1 << 1),  /*!< Transaction is dead */
169         FLAG_FINAL =       (1 << 2),  /*!< Transaction has final message sent */
170         FLAG_ISQUAL =      (1 << 3),  /*!< Transaction is a qualification */
171         FLAG_ENCRYPT =     (1 << 4),  /*!< Transaction is encrypted wiht ECX/DCX */
172         FLAG_SENDFULLKEY = (1 << 5),  /*!< Send full key on transaction */
173         FLAG_STOREHIST =   (1 << 6),  /*!< Record historic performance */
174 };
175
176 #define DUNDI_FLAG_INTERNAL_NOPARTIAL (1 << 17)
177
178 #if 0
179 #define DUNDI_SECRET_TIME 15    /* Testing only */
180 #else
181 #define DUNDI_SECRET_TIME DUNDI_DEFAULT_CACHE_TIME
182 #endif
183
184 static struct io_context *io;
185 static struct ast_sched_context *sched;
186 static int netsocket = -1; /* Socket for bindaddr if only one bindaddr. Otherwise the IPv4 socket when bindaddr2 given. */
187 static int netsocket2 = -1; /* IPv6 socket when bindaddr2 given. */
188 static pthread_t netthreadid = AST_PTHREADT_NULL;
189 static pthread_t precachethreadid = AST_PTHREADT_NULL;
190 static pthread_t clearcachethreadid = AST_PTHREADT_NULL;
191 static unsigned int tos = 0;
192 static int dundidebug = 0;
193 static int authdebug = 0;
194 static int dundi_ttl = DUNDI_DEFAULT_TTL;
195 static int dundi_key_ttl = DUNDI_DEFAULT_KEY_EXPIRE;
196 static int dundi_cache_time = DUNDI_DEFAULT_CACHE_TIME;
197 static int global_autokilltimeout = 0;
198 static dundi_eid global_eid;
199 static int default_expiration = 60;
200 static int global_storehistory = 0;
201 static char dept[80];
202 static char org[80];
203 static char locality[80];
204 static char stateprov[80];
205 static char country[80];
206 static char email[80];
207 static char phone[80];
208 static char secretpath[80];
209 static char cursecret[80];
210 static char ipaddr[80];
211 static time_t rotatetime;
212 static dundi_eid empty_eid = { { 0, 0, 0, 0, 0, 0 } };
213 static int dundi_shutdown = 0;
214
215 struct permission {
216         AST_LIST_ENTRY(permission) list;
217         int allow;
218         char name[0];
219 };
220
221 struct dundi_packet {
222         AST_LIST_ENTRY(dundi_packet) list;
223         struct dundi_hdr *h;
224         int datalen;
225         struct dundi_transaction *parent;
226         int retransid;
227         int retrans;
228         unsigned char data[0];
229 };
230
231 struct dundi_hint_metadata {
232         unsigned short flags;
233         char exten[AST_MAX_EXTENSION];
234 };
235
236 struct dundi_precache_queue {
237         AST_LIST_ENTRY(dundi_precache_queue) list;
238         char *context;
239         time_t expiration;
240         char number[0];
241 };
242
243 struct dundi_request;
244
245 struct dundi_transaction {
246         struct ast_sockaddr addr;                      /*!< Other end of transaction */
247         struct timeval start;                          /*!< When this transaction was created */
248         dundi_eid eids[DUNDI_MAX_STACK + 1];
249         int eidcount;                                  /*!< Number of eids in eids */
250         dundi_eid us_eid;                              /*!< Our EID, to them */
251         dundi_eid them_eid;                            /*!< Their EID, to us */
252         ast_aes_encrypt_key ecx;                       /*!< AES 128 Encryption context */
253         ast_aes_decrypt_key dcx;                       /*!< AES 128 Decryption context */
254         unsigned int flags;                            /*!< Has final packet been sent */
255         int ttl;                                       /*!< Remaining TTL for queries on this one */
256         int thread;                                    /*!< We have a calling thread */
257         int retranstimer;                              /*!< How long to wait before retransmissions */
258         int autokillid;                                /*!< ID to kill connection if answer doesn't come back fast enough */
259         int autokilltimeout;                           /*!< Recommended timeout for autokill */
260         unsigned short strans;                         /*!< Our transaction identifier */
261         unsigned short dtrans;                         /*!< Their transaction identifer */
262         unsigned char iseqno;                          /*!< Next expected received seqno */
263         unsigned char oiseqno;                         /*!< Last received incoming seqno */
264         unsigned char oseqno;                          /*!< Next transmitted seqno */
265         unsigned char aseqno;                          /*!< Last acknowledge seqno */
266         AST_LIST_HEAD_NOLOCK(packetlist, dundi_packet) packets;  /*!< Packets to be retransmitted */
267         struct packetlist lasttrans;                   /*!< Last transmitted / ACK'd packet */
268         struct dundi_request *parent;                  /*!< Parent request (if there is one) */
269         AST_LIST_ENTRY(dundi_transaction) parentlist;  /*!< Next with respect to the parent */
270         AST_LIST_ENTRY(dundi_transaction) all;         /*!< Next with respect to all DUNDi transactions */
271 };
272
273 struct dundi_request {
274         char dcontext[AST_MAX_EXTENSION];
275         char number[AST_MAX_EXTENSION];
276         dundi_eid query_eid;
277         dundi_eid root_eid;
278         struct dundi_result *dr;
279         struct dundi_entity_info *dei;
280         struct dundi_hint_metadata *hmd;
281         int maxcount;
282         int respcount;
283         int expiration;
284         int cbypass;
285         int pfds[2];
286         uint32_t crc32;                              /*!< CRC-32 of all but root EID's in avoid list */
287         AST_LIST_HEAD_NOLOCK(, dundi_transaction) trans;  /*!< Transactions */
288         AST_LIST_ENTRY(dundi_request) list;
289 };
290
291 struct dundi_mapping {
292         char dcontext[AST_MAX_EXTENSION];
293         char lcontext[AST_MAX_EXTENSION];
294         int _weight;
295         char *weightstr;
296         int options;
297         int tech;
298         int dead;
299         char dest[512];
300         AST_LIST_ENTRY(dundi_mapping) list;
301 };
302
303 struct dundi_peer {
304         dundi_eid eid;
305         struct ast_sockaddr addr;              /*!< Address of DUNDi peer */
306         AST_LIST_HEAD_NOLOCK(permissionlist, permission) permit;
307         struct permissionlist include;
308         dundi_eid us_eid;
309         char inkey[80];
310         char outkey[80];
311         int dead;
312         int registerid;
313         int qualifyid;
314         int sentfullkey;
315         int order;
316         unsigned char txenckey[256];           /*!< Transmitted encrypted key + sig */
317         unsigned char rxenckey[256];           /*!< Cache received encrypted key + sig */
318         uint32_t us_keycrc32;                  /*!< CRC-32 of our key */
319         ast_aes_encrypt_key us_ecx;            /*!< Cached AES 128 Encryption context */
320         ast_aes_decrypt_key us_dcx;            /*!< Cached AES 128 Decryption context */
321         uint32_t them_keycrc32;                /*!< CRC-32 of our key */
322         ast_aes_encrypt_key them_ecx;          /*!< Cached AES 128 Encryption context */
323         ast_aes_decrypt_key them_dcx;          /*!< Cached AES 128 Decryption context */
324         time_t keyexpire;                      /*!< When to expire/recreate key */
325         int registerexpire;
326         int lookuptimes[DUNDI_TIMING_HISTORY];
327         char *lookups[DUNDI_TIMING_HISTORY];
328         int avgms;
329         struct dundi_transaction *regtrans;    /*!< Registration transaction */
330         struct dundi_transaction *qualtrans;   /*!< Qualify transaction */
331         int model;                             /*!< Pull model */
332         int pcmodel;                           /*!< Push/precache model */
333         /*! Dynamic peers register with us */
334         unsigned int dynamic:1;
335         int lastms;                            /*!< Last measured latency */
336         int maxms;                             /*!< Max permissible latency */
337         struct timeval qualtx;                 /*!< Time of transmit */
338         AST_LIST_ENTRY(dundi_peer) list;
339 };
340
341 static AST_LIST_HEAD_STATIC(peers, dundi_peer);
342 static AST_LIST_HEAD_STATIC(pcq, dundi_precache_queue);
343 static AST_LIST_HEAD_NOLOCK_STATIC(mappings, dundi_mapping);
344 static AST_LIST_HEAD_NOLOCK_STATIC(requests, dundi_request);
345 static AST_LIST_HEAD_NOLOCK_STATIC(alltrans, dundi_transaction);
346
347 /*!
348  * \brief Wildcard peer
349  *
350  * This peer is created if the [*] entry is specified in dundi.conf
351  */
352 static struct dundi_peer *any_peer;
353
354 static int dundi_xmit(struct dundi_packet *pack);
355
356 static void dundi_debug_output(const char *data)
357 {
358         if (dundidebug)
359                 ast_verbose("%s", data);
360 }
361
362 static void dundi_error_output(const char *data)
363 {
364         ast_log(LOG_WARNING, "%s", data);
365 }
366
367 static int has_permission(struct permissionlist *permlist, char *cont)
368 {
369         struct permission *perm;
370         int res = 0;
371
372         AST_LIST_TRAVERSE(permlist, perm, list) {
373                 if (!strcasecmp(perm->name, "all") || !strcasecmp(perm->name, cont))
374                         res = perm->allow;
375         }
376
377         return res;
378 }
379
380 static char *tech2str(int tech)
381 {
382         switch(tech) {
383         case DUNDI_PROTO_NONE:
384                 return "None";
385         case DUNDI_PROTO_IAX:
386                 return "IAX2";
387         case DUNDI_PROTO_SIP:
388                 return "SIP";
389         case DUNDI_PROTO_H323:
390                 return "H323";
391         default:
392                 return "Unknown";
393         }
394 }
395
396 static int str2tech(char *str)
397 {
398         if (!strcasecmp(str, "IAX") || !strcasecmp(str, "IAX2"))
399                 return DUNDI_PROTO_IAX;
400         else if (!strcasecmp(str, "SIP"))
401                 return DUNDI_PROTO_SIP;
402         else if (!strcasecmp(str, "H323"))
403                 return DUNDI_PROTO_H323;
404         else
405                 return -1;
406 }
407
408 static int dundi_lookup_internal(struct dundi_result *result, int maxret, struct ast_channel *chan, const char *dcontext, const char *number, int ttl, int blockempty, struct dundi_hint_metadata *md, int *expiration, int cybpass, int modeselect, dundi_eid *skip, dundi_eid *avoid[], int direct[]);
409 static int dundi_precache_internal(const char *context, const char *number, int ttl, dundi_eid *avoids[]);
410 static struct dundi_transaction *create_transaction(struct dundi_peer *p);
411
412 static struct dundi_transaction *find_transaction(struct dundi_hdr *hdr, struct ast_sockaddr *sin)
413 {
414         struct dundi_transaction *trans;
415
416         /* Look for an exact match first */
417         AST_LIST_TRAVERSE(&alltrans, trans, all) {
418                 if (!ast_sockaddr_cmp(&trans->addr, sin) &&
419                         ((trans->strans == (ntohs(hdr->dtrans) & 32767)) /* Matches our destination */ ||
420                                 ((trans->dtrans == (ntohs(hdr->strans) & 32767)) && (!hdr->dtrans))) /* We match their destination */) {
421                         if (hdr->strans) {
422                                 trans->dtrans = ntohs(hdr->strans) & 32767;
423                         }
424                         return trans;
425                 }
426         }
427
428         switch(hdr->cmdresp & 0x7f) {
429         case DUNDI_COMMAND_DPDISCOVER:
430         case DUNDI_COMMAND_EIDQUERY:
431         case DUNDI_COMMAND_PRECACHERQ:
432         case DUNDI_COMMAND_REGREQ:
433         case DUNDI_COMMAND_NULL:
434         case DUNDI_COMMAND_ENCRYPT:
435                 if (!hdr->strans)
436                         break;
437                 /* Create new transaction */
438                 if (!(trans = create_transaction(NULL)))
439                         break;
440                 ast_sockaddr_copy(&trans->addr, sin);
441                 trans->dtrans = ntohs(hdr->strans) & 32767;
442         default:
443                 break;
444         }
445
446         return trans;
447 }
448
449 static int dundi_send(struct dundi_transaction *trans, int cmdresp, int flags, int final, struct dundi_ie_data *ied);
450
451 static int dundi_ack(struct dundi_transaction *trans, int final)
452 {
453         return dundi_send(trans, DUNDI_COMMAND_ACK, 0, final, NULL);
454 }
455 static void dundi_reject(struct dundi_hdr *h, struct ast_sockaddr *sin)
456 {
457         struct {
458                 struct dundi_packet pack;
459                 struct dundi_hdr hdr;
460         } tmp;
461         struct dundi_transaction trans;
462         /* Never respond to an INVALID with another INVALID */
463         if (h->cmdresp == DUNDI_COMMAND_INVALID)
464                 return;
465         memset(&tmp, 0, sizeof(tmp));
466         memset(&trans, 0, sizeof(trans));
467         ast_sockaddr_copy(&trans.addr, sin);
468         tmp.hdr.strans = h->dtrans;
469         tmp.hdr.dtrans = h->strans;
470         tmp.hdr.iseqno = h->oseqno;
471         tmp.hdr.oseqno = h->iseqno;
472         tmp.hdr.cmdresp = DUNDI_COMMAND_INVALID;
473         tmp.hdr.cmdflags = 0;
474         tmp.pack.h = (struct dundi_hdr *)tmp.pack.data;
475         tmp.pack.datalen = sizeof(struct dundi_hdr);
476         tmp.pack.parent = &trans;
477         dundi_xmit(&tmp.pack);
478 }
479
480 static int get_trans_id(void)
481 {
482         struct dundi_transaction *t;
483         int stid = (ast_random() % 32766) + 1;
484         int tid = stid;
485
486         do {
487                 AST_LIST_TRAVERSE(&alltrans, t, all) {
488                         if (t->strans == tid)
489                                 break;
490                 }
491                 if (!t)
492                         return tid;
493                 tid = (tid % 32766) + 1;
494         } while (tid != stid);
495
496         return 0;
497 }
498
499 static int reset_transaction(struct dundi_transaction *trans)
500 {
501         int tid;
502         tid = get_trans_id();
503         if (tid < 1)
504                 return -1;
505         trans->strans = tid;
506         trans->dtrans = 0;
507         trans->iseqno = 0;
508         trans->oiseqno = 0;
509         trans->oseqno = 0;
510         trans->aseqno = 0;
511         ast_clear_flag(trans, FLAG_FINAL);
512         return 0;
513 }
514
515 static struct dundi_peer *find_peer(dundi_eid *eid)
516 {
517         struct dundi_peer *cur = NULL;
518
519         if (!eid)
520                 eid = &empty_eid;
521
522         AST_LIST_TRAVERSE(&peers, cur, list) {
523                 if (!ast_eid_cmp(&cur->eid,eid))
524                         break;
525         }
526
527         if (!cur && any_peer)
528                 cur = any_peer;
529
530         return cur;
531 }
532
533 static void build_iv(unsigned char *iv)
534 {
535         /* XXX Would be nice to be more random XXX */
536         unsigned int *fluffy;
537         int x;
538         fluffy = (unsigned int *)(iv);
539         for (x=0;x<4;x++)
540                 fluffy[x] = ast_random();
541 }
542
543 struct dundi_query_state {
544         dundi_eid *eids[DUNDI_MAX_STACK + 1];
545         int directs[DUNDI_MAX_STACK + 1];
546         dundi_eid reqeid;
547         char called_context[AST_MAX_EXTENSION];
548         char called_number[AST_MAX_EXTENSION];
549         struct dundi_mapping *maps;
550         int nummaps;
551         int nocache;
552         struct dundi_transaction *trans;
553         void *chal;
554         int challen;
555         int ttl;
556         char fluffy[0];
557 };
558
559 static int get_mapping_weight(struct dundi_mapping *map, struct varshead *headp)
560 {
561         char buf[32];
562
563         buf[0] = 0;
564         if (map->weightstr) {
565                 if (headp) {
566                         pbx_substitute_variables_varshead(headp, map->weightstr, buf, sizeof(buf) - 1);
567                 } else {
568                         pbx_substitute_variables_helper(NULL, map->weightstr, buf, sizeof(buf) - 1);
569                 }
570
571                 if (sscanf(buf, "%30d", &map->_weight) != 1)
572                         map->_weight = MAX_WEIGHT;
573         }
574
575         return map->_weight;
576 }
577
578 static int dundi_lookup_local(struct dundi_result *dr, struct dundi_mapping *map, char *called_number, dundi_eid *us_eid, int anscnt, struct dundi_hint_metadata *hmd)
579 {
580         struct ast_flags flags = {0};
581         int x;
582         if (!ast_strlen_zero(map->lcontext)) {
583                 if (ast_exists_extension(NULL, map->lcontext, called_number, 1, NULL))
584                         ast_set_flag(&flags, DUNDI_FLAG_EXISTS);
585                 if (ast_canmatch_extension(NULL, map->lcontext, called_number, 1, NULL))
586                         ast_set_flag(&flags, DUNDI_FLAG_CANMATCH);
587                 if (ast_matchmore_extension(NULL, map->lcontext, called_number, 1, NULL))
588                         ast_set_flag(&flags, DUNDI_FLAG_MATCHMORE);
589                 if (ast_ignore_pattern(map->lcontext, called_number))
590                         ast_set_flag(&flags, DUNDI_FLAG_IGNOREPAT);
591
592                 /* Clearly we can't say 'don't ask' anymore if we found anything... */
593                 if (ast_test_flag(&flags, AST_FLAGS_ALL))
594                         ast_clear_flag_nonstd(hmd, DUNDI_HINT_DONT_ASK);
595
596                 if (map->options & DUNDI_FLAG_INTERNAL_NOPARTIAL) {
597                         /* Skip partial answers */
598                         ast_clear_flag(&flags, DUNDI_FLAG_MATCHMORE|DUNDI_FLAG_CANMATCH);
599                 }
600                 if (ast_test_flag(&flags, AST_FLAGS_ALL)) {
601                         struct varshead headp;
602                         struct ast_var_t *newvariable;
603                         ast_set_flag(&flags, map->options & 0xffff);
604                         ast_copy_flags(dr + anscnt, &flags, AST_FLAGS_ALL);
605                         dr[anscnt].techint = map->tech;
606                         dr[anscnt].expiration = dundi_cache_time;
607                         ast_copy_string(dr[anscnt].tech, tech2str(map->tech), sizeof(dr[anscnt].tech));
608                         dr[anscnt].eid = *us_eid;
609                         ast_eid_to_str(dr[anscnt].eid_str, sizeof(dr[anscnt].eid_str), &dr[anscnt].eid);
610                         if (ast_test_flag(&flags, DUNDI_FLAG_EXISTS)) {
611                                 AST_LIST_HEAD_INIT_NOLOCK(&headp);
612                                 if ((newvariable = ast_var_assign("NUMBER", called_number))) {
613                                         AST_LIST_INSERT_HEAD(&headp, newvariable, entries);
614                                 }
615                                 if ((newvariable = ast_var_assign("EID", dr[anscnt].eid_str))) {
616                                         AST_LIST_INSERT_HEAD(&headp, newvariable, entries);
617                                 }
618                                 if ((newvariable = ast_var_assign("SECRET", cursecret))) {
619                                         AST_LIST_INSERT_HEAD(&headp, newvariable, entries);
620                                 }
621                                 if ((newvariable = ast_var_assign("IPADDR", ipaddr))) {
622                                         AST_LIST_INSERT_HEAD(&headp, newvariable, entries);
623                                 }
624                                 pbx_substitute_variables_varshead(&headp, map->dest, dr[anscnt].dest, sizeof(dr[anscnt].dest));
625                                 dr[anscnt].weight = get_mapping_weight(map, &headp);
626                                 while ((newvariable = AST_LIST_REMOVE_HEAD(&headp, entries)))
627                                         ast_var_delete(newvariable);
628                         } else {
629                                 dr[anscnt].dest[0] = '\0';
630                                 dr[anscnt].weight = get_mapping_weight(map, NULL);
631                         }
632                         anscnt++;
633                 } else {
634                         /* No answers...  Find the fewest number of digits from the
635                            number for which we have no answer. */
636                         char tmp[AST_MAX_EXTENSION + 1] = "";
637                         for (x = 0; x < (sizeof(tmp) - 1); x++) {
638                                 tmp[x] = called_number[x];
639                                 if (!tmp[x])
640                                         break;
641                                 if (!ast_canmatch_extension(NULL, map->lcontext, tmp, 1, NULL)) {
642                                         /* Oops found something we can't match.  If this is longer
643                                            than the running hint, we have to consider it */
644                                         if (strlen(tmp) > strlen(hmd->exten)) {
645                                                 ast_copy_string(hmd->exten, tmp, sizeof(hmd->exten));
646                                         }
647                                         break;
648                                 }
649                         }
650                 }
651         }
652         return anscnt;
653 }
654
655 static void destroy_trans(struct dundi_transaction *trans, int fromtimeout);
656
657 static void *dundi_lookup_thread(void *data)
658 {
659         struct dundi_query_state *st = data;
660         struct dundi_result dr[MAX_RESULTS];
661         struct dundi_ie_data ied;
662         struct dundi_hint_metadata hmd;
663         char eid_str[20];
664         int res, x;
665         int ouranswers=0;
666         int max = 999999;
667         int expiration = dundi_cache_time;
668
669         ast_debug(1, "Whee, looking up '%s@%s' for '%s'\n", st->called_number, st->called_context,
670                         st->eids[0] ? ast_eid_to_str(eid_str, sizeof(eid_str), st->eids[0]) :  "ourselves");
671         memset(&ied, 0, sizeof(ied));
672         memset(&dr, 0, sizeof(dr));
673         memset(&hmd, 0, sizeof(hmd));
674         /* Assume 'don't ask for anything' and 'unaffected', no TTL expired */
675         hmd.flags = DUNDI_HINT_DONT_ASK | DUNDI_HINT_UNAFFECTED;
676         for (x=0;x<st->nummaps;x++)
677                 ouranswers = dundi_lookup_local(dr, st->maps + x, st->called_number, &st->trans->us_eid, ouranswers, &hmd);
678         if (ouranswers < 0)
679                 ouranswers = 0;
680         for (x=0;x<ouranswers;x++) {
681                 if (dr[x].weight < max)
682                         max = dr[x].weight;
683         }
684
685         if (max) {
686                 /* If we do not have a canonical result, keep looking */
687                 res = dundi_lookup_internal(dr + ouranswers, MAX_RESULTS - ouranswers, NULL, st->called_context, st->called_number, st->ttl, 1, &hmd, &expiration, st->nocache, 0, NULL, st->eids, st->directs);
688                 if (res > 0) {
689                         /* Append answer in result */
690                         ouranswers += res;
691                 } else {
692                         if ((res < -1) && (!ouranswers))
693                                 dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_DUPLICATE, "Duplicate Request Pending");
694                 }
695         }
696         AST_LIST_LOCK(&peers);
697         /* Truncate if "don't ask" isn't present */
698         if (!ast_test_flag_nonstd(&hmd, DUNDI_HINT_DONT_ASK))
699                 hmd.exten[0] = '\0';
700         if (ast_test_flag(st->trans, FLAG_DEAD)) {
701                 ast_debug(1, "Our transaction went away!\n");
702                 st->trans->thread = 0;
703                 destroy_trans(st->trans, 0);
704         } else {
705                 for (x=0;x<ouranswers;x++) {
706                         /* Add answers */
707                         if (dr[x].expiration && (expiration > dr[x].expiration))
708                                 expiration = dr[x].expiration;
709                         dundi_ie_append_answer(&ied, DUNDI_IE_ANSWER, &dr[x].eid, dr[x].techint, dr[x].flags, dr[x].weight, dr[x].dest);
710                 }
711                 dundi_ie_append_hint(&ied, DUNDI_IE_HINT, hmd.flags, hmd.exten);
712                 dundi_ie_append_short(&ied, DUNDI_IE_EXPIRATION, expiration);
713                 dundi_send(st->trans, DUNDI_COMMAND_DPRESPONSE, 0, 1, &ied);
714                 st->trans->thread = 0;
715         }
716         AST_LIST_UNLOCK(&peers);
717         ast_free(st);
718         return NULL;
719 }
720
721 static void *dundi_precache_thread(void *data)
722 {
723         struct dundi_query_state *st = data;
724         struct dundi_ie_data ied;
725         struct dundi_hint_metadata hmd = {0};
726         char eid_str[20];
727
728         ast_debug(1, "Whee, precaching '%s@%s' for '%s'\n", st->called_number, st->called_context,
729                 st->eids[0] ? ast_eid_to_str(eid_str, sizeof(eid_str), st->eids[0]) :  "ourselves");
730         memset(&ied, 0, sizeof(ied));
731
732         /* Now produce precache */
733         dundi_precache_internal(st->called_context, st->called_number, st->ttl, st->eids);
734
735         AST_LIST_LOCK(&peers);
736         /* Truncate if "don't ask" isn't present */
737         if (!ast_test_flag_nonstd(&hmd, DUNDI_HINT_DONT_ASK))
738                 hmd.exten[0] = '\0';
739         if (ast_test_flag(st->trans, FLAG_DEAD)) {
740                 ast_debug(1, "Our transaction went away!\n");
741                 st->trans->thread = 0;
742                 destroy_trans(st->trans, 0);
743         } else {
744                 dundi_send(st->trans, DUNDI_COMMAND_PRECACHERP, 0, 1, &ied);
745                 st->trans->thread = 0;
746         }
747         AST_LIST_UNLOCK(&peers);
748         ast_free(st);
749         return NULL;
750 }
751
752 static int dundi_query_eid_internal(struct dundi_entity_info *dei, const char *dcontext, dundi_eid *eid, struct dundi_hint_metadata *hmd, int ttl, int blockempty, dundi_eid *avoid[]);
753
754 static void *dundi_query_thread(void *data)
755 {
756         struct dundi_query_state *st = data;
757         struct dundi_entity_info dei;
758         struct dundi_ie_data ied;
759         struct dundi_hint_metadata hmd;
760         char eid_str[20];
761         int res;
762
763         ast_debug(1, "Whee, looking up '%s@%s' for '%s'\n", st->called_number, st->called_context,
764                 st->eids[0] ? ast_eid_to_str(eid_str, sizeof(eid_str), st->eids[0]) :  "ourselves");
765         memset(&ied, 0, sizeof(ied));
766         memset(&dei, 0, sizeof(dei));
767         memset(&hmd, 0, sizeof(hmd));
768         if (!ast_eid_cmp(&st->trans->us_eid, &st->reqeid)) {
769                 /* Ooh, it's us! */
770                 ast_debug(1, "Neat, someone look for us!\n");
771                 ast_copy_string(dei.orgunit, dept, sizeof(dei.orgunit));
772                 ast_copy_string(dei.org, org, sizeof(dei.org));
773                 ast_copy_string(dei.locality, locality, sizeof(dei.locality));
774                 ast_copy_string(dei.stateprov, stateprov, sizeof(dei.stateprov));
775                 ast_copy_string(dei.country, country, sizeof(dei.country));
776                 ast_copy_string(dei.email, email, sizeof(dei.email));
777                 ast_copy_string(dei.phone, phone, sizeof(dei.phone));
778                 res = 1;
779         } else {
780                 /* If we do not have a canonical result, keep looking */
781                 res = dundi_query_eid_internal(&dei, st->called_context, &st->reqeid, &hmd, st->ttl, 1, st->eids);
782         }
783         AST_LIST_LOCK(&peers);
784         if (ast_test_flag(st->trans, FLAG_DEAD)) {
785                 ast_debug(1, "Our transaction went away!\n");
786                 st->trans->thread = 0;
787                 destroy_trans(st->trans, 0);
788         } else {
789                 if (res) {
790                         dundi_ie_append_str(&ied, DUNDI_IE_DEPARTMENT, dei.orgunit);
791                         dundi_ie_append_str(&ied, DUNDI_IE_ORGANIZATION, dei.org);
792                         dundi_ie_append_str(&ied, DUNDI_IE_LOCALITY, dei.locality);
793                         dundi_ie_append_str(&ied, DUNDI_IE_STATE_PROV, dei.stateprov);
794                         dundi_ie_append_str(&ied, DUNDI_IE_COUNTRY, dei.country);
795                         dundi_ie_append_str(&ied, DUNDI_IE_EMAIL, dei.email);
796                         dundi_ie_append_str(&ied, DUNDI_IE_PHONE, dei.phone);
797                         if (!ast_strlen_zero(dei.ipaddr))
798                                 dundi_ie_append_str(&ied, DUNDI_IE_IPADDR, dei.ipaddr);
799                 }
800                 dundi_ie_append_hint(&ied, DUNDI_IE_HINT, hmd.flags, hmd.exten);
801                 dundi_send(st->trans, DUNDI_COMMAND_EIDRESPONSE, 0, 1, &ied);
802                 st->trans->thread = 0;
803         }
804         AST_LIST_UNLOCK(&peers);
805         ast_free(st);
806         return NULL;
807 }
808
809 static int dundi_answer_entity(struct dundi_transaction *trans, struct dundi_ies *ies, char *ccontext)
810 {
811         struct dundi_query_state *st;
812         int totallen;
813         int x;
814         int skipfirst=0;
815         char eid_str[20];
816         char *s;
817         pthread_t lookupthread;
818
819         if (ies->eidcount > 1) {
820                 /* Since it is a requirement that the first EID is the authenticating host
821                    and the last EID is the root, it is permissible that the first and last EID
822                    could be the same.  In that case, we should go ahead copy only the "root" section
823                    since we will not need it for authentication. */
824                 if (!ast_eid_cmp(ies->eids[0], ies->eids[ies->eidcount - 1]))
825                         skipfirst = 1;
826         }
827         totallen = sizeof(struct dundi_query_state);
828         totallen += (ies->eidcount - skipfirst) * sizeof(dundi_eid);
829         st = ast_calloc(1, totallen);
830         if (st) {
831                 ast_copy_string(st->called_context, ies->called_context, sizeof(st->called_context));
832                 memcpy(&st->reqeid, ies->reqeid, sizeof(st->reqeid));
833                 st->trans = trans;
834                 st->ttl = ies->ttl - 1;
835                 if (st->ttl < 0)
836                         st->ttl = 0;
837                 s = st->fluffy;
838                 for (x=skipfirst;ies->eids[x];x++) {
839                         st->eids[x-skipfirst] = (dundi_eid *)s;
840                         *st->eids[x-skipfirst] = *ies->eids[x];
841                         s += sizeof(dundi_eid);
842                 }
843                 ast_debug(1, "Answering EID query for '%s@%s'!\n", ast_eid_to_str(eid_str, sizeof(eid_str), ies->reqeid), ies->called_context);
844
845                 trans->thread = 1;
846                 if (ast_pthread_create_detached(&lookupthread, NULL, dundi_query_thread, st)) {
847                         struct dundi_ie_data ied = { 0, };
848                         trans->thread = 0;
849                         ast_log(LOG_WARNING, "Unable to create thread!\n");
850                         ast_free(st);
851                         dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of threads");
852                         dundi_send(trans, DUNDI_COMMAND_EIDRESPONSE, 0, 1, &ied);
853                         return -1;
854                 }
855         } else {
856                 struct dundi_ie_data ied = { 0, };
857                 dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of memory");
858                 dundi_send(trans, DUNDI_COMMAND_EIDRESPONSE, 0, 1, &ied);
859                 return -1;
860         }
861         return 0;
862 }
863
864 static int cache_save_hint(dundi_eid *eidpeer, struct dundi_request *req, struct dundi_hint *hint, int expiration)
865 {
866         int unaffected;
867         char key1[256];
868         char key2[256];
869         char eidpeer_str[20];
870         char eidroot_str[20];
871         char data[80];
872         time_t timeout;
873
874         if (expiration < 0)
875                 expiration = dundi_cache_time;
876
877         /* Only cache hint if "don't ask" is there... */
878         if (!ast_test_flag_nonstd(hint, htons(DUNDI_HINT_DONT_ASK)))
879                 return 0;
880
881         unaffected = ast_test_flag_nonstd(hint, htons(DUNDI_HINT_UNAFFECTED));
882
883         dundi_eid_to_str_short(eidpeer_str, sizeof(eidpeer_str), eidpeer);
884         dundi_eid_to_str_short(eidroot_str, sizeof(eidroot_str), &req->root_eid);
885         snprintf(key1, sizeof(key1), "hint/%s/%s/%s/e%08x", eidpeer_str, hint->data, req->dcontext, unaffected ? 0 : req->crc32);
886         snprintf(key2, sizeof(key2), "hint/%s/%s/%s/r%s", eidpeer_str, hint->data, req->dcontext, eidroot_str);
887
888         time(&timeout);
889         timeout += expiration;
890         snprintf(data, sizeof(data), "%ld|", (long)(timeout));
891
892         ast_db_put("dundi/cache", key1, data);
893         ast_debug(1, "Caching hint at '%s'\n", key1);
894         ast_db_put("dundi/cache", key2, data);
895         ast_debug(1, "Caching hint at '%s'\n", key2);
896         return 0;
897 }
898
899 static int cache_save(dundi_eid *eidpeer, struct dundi_request *req, int start, int unaffected, int expiration, int push)
900 {
901         int x;
902         char key1[256];
903         char key2[256];
904         char data[1024];
905         char eidpeer_str[20];
906         char eidroot_str[20];
907         time_t timeout;
908
909         if (expiration < 1)
910                 expiration = dundi_cache_time;
911
912         /* Keep pushes a little longer, cut pulls a little short */
913         if (push)
914                 expiration += 10;
915         else
916                 expiration -= 10;
917         if (expiration < 1)
918                 expiration = 1;
919         dundi_eid_to_str_short(eidpeer_str, sizeof(eidpeer_str), eidpeer);
920         dundi_eid_to_str_short(eidroot_str, sizeof(eidroot_str), &req->root_eid);
921         snprintf(key1, sizeof(key1), "%s/%s/%s/e%08x", eidpeer_str, req->number, req->dcontext, unaffected ? 0 : req->crc32);
922         snprintf(key2, sizeof(key2), "%s/%s/%s/r%s", eidpeer_str, req->number, req->dcontext, eidroot_str);
923         /* Build request string */
924         time(&timeout);
925         timeout += expiration;
926         snprintf(data, sizeof(data), "%ld|", (long)(timeout));
927         for (x=start;x<req->respcount;x++) {
928                 /* Skip anything with an illegal pipe in it */
929                 if (strchr(req->dr[x].dest, '|'))
930                         continue;
931                 snprintf(data + strlen(data), sizeof(data) - strlen(data), "%u/%d/%d/%s/%s|",
932                         req->dr[x].flags, req->dr[x].weight, req->dr[x].techint, req->dr[x].dest,
933                         dundi_eid_to_str_short(eidpeer_str, sizeof(eidpeer_str), &req->dr[x].eid));
934         }
935         ast_db_put("dundi/cache", key1, data);
936         ast_db_put("dundi/cache", key2, data);
937         return 0;
938 }
939
940 static int dundi_prop_precache(struct dundi_transaction *trans, struct dundi_ies *ies, char *ccontext)
941 {
942         struct dundi_query_state *st;
943         int totallen;
944         int x,z;
945         struct dundi_ie_data ied;
946         char *s;
947         struct dundi_result dr2[MAX_RESULTS];
948         struct dundi_request dr;
949         struct dundi_hint_metadata hmd;
950
951         struct dundi_mapping *cur;
952         int mapcount;
953         int skipfirst = 0;
954
955         pthread_t lookupthread;
956
957         memset(&dr2, 0, sizeof(dr2));
958         memset(&dr, 0, sizeof(dr));
959         memset(&hmd, 0, sizeof(hmd));
960
961         /* Forge request structure to hold answers for cache */
962         hmd.flags = DUNDI_HINT_DONT_ASK | DUNDI_HINT_UNAFFECTED;
963         dr.dr = dr2;
964         dr.maxcount = MAX_RESULTS;
965         dr.expiration = dundi_cache_time;
966         dr.hmd = &hmd;
967         dr.pfds[0] = dr.pfds[1] = -1;
968         trans->parent = &dr;
969         ast_copy_string(dr.dcontext, ies->called_context ? ies->called_context : "e164", sizeof(dr.dcontext));
970         ast_copy_string(dr.number, ies->called_number, sizeof(dr.number));
971
972         for (x=0;x<ies->anscount;x++) {
973                 if (trans->parent->respcount < trans->parent->maxcount) {
974                         /* Make sure it's not already there */
975                         for (z=0;z<trans->parent->respcount;z++) {
976                                 if ((trans->parent->dr[z].techint == ies->answers[x]->protocol) &&
977                                     !strcmp(trans->parent->dr[z].dest, (char *)ies->answers[x]->data))
978                                                 break;
979                         }
980                         if (z == trans->parent->respcount) {
981                                 /* Copy into parent responses */
982                                 trans->parent->dr[trans->parent->respcount].flags = ntohs(ies->answers[x]->flags);
983                                 trans->parent->dr[trans->parent->respcount].techint = ies->answers[x]->protocol;
984                                 trans->parent->dr[trans->parent->respcount].weight = ntohs(ies->answers[x]->weight);
985                                 trans->parent->dr[trans->parent->respcount].eid = ies->answers[x]->eid;
986                                 if (ies->expiration > 0)
987                                         trans->parent->dr[trans->parent->respcount].expiration = ies->expiration;
988                                 else
989                                         trans->parent->dr[trans->parent->respcount].expiration = dundi_cache_time;
990                                 ast_eid_to_str(trans->parent->dr[trans->parent->respcount].eid_str,
991                                         sizeof(trans->parent->dr[trans->parent->respcount].eid_str),
992                                         &ies->answers[x]->eid);
993                                 ast_copy_string(trans->parent->dr[trans->parent->respcount].dest, (char *)ies->answers[x]->data,
994                                         sizeof(trans->parent->dr[trans->parent->respcount].dest));
995                                         ast_copy_string(trans->parent->dr[trans->parent->respcount].tech, tech2str(ies->answers[x]->protocol),
996                                         sizeof(trans->parent->dr[trans->parent->respcount].tech));
997                                 trans->parent->respcount++;
998                                 ast_clear_flag_nonstd(trans->parent->hmd, DUNDI_HINT_DONT_ASK);
999                         } else if (trans->parent->dr[z].weight > ntohs(ies->answers[x]->weight)) {
1000                                 /* Update weight if appropriate */
1001                                 trans->parent->dr[z].weight = ntohs(ies->answers[x]->weight);
1002                         }
1003                 } else
1004                         ast_log(LOG_NOTICE, "Dropping excessive answers in precache for %s@%s\n",
1005                                 trans->parent->number, trans->parent->dcontext);
1006
1007         }
1008         /* Save all the results (if any) we had.  Even if no results, still cache lookup. */
1009         cache_save(&trans->them_eid, trans->parent, 0, 0, ies->expiration, 1);
1010         if (ies->hint)
1011                 cache_save_hint(&trans->them_eid, trans->parent, ies->hint, ies->expiration);
1012
1013         totallen = sizeof(struct dundi_query_state);
1014         /* Count matching map entries */
1015         mapcount = 0;
1016         AST_LIST_TRAVERSE(&mappings, cur, list) {
1017                 if (!strcasecmp(cur->dcontext, ccontext))
1018                         mapcount++;
1019         }
1020
1021         /* If no maps, return -1 immediately */
1022         if (!mapcount)
1023                 return -1;
1024
1025         if (ies->eidcount > 1) {
1026                 /* Since it is a requirement that the first EID is the authenticating host
1027                    and the last EID is the root, it is permissible that the first and last EID
1028                    could be the same.  In that case, we should go ahead copy only the "root" section
1029                    since we will not need it for authentication. */
1030                 if (!ast_eid_cmp(ies->eids[0], ies->eids[ies->eidcount - 1]))
1031                         skipfirst = 1;
1032         }
1033
1034         /* Prepare to run a query and then propagate that as necessary */
1035         totallen += mapcount * sizeof(struct dundi_mapping);
1036         totallen += (ies->eidcount - skipfirst) * sizeof(dundi_eid);
1037         st = ast_calloc(1, totallen);
1038         if (st) {
1039                 ast_copy_string(st->called_context, dr.dcontext, sizeof(st->called_context));
1040                 ast_copy_string(st->called_number, ies->called_number, sizeof(st->called_number));
1041                 st->trans = trans;
1042                 st->ttl = ies->ttl - 1;
1043                 st->nocache = ies->cbypass;
1044                 if (st->ttl < 0)
1045                         st->ttl = 0;
1046                 s = st->fluffy;
1047                 for (x=skipfirst;ies->eids[x];x++) {
1048                         st->eids[x-skipfirst] = (dundi_eid *)s;
1049                         *st->eids[x-skipfirst] = *ies->eids[x];
1050                         st->directs[x-skipfirst] = ies->eid_direct[x];
1051                         s += sizeof(dundi_eid);
1052                 }
1053                 /* Append mappings */
1054                 x = 0;
1055                 st->maps = (struct dundi_mapping *)s;
1056                 AST_LIST_TRAVERSE(&mappings, cur, list) {
1057                         if (!strcasecmp(cur->dcontext, ccontext)) {
1058                                 if (x < mapcount) {
1059                                         st->maps[x] = *cur;
1060                                         st->maps[x].list.next = NULL;
1061                                         x++;
1062                                 }
1063                         }
1064                 }
1065                 st->nummaps = mapcount;
1066                 ast_debug(1, "Forwarding precache for '%s@%s'!\n", ies->called_number, ies->called_context);
1067                 trans->thread = 1;
1068                 if (ast_pthread_create_detached(&lookupthread, NULL, dundi_precache_thread, st)) {
1069                         trans->thread = 0;
1070                         ast_log(LOG_WARNING, "Unable to create thread!\n");
1071                         ast_free(st);
1072                         memset(&ied, 0, sizeof(ied));
1073                         dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of threads");
1074                         dundi_send(trans, DUNDI_COMMAND_PRECACHERP, 0, 1, &ied);
1075                         return -1;
1076                 }
1077         } else {
1078                 ast_log(LOG_WARNING, "Out of memory!\n");
1079                 memset(&ied, 0, sizeof(ied));
1080                 dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of memory");
1081                 dundi_send(trans, DUNDI_COMMAND_PRECACHERP, 0, 1, &ied);
1082                 return -1;
1083         }
1084         return 0;
1085 }
1086
1087 static int dundi_answer_query(struct dundi_transaction *trans, struct dundi_ies *ies, char *ccontext)
1088 {
1089         struct dundi_query_state *st;
1090         int totallen;
1091         int x;
1092         struct dundi_ie_data ied;
1093         char *s;
1094         struct dundi_mapping *cur;
1095         int mapcount = 0;
1096         int skipfirst = 0;
1097
1098         pthread_t lookupthread;
1099         totallen = sizeof(struct dundi_query_state);
1100         /* Count matching map entries */
1101         AST_LIST_TRAVERSE(&mappings, cur, list) {
1102                 if (!strcasecmp(cur->dcontext, ccontext))
1103                         mapcount++;
1104         }
1105         /* If no maps, return -1 immediately */
1106         if (!mapcount)
1107                 return -1;
1108
1109         if (ies->eidcount > 1) {
1110                 /* Since it is a requirement that the first EID is the authenticating host
1111                    and the last EID is the root, it is permissible that the first and last EID
1112                    could be the same.  In that case, we should go ahead copy only the "root" section
1113                    since we will not need it for authentication. */
1114                 if (!ast_eid_cmp(ies->eids[0], ies->eids[ies->eidcount - 1]))
1115                         skipfirst = 1;
1116         }
1117
1118         totallen += mapcount * sizeof(struct dundi_mapping);
1119         totallen += (ies->eidcount - skipfirst) * sizeof(dundi_eid);
1120         st = ast_calloc(1, totallen);
1121         if (st) {
1122                 ast_copy_string(st->called_context, ies->called_context, sizeof(st->called_context));
1123                 ast_copy_string(st->called_number, ies->called_number, sizeof(st->called_number));
1124                 st->trans = trans;
1125                 st->ttl = ies->ttl - 1;
1126                 st->nocache = ies->cbypass;
1127                 if (st->ttl < 0)
1128                         st->ttl = 0;
1129                 s = st->fluffy;
1130                 for (x=skipfirst;ies->eids[x];x++) {
1131                         st->eids[x-skipfirst] = (dundi_eid *)s;
1132                         *st->eids[x-skipfirst] = *ies->eids[x];
1133                         st->directs[x-skipfirst] = ies->eid_direct[x];
1134                         s += sizeof(dundi_eid);
1135                 }
1136                 /* Append mappings */
1137                 x = 0;
1138                 st->maps = (struct dundi_mapping *)s;
1139                 AST_LIST_TRAVERSE(&mappings, cur, list) {
1140                         if (!strcasecmp(cur->dcontext, ccontext)) {
1141                                 if (x < mapcount) {
1142                                         st->maps[x] = *cur;
1143                                         st->maps[x].list.next = NULL;
1144                                         x++;
1145                                 }
1146                         }
1147                 }
1148                 st->nummaps = mapcount;
1149                 ast_debug(1, "Answering query for '%s@%s'!\n", ies->called_number, ies->called_context);
1150                 trans->thread = 1;
1151                 if (ast_pthread_create_detached(&lookupthread, NULL, dundi_lookup_thread, st)) {
1152                         trans->thread = 0;
1153                         ast_log(LOG_WARNING, "Unable to create thread!\n");
1154                         ast_free(st);
1155                         memset(&ied, 0, sizeof(ied));
1156                         dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of threads");
1157                         dundi_send(trans, DUNDI_COMMAND_DPRESPONSE, 0, 1, &ied);
1158                         return -1;
1159                 }
1160         } else {
1161                 ast_log(LOG_WARNING, "Out of memory!\n");
1162                 memset(&ied, 0, sizeof(ied));
1163                 dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of memory");
1164                 dundi_send(trans, DUNDI_COMMAND_DPRESPONSE, 0, 1, &ied);
1165                 return -1;
1166         }
1167         return 0;
1168 }
1169
1170 static int cache_lookup_internal(time_t now, struct dundi_request *req, char *key, char *eid_str_full, int *lowexpiration)
1171 {
1172         char data[1024];
1173         char *ptr, *term, *src;
1174         int tech;
1175         struct ast_flags flags;
1176         int weight;
1177         int length;
1178         int z;
1179         char fs[256];
1180
1181         /* Build request string */
1182         if (!ast_db_get("dundi/cache", key, data, sizeof(data))) {
1183                 time_t timeout;
1184                 ptr = data;
1185                 if (!ast_get_time_t(ptr, &timeout, 0, &length)) {
1186                         int expiration = timeout - now;
1187                         if (expiration > 0) {
1188                                 ast_debug(1, "Found cache expiring in %d seconds!\n", expiration);
1189                                 ptr += length + 1;
1190                                 while((sscanf(ptr, "%30d/%30d/%30d/%n", (int *)&(flags.flags), &weight, &tech, &length) == 3)) {
1191                                         ptr += length;
1192                                         term = strchr(ptr, '|');
1193                                         if (term) {
1194                                                 *term = '\0';
1195                                                 src = strrchr(ptr, '/');
1196                                                 if (src) {
1197                                                         *src = '\0';
1198                                                         src++;
1199                                                 } else
1200                                                         src = "";
1201                                                 ast_debug(1, "Found cached answer '%s/%s' originally from '%s' with flags '%s' on behalf of '%s'\n",
1202                                                         tech2str(tech), ptr, src, dundi_flags2str(fs, sizeof(fs), flags.flags), eid_str_full);
1203                                                 /* Make sure it's not already there */
1204                                                 for (z=0;z<req->respcount;z++) {
1205                                                         if ((req->dr[z].techint == tech) &&
1206                                                             !strcmp(req->dr[z].dest, ptr))
1207                                                                         break;
1208                                                 }
1209                                                 if (z == req->respcount) {
1210                                                         /* Copy into parent responses */
1211                                                         ast_copy_flags(&(req->dr[req->respcount]), &flags, AST_FLAGS_ALL);
1212                                                         req->dr[req->respcount].weight = weight;
1213                                                         req->dr[req->respcount].techint = tech;
1214                                                         req->dr[req->respcount].expiration = expiration;
1215                                                         dundi_str_short_to_eid(&req->dr[req->respcount].eid, src);
1216                                                         ast_eid_to_str(req->dr[req->respcount].eid_str,
1217                                                                 sizeof(req->dr[req->respcount].eid_str), &req->dr[req->respcount].eid);
1218                                                         ast_copy_string(req->dr[req->respcount].dest, ptr,
1219                                                                 sizeof(req->dr[req->respcount].dest));
1220                                                         ast_copy_string(req->dr[req->respcount].tech, tech2str(tech),
1221                                                                 sizeof(req->dr[req->respcount].tech));
1222                                                         req->respcount++;
1223                                                         ast_clear_flag_nonstd(req->hmd, DUNDI_HINT_DONT_ASK);
1224                                                 } else if (req->dr[z].weight > weight)
1225                                                         req->dr[z].weight = weight;
1226                                                 ptr = term + 1;
1227                                         }
1228                                 }
1229                                 /* We found *something* cached */
1230                                 if (expiration < *lowexpiration)
1231                                         *lowexpiration = expiration;
1232                                 return 1;
1233                         } else
1234                                 ast_db_del("dundi/cache", key);
1235                 } else
1236                         ast_db_del("dundi/cache", key);
1237         }
1238
1239         return 0;
1240 }
1241
1242 static int cache_lookup(struct dundi_request *req, dundi_eid *peer_eid, uint32_t crc, int *lowexpiration)
1243 {
1244         char eid_str[20];
1245         char eidroot_str[20];
1246         time_t now;
1247         int res=0;
1248         int res2=0;
1249         char eid_str_full[20];
1250         char tmp[256]="";
1251         /* Enough space for largest value that can be stored in key. */
1252         char key[sizeof(eid_str) + sizeof(tmp) + sizeof(req->dcontext) + sizeof(eidroot_str) + sizeof("hint////r")];
1253         int x;
1254
1255         time(&now);
1256         dundi_eid_to_str_short(eid_str, sizeof(eid_str), peer_eid);
1257         dundi_eid_to_str_short(eidroot_str, sizeof(eidroot_str), &req->root_eid);
1258         ast_eid_to_str(eid_str_full, sizeof(eid_str_full), peer_eid);
1259         snprintf(key, sizeof(key), "%s/%s/%s/e%08x", eid_str, req->number, req->dcontext, crc);
1260         res |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration);
1261         snprintf(key, sizeof(key), "%s/%s/%s/e%08x", eid_str, req->number, req->dcontext, (unsigned)0);
1262         res |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration);
1263         snprintf(key, sizeof(key), "%s/%s/%s/r%s", eid_str, req->number, req->dcontext, eidroot_str);
1264         res |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration);
1265         x = 0;
1266         if (!req->respcount) {
1267                 while(!res2) {
1268                         /* Look and see if we have a hint that would preclude us from looking at this
1269                            peer for this number. */
1270                         if (!(tmp[x] = req->number[x]))
1271                                 break;
1272                         x++;
1273                         /* Check for hints */
1274                         snprintf(key, sizeof(key), "hint/%s/%s/%s/e%08x", eid_str, tmp, req->dcontext, crc);
1275                         res2 |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration);
1276                         snprintf(key, sizeof(key), "hint/%s/%s/%s/e%08x", eid_str, tmp, req->dcontext, (unsigned)0);
1277                         res2 |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration);
1278                         snprintf(key, sizeof(key), "hint/%s/%s/%s/r%s", eid_str, tmp, req->dcontext, eidroot_str);
1279                         res2 |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration);
1280                         if (res2) {
1281                                 if (strlen(tmp) > strlen(req->hmd->exten)) {
1282                                         /* Update meta data if appropriate */
1283                                         ast_copy_string(req->hmd->exten, tmp, sizeof(req->hmd->exten));
1284                                 }
1285                         }
1286                 }
1287                 res |= res2;
1288         }
1289
1290         return res;
1291 }
1292
1293 static void qualify_peer(struct dundi_peer *peer, int schedonly);
1294
1295 static void apply_peer(struct dundi_transaction *trans, struct dundi_peer *p)
1296 {
1297         if (ast_sockaddr_isnull(&trans->addr)) {
1298                 ast_sockaddr_copy(&trans->addr, &p->addr);
1299         }
1300         trans->us_eid = p->us_eid;
1301         trans->them_eid = p->eid;
1302         /* Enable encryption if appropriate */
1303         if (!ast_strlen_zero(p->inkey))
1304                 ast_set_flag(trans, FLAG_ENCRYPT);
1305         if (p->maxms) {
1306                 trans->autokilltimeout = p->maxms;
1307                 trans->retranstimer = DUNDI_DEFAULT_RETRANS_TIMER;
1308                 if (p->lastms > 1) {
1309                         trans->retranstimer = p->lastms * 2;
1310                         /* Keep it from being silly */
1311                         if (trans->retranstimer < 150)
1312                                 trans->retranstimer = 150;
1313                 }
1314                 if (trans->retranstimer > DUNDI_DEFAULT_RETRANS_TIMER)
1315                         trans->retranstimer = DUNDI_DEFAULT_RETRANS_TIMER;
1316         } else
1317                 trans->autokilltimeout = global_autokilltimeout;
1318 }
1319
1320 /*! \note Called with the peers list already locked */
1321 static int do_register_expire(const void *data)
1322 {
1323         struct dundi_peer *peer = (struct dundi_peer *)data;
1324         char eid_str[20];
1325
1326         ast_debug(1, "Register expired for '%s'\n", ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
1327         ast_db_del("dundi/dpeers", dundi_eid_to_str_short(eid_str, sizeof(eid_str), &peer->eid));
1328         peer->registerexpire = -1;
1329         peer->lastms = 0;
1330         ast_sockaddr_setnull(&peer->addr);
1331         return 0;
1332 }
1333
1334 static int update_key(struct dundi_peer *peer)
1335 {
1336         unsigned char key[16];
1337         struct ast_key *ekey, *skey;
1338         char eid_str[20];
1339         int res;
1340         if (!peer->keyexpire || (peer->keyexpire < time(NULL))) {
1341                 build_iv(key);
1342                 ast_aes_set_encrypt_key(key, &peer->us_ecx);
1343                 ast_aes_set_decrypt_key(key, &peer->us_dcx);
1344                 ekey = ast_key_get(peer->inkey, AST_KEY_PUBLIC);
1345                 if (!ekey) {
1346                         ast_log(LOG_NOTICE, "No such key '%s' for creating RSA encrypted shared key for '%s'!\n",
1347                                 peer->inkey, ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
1348                         return -1;
1349                 }
1350                 skey = ast_key_get(peer->outkey, AST_KEY_PRIVATE);
1351                 if (!skey) {
1352                         ast_log(LOG_NOTICE, "No such key '%s' for signing RSA encrypted shared key for '%s'!\n",
1353                                 peer->outkey, ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
1354                         return -1;
1355                 }
1356                 if ((res = ast_encrypt_bin(peer->txenckey, key, sizeof(key), ekey)) != 128) {
1357                         ast_log(LOG_NOTICE, "Whoa, got a weird encrypt size (%d != %d)!\n", res, 128);
1358                         return -1;
1359                 }
1360                 if ((res = ast_sign_bin(skey, (char *)peer->txenckey, 128, peer->txenckey + 128))) {
1361                         ast_log(LOG_NOTICE, "Failed to sign key (%d)!\n", res);
1362                         return -1;
1363                 }
1364                 peer->us_keycrc32 = crc32(0L, peer->txenckey, 128);
1365                 peer->sentfullkey = 0;
1366                 /* Looks good */
1367                 time(&peer->keyexpire);
1368                 peer->keyexpire += dundi_key_ttl;
1369         }
1370         return 0;
1371 }
1372
1373 static int encrypt_memcpy(unsigned char *dst, unsigned char *src, int len, unsigned char *iv, ast_aes_encrypt_key *ecx)
1374 {
1375         unsigned char curblock[16];
1376         int x;
1377         memcpy(curblock, iv, sizeof(curblock));
1378         while(len > 0) {
1379                 for (x=0;x<16;x++)
1380                         curblock[x] ^= src[x];
1381                 ast_aes_encrypt(curblock, dst, ecx);
1382                 memcpy(curblock, dst, sizeof(curblock));
1383                 dst += 16;
1384                 src += 16;
1385                 len -= 16;
1386         }
1387         return 0;
1388 }
1389 static int decrypt_memcpy(unsigned char *dst, unsigned char *src, int len, unsigned char *iv, ast_aes_decrypt_key *dcx)
1390 {
1391         unsigned char lastblock[16];
1392         int x;
1393         memcpy(lastblock, iv, sizeof(lastblock));
1394         while(len > 0) {
1395                 ast_aes_decrypt(src, dst, dcx);
1396                 for (x=0;x<16;x++)
1397                         dst[x] ^= lastblock[x];
1398                 memcpy(lastblock, src, sizeof(lastblock));
1399                 dst += 16;
1400                 src += 16;
1401                 len -= 16;
1402         }
1403         return 0;
1404 }
1405
1406 static struct dundi_hdr *dundi_decrypt(struct dundi_transaction *trans, unsigned char *dst, int *dstlen, struct dundi_hdr *ohdr, struct dundi_encblock *src, int srclen)
1407 {
1408         int space = *dstlen;
1409         unsigned long bytes;
1410         struct dundi_hdr *h;
1411         unsigned char *decrypt_space;
1412         decrypt_space = ast_alloca(srclen);
1413         decrypt_memcpy(decrypt_space, src->encdata, srclen, src->iv, &trans->dcx);
1414         /* Setup header */
1415         h = (struct dundi_hdr *)dst;
1416         *h = *ohdr;
1417         bytes = space - 6;
1418         if (uncompress(dst + 6, &bytes, decrypt_space, srclen) != Z_OK) {
1419                 ast_debug(1, "Ouch, uncompress failed :(\n");
1420                 return NULL;
1421         }
1422         /* Update length */
1423         *dstlen = bytes + 6;
1424         /* Return new header */
1425         return h;
1426 }
1427
1428 static int dundi_encrypt(struct dundi_transaction *trans, struct dundi_packet *pack)
1429 {
1430         unsigned char *compress_space;
1431         int len;
1432         int res;
1433         unsigned long bytes;
1434         struct dundi_ie_data ied;
1435         struct dundi_peer *peer;
1436         unsigned char iv[16];
1437         len = pack->datalen + pack->datalen / 100 + 42;
1438         compress_space = ast_alloca(len);
1439         memset(compress_space, 0, len);
1440         /* We care about everthing save the first 6 bytes of header */
1441         bytes = len;
1442         res = compress(compress_space, &bytes, pack->data + 6, pack->datalen - 6);
1443         if (res != Z_OK) {
1444                 ast_debug(1, "Ouch, compression failed!\n");
1445                 return -1;
1446         }
1447         memset(&ied, 0, sizeof(ied));
1448         /* Say who we are */
1449         if (!pack->h->iseqno && !pack->h->oseqno) {
1450                 /* Need the key in the first copy */
1451                 if (!(peer = find_peer(&trans->them_eid)))
1452                         return -1;
1453                 if (update_key(peer))
1454                         return -1;
1455                 if (!peer->sentfullkey)
1456                         ast_set_flag(trans, FLAG_SENDFULLKEY);
1457                 /* Append key data */
1458                 dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->us_eid);
1459                 if (ast_test_flag(trans, FLAG_SENDFULLKEY)) {
1460                         dundi_ie_append_raw(&ied, DUNDI_IE_SHAREDKEY, peer->txenckey, 128);
1461                         dundi_ie_append_raw(&ied, DUNDI_IE_SIGNATURE, peer->txenckey + 128, 128);
1462                 } else {
1463                         dundi_ie_append_int(&ied, DUNDI_IE_KEYCRC32, peer->us_keycrc32);
1464                 }
1465                 /* Setup contexts */
1466                 trans->ecx = peer->us_ecx;
1467                 trans->dcx = peer->us_dcx;
1468
1469                 /* We've sent the full key */
1470                 peer->sentfullkey = 1;
1471         }
1472         /* Build initialization vector */
1473         build_iv(iv);
1474         /* Add the field, rounded up to 16 bytes */
1475         dundi_ie_append_encdata(&ied, DUNDI_IE_ENCDATA, iv, NULL, ((bytes + 15) / 16) * 16);
1476         /* Copy the data */
1477         if ((ied.pos + bytes) >= sizeof(ied.buf)) {
1478                 ast_log(LOG_NOTICE, "Final packet too large!\n");
1479                 return -1;
1480         }
1481         encrypt_memcpy(ied.buf + ied.pos, compress_space, bytes, iv, &trans->ecx);
1482         ied.pos += ((bytes + 15) / 16) * 16;
1483         /* Reconstruct header */
1484         pack->datalen = sizeof(struct dundi_hdr);
1485         pack->h->cmdresp = DUNDI_COMMAND_ENCRYPT;
1486         pack->h->cmdflags = 0;
1487         memcpy(pack->h->ies, ied.buf, ied.pos);
1488         pack->datalen += ied.pos;
1489         return 0;
1490 }
1491
1492 static int check_key(struct dundi_peer *peer, unsigned char *newkey, unsigned char *newsig, uint32_t keycrc32)
1493 {
1494         unsigned char dst[128];
1495         int res;
1496         struct ast_key *key, *skey;
1497         char eid_str[20];
1498         ast_debug(1, "Expected '%08x' got '%08x'\n", peer->them_keycrc32, keycrc32);
1499         if (peer->them_keycrc32 && (peer->them_keycrc32 == keycrc32)) {
1500                 /* A match */
1501                 return 1;
1502         } else if (!newkey || !newsig)
1503                 return 0;
1504         if (!memcmp(peer->rxenckey, newkey, 128) &&
1505             !memcmp(peer->rxenckey + 128, newsig, 128)) {
1506                 /* By definition, a match */
1507                 return 1;
1508         }
1509         /* Decrypt key */
1510         key = ast_key_get(peer->outkey, AST_KEY_PRIVATE);
1511         if (!key) {
1512                 ast_log(LOG_NOTICE, "Unable to find key '%s' to decode shared key from '%s'\n",
1513                         peer->outkey, ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
1514                 return -1;
1515         }
1516
1517         skey = ast_key_get(peer->inkey, AST_KEY_PUBLIC);
1518         if (!skey) {
1519                 ast_log(LOG_NOTICE, "Unable to find key '%s' to verify shared key from '%s'\n",
1520                         peer->inkey, ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
1521                 return -1;
1522         }
1523
1524         /* First check signature */
1525         res = ast_check_signature_bin(skey, (char *)newkey, 128, newsig);
1526         if (res)
1527                 return 0;
1528
1529         res = ast_decrypt_bin(dst, newkey, sizeof(dst), key);
1530         if (res != 16) {
1531                 if (res >= 0)
1532                         ast_log(LOG_NOTICE, "Weird, key decoded to the wrong size (%d)\n", res);
1533                 return 0;
1534         }
1535         /* Decrypted, passes signature */
1536         ast_debug(1, "Wow, new key combo passed signature and decrypt!\n");
1537         memcpy(peer->rxenckey, newkey, 128);
1538         memcpy(peer->rxenckey + 128, newsig, 128);
1539         peer->them_keycrc32 = crc32(0L, peer->rxenckey, 128);
1540         ast_aes_set_decrypt_key(dst, &peer->them_dcx);
1541         ast_aes_set_encrypt_key(dst, &peer->them_ecx);
1542         return 1;
1543 }
1544
1545 static void deep_copy_peer(struct dundi_peer *peer_dst, const struct dundi_peer *peer_src)
1546 {
1547         struct permission *cur, *perm;
1548
1549         *peer_dst = *peer_src;
1550         AST_LIST_NEXT(peer_dst, list) = NULL;
1551
1552         /* Scheduled items cannot go with the copy */
1553         peer_dst->registerid = -1;
1554         peer_dst->qualifyid = -1;
1555         peer_dst->registerexpire = -1;
1556
1557         /* Transactions and lookup history cannot go with the copy either */
1558         peer_dst->regtrans = NULL;
1559         peer_dst->qualtrans = NULL;
1560         memset(&peer_dst->lookups, 0, sizeof(peer_dst->lookups));
1561
1562         memset(&peer_dst->permit, 0, sizeof(peer_dst->permit));
1563         memset(&peer_dst->include, 0, sizeof(peer_dst->permit));
1564
1565         AST_LIST_TRAVERSE(&peer_src->permit, cur, list) {
1566                 if (!(perm = ast_calloc(1, sizeof(*perm) + strlen(cur->name) + 1)))
1567                         continue;
1568
1569                 perm->allow = cur->allow;
1570                 strcpy(perm->name, cur->name);
1571
1572                 AST_LIST_INSERT_HEAD(&peer_dst->permit, perm, list);
1573         }
1574
1575         AST_LIST_TRAVERSE(&peer_src->include, cur, list) {
1576                 if (!(perm = ast_calloc(1, sizeof(*perm) + strlen(cur->name) + 1)))
1577                         continue;
1578
1579                 perm->allow = cur->allow;
1580                 strcpy(perm->name, cur->name);
1581
1582                 AST_LIST_INSERT_HEAD(&peer_dst->include, perm, list);
1583         }
1584 }
1585
1586 static int handle_command_response(struct dundi_transaction *trans, struct dundi_hdr *hdr, int datalen, int encrypted)
1587 {
1588         /* Handle canonical command / response */
1589         int final = hdr->cmdresp & 0x80;
1590         int cmd = hdr->cmdresp & 0x7f;
1591         int x,y,z;
1592         int resp;
1593         int res;
1594         int authpass=0;
1595         unsigned char *bufcpy;
1596 #ifdef LOW_MEMORY
1597         struct dundi_ie_data *ied = ast_calloc(1, sizeof(*ied));
1598 #else
1599         struct dundi_ie_data _ied = {
1600                 .pos = 0,
1601         };
1602         struct dundi_ie_data *ied = &_ied;
1603 #endif
1604         struct dundi_ies ies = {
1605                 .eidcount = 0,
1606         };
1607         struct dundi_peer *peer = NULL;
1608         char eid_str[20];
1609         char eid_str2[20];
1610         int retval = -1;
1611
1612         if (!ied) {
1613                 return -1;
1614         }
1615
1616         if (datalen) {
1617                 bufcpy = ast_alloca(datalen);
1618                 /* Make a copy for parsing */
1619                 memcpy(bufcpy, hdr->ies, datalen);
1620                 ast_debug(1, "Got canonical message %d (%d), %d bytes data%s\n", cmd, hdr->oseqno, datalen, final ? " (Final)" : "");
1621                 if (dundi_parse_ies(&ies, bufcpy, datalen) < 0) {
1622                         ast_log(LOG_WARNING, "Failed to parse DUNDI information elements!\n");
1623                         goto return_cleanup;
1624                 }
1625         }
1626         switch(cmd) {
1627         case DUNDI_COMMAND_DPDISCOVER:
1628         case DUNDI_COMMAND_EIDQUERY:
1629         case DUNDI_COMMAND_PRECACHERQ:
1630                 if (cmd == DUNDI_COMMAND_EIDQUERY)
1631                         resp = DUNDI_COMMAND_EIDRESPONSE;
1632                 else if (cmd == DUNDI_COMMAND_PRECACHERQ)
1633                         resp = DUNDI_COMMAND_PRECACHERP;
1634                 else
1635                         resp = DUNDI_COMMAND_DPRESPONSE;
1636                 /* A dialplan or entity discover -- qualify by highest level entity */
1637                 peer = find_peer(ies.eids[0]);
1638                 if (!peer) {
1639                         dundi_ie_append_cause(ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_NOAUTH, NULL);
1640                         dundi_send(trans, resp, 0, 1, ied);
1641                 } else {
1642                         int hasauth = 0;
1643                         trans->us_eid = peer->us_eid;
1644                         if (strlen(peer->inkey)) {
1645                                 hasauth = encrypted;
1646                         } else
1647                                 hasauth = 1;
1648                         if (hasauth) {
1649                                 /* Okay we're authentiated and all, now we check if they're authorized */
1650                                 if (!ies.called_context)
1651                                         ies.called_context = "e164";
1652                                 if (cmd == DUNDI_COMMAND_EIDQUERY) {
1653                                         res = dundi_answer_entity(trans, &ies, ies.called_context);
1654                                 } else {
1655                                         if (ast_strlen_zero(ies.called_number)) {
1656                                                 /* They're not permitted to access that context */
1657                                                 dundi_ie_append_cause(ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Invalid or missing number/entity");
1658                                                 dundi_send(trans, resp, 0, 1, ied);
1659                                         } else if ((cmd == DUNDI_COMMAND_DPDISCOVER) &&
1660                                                    (peer->model & DUNDI_MODEL_INBOUND) &&
1661                                                            has_permission(&peer->permit, ies.called_context)) {
1662                                                 res = dundi_answer_query(trans, &ies, ies.called_context);
1663                                                 if (res < 0) {
1664                                                         /* There is no such dundi context */
1665                                                         dundi_ie_append_cause(ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_NOAUTH, "Unsupported DUNDI Context");
1666                                                         dundi_send(trans, resp, 0, 1, ied);
1667                                                 }
1668                                         } else if ((cmd = DUNDI_COMMAND_PRECACHERQ) &&
1669                                                    (peer->pcmodel & DUNDI_MODEL_INBOUND) &&
1670                                                            has_permission(&peer->include, ies.called_context)) {
1671                                                 res = dundi_prop_precache(trans, &ies, ies.called_context);
1672                                                 if (res < 0) {
1673                                                         /* There is no such dundi context */
1674                                                         dundi_ie_append_cause(ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_NOAUTH, "Unsupported DUNDI Context");
1675                                                         dundi_send(trans, resp, 0, 1, ied);
1676                                                 }
1677                                         } else {
1678                                                 /* They're not permitted to access that context */
1679                                                 dundi_ie_append_cause(ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_NOAUTH, "Permission to context denied");
1680                                                 dundi_send(trans, resp, 0, 1, ied);
1681                                         }
1682                                 }
1683                         } else {
1684                                 /* They're not permitted to access that context */
1685                                 dundi_ie_append_cause(ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_NOAUTH, "Unencrypted responses not permitted");
1686                                 dundi_send(trans, resp, 0, 1, ied);
1687                         }
1688                 }
1689                 break;
1690         case DUNDI_COMMAND_REGREQ:
1691                 /* A register request -- should only have one entity */
1692                 peer = find_peer(ies.eids[0]);
1693
1694                 /* if the peer is not found and we have a valid 'any_peer' setting */
1695                 if (any_peer && peer == any_peer) {
1696                         /* copy any_peer into a new peer object */
1697                         peer = ast_calloc(1, sizeof(*peer));
1698                         if (peer) {
1699                                 deep_copy_peer(peer, any_peer);
1700
1701                                 /* set EID to remote EID */
1702                                 peer->eid = *ies.eids[0];
1703
1704                                 AST_LIST_LOCK(&peers);
1705                                 AST_LIST_INSERT_HEAD(&peers, peer, list);
1706                                 AST_LIST_UNLOCK(&peers);
1707                         }
1708                 }
1709
1710                 if (!peer || !peer->dynamic) {
1711                         dundi_ie_append_cause(ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_NOAUTH, NULL);
1712                         dundi_send(trans, DUNDI_COMMAND_REGRESPONSE, 0, 1, ied);
1713                 } else {
1714                         int hasauth = 0;
1715                         trans->us_eid = peer->us_eid;
1716                         if (!ast_strlen_zero(peer->inkey)) {
1717                                 hasauth = encrypted;
1718                         } else
1719                                 hasauth = 1;
1720                         if (hasauth) {
1721                                 int expire = default_expiration;
1722                                 char data[256];
1723                                 int needqual = 0;
1724                                 AST_SCHED_DEL(sched, peer->registerexpire);
1725                                 peer->registerexpire = ast_sched_add(sched, (expire + 10) * 1000, do_register_expire, peer);
1726                                 snprintf(data, sizeof(data), "%s:%d", ast_sockaddr_stringify(&trans->addr), expire);
1727                                 ast_db_put("dundi/dpeers", dundi_eid_to_str_short(eid_str, sizeof(eid_str), &peer->eid), data);
1728                                 if (ast_sockaddr_cmp(&peer->addr, &trans->addr)) {
1729                                         ast_verb(3, "Registered DUNDi peer '%s' at '%s'\n",
1730                                                 ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid),
1731                                                 ast_sockaddr_stringify(&trans->addr));
1732                                         needqual = 1;
1733                                 }
1734
1735                                 ast_sockaddr_copy(&peer->addr, &trans->addr);
1736                                 dundi_ie_append_short(ied, DUNDI_IE_EXPIRATION, default_expiration);
1737                                 dundi_send(trans, DUNDI_COMMAND_REGRESPONSE, 0, 1, ied);
1738                                 if (needqual)
1739                                         qualify_peer(peer, 1);
1740                         }
1741                 }
1742                 break;
1743         case DUNDI_COMMAND_DPRESPONSE:
1744                 /* A dialplan response, lets see what we got... */
1745                 if (ies.cause < 1) {
1746                         /* Success of some sort */
1747                         ast_debug(1, "Looks like success of some sort (%d), %d answers\n", ies.cause, ies.anscount);
1748                         if (ast_test_flag(trans, FLAG_ENCRYPT)) {
1749                                 authpass = encrypted;
1750                         } else
1751                                 authpass = 1;
1752                         if (authpass) {
1753                                 /* Pass back up answers */
1754                                 if (trans->parent && trans->parent->dr) {
1755                                         y = trans->parent->respcount;
1756                                         for (x=0;x<ies.anscount;x++) {
1757                                                 if (trans->parent->respcount < trans->parent->maxcount) {
1758                                                         /* Make sure it's not already there */
1759                                                         for (z=0;z<trans->parent->respcount;z++) {
1760                                                                 if ((trans->parent->dr[z].techint == ies.answers[x]->protocol) &&
1761                                                                     !strcmp(trans->parent->dr[z].dest, (char *)ies.answers[x]->data))
1762                                                                                 break;
1763                                                         }
1764                                                         if (z == trans->parent->respcount) {
1765                                                                 /* Copy into parent responses */
1766                                                                 trans->parent->dr[trans->parent->respcount].flags = ntohs(ies.answers[x]->flags);
1767                                                                 trans->parent->dr[trans->parent->respcount].techint = ies.answers[x]->protocol;
1768                                                                 trans->parent->dr[trans->parent->respcount].weight = ntohs(ies.answers[x]->weight);
1769                                                                 trans->parent->dr[trans->parent->respcount].eid = ies.answers[x]->eid;
1770                                                                 if (ies.expiration > 0)
1771                                                                         trans->parent->dr[trans->parent->respcount].expiration = ies.expiration;
1772                                                                 else
1773                                                                         trans->parent->dr[trans->parent->respcount].expiration = dundi_cache_time;
1774                                                                 ast_eid_to_str(trans->parent->dr[trans->parent->respcount].eid_str,
1775                                                                         sizeof(trans->parent->dr[trans->parent->respcount].eid_str),
1776                                                                         &ies.answers[x]->eid);
1777                                                                 ast_copy_string(trans->parent->dr[trans->parent->respcount].dest, (char *)ies.answers[x]->data,
1778                                                                         sizeof(trans->parent->dr[trans->parent->respcount].dest));
1779                                                                 ast_copy_string(trans->parent->dr[trans->parent->respcount].tech, tech2str(ies.answers[x]->protocol),
1780                                                                         sizeof(trans->parent->dr[trans->parent->respcount].tech));
1781                                                                 trans->parent->respcount++;
1782                                                                 ast_clear_flag_nonstd(trans->parent->hmd, DUNDI_HINT_DONT_ASK);
1783                                                         } else if (trans->parent->dr[z].weight > ntohs(ies.answers[x]->weight)) {
1784                                                                 /* Update weight if appropriate */
1785                                                                 trans->parent->dr[z].weight = ntohs(ies.answers[x]->weight);
1786                                                         }
1787                                                 } else
1788                                                         ast_log(LOG_NOTICE, "Dropping excessive answers to request for %s@%s\n",
1789                                                                 trans->parent->number, trans->parent->dcontext);
1790                                         }
1791                                         /* Save all the results (if any) we had.  Even if no results, still cache lookup.  Let
1792                                            the cache know if this request was unaffected by our entity list. */
1793                                         cache_save(&trans->them_eid, trans->parent, y,
1794                                                         ies.hint ? ast_test_flag_nonstd(ies.hint, htons(DUNDI_HINT_UNAFFECTED)) : 0, ies.expiration, 0);
1795                                         if (ies.hint) {
1796                                                 cache_save_hint(&trans->them_eid, trans->parent, ies.hint, ies.expiration);
1797                                                 if (ast_test_flag_nonstd(ies.hint, htons(DUNDI_HINT_TTL_EXPIRED)))
1798                                                         ast_set_flag_nonstd(trans->parent->hmd, DUNDI_HINT_TTL_EXPIRED);
1799                                                 if (ast_test_flag_nonstd(ies.hint, htons(DUNDI_HINT_DONT_ASK))) {
1800                                                         if (strlen((char *)ies.hint->data) > strlen(trans->parent->hmd->exten)) {
1801                                                                 ast_copy_string(trans->parent->hmd->exten, (char *)ies.hint->data,
1802                                                                         sizeof(trans->parent->hmd->exten));
1803                                                         }
1804                                                 } else {
1805                                                         ast_clear_flag_nonstd(trans->parent->hmd, DUNDI_HINT_DONT_ASK);
1806                                                 }
1807                                         }
1808                                         if (ies.expiration > 0) {
1809                                                 if (trans->parent->expiration > ies.expiration) {
1810                                                         trans->parent->expiration = ies.expiration;
1811                                                 }
1812                                         }
1813                                 }
1814                                 /* Close connection if not final */
1815                                 if (!final)
1816                                         dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL);
1817                         }
1818
1819                 } else {
1820                         /* Auth failure, check for data */
1821                         if (!final) {
1822                                 /* Cancel if they didn't already */
1823                                 dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL);
1824                         }
1825                 }
1826                 break;
1827         case DUNDI_COMMAND_EIDRESPONSE:
1828                 /* A dialplan response, lets see what we got... */
1829                 if (ies.cause < 1) {
1830                         /* Success of some sort */
1831                         ast_debug(1, "Looks like success of some sort (%d)\n", ies.cause);
1832                         if (ast_test_flag(trans, FLAG_ENCRYPT)) {
1833                                 authpass = encrypted;
1834                         } else
1835                                 authpass = 1;
1836                         if (authpass) {
1837                                 /* Pass back up answers */
1838                                 if (trans->parent && trans->parent->dei && ies.q_org) {
1839                                         if (!trans->parent->respcount) {
1840                                                 trans->parent->respcount++;
1841                                                 if (ies.q_dept)
1842                                                         ast_copy_string(trans->parent->dei->orgunit, ies.q_dept, sizeof(trans->parent->dei->orgunit));
1843                                                 if (ies.q_org)
1844                                                         ast_copy_string(trans->parent->dei->org, ies.q_org, sizeof(trans->parent->dei->org));
1845                                                 if (ies.q_locality)
1846                                                         ast_copy_string(trans->parent->dei->locality, ies.q_locality, sizeof(trans->parent->dei->locality));
1847                                                 if (ies.q_stateprov)
1848                                                         ast_copy_string(trans->parent->dei->stateprov, ies.q_stateprov, sizeof(trans->parent->dei->stateprov));
1849                                                 if (ies.q_country)
1850                                                         ast_copy_string(trans->parent->dei->country, ies.q_country, sizeof(trans->parent->dei->country));
1851                                                 if (ies.q_email)
1852                                                         ast_copy_string(trans->parent->dei->email, ies.q_email, sizeof(trans->parent->dei->email));
1853                                                 if (ies.q_phone)
1854                                                         ast_copy_string(trans->parent->dei->phone, ies.q_phone, sizeof(trans->parent->dei->phone));
1855                                                 if (ies.q_ipaddr)
1856                                                         ast_copy_string(trans->parent->dei->ipaddr, ies.q_ipaddr, sizeof(trans->parent->dei->ipaddr));
1857                                                 if (!ast_eid_cmp(&trans->them_eid, &trans->parent->query_eid)) {
1858                                                         /* If it's them, update our address */
1859                                                         ast_copy_string(trans->parent->dei->ipaddr, ast_sockaddr_stringify_addr(&trans->addr), sizeof(trans->parent->dei->ipaddr));
1860                                                 }
1861                                         }
1862                                         if (ies.hint) {
1863                                                 if (ast_test_flag_nonstd(ies.hint, htons(DUNDI_HINT_TTL_EXPIRED)))
1864                                                         ast_set_flag_nonstd(trans->parent->hmd, DUNDI_HINT_TTL_EXPIRED);
1865                                         }
1866                                 }
1867                                 /* Close connection if not final */
1868                                 if (!final)
1869                                         dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL);
1870                         }
1871
1872                 } else {
1873                         /* Auth failure, check for data */
1874                         if (!final) {
1875                                 /* Cancel if they didn't already */
1876                                 dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL);
1877                         }
1878                 }
1879                 break;
1880         case DUNDI_COMMAND_REGRESPONSE:
1881                 /* A dialplan response, lets see what we got... */
1882                 if (ies.cause < 1) {
1883                         int hasauth;
1884                         /* Success of some sort */
1885                         if (ast_test_flag(trans, FLAG_ENCRYPT)) {
1886                                 hasauth = encrypted;
1887                         } else
1888                                 hasauth = 1;
1889
1890                         if (!hasauth) {
1891                                 ast_log(LOG_NOTICE, "Reponse to register not authorized!\n");
1892                                 if (!final) {
1893                                         dundi_ie_append_cause(ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_NOAUTH, "Improper signature in answer");
1894                                         dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, ied);
1895                                 }
1896                         } else {
1897                                 ast_debug(1, "Yay, we've registered as '%s' to '%s'\n", ast_eid_to_str(eid_str, sizeof(eid_str), &trans->us_eid),
1898                                                 ast_eid_to_str(eid_str2, sizeof(eid_str2), &trans->them_eid));
1899                                 /* Close connection if not final */
1900                                 if (!final)
1901                                         dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL);
1902                         }
1903                 } else {
1904                         /* Auth failure, cancel if they didn't for some reason */
1905                         if (!final) {
1906                                 dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL);
1907                         }
1908                 }
1909                 break;
1910         case DUNDI_COMMAND_INVALID:
1911         case DUNDI_COMMAND_NULL:
1912         case DUNDI_COMMAND_PRECACHERP:
1913                 /* Do nothing special */
1914                 if (!final)
1915                         dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL);
1916                 break;
1917         case DUNDI_COMMAND_ENCREJ:
1918                 if ((ast_test_flag(trans, FLAG_SENDFULLKEY)) || AST_LIST_EMPTY(&trans->lasttrans) || !(peer = find_peer(&trans->them_eid))) {
1919                         /* No really, it's over at this point */
1920                         if (!final)
1921                                 dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL);
1922                 } else {
1923                         /* Send with full key */
1924                         ast_set_flag(trans, FLAG_SENDFULLKEY);
1925                         if (final) {
1926                                 /* Ooops, we got a final message, start by sending ACK... */
1927                                 dundi_ack(trans, hdr->cmdresp & 0x80);
1928                                 trans->aseqno = trans->iseqno;
1929                                 /* Now, we gotta create a new transaction */
1930                                 if (!reset_transaction(trans)) {
1931                                         /* Make sure handle_frame doesn't destroy us */
1932                                         hdr->cmdresp &= 0x7f;
1933                                         /* Parse the message we transmitted */
1934                                         memset(&ies, 0, sizeof(ies));
1935                                         dundi_parse_ies(&ies, (AST_LIST_FIRST(&trans->lasttrans))->h->ies, (AST_LIST_FIRST(&trans->lasttrans))->datalen - sizeof(struct dundi_hdr));
1936                                         /* Reconstruct outgoing encrypted packet */
1937                                         memset(ied, 0, sizeof(*ied));
1938                                         dundi_ie_append_eid(ied, DUNDI_IE_EID, &trans->us_eid);
1939                                         dundi_ie_append_raw(ied, DUNDI_IE_SHAREDKEY, peer->txenckey, 128);
1940                                         dundi_ie_append_raw(ied, DUNDI_IE_SIGNATURE, peer->txenckey + 128, 128);
1941                                         if (ies.encblock)
1942                                                 dundi_ie_append_encdata(ied, DUNDI_IE_ENCDATA, ies.encblock->iv, ies.encblock->encdata, ies.enclen);
1943                                         dundi_send(trans, DUNDI_COMMAND_ENCRYPT, 0, (AST_LIST_FIRST(&trans->lasttrans))->h->cmdresp & 0x80, ied);
1944                                         peer->sentfullkey = 1;
1945                                 }
1946                         }
1947                 }
1948                 break;
1949         case DUNDI_COMMAND_ENCRYPT:
1950                 if (!encrypted) {
1951                         /* No nested encryption! */
1952                         if ((trans->iseqno == 1) && !trans->oseqno) {
1953                                 if (!ies.eids[0] || !(peer = find_peer(ies.eids[0])) ||
1954                                         ((!ies.encsharedkey || !ies.encsig) && !ies.keycrc32) ||
1955                                         (check_key(peer, ies.encsharedkey, ies.encsig, ies.keycrc32) < 1)) {
1956                                         if (!final) {
1957                                                 dundi_send(trans, DUNDI_COMMAND_ENCREJ, 0, 1, NULL);
1958                                         }
1959                                         break;
1960                                 }
1961                                 apply_peer(trans, peer);
1962                                 /* Key passed, use new contexts for this session */
1963                                 trans->ecx = peer->them_ecx;
1964                                 trans->dcx = peer->them_dcx;
1965                         }
1966                         if (ast_test_flag(trans, FLAG_ENCRYPT) && ies.encblock && ies.enclen) {
1967                                 struct dundi_hdr *dhdr;
1968                                 unsigned char decoded[MAX_PACKET_SIZE];
1969                                 int ddatalen;
1970                                 ddatalen = sizeof(decoded);
1971                                 dhdr = dundi_decrypt(trans, decoded, &ddatalen, hdr, ies.encblock, ies.enclen);
1972                                 if (dhdr) {
1973                                         /* Handle decrypted response */
1974                                         if (dundidebug)
1975                                                 dundi_showframe(dhdr, 3, &trans->addr, ddatalen - sizeof(struct dundi_hdr));
1976                                         handle_command_response(trans, dhdr, ddatalen - sizeof(struct dundi_hdr), 1);
1977                                         /* Carry back final flag */
1978                                         hdr->cmdresp |= dhdr->cmdresp & 0x80;
1979                                         break;
1980                                 } else {
1981                                         ast_debug(1, "Ouch, decrypt failed :(\n");
1982                                 }
1983                         }
1984                 }
1985                 if (!final) {
1986                         /* Turn off encryption */
1987                         ast_clear_flag(trans, FLAG_ENCRYPT);
1988                         dundi_send(trans, DUNDI_COMMAND_ENCREJ, 0, 1, NULL);
1989                 }
1990                 break;
1991         default:
1992                 /* Send unknown command if we don't know it, with final flag IFF it's the
1993                    first command in the dialog and only if we haven't received final notification */
1994                 if (!final) {
1995                         dundi_ie_append_byte(ied, DUNDI_IE_UNKNOWN, cmd);
1996                         dundi_send(trans, DUNDI_COMMAND_UNKNOWN, 0, !hdr->oseqno, ied);
1997                 }
1998         }
1999
2000         retval = 0;
2001
2002 return_cleanup:
2003 #ifdef LOW_MEMORY
2004         ast_free(ied);
2005 #endif
2006         return retval;
2007 }
2008
2009 static void destroy_packet(struct dundi_packet *pack, int needfree);
2010 static void destroy_packets(struct packetlist *p)
2011 {
2012         struct dundi_packet *pack;
2013
2014         while ((pack = AST_LIST_REMOVE_HEAD(p, list))) {
2015                 AST_SCHED_DEL(sched, pack->retransid);
2016                 ast_free(pack);
2017         }
2018 }
2019
2020
2021 static int ack_trans(struct dundi_transaction *trans, int iseqno)
2022 {
2023         struct dundi_packet *pack;
2024
2025         /* Ack transmitted packet corresponding to iseqno */
2026         AST_LIST_TRAVERSE(&trans->packets, pack, list) {
2027                 if ((pack->h->oseqno + 1) % 255 == iseqno) {
2028                         destroy_packet(pack, 0);
2029                         if (!AST_LIST_EMPTY(&trans->lasttrans)) {
2030                                 ast_log(LOG_WARNING, "Whoa, there was still a last trans?\n");
2031                                 destroy_packets(&trans->lasttrans);
2032                         }
2033                         AST_LIST_INSERT_HEAD(&trans->lasttrans, pack, list);
2034                         AST_SCHED_DEL(sched, trans->autokillid);
2035                         return 1;
2036                 }
2037         }
2038
2039         return 0;
2040 }
2041
2042 static int handle_frame(struct dundi_hdr *h, struct ast_sockaddr *sin, int datalen)
2043 {
2044         struct dundi_transaction *trans;
2045         trans = find_transaction(h, sin);
2046         if (!trans) {
2047                 dundi_reject(h, sin);
2048                 return 0;
2049         }
2050         /* Got a transaction, see where this header fits in */
2051         if (h->oseqno == trans->iseqno) {
2052                 /* Just what we were looking for...  Anything but ack increments iseqno */
2053                 if (ack_trans(trans, h->iseqno) && ast_test_flag(trans, FLAG_FINAL)) {
2054                         /* If final, we're done */
2055                         destroy_trans(trans, 0);
2056                         return 0;
2057                 }
2058                 if (h->cmdresp != DUNDI_COMMAND_ACK) {
2059                         trans->oiseqno = trans->iseqno;
2060                         trans->iseqno++;
2061                         handle_command_response(trans, h, datalen, 0);
2062                 }
2063                 if (trans->aseqno != trans->iseqno) {
2064                         dundi_ack(trans, h->cmdresp & 0x80);
2065                         trans->aseqno = trans->iseqno;
2066                 }
2067                 /* Delete any saved last transmissions */
2068                 destroy_packets(&trans->lasttrans);
2069                 if (h->cmdresp & 0x80) {
2070                         /* Final -- destroy now */
2071                         destroy_trans(trans, 0);
2072                 }
2073         } else if (h->oseqno == trans->oiseqno) {
2074                 /* Last incoming sequence number -- send ACK without processing */
2075                 dundi_ack(trans, 0);
2076         } else {
2077                 /* Out of window -- simply drop */
2078                 ast_debug(1, "Dropping packet out of window!\n");
2079         }
2080         return 0;
2081 }
2082
2083 static int socket_read(int *id, int fd, short events, void *sock)
2084 {
2085         struct ast_sockaddr sin;
2086         int res;
2087         struct dundi_hdr *h;
2088         char buf[MAX_PACKET_SIZE];
2089
2090         res = ast_recvfrom(*((int *)sock), buf, sizeof(buf), 0, &sin);
2091         if (res < 0) {
2092                 if (errno != ECONNREFUSED)
2093                         ast_log(LOG_WARNING, "Error: %s\n", strerror(errno));
2094                 return 1;
2095         }
2096         if (res < sizeof(struct dundi_hdr)) {
2097                 ast_log(LOG_WARNING, "midget packet received (%d of %d min)\n", res, (int)sizeof(struct dundi_hdr));
2098                 return 1;
2099         }
2100         buf[res] = '\0';
2101         h = (struct dundi_hdr *) buf;
2102         if (dundidebug)
2103                 dundi_showframe(h, 1, &sin, res - sizeof(struct dundi_hdr));
2104         AST_LIST_LOCK(&peers);
2105         handle_frame(h, &sin, res - sizeof(struct dundi_hdr));
2106         AST_LIST_UNLOCK(&peers);
2107         return 1;
2108 }
2109
2110 static void build_secret(char *secret, int seclen)
2111 {
2112         unsigned char tmp[16];
2113         char *s;
2114         build_iv(tmp);
2115         secret[0] = '\0';
2116         ast_base64encode(secret, tmp, sizeof(tmp), seclen);
2117         /* Eliminate potential bad characters */
2118         while((s = strchr(secret, ';'))) *s = '+';
2119         while((s = strchr(secret, '/'))) *s = '+';
2120         while((s = strchr(secret, ':'))) *s = '+';
2121         while((s = strchr(secret, '@'))) *s = '+';
2122 }
2123
2124
2125 static void save_secret(const char *newkey, const char *oldkey)
2126 {
2127         char tmp[350];
2128         if (oldkey)
2129                 snprintf(tmp, sizeof(tmp), "%s;%s", oldkey, newkey);
2130         else
2131                 snprintf(tmp, sizeof(tmp), "%s", newkey);
2132         rotatetime = time(NULL) + DUNDI_SECRET_TIME;
2133         ast_db_put(secretpath, "secret", tmp);
2134         snprintf(tmp, sizeof(tmp), "%d", (int)rotatetime);
2135         ast_db_put(secretpath, "secretexpiry", tmp);
2136 }
2137
2138 static void load_password(void)
2139 {
2140         char *current=NULL;
2141         char *last=NULL;
2142         char tmp[256];
2143         time_t expired;
2144
2145         ast_db_get(secretpath, "secretexpiry", tmp, sizeof(tmp));
2146         if (!ast_get_time_t(tmp, &expired, 0, NULL)) {
2147                 ast_db_get(secretpath, "secret", tmp, sizeof(tmp));
2148                 current = strchr(tmp, ';');
2149                 if (!current)
2150                         current = tmp;
2151                 else {
2152                         *current = '\0';
2153                         current++;
2154                 };
2155                 if ((time(NULL) - expired) < 0) {
2156                         if ((expired - time(NULL)) > DUNDI_SECRET_TIME)
2157                                 expired = time(NULL) + DUNDI_SECRET_TIME;
2158                 } else if ((time(NULL) - (expired + DUNDI_SECRET_TIME)) < 0) {
2159                         last = current;
2160                         current = NULL;
2161                 } else {
2162                         last = NULL;
2163                         current = NULL;
2164                 }
2165         }
2166         if (current) {
2167                 /* Current key is still valid, just setup rotatation properly */
2168                 ast_copy_string(cursecret, current, sizeof(cursecret));
2169                 rotatetime = expired;
2170         } else {
2171                 /* Current key is out of date, rotate or eliminate all together */
2172                 build_secret(cursecret, sizeof(cursecret));
2173                 save_secret(cursecret, last);
2174         }
2175 }
2176
2177 static void check_password(void)
2178 {
2179         char oldsecret[80];
2180         time_t now;
2181
2182         time(&now);
2183 #if 0
2184         printf("%ld/%ld\n", now, rotatetime);
2185 #endif
2186         if ((now - rotatetime) >= 0) {
2187                 /* Time to rotate keys */
2188                 ast_copy_string(oldsecret, cursecret, sizeof(oldsecret));
2189                 build_secret(cursecret, sizeof(cursecret));
2190                 save_secret(cursecret, oldsecret);
2191         }
2192 }
2193
2194 static void *network_thread(void *ignore)
2195 {
2196         /* Our job is simple: Send queued messages, retrying if necessary.  Read frames
2197            from the network, and queue them for delivery to the channels */
2198         int res;
2199         /* Establish I/O callback for socket read */
2200         int *socket_read_id = ast_io_add(io, netsocket, socket_read, AST_IO_IN, &netsocket);
2201         int *socket_read_id2 = NULL;
2202         if (netsocket2 >= 0) {
2203                 socket_read_id2 = ast_io_add(io, netsocket2, socket_read, AST_IO_IN, &netsocket2);
2204         }
2205
2206         while (!dundi_shutdown) {
2207                 res = ast_sched_wait(sched);
2208                 if ((res > 1000) || (res < 0))
2209                         res = 1000;
2210                 res = ast_io_wait(io, res);
2211                 if (res >= 0) {
2212                         AST_LIST_LOCK(&peers);
2213                         ast_sched_runq(sched);
2214                         AST_LIST_UNLOCK(&peers);
2215                 }
2216                 check_password();
2217         }
2218
2219         ast_io_remove(io, socket_read_id);
2220
2221         if (socket_read_id2) {
2222                 ast_io_remove(io, socket_read_id2);
2223         }
2224
2225         return NULL;
2226 }
2227
2228 static void *process_clearcache(void *ignore)
2229 {
2230         struct ast_db_entry *db_entry, *db_tree;
2231         int striplen = sizeof("/dundi/cache");
2232         time_t now;
2233
2234         while (!dundi_shutdown) {
2235                 pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
2236
2237                 time(&now);
2238
2239                 db_entry = db_tree = ast_db_gettree("dundi/cache", NULL);
2240                 for (; db_entry; db_entry = db_entry->next) {
2241                         time_t expiry;
2242
2243                         if (!ast_get_time_t(db_entry->data, &expiry, 0, NULL)) {
2244                                 if (expiry < now) {
2245                                         ast_debug(1, "clearing expired DUNDI cache entry: %s\n", db_entry->key);
2246                                         ast_db_del("dundi/cache", db_entry->key + striplen);
2247                                 }
2248                         }
2249                 }
2250                 ast_db_freetree(db_tree);
2251
2252                 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
2253                 pthread_testcancel();
2254                 sleep(60);
2255                 pthread_testcancel();
2256         }
2257
2258         return NULL;
2259 }
2260
2261 static void *process_precache(void *ign)
2262 {
2263         struct dundi_precache_queue *qe;
2264         time_t now;
2265         char context[256];
2266         char number[256];
2267         int run;
2268
2269         while (!dundi_shutdown) {
2270                 time(&now);
2271                 run = 0;
2272                 AST_LIST_LOCK(&pcq);
2273                 if ((qe = AST_LIST_FIRST(&pcq))) {
2274                         if (!qe->expiration) {
2275                                 /* Gone...  Remove... */
2276                                 AST_LIST_REMOVE_HEAD(&pcq, list);
2277                                 ast_free(qe);
2278                         } else if (qe->expiration < now) {
2279                                 /* Process this entry */
2280                                 qe->expiration = 0;
2281                                 ast_copy_string(context, qe->context, sizeof(context));
2282                                 ast_copy_string(number, qe->number, sizeof(number));
2283                                 run = 1;
2284                         }
2285                 }
2286                 AST_LIST_UNLOCK(&pcq);
2287                 if (run) {
2288                         dundi_precache(context, number);
2289                 } else
2290                         sleep(1);
2291         }
2292
2293         return NULL;
2294 }
2295
2296 static int start_network_thread(void)
2297 {
2298         ast_pthread_create_background(&netthreadid, NULL, network_thread, NULL);
2299         ast_pthread_create_background(&precachethreadid, NULL, process_precache, NULL);
2300         ast_pthread_create_background(&clearcachethreadid, NULL, process_clearcache, NULL);
2301         return 0;
2302 }
2303
2304 static char *dundi_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2305 {
2306         switch (cmd) {
2307         case CLI_INIT:
2308                 e->command = "dundi set debug {on|off}";
2309                 e->usage =
2310                         "Usage: dundi set debug {on|off}\n"
2311                         "       Enables/Disables dumping of DUNDi packets for debugging purposes\n";
2312                 return NULL;
2313         case CLI_GENERATE:
2314                 return NULL;
2315         }
2316
2317         if (a->argc != e->args) {
2318                 return CLI_SHOWUSAGE;
2319         }
2320         if (!strncasecmp(a->argv[e->args -1], "on", 2)) {
2321                 dundidebug = 1;
2322                 ast_cli(a->fd, "DUNDi Debugging Enabled\n");
2323         } else {
2324                 dundidebug = 0;
2325                 ast_cli(a->fd, "DUNDi Debugging Disabled\n");
2326         }
2327         return CLI_SUCCESS;
2328 }
2329
2330 static char *dundi_store_history(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2331 {
2332         switch (cmd) {
2333         case CLI_INIT:
2334                 e->command = "dundi store history {on|off}";
2335                 e->usage =
2336                         "Usage: dundi store history {on|off}\n"
2337                         "       Enables/Disables storing of DUNDi requests and times for debugging\n"
2338                         "purposes\n";
2339                 return NULL;
2340         case CLI_GENERATE:
2341                 return NULL;
2342         }
2343
2344         if (a->argc != e->args) {
2345                 return CLI_SHOWUSAGE;
2346         }
2347         if (!strncasecmp(a->argv[e->args -1], "on", 2)) {
2348                 global_storehistory = 1;
2349                 ast_cli(a->fd, "DUNDi History Storage Enabled\n");
2350         } else {
2351                 global_storehistory = 0;
2352                 ast_cli(a->fd, "DUNDi History Storage Disabled\n");
2353         }
2354         return CLI_SUCCESS;
2355 }
2356
2357 static char *dundi_flush(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2358 {
2359         int stats = 0;
2360         switch (cmd) {
2361         case CLI_INIT:
2362                 e->command = "dundi flush [stats]";
2363                 e->usage =
2364                         "Usage: dundi flush [stats]\n"
2365                         "       Flushes DUNDi answer cache, used primarily for debug.  If\n"
2366                         "'stats' is present, clears timer statistics instead of normal\n"
2367                         "operation.\n";
2368                 return NULL;
2369         case CLI_GENERATE:
2370                 return NULL;
2371         }
2372         if ((a->argc < 2) || (a->argc > 3)) {
2373                 return CLI_SHOWUSAGE;
2374         }
2375         if (a->argc > 2) {
2376                 if (!strcasecmp(a->argv[2], "stats")) {
2377                         stats = 1;
2378                 } else {
2379                         return CLI_SHOWUSAGE;
2380                 }
2381         }
2382         if (stats) {
2383                 /* Flush statistics */
2384                 struct dundi_peer *p;
2385                 int x;
2386                 AST_LIST_LOCK(&peers);
2387                 AST_LIST_TRAVERSE(&peers, p, list) {
2388                         for (x = 0;x < DUNDI_TIMING_HISTORY; x++) {
2389                                 ast_free(p->lookups[x]);
2390                                 p->lookups[x] = NULL;
2391                                 p->lookuptimes[x] = 0;
2392                         }
2393                         p->avgms = 0;
2394                 }
2395                 AST_LIST_UNLOCK(&peers);
2396         } else {
2397                 ast_db_deltree("dundi/cache", NULL);
2398                 ast_cli(a->fd, "DUNDi Cache Flushed\n");
2399         }
2400         return CLI_SUCCESS;
2401 }
2402
2403 static char *model2str(int model)
2404 {
2405         switch(model) {
2406         case DUNDI_MODEL_INBOUND:
2407                 return "Inbound";
2408         case DUNDI_MODEL_OUTBOUND:
2409                 return "Outbound";
2410         case DUNDI_MODEL_SYMMETRIC:
2411                 return "Symmetric";
2412         default:
2413                 return "Unknown";
2414         }
2415 }
2416
2417 static char *complete_peer_helper(const char *line, const char *word, int pos, int state, int rpos)
2418 {
2419         int which=0, len;
2420         char *ret = NULL;
2421         struct dundi_peer *p;
2422         char eid_str[20];
2423
2424         if (pos != rpos)
2425                 return NULL;
2426         AST_LIST_LOCK(&peers);
2427         len = strlen(word);
2428         AST_LIST_TRAVERSE(&peers, p, list) {
2429                 const char *s = ast_eid_to_str(eid_str, sizeof(eid_str), &p->eid);
2430                 if (!strncasecmp(word, s, len) && ++which > state) {
2431                         ret = ast_strdup(s);
2432                         break;
2433                 }
2434         }
2435         AST_LIST_UNLOCK(&peers);
2436         return ret;
2437 }
2438
2439 static int rescomp(const void *a, const void *b)
2440 {
2441         const struct dundi_result *resa, *resb;
2442         resa = a;
2443         resb = b;
2444         if (resa->weight < resb->weight)
2445                 return -1;
2446         if (resa->weight > resb->weight)
2447                 return 1;
2448         return 0;
2449 }
2450
2451 static void sort_results(struct dundi_result *results, int count)
2452 {
2453         qsort(results, count, sizeof(results[0]), rescomp);
2454 }
2455
2456 static char *dundi_do_lookup(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2457 {
2458         int res;
2459         char tmp[256];
2460         char fs[80] = "";
2461         char *context;
2462         int x;
2463         int bypass = 0;
2464         struct dundi_result dr[MAX_RESULTS];
2465         struct timeval start;
2466         switch (cmd) {
2467         case CLI_INIT:
2468                 e->command = "dundi lookup";
2469                 e->usage =
2470                         "Usage: dundi lookup <number>[@context] [bypass]\n"
2471                         "       Lookup the given number within the given DUNDi context\n"
2472                         "(or e164 if none is specified).  Bypasses cache if 'bypass'\n"
2473                         "keyword is specified.\n";
2474                 return NULL;
2475         case CLI_GENERATE:
2476                 return NULL;
2477         }
2478
2479         if ((a->argc < 3) || (a->argc > 4)) {
2480                 return CLI_SHOWUSAGE;
2481         }
2482         if (a->argc > 3) {
2483                 if (!strcasecmp(a->argv[3], "bypass")) {
2484                         bypass=1;
2485                 } else {
2486                         return CLI_SHOWUSAGE;
2487                 }
2488         }
2489         ast_copy_string(tmp, a->argv[2], sizeof(tmp));
2490         context = strchr(tmp, '@');
2491         if (context) {
2492                 *context = '\0';
2493                 context++;
2494         }
2495         start = ast_tvnow();
2496         res = dundi_lookup(dr, MAX_RESULTS, NULL, context, tmp, bypass);
2497
2498         if (res < 0)
2499                 ast_cli(a->fd, "DUNDi lookup returned error.\n");
2500         else if (!res)
2501                 ast_cli(a->fd, "DUNDi lookup returned no results.\n");
2502         else
2503                 sort_results(dr, res);
2504         for (x=0;x<res;x++) {
2505                 ast_cli(a->fd, "%3d. %5d %s/%s (%s)\n", x + 1, dr[x].weight, dr[x].tech, dr[x].dest, dundi_flags2str(fs, sizeof(fs), dr[x].flags));
2506                 ast_cli(a->fd, "     from %s, expires in %d s\n", dr[x].eid_str, dr[x].expiration);
2507         }
2508         ast_cli(a->fd, "DUNDi lookup completed in %" PRIi64 " ms\n", ast_tvdiff_ms(ast_tvnow(), start));
2509         return CLI_SUCCESS;
2510 }
2511
2512 static char *dundi_do_precache(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2513 {
2514         int res;
2515         char tmp[256];
2516         char *context;
2517         struct timeval start;
2518         switch (cmd) {
2519         case CLI_INIT:
2520                 e->command = "dundi precache";
2521                 e->usage =
2522                         "Usage: dundi precache <number>[@context]\n"
2523                         "       Lookup the given number within the given DUNDi context\n"
2524                         "(or e164 if none is specified) and precaches the results to any\n"
2525                         "upstream DUNDi push servers.\n";
2526                 return NULL;
2527         case CLI_GENERATE:
2528                 return NULL;
2529         }
2530         if ((a->argc < 3) || (a->argc > 3)) {
2531                 return CLI_SHOWUSAGE;
2532         }
2533         ast_copy_string(tmp, a->argv[2], sizeof(tmp));
2534         context = strchr(tmp, '@');
2535         if (context) {
2536                 *context = '\0';
2537                 context++;
2538         }
2539         start = ast_tvnow();
2540         res = dundi_precache(context, tmp);
2541
2542         if (res < 0)
2543                 ast_cli(a->fd, "DUNDi precache returned error.\n");
2544         else if (!res)
2545                 ast_cli(a->fd, "DUNDi precache returned no error.\n");
2546         ast_cli(a->fd, "DUNDi lookup completed in %" PRIi64 " ms\n", ast_tvdiff_ms(ast_tvnow(), start));
2547         return CLI_SUCCESS;
2548 }
2549
2550 static char *dundi_do_query(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2551 {
2552         int res;
2553         char tmp[256];
2554         char *context;
2555         dundi_eid eid;
2556         struct dundi_entity_info dei;
2557         switch (cmd) {
2558         case CLI_INIT:
2559                 e->command = "dundi query";
2560                 e->usage =
2561                         "Usage: dundi query <entity>[@context]\n"
2562                         "       Attempts to retrieve contact information for a specific\n"
2563                         "DUNDi entity identifier (EID) within a given DUNDi context (or\n"
2564                         "e164 if none is specified).\n";
2565                 return NULL;
2566         case CLI_GENERATE:
2567                 return NULL;
2568         }
2569         if ((a->argc < 3) || (a->argc > 3)) {
2570                 return CLI_SHOWUSAGE;
2571         }
2572         if (ast_str_to_eid(&eid, a->argv[2])) {
2573                 ast_cli(a->fd, "'%s' is not a valid EID!\n", a->argv[2]);
2574                 return CLI_SHOWUSAGE;
2575         }
2576         ast_copy_string(tmp, a->argv[2], sizeof(tmp));
2577         context = strchr(tmp, '@');
2578         if (context) {
2579                 *context = '\0';
2580                 context++;
2581         }
2582         res = dundi_query_eid(&dei, context, eid);
2583         if (res < 0)
2584                 ast_cli(a->fd, "DUNDi Query EID returned error.\n");
2585         else if (!res)
2586                 ast_cli(a->fd, "DUNDi Query EID returned no results.\n");
2587         else {
2588                 ast_cli(a->fd, "DUNDi Query EID succeeded:\n");
2589                 ast_cli(a->fd, "Department:      %s\n", dei.orgunit);
2590                 ast_cli(a->fd, "Organization:    %s\n", dei.org);
2591                 ast_cli(a->fd, "City/Locality:   %s\n", dei.locality);
2592                 ast_cli(a->fd, "State/Province:  %s\n", dei.stateprov);
2593                 ast_cli(a->fd, "Country:         %s\n", dei.country);
2594                 ast_cli(a->fd, "E-mail:          %s\n", dei.email);
2595                 ast_cli(a->fd, "Phone:           %s\n", dei.phone);
2596                 ast_cli(a->fd, "IP Address:      %s\n", dei.ipaddr);
2597         }
2598         return CLI_SUCCESS;
2599 }
2600
2601 static char *dundi_sockaddr_stringify_host(const struct ast_sockaddr *addr)
2602 {
2603         if (ast_sockaddr_isnull(addr)) {
2604                 return "(Unspecified)";
2605         }
2606         return ast_sockaddr_stringify_host(addr);
2607 }
2608
2609 static uint16_t dundi_sockaddr_port(const struct ast_sockaddr *addr)
2610 {
2611         /*
2612          * Test to avoid a debug message complaining about addr
2613          * not being an IPv4 or IPv6 address.
2614          */
2615         if (ast_sockaddr_isnull(addr)) {
2616                 return 0;
2617         }
2618         return ast_sockaddr_port(addr);
2619 }
2620
2621 static char *dundi_show_peer(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2622 {
2623         struct dundi_peer *peer;
2624         struct permission *p;
2625         char *order;
2626         char eid_str[20];
2627         int x, cnt;
2628         switch (cmd) {
2629         case CLI_INIT:
2630                 e->command = "dundi show peer";
2631                 e->usage =
2632                         "Usage: dundi show peer [peer]\n"
2633                         "       Provide a detailed description of a specifid DUNDi peer.\n";
2634                 return NULL;
2635         case CLI_GENERATE:
2636                 return complete_peer_helper(a->line, a->word, a->pos, a->n, 3);
2637         }
2638         if (a->argc != 4) {
2639                 return CLI_SHOWUSAGE;
2640         }
2641         AST_LIST_LOCK(&peers);
2642         AST_LIST_TRAVERSE(&peers, peer, list) {
2643                 if (!strcasecmp(ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid), a->argv[3]))
2644                         break;
2645         }
2646         if (peer) {
2647                 switch(peer->order) {
2648                 case 0:
2649                         order = "Primary";
2650                         break;
2651                 case 1:
2652                         order = "Secondary";
2653                         break;
2654                 case 2:
2655                         order = "Tertiary";
2656                         break;
2657                 case 3:
2658                         order = "Quartiary";
2659                         break;
2660                 default:
2661                         order = "Unknown";
2662                 }
2663                 ast_cli(a->fd, "Peer:    %s\n", ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
2664                 ast_cli(a->fd, "Model:   %s\n", model2str(peer->model));
2665                 ast_cli(a->fd, "Order:   %s\n", order);
2666                 ast_cli(a->fd, "Host:    %s\n", ast_sockaddr_isnull(&peer->addr) ? "<Unspecified>" : ast_sockaddr_stringify_host(&peer->addr));
2667                 ast_cli(a->fd, "Port:    %d\n", dundi_sockaddr_port(&peer->addr));
2668                 ast_cli(a->fd, "Dynamic: %s\n", peer->dynamic ? "yes" : "no");
2669                 ast_cli(a->fd, "Reg:     %s\n", peer->registerid < 0 ? "No" : "Yes");
2670                 ast_cli(a->fd, "In Key:  %s\n", ast_strlen_zero(peer->inkey) ? "<None>" : peer->inkey);
2671                 ast_cli(a->fd, "Out Key: %s\n", ast_strlen_zero(peer->outkey) ? "<None>" : peer->outkey);
2672                 if (!AST_LIST_EMPTY(&peer->include))
2673                         ast_cli(a->fd, "Include logic%s:\n", peer->model & DUNDI_MODEL_OUTBOUND ? "" : " (IGNORED)");
2674                 AST_LIST_TRAVERSE(&peer->include, p, list)
2675                         ast_cli(a->fd, "-- %s %s\n", p->allow ? "include" : "do not include", p->name);
2676                 if (!AST_LIST_EMPTY(&peer->permit))
2677                         ast_cli(a->fd, "Query logic%s:\n", peer->model & DUNDI_MODEL_INBOUND ? "" : " (IGNORED)");
2678                 AST_LIST_TRAVERSE(&peer->permit, p, list)
2679                         ast_cli(a->fd, "-- %s %s\n", p->allow ? "permit" : "deny", p->name);
2680                 cnt = 0;
2681                 for (x = 0;x < DUNDI_TIMING_HISTORY; x++) {
2682                         if (peer->lookups[x]) {
2683                                 if (!cnt)
2684                                         ast_cli(a->fd, "Last few query times:\n");
2685                                 ast_cli(a->fd, "-- %d. %s (%d ms)\n", x + 1, peer->lookups[x], peer->lookuptimes[x]);
2686                                 cnt++;
2687                         }
2688                 }
2689                 if (cnt)
2690                         ast_cli(a->fd, "Average query time: %d ms\n", peer->avgms);
2691         } else
2692                 ast_cli(a->fd, "No such peer '%s'\n", a->argv[3]);
2693         AST_LIST_UNLOCK(&peers);
2694         return CLI_SUCCESS;
2695 }
2696
2697 static char *dundi_show_peers(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2698 {
2699 #define FORMAT2 "%-20.20s %-41s     %-6.6s %-10.10s %-8.8s %-15.15s\n"
2700 #define FORMAT "%-20.20s %-41s %s %-6d %-10.10s %-8.8s %-15.15s\n"
2701         struct dundi_peer *peer;
2702         int registeredonly=0;
2703         char avgms[20];
2704         char eid_str[20];
2705         int online_peers = 0;
2706         int offline_peers = 0;
2707         int unmonitored_peers = 0;
2708         int total_peers = 0;
2709         switch (cmd) {
2710         case CLI_INIT:
2711                 e->command = "dundi show peers [registered|include|exclude|begin]";
2712                 e->usage =
2713                         "Usage: dundi show peers [registered|include|exclude|begin]\n"
2714                         "       Lists all known DUNDi peers.\n"
2715                         "       If 'registered' is present, only registered peers are shown.\n";
2716                 return NULL;
2717         case CLI_GENERATE:
2718                 return NULL;
2719         }
2720
2721         if ((a->argc != 3) && (a->argc != 4) && (a->argc != 5)) {
2722                 return CLI_SHOWUSAGE;
2723         }
2724         if ((a->argc == 4)) {
2725                 if (!strcasecmp(a->argv[3], "registered")) {
2726                         registeredonly = 1;
2727                 } else {
2728                         return CLI_SHOWUSAGE;
2729                 }
2730         }
2731         AST_LIST_LOCK(&peers);
2732         ast_cli(a->fd, FORMAT2, "EID", "Host", "Port", "Model", "AvgTime", "Status");
2733         AST_LIST_TRAVERSE(&peers, peer, list) {
2734                 char status[64];
2735                 int print_line = -1;
2736                 char srch[2000];
2737
2738                 total_peers++;
2739                 if (registeredonly && ast_sockaddr_isnull(&peer->addr)) {
2740                         continue;
2741                 }
2742                 if (peer->maxms) {
2743                         if (peer->lastms < 0) {
2744                                 strcpy(status, "UNREACHABLE");
2745                                 offline_peers++;
2746                         }
2747                         else if (peer->lastms > peer->maxms) {
2748                                 snprintf(status, sizeof(status), "LAGGED (%d ms)", peer->lastms);
2749                                 offline_peers++;
2750                         }
2751                         else if (peer->lastms) {
2752                                 snprintf(status, sizeof(status), "OK (%d ms)", peer->lastms);
2753                                 online_peers++;
2754                         }
2755                         else {
2756                                 strcpy(status, "UNKNOWN");
2757                                 offline_peers++;
2758                         }
2759                 } else {
2760                         strcpy(status, "Unmonitored");
2761                         unmonitored_peers++;
2762                 }
2763                 if (peer->avgms)
2764                         snprintf(avgms, sizeof(avgms), "%d ms", peer->avgms);
2765                 else
2766                         strcpy(avgms, "Unavail");
2767                 snprintf(srch, sizeof(srch), FORMAT, ast_eid_to_str(eid_str, sizeof(eid_str),
2768                         &peer->eid), dundi_sockaddr_stringify_host(&peer->addr),
2769                         peer->dynamic ? "(D)" : "(S)", dundi_sockaddr_port(&peer->addr), model2str(peer->model), avgms, status);
2770
2771                 if (a->argc == 5) {
2772                   if (!strcasecmp(a->argv[3],"include") && strstr(srch,a->argv[4])) {
2773                         print_line = -1;
2774                    } else if (!strcasecmp(a->argv[3],"exclude") && !strstr(srch,a->argv[4])) {
2775                         print_line = 1;
2776                    } else if (!strcasecmp(a->argv[3],"begin") && !strncasecmp(srch,a->argv[4],strlen(a->argv[4]))) {
2777                         print_line = -1;
2778                    } else {
2779                         print_line = 0;
2780                   }
2781                 }
2782
2783         if (print_line) {
2784                         ast_cli(a->fd, FORMAT, ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid),
2785                                 dundi_sockaddr_stringify_host(&peer->addr),
2786                                 peer->dynamic ? "(D)" : "(S)", dundi_sockaddr_port(&peer->addr), model2str(peer->model), avgms, status);
2787                 }
2788         }
2789         ast_cli(a->fd, "%d dundi peers [%d online, %d offline, %d unmonitored]\n", total_peers, online_peers, offline_peers, unmonitored_peers);
2790         AST_LIST_UNLOCK(&peers);
2791         return CLI_SUCCESS;
2792 #undef FORMAT
2793 #undef FORMAT2
2794 }
2795
2796 static char *dundi_show_trans(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2797 {
2798 #define FORMAT2 "%-47s %-5.5s %-5.5s %-3.3s %-3.3s %-3.3s\n"
2799 #define FORMAT "%-41s:%5d %-5.5d %-5.5d %-3.3d %-3.3d %-3.3d\n"
2800         struct dundi_transaction *trans;
2801         switch (cmd) {
2802         case CLI_INIT:
2803                 e->command = "dundi show trans";
2804                 e->usage =
2805                         "Usage: dundi show trans\n"
2806                         "       Lists all known DUNDi transactions.\n";
2807                 return NULL;
2808         case CLI_GENERATE:
2809                 return NULL;
2810         }
2811         if (a->argc != 3) {
2812                 return CLI_SHOWUSAGE;
2813         }
2814         AST_LIST_LOCK(&peers);
2815         ast_cli(a->fd, FORMAT2, "Remote", "Src", "Dst", "Tx", "Rx", "Ack");
2816         AST_LIST_TRAVERSE(&alltrans, trans, all) {
2817                 ast_cli(a->fd, FORMAT, ast_sockaddr_stringify_host(&trans->addr),
2818                         ast_sockaddr_port(&trans->addr), trans->strans, trans->dtrans,
2819                         trans->oseqno, trans->iseqno, trans->aseqno);
2820         }
2821         AST_LIST_UNLOCK(&peers);
2822         return CLI_SUCCESS;
2823 #undef FORMAT
2824 #undef FORMAT2
2825 }
2826
2827 static char *dundi_show_entityid(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2828 {
2829         char eid_str[20];
2830         switch (cmd) {
2831         case CLI_INIT:
2832                 e->command = "dundi show entityid";
2833                 e->usage =
2834                         "Usage: dundi show entityid\n"
2835                         "       Displays the global entityid for this host.\n";
2836                 return NULL;
2837         case CLI_GENERATE:
2838                 return NULL;
2839         }
2840         if (a->argc != 3) {
2841                 return CLI_SHOWUSAGE;
2842         }
2843         AST_LIST_LOCK(&peers);
2844         ast_eid_to_str(eid_str, sizeof(eid_str), &global_eid);
2845         AST_LIST_UNLOCK(&peers);
2846         ast_cli(a->fd, "Global EID for this system is '%s'\n", eid_str);
2847         return CLI_SUCCESS;
2848 }
2849
2850 static char *dundi_show_requests(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2851 {
2852 #define FORMAT2 "%-15s %-15s %-15s %-3.3s %-3.3s\n"
2853 #define FORMAT "%-15s %-15s %-15s %-3.3d %-3.3d\n"
2854         struct dundi_request *req;
2855         char eidstr[20];
2856         switch (cmd) {
2857         case CLI_INIT:
2858                 e->command = "dundi show requests";
2859                 e->usage =
2860                         "Usage: dundi show requests\n"
2861                         "       Lists all known pending DUNDi requests.\n";
2862                 return NULL;
2863         case CLI_GENERATE:
2864                 return NULL;
2865         }
2866         if (a->argc != 3) {
2867                 return CLI_SHOWUSAGE;
2868         }
2869         AST_LIST_LOCK(&peers);
2870         ast_cli(a->fd, FORMAT2, "Number", "Context", "Root", "Max", "Rsp");
2871         AST_LIST_TRAVERSE(&requests, req, list) {
2872                 ast_cli(a->fd, FORMAT, req->number, req->dcontext,
2873                         dundi_eid_zero(&req->root_eid) ? "<unspecified>" : ast_eid_to_str(eidstr, sizeof(eidstr), &req->root_eid), req->maxcount, req->respcount);
2874         }
2875         AST_LIST_UNLOCK(&peers);
2876         return CLI_SUCCESS;
2877 #undef FORMAT
2878 #undef FORMAT2
2879 }
2880
2881 /* Grok-a-dial DUNDi */
2882
2883 static char *dundi_show_mappings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2884 {
2885 #define FORMAT2 "%-12.12s %-7.7s %-12.12s %-10.10s %-5.5s %-25.25s\n"
2886 #define FORMAT "%-12.12s %-7s %-12.12s %-10.10s %-5.5s %-25.25s\n"
2887         struct dundi_mapping *map;
2888         char fs[256];
2889         char weight[8];
2890         switch (cmd) {
2891         case CLI_INIT:
2892                 e->command = "dundi show mappings";
2893                 e->usage =
2894                         "Usage: dundi show mappings\n"
2895                         "       Lists all known DUNDi mappings.\n";
2896                 return NULL;
2897         case CLI_GENERATE:
2898                 return NULL;
2899         }
2900         if (a->argc != 3) {
2901                 return CLI_SHOWUSAGE;
2902         }
2903         AST_LIST_LOCK(&peers);
2904         ast_cli(a->fd, FORMAT2, "DUNDi Cntxt", "Weight", "Local Cntxt", "Options", "Tech", "Destination");
2905         AST_LIST_TRAVERSE(&mappings, map, list) {
2906                 snprintf(weight, sizeof(weight), "%d", get_mapping_weight(map, NULL));
2907                 ast_cli(a->fd, FORMAT, map->dcontext, weight,
2908                         ast_strlen_zero(map->lcontext) ? "<none>" : map->lcontext,
2909                         dundi_flags2str(fs, sizeof(fs), map->options), tech2str(map->tech), map->dest);
2910         }
2911         AST_LIST_UNLOCK(&peers);
2912         return CLI_SUCCESS;
2913 #undef FORMAT
2914 #undef FORMAT2
2915 }
2916
2917 static char *dundi_show_precache(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2918 {
2919 #define FORMAT2 "%-12.12s %-12.12s %-10.10s\n"
2920 #define FORMAT "%-12.12s %-12.12s %02d:%02d:%02d\n"
2921         struct dundi_precache_queue *qe;
2922         int h,m,s;
2923         time_t now;
2924         switch (cmd) {
2925         case CLI_INIT:
2926                 e->command = "dundi show precache";
2927                 e->usage =
2928                         "Usage: dundi show precache\n"
2929                         "       Lists all known DUNDi scheduled precache updates.\n";
2930                 return NULL;
2931         case CLI_GENERATE:
2932                 return NULL;
2933         }
2934         if (a->argc != 3) {
2935                 return CLI_SHOWUSAGE;
2936         }
2937         time(&now);
2938         ast_cli(a->fd, FORMAT2, "Number", "Context", "Expiration");
2939         AST_LIST_LOCK(&pcq);
2940         AST_LIST_TRAVERSE(&pcq, qe, list) {
2941                 s = qe->expiration - now;
2942                 h = s / 3600;
2943                 s = s % 3600;
2944                 m = s / 60;
2945                 s = s % 60;
2946                 ast_cli(a->fd, FORMAT, qe->number, qe->context, h,m,s);
2947         }
2948         AST_LIST_UNLOCK(&pcq);
2949
2950         return CLI_SUCCESS;
2951 #undef FORMAT
2952 #undef FORMAT2
2953 }
2954
2955 static char *dundi_show_cache(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2956 {
2957 #define FORMAT2 "%-12.12s %-16.16s %-10.10s  %-18s %-7s %s\n"
2958 #define FORMAT "%-12.12s %-16.16s %6d sec  %-18s %-7d %s/%s (%s)\n"
2959         struct ast_db_entry *db_tree, *db_entry;
2960         int cnt = 0;
2961         time_t ts, now;
2962         dundi_eid src_eid;
2963         char src_eid_str[20];
2964         int expiry, tech, weight;
2965         struct ast_flags flags;
2966         char fs[256];
2967         int length;
2968         char *ptr, *term, *src, *number, *context, *dst;
2969
2970         switch (cmd) {
2971         case CLI_INIT:
2972                 e->command = "dundi show cache";
2973                 e->usage =
2974                 "Usage: dundi show cache\n"
2975                 "       Lists all DUNDi cache entries.\n";
2976                 return NULL;
2977         case CLI_GENERATE:
2978                 return NULL;
2979         }
2980
2981         if (a->argc != 3) {
2982                 return CLI_SHOWUSAGE;
2983         }
2984
2985         time(&now);
2986         db_tree = ast_db_gettree("dundi/cache", NULL);
2987         ast_cli(a->fd, FORMAT2, "Number", "Context", "Expiration", "From", "Weight", "Destination (Flags)");
2988         for (db_entry = db_tree; db_entry; db_entry = db_entry->next) {
2989                 char *rest;
2990
2991                 if ((strncmp(db_entry->key, "/dundi/cache/hint/", 18) == 0) || ast_get_time_t(db_entry->data, &ts, 0, &length)) {
2992                         continue;
2993                 }
2994
2995                 expiry = ts - now;
2996
2997                 if (expiry <= 0) {
2998                         continue;
2999                 }
3000
3001                 ptr = db_entry->key + sizeof("/dundi/cache");
3002                 strtok_r(ptr, "/", &rest);
3003                 number = strtok_r(NULL, "/", &rest);
3004                 context = strtok_r(NULL, "/", &rest);
3005                 ptr = strtok_r(NULL, "/", &rest);
3006
3007                 if (*ptr != 'e') {
3008                         continue;
3009                 }
3010
3011                 ptr = db_entry->data + length + 1;
3012
3013                 if ((sscanf(ptr, "%30u/%30d/%30d/%n", &(flags.flags), &weight, &tech, &length) != 3)) {
3014                         continue;
3015                 }
3016
3017                 ptr += length;
3018                 dst = ptr;
3019                 term = strchr(ptr, '|');
3020
3021                 if (!term) {
3022                         continue;
3023                 }
3024
3025                 /* Ok, at this point we know we aren't going to skp the entry, so we go ahead and increment the count. */
3026                 cnt++;
3027
3028                 *term = '\0';
3029                 src = strrchr(ptr, '/');
3030                 dundi_eid_zero(&src_eid);
3031
3032                 if (src) {
3033                         *src = '\0';
3034                         src++;
3035                         dundi_str_short_to_eid(&src_eid, src);
3036                         ast_eid_to_str(src_eid_str, sizeof(src_eid_str), &src_eid);
3037                 }
3038
3039                 ast_cli(a->fd, FORMAT, number, context, expiry, src_eid_str, weight, tech2str(tech), dst, dundi_flags2str(fs, sizeof(fs), flags.flags));
3040         }
3041
3042         ast_cli(a->fd, "Number of entries: %d\n", cnt);
3043         ast_db_freetree(db_tree);
3044
3045         return CLI_SUCCESS;
3046 #undef FORMAT
3047 #undef FORMAT2
3048 }
3049
3050 static char *dundi_show_hints(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
3051 {
3052 #define FORMAT2 "%-12.12s %-16.16s %-10.10s  %-18s\n"
3053 #define FORMAT "%-12.12s %-16.16s %6d sec  %-18s\n"
3054         struct ast_db_entry *db_tree, *db_entry;
3055         int cnt = 0;
3056         time_t ts, now;
3057         dundi_eid src_eid;
3058         char src_eid_str[20];
3059         int expiry;
3060         int length;
3061         char *ptr, *src, *number, *context;
3062
3063         switch (cmd) {
3064         case CLI_INIT:
3065                 e->command = "dundi show hints";
3066                 e->usage =
3067                         "Usage: dundi show hints\n"
3068                         "       Lists all DUNDi 'DONTASK' hints in the cache.\n";
3069                 return NULL;
3070         case CLI_GENERATE:
3071                 return NULL;
3072         }
3073
3074         if (a->argc != 3) {
3075                 return CLI_SHOWUSAGE;
3076         }
3077
3078         time(&now);
3079         db_tree = ast_db_gettree("dundi/cache/hint", NULL);
3080         ast_cli(a->fd, FORMAT2, "Prefix", "Context", "Expiration", "From");
3081
3082         for (db_entry = db_tree; db_entry; db_entry = db_entry->next) {
3083                 char *rest = NULL;
3084
3085                 if (ast_get_time_t(db_entry->data, &ts, 0, &length)) {
3086                         continue;
3087                 }
3088
3089                 expiry = ts - now;
3090
3091                 if (expiry <= 0) {
3092                         continue;
3093                 }
3094
3095                 ptr = db_entry->key + sizeof("/dundi/cache/hint");
3096                 src = strtok_r(ptr, "/", &rest);
3097                 number = strtok_r(NULL, "/", &rest);
3098                 context = strtok_r(NULL, "/", &rest);
3099                 ptr = strtok_r(NULL, "/", &rest);
3100
3101                 if (*ptr != 'e') {
3102                         continue;
3103                 }
3104
3105                 cnt++;
3106                 dundi_str_short_to_eid(&src_eid, src);
3107                 ast_eid_to_str(src_eid_str, sizeof(src_eid_str), &src_eid);
3108                 ast_cli(a->fd, FORMAT, number, context, expiry, src_eid_str);
3109         }
3110
3111         ast_cli(a->fd, "Number of entries: %d\n", cnt);
3112         ast_db_freetree(db_tree);
3113
3114         return CLI_SUCCESS;
3115 #undef FORMAT
3116 #undef FORMAT2
3117 }
3118
3119 static struct ast_cli_entry cli_dundi[] = {
3120         AST_CLI_DEFINE(dundi_set_debug, "Enable/Disable DUNDi debugging"),
3121         AST_CLI_DEFINE(dundi_store_history, "Enable/Disable DUNDi historic records"),
3122         AST_CLI_DEFINE(dundi_flush, "Flush DUNDi cache"),
3123         AST_CLI_DEFINE(dundi_show_peers, "Show defined DUNDi peers"),
3124         AST_CLI_DEFINE(dundi_show_trans, "Show active DUNDi transactions"),
3125         AST_CLI_DEFINE(dundi_show_entityid, "Display Global Entity ID"),
3126         AST_CLI_DEFINE(dundi_show_mappings, "Show DUNDi mappings"),
3127         AST_CLI_DEFINE(dundi_show_precache, "Show DUNDi precache"),
3128         AST_CLI_DEFINE(dundi_show_requests, "Show DUNDi requests"),
3129         AST_CLI_DEFINE(dundi_show_peer, "Show info on a specific DUNDi peer"),
3130         AST_CLI_DEFINE(dundi_show_cache, "Show DUNDi cache"),
3131         AST_CLI_DEFINE(dundi_show_hints, "Show DUNDi hints in the cache"),
3132         AST_CLI_DEFINE(dundi_do_precache, "Precache a number in DUNDi"),
3133         AST_CLI_DEFINE(dundi_do_lookup, "Lookup a number in DUNDi"),
3134         AST_CLI_DEFINE(dundi_do_query, "Query a DUNDi EID"),
3135 };
3136
3137 static struct dundi_transaction *create_transaction(struct dundi_peer *p)
3138 {
3139         struct dundi_transaction *trans;
3140         int tid;
3141
3142         /* Don't allow creation of transactions to non-registered peers */
3143         if (p && ast_sockaddr_isnull(&p->addr)) {
3144                 return NULL;
3145         }
3146         tid = get_trans_id();
3147         if (tid < 1)
3148                 return NULL;
3149         if (!(trans = ast_calloc(1, sizeof(*trans))))
3150                 return NULL;
3151
3152         if (global_storehistory) {
3153                 trans->start = ast_tvnow();
3154                 ast_set_flag(trans, FLAG_STOREHIST);
3155         }
3156         trans->retranstimer = DUNDI_DEFAULT_RETRANS_TIMER;
3157         trans->autokillid = -1;
3158         if (p) {
3159                 apply_peer(trans, p);
3160                 if (!p->sentfullkey)
3161                         ast_set_flag(trans, FLAG_SENDFULLKEY);
3162         }
3163         trans->strans = tid;
3164         AST_LIST_INSERT_HEAD(&alltrans, trans, all);
3165
3166         return trans;
3167 }
3168
3169 static int dundi_xmit(struct dundi_packet *pack)
3170 {
3171         int res;
3172         if (dundidebug)
3173                 dundi_showframe(pack->h, 0, &pack->parent->addr, pack->datalen - sizeof(struct dundi_hdr));
3174
3175         if (netsocket2 < 0) {
3176                 res = ast_sendto(netsocket, pack->data, pack->datalen, 0, &pack->parent->addr);
3177         } else {
3178                 if (ast_sockaddr_is_ipv4(&pack->parent->addr)) {
3179                         res = ast_sendto(netsocket, pack->data, pack->datalen, 0, &pack->parent->addr);
3180                 } else {
3181                         res = ast_sendto(netsocket2, pack->data, pack->datalen, 0, &pack->parent->addr);
3182                 }
3183         }
3184
3185         if (res < 0) {
3186                 ast_log(LOG_WARNING, "Failed to transmit to '%s': %s\n",
3187                         ast_sockaddr_stringify(&pack->parent->addr), strerror(errno));
3188         }
3189         if (res > 0)
3190                 res = 0;
3191         return res;
3192 }
3193
3194 static void destroy_packet(struct dundi_packet *pack, int needfree)
3195 {
3196         if (pack->parent)
3197                 AST_LIST_REMOVE(&pack->parent->packets, pack, list);
3198         AST_SCHED_DEL(sched, pack->retransid);
3199         if (needfree)
3200                 ast_free(pack);
3201 }
3202
3203 static void destroy_trans(struct dundi_transaction *trans, int fromtimeout)
3204 {
3205         struct dundi_peer *peer;
3206         int ms;
3207         int x;
3208         int cnt;
3209         char eid_str[20];
3210         if (ast_test_flag(trans, FLAG_ISREG | FLAG_ISQUAL | FLAG_STOREHIST)) {
3211                 AST_LIST_TRAVERSE(&peers, peer, list) {
3212                         if (peer->regtrans == trans)
3213                                 peer->regtrans = NULL;
3214                         if (peer->qualtrans == trans) {
3215                                 if (fromtimeout) {
3216                                         if (peer->lastms > -1)
3217                                                 ast_log(LOG_NOTICE, "Peer '%s' has become UNREACHABLE!\n", ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
3218                                         peer->lastms = -1;
3219                                 } else {
3220                                         ms = ast_tvdiff_ms(ast_tvnow(), peer->qualtx);
3221                                         if (ms < 1)
3222                                                 ms = 1;
3223                                         if (ms < peer->maxms) {
3224                                                 if ((peer->lastms >= peer->maxms) || (peer->lastms < 0))
3225                                                         ast_log(LOG_NOTICE, "Peer '%s' has become REACHABLE!\n", ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
3226                                         } else if (peer->lastms < peer->maxms) {
3227                                                 ast_log(LOG_NOTICE, "Peer '%s' has become TOO LAGGED (%d ms)\n", ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid), ms);
3228                                         }
3229                                         peer->lastms = ms;
3230                                 }
3231                                 peer->qualtrans = NULL;
3232                         }
3233                         if (ast_test_flag(trans, FLAG_STOREHIST)) {
3234                                 if (trans->parent && !ast_strlen_zero(trans->parent->number)) {
3235                                         if (!ast_eid_cmp(&trans->them_eid, &peer->eid)) {
3236                                                 peer->avgms = 0;
3237                                                 cnt = 0;
3238                                                 ast_free(peer->lookups[DUNDI_TIMING_HISTORY - 1]);
3239                                                 for (x=DUNDI_TIMING_HISTORY-1;x>0;x--) {
3240                                                         peer->lookuptimes[x] = peer->lookuptimes[x-1];
3241                                                         peer->lookups[x] = peer->lookups[x-1];
3242                                                         if (peer->lookups[x]) {
3243                                                                 peer->avgms += peer->lookuptimes[x];
3244                                                                 cnt++;
3245                                                         }
3246                                                 }
3247                                                 peer->lookuptimes[0] = ast_tvdiff_ms(ast_tvnow(), trans->start);
3248                                                 peer->lookups[0] = ast_malloc(strlen(trans->parent->number) + strlen(trans->parent->dcontext) + 2);
3249                                                 if (peer->lookups[0]) {
3250                                                         sprintf(peer->lookups[0], "%s@%s", trans->parent->number, trans->parent->dcontext);
3251                                                         peer->avgms += peer->lookuptimes[0];
3252                                                         cnt++;
3253                                                 }
3254                                                 if (cnt)
3255                                                         peer->avgms /= cnt;
3256                                         }
3257                                 }
3258                         }
3259                 }
3260         }
3261         if (trans->parent) {
3262                 /* Unlink from parent if appropriate */
3263                 AST_LIST_REMOVE(&trans->parent->trans, trans, parentlist);
3264                 if (AST_LIST_EMPTY(&trans->parent->trans)) {
3265                         /* Wake up sleeper */
3266                         if (trans->parent->pfds[1] > -1) {
3267                                 if (write(trans->parent->pfds[1], "killa!", 6) < 0) {
3268                                         ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
3269                                 }
3270                         }
3271                 }
3272         }
3273         /* Unlink from all trans */
3274         AST_LIST_REMOVE(&alltrans, trans, all);
3275         destroy_packets(&trans->packets);
3276         destroy_packets(&trans->lasttrans);
3277         AST_SCHED_DEL(sched, trans->autokillid);
3278         if (trans->thread) {
3279                 /* If used by a thread, mark as dead and be done */
3280                 ast_set_flag(trans, FLAG_DEAD);
3281         } else
3282                 ast_free(trans);
3283 }
3284
3285 static int dundi_rexmit(const void *data)
3286 {
3287         struct dundi_packet *pack = (struct dundi_packet *)data;
3288         int res;
3289         AST_LIST_LOCK(&peers);
3290         if (pack->retrans < 1) {
3291                 pack->ret