1 /*
2 * $Id: header_f.c 397 2006-01-28 21:11:50Z calrissian $
3 *
4 * Copyright (C) 2002-2004 Fhg Fokus
5 * Copyright (C) 2004-2005 Nils Ohlmeier
6 *
7 * This file belongs to sipsak, a free sip testing tool.
8 *
9 * sipsak is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * sipsak is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 */
19
20 #include "sipsak.h"
21
22 #include "header_f.h"
23 #include "exit_code.h"
24 #include "helper.h"
25 #include "shoot.h"
26
27
28 /* add the given header(s) below the request line */
insert_header(char * mes,char * header,int first)29 void insert_header(char *mes, char *header, int first) {
30 char *ins, *backup;
31
32 if (first) {
33 ins = strchr(mes, '\n');
34 if (ins == NULL) {
35 printf("failed to find a new line in the message\n");
36 exit_code(2);
37 }
38 ins++;
39 }
40 else {
41 ins = mes;
42 }
43 backup = str_alloc(strlen(ins) + 1);
44 strncpy(backup, ins, strlen(ins));
45 strncpy(ins, header, strlen(header));
46 strncpy(ins + strlen(header), backup, strlen(backup)+1);
47 free(backup);
48 }
49
50 /* add a Via Header Field in the message. */
add_via(char * mes)51 void add_via(char *mes)
52 {
53 char *via_line, *via, *backup;
54
55 if ((via=STRCASESTR(mes, VIA_STR)) == NULL &&
56 (via=STRCASESTR(mes, VIA_SHORT_STR)) == NULL) {
57 /* We didn't found a Via so we insert our via
58 direct after the first line. */
59 via=strchr(mes,'\n');
60 if(via == NULL) {
61 fprintf(stderr, "error: failed to find a position to insert Via:\n"
62 "'%s'\n", mes);
63 exit_code(2);
64 }
65 via++;
66 }
67 if (*via == '\n')
68 via++;
69 /* build our own Via-header-line */
70 via_line = str_alloc(VIA_SIP_STR_LEN+TRANSPORT_STR_LEN+1+
71 strlen(fqdn)+15+30+1);
72 snprintf(via_line,
73 VIA_SIP_STR_LEN+TRANSPORT_STR_LEN+1+strlen(fqdn)+15+30,
74 "%s%s %s:%i;branch=z9hG4bK.%08x;rport;alias\r\n",
75 VIA_SIP_STR, transport_str, fqdn, lport, rand());
76 if (verbose > 2)
77 printf("our Via-Line: %s\n", via_line);
78
79 if (strlen(mes)+strlen(via_line)>= BUFSIZE){
80 printf("can't add our Via Header Line because file is too big\n");
81 exit_code(2);
82 }
83 /* finnaly make a backup, insert our via and append the backup */
84 backup=str_alloc((strlen(via)+1));
85 strncpy(backup, via, strlen(via));
86 strncpy(via, via_line, strlen(via_line));
87 strncpy(via+strlen(via_line), backup, strlen(backup)+1);
88 if (verbose > 2)
89 printf("New message with Via-Line:\n%s\n", mes);
90 free(via_line);
91 free(backup);
92 }
93
94 /* copy the via lines from the message to the message
95 reply for correct routing of our reply.
96 */
cpy_vias(char * reply,char * dest)97 void cpy_vias(char *reply, char *dest){
98 char *first_via, *middle_via, *last_via, *backup;
99
100 /* lets see if we find any via */
101 if ((first_via=STRCASESTR(reply, VIA_STR))==NULL &&
102 (first_via=STRCASESTR(reply, VIA_SHORT_STR))==NULL ){
103 fprintf(stderr, "error: the received message doesn't contain a Via header\n");
104 exit_code(3);
105 }
106 last_via=first_via+4;
107 middle_via=last_via;
108 /* proceed additional via lines */
109 while ((middle_via=STRCASESTR(last_via, VIA_STR))!=NULL ||
110 (middle_via=STRCASESTR(last_via, VIA_SHORT_STR))!=NULL )
111 last_via=middle_via+4;
112 last_via=strchr(last_via, '\n');
113 middle_via=strchr(dest, '\n')+1;
114 /* make a backup, insert the vias after the first line and append
115 backup
116 */
117 backup=str_alloc(strlen(middle_via)+1);
118 strcpy(backup, middle_via);
119 strncpy(middle_via, first_via, (size_t)(last_via-first_via+1));
120 strcpy(middle_via+(last_via-first_via+1), backup);
121 free(backup);
122 if (verbose > 2)
123 printf("message reply with vias included:\n%s\n", dest);
124 }
125
cpy_to(char * reply,char * dest)126 void cpy_to(char *reply, char *dest) {
127 char *src_to, *dst_to, *backup, *tmp;
128
129 /* find the position where we want to insert the To */
130 if ((dst_to=STRCASESTR(dest, TO_STR))==NULL &&
131 (dst_to=STRCASESTR(dest, TO_SHORT_STR))==NULL) {
132 fprintf(stderr, "error: could not find To in the destination: %s\n", dest);
133 exit_code(2);
134 }
135 if (*dst_to == '\n')
136 dst_to++;
137 /* find the To we want to copy */
138 if ((src_to=STRCASESTR(reply, TO_STR))==NULL &&
139 (src_to=STRCASESTR(reply, TO_SHORT_STR))==NULL) {
140 if (verbose > 0)
141 fprintf(stderr, "warning: could not find To in reply. "
142 "trying with original To\n");
143 }
144 else {
145 if (*src_to == '\n')
146 src_to++;
147 /* both To found, so copy it */
148 tmp=strchr(dst_to, '\n');
149 tmp++;
150 backup=str_alloc(strlen(tmp)+1);
151 strcpy(backup, tmp);
152 tmp=strchr(src_to, '\n');
153 strncpy(dst_to, src_to, (size_t)(tmp-src_to+1));
154 strcpy(dst_to+(tmp-src_to+1), backup);
155 free(backup);
156 if (verbose >2)
157 printf("reply with copyed To:\n%s\n", dest);
158 }
159 }
160
161 /* check for the existence of a Max-Forwards header field. if its
162 present it sets it to the given value, if not it will be inserted.*/
set_maxforw(char * mes,int value)163 void set_maxforw(char *mes, int value){
164 char *max, *backup, *crlfi;
165 int maxforward;
166
167 if ((max=STRCASESTR(mes, MAX_FRW_STR))==NULL){
168 /* no max-forwards found so insert it after the first line*/
169 max=strchr(mes,'\n');
170 if (!max) {
171 printf("failed to find newline\n");
172 exit_code(254);
173 }
174 max++;
175 backup=str_alloc(strlen(max)+1);
176 strncpy(backup, max, (size_t)(strlen(max)));
177 if (value == -1) {
178 maxforward = 70; // RFC3261 default
179 }
180 else {
181 maxforward = value;
182 }
183 snprintf(max, MAX_FRW_STR_LEN+6, "%s%i\r\n", MAX_FRW_STR, maxforward);
184 max=strchr(max,'\n');
185 max++;
186 strncpy(max, backup, strlen(backup)+1);
187 free(backup);
188 if (verbose > 1)
189 printf("Max-Forwards %i inserted into header\n", maxforward);
190 if (verbose > 2)
191 printf("New message with inserted Max-Forwards:\n%s\n", mes);
192 }
193 else{
194 /* found max-forwards => overwrite the value with maxforw*/
195 crlfi=strchr(max,'\n');
196 crlfi++;
197 backup=str_alloc(strlen(crlfi)+1);
198 strncpy(backup, crlfi, strlen(crlfi));
199 crlfi=max + MAX_FRW_STR_LEN;
200 if (value == -1) {
201 maxforward = str_to_int(crlfi);
202 maxforward++;
203 }
204 else {
205 maxforward = value;
206 }
207 snprintf(crlfi, 6, "%i\r\n", maxforward);
208 crlfi=strchr(max,'\n');
209 crlfi++;
210 strncpy(crlfi, backup, strlen(backup)+1);
211 free(backup);
212 if (verbose > 1)
213 printf("Max-Forwards set to %i\n", maxforward);
214 if (verbose > 2)
215 printf("New message with changed Max-Forwards:\n%s\n", mes);
216 }
217 }
218
219 /* replaces the uri in first line of mes with the other uri */
uri_replace(char * mes,char * uri)220 void uri_replace(char *mes, char *uri)
221 {
222 char *foo, *backup;
223
224 foo=strchr(mes, '\n');
225 if (!foo) {
226 printf("failed to find newline\n");
227 exit_code(254);
228 }
229 foo++;
230 backup=str_alloc(strlen(foo)+1);
231 strncpy(backup, foo, strlen(foo));
232 foo=STRCASESTR(mes, "sip");
233 strncpy(foo, uri, strlen(uri));
234 strncpy(foo+strlen(uri), SIP20_STR, SIP20_STR_LEN);
235 strncpy(foo+strlen(uri)+SIP20_STR_LEN, backup, strlen(backup)+1);
236 free(backup);
237 if (verbose > 2)
238 printf("Message with modified uri:\n%s\n", mes);
239 }
240
241 /* replace the Content-Length value with the given value */
set_cl(char * mes,int contentlen)242 void set_cl(char* mes, int contentlen) {
243 char *cl, *cr, *backup;
244
245 if ((cl=STRCASESTR(mes, CON_LEN_STR)) == NULL &&
246 (cl=STRCASESTR(mes, CON_LEN_SHORT_STR)) == NULL) {
247 printf("missing Content-Length in message\n");
248 return;
249 }
250 if (*cl == '\n') {
251 cl++;
252 }
253 cr = strchr(cl, '\n');
254 cr++;
255 backup=str_alloc(strlen(cr)+1);
256 strncpy(backup, cr, strlen(cr));
257 if (*cl == 'C')
258 cr=cl + CON_LEN_STR_LEN;
259 else
260 cr=cl + 3;
261 snprintf(cr, 6, "%i\r\n", contentlen);
262 cr=strchr(cr, '\n');
263 cr++;
264 strncpy(cr, backup, strlen(backup)+1);
265 free(backup);
266 if (verbose > 2) {
267 printf("Content-Length set to %i\n"
268 "New message with changed Content-Length:\n%s\n", contentlen, mes);
269 }
270 }
271
272 /* returns the content length from the message; in case of error it
273 * return -1 */
get_cl(char * mes)274 int get_cl(char* mes) {
275 char *cl;
276
277 if ((cl=STRCASESTR(mes, CON_LEN_STR)) == NULL &&
278 (cl=STRCASESTR(mes, CON_LEN_SHORT_STR)) == NULL) {
279 if (verbose > 1)
280 printf("missing Content-Length in message\n");
281 return -1;
282 }
283 if (*cl == '\n') {
284 cl+=3;
285 }
286 else {
287 cl+=15;
288 }
289 return str_to_int(cl);
290 }
291
292 /* returns 1 if the rr_line contains the lr parameter
293 * otherwise 0 */
find_lr_parameter(char * rr_line)294 int find_lr_parameter(char *rr_line) {
295 char *eol, *lr;
296
297 eol = strchr(rr_line, '\n');
298 lr = STRCASESTR(rr_line, ";lr");
299 if ((eol == NULL) || (lr == NULL) || (lr > eol)) {
300 return 0;
301 }
302 else {
303 return 1;
304 }
305 }
306
307 /* copies the Record-Route header from src to dst.
308 * if route is set Record-Route will be replaced by Route */
cpy_rr(char * src,char * dst,int route)309 void cpy_rr(char* src, char *dst, int route) {
310 char *rr, *cr, *cr2, *backup;
311 int len;
312
313 cr = strchr(dst, '\n');
314 if (cr == NULL) {
315 fprintf(stderr, "error: failed to end of line in destination\n");
316 exit_code(3);
317 }
318 cr++;
319 rr = STRCASESTR(src, RR_STR);
320 if (rr != NULL) {
321 if (find_lr_parameter(rr) == 0) {
322 fprintf(stderr, "error: strict routing is not support yet\n");
323 exit_code(252);
324 }
325 backup=str_alloc(strlen(cr)+1);
326 strncpy(backup, cr, strlen(cr));
327 if (route == 0)
328 len = RR_STR_LEN;
329 else
330 len = ROUTE_STR_LEN;
331 while (rr != NULL) {
332 if (route == 0) {
333 strncpy(cr, RR_STR, RR_STR_LEN);
334 }
335 else {
336 strncpy(cr, ROUTE_STR, ROUTE_STR_LEN);
337 }
338 cr += len;
339 cr2 = strchr(rr, '\n');
340 if (cr2 == NULL) {
341 fprintf(stderr, "error: failed to find end of line\n");
342 exit_code(3);
343 }
344 strncpy(cr, rr + RR_STR_LEN, (cr2 - (rr + len) + 1));
345 cr+=(cr2 - (rr + RR_STR_LEN) + 1);
346 rr = STRCASESTR(++rr, RR_STR);
347 }
348 strncpy(cr, backup, strlen(backup)+1);
349 free(backup);
350 if (verbose > 2)
351 printf("New message with inserted Route:\n%s\n", dst);
352 }
353 }
354
355 /* build an ACK from the given invite and reply.
356 * NOTE: space has to be allocated allready for the ACK */
build_ack(char * invite,char * reply,char * dest,struct sipsak_regexp * reg)357 void build_ack(char *invite, char *reply, char *dest,
358 struct sipsak_regexp *reg) {
359 char *tmp;
360 int len;
361
362 if ((tmp = STRCASESTR(invite, "\r\n\r\n")) != NULL) {
363 len = (tmp + 4) - invite;
364 }
365 else {
366 len = strlen(invite);
367 }
368 memcpy(dest, invite, len);
369 *(dest + len) = '\0';
370 replace_string(dest, "INVITE", "ACK");
371 set_cl(dest, 0);
372 cpy_to(reply, dest);
373 if (regexec(&(reg->okexp), reply, 0, 0, 0)==0) {
374 cpy_rr(reply, dest, 1);
375 /* 200 ACK must be in new transaction */
376 new_branch(dest);
377 if((tmp = uri_from_contact(reply))!= NULL) {
378 uri_replace(dest, tmp);
379 free(tmp);
380 }
381 }
382 }
383
384 /* tryes to find the warning header filed and prints out the IP */
warning_extract(char * message)385 void warning_extract(char *message)
386 {
387 char *warning, *end, *mid, *server;
388 int srvsize;
389
390 if ((warning=STRCASESTR(message, "Warning:"))==NULL) {
391 if (verbose > 0)
392 printf("'no Warning header found' ");
393 else
394 printf("?? ");
395 return;
396 }
397 end=strchr(warning, '"');
398 end--;
399 warning=strchr(warning, '3');
400 warning+=4;
401 mid=strchr(warning, ':');
402 if (mid)
403 end=mid;
404 srvsize=end - warning + 1;
405 server=str_alloc((size_t)srvsize);
406 server=strncpy(server, warning, (size_t)(srvsize - 1));
407 printf("%s ", server);
408 free(server);
409 }
410
411 /* tries to find and return the number in the CSeq header */
cseq(char * message)412 int cseq(char *message)
413 {
414 char *cseq;
415 int num=-1;
416
417 cseq=STRCASESTR(message, CSEQ_STR);
418 if (cseq) {
419 cseq+=6;
420 num=str_to_int(cseq);
421 if (num < 1) {
422 if (verbose > 2)
423 printf("CSeq found but not convertable\n");
424 return 0;
425 }
426 return num;
427 }
428 if (verbose > 2)
429 printf("no CSeq found\n");
430 return 0;
431 }
432
433 /* if it find the Cseq number in the message it will increased by one */
increase_cseq(char * message)434 void increase_cseq(char *message)
435 {
436 int cs;
437 char *cs_s, *eol, *backup;
438
439 cs = cseq(message);
440 if ((cs < 1) && (verbose > 1)) {
441 printf("CSeq increase failed because unable to extract CSeq number\n");
442 return;
443 }
444 if (cs == INT_MAX)
445 cs = 1;
446 else
447 cs++;
448 cs_s=STRCASESTR(message, CSEQ_STR);
449 if (cs_s) {
450 cs_s+=6;
451 eol=strchr(cs_s, ' ');
452 eol++;
453 backup=str_alloc(strlen(eol)+1);
454 strncpy(backup, eol, (size_t)(strlen(eol)));
455 snprintf(cs_s, 11, "%i ", cs);
456 cs_s+=strlen(cs_s);
457 strncpy(cs_s, backup, strlen(backup));
458 free(backup);
459 cseq_counter = cs;
460 }
461 else if (verbose > 1)
462 printf("'CSeq' not found in message\n");
463 }
464
465 /* separates the given URI into the parts by setting the pointer but it
466 destroyes the URI */
parse_uri(char * uri,char ** scheme,char ** user,char ** host,int * port)467 void parse_uri(char *uri, char **scheme, char **user, char **host, int *port)
468 {
469 char *col, *col2, *at;
470 col = col2 = at = NULL;
471 *port = 0;
472 *scheme = *user = *host = NULL;
473 if ((col=strchr(uri,':'))!=NULL) {
474 if ((at=strchr(uri,'@'))!=NULL) {
475 *col = '\0';
476 *at = '\0';
477 if (at > col) {
478 *scheme = uri;
479 *user = ++col;
480 *host = ++at;
481 if ((col2=strchr(*host,':'))!=NULL) {
482 *col2 = '\0';
483 *port = str_to_int(++col2);
484 }
485 }
486 else {
487 *user = uri;
488 *host = ++at;
489 *port = str_to_int(++col);
490 }
491 }
492 else {
493 *col = '\0';
494 col++;
495 if ((col2=strchr(col,':'))!=NULL) {
496 *col2 = '\0';
497 *scheme = uri;
498 *host = col;
499 *port = str_to_int(++col2);
500 }
501 else {
502 if (is_number(col)) {
503 *host = uri;
504 *port = str_to_int(col);
505 }
506 else {
507 *scheme = uri;
508 *host = col;
509 }
510 }
511 }
512 }
513 else {
514 *host = uri;
515 }
516 }
517
518 /* return a copy of the URI from the Contact of the message if found */
uri_from_contact(char * message)519 char* uri_from_contact(char *message)
520 {
521 char *contact, *end, *tmp, c;
522
523 /* try to find the contact in the redirect */
524 if ((contact=STRCASESTR(message, CONT_STR))==NULL &&
525 (contact=STRCASESTR(message, CONT_SHORT_STR))==NULL ) {
526 if(verbose > 1)
527 printf("'Contact' not found in the message\n");
528 return NULL;
529 }
530 if (*contact == '\n')
531 contact++;
532
533 if((end=strchr(contact,'\r'))!=NULL) {
534 c = '\r';
535 *end = '\0';
536 }
537 else if((end=strchr(contact,'\n'))!=NULL) {
538 c = '\n';
539 *end = '\0';
540 }
541 else {
542 c = '\0';
543 end = contact + strlen(contact);
544 }
545
546 tmp = NULL;
547
548 if ((contact=STRCASESTR(contact, "sip:"))!=NULL) {
549 if ((tmp=strchr(contact+4, ';'))!=NULL) {
550 *end = c;
551 end = tmp;
552 c = *end;
553 *end = '\0';
554 }
555 if ((tmp=strchr(contact+4, '>'))!=NULL) {
556 *end = c;
557 end = tmp;
558 c = *end;
559 *end = '\0';
560 }
561 tmp = str_alloc(strlen(contact)+1);
562 memcpy(tmp,contact,strlen(contact));
563 }
564
565 *end = c;
566
567 return tmp;
568 }
569
570 /* replace the 8 bytes behind the first magic cookie with a new
571 * random value */
new_branch(char * message)572 void new_branch(char *message)
573 {
574 char *branch;
575 char backup;
576
577 if((branch = STRCASESTR(message,"branch=z9hG4bK.")) != NULL) {
578 backup = *(branch+15+8);
579 snprintf(branch+15, 9, "%08x", rand());
580 *(branch+15+8) = backup;
581 }
582 }
583
584 /* increase the CSeq and insert a new branch value */
new_transaction(char * message)585 void new_transaction(char *message)
586 {
587 increase_cseq(message);
588 new_branch(message);
589 }
590
591 /* just print the first line of the message */
print_message_line(char * message)592 void print_message_line(char *message)
593 {
594 char *crlf;
595
596 crlf=strchr(message, '\n');
597 if (!crlf) {
598 printf("failed to find newline\n");
599 exit_code(254);
600 }
601 else if (*(crlf - 1) == '\r')
602 crlf--;
603 printf("%.*s\n", (int)(crlf - message), message);
604 }
605
606 /* return pointer to the beginning of the message body */
get_body(char * mes)607 inline char* get_body(char *mes) {
608 char *cr;
609
610 if ((cr = strstr(mes, "\r\n\r\n")) != NULL) {
611 cr+=4;
612 }
613 return cr;
614 }
615