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