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