You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
kamailio/modules_s/mangler/contact_ops.c

728 lines
18 KiB

/*
* mangler module
*
* $Id$
*
* Copyright (C) 2001-2003 FhG Fokus
*
* This file is part of ser, a free SIP server.
*
* ser is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version
*
* For a license to use the ser software under conditions
* other than those described here, or to purchase support for this
* software, please contact iptel.org by e-mail at the following addresses:
* info@iptel.org
*
* ser is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* History:
* --------
* 2003-04-07 first version.
*/
#include "contact_ops.h"
#include "utils.h"
#include "common.h"
#include "../../mem/mem.h"
#include "../../data_lump.h"
#include "../../parser/hf.h"
#include "../../parser/parse_uri.h"
#include "../../parser/contact/parse_contact.h"
#include "../../ut.h"
#include "../../dset.h"
#include <stdio.h>
#include <string.h>
#define SIP_SCH "sip:"
#define SIP_SCH_LEN (sizeof(SIP_SCH)-1)
int
encode_contact (struct sip_msg *msg, char *encoding_prefix,char *public_ip)
{
contact_body_t *cb;
contact_t *c;
str* uri;
str newUri;
int res;
char separator;
/*
* I have a list of contacts in contact->parsed which is of type contact_body_t
* inside i have a contact->parsed->contact which is the head of the list of contacts
* inside it is a
* str uri;
* struct contact *next;
* I just have to visit each uri and encode each uri according to a scheme
*/
if ((msg->contact == NULL)&&((parse_headers(msg,HDR_CONTACT_F,0) == -1) ||
(msg->contact == NULL) ))
{
LOG(L_ERR,"ERROR: encode_contact: no Contact header present\n");
return -1;
}
separator = DEFAULT_SEPARATOR[0];
if (contact_flds_separator != NULL)
if (strlen(contact_flds_separator)>=1)
separator = contact_flds_separator[0];
if (msg->contact->parsed == NULL) parse_contact (msg->contact);
if (msg->contact->parsed != NULL)
{
cb = (contact_body_t *) msg->contact->parsed;
c = cb->contacts;
/* we visit each contact */
if (c != NULL)
{
uri = &c->uri;
res = encode_uri(msg, uri, encoding_prefix, public_ip,
separator, &newUri);
if (res != 0)
{
LOG (L_ERR,"ERROR: encode_contact: Failed encoding contact.Code %d\n", res);
return res;
}
else
if (patch (msg, uri->s, uri->len, newUri.s, newUri.len) < 0)
{
LOG (L_ERR,"ERROR: encode_contact: lumping failed in mangling port \n");
return -2;
}
/* encoding next contacts too?*/
#ifdef ENCODE_ALL_CONTACTS
while (c->next != NULL)
{
c = c->next;
uri = &c->uri;
res = encode_uri (msg, uri, encoding_prefix, public_ip,
separator, &newUri);
if (res != 0)
{
LOG(L_ERR,"ERROR: encode_contact: Failed encode_uri.Code %d\n",res);
#ifdef STRICT_CHECK
return res;
#endif
}
else
if (patch (msg, uri->s, uri->len, newUri.s, newUri.len)< 0)
{
LOG (L_ERR,"ERROR: encode_contact: lumping failed in mangling port \n");
return -3;
}
} /* while */
#endif /* ENCODE_ALL_CONTACTS */
} /* if c != NULL */
} /* end if */
else /* after parsing still NULL */
{
LOG(L_ERR,"ERROR: encode_contact: Unable to parse Contact header\n");
#ifdef EXTRA_DEBUG
printf("ERROR: encode_contact: Unable to parse Contact header\n");
#endif
return -4;
}
#ifdef EXTRA_DEBUG
fprintf (stdout,"---END--------ENCODE CONTACT-----------------\n");
#endif
return 1;
}
int
decode_contact (struct sip_msg *msg,char *unused1,char *unused2)
{
str* uri;
str newUri;
str dst_uri;
char separator;
int res;
separator = DEFAULT_SEPARATOR[0];
if (contact_flds_separator != NULL)
if (strlen(contact_flds_separator)>=1)
separator = contact_flds_separator[0];
if ((msg->new_uri.s == NULL) || (msg->new_uri.len == 0)) {
uri = &msg->first_line.u.request.uri;
}else{
uri = &msg->new_uri;
}
res = decode_uri (uri, separator, &newUri, &dst_uri);
if (res != 0) {
LOG (L_ERR,"ERROR: decode_contact:Failed decoding contact."
"Code %d\n", res);
return res;
} else {
/* we do not modify the original first line */
if (msg->new_uri.s)
pkg_free(msg->new_uri.s);
msg->new_uri = newUri;
msg->parsed_uri_ok=0;
msg->dst_uri = dst_uri;
ruri_mark_new();
}
return 1;
}
int
decode_contact_header (struct sip_msg *msg,char *unused1,char *unused2)
{
contact_body_t *cb;
contact_t *c;
str* uri;
str newUri;
char separator;
int res;
if ((msg->contact == NULL)&&((parse_headers(msg,HDR_CONTACT_F,0) == -1) ||
(msg->contact== NULL) ))
{
LOG(L_ERR,"ERROR: decode_contact_header: no Contact header present\n");
return -1;
}
separator = DEFAULT_SEPARATOR[0];
if (contact_flds_separator != NULL)
if (strlen(contact_flds_separator)>=1)
separator = contact_flds_separator[0];
if (msg->contact->parsed == NULL) parse_contact (msg->contact);
if (msg->contact->parsed != NULL)
{
cb = (contact_body_t *) msg->contact->parsed;
c = cb->contacts;
// we visit each contact
if (c != NULL)
{
uri = &c->uri;
res = decode_uri (uri, separator, &newUri, 0);
if (res != 0)
{
LOG (L_ERR,"ERROR: decode_contact_header:Failed decoding contact.Code %d\n", res);
#ifdef STRICT_CHECK
return res;
#endif
}
else
if (patch (msg, uri->s, uri->len, newUri.s, newUri.len) < 0)
{
LOG (L_ERR,"ERROR: decode_contact:lumping failed in mangling port \n");
return -2;
}
#ifdef DECODE_ALL_CONTACTS
while (c->next != NULL)
{
c = c->next;
uri = &c->uri;
res = decode_uri (uri, separator, &newUri, 0);
if (res != 0)
{
LOG (L_ERR,"ERROR: decode_contact: Failed decoding contact.Code %d\n",res);
#ifdef STRICT_CHECK
return res;
#endif
}
else
if (patch (msg, uri->s, uri->len, newUri.s, newUri.len) < 0)
{
LOG (L_ERR,"ERROR: decode_contact:lumping failed in mangling port \n");
return -3;
}
} // end while
#endif
} // if c!= NULL
} // end if
else // after parsing still NULL
{
LOG(L_ERR,"ERROR: decode_contact: Unable to parse Contact header\n");
return -4;
}
return 1;
}
static str s_tcp = STR_STATIC_INIT("tcp");
static str s_tls = STR_STATIC_INIT("tls");
static str s_sctp = STR_STATIC_INIT("sctp");
int
encode2format (struct sip_msg* msg, str* uri, struct uri_format *format)
{
int foo;
char *string, *pos, *start, *end;
struct sip_uri sipUri;
int scheme_len;
if (uri->s == NULL)
return -1;
string = uri->s;
pos = q_memchr (string, '<', uri->len);
if (pos != NULL) /* we are only interested of chars inside <> */
{
start = q_memchr (string, ':', uri->len);
if (start == NULL) return -2;
if (start - pos < 4) return -3;
if ((*(start-1)|0x20)=='s' && (start-pos)>4)
/* if it ends in s: it is a sips or tels uri */
scheme_len=4;
else
scheme_len=3;
start-=scheme_len;
end = strchr (start, '>');
if (end == NULL)
return -4; /* must be a match to < */
}
else /* we do not have <> */
{
pos=string;
start = q_memchr (string, ':', uri->len);
if (start == NULL)
return -5;
if (start - pos < 3)
return -6;
if ((*(start-1)|0x20)=='s' && (start-pos)>3)
/* if it ends in s: it is a sips or tels uri */
scheme_len=4;
else
scheme_len=3;
start = start - scheme_len;
end = string + uri->len;
}
memset(format,0,sizeof(struct uri_format));
format->first = start - string + scheme_len+1 /* ':' */;
format->second = end - string;
/* --------------------------testing ------------------------------- */
/* sip:gva@pass@10.0.0.1;;transport=udp>;expires=2 INCORECT BEHAVIOR OF parse_uri,myfunction works good */
foo = parse_uri (start, end - start, &sipUri);
if (foo != 0)
{
LOG(L_ERR,"ERROR: encode2format: parse_uri failed on [%.*s]."
"Code %d \n", uri->len, uri->s, foo);
return foo-10;
}
format->username = sipUri.user;
format->password = sipUri.passwd;
format->ip = sipUri.host;
format->port = sipUri.port;
format->protocol = sipUri.transport_val;
format->transport=sipUri.transport; /* the whole transport header */
format->rest.s = sipUri.port.s?(sipUri.port.s+sipUri.port.len):
(sipUri.host.s+sipUri.host.len);
format->rest.len = (int)(end-format->rest.s);
format->rcv_ip.s=ip_addr2a(&msg->rcv.src_ip);
format->rcv_ip.len=strlen(format->rcv_ip.s);
if (msg->rcv.src_port!=SIP_PORT){
format->rcv_port.s=
int2str(msg->rcv.src_port, &format->rcv_port.len);
}else{
format->rcv_port.s=0;
format->rcv_port.len=0;
}
if (msg->rcv.proto!=PROTO_UDP){
switch(msg->rcv.proto){
case PROTO_TCP:
format->rcv_proto=s_tcp;
break;
case PROTO_TLS:
format->rcv_proto=s_tls;
break;
case PROTO_SCTP:
format->rcv_proto=s_sctp;
break;
default:
BUG("unkown proto %d\n", msg->rcv.proto);
}
}else{
format->rcv_proto.s=0;
format->rcv_proto.len=0;
}
#ifdef EXTRA_DEBUG
fprintf (stdout, "transport=[%.*s] transportval=[%.*s]\n", sipUri.transport.len,sipUri.transport.s,sipUri.transport_val.len,sipUri.transport_val.s);
fprintf(stdout,"First %d,second %d\n",format->first,format->second);
#endif
return 0;
}
int
encode_uri (struct sip_msg* msg, str* uri, char *encoding_prefix,
char *public_ip,char separator, str * result)
{
struct uri_format format;
char *pos;
int foo,res;
result->s = NULL;
result->len = 0;
if (uri->len <= 1)
return -1; /* no contact or an invalid one */
if (public_ip == NULL)
{
LOG(L_ERR,"ERROR: encode_uri: Invalid NULL value for public_ip parameter\n");
return -2;
}
foo = encode2format (msg, uri, &format);
if (foo < 0)
{
LOG(L_ERR,"ERROR: encode_uri: Unable to encode Contact URI"
" [%.*s].Return code %d\n",uri->len, uri->s, foo);
return foo - 20;
}
/* a complete uri would be sip:username@ip:port;transport=protocol goes to
* sip:enc_pref*username*ip*port*protocol@public_ip
*/
foo = 1; /*strlen(separator); */
result->len = format.first + uri->s+uri->len - format.rest.s +
strlen (encoding_prefix) + foo +
format.username.len + foo +
format.password.len + foo +
format.ip.len + foo + format.port.len + foo +
format.protocol.len + foo + format.rcv_ip.len + foo +
format.rcv_port.len + foo + format.rcv_proto.len +
1 + strlen (public_ip);
/* adding one comes from @ */
result->s = pkg_malloc (result->len);
pos = result->s;
if (pos == NULL)
{
LOG(L_ERR,"ERROR: encode_uri:Unable to alloc memory\n");
return -3;
}
res = snprintf(pos,result->len,"%.*s%s%c%.*s%c%.*s%c%.*s%c%.*s%c%.*s%c"
"%.*s%c%.*s%c%.*s@",
format.first, uri->s,encoding_prefix,separator,
format.username.len,format.username.s,separator,
format.password.len,format.password.s,
separator,format.ip.len,format.ip.s,separator,format.port.len,
format.port.s,separator,format.protocol.len,format.protocol.s,
separator, format.rcv_ip.len, format.rcv_ip.s, separator,
format.rcv_port.len, format.rcv_port.s, separator,
format.rcv_proto.len, format.rcv_proto.s
);
if ((res < 0 )||(res>result->len))
{
LOG(L_ERR,"ERROR: encode_uri: Unable to construct new uri.\n");
if (result->s != NULL) pkg_free(result->s);
return -4;
}
pos = pos + res ;/* overwriting the \0 from snprintf */
memcpy (pos, public_ip, strlen (public_ip));
pos = pos + strlen (public_ip);
/* copy the rest of the parameters and the rest of uri line*/
memcpy (pos, format.rest.s, uri->s+uri->len - format.rest.s);
/*memcpy (pos, uri.s + format.second, uri.len - format.second);*/
/* Because called parse_uri format contains pointers to the inside of msg,
* must not deallocate */
return 0;
}
int
decode2format (str* uri, char separator, struct uri_format *format)
{
char *start, *end, *pos,*lastpos;
str tmp;
enum {EX_PREFIX=0,EX_USER,EX_PASS,EX_IP,EX_PORT,EX_PROT, EX_RCVIP,
EX_RCVPORT, EX_RCVPROTO, EX_FINAL} state;
memset (format, 0, sizeof(struct uri_format));
if (uri->s == NULL)
{
LOG(L_ERR,"ERROR: decode2format: Invalid parameter uri.It is NULL\n");
return -1;
}
/* sip:enc_pref*username*password*ip*port*protocol@public_ip */
start = q_memchr (uri->s, ':', uri->len);
if (start == NULL)
{
LOG(L_ERR,"ERROR: decode2format: Invalid SIP uri.Missing :\n");
return -2;
} /* invalid uri */
start = start + 1;
if (start >= (uri->s+uri->len)){
LOG(L_ERR, "ERROR: decode2format> Invalid sip uri: too short: %.*s\n",
uri->len, uri->s);
return -2;
}
format->first = start - uri->s;
/* start */
end = q_memchr(start,'@',uri->len-(start-uri->s));
if (end == NULL)
{
LOG(L_ERR,"ERROR: decode2format: Invalid SIP uri.Missing @\n");
return -3;/* no host address found */
}
#ifdef EXTRA_DEBUG
fprintf (stdout, "Decoding %.*s\n",(int)(long)(end-start), start);
#endif
state = EX_PREFIX;
lastpos = start;
for (pos = start;pos<end;pos++)
{
if (*pos == separator)
{
/* we copy between lastpos and pos */
tmp.len = pos - lastpos;
if (tmp.len>0) tmp.s = lastpos;
else tmp.s = NULL;
switch (state)
{
case EX_PREFIX: state = EX_USER;break;
case EX_USER:format->username = tmp;state = EX_PASS;break;
case EX_PASS:format->password = tmp;state = EX_IP;break;
case EX_IP:format->ip = tmp;state = EX_PORT;break;
case EX_PORT:format->port = tmp;state = EX_PROT;break;
case EX_PROT:
format->protocol=tmp;
state=EX_RCVIP;
break;
case EX_RCVIP:
format->rcv_ip=tmp;
state=EX_RCVPORT;
break;
case EX_RCVPORT:
format->rcv_port=tmp;
state=EX_RCVPROTO;
break;
default:
{
/* this should not happen, we should find @ not separator */
return -4;
break;
}
}
lastpos = pos+1;
}
else
if (((*pos) == '>')||(*pos == ';'))
{
/* invalid chars inside username part */
return -5;
}
}
/* we must be in state EX_RCVPROTO and protocol is between lastpos and
* end@ */
if (state != EX_RCVPROTO) return -6;
format->rcv_proto.len = end - lastpos;
if (format->rcv_proto.len>0) format->rcv_proto.s = lastpos;
/* I should check perhaps that after @ there is something */
/* looking for the end of public ip */
start = end;/*we are now at @ */
for(pos = start;pos<(uri->s+uri->len);pos++)
{
if ((*pos == ';')||(*pos == '>'))
{
/* found end */
format->second = pos - uri->s;
return 0;
}
}
/* if we are here we did not find > or ; */
format->second = uri->len;
return 0;
}
int
decode_uri (str* uri, char separator, str * result, str* dst_uri)
{
char *pos;
struct uri_format format;
int foo;
result->s = NULL;
result->len = 0;
if (dst_uri){
dst_uri->s=0;
dst_uri->len=0;
}
if ((uri->len <= 0) || (uri->s == NULL))
{
LOG(L_ERR,"ERROR: decode_uri: Invalid value for uri\n");
return -1;
}
foo = decode2format (uri, separator, &format);
if (foo < 0)
{
LOG(L_ERR,"ERROR: decode_uri: Error decoding Contact uri .Error code %d\n",foo);
return foo - 20;
}
/* sanity check */
if (format.ip.len <= 0)
{
LOG(L_ERR,"ERROR: decode_uri: Unable to decode host address \n");
return -2;/* should I quit or ignore ? */
}
if ((format.password.len > 0) && (format.username.len <= 0))
{
LOG(L_ERR,"ERROR: decode_uri: Password decoded but no username available\n");
return -3;
}
/* a complete uri would be sip:username:password@ip:port;transport=protocol goes to
* sip:enc_pref#username#password#ip#port#protocol@public_ip
*/
result->len = format.first + (uri->len - format.second); /* not NULL terminated */
if (format.username.len > 0) result->len += format.username.len + 1; //: or @
if (format.password.len > 0) result->len += format.password.len + 1; //@
/* if (format.ip.len > 0) */ result->len += format.ip.len;
if (format.port.len > 0) result->len += 1 + format.port.len; //:
if (format.protocol.len > 0) result->len += 1 + 10 + format.protocol.len; //;transport=
/* adding one comes from * */
result->s = pkg_malloc (result->len);
if (result->s == NULL)
{
LOG(L_ERR,"ERROR: decode_contact: Unable to allocate memory\n");
return -4;
}
pos = result->s;
memcpy (pos, uri->s, format.first); /* till sip: */
pos = pos + format.first;
if (format.username.len > 0)
{
memcpy (pos, format.username.s, format.username.len);
pos = pos + format.username.len;
if (format.password.len > 0)
memcpy (pos, ":", 1);
else
memcpy (pos, "@", 1);
pos = pos + 1;
}
if (format.password.len > 0)
{
memcpy (pos, format.password.s, format.password.len);
pos = pos + format.password.len;
memcpy (pos, "@", 1);
pos = pos + 1;
}
/* if (format.ip.len > 0) */
memcpy (pos, format.ip.s, format.ip.len);
pos = pos + format.ip.len;
if (format.port.len > 0)
{
memcpy (pos, ":", 1);
pos = pos + 1;
memcpy (pos, format.port.s, format.port.len);
pos = pos + format.port.len;
}
if (format.protocol.len > 0)
{
memcpy (pos, ";transport=", 11);
pos = pos + 11;
memcpy (pos, format.protocol.s, format.protocol.len);
pos = pos + format.protocol.len;
}
memcpy (pos, uri->s + format.second, uri->len - format.second); /* till end: */
/* dst_uri */
if (dst_uri && format.rcv_ip.s){
dst_uri->len=4 /* sip: */ + format.rcv_ip.len;
if (format.rcv_port.len){
dst_uri->len+=1 /* : */+format.rcv_port.len;
}
if (format.rcv_proto.len){
dst_uri->len+=TRANSPORT_PARAM_LEN+format.rcv_proto.len;
}
dst_uri->s=pkg_malloc(dst_uri->len);
if (dst_uri->s==0){
LOG(L_ERR,"ERROR: decode_contact: dst_uri: memory allocation"
" failed\n");
dst_uri->len=0;
pkg_free(result->s);
result->s=0;
result->len=0;
return -4;
}
pos=dst_uri->s;
memcpy(pos, SIP_SCH, SIP_SCH_LEN);
pos+=SIP_SCH_LEN;
memcpy(pos, format.rcv_ip.s, format.rcv_ip.len);
pos+=format.rcv_ip.len;
if (format.rcv_port.len){
*pos=':';
pos++;
memcpy(pos, format.rcv_port.s, format.rcv_port.len);
pos+=format.rcv_port.len;
}
if (format.rcv_proto.len){
memcpy(pos, TRANSPORT_PARAM, TRANSPORT_PARAM_LEN);
pos+=TRANSPORT_PARAM_LEN;
memcpy(pos, format.rcv_proto.s, format.rcv_proto.len);
}
}
return 0;
}