Add transfer ID for potential use in more complex NAT environments
[asterisk/asterisk.git] / channels / iax2-parser.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Implementation of Inter-Asterisk eXchange
5  * 
6  * Copyright (C) 2003, Digium
7  *
8  * Mark Spencer <markster@linux-support.net>
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU General Public License
12  */
13
14 #include <sys/socket.h>
15 #include <string.h>
16 #include <netinet/in.h>
17 #include <asterisk/frame.h>
18 #include <arpa/inet.h>
19 #include <unistd.h>
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include "iax2.h"
23 #include "iax2-parser.h"
24
25
26 static void internaloutput(const char *str)
27 {
28         printf(str);
29 }
30
31 static void internalerror(const char *str)
32 {
33         fprintf(stderr, "WARNING: %s", str);
34 }
35
36 static void (*outputf)(const char *str) = internaloutput;
37 static void (*errorf)(const char *str) = internalerror;
38
39 static void dump_addr(char *output, int maxlen, void *value, int len)
40 {
41         struct sockaddr_in sin;
42         if (len == sizeof(sin)) {
43                 memcpy(&sin, value, len);
44                 snprintf(output, maxlen, "IPV4 %s:%d", inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
45         } else {
46                 snprintf(output, maxlen, "Invalid Address");
47         }
48 }
49
50 static void dump_string(char *output, int maxlen, void *value, int len)
51 {
52         maxlen--;
53         if (maxlen > len)
54                 maxlen = len;
55         strncpy(output,value, maxlen);
56         output[maxlen] = '\0';
57 }
58
59 static void dump_int(char *output, int maxlen, void *value, int len)
60 {
61         if (len == sizeof(unsigned int))
62                 snprintf(output, maxlen, "%d", ntohl(*((unsigned int *)value)));
63         else
64                 snprintf(output, maxlen, "Invalid INT");
65 }
66
67 static void dump_short(char *output, int maxlen, void *value, int len)
68 {
69         if (len == sizeof(unsigned short))
70                 snprintf(output, maxlen, "%d", ntohs(*((unsigned short *)value)));
71         else
72                 snprintf(output, maxlen, "Invalid SHORT");
73 }
74
75 static void dump_byte(char *output, int maxlen, void *value, int len)
76 {
77         if (len == sizeof(unsigned char))
78                 snprintf(output, maxlen, "%d", ntohs(*((unsigned char *)value)));
79         else
80                 snprintf(output, maxlen, "Invalid BYTE");
81 }
82
83 static struct iax2_ie {
84         int ie;
85         char *name;
86         void (*dump)(char *output, int maxlen, void *value, int len);
87 } ies[] = {
88         { IAX_IE_CALLED_NUMBER, "CALLED NUMBER", dump_string },
89         { IAX_IE_CALLING_NUMBER, "CALLING NUMBER", dump_string },
90         { IAX_IE_CALLING_NUMBER, "ANI", dump_string },
91         { IAX_IE_CALLING_NAME, "CALLING NAME", dump_string },
92         { IAX_IE_CALLED_CONTEXT, "CALLED CONTEXT", dump_string },
93         { IAX_IE_USERNAME, "USERNAME", dump_string },
94         { IAX_IE_PASSWORD, "PASSWORD", dump_string },
95         { IAX_IE_CAPABILITY, "CAPABILITY", dump_int },
96         { IAX_IE_FORMAT, "FORMAT", dump_int },
97         { IAX_IE_LANGUAGE, "LANGUAGE", dump_string },
98         { IAX_IE_VERSION, "VERSION", dump_short },
99         { IAX_IE_ADSICPE, "ADSICPE", dump_short },
100         { IAX_IE_DNID, "DNID", dump_string },
101         { IAX_IE_AUTHMETHODS, "AUTHMETHODS", dump_short },
102         { IAX_IE_CHALLENGE, "CHALLENGE", dump_string },
103         { IAX_IE_MD5_RESULT, "MD5 RESULT", dump_string },
104         { IAX_IE_RSA_RESULT, "RSA RESULT", dump_string },
105         { IAX_IE_APPARENT_ADDR, "APPARENT ADDRESS", dump_addr },
106         { IAX_IE_REFRESH, "REFRESH", dump_short },
107         { IAX_IE_DPSTATUS, "DIALPLAN STATUS", dump_short },
108         { IAX_IE_CALLNO, "CALL NUMBER", dump_short },
109         { IAX_IE_CAUSE, "CAUSE", dump_string },
110         { IAX_IE_IAX_UNKNOWN, "UNKNOWN IAX CMD", dump_byte },
111         { IAX_IE_MSGCOUNT, "MESSAGE COUNT", dump_short },
112         { IAX_IE_AUTOANSWER, "AUTO ANSWER REQ" },
113         { IAX_IE_TRANSFERID, "TRANSFER ID", dump_int },
114 };
115
116 const char *iax_ie2str(int ie)
117 {
118         int x;
119         for (x=0;x<sizeof(ies) / sizeof(ies[0]); x++) {
120                 if (ies[x].ie == ie)
121                         return ies[x].name;
122         }
123         return "Unknown IE";
124 }
125
126 static void dump_ies(unsigned char *iedata, int len)
127 {
128         int ielen;
129         int ie;
130         int x;
131         int found;
132         char interp[80];
133         char tmp[256];
134         if (len < 2)
135                 return;
136         while(len > 2) {
137                 ie = iedata[0];
138                 ielen = iedata[1];
139                 if (ielen + 2> len) {
140                         snprintf(tmp, sizeof(tmp), "Total IE length of %d bytes exceeds remaining frame length of %d bytes\n", ielen + 2, len);
141                         outputf(tmp);
142                         return;
143                 }
144                 found = 0;
145                 for (x=0;x<sizeof(ies) / sizeof(ies[0]); x++) {
146                         if (ies[x].ie == ie) {
147                                 if (ies[x].dump) {
148                                         ies[x].dump(interp, sizeof(interp), iedata + 2, ielen);
149                                         snprintf(tmp, sizeof(tmp), "   %-15.15s : %s\n", ies[x].name, interp);
150                                         outputf(tmp);
151                                 } else {
152                                         snprintf(tmp, sizeof(tmp), "   %-15.15s : Present\n", ies[x].name);
153                                         outputf(tmp);
154                                 }
155                                 found++;
156                         }
157                 }
158                 if (!found) {
159                         snprintf(tmp, sizeof(tmp), "   Unknown IE %03d  : Present\n", ie);
160                         outputf(tmp);
161                 }
162                 iedata += (2 + ielen);
163                 len -= (2 + ielen);
164         }
165         outputf("\n");
166 }
167
168 void iax_showframe(struct ast_iax2_frame *f, struct ast_iax2_full_hdr *fhi, int rx, struct sockaddr_in *sin, int datalen)
169 {
170         char *frames[] = {
171                 "(0?)",
172                 "DTMF   ",
173                 "VOICE  ",
174                 "VIDEO  ",
175                 "CONTROL",
176                 "NULL   ",
177                 "IAX    ",
178                 "TEXT   ",
179                 "IMAGE  " };
180         char *iaxs[] = {
181                 "(0?)",
182                 "NEW    ",
183                 "PING   ",
184                 "PONG   ",
185                 "ACK    ",
186                 "HANGUP ",
187                 "REJECT ",
188                 "ACCEPT ",
189                 "AUTHREQ",
190                 "AUTHREP",
191                 "INVAL  ",
192                 "LAGRQ  ",
193                 "LAGRP  ",
194                 "REGREQ ",
195                 "REGAUTH",
196                 "REGACK ",
197                 "REGREJ ",
198                 "REGREL ",
199                 "VNAK   ",
200                 "DPREQ  ",
201                 "DPREP  ",
202                 "DIAL   ",
203                 "TXREQ  ",
204                 "TXCNT  ",
205                 "TXACC  ",
206                 "TXREADY",
207                 "TXREL  ",
208                 "TXREJ  ",
209                 "QUELCH ",
210                 "UNQULCH",
211                 "POKE",
212                 "PAGE",
213                 "MWI",
214                 "UNSUPPORTED",
215         };
216         char *cmds[] = {
217                 "(0?)",
218                 "HANGUP ",
219                 "RING   ",
220                 "RINGING",
221                 "ANSWER ",
222                 "BUSY   ",
223                 "TKOFFHK ",
224                 "OFFHOOK" };
225         struct ast_iax2_full_hdr *fh;
226         char retries[20];
227         char class2[20];
228         char subclass2[20];
229         char *class;
230         char *subclass;
231         char tmp[256];
232         if (f) {
233                 fh = f->data;
234                 snprintf(retries, sizeof(retries), "%03d", f->retries);
235         } else {
236                 fh = fhi;
237                 if (ntohs(fh->dcallno) & IAX_FLAG_RETRANS)
238                         strcpy(retries, "Yes");
239                 else
240                         strcpy(retries, "No");
241         }
242         if (!(ntohs(fh->scallno) & IAX_FLAG_FULL)) {
243                 /* Don't mess with mini-frames */
244                 return;
245         }
246         if (fh->type > sizeof(frames)/sizeof(char *)) {
247                 snprintf(class2, sizeof(class2), "(%d?)", fh->type);
248                 class = class2;
249         } else {
250                 class = frames[(int)fh->type];
251         }
252         if (fh->type == AST_FRAME_DTMF) {
253                 sprintf(subclass2, "%c", fh->csub);
254                 subclass = subclass2;
255         } else if (fh->type == AST_FRAME_IAX) {
256                 if (fh->csub >= sizeof(iaxs)/sizeof(iaxs[0])) {
257                         snprintf(subclass2, sizeof(subclass2), "(%d?)", fh->csub);
258                         subclass = subclass2;
259                 } else {
260                         subclass = iaxs[(int)fh->csub];
261                 }
262         } else if (fh->type == AST_FRAME_CONTROL) {
263                 if (fh->csub > sizeof(cmds)/sizeof(char *)) {
264                         snprintf(subclass2, sizeof(subclass2), "(%d?)", fh->csub);
265                         subclass = subclass2;
266                 } else {
267                         subclass = cmds[(int)fh->csub];
268                 }
269         } else {
270                 snprintf(subclass2, sizeof(subclass2), "%d", fh->csub);
271                 subclass = subclass2;
272         }
273 snprintf(tmp, sizeof(tmp), 
274 "%s-Frame Retry[%s] -- OSeqno: %3.3d ISeqno: %3.3d Type: %s Subclass: %s\n",
275         (rx ? "Rx" : "Tx"),
276         retries, fh->oseqno, fh->iseqno, class, subclass);
277         outputf(tmp);
278 snprintf(tmp, sizeof(tmp), 
279 "   Timestamp: %05dms  SCall: %5.5d  DCall: %5.5d [%s:%d]\n",
280         ntohl(fh->ts),
281         ntohs(fh->scallno) & ~IAX_FLAG_FULL, ntohs(fh->dcallno) & ~IAX_FLAG_RETRANS,
282                 inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
283         outputf(tmp);
284         if (fh->type == AST_FRAME_IAX)
285                 dump_ies(fh->iedata, datalen);
286 }
287
288 int iax_ie_append_raw(struct iax_ie_data *ied, unsigned char ie, void *data, int datalen)
289 {
290         char tmp[256];
291         if (datalen > (sizeof(ied->buf) - ied->pos)) {
292                 snprintf(tmp, sizeof(tmp), "Out of space for ie '%s' (%d), need %d have %d\n", iax_ie2str(ie), ie, datalen, sizeof(ied->buf) - ied->pos);
293                 errorf(tmp);
294                 return -1;
295         }
296         ied->buf[ied->pos++] = ie;
297         ied->buf[ied->pos++] = datalen;
298         memcpy(ied->buf + ied->pos, data, datalen);
299         ied->pos += datalen;
300         return 0;
301 }
302
303 int iax_ie_append_addr(struct iax_ie_data *ied, unsigned char ie, struct sockaddr_in *sin)
304 {
305         return iax_ie_append_raw(ied, ie, sin, sizeof(struct sockaddr_in));
306 }
307
308 int iax_ie_append_int(struct iax_ie_data *ied, unsigned char ie, unsigned int value) 
309 {
310         unsigned int newval;
311         newval = htonl(value);
312         return iax_ie_append_raw(ied, ie, &newval, sizeof(newval));
313 }
314
315 int iax_ie_append_short(struct iax_ie_data *ied, unsigned char ie, unsigned short value) 
316 {
317         unsigned short newval;
318         newval = htons(value);
319         return iax_ie_append_raw(ied, ie, &newval, sizeof(newval));
320 }
321
322 int iax_ie_append_str(struct iax_ie_data *ied, unsigned char ie, unsigned char *str)
323 {
324         return iax_ie_append_raw(ied, ie, str, strlen(str));
325 }
326
327 int iax_ie_append_byte(struct iax_ie_data *ied, unsigned char ie, unsigned char dat)
328 {
329         return iax_ie_append_raw(ied, ie, &dat, 1);
330 }
331
332 int iax_ie_append(struct iax_ie_data *ied, unsigned char ie) 
333 {
334         return iax_ie_append_raw(ied, ie, NULL, 0);
335 }
336
337 void iax_set_output(void (*func)(const char *))
338 {
339         outputf = func;
340 }
341
342 void iax_set_error(void (*func)(const char *))
343 {
344         errorf = func;
345 }
346
347 int iax_parse_ies(struct iax_ies *ies, unsigned char *data, int datalen)
348 {
349         /* Parse data into information elements */
350         int len;
351         int ie;
352         char tmp[256];
353         memset(ies, 0, sizeof(struct iax_ies));
354         ies->msgcount = -1;
355         while(datalen >= 2) {
356                 ie = data[0];
357                 len = data[1];
358                 if (len > datalen - 2) {
359                         errorf("Information element length exceeds message size\n");
360                         return -1;
361                 }
362                 switch(ie) {
363                 case IAX_IE_CALLED_NUMBER:
364                         ies->called_number = data + 2;
365                         break;
366                 case IAX_IE_CALLING_NUMBER:
367                         ies->calling_number = data + 2;
368                         break;
369                 case IAX_IE_CALLING_ANI:
370                         ies->calling_ani = data + 2;
371                         break;
372                 case IAX_IE_CALLING_NAME:
373                         ies->calling_name = data + 2;
374                         break;
375                 case IAX_IE_CALLED_CONTEXT:
376                         ies->called_context = data + 2;
377                         break;
378                 case IAX_IE_USERNAME:
379                         ies->username = data + 2;
380                         break;
381                 case IAX_IE_PASSWORD:
382                         ies->password = data + 2;
383                         break;
384                 case IAX_IE_CAPABILITY:
385                         if (len != sizeof(unsigned int)) {
386                                 snprintf(tmp, sizeof(tmp), "Expecting capability to be %d bytes long but was %d\n", sizeof(unsigned int), len);
387                                 errorf(tmp);
388                         } else
389                                 ies->capability = ntohl(*((unsigned int *)(data + 2)));
390                         break;
391                 case IAX_IE_FORMAT:
392                         if (len != sizeof(unsigned int)) {
393                                 snprintf(tmp, sizeof(tmp), "Expecting format to be %d bytes long but was %d\n", sizeof(unsigned int), len);
394                                 errorf(tmp);
395                         } else
396                                 ies->format = ntohl(*((unsigned int *)(data + 2)));
397                         break;
398                 case IAX_IE_LANGUAGE:
399                         ies->language = data + 2;
400                         break;
401                 case IAX_IE_VERSION:
402                         if (len != sizeof(unsigned short)) {
403                                 snprintf(tmp, sizeof(tmp),  "Expecting version to be %d bytes long but was %d\n", sizeof(unsigned short), len);
404                                 errorf(tmp);
405                         } else
406                                 ies->version = ntohs(*((unsigned short *)(data + 2)));
407                         break;
408                 case IAX_IE_ADSICPE:
409                         if (len != sizeof(unsigned short)) {
410                                 snprintf(tmp, sizeof(tmp), "Expecting adsicpe to be %d bytes long but was %d\n", sizeof(unsigned short), len);
411                                 errorf(tmp);
412                         } else
413                                 ies->adsicpe = ntohs(*((unsigned short *)(data + 2)));
414                         break;
415                 case IAX_IE_DNID:
416                         ies->dnid = data + 2;
417                         break;
418                 case IAX_IE_AUTHMETHODS:
419                         if (len != sizeof(unsigned short))  {
420                                 snprintf(tmp, sizeof(tmp), "Expecting authmethods to be %d bytes long but was %d\n", sizeof(unsigned short), len);
421                                 errorf(tmp);
422                         } else
423                                 ies->authmethods = ntohs(*((unsigned short *)(data + 2)));
424                         break;
425                 case IAX_IE_CHALLENGE:
426                         ies->challenge = data + 2;
427                         break;
428                 case IAX_IE_MD5_RESULT:
429                         ies->md5_result = data + 2;
430                         break;
431                 case IAX_IE_RSA_RESULT:
432                         ies->rsa_result = data + 2;
433                         break;
434                 case IAX_IE_APPARENT_ADDR:
435                         ies->apparent_addr = ((struct sockaddr_in *)(data + 2));
436                         break;
437                 case IAX_IE_REFRESH:
438                         if (len != sizeof(unsigned short)) {
439                                 snprintf(tmp, sizeof(tmp),  "Expecting refresh to be %d bytes long but was %d\n", sizeof(unsigned short), len);
440                                 errorf(tmp);
441                         } else
442                                 ies->refresh = ntohs(*((unsigned short *)(data + 2)));
443                         break;
444                 case IAX_IE_DPSTATUS:
445                         if (len != sizeof(unsigned short)) {
446                                 snprintf(tmp, sizeof(tmp),  "Expecting dpstatus to be %d bytes long but was %d\n", sizeof(unsigned short), len);
447                                 errorf(tmp);
448                         } else
449                                 ies->dpstatus = ntohs(*((unsigned short *)(data + 2)));
450                         break;
451                 case IAX_IE_CALLNO:
452                         if (len != sizeof(unsigned short)) {
453                                 snprintf(tmp, sizeof(tmp),  "Expecting callno to be %d bytes long but was %d\n", sizeof(unsigned short), len);
454                                 errorf(tmp);
455                         } else
456                                 ies->callno = ntohs(*((unsigned short *)(data + 2)));
457                         break;
458                 case IAX_IE_CAUSE:
459                         ies->cause = data + 2;
460                         break;
461                 case IAX_IE_IAX_UNKNOWN:
462                         if (len == 1)
463                                 ies->iax_unknown = data[2];
464                         else {
465                                 snprintf(tmp, sizeof(tmp), "Expected single byte Unknown command, but was %d long\n", len);
466                                 errorf(tmp);
467                         }
468                         break;
469                 case IAX_IE_MSGCOUNT:
470                         if (len != sizeof(unsigned short)) {
471                                 snprintf(tmp, sizeof(tmp), "Expecting msgcount to be %d bytes long but was %d\n", sizeof(unsigned short), len);
472                                 errorf(tmp);
473                         } else
474                                 ies->msgcount = ntohs(*((unsigned short *)(data + 2))); 
475                         break;
476                 case IAX_IE_AUTOANSWER:
477                         ies->autoanswer = 1;
478                         break;
479                 case IAX_IE_MUSICONHOLD:
480                         ies->musiconhold = 1;
481                         break;
482                 case IAX_IE_TRANSFERID:
483                         if (len != sizeof(unsigned int)) {
484                                 snprintf(tmp, sizeof(tmp), "Expecting transferid to be %d bytes long but was %d\n", sizeof(unsigned int), len);
485                                 errorf(tmp);
486                         } else
487                                 ies->transferid = ntohl(*((unsigned int *)(data + 2)));
488                         break;
489                 default:
490                         snprintf(tmp, sizeof(tmp), "Ignoring unknown information element '%s' (%d) of length %d\n", iax_ie2str(ie), ie, len);
491                         errorf(tmp);
492                 }
493                 /* Overwrite information element with 0, to null terminate previous portion */
494                 data[0] = 0;
495                 datalen -= (len + 2);
496                 data += (len + 2);
497         }
498         /* Null-terminate last field */
499         *data = '\0';
500         if (datalen) {
501                 errorf("Invalid information element contents, strange boundary\n");
502                 return -1;
503         }
504         return 0;
505 }
506