int osip_body_clone (const osip_body_t * body, osip_body_t ** dest) { int pos; int i; osip_body_t *copy; if (body == NULL || body->length<=0) return -1; i = osip_body_init (©); if (i != 0) return -1; copy->body = (char*)osip_malloc(body->length+2); copy->length = body->length; memcpy(copy->body,body->body,body->length); copy->body[body->length]='\0'; if (body->content_type != NULL) { i = osip_content_type_clone (body->content_type, &(copy->content_type)); if (i != 0) goto bc_error1; } { osip_header_t *header; osip_header_t *header2; pos = 0; while (!osip_list_eol (body->headers, pos)) { header = (osip_header_t *) osip_list_get (body->headers, pos); i = osip_header_clone (header, &header2); if (i != 0) goto bc_error1; osip_list_add (copy->headers, header2, -1); /* insert as last element */ pos++; } } *dest = copy; return 0; bc_error1: osip_body_free (copy); return -1; }
/** * Fill the body of message. * @param sip The structure to store results. * @param buf The pointer to the start of body. * @param length The length of body; */ int osip_message_set_body (osip_message_t * sip, const char *buf, size_t length) { osip_body_t *body; int i; i = osip_body_init (&body); if (i != 0) return -1; i = osip_body_parse (body, buf, length); if (i != 0) { osip_body_free (body); return -1; } sip->message_property = 2; osip_list_add (sip->bodies, body, -1); return 0; }
/* * PROXY_REWRITE_INVITATION_BODY * * rewrites the outgoing INVITATION request or response packet * * RETURNS * STS_SUCCESS on success * STS_FAILURE on error */ int proxy_rewrite_invitation_body(osip_message_t *mymsg, int direction){ osip_body_t *body; sdp_message_t *sdp; struct in_addr map_addr, addr_sess, addr_media, outside_addr, inside_addr; int sts; char *bodybuff; int bodybuflen; char clen[8]; /* content length: probably never more than 7 digits !*/ int map_port, msg_port; int media_stream_no; sdp_connection_t *sdp_conn; sdp_media_t *sdp_med; int rtp_direction=0; int have_c_media=0; if (configuration.rtp_proxy_enable == 0) return STS_SUCCESS; /* * get SDP structure */ sts = osip_message_get_body(mymsg, 0, &body); if (sts != 0) { #if 0 if ((MSG_IS_RESPONSE_FOR(mymsg,"INVITE")) && (MSG_IS_STATUS_1XX(mymsg))) { /* 1xx responses *MAY* contain SDP data */ DEBUGC(DBCLASS_PROXY, "rewrite_invitation_body: " "no body found in message"); return STS_SUCCESS; } else { /* INVITE request and 200 response *MUST* contain SDP data */ ERROR("rewrite_invitation_body: no body found in message"); return STS_FAILURE; } #else DEBUGC(DBCLASS_PROXY, "rewrite_invitation_body: " "no body found in message"); return STS_SUCCESS; #endif } sts = sip_body_to_str(body, &bodybuff, &bodybuflen); if (sts != 0) { ERROR("rewrite_invitation_body: unable to sip_body_to_str"); } sts = sdp_message_init(&sdp); sts = sdp_message_parse (sdp, bodybuff); if (sts != 0) { ERROR("rewrite_invitation_body: unable to sdp_message_parse body"); DUMP_BUFFER(-1, bodybuff, bodybuflen); osip_free(bodybuff); sdp_message_free(sdp); return STS_FAILURE; } osip_free(bodybuff); if (configuration.debuglevel) { /* just dump the buffer */ char *tmp, *tmp2; int tmplen; sts = osip_message_get_body(mymsg, 0, &body); sts = sip_body_to_str(body, &tmp, &tmplen); osip_content_length_to_str(mymsg->content_length, &tmp2); DEBUG("Body before rewrite (clen=%s, strlen=%i):\n%s\n----", tmp2, tmplen, tmp); osip_free(tmp); osip_free(tmp2); } /* * RTP proxy: get ready and start forwarding * start forwarding for each media stream ('m=' item in SIP message) */ /* get outbound address */ if (get_interface_ip(IF_OUTBOUND, &outside_addr) != STS_SUCCESS) { sdp_message_free(sdp); return STS_FAILURE; } /* get inbound address */ if (get_interface_ip(IF_INBOUND, &inside_addr) != STS_SUCCESS) { sdp_message_free(sdp); return STS_FAILURE; } /* figure out what address to use for RTP masquerading */ if (MSG_IS_REQUEST(mymsg)) { if (direction == DIR_INCOMING) { memcpy(&map_addr, &inside_addr, sizeof (map_addr)); rtp_direction = DIR_OUTGOING; } else { memcpy(&map_addr, &outside_addr, sizeof (map_addr)); rtp_direction = DIR_INCOMING; } } else /* MSG_IS_REPONSE(mymsg) */ { if (direction == DIR_INCOMING) { memcpy(&map_addr, &inside_addr, sizeof (map_addr)); rtp_direction = DIR_OUTGOING; } else { memcpy(&map_addr, &outside_addr, sizeof (map_addr)); rtp_direction = DIR_INCOMING; } } DEBUGC(DBCLASS_PROXY, "proxy_rewrite_invitation_body: SIP[%s %s] RTP[%s %s]", MSG_IS_REQUEST(mymsg)? "RQ" : "RS", (direction==DIR_INCOMING)? "IN" : "OUT", (rtp_direction==DIR_INCOMING)? "IN" : "OUT", utils_inet_ntoa(map_addr)); /* * first, check presence of a 'c=' item on session level */ if (sdp->c_connection==NULL || sdp->c_connection->c_addr==NULL) { /* * No 'c=' on session level, search on media level now * * According to RFC2327, ALL media description must * include a 'c=' item now: */ media_stream_no=0; while (!sdp_message_endof_media(sdp, media_stream_no)) { /* check if n'th media stream is present */ if (sdp_message_c_addr_get(sdp, media_stream_no, 0) == NULL) { ERROR("SDP: have no 'c=' on session level and neither " "on media level (media=%i)",media_stream_no); sdp_message_free(sdp); return STS_FAILURE; } media_stream_no++; } /* while */ } /* Required 'c=' items ARE present */ /* * rewrite 'c=' item on session level if present and not yet done. * remember the original address in addr_sess */ memset(&addr_sess, 0, sizeof(addr_sess)); if (sdp->c_connection && sdp->c_connection->c_addr) { sts = get_ip_by_host(sdp->c_connection->c_addr, &addr_sess); if (sts == STS_FAILURE) { ERROR("SDP: cannot resolve session 'c=' host [%s]", sdp->c_connection->c_addr); sdp_message_free(sdp); return STS_FAILURE; } /* * Rewrite * an IP address of 0.0.0.0 means *MUTE*, don't rewrite such */ if (strcmp(sdp->c_connection->c_addr, "0.0.0.0") != 0) { osip_free(sdp->c_connection->c_addr); sdp->c_connection->c_addr=osip_malloc(HOSTNAME_SIZE); sprintf(sdp->c_connection->c_addr, "%s", utils_inet_ntoa(map_addr)); } else { /* 0.0.0.0 - don't rewrite */ DEBUGC(DBCLASS_PROXY, "proxy_rewrite_invitation_body: " "got a MUTE c= record (on session level - legal?)"); } } /* * rewrite 'o=' item (originator) on session level if present. */ if (sdp->o_addrtype && sdp->o_addr) { if (strcmp(sdp->o_addrtype, "IP4") != 0) { ERROR("got IP6 in SDP originator - not yet suported by siproxd"); sdp_message_free(sdp); return STS_FAILURE; } osip_free(sdp->o_addr); sdp->o_addr=osip_malloc(HOSTNAME_SIZE); sprintf(sdp->o_addr, "%s", utils_inet_ntoa(map_addr)); } /* * loop through all media descritions, * start RTP proxy and rewrite them */ for (media_stream_no=0;;media_stream_no++) { /* check if n'th media stream is present */ if (sdp_message_m_port_get(sdp, media_stream_no) == NULL) break; /* * check if a 'c=' item is present in this media description, * if so -> rewrite it */ memset(&addr_media, 0, sizeof(addr_media)); have_c_media=0; sdp_conn=sdp_message_connection_get(sdp, media_stream_no, 0); if (sdp_conn && sdp_conn->c_addr) { if (strcmp(sdp_conn->c_addr, "0.0.0.0") != 0) { sts = get_ip_by_host(sdp_conn->c_addr, &addr_media); have_c_media=1; /* have a valid address */ osip_free(sdp_conn->c_addr); sdp_conn->c_addr=osip_malloc(HOSTNAME_SIZE); sprintf(sdp_conn->c_addr, "%s", utils_inet_ntoa(map_addr)); } else { /* 0.0.0.0 - don't rewrite */ DEBUGC(DBCLASS_PROXY, "proxy_rewrite_invitation_body: got a " "MUTE c= record (media level)"); } } /* start an RTP proxying stream */ if (sdp_message_m_port_get(sdp, media_stream_no)) { msg_port=atoi(sdp_message_m_port_get(sdp, media_stream_no)); if (msg_port > 0) { osip_uri_t *cont_url = NULL; char *client_id=NULL; /* try to get some additional UA specific unique ID. * Try: * 1) User part of Contact header * 2) Host part of Contact header (will be different * between internal UA and external UA) */ if (!osip_list_eol(mymsg->contacts, 0)) cont_url = ((osip_contact_t*)(mymsg->contacts->node->element))->url; if (cont_url) { client_id=cont_url->username; if (client_id == NULL) client_id=cont_url->host; } /* * do we have a 'c=' item on media level? * if not, use the same as on session level */ if (have_c_media == 0) { memcpy(&addr_media, &addr_sess, sizeof(addr_sess)); } /* * Am I running in front of the routing device? Then I cannot * use the external IP to bind a listen socket to, so force * the use of my inbound IP for listening. */ if ((rtp_direction == DIR_INCOMING) && (configuration.outbound_host) && (strcmp(configuration.outbound_host, "")!=0)) { DEBUGC(DBCLASS_PROXY, "proxy_rewrite_invitation_body: " "in-front-of-NAT-Router"); memcpy(&map_addr, &inside_addr, sizeof (map_addr)); } sts = rtp_start_fwd(osip_message_get_call_id(mymsg), client_id, rtp_direction, media_stream_no, map_addr, &map_port, addr_media, msg_port); if (sts == STS_SUCCESS) { /* and rewrite the port */ sdp_med=osip_list_get(sdp->m_medias, media_stream_no); if (sdp_med && sdp_med->m_port) { osip_free(sdp_med->m_port); sdp_med->m_port=osip_malloc(8); /* 5 digits, \0 + align */ sprintf(sdp_med->m_port, "%i", map_port); DEBUGC(DBCLASS_PROXY, "proxy_rewrite_invitation_body: " "m= rewrote port to [%i]",map_port); } else { ERROR("rewriting port in m= failed sdp_med=%p, " "m_number_of_port=%p", sdp_med, sdp_med->m_port); } } /* sts == success */ } /* if msg_port > 0 */ } else { /* no port defined - skip entry */ WARN("no port defined in m=(media) stream_no=%i", media_stream_no); continue; } } /* for media_stream_no */ /* remove old body */ sts = osip_list_remove(mymsg->bodies, 0); osip_body_free(body); /* dump new body */ sdp_message_to_str(sdp, &bodybuff); bodybuflen=strlen(bodybuff); /* free sdp structure */ sdp_message_free(sdp); /* include new body */ sip_message_set_body(mymsg, bodybuff, bodybuflen); if (sts != 0) { ERROR("rewrite_invitation_body: unable to sip_message_set_body body"); } /* free content length resource and include new one*/ osip_content_length_free(mymsg->content_length); mymsg->content_length=NULL; sprintf(clen,"%i",bodybuflen); sts = osip_message_set_content_length(mymsg, clen); /* free old body */ osip_free(bodybuff); if (configuration.debuglevel) { /* just dump the buffer */ char *tmp, *tmp2; int tmplen; sts = osip_message_get_body(mymsg, 0, &body); sts = sip_body_to_str(body, &tmp, &tmplen); osip_content_length_to_str(mymsg->content_length, &tmp2); DEBUG("Body after rewrite (clen=%s, strlen=%i):\n%s\n----", tmp2, tmplen, tmp); osip_free(tmp); osip_free(tmp2); } return STS_SUCCESS; }
/* * Processing. * */ int PLUGIN_PROCESS(int stage, sip_ticket_t *ticket){ /* stage contains the PLUGIN_* value - the stage of SIP processing. */ int sts; char *buff; size_t buflen; osip_body_t *body; sdp_message_t *sdp; int content_length; osip_content_type_t *content_type; char clen[8]; /* content length: probably never more than 7 digits !*/ // // check that we have the expected payload "application/sdp" // // get content length content_length=0; if (ticket->sipmsg && ticket->sipmsg->content_length && ticket->sipmsg->content_length->value) { sts=sscanf(ticket->sipmsg->content_length->value, "%i", &content_length); } // check if we have a content type defined and that payload length >0 content_type=osip_message_get_content_type(ticket->sipmsg); if ((content_length == 0) || (content_type == NULL) || (content_type->type == NULL) || (content_type->subtype == NULL)) { DEBUGC(DBCLASS_PLUGIN, "%s: no content", name); return STS_SUCCESS; } // check content type: must be "application/sdp" if ((strncmp(content_type->type, "application", sizeof("application")) != 0) || (strncmp(content_type->subtype, "sdp", sizeof("sdp")) != 0)) { DEBUGC(DBCLASS_PLUGIN, "%s: unsupported content-type %s/%s", name, content_type->type, content_type->subtype); return STS_SUCCESS; } DEBUGC(DBCLASS_PLUGIN, "%s: content-type %s/%s, size=%i", name, content_type->type, content_type->subtype, content_length); // // parse the payload // // get a pointer to the payload of the SIP packet sts = osip_message_get_body(ticket->sipmsg, 0, &body); if (sts != 0) { DEBUGC(DBCLASS_PLUGIN, "%s: no body found in message", name); return STS_SUCCESS; } // dump it into a buffer sts = sip_body_to_str(body, &buff, &buflen); if (sts != 0) { WARN("%s: unable to sip_body_to_str", name); return STS_SUCCESS; } // and parse it into an SDP structure sts = sdp_message_init(&sdp); sts = sdp_message_parse (sdp, buff); if (sts != 0) { WARN("%s: unable to sdp_message_parse() body", name); DUMP_BUFFER(-1, buff, buflen); osip_free(buff); buff=NULL; sdp_message_free(sdp); return STS_SUCCESS; } osip_free(buff); buff=NULL; // // now do the codec filtering magic... sdp_filter_codec(sdp); // // replace the original payload with the new modified payload // // remove old body from SIP packet sts = osip_list_remove(&(ticket->sipmsg->bodies), 0); osip_body_free(body); body=NULL; // dump new body to buffer sdp_message_to_str(sdp, &buff); buflen=strlen(buff); // free sdp structure (no longer needed) sdp_message_free(sdp); sdp=NULL; // put new body into SIP message sts=sip_message_set_body(ticket->sipmsg, buff, buflen); if (sts != 0) { ERROR("%s: unable to sip_message_set_body body", name); DUMP_BUFFER(-1, buff, buflen); buflen=0; } // free buffer osip_free(buff); buff=NULL; // // set new content length // // remove old content leght field osip_content_length_free(ticket->sipmsg->content_length); ticket->sipmsg->content_length=NULL; // set new content length sprintf(clen,"%ld",(long)buflen); sts = osip_message_set_content_length(ticket->sipmsg, clen); return STS_SUCCESS; }
void osip_message_free (osip_message_t * sip) { int pos = 0; if (sip == NULL) return; osip_free (sip->sip_method); osip_free (sip->sip_version); if (sip->req_uri != NULL) { osip_uri_free (sip->req_uri); } osip_free (sip->reason_phrase); { osip_accept_t *accept; while (!osip_list_eol (&sip->accepts, pos)) { accept = (osip_accept_t *) osip_list_get (&sip->accepts, pos); osip_list_remove (&sip->accepts, pos); osip_accept_free (accept); } } { osip_accept_encoding_t *accept_encoding; while (!osip_list_eol (&sip->accept_encodings, pos)) { accept_encoding = (osip_accept_encoding_t *) osip_list_get (&sip->accept_encodings, pos); osip_list_remove (&sip->accept_encodings, pos); osip_accept_encoding_free (accept_encoding); } } { osip_accept_language_t *accept_language; while (!osip_list_eol (&sip->accept_languages, pos)) { accept_language = (osip_accept_language_t *) osip_list_get (&sip->accept_languages, pos); osip_list_remove (&sip->accept_languages, pos); osip_accept_language_free (accept_language); } } { osip_alert_info_t *alert_info; while (!osip_list_eol (&sip->alert_infos, pos)) { alert_info = (osip_alert_info_t *) osip_list_get (&sip->alert_infos, pos); osip_list_remove (&sip->alert_infos, pos); osip_alert_info_free (alert_info); } } { osip_allow_t *al; while (!osip_list_eol (&sip->allows, pos)) { al = (osip_allow_t *) osip_list_get (&sip->allows, pos); osip_list_remove (&sip->allows, pos); osip_allow_free (al); } } { osip_authentication_info_t *al; while (!osip_list_eol (&sip->authentication_infos, pos)) { al = (osip_authentication_info_t *) osip_list_get (&sip-> authentication_infos, pos); osip_list_remove (&sip->authentication_infos, pos); osip_authentication_info_free (al); } } { osip_authorization_t *al; while (!osip_list_eol (&sip->authorizations, pos)) { al = (osip_authorization_t *) osip_list_get (&sip->authorizations, pos); osip_list_remove (&sip->authorizations, pos); osip_authorization_free (al); } } if (sip->call_id != NULL) { osip_call_id_free (sip->call_id); } { osip_call_info_t *call_info; while (!osip_list_eol (&sip->call_infos, pos)) { call_info = (osip_call_info_t *) osip_list_get (&sip->call_infos, pos); osip_list_remove (&sip->call_infos, pos); osip_call_info_free (call_info); } } { osip_contact_t *contact; while (!osip_list_eol (&sip->contacts, pos)) { contact = (osip_contact_t *) osip_list_get (&sip->contacts, pos); osip_list_remove (&sip->contacts, pos); osip_contact_free (contact); } } { osip_content_encoding_t *ce; while (!osip_list_eol (&sip->content_encodings, pos)) { ce = (osip_content_encoding_t *) osip_list_get (&sip->content_encodings, pos); osip_list_remove (&sip->content_encodings, pos); osip_content_encoding_free (ce); } } if (sip->content_length != NULL) { osip_content_length_free (sip->content_length); } if (sip->content_type != NULL) { osip_content_type_free (sip->content_type); } if (sip->cseq != NULL) { osip_cseq_free (sip->cseq); } { osip_error_info_t *error_info; while (!osip_list_eol (&sip->error_infos, pos)) { error_info = (osip_error_info_t *) osip_list_get (&sip->error_infos, pos); osip_list_remove (&sip->error_infos, pos); osip_error_info_free (error_info); } } if (sip->from != NULL) { osip_from_free (sip->from); } if (sip->mime_version != NULL) { osip_mime_version_free (sip->mime_version); } { osip_proxy_authenticate_t *al; while (!osip_list_eol (&sip->proxy_authenticates, pos)) { al = (osip_proxy_authenticate_t *) osip_list_get (&sip-> proxy_authenticates, pos); osip_list_remove (&sip->proxy_authenticates, pos); osip_proxy_authenticate_free (al); } } { osip_proxy_authentication_info_t *al; while (!osip_list_eol (&sip->proxy_authentication_infos, pos)) { al = (osip_proxy_authentication_info_t *) osip_list_get (&sip-> proxy_authentication_infos, pos); osip_list_remove (&sip->proxy_authentication_infos, pos); osip_proxy_authentication_info_free (al); } } { osip_proxy_authorization_t *proxy_authorization; while (!osip_list_eol (&sip->proxy_authorizations, pos)) { proxy_authorization = (osip_proxy_authorization_t *) osip_list_get (&sip-> proxy_authorizations, pos); osip_list_remove (&sip->proxy_authorizations, pos); osip_proxy_authorization_free (proxy_authorization); } } { osip_record_route_t *record_route; while (!osip_list_eol (&sip->record_routes, pos)) { record_route = (osip_record_route_t *) osip_list_get (&sip->record_routes, pos); osip_list_remove (&sip->record_routes, pos); osip_record_route_free (record_route); } } { osip_route_t *route; while (!osip_list_eol (&sip->routes, pos)) { route = (osip_route_t *) osip_list_get (&sip->routes, pos); osip_list_remove (&sip->routes, pos); osip_route_free (route); } } if (sip->to != NULL) { osip_to_free (sip->to); } { osip_via_t *via; while (!osip_list_eol (&sip->vias, pos)) { via = (osip_via_t *) osip_list_get (&sip->vias, pos); osip_list_remove (&sip->vias, pos); osip_via_free (via); } } { osip_www_authenticate_t *al; while (!osip_list_eol (&sip->www_authenticates, pos)) { al = (osip_www_authenticate_t *) osip_list_get (&sip->www_authenticates, pos); osip_list_remove (&sip->www_authenticates, pos); osip_www_authenticate_free (al); } } { osip_header_t *header; while (!osip_list_eol (&sip->headers, pos)) { header = (osip_header_t *) osip_list_get (&sip->headers, pos); osip_list_remove (&sip->headers, pos); osip_header_free (header); } } { osip_body_t *body; while (!osip_list_eol (&sip->bodies, pos)) { body = (osip_body_t *) osip_list_get (&sip->bodies, pos); osip_list_remove (&sip->bodies, pos); osip_body_free (body); } } osip_free (sip->message); osip_free (sip); }