1bb833b5c803201093c0267be108bc88a0e26108
[sip-router] / msg_translator.c
1 /* 
2  * $Id$
3  *
4  *
5  * Copyright (C) 2001-2003 Fhg Fokus
6  *
7  * This file is part of ser, a free SIP server.
8  *
9  * ser 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  * For a license to use the ser software under conditions
15  * other than those described here, or to purchase support for this
16  * software, please contact iptel.org by e-mail at the following addresses:
17  *    info@iptel.org
18  *
19  * ser is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License 
25  * along with this program; if not, write to the Free Software 
26  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
27  * 
28  *
29  * History:
30  * --------
31  * 2003-01-20 bug_fix: use of return value of snprintf aligned to C99 (jiri)
32  * 2003-01-23 added rport patches, contributed by 
33  *             Maxim Sobolev <sobomax@FreeBSD.org> and heavily modified by me
34  *             (andrei)
35  * 2003-01-24 added i param to via of outgoing requests (used by tcp),
36  *             modified via_builder params (andrei)
37  * 2003-01-27 more rport fixes (make use of new via_param->start)  (andrei)
38  * 2003-01-27 next baby-step to removing ZT - PRESERVE_ZT (jiri)
39  * 2003-01-29 scrathcpad removed (jiri)
40  *
41  */
42
43
44
45 #include <sys/types.h>
46 #include <sys/socket.h>
47 #include <netdb.h>
48 #include <string.h>
49 #include <stdio.h>
50 #include <stdlib.h>
51
52 #include "comp_defs.h"
53 #include "msg_translator.h"
54 #include "globals.h"
55 #include "error.h"
56 #include "mem/mem.h"
57 #include "dprint.h"
58 #include "config.h"
59 #include "md5utils.h"
60 #include "data_lump_rpl.h"
61 #include "ip_addr.h"
62 #include "resolve.h"
63 #include "ut.h"
64 #include "pt.h"
65
66
67 #define append_str(_dest,_src,_len) \
68         do{\
69                 memcpy( (_dest) , (_src) , (_len) );\
70                 (_dest) += (_len) ;\
71         }while(0);
72
73 #ifdef SCRATCH
74 #define append_str_trans(_dest,_src,_len,_msg) \
75         append_str( (_dest), (_msg)->orig+((_src)-(_msg)->buf) , (_len) );
76 #else
77 #define append_str_trans(_dest,_src,_len,_msg) \
78         append_str( (_dest), (_src), (_len) );
79 #endif
80
81 extern char version[];
82 extern int version_len;
83
84
85
86 #ifndef REMOVE_ALL_ZT
87 /* checks if ip is in host(name) and ?host(ip)=name?
88  * ip must be in network byte order!
89  *  resolver = DO_DNS | DO_REV_DNS; if 0 no dns check is made
90  * return 0 if equal */
91 static int check_address(struct ip_addr* ip, char *name, int resolver)
92 {
93         struct hostent* he;
94         int i;
95         char* s;
96
97         /* maybe we are lucky and name it's an ip */
98         s=ip_addr2a(ip);
99         if (s){
100                 DBG("check_address(%s, %.*s, %d)\n", 
101                         s, name->len, name->s, resolver);
102
103         #ifdef USE_IPV6
104                 if ((ip->af==AF_INET6) && (strcasecmp(name, s)==0))
105                                 return 0;
106                 else
107         #endif
108
109                         if (strcmp(name, s)==0) 
110                                 return 0;
111         }else{
112                 LOG(L_CRIT, "check_address: BUG: could not convert ip address\n");
113                 return -1;
114         }
115
116         if (resolver&DO_DNS){
117                 DBG("check_address: doing dns lookup\n");
118                 /* try all names ips */
119                 he=resolvehost(name);
120                 if (he && ip->af==he->h_addrtype){
121                         for(i=0;he && he->h_addr_list[i];i++){
122                                 if ( memcmp(&he->h_addr_list[i], ip->u.addr, ip->len)==0)
123                                         return 0;
124                         }
125                 }
126         }
127         if (resolver&DO_REV_DNS){
128                 DBG("check_address: doing rev. dns lookup\n");
129                 /* try reverse dns */
130                 he=rev_resolvehost(ip);
131                 if (he && (strcmp(he->h_name, name)==0))
132                         return 0;
133                 for (i=0; he && he->h_aliases[i];i++){
134                         if (strcmp(he->h_aliases[i],name)==0)
135                                 return 0;
136                 }
137         }
138         return -1;
139 }
140 #endif
141
142
143
144 /* checks if ip is in host(name) and ?host(ip)=name?
145  * ip must be in network byte order!
146  *  resolver = DO_DNS | DO_REV_DNS; if 0 no dns check is made
147  * return 0 if equal */
148 static int check_via_address(struct ip_addr* ip, str *name, 
149                                 unsigned short port, int resolver)
150 {
151         struct hostent* he;
152         int i;
153         char* s;
154
155         /* maybe we are lucky and name it's an ip */
156         s=ip_addr2a(ip);
157         if (s){
158                 DBG("check_address(%s, %.*s, %d)\n", 
159                         s, name->len, name->s, resolver);
160
161         #ifdef USE_IPV6
162                 if ((ip->af==AF_INET6) && (strncasecmp(name->s, s, name->len)==0))
163                         return 0;
164                 else
165         #endif
166
167                         if (strncmp(name->s, s, name->len)==0) 
168                                 return 0;
169         }else{
170                 LOG(L_CRIT, "check_address: BUG: could not convert ip address\n");
171                 return -1;
172         }
173
174         if (port==0) port=SIP_PORT;
175         if (resolver&DO_DNS){
176                 DBG("check_address: doing dns lookup\n");
177                 /* try all names ips */
178                 he=sip_resolvehost(name, &port);
179                 if (he && ip->af==he->h_addrtype){
180                         for(i=0;he && he->h_addr_list[i];i++){
181                                 if ( memcmp(&he->h_addr_list[i], ip->u.addr, ip->len)==0)
182                                         return 0;
183                         }
184                 }
185         }
186         if (resolver&DO_REV_DNS){
187                 DBG("check_address: doing rev. dns lookup\n");
188                 /* try reverse dns */
189                 he=rev_resolvehost(ip);
190                 if (he && (strncmp(he->h_name, name->s, name->len)==0))
191                         return 0;
192                 for (i=0; he && he->h_aliases[i];i++){
193                         if (strncmp(he->h_aliases[i],name->s, name->len)==0)
194                                 return 0;
195                 }
196         }
197         return -1;
198 }
199
200
201 static char * warning_builder( struct sip_msg *msg, unsigned int *returned_len)
202 {
203         static char buf[MAX_WARNING_LEN];
204         static unsigned int fix_len=0;
205         str *foo;
206         int print_len;
207
208         if (!fix_len)
209         {
210                 memcpy(buf+fix_len,WARNING, WARNING_LEN);
211                 fix_len +=WARNING_LEN;
212                 memcpy(buf+fix_len, bind_address->name.s,bind_address->name.len);
213                 fix_len += bind_address->name.len;
214                 //*(buf+fix_len++) = ':';
215                 memcpy(buf+fix_len,bind_address->port_no_str.s,
216                         bind_address->port_no_str.len);
217                 fix_len += bind_address->port_no_str.len;
218                 memcpy(buf+fix_len, WARNING_PHRASE,WARNING_PHRASE_LEN);
219                 fix_len += WARNING_PHRASE_LEN;
220         }
221
222         /*adding out_uri*/
223         if (msg->new_uri.s)
224                 foo=&(msg->new_uri);
225         else
226                 foo=&(msg->first_line.u.request.uri);
227         print_len=snprintf(buf+fix_len, MAX_WARNING_LEN-fix_len,
228                 "pid=%d req_src_ip=%s in_uri=%.*s out_uri=%.*s via_cnt%c=%d\"",
229                 my_pid(),
230                 ip_addr2a(&msg->rcv.src_ip),
231                 msg->first_line.u.request.uri.len, msg->first_line.u.request.uri.s,
232                 foo->len, foo->s, 
233                 msg->parsed_flag & HDR_EOH ? '=' : '>', /* should be = */
234                 via_cnt );
235
236         if (print_len==-1 || print_len>=MAX_WARNING_LEN-fix_len) {
237                 LOG(L_ERR, "ERROR: warning_builder: buffer size exceeded\n");
238                 *returned_len=0;
239                 return 0;
240         } else {
241                 *returned_len=fix_len+print_len;
242                 return buf;
243         }
244 }
245
246
247
248
249 char* received_builder(struct sip_msg *msg, unsigned int *received_len)
250 {
251         char *buf;
252         int  len;
253         struct ip_addr *source_ip;
254         char *tmp;
255         int  tmp_len;
256         int extra_len;
257
258         extra_len = 0;
259         source_ip=&msg->rcv.src_ip;
260
261         buf=pkg_malloc(sizeof(char)*MAX_RECEIVED_SIZE);
262         if (buf==0){
263                 ser_error=E_OUT_OF_MEM;
264                 LOG(L_ERR, "ERROR: received_builder: out of memory\n");
265                 return 0;
266         }
267         memcpy(buf, RECEIVED, RECEIVED_LEN);
268         if ( (tmp=ip_addr2a(source_ip))==0)
269                 return 0; /* error*/
270         tmp_len=strlen(tmp);
271         len=RECEIVED_LEN+tmp_len;
272         if(source_ip->af==AF_INET6){
273                 len+=2;
274                 buf[RECEIVED_LEN]='[';
275                 buf[RECEIVED_LEN+tmp_len+1]=']';
276                 extra_len=1;
277         }
278         
279         memcpy(buf+RECEIVED_LEN+extra_len, tmp, tmp_len);
280         buf[len+1]=0; /*null terminate it */
281
282         *received_len = len;
283         return buf;
284 }
285
286
287
288 char* rport_builder(struct sip_msg *msg, unsigned int *rport_len)
289 {
290         char* buf;
291         char* tmp;
292         int tmp_len;
293         int len;
294         
295         tmp_len=0;
296         tmp=int2str(ntohs(msg->rcv.src_port), &tmp_len);
297         len=RPORT_LEN+tmp_len; /* space for null term */
298         buf=pkg_malloc(sizeof(char)*(len+1));
299         if (buf==0){
300                 ser_error=E_OUT_OF_MEM;
301                 LOG(L_ERR, "ERROR: rport_builder: out of memory\n");
302                 return 0;
303         }
304         memcpy(buf, RPORT, RPORT_LEN);
305         memcpy(buf+RPORT_LEN, tmp, tmp_len);
306         buf[len+1]=0; /*null terminate it*/
307         
308         *rport_len=len;
309         return buf;
310 }
311
312
313
314 char* id_builder(struct sip_msg* msg, unsigned int *id_len)
315 {
316         char* buf;
317         int len, value_len;
318         char revhex[sizeof(int)*2];
319         char* p;
320         int size;
321         
322         size=sizeof(int)*2;
323         p=&revhex[0];
324         if (int2reverse_hex(&p, &size, msg->rcv.proto_reserved1)==-1){
325                 LOG(L_CRIT, "BUG: id_builder: not enough space for id\n");
326                 return 0;
327         }
328         value_len=p-&revhex[0];
329         len=ID_PARAM_LEN+value_len; /* place for ending \0 */
330         buf=pkg_malloc(sizeof(char)*(len+1));
331         if (buf==0){
332                 ser_error=E_OUT_OF_MEM;
333                 LOG(L_ERR, "ERROR: rport_builder: out of memory\n");
334                 return 0;
335         }
336         memcpy(buf, ID_PARAM, ID_PARAM_LEN);
337         memcpy(buf+ID_PARAM_LEN, revhex, value_len);
338         buf[len+1]=0; /* null terminate it */
339         *id_len=len;
340         return buf;
341 }
342
343
344
345 /* computes the "unpacked" len of a lump list,
346    code moved from build_req_from_req */
347 static inline int lumps_len(struct lump* l)
348 {
349         int s_offset;
350         int new_len;
351         struct lump* t;
352         struct lump* r;
353
354         s_offset=0;
355         new_len=0;
356         for(t=l;t;t=t->next){
357                 for(r=t->before;r;r=r->before){
358                         switch(r->op){
359                                 case LUMP_ADD:
360                                         new_len+=r->len;
361                                         break;
362                                 default:
363                                         /* only ADD allowed for before/after */
364                                         LOG(L_CRIT, "BUG: lumps_len: invalid op "
365                                                         "for data lump (%x)\n", r->op);
366                         }
367                 }
368                 switch(t->op){
369                         case LUMP_ADD:
370                                 new_len+=t->len;
371                                 break;
372                         case LUMP_DEL:
373                                 /* fix overlapping deleted zones */
374                                 if (t->u.offset < s_offset){
375                                         /* change len */
376                                         if (t->len>s_offset-t->u.offset)
377                                                         t->len-=s_offset-t->u.offset;
378                                         else t->len=0;
379                                         t->u.offset=s_offset;
380                                 }
381                                 s_offset=t->u.offset+t->len;
382                                 new_len-=t->len;
383                                 break;
384                         case LUMP_NOP:
385                                 /* fix offset if overlapping on a deleted zone */
386                                 if (t->u.offset < s_offset){
387                                         t->u.offset=s_offset;
388                                 }else
389                                         s_offset=t->u.offset;
390                                 /* do nothing */
391                                 break;
392                         default:
393                                 LOG(L_CRIT,"BUG:lumps_len: invalid"
394                                                         " op for data lump (%x)\n", r->op);
395                 }
396                 for (r=t->after;r;r=r->after){
397                         switch(r->op){
398                                 case LUMP_ADD:
399                                         new_len+=r->len;
400                                         break;
401                                 default:
402                                         /* only ADD allowed for before/after */
403                                         LOG(L_CRIT, "BUG:lumps_len: invalid"
404                                                                 " op for data lump (%x)\n", r->op);
405                         }
406                 }
407         }
408         return new_len;
409 }
410
411
412
413 /* another helper functions, adds/Removes the lump,
414         code moved form build_req_from_req  */
415
416 static inline void process_lumps(       struct lump* l, char* new_buf, 
417                                                                         unsigned int* new_buf_offs, char* orig,
418                                                                         unsigned int* orig_offs)
419 {
420         struct lump *t;
421         struct lump *r;
422         int size;
423         int offset;
424         int s_offset;
425         
426         offset=*new_buf_offs;
427         s_offset=*orig_offs;
428         
429         for (t=l;t;t=t->next){
430                 switch(t->op){
431                         case LUMP_ADD:
432                                 /* just add it here! */
433                                 /* process before  */
434                                 for(r=t->before;r;r=r->before){
435                                         switch (r->op){
436                                                 case LUMP_ADD:
437                                                         /*just add it here*/
438                                                         memcpy(new_buf+offset, r->u.value, r->len);
439                                                         offset+=r->len;
440                                                         break;
441                                                 default:
442                                                         /* only ADD allowed for before/after */
443                                                         LOG(L_CRIT, "BUG:process_lumps: "
444                                                                         "invalid op for data lump (%x)\n", r->op);
445                                         }
446                                 }
447                                 /* copy "main" part */
448                                 memcpy(new_buf+offset, t->u.value, t->len);
449                                 offset+=t->len;
450                                 /* process after */
451                                 for(r=t->after;r;r=r->after){
452                                         switch (r->op){
453                                                 case LUMP_ADD:
454                                                         /*just add it here*/
455                                                         memcpy(new_buf+offset, r->u.value, r->len);
456                                                         offset+=r->len;
457                                                         break;
458                                                 default:
459                                                         /* only ADD allowed for before/after */
460                                                         LOG(L_CRIT, "BUG:process_lumps: "
461                                                                         "invalid op for data lump (%x)\n", r->op);
462                                         }
463                                 }
464                                 break;
465                         case LUMP_NOP:
466                         case LUMP_DEL:
467                                 /* copy till offset */
468                                 if (s_offset>t->u.offset){
469                                         DBG("Warning: (%d) overlapped lumps offsets,"
470                                                 " ignoring(%x, %x)\n", t->op, s_offset,t->u.offset);
471                                         /* this should've been fixed above (when computing len) */
472                                         /* just ignore it*/
473                                         break;
474                                 }
475                                 size=t->u.offset-s_offset;
476                                 if (size){
477                                         memcpy(new_buf+offset, orig+s_offset,size);
478                                         offset+=size;
479                                         s_offset+=size;
480                                 }
481                                 /* process before  */
482                                 for(r=t->before;r;r=r->before){
483                                         switch (r->op){
484                                                 case LUMP_ADD:
485                                                         /*just add it here*/
486                                                         memcpy(new_buf+offset, r->u.value, r->len);
487                                                         offset+=r->len;
488                                                         break;
489                                                 default:
490                                                         /* only ADD allowed for before/after */
491                                                         LOG(L_CRIT, "BUG:process_lumps: "
492                                                                         "invalid op for data lump (%x)\n",r->op);
493                                         }
494                                 }
495                                 /* process main (del only) */
496                                 if (t->op==LUMP_DEL){
497                                         /* skip len bytes from orig msg */
498                                         s_offset+=t->len;
499                                 }
500                                 /* process after */
501                                 for(r=t->after;r;r=r->after){
502                                         switch (r->op){
503                                                 case LUMP_ADD:
504                                                         /*just add it here*/
505                                                         memcpy(new_buf+offset, r->u.value, r->len);
506                                                         offset+=r->len;
507                                                         break;
508                                                 default:
509                                                         /* only ADD allowed for before/after */
510                                                         LOG(L_CRIT, "BUG:process_lumps: "
511                                                                         "invalid op for data lump (%x)\n", r->op);
512                                         }
513                                 }
514                                 break;
515                         default:
516                                         LOG(L_CRIT, "BUG: process_lumps: "
517                                                         "unknown op (%x)\n", t->op);
518                 }
519         }
520         *new_buf_offs=offset;
521         *orig_offs=s_offset;
522 }
523
524
525
526 char * build_req_buf_from_sip_req( struct sip_msg* msg,
527                                                                 unsigned int *returned_len,
528                                                                 struct socket_info* send_sock, int proto)
529 {
530         unsigned int len, new_len, received_len, rport_len, uri_len, via_len;
531         char* line_buf;
532         char* received_buf;
533         char* rport_buf;
534         char* new_buf;
535 #ifdef SCRATCH
536         char* orig;
537 #endif
538         char* buf;
539 #ifndef REMOVE_ALL_ZT
540         char  backup;
541 #endif
542         unsigned int offset, s_offset, size;
543         struct lump* anchor;
544         int r;
545         str branch;
546         str extra_params;
547         
548 #ifdef USE_TCP
549         char* id_buf;
550         int id_len;
551         
552         
553         id_buf=0;
554         id_len=0;
555 #endif
556         extra_params.len=0;
557         extra_params.s=0;
558         uri_len=0;
559 #ifdef SCRATCH
560         orig=msg->orig;
561 #endif
562         buf=msg->buf;
563         len=msg->len;
564         received_len=0;
565         rport_len=0;
566         new_buf=0;
567         received_buf=0;
568         rport_buf=0;
569         line_buf=0;
570
571         
572 #ifdef USE_TCP
573         /* add id if tcp */
574         if (msg->rcv.proto==PROTO_TCP){
575                 if  ((id_buf=id_builder(msg, &id_len))==0){
576                         LOG(L_ERR, "ERROR: build_req_buf_from_sip_req:"
577                                                         " id_builder failed\n");
578                         goto error01; /* free everything */
579                 }
580                 extra_params.s=id_buf;
581                 extra_params.len=id_len;
582         }
583 #endif
584         branch.s=msg->add_to_branch_s;
585         branch.len=msg->add_to_branch_len;
586         line_buf = via_builder( &via_len, send_sock, &branch,
587                                                         extra_params.len?&extra_params:0, proto);
588         if (!line_buf){
589                 LOG(L_ERR,"ERROR: build_req_buf_from_sip_req: no via received!\n");
590                 goto error00;
591         }
592         /* check if received needs to be added */
593 #ifdef REMOVE_ALL_ZT
594         r=check_via_address(&msg->rcv.src_ip, &msg->via1->host, 
595                 msg->via1->port, received_dns);
596 #else
597         backup = msg->via1->host.s[msg->via1->host.len];
598         msg->via1->host.s[msg->via1->host.len] = 0;
599         r=check_address(&msg->rcv.src_ip, msg->via1->host.s, received_dns);
600         msg->via1->host.s[msg->via1->host.len] = backup;
601 #endif
602         if (r!=0){
603                 if ((received_buf=received_builder(msg,&received_len))==0){
604                         LOG(L_ERR, "ERROR: build_req_buf_from_sip_req:"
605                                                         " received_builder failed\n");
606                         goto error01;  /* free also line_buf */
607                 }
608         }
609         
610         /* check if rport needs to be updated */
611         if (msg->via1->rport && msg->via1->rport->value.s==0){
612                 if ((rport_buf=rport_builder(msg, &rport_len))==0){
613                         LOG(L_ERR, "ERROR: build_req_buf_from_sip_req:"
614                                                         " rport_builder failed\n");
615                         goto error01; /* free everything */
616                 }
617         }
618
619         /* add via header to the list */
620         /* try to add it before msg. 1st via */
621         /* add first via, as an anchor for second via*/
622         anchor=anchor_lump(&(msg->add_rm), msg->via1->hdr.s-buf, 0, HDR_VIA);
623         if (anchor==0) goto error01;
624         if (insert_new_lump_before(anchor, line_buf, via_len, HDR_VIA)==0)
625                 goto error01;
626         /* if received needs to be added, add anchor after host and add it */
627         if (received_len){
628                 if (msg->via1->params.s){
629                                 size= msg->via1->params.s-msg->via1->hdr.s-1; /*compensate
630                                                                                                                           for ';' */
631                 }else{
632                                 size= msg->via1->host.s-msg->via1->hdr.s+msg->via1->host.len;
633                                 if (msg->via1->port!=0){
634                                         /*size+=strlen(msg->via1->hdr.s+size+1)+1;*/
635                                         size += msg->via1->port_str.len + 1; /* +1 for ':'*/
636                                 }
637                         #ifdef USE_IPV6
638                                 if(send_sock->address.af==AF_INET6) size+=1; /* +1 for ']'*/
639                         #endif
640                 }
641                 anchor=anchor_lump(&(msg->add_rm),msg->via1->hdr.s-buf+size,0,
642                                 HDR_VIA);
643                 if (anchor==0) goto error02; /* free received_buf */
644                 if (insert_new_lump_after(anchor, received_buf, received_len, HDR_VIA)
645                                 ==0 ) goto error02; /* free received_buf */
646         }
647         /* if rport needs to be updated, delete it and add it's value */
648         if (rport_len){
649                 anchor=del_lump(&(msg->add_rm), msg->via1->rport->start-buf-1, /*';'*/
650                                                         msg->via1->rport->size+1 /* ; */, HDR_VIA);
651                 if (anchor==0) goto error03; /* free rport_buf*/
652                 if (insert_new_lump_after(anchor, rport_buf, rport_len, HDR_VIA)==0)
653                         goto error03; /* free rport_buf*/
654         }
655
656         /* compute new msg len and fix overlapping zones*/
657         new_len=len+lumps_len(msg->add_rm);
658
659         if (msg->new_uri.s){
660                 uri_len=msg->new_uri.len;
661                 new_len=new_len-msg->first_line.u.request.uri.len+uri_len;
662         }
663         new_buf=(char*)pkg_malloc(new_len+1);
664         if (new_buf==0){
665                 ser_error=E_OUT_OF_MEM;
666                 LOG(L_ERR, "ERROR: build_req_buf_from_sip_req: out of memory\n");
667                 goto error00;
668         }
669
670         offset=s_offset=0;
671         if (msg->new_uri.s){
672                 /* copy message up to uri */
673                 size=msg->first_line.u.request.uri.s-buf;
674 #ifdef SCRATCH
675                 memcpy(new_buf, orig, size);
676 #else
677                 memcpy(new_buf, buf, size);
678 #endif
679                 offset+=size;
680                 s_offset+=size;
681                 /* add our uri */
682                 memcpy(new_buf+offset, msg->new_uri.s, uri_len);
683                 offset+=uri_len;
684                 s_offset+=msg->first_line.u.request.uri.len; /* skip original uri */
685         }
686         new_buf[new_len]=0;
687 #ifdef SCRATCH
688         /* copy msg adding/removing lumps */
689         process_lumps(msg->add_rm, new_buf, &offset, orig, &s_offset);
690         /* copy the rest of the message */
691         memcpy(new_buf+offset, orig+s_offset, len-s_offset);
692 #else
693         /* copy msg adding/removing lumps */
694         process_lumps(msg->add_rm, new_buf, &offset, buf, &s_offset);
695         /* copy the rest of the message */
696         memcpy(new_buf+offset, buf+s_offset, len-s_offset);
697 #endif
698         new_buf[new_len]=0;
699
700 #ifdef DBG_MSG_QA
701         if (new_buf[new_len-1]==0) {
702                 LOG(L_ERR, "ERROR: build_req_buf_from_sip_req: 0 in the end\n");
703                 abort();
704         }
705 #endif
706
707         *returned_len=new_len;
708         return new_buf;
709
710 error01:
711         pkg_free(line_buf);
712 #ifdef USE_TCP
713         if (id_buf) pkg_free(id_buf);
714 #endif
715 error02:
716         if (received_buf) pkg_free(received_buf);
717 error03:
718         if (rport_buf) pkg_free(rport_buf);
719 error00:
720         *returned_len=0;
721         return 0;
722 }
723
724
725 char * build_res_buf_from_sip_res( struct sip_msg* msg,
726                                 unsigned int *returned_len)
727 {
728         unsigned int new_len, via_len;
729         char* new_buf;
730         unsigned offset, s_offset, via_offset;
731 #ifdef SCRATCH
732         char* orig;
733 #endif
734         char* buf;
735         unsigned int len;
736
737 #ifdef SCRATCH
738         orig=msg->orig;
739 #endif
740         buf=msg->buf;
741         len=msg->len;
742         new_buf=0;
743         /* we must remove the first via */
744 #ifdef PRESERVE_ZT
745         via_len=msg->via1->bsize;
746         via_offset=msg->via1->hdr.s-buf;
747         DBG("via len: %d, initial via offset: %d\n", via_len, via_offset);
748         if (msg->via1->next){
749                 /* add hdr size*/
750                 via_offset+=msg->via1->hdr.len+1;
751             DBG(" adjusted via len: %d, initial offset: %d\n",
752                                 via_len, via_offset);
753         }else{
754                 /* add hdr size ("Via:")*/
755                 via_len+=msg->via1->hdr.len+1;
756         }
757 #else
758         if (msg->via1->next) {
759                 via_len=msg->via1->bsize;
760                 via_offset=msg->h_via1->body.s-buf;
761         } else {
762                 via_len=msg->h_via1->len;
763                 via_offset=msg->h_via1->name.s-buf;
764         }
765 #endif
766         /* remove the first via*/
767         if (del_lump( &(msg->repl_add_rm), via_offset, via_len, HDR_VIA)==0){
768                 LOG(L_ERR, "build_res_buf_from_sip_res: error trying to remove first"
769                                         "via\n");
770                 goto error;
771         }
772         new_len=len+lumps_len(msg->repl_add_rm);
773
774         DBG(" old size: %d, new size: %d\n", len, new_len);
775         new_buf=(char*)pkg_malloc(new_len+1); /* +1 is for debugging 
776                                                                                          (\0 to print it )*/
777         if (new_buf==0){
778                 LOG(L_ERR, "ERROR: build_res_buf_from_sip_res: out of mem\n");
779                 goto error;
780         }
781         new_buf[new_len]=0; /* debug: print the message */
782         offset=s_offset=0;
783         process_lumps(msg->repl_add_rm, new_buf, &offset, 
784 #ifdef SCRATCH
785                 orig, 
786 #else
787                 buf,
788 #endif
789                 &s_offset);
790         /* copy the rest of the message */
791         memcpy(new_buf+offset,
792 #ifdef SCRATCH
793                 orig+s_offset, 
794 #else
795                 buf+s_offset, 
796 #endif
797                 len-s_offset);
798          /* send it! */
799         DBG(" copied size: orig:%d, new: %d, rest: %d\n",
800                         s_offset, offset,
801                         len-s_offset );
802
803         *returned_len=new_len;
804         return new_buf;
805 error:
806         *returned_len=0;
807         return 0;
808 }
809
810
811
812
813
814 char * build_res_buf_from_sip_req( unsigned int code, char *text,
815                                         char *new_tag, unsigned int new_tag_len,
816                                         struct sip_msg* msg, unsigned int *returned_len)
817 {
818         char              *buf, *p;
819         unsigned int      len,foo;
820         struct hdr_field  *hdr;
821         struct lump_rpl   *lump;
822         int               i;
823         char              backup;
824         char              *received_buf;
825         char              *rport_buf;
826         unsigned int      received_len;
827         unsigned int      rport_len;
828         unsigned int      delete_len;
829         char              *warning;
830         unsigned int      warning_len;
831         unsigned int      text_len;
832         int r;
833 #ifndef PRESERVE_ZT
834         char *after_body;
835 #endif
836         str to_tag;
837
838         received_buf=0;
839         received_len=0;
840         rport_buf=0;
841         rport_len=0;
842         delete_len=0;
843         buf=0;
844         /* make -Wall happy */
845         warning=0;
846
847         text_len=strlen(text);
848
849         /* force parsing all headers -- we want to return all
850         Via's in the reply and they may be scattered down to the
851         end of header (non-block Vias are a really poor property
852         of SIP :( ) */
853         if (parse_headers( msg, HDR_EOH, 0 )==-1) {
854                 LOG(L_ERR, "ERROR: build_res_buf_from_sip_req: "
855                         "alas, parse_headers failed\n");
856                 goto error00;
857         }
858
859         /* check if received needs to be added */
860         backup = msg->via1->host.s[msg->via1->host.len];
861         msg->via1->host.s[msg->via1->host.len] = 0;
862 #ifdef REMOVE_ALL_ZT
863         r=check_via_address(&msg->rcv.src_ip, &msg->via1->host, 
864                 msg->via1->port, received_dns);
865 #else
866         r=check_address(&msg->rcv.src_ip, msg->via1->host.s, received_dns);
867 #endif
868         msg->via1->host.s[msg->via1->host.len] = backup;
869         if (r!=0) {
870                 if ((received_buf=received_builder(msg,&received_len))==0) {
871                         LOG(L_ERR, "ERROR: build_res_buf_from_sip_req: "
872                                 "alas, received_builder failed\n");
873                         goto error00;
874                 }
875         }
876         /* check if rport needs to be updated */
877         if (msg->via1->rport && msg->via1->rport->value.s==0){
878                 if ((rport_buf=rport_builder(msg, &rport_len))==0){
879                         LOG(L_ERR, "ERROR: build_res_buf_from_sip_req:"
880                                                         " rport_builder failed\n");
881                         goto error01; /* free everything */
882                 }
883                 delete_len=msg->via1->rport->size+1; /* include ';' */
884         }
885
886         /*computes the lenght of the new response buffer*/
887         len = 0;
888         /* first line */
889         len += SIP_VERSION_LEN + 1/*space*/ + 3/*code*/ + 1/*space*/ +
890                 text_len + CRLF_LEN/*new line*/;
891         /*headers that will be copied (TO, FROM, CSEQ,CALLID,VIA)*/
892         for ( hdr=msg->headers ; hdr ; hdr=hdr->next ) {
893                 if (hdr->type==HDR_TO) {
894                         if (new_tag)
895                         {
896                                 to_tag=get_to(msg)->tag_value;
897                                 if (to_tag.s )
898                                         len+=new_tag_len-to_tag.len;
899                                 else
900                                         len+=new_tag_len+TOTAG_TOKEN_LEN/*";tag="*/;
901                         }
902 #ifndef PRESERVE_ZT
903                         else {
904                                 len+=hdr->len;
905                                 continue;
906                         }
907 #endif
908                 } else if (hdr->type==HDR_VIA) {
909                                 if (hdr==msg->h_via1) len += received_len+rport_len;
910                 } else if (hdr->type==HDR_RECORDROUTE) {
911                                 /* RR only for 1xx and 2xx replies */
912                                 if (code<180 || code>=300) continue;
913                 } else if (!(hdr->type==HDR_FROM 
914                                         || hdr->type==HDR_CALLID
915                                         || hdr->type==HDR_CSEQ)) {
916                         continue;
917                 }
918 #ifdef PRESERVE_ZT
919                 len += ((hdr->body.s+hdr->body.len )-hdr->name.s )+CRLF_LEN;
920 #else
921                 len += hdr->len;
922 #endif
923         }
924         len-=delete_len;
925         /*lumps length*/
926         for(lump=msg->reply_lump;lump;lump=lump->next)
927                 len += lump->text.len;
928         if (server_signature) {
929                 /*server header*/
930                 len += SERVER_HDR_LEN + CRLF_LEN;
931                 /*content length header*/
932                 len +=CONTENT_LENGTH_LEN+1 + CRLF_LEN;
933         }
934         if (sip_warning) {
935                 warning = warning_builder(msg,&warning_len);
936                 if (warning) len += warning_len + CRLF_LEN;
937                 else LOG(L_WARN, "WARNING: warning skipped -- too big\n");
938         }
939         /* end of message */
940         len += CRLF_LEN; /*new line*/
941         /*allocating mem*/
942         buf = (char*) pkg_malloc( len+1 );
943         if (!buf)
944         {
945                 LOG(L_ERR, "ERROR: build_res_buf_from_sip_req: out of memory "
946                         " ; needs %d\n",len);
947                 goto error01;
948         }
949
950         /* filling the buffer*/
951         p=buf;
952         /* first line */
953         memcpy( p , SIP_VERSION , SIP_VERSION_LEN );
954         p += SIP_VERSION_LEN;
955         *(p++) = ' ' ;
956         /*code*/
957         for ( i=2 , foo = code  ;  i>=0  ;  i-- , foo=foo/10 )
958                 *(p+i) = '0' + foo - ( foo/10 )*10;
959         p += 3;
960         *(p++) = ' ' ;
961         memcpy( p , text , text_len );
962         p += text_len;
963         memcpy( p, CRLF, CRLF_LEN );
964         p+=CRLF_LEN;
965         /* headers*/
966         for ( hdr=msg->headers ; hdr ; hdr=hdr->next )
967                 switch (hdr->type)
968                 {
969                         case HDR_VIA:
970                                 if (hdr==msg->h_via1){
971                                         if (rport_buf){
972                                                 /* copy until rport */
973                                                 append_str_trans( p, hdr->name.s ,
974                                                         msg->via1->rport->start-hdr->name.s-1,msg);
975                                                 /* copy new rport */
976                                                 append_str(p, rport_buf, rport_len);
977                                                 /* copy the rest of the via */
978                                                 append_str_trans(p, msg->via1->rport->start+
979                                                                                         msg->via1->rport->size, 
980                                                                                         hdr->body.s+hdr->body.len-
981                                                                                         msg->via1->rport->start-
982                                                                                         msg->via1->rport->size, msg);
983                                         }else{
984                                                 /* normal whole via copy */
985                                                 append_str_trans( p, hdr->name.s ,
986                                                         ((hdr->body.s+hdr->body.len )-hdr->name.s ), msg);
987                                         }
988                                         if (received_buf)
989                                                 append_str( p, received_buf, received_len);
990                                 }else{
991                                         /* normal whole via copy */
992                                         append_str_trans( p, hdr->name.s ,
993                                                 ((hdr->body.s+hdr->body.len )-hdr->name.s ),msg);
994                                 }
995                                 append_str( p, CRLF,CRLF_LEN);
996                                 break;
997                         case HDR_RECORDROUTE:
998                                 /* RR only for 1xx and 2xx replies */
999                                 if (code<180 || code>=300) break;
1000                         case HDR_TO:
1001                                 if (new_tag){
1002                                         if (to_tag.s ) { /* replacement */
1003 #ifdef PRESERVE_ZT
1004                                                 /* before to-tag */
1005                                                 append_str_trans( p, hdr->name.s ,
1006                                                         to_tag.s-hdr->name.s,msg);
1007                                                 /* to tag replacement */
1008                                                 append_str( p, new_tag,new_tag_len);
1009                                                 /* the rest after to-tag */
1010                                                 append_str_trans( p,to_tag.s+to_tag.len,
1011                                                         ((hdr->body.s+hdr->body.len )-
1012                                                         (to_tag.s+to_tag.len)),msg);
1013                                                 append_str( p, CRLF,CRLF_LEN);
1014 #else
1015                                                 /* before to-tag */
1016                                                 append_str( p, hdr->name.s, to_tag.s-hdr->name.s);
1017                                                 /* to tag replacement */
1018                                                 append_str( p, new_tag,new_tag_len);
1019                                                 /* the rest after to-tag */
1020                                                 append_str( p, to_tag.s+to_tag.len,
1021                                                         hdr->name.s+hdr->len-(to_tag.s+to_tag.len));
1022 #endif
1023                                         }else{ /* adding a new to-tag */
1024 #ifdef PRESERVE_ZT
1025                                                 append_str_trans( p, hdr->name.s ,
1026                                                         ((hdr->body.s+hdr->body.len )-hdr->name.s ),
1027                                                         msg);
1028                                                 append_str( p, TOTAG_TOKEN,TOTAG_TOKEN_LEN);
1029                                                 append_str( p, new_tag,new_tag_len);
1030                                                 append_str( p, CRLF,CRLF_LEN);
1031 #else
1032                                                 after_body=hdr->body.s+hdr->body.len;
1033                                                 append_str( p, hdr->name.s, after_body-hdr->name.s);
1034                                                 append_str(p, TOTAG_TOKEN, TOTAG_TOKEN_LEN);
1035                                                 append_str( p, new_tag,new_tag_len);
1036                                                 append_str( p, after_body, 
1037                                                                                 hdr->name.s+hdr->len-after_body);
1038 #endif
1039                                         }
1040                                         break;
1041                                 } /* no new to-tag -- proceed to 1:1 copying  */
1042                         case HDR_FROM:
1043                         case HDR_CALLID:
1044                         case HDR_CSEQ:
1045 #ifdef PRESERVE_ZT
1046                                         append_str_trans( p, hdr->name.s ,
1047                                                 ((hdr->body.s+hdr->body.len )-hdr->name.s ),msg);
1048                                         append_str( p, CRLF,CRLF_LEN);
1049 #else
1050                                         append_str(p, hdr->name.s, hdr->len);
1051 #endif
1052                 } /* for switch */
1053         /*lumps*/
1054         for(lump=msg->reply_lump;lump;lump=lump->next)
1055         {
1056                 memcpy(p,lump->text.s,lump->text.len);
1057                 p += lump->text.len;
1058         }
1059         if (server_signature) {
1060                 /*server header*/
1061                 memcpy( p, SERVER_HDR , SERVER_HDR_LEN );
1062                 p+=SERVER_HDR_LEN;
1063                 memcpy( p, CRLF, CRLF_LEN );
1064                 p+=CRLF_LEN;
1065                 /* content length header*/
1066                 memcpy( p, CONTENT_LENGTH "0" , CONTENT_LENGTH_LEN+1 );
1067                 p+=CONTENT_LENGTH_LEN+1;
1068                 memcpy( p, CRLF, CRLF_LEN );
1069                 p+=CRLF_LEN;
1070         }
1071         if (sip_warning && warning) {
1072                 memcpy( p, warning, warning_len);
1073                 p+=warning_len;
1074                 memcpy( p, CRLF, CRLF_LEN);
1075                 p+=CRLF_LEN;
1076         }
1077         /*end of message*/
1078         memcpy( p, CRLF, CRLF_LEN );
1079         p+=CRLF_LEN;
1080         *(p) = 0;
1081         *returned_len = len;
1082         /* in req2reply, received_buf is not introduced to lumps and
1083            needs to be deleted here
1084         */
1085         if (received_buf) pkg_free(received_buf);
1086         if (rport_buf) pkg_free(rport_buf);
1087         return buf;
1088
1089 error01:
1090         if (received_buf) pkg_free(received_buf);
1091         if (rport_buf) pkg_free(rport_buf);
1092 error00:
1093         *returned_len=0;
1094         return 0;
1095 }
1096
1097 /* return number of chars printed or 0 if space exceeded;
1098    assumes buffer sace of at least MAX_BRANCH_PARAM_LEN
1099  */
1100
1101 int branch_builder( unsigned int hash_index,
1102         /* only either parameter useful */
1103         unsigned int label, char * char_v,
1104         int branch,
1105         char *branch_str, int *len )
1106 {
1107
1108         char *begin;
1109         int size;
1110
1111 #ifdef _OBSOLETED
1112         /* no hash_id --- whoever called me wants to have
1113            very simple branch_id
1114         */
1115         if (hash_index==0) {
1116                 *branch_str='0';
1117                 *len=1;
1118                 return *len;
1119         }
1120 #endif
1121
1122         /* hash id provided ... start with it */
1123         size=MAX_BRANCH_PARAM_LEN;
1124         begin=branch_str;
1125         *len=0;
1126
1127         memcpy(begin, MCOOKIE, MCOOKIE_LEN );
1128         size-=MCOOKIE_LEN;begin+=MCOOKIE_LEN;
1129
1130         if (int2reverse_hex( &begin, &size, hash_index)==-1)
1131                 return 0;
1132
1133         if (size) {
1134                 *begin=BRANCH_SEPARATOR;
1135                 begin++; size--;
1136         } else return 0;
1137
1138         /* string with request's characteristic value ... use it ... */
1139         if (char_v) {
1140                 if (memcpy(begin,char_v,MD5_LEN)) {
1141                         begin+=MD5_LEN; size-=MD5_LEN;
1142                 } else return 0;
1143         } else { /* ... use the "label" value otherwise */
1144                 if (int2reverse_hex( &begin, &size, label )==-1)
1145                         return 0;
1146         }
1147
1148         if (size) {
1149                 *begin=BRANCH_SEPARATOR;
1150                 begin++; size--;
1151         } else return 0;
1152
1153         if (int2reverse_hex( &begin, &size, branch)==-1)
1154                 return 0;
1155
1156         *len=MAX_BRANCH_PARAM_LEN-size;
1157         return size;
1158                 
1159 }
1160
1161
1162 char* via_builder( unsigned int *len, 
1163         struct socket_info* send_sock,
1164         str* branch, str* extra_params, int proto )
1165 {
1166         unsigned int  via_len, extra_len;
1167         char               *line_buf;
1168         int max_len;
1169
1170
1171         max_len=MY_VIA_LEN+send_sock->address_str.len /* space in MY_VIA */
1172                 +2 /* just in case it is a v6 address ... [ ] */
1173                 +send_sock->port_no_str.len
1174                 +(branch?(MY_BRANCH_LEN+branch->len):0)
1175                 +(extra_params?extra_params->len:0)
1176                 +CRLF_LEN+1;
1177         line_buf=pkg_malloc( max_len );
1178         if (line_buf==0){
1179                 ser_error=E_OUT_OF_MEM;
1180                 LOG(L_ERR, "ERROR: via_builder: out of memory\n");
1181                 return 0;
1182         }
1183
1184         extra_len=0;
1185
1186         via_len=MY_VIA_LEN+send_sock->address_str.len; /*space included in MY_VIA*/
1187
1188         memcpy(line_buf, MY_VIA, MY_VIA_LEN-4); /* without "UPD " */
1189         if (proto==PROTO_UDP)
1190                 memcpy(line_buf+MY_VIA_LEN-4, "UDP ", 4);
1191         else if (proto==PROTO_TCP)
1192                 memcpy(line_buf+MY_VIA_LEN-4, "TCP ", 4);
1193         else{
1194                 LOG(L_CRIT, "BUG: via_builder: unknown proto %d\n", proto);
1195                 return 0;
1196         }
1197 #       ifdef USE_IPV6
1198         if (send_sock->address.af==AF_INET6) {
1199                 line_buf[MY_VIA_LEN]='[';
1200                 line_buf[MY_VIA_LEN+1+send_sock->address_str.len]=']';
1201                 extra_len=1;
1202                 via_len+=2; /* [ ]*/
1203         }
1204 #       endif
1205         memcpy(line_buf+MY_VIA_LEN+extra_len, send_sock->address_str.s,
1206                 send_sock->address_str.len);
1207         if (send_sock->port_no!=SIP_PORT){
1208                 memcpy(line_buf+via_len, send_sock->port_no_str.s,
1209                          send_sock->port_no_str.len);
1210                 via_len+=send_sock->port_no_str.len;
1211         }
1212
1213         /* branch parameter */
1214         if (branch){
1215                 memcpy(line_buf+via_len, MY_BRANCH, MY_BRANCH_LEN );
1216                 via_len+=MY_BRANCH_LEN;
1217                 memcpy(line_buf+via_len, branch->s, branch->len );
1218                 via_len+=branch->len;
1219         }
1220         /* extra params  */
1221         if (extra_params){
1222                 memcpy(line_buf+via_len, extra_params->s, extra_params->len);
1223                 via_len+=extra_params->len;
1224         }
1225         
1226         memcpy(line_buf+via_len, CRLF, CRLF_LEN);
1227         via_len+=CRLF_LEN;
1228         line_buf[via_len]=0; /* null terminate the string*/
1229
1230         *len = via_len;
1231         return line_buf;
1232 }