1 /*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15 *
16 * Author : Richard GAYRAUD - 04 Nov 2003
17 * Olivier Jacques
18 * From Hewlett Packard Company.
19 * Shriram Natarajan
20 * Peter Higginson
21 * Eric Miller
22 * Venkatesh
23 * Enrico Hartung
24 * Nasir Khan
25 * Lee Ballard
26 * Guillaume Teissier from FTR&D
27 * Wolfgang Beck
28 * Venkatesh
29 * Vlad Troyanker
30 * Charles P Wright from IBM Research
31 * Amit On from Followap
32 * Jan Andres from Freenet
33 * Ben Evans from Open Cloud
34 * Marc Van Diest from Belgacom
35 * Stefan Esser
36 * Andy Aicken
37 */
38
39 #include "sipp.hpp"
40 #include "message.hpp"
41
42 struct KeywordMap {
43 const char *keyword;
44 MessageCompType type;
45 };
46
47 typedef std::map<std::string, customKeyword> kw_map;
48 kw_map keyword_map;
49
50 /* These keywords take no parameters. */
51 struct KeywordMap SimpleKeywords[] = {
52 {"remote_ip", E_Message_Remote_IP },
53 {"remote_host", E_Message_Remote_Host },
54 {"remote_port", E_Message_Remote_Port },
55 {"transport", E_Message_Transport },
56 {"local_ip", E_Message_Local_IP },
57 {"local_ip_type", E_Message_Local_IP_Type },
58 {"local_port", E_Message_Local_Port },
59 {"server_ip", E_Message_Server_IP },
60 {"media_ip", E_Message_Media_IP },
61 #ifdef PCAPPLAY
62 {"auto_media_port", E_Message_Auto_Media_Port },
63 #endif
64 #ifdef RTP_STREAM
65 {"rtpstream_audio_port", E_Message_RTPStream_Audio_Port },
66 {"rtpstream_video_port", E_Message_RTPStream_Video_Port },
67 #endif
68 {"media_port", E_Message_Media_Port },
69 {"media_ip_type", E_Message_Media_IP_Type },
70 {"call_number", E_Message_Call_Number },
71 {"dynamic_id", E_Message_DynamicId }, // wrapping global counter
72 {"call_id", E_Message_Call_ID },
73 {"cseq", E_Message_CSEQ },
74 {"pid", E_Message_PID },
75 {"service", E_Message_Service },
76 {"branch", E_Message_Branch },
77 {"msg_index", E_Message_Index },
78 {"next_url", E_Message_Next_Url },
79 {"len", E_Message_Len },
80 {"peer_tag_param", E_Message_Peer_Tag_Param },
81 {"last_Request_URI", E_Message_Last_Request_URI },
82 {"last_cseq_number", E_Message_Last_CSeq_Number },
83 {"last_message", E_Message_Last_Message },
84 {"routes", E_Message_Routes },
85 {"tdmmap", E_Message_TDM_Map },
86 {"clock_tick", E_Message_ClockTick },
87 {"users", E_Message_Users },
88 {"userid", E_Message_UserID },
89 {"timestamp", E_Message_Timestamp },
90 {"date", E_Message_Date },
91 {"sipp_version", E_Message_SippVersion },
92 };
93
94 #define KEYWORD_SIZE 256
95
quoted_strchr(const char * s,int c)96 static char* quoted_strchr(const char* s, int c)
97 {
98 const char* p;
99
100 for (p = s; *p && *p != c; p++) {
101 if (*p == '"') {
102 p++;
103 p += strcspn(p, "\"");
104 }
105 }
106
107 return *p == c ? const_cast<char*>(p) : NULL;
108 }
109
SendingMessage(scenario * msg_scenario,char * const_src,bool skip_sanity)110 SendingMessage::SendingMessage(scenario *msg_scenario, char *const_src, bool skip_sanity)
111 {
112 char * src = strdup(const_src);
113 char * osrc = src;
114 char * literal;
115 int literalLen;
116 char * dest;
117 char * key;
118 char current_line[MAX_HEADER_LEN];
119 char * line_mark = NULL;
120 char * tsrc;
121 int num_cr = get_cr_number(src);
122
123 this->msg_scenario = msg_scenario;
124
125 dest = literal = (char *)malloc(strlen(src) + num_cr + 1);
126
127 current_line[0] = '\0';
128 *dest = 0;
129
130 while(*src) {
131 if (current_line[0] == '\0') {
132 line_mark = strchr(src, '\n');
133 if (line_mark) {
134 int header_len = line_mark - src;
135 if (header_len > MAX_HEADER_LEN-1)
136 header_len = MAX_HEADER_LEN-1;
137 memcpy(current_line, src, header_len);
138 current_line[header_len] = '\0';
139 }
140 }
141
142 /* This hex encoding could be done in XML parsing, allowing us to skip
143 * these conditionals and branches. */
144 if ((*src == '\\') && (*(src+1) == 'x')) {
145 /* Allows any hex coded char like '\x5B' ([) */
146 src += 2;
147 if (isxdigit(*src)) {
148 int val = get_decimal_from_hex(*src);
149 src++;
150 if (isxdigit(*src)) {
151 val = (val << 4) + get_decimal_from_hex(*src);
152 }
153 *dest++ = val & 0xff;
154 }
155 src++;
156 } else if (*src == '\n') {
157 *dest++ = '\r';
158 *dest++ = *src++;
159 current_line[0] = '\0';
160 } else if (*src != '[') {
161 *dest++ = *src++;
162 } else {
163 /* We have found a keyword, store the literal that we have been generating. */
164 literalLen = dest - literal;
165 if (literalLen) {
166 *dest = '\0';
167 literal = (char *)realloc(literal, literalLen + 1);
168 if (!literal) {
169 ERROR("Out of memory!");
170 }
171
172 MessageComponent *newcomp = (MessageComponent *)calloc(1, sizeof(MessageComponent));
173 if (!newcomp) {
174 ERROR("Out of memory!");
175 }
176
177 newcomp->type = E_Message_Literal;
178 newcomp->literal = literal;
179 newcomp->literalLen = literalLen; // length without the terminator
180 messageComponents.push_back(newcomp);
181 } else {
182 free(literal);
183 }
184
185 dest = literal = (char *)malloc(strlen(src) + num_cr + 1);
186 *dest = '\0';
187
188 /* Now lets determine which keyword we have. */
189 MessageComponent *newcomp = (MessageComponent *)calloc(1, sizeof(MessageComponent));
190 if (!newcomp) {
191 ERROR("Out of memory!");
192 }
193
194 char keyword [KEYWORD_SIZE+1];
195 src++;
196
197 tsrc = quoted_strchr(src, '[');
198 key = quoted_strchr(src, ']');
199
200 if ((tsrc) && (tsrc<key)) {
201 memcpy(keyword, src-1, tsrc - src + 1);
202 src=tsrc+1;
203 dest += sprintf(dest, "%s", keyword);
204 }
205
206 if((!key) || ((key - src) > KEYWORD_SIZE) || (!(key - src))) {
207 ERROR("Syntax error or invalid [keyword] in scenario while parsing '%s'", current_line);
208 }
209 memcpy(keyword, src, key - src);
210 keyword[key - src] = 0;
211 src = key + 1;
212 // allow +/-n for numeric variables
213 newcomp->offset = 0;
214 if ((strncmp(keyword, "authentication", strlen("authentication")) &&
215 strncmp(keyword, "tdmmap", strlen("tdmmap"))) &&
216 ((key = strchr(keyword,'+')) || (key = strchr(keyword,'-')))) {
217 if (isdigit(*(key+1))) {
218 newcomp->offset = atoi(key);
219 *key = 0;
220 }
221 }
222
223 char *spc = NULL;
224 char ospc;
225 if ((spc = strchr(keyword, ' '))) {
226 ospc = *spc;
227 *spc = '\0';
228 }
229 kw_map::iterator it = keyword_map.find(keyword);
230 if (spc) {
231 *spc = ospc;
232 }
233
234 if (it != keyword_map.end()) {
235 newcomp->type = E_Message_Custom;
236 newcomp->comp_param.fxn = it->second;
237 messageComponents.push_back(newcomp);
238 continue;
239 }
240
241 bool simple_keyword = false;
242 for (unsigned int i = 0; i < sizeof(SimpleKeywords)/sizeof(SimpleKeywords[0]); i++) {
243 if (!strcmp(keyword, SimpleKeywords[i].keyword)) {
244 newcomp->type = SimpleKeywords[i].type;
245 simple_keyword = true;
246 break;
247 }
248 }
249
250 if (simple_keyword) {
251 messageComponents.push_back(newcomp);
252 continue;
253 }
254
255 if(!strncmp(keyword, "field", strlen("field"))) {
256 newcomp->type = E_Message_Injection;
257
258 /* Parse out the interesting things like file and number. */
259 newcomp->comp_param.field_param.field = atoi(keyword + strlen("field"));
260
261 char fileName[KEYWORD_SIZE];
262 getKeywordParam(keyword, "file=", fileName);
263 if (fileName[0] == '\0') {
264 if (!default_file) {
265 ERROR("No injection file was specified!\n");
266 }
267 newcomp->comp_param.field_param.filename = strdup(default_file);
268 } else {
269 newcomp->comp_param.field_param.filename = strdup(fileName);
270 }
271 if (inFiles.find(newcomp->comp_param.field_param.filename) == inFiles.end()) {
272 ERROR("Invalid injection file: %s\n", fileName);
273 }
274
275 char line[KEYWORD_SIZE];
276 getKeywordParam(keyword, "line=", line);
277 if (line[0]) {
278 /* Turn this into a new message component. */
279 newcomp->comp_param.field_param.line = new SendingMessage(msg_scenario, line, true);
280 }
281 } else if(!strncmp(keyword, "file", strlen("file"))) {
282 newcomp->type = E_Message_File;
283
284 /* Parse out the interesting things like file and number. */
285 char fileName[KEYWORD_SIZE];
286 getKeywordParam(keyword, "name=", fileName);
287 if (fileName[0] == '\0') {
288 ERROR("No name specified for 'file' keyword!\n");
289 }
290 /* Turn this into a new message component. */
291 newcomp->comp_param.filename = new SendingMessage(msg_scenario, fileName, true);
292 } else if(*keyword == '$') {
293 newcomp->type = E_Message_Variable;
294 if (!msg_scenario) {
295 ERROR("SendingMessage with variable usage outside of scenario!");
296 }
297 newcomp->varId = msg_scenario->get_var(keyword + 1, "Variable keyword");
298 } else if(!strncmp(keyword, "fill", strlen("fill"))) {
299 newcomp->type = E_Message_Fill;
300 char filltext[KEYWORD_SIZE];
301 char varName[KEYWORD_SIZE];
302
303 getKeywordParam(keyword, "text=", filltext);
304 if (filltext[0] == '\0') {
305 strcpy(filltext, "X");
306 }
307 getKeywordParam(keyword, "variable=", varName);
308
309 newcomp->literal = strdup(filltext);
310 newcomp->literalLen = strlen(newcomp->literal);
311 if (!msg_scenario) {
312 ERROR("SendingMessage with variable usage outside of scenario!");
313 }
314 newcomp->varId = msg_scenario->get_var(varName, "Fill Variable");
315 } else if(!strncmp(keyword, "last_", strlen("last_"))) {
316 newcomp->type = E_Message_Last_Header;
317 newcomp->literal = strdup(keyword + strlen("last_"));
318 newcomp->literalLen = strlen(newcomp->literal);
319 } else if(!strncmp(keyword, "authentication", strlen("authentication"))) {
320 parseAuthenticationKeyword(msg_scenario, newcomp, keyword);
321 }
322 #ifndef PCAPPLAY
323 else if(!strcmp(keyword, "auto_media_port")) {
324 ERROR("The %s keyword requires PCAPPLAY.\n", keyword);
325 }
326 #endif
327 else {
328 // scan for the generic parameters - must be last test
329
330 int i = 0;
331 while (generic[i]) {
332 char *msg1 = *generic[i];
333 char *msg2 = *(generic[i] + 1);
334 if(!strcmp(keyword, msg1)) {
335 newcomp->type = E_Message_Literal;
336 newcomp->literal = strdup(msg2);
337 newcomp->literalLen = strlen(newcomp->literal);
338 break;
339 }
340 ++i;
341 }
342 if (!generic[i]) {
343 ERROR("Unsupported keyword '%s' in xml scenario file",
344 keyword);
345 }
346 }
347
348 messageComponents.push_back(newcomp);
349 }
350 }
351 if (literal[0]) {
352 *dest++ = '\0';
353 literalLen = dest - literal;
354 literal = (char *)realloc(literal, literalLen);
355 if (!literal) {
356 ERROR("Out of memory!");
357 }
358
359 MessageComponent *newcomp = (MessageComponent *)calloc(1, sizeof(MessageComponent));
360 if (!newcomp) {
361 ERROR("Out of memory!");
362 }
363
364 newcomp->type = E_Message_Literal;
365 newcomp->literal = literal;
366 newcomp->literalLen = literalLen-1;
367 messageComponents.push_back(newcomp);
368 } else {
369 free(literal);
370 }
371
372 if (skip_sanity) {
373 cancel = response = ack = false;
374 method = NULL;
375 free(osrc);
376 return;
377 }
378
379 if (numComponents() < 1) {
380 ERROR("Can not create a message that is empty!");
381 }
382 if (getComponent(0)->type != E_Message_Literal) {
383 ERROR("You can not use a keyword for the METHOD or to generate \"SIP/2.0\" to ensure proper [cseq] operation!\n%s\n", osrc);
384 }
385
386 char *p = method = strdup(getComponent(0)->literal);
387 char *q;
388 while (isspace(*p)) {
389 p++;
390 }
391 if (!(q = strchr(method, ' '))) {
392 ERROR("You can not use a keyword for the METHOD or to generate \"SIP/2.0\" to ensure proper [cseq] operation!%s\n", osrc);
393 }
394 *q++ = '\0';
395 while (isspace(*q)) {
396 q++;
397 }
398 if (!strcmp(method, "SIP/2.0")) {
399 char *endptr;
400 code = strtol(q, &endptr, 10);
401 if (*endptr && !isspace(*endptr)) {
402 ERROR("Invalid reply code: %s\n", q);
403 }
404 if (code < 100 || code >= 700) {
405 ERROR("Response codes must be in the range of 100-700");
406 }
407 response = true;
408 ack = false;
409 cancel = false;
410 free(method);
411 method = NULL;
412 } else {
413 if (p != method) {
414 memmove(method, p, strlen(p) + 1);
415 }
416 method = (char *)realloc(method, strlen(method) + 1);
417 if (!method) {
418 ERROR("Out of memory");
419 }
420 ack = (!strcmp(method, "ACK"));
421 cancel = (!strcmp(method, "CANCEL"));
422 response = false;
423 };
424 free(osrc);
425 }
426
~SendingMessage()427 SendingMessage::~SendingMessage()
428 {
429 for (int i = 0; i < numComponents(); i++) {
430 freeMessageComponent(messageComponents[i]);
431 }
432 free(method);
433 }
434
isAck()435 bool SendingMessage::isAck()
436 {
437 return ack;
438 }
isCancel()439 bool SendingMessage::isCancel()
440 {
441 return cancel;
442 }
isResponse()443 bool SendingMessage::isResponse()
444 {
445 return response;
446 }
getMethod()447 char *SendingMessage::getMethod()
448 {
449 return method;
450 }
getCode()451 int SendingMessage::getCode()
452 {
453 return code;
454 }
455
getQuotedParam(char * dest,char * src,int * len)456 void SendingMessage::getQuotedParam(char * dest, char * src, int * len)
457 {
458 *len=0;
459 /* Allows any hex coded string like '0x5B07F6' */
460 while (char c = *src++) {
461 switch(c) {
462 case '"':
463 (*len)++;
464 *dest = '\0';
465 return;
466 case '\\':
467 c = *src++;
468 (*len)++;
469 if (c == 0) {
470 *dest = '\0';
471 return;
472 }
473 /* Fall-Through. */
474 default:
475 *dest++ = c;
476 (*len)++;
477 }
478 }
479 *dest = '\0';
480 }
481
getHexStringParam(char * dest,char * src,int * len)482 void SendingMessage::getHexStringParam(char * dest, char * src, int * len)
483 {
484 *len=0;
485 /* Allows any hex coded string like '0x5B07F6' */
486 while (isxdigit(*src)) {
487 int val = get_decimal_from_hex(*src);
488 src++;
489 if (isxdigit(*src)) {
490 val = (val << 4) + get_decimal_from_hex(*src);
491 src++;
492 }
493 *dest++ = val & 0xff;
494 (*len)++;
495 }
496 }
497
getKeywordParam(char * src,const char * param,char * output)498 void SendingMessage::getKeywordParam(char * src, const char * param, char * output)
499 {
500 char *key, *tmp;
501 int len;
502
503 len = 0;
504 key = NULL;
505 if ((tmp = strstr(src, param))) {
506 tmp += strlen(param);
507 key = tmp;
508 if ((*key == '0') && (*(key+1) == 'x')) {
509 key += 2;
510 getHexStringParam(output, key, &len);
511 } else if (*key == '\"') {
512 key++;
513 getQuotedParam(output, key, &len);
514 } else {
515 while (*key) {
516 if (((key - src) > KEYWORD_SIZE) || (!(key - src))) {
517 ERROR("Syntax error parsing '%s' parameter", param);
518 } else if (*key == ']' || *key < 33 || *key > 126) {
519 break;
520 }
521 key++;
522 }
523 strncpy(output, tmp, key-tmp);
524 output[key-tmp] = '\0';
525 }
526 } else {
527 output[0] = '\0';
528 }
529 }
530
parseAuthenticationKeyword(scenario * msg_scenario,struct MessageComponent * dst,char * keyword)531 void SendingMessage::parseAuthenticationKeyword(scenario *msg_scenario, struct MessageComponent *dst, char *keyword)
532 {
533 char my_auth_user[KEYWORD_SIZE + 1];
534 char my_auth_pass[KEYWORD_SIZE + 1];
535 char my_aka[KEYWORD_SIZE + 1];
536
537 dst->type = E_Message_Authentication;
538
539 memset(my_auth_user,0,KEYWORD_SIZE);
540 memset(my_auth_pass,0,KEYWORD_SIZE);
541 /* Look for optional username and password parameters */
542 getKeywordParam(keyword, "username=", my_auth_user);
543 getKeywordParam(keyword, "password=", my_auth_pass);
544
545 if(*my_auth_user == '\0') {
546 strncpy(my_auth_user, auth_username ? auth_username : service,
547 sizeof(my_auth_user) - 1);
548 }
549 if(*my_auth_pass == '\0') {
550 strncpy(my_auth_pass, auth_password, sizeof(my_auth_pass) - 1);
551 }
552
553
554 dst->comp_param.auth_param.auth_user = new SendingMessage(msg_scenario, my_auth_user, true /* skip sanity */);
555 dst->comp_param.auth_param.auth_pass = new SendingMessage(msg_scenario, my_auth_pass, true);
556
557 /* add aka_OP, aka_AMF, aka_K */
558 getKeywordParam(keyword, "aka_K=", my_aka);
559 if (my_aka[0]==0) {
560 memcpy(my_aka,my_auth_pass,16);
561 my_aka[16]=0;
562 }
563 dst->comp_param.auth_param.aka_K = new SendingMessage(msg_scenario, my_aka, true);
564
565 getKeywordParam(keyword, "aka_OP=", my_aka);
566 dst->comp_param.auth_param.aka_OP = new SendingMessage(msg_scenario, my_aka, true);
567 getKeywordParam(keyword, "aka_AMF=", my_aka);
568 dst->comp_param.auth_param.aka_AMF = new SendingMessage(msg_scenario, my_aka, true);
569 }
570
freeMessageComponent(struct MessageComponent * comp)571 void SendingMessage::freeMessageComponent(struct MessageComponent *comp)
572 {
573 free(comp->literal);
574 if (comp->type == E_Message_Authentication) {
575 if (comp->comp_param.auth_param.auth_user) {
576 delete comp->comp_param.auth_param.auth_user;
577 }
578 if (comp->comp_param.auth_param.auth_pass) {
579 delete comp->comp_param.auth_param.auth_pass;
580 }
581 if (comp->comp_param.auth_param.aka_K) {
582 delete comp->comp_param.auth_param.aka_K;
583 }
584 if (comp->comp_param.auth_param.aka_AMF) {
585 delete comp->comp_param.auth_param.aka_AMF;
586 }
587 if (comp->comp_param.auth_param.aka_OP) {
588 delete comp->comp_param.auth_param.aka_OP;
589 }
590 } else if (comp->type == E_Message_Injection) {
591 free(comp->comp_param.field_param.filename);
592 }
593 free(comp);
594 }
595
numComponents()596 int SendingMessage::numComponents()
597 {
598 return messageComponents.size();
599 }
getComponent(int i)600 struct MessageComponent *SendingMessage::getComponent(int i) {
601 return messageComponents[i];
602 }
603
604 /* This is very simplistic and does not yet allow any arguments, but it is a start. */
registerKeyword(char * keyword,customKeyword fxn)605 int registerKeyword(char *keyword, customKeyword fxn)
606 {
607 if (keyword_map.find(keyword) != keyword_map.end()) {
608 ERROR("Can not register keyword '%s', already registered!\n", keyword);
609 }
610 keyword_map[keyword] = fxn;
611 return 0;
612 }
613