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