int osip_uri_param_get_byname (osip_list_t * params, char *pname, osip_uri_param_t ** url_param) { int pos = 0; size_t pname_len; osip_uri_param_t *u_param; *url_param = NULL; if (pname == NULL) return -1; pname_len = strlen (pname); if (pname_len <= 0) return -1; while (!osip_list_eol (params, pos)) { size_t len; u_param = (osip_uri_param_t *) osip_list_get (params, pos); len = strlen (u_param->gname); if (pname_len == len && osip_strncasecmp (u_param->gname, pname, strlen (pname)) == 0) { *url_param = u_param; return 0; } pos++; } return -1; }
char *osip_strcasestr(const char *haystack, const char *needle) { char c, sc; size_t len; if ((c = *needle++) != 0) { c = tolower((unsigned char) c); len = strlen(needle); do { do { if ((sc = *haystack++) == 0) return (NULL); } while ((char) tolower((unsigned char) sc) != c); } while (osip_strncasecmp(haystack, needle, len) != 0); haystack--; } return (char *) haystack; }
/* * PROXY_RESPONSE * * RETURNS * STS_SUCCESS on success * STS_FAILURE on error * RFC3261 * Section 16.7: Proxy Behavior - Response Processing * 1. Find the appropriate response context * 2. Update timer C for provisional responses * 3. Remove the topmost Via * 4. Add the response to the response context * 5. Check to see if this response should be forwarded immediately * 6. When necessary, choose the best final response from the * response context * 7. Aggregate authorization header field values if necessary * 8. Optionally rewrite Record-Route header field values * 9. Forward the response * 10. Generate any necessary CANCEL requests * */ int proxy_response (sip_ticket_t *ticket) { int i; int sts; int type; struct in_addr sendto_addr; osip_via_t *via; int port; char *buffer; int buflen; osip_message_t *response; struct sockaddr_in *from; DEBUGC(DBCLASS_PROXY,"proxy_response"); if (ticket==NULL) { ERROR("proxy_response: called with NULL ticket"); return STS_FAILURE; } response=ticket->sipmsg; from=&ticket->from; /* * RFC 3261, Section 16.7 step 3 * Proxy Behavior - Response Processing - Remove my Via header field value */ /* remove my Via header line */ sts = sip_del_myvia(ticket); if (sts == STS_FAILURE) { DEBUGC(DBCLASS_PROXY,"not addressed to my VIA, ignoring response"); return STS_FAILURE; } /* * figure out if this is an request coming from the outside * world to one of our registered clients */ /* Ahhrghh...... a response seems to have NO contact information... * so let's take FROM instead... * the TO and FROM headers are EQUAL to the request - that means * they are swapped in their meaning for a response... */ #if _OLD_DIRECTION_EVALUATION type = 0; for (i=0; i<URLMAP_SIZE; i++) { if (urlmap[i].active == 0) continue; /* incoming response ('from' == 'masq') || ('from' == 'reg') */ if ((compare_url(response->from->url, urlmap[i].reg_url)==STS_SUCCESS) || (compare_url(response->from->url, urlmap[i].masq_url)==STS_SUCCESS)) { type=RESTYP_INCOMING; DEBUGC(DBCLASS_PROXY,"incoming response for %s@%s from outbound", response->from->url->username? response->from->url->username:"******", response->from->url->host? response->from->url->host : "*NULL*"); break; } /* outgoing response ('to' == 'reg') || ('to' == 'masq' ) */ if ((compare_url(response->to->url, urlmap[i].masq_url)==STS_SUCCESS) || (compare_url(response->to->url, urlmap[i].reg_url)==STS_SUCCESS)){ type=RESTYP_OUTGOING; DEBUGC(DBCLASS_PROXY,"outgoing response for %s@%s from inbound", response->from->url->username ? response->from->url->username : "******", response->from->url->host ? response->from->url->host : "*NULL*"); break; } } #else type = 0; /* * did I receive the telegram from a REGISTERED host? * -> it must be an OUTGOING response */ for (i=0; i<URLMAP_SIZE; i++) { struct in_addr tmp_addr; if (urlmap[i].active == 0) continue; if (get_ip_by_host(urlmap[i].true_url->host, &tmp_addr) == STS_FAILURE) { DEBUGC(DBCLASS_PROXY, "proxy_response: cannot resolve host [%s]", urlmap[i].true_url); } else { DEBUGC(DBCLASS_PROXY, "proxy_response: reghost:%s ip:%s", urlmap[i].true_url->host, utils_inet_ntoa(from->sin_addr)); if (memcmp(&tmp_addr, &from->sin_addr, sizeof(tmp_addr)) == 0) { type=RESTYP_OUTGOING; break; } } } /* * is the telegram directed to an internal registered host? * -> it must be an INCOMING response */ if (type == 0) { for (i=0; i<URLMAP_SIZE; i++) { if (urlmap[i].active == 0) continue; /* incoming response ('from' == 'masq') || ('from' == 'reg') */ if ((compare_url(response->from->url, urlmap[i].reg_url)==STS_SUCCESS) || (compare_url(response->from->url, urlmap[i].masq_url)==STS_SUCCESS)) { type=RESTYP_INCOMING; break; } } } /* &&&& Open Issue &&&& it has been seen with cross-provider calls that the FROM may be 'garbled' (e.g [email protected] for calls made sipphone -> FWD) How can we deal with this? Should I take into consideration the 'Via' headers? This is the only clue I have, pointing to the *real* UA. Maybe I should put in a 'siproxd' ftag value to recognize it as a header inserted by myself */ if ((type == 0) && (!osip_list_eol(response->vias, 0))) { osip_via_t *via; struct in_addr addr_via, addr_myself; int port_via, port_ua; /* get the via address */ via = (osip_via_t *) osip_list_get (response->vias, 0); DEBUGC(DBCLASS_PROXY, "proxy_response: check via [%s] for " "registered UA",via->host); sts=get_ip_by_host(via->host, &addr_via); if (sts == STS_FAILURE) { DEBUGC(DBCLASS_DNS, "proxy_response: cannot resolve VIA [%s]", via->host); } else { for (i=0; i<URLMAP_SIZE; i++) { if (urlmap[i].active == 0) continue; /* incoming response (1st via in list points to a registered UA) */ sts=get_ip_by_host(urlmap[i].true_url->host, &addr_myself); if (sts == STS_FAILURE) { DEBUGC(DBCLASS_DNS, "proxy_response: cannot resolve " "true_url [%s]", via->host); continue; } port_via=0; if (via->port) port_via=atoi(via->port); if (port_via <= 0) port_via=SIP_PORT; port_ua=0; if (urlmap[i].true_url->port) port_ua=atoi(urlmap[i].true_url->port); if (port_ua <= 0) port_ua=SIP_PORT; DEBUGC(DBCLASS_BABBLE, "proxy_response: checking for registered " "host [%s:%i] <-> [%s:%i]", urlmap[i].true_url->host, port_ua, via->host, port_via); if ((memcmp(&addr_myself, &addr_via, sizeof(addr_myself))==0) && (port_via == port_ua)) { type=RESTYP_INCOMING; break; } } } } #endif ticket->direction=type; /* * ok, we got a response that we are allowed to process. */ switch (type) { /* * from an external host to the internal masqueraded host */ case RESTYP_INCOMING: DEBUGC(DBCLASS_PROXY,"incoming response for %s@%s from outbound", response->from->url->username? response->from->url->username:"******", response->from->url->host? response->from->url->host : "*NULL*"); /* * Response for INVITE - deal with RTP data in body and * start RTP proxy stream(s). In case * of a negative answer, stop RTP stream */ if (MSG_IS_RESPONSE_FOR(response,"INVITE")) { /* positive response, start RTP stream */ if ((MSG_IS_STATUS_1XX(response)) || (MSG_IS_STATUS_2XX(response))) { if (configuration.rtp_proxy_enable == 1) { sts = proxy_rewrite_invitation_body(response, DIR_INCOMING); } /* negative - stop a possibly started RTP stream */ } else if ((MSG_IS_STATUS_4XX(response)) || (MSG_IS_STATUS_5XX(response)) || (MSG_IS_STATUS_6XX(response))) { rtp_stop_fwd(osip_message_get_call_id(response), DIR_INCOMING); rtp_stop_fwd(osip_message_get_call_id(response), DIR_OUTGOING); } } /* if INVITE */ /* * Response for REGISTER - special handling of Contact header */ if (MSG_IS_RESPONSE_FOR(response,"REGISTER")) { /* * REGISTER returns *my* Contact header information. * Rewrite Contact header back to represent the true address. * Other responses do return the Contact header of the sender. */ sip_rewrite_contact(ticket, DIR_INCOMING); } /* * Response for SUBSCRIBE * * HACK for Grandstream SIP phones (with newer firmware like 1.0.4.40): * They send a SUBSCRIBE request to the registration server. In * case of beeing registering directly to siproxd, this request of * course will eventually be forwarded back to the same UA. * Grandstream then does reply with an '202' response (A 202 * response merely indicates that the subscription has been * understood, and that authorization may or may not have been * granted), which then of course is forwarded back to the phone. * Ans it seems that the Grandstream can *not* *handle* this * response, as it immediately sends another SUBSCRIBE request. * And this games goes on and on and on... * * As a workaround we will transform any 202 response to a * '404 unknown destination' * */ { osip_header_t *ua_hdr=NULL; osip_message_get_user_agent(response, 0, &ua_hdr); if (ua_hdr && ua_hdr->hvalue && (osip_strncasecmp(ua_hdr->hvalue,"grandstream", 11)==0) && (MSG_IS_RESPONSE_FOR(response,"SUBSCRIBE")) && (MSG_TEST_CODE(response, 202))) { DEBUGC(DBCLASS_PROXY, "proxy_response: Grandstream hack 202->404"); response->status_code=404; } } break; /* * from the internal masqueraded host to an external host */ case RESTYP_OUTGOING: DEBUGC(DBCLASS_PROXY,"outgoing response for %s@%s from inbound", response->from->url->username ? response->from->url->username : "******", response->from->url->host ? response->from->url->host : "*NULL*"); /* rewrite Contact header to represent the masqued address */ sip_rewrite_contact(ticket, DIR_OUTGOING); /* * If an 2xx OK or 1xx response, answer to an INVITE request, * rewrite body * * In case of a negative answer, stop RTP stream */ if (MSG_IS_RESPONSE_FOR(response,"INVITE")) { /* positive response, start RTP stream */ if ((MSG_IS_STATUS_1XX(response)) || (MSG_IS_STATUS_2XX(response))) { /* This is an outgoing response, therefore an outgoing stream */ sts = proxy_rewrite_invitation_body(response, DIR_OUTGOING); /* megative - stop a possibly started RTP stream */ } else if ((MSG_IS_STATUS_4XX(response)) || (MSG_IS_STATUS_5XX(response)) || (MSG_IS_STATUS_6XX(response))) { rtp_stop_fwd(osip_message_get_call_id(response), DIR_INCOMING); rtp_stop_fwd(osip_message_get_call_id(response), DIR_OUTGOING); } } /* if INVITE */ break; default: DEBUGC(DBCLASS_PROXY, "response from/to unregistered UA (%s@%s)", response->from->url->username? response->from->url->username:"******", response->from->url->host? response->from->url->host : "*NULL*"); return STS_FAILURE; } /* * for ALL incoming response include my Record-Route header. * The local UA will probably send its answer to the topmost * Route Header (8.1.2 of RFC3261) */ if (type == RESTYP_INCOMING) { DEBUGC(DBCLASS_PROXY,"Adding my Record-Route"); route_add_recordroute(ticket); } else { /* * outgoing packets must not have my record route header, as * this likely will contain a private IP address (my inbound). */ DEBUGC(DBCLASS_PROXY,"Purging Record-Routes (outgoing packet)"); route_purge_recordroute(ticket); } /* * Determine Next-Hop Address */ /*&&&& priority probably should be: * 1) Route header * 2) fixed outbound proxy * 3) SIP URI */ /* * check if we need to send to an outbound proxy */ if ((type == RESTYP_OUTGOING) && (sip_find_outbound_proxy(ticket, &sendto_addr, &port) == STS_SUCCESS)) { DEBUGC(DBCLASS_PROXY, "proxy_response: have outbound proxy %s:%i", utils_inet_ntoa(sendto_addr), port); /* * Route present? * If so, fetch address from topmost Route: header and remove it. */ } else if ((type == RESTYP_OUTGOING) && (response->routes && !osip_list_eol(response->routes, 0))) { sts=route_determine_nexthop(ticket, &sendto_addr, &port); if (sts == STS_FAILURE) { DEBUGC(DBCLASS_PROXY, "proxy_response: route_determine_nexthop failed"); return STS_FAILURE; } DEBUGC(DBCLASS_PROXY, "proxy_response: have Route header to %s:%i", utils_inet_ntoa(sendto_addr), port); } else { /* get target address and port from VIA header */ via = (osip_via_t *) osip_list_get (response->vias, 0); if (via == NULL) { ERROR("proxy_response: list_get via failed"); return STS_FAILURE; } sts = get_ip_by_host(via->host, &sendto_addr); if (sts == STS_FAILURE) { DEBUGC(DBCLASS_PROXY, "proxy_response: cannot resolve VIA [%s]", via->host); return STS_FAILURE; } if (via->port) { port=atoi(via->port); } else { port=SIP_PORT; } } sts = sip_message_to_str(response, &buffer, &buflen); if (sts != 0) { ERROR("proxy_response: sip_message_to_str failed"); return STS_FAILURE; } sipsock_send(sendto_addr, port, ticket->protocol, buffer, buflen); osip_free (buffer); return STS_SUCCESS; }
int __osip_quoted_string_set (const char *name, const char *str, char **result, const char **next) { *next = str; if (*result != NULL) return OSIP_SUCCESS; /* already parsed */ *next = NULL; while ((' ' == *str) || ('\t' == *str) || (',' == *str)) if (*str) str++; else return OSIP_SYNTAXERROR; /* bad header format */ if (osip_strncasecmp (name, str, strlen (name)) == 0) { const char *quote1; const char *quote2; const char *tmp; const char *hack = strchr (str, '='); if (hack == NULL) return OSIP_SYNTAXERROR; while (' ' == *(hack - 1)) /* get rid of extra spaces */ hack--; if ((size_t) (hack - str) != strlen (name)) { *next = str; return OSIP_SUCCESS; } quote1 = __osip_quote_find (str); if (quote1 == NULL) return OSIP_SYNTAXERROR; /* bad header format... */ quote2 = __osip_quote_find (quote1 + 1); if (quote2 == NULL) return OSIP_SYNTAXERROR; /* bad header format... */ if (quote2 - quote1 == 1) { /* this is a special case! The quote contains nothing! */ /* example: Digest opaque="",cnonce="" */ /* in this case, we just forget the parameter... this */ /* this should prevent from user manipulating empty */ /* strings */ tmp = quote2 + 1; /* next element start here */ for (; *tmp == ' ' || *tmp == '\t'; tmp++) { } for (; *tmp == '\n' || *tmp == '\r'; tmp++) { } /* skip LWS */ *next = NULL; if (*tmp == '\0') /* end of header detected */ return OSIP_SUCCESS; if (*tmp != '\t' && *tmp != ' ') /* LWS here ? */ *next = tmp; else { /* it is: skip it... */ for (; *tmp == ' ' || *tmp == '\t'; tmp++) { } if (*tmp == '\0') /* end of header detected */ return OSIP_SUCCESS; *next = tmp; } return OSIP_SUCCESS; } *result = (char *) osip_malloc (quote2 - quote1 + 3); if (*result == NULL) return OSIP_NOMEM; osip_strncpy (*result, quote1, quote2 - quote1 + 1); tmp = quote2 + 1; /* next element start here */ for (; *tmp == ' ' || *tmp == '\t'; tmp++) { } for (; *tmp == '\n' || *tmp == '\r'; tmp++) { } /* skip LWS */ *next = NULL; if (*tmp == '\0') /* end of header detected */ return OSIP_SUCCESS; if (*tmp != '\t' && *tmp != ' ') /* LWS here ? */ *next = tmp; else { /* it is: skip it... */ for (; *tmp == ' ' || *tmp == '\t'; tmp++) { } if (*tmp == '\0') /* end of header detected */ return OSIP_SUCCESS; *next = tmp; } } else *next = str; /* wrong header asked! */ return OSIP_SUCCESS; }
int __osip_token_set (const char *name, const char *str, char **result, const char **next) { const char *beg; const char *tmp; *next = str; if (*result != NULL) return OSIP_SUCCESS; /* already parsed */ *next = NULL; beg = strchr (str, '='); if (beg == NULL) return OSIP_SYNTAXERROR; /* bad header format... */ if (strlen (str) < 6) return OSIP_SUCCESS; /* end of header... */ while ((' ' == *str) || ('\t' == *str) || (',' == *str)) if (*str) str++; else return OSIP_SYNTAXERROR; /* bad header format */ if (osip_strncasecmp (name, str, strlen (name)) == 0) { const char *end; end = strchr (str, ','); if (end == NULL) end = str + strlen (str); /* This is the end of the header */ if (end - beg < 2) return OSIP_SYNTAXERROR; *result = (char *) osip_malloc (end - beg); if (*result == NULL) return OSIP_NOMEM; osip_clrncpy (*result, beg + 1, end - beg - 1); /* make sure the element does not contain more parameter */ tmp = (*end) ? (end + 1) : end; for (; *tmp == ' ' || *tmp == '\t'; tmp++) { } for (; *tmp == '\n' || *tmp == '\r'; tmp++) { } /* skip LWS */ *next = NULL; if (*tmp == '\0') /* end of header detected */ return OSIP_SUCCESS; if (*tmp != '\t' && *tmp != ' ') /* LWS here ? */ *next = tmp; else { /* it is: skip it... */ for (; *tmp == ' ' || *tmp == '\t'; tmp++) { } if (*tmp == '\0') /* end of header detected */ return OSIP_SUCCESS; *next = tmp; } } else *next = str; /* next element start here */ return OSIP_SUCCESS; }
static int osip_body_parse_header (osip_body_t * body, const char *start_of_osip_body_header, const char **next_body) { const char *start_of_line; const char *end_of_line; const char *colon_index; char *hname; char *hvalue; int i; *next_body = NULL; start_of_line = start_of_osip_body_header; for (;;) { i = __osip_find_next_crlf (start_of_line, &end_of_line); if (i == -1) return -1; /* error case: no end of body found */ /* find the headere name */ colon_index = strchr (start_of_line, ':'); if (colon_index == NULL) return -1; /* this is also an error case */ if (colon_index - start_of_line + 1 < 2) return -1; hname = (char *) osip_malloc (colon_index - start_of_line + 1); if (hname == NULL) return -1; osip_strncpy (hname, start_of_line, colon_index - start_of_line); osip_clrspace (hname); if ((end_of_line - 2) - colon_index < 2) return -1; hvalue = (char *) osip_malloc ((end_of_line - 2) - colon_index); if (hvalue == NULL) { osip_free (hname); return -1; } osip_strncpy (hvalue, colon_index + 1, (end_of_line - 2) - colon_index - 1); osip_clrspace (hvalue); /* really store the header in the sip structure */ if (osip_strncasecmp (hname, "content-type", 12) == 0) i = osip_body_set_contenttype (body, hvalue); else i = osip_body_set_header (body, hname, hvalue); osip_free (hname); osip_free (hvalue); if (i == -1) return -1; if (strncmp (end_of_line, CRLF, 2) == 0 || strncmp (end_of_line, "\n", 1) == 0 || strncmp (end_of_line, "\r", 1) == 0) { *next_body = end_of_line; return 0; } start_of_line = end_of_line; } }
int ice_sound_send_stun_request(RtpSession *session, struct CandidatePair *remote_candidates, int round) { int roll=250; #if 0 /* in "passive" mode (UA not behind a NATor behind a full cone NAT), wait a few delay before sending the first STUN request: this help to traverse */ if (session->setup_passive>0) { return 0; } #endif if (remote_candidates==NULL) return 0; if (round>500) roll=2*roll; if (round%roll==50) { int pos; #if 0 /* do this only with application that support this */ if (osip_strncasecmp(remote_useragent, "linphone/", 8)!=0) { /* use stun only with linphone to linphone softphone */ return 0; } #endif for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.ipaddr[0]!='\0';pos++) { int media_socket = rtp_session_get_rtp_socket(session); StunAddress4 stunServerAddr; StunAtrString username; StunAtrString password; bool res; int pad_size; struct CandidatePair *cand_pair = &remote_candidates[pos]; username.sizeValue = 0; password.sizeValue = 0; /* set username to L3:1:R2:1 */ snprintf(username.value, sizeof(username.value), "%s:%i:%s:%i", cand_pair->local_candidate.candidate_id, 1, cand_pair->remote_candidate.candidate_id, 1); username.sizeValue = (UInt16)strlen(username.value); pad_size = username.sizeValue % 4; username.value[username.sizeValue]='\0'; username.value[username.sizeValue+1]='\0'; username.value[username.sizeValue+2]='\0'; username.value[username.sizeValue+3]='\0'; username.sizeValue = username.sizeValue + 4 - pad_size; snprintf(password.value, sizeof(password.value), "%s", cand_pair->remote_candidate.password); password.sizeValue = (UInt16)strlen(password.value); #if 0 pad_size = password.sizeValue%4; password.value[password.sizeValue]='\0'; password.value[password.sizeValue+1]='\0'; password.value[password.sizeValue+2]='\0'; password.value[password.sizeValue+3]='\0'; password.sizeValue = password.sizeValue + pad_size; #endif res = stunParseServerName(cand_pair->remote_candidate.ipaddr, &stunServerAddr); if ( res == true ) { stunServerAddr.port = cand_pair->remote_candidate.port; ice_sendtest(media_socket, &stunServerAddr, &username, &password, 1, 0/*false*/, &(cand_pair->tid)); } } } return 0; }
int __osip_nict_init (osip_nict_t ** nict, osip_t * osip, osip_message_t * request) { osip_route_t *route; int i; time_t now; OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_INFO2, NULL, "allocating NICT context\n")); *nict = (osip_nict_t *) osip_malloc (sizeof (osip_nict_t)); if (*nict == NULL) return -1; now = time (NULL); #ifndef DISABLE_MEMSET memset (*nict, 0, sizeof (osip_nict_t)); #else (*ict)->destination = NULL; #endif /* for REQUEST retransmissions */ { osip_via_t *via; char *proto; i = osip_message_get_via (request, 0, &via); /* get top via */ if (i != 0) goto ii_error_1; proto = via_get_protocol (via); if (proto == NULL) goto ii_error_1; i = osip_strncasecmp (proto, "TCP", 3); if (i != 0) { /* for other reliable protocol than TCP, the timer must be desactived by the external application */ (*nict)->timer_e_length = DEFAULT_T1; (*nict)->timer_e_start = now; /* started */ (*nict)->timer_k_length = DEFAULT_T4; (*nict)->timer_k_start = -1; /* not started */ } else { /* TCP is used: */ (*nict)->timer_e_length = -1; /* E is not ACTIVE */ (*nict)->timer_e_start = -1; (*nict)->timer_k_length = 0; /* MUST do the transition immediatly */ (*nict)->timer_k_start = -1; /* not started */ } } /* for PROXY, the destination MUST be set by the application layer, this one may not be correct. */ osip_message_get_route (request, 0, &route); if (route != NULL) { int port = 5060; if (route->url->port != NULL) port = osip_atoi (route->url->port); osip_nict_set_destination ((*nict), osip_strdup (route->url->host), port); } else (*nict)->port = 5060; (*nict)->timer_f_length = 64 * DEFAULT_T1; (*nict)->timer_f_start = now; /* started */ /* Oups! a Bug! */ /* (*nict)->port = 5060; */ return 0; ii_error_1: osip_free (*nict); return -1; }
int osip_message_set_multiple_header (osip_message_t * sip, char *hname, char *hvalue) { int i; char *ptr, *p; /* current location of the search */ char *comma; /* This is the separator we are elooking for */ char *beg; /* beg of a header */ char *end; /* end of a header */ int inquotes, inuri; /* state for inside/outside of double-qoutes or URI */ size_t hname_len; /* Find header based upon lowercase comparison */ osip_tolower (hname); if (hvalue == NULL) { i = osip_message_set__header (sip, hname, hvalue); if (i != 0) return i; return OSIP_SUCCESS; } ptr = hvalue; comma = strchr (ptr, ','); hname_len = strlen (hname); if (comma == NULL || (hname_len == 4 && strncmp (hname, "date", 4) == 0) || (hname_len == 1 && strncmp (hname, "t", 1) == 0) || (hname_len == 2 && strncmp (hname, "to", 2) == 0) || (hname_len == 1 && strncmp (hname, "f", 1) == 0) || (hname_len == 4 && strncmp (hname, "from", 4) == 0) || (hname_len == 1 && strncmp (hname, "i", 1) == 0) || (hname_len == 7 && strncmp (hname, "call-id", 7) == 0) || (hname_len == 4 && strncmp (hname, "cseq", 4) == 0) || (hname_len == 1 && strncmp (hname, "s", 1) == 0) || (hname_len == 7 && strncmp (hname, "subject", 7) == 0) || (hname_len == 7 && strncmp (hname, "expires", 7) == 0) || (hname_len == 6 && strncmp (hname, "server", 6) == 0) || (hname_len == 10 && strncmp (hname, "user-agent", 10) == 0) || (hname_len == 16 && strncmp (hname, "www-authenticate", 16) == 0) || (hname_len == 19 && strncmp (hname, "authentication-info", 19) == 0) || (hname_len == 18 && strncmp (hname, "proxy-authenticate", 18) == 0) || (hname_len == 19 && strncmp (hname, "proxy-authorization", 19) == 0) || (hname_len == 25 && strncmp (hname, "proxy-authentication-info", 25) == 0) || (hname_len == 12 && strncmp (hname, "organization", 12) == 0) || (hname_len == 13 && strncmp (hname, "authorization", 13) == 0) || (hname_len == 1 && strncmp (hname, "r", 1) == 0) /* refer-to */ || (hname_len == 8 && strncmp (hname, "refer-to", 8) == 0) || (hname_len == 1 && strncmp (hname, "b", 1) == 0) /* referred-by */ || (hname_len == 11 && strncmp (hname, "referred-by", 11) == 0)) /* there is no multiple header! likely */ /* to happen most of the time... */ /* or hname is a TEXT-UTF8-TRIM and may */ /* contain a comma. this is not a separator */ /* THIS DOES NOT WORK FOR UNKNOWN HEADER!!!! */ { i = osip_message_set__header (sip, hname, hvalue); if (i != 0) return i; return OSIP_SUCCESS; } beg = hvalue; inquotes = 0; inuri = 0; /* Seach for a comma that is not within quotes or a URI */ for (;; ptr++) { switch (*ptr) { case '"': /* Check that the '"' is not escaped */ for (i = 0, p = ptr; p >= beg && *p == '\\'; p--, i++); if (i % 2 == 0) inquotes = !inquotes; /* the '"' was not escaped */ break; case '<': if (!inquotes) { if (!inuri) { if((osip_strncasecmp(ptr+1, "sip:", 4) == 0 || osip_strncasecmp(ptr+1, "sips:", 5) == 0 || osip_strncasecmp(ptr+1, "http:", 5) == 0 || osip_strncasecmp(ptr+1, "https:", 6) == 0 || osip_strncasecmp(ptr+1, "tel:", 4) == 0) && strchr(ptr, '>')) inuri = 1; } /* else { if we found such sequence: "<sip:" "<sip:" ">" It might be a valid header containing data and not URIs. Thus, we ignore inuri } */ } break; case '>': if (!inquotes) { if (inuri) inuri = 0; } break; case '\0': /* we discard any validation we tried: no valid uri detected */ inquotes=0; inuri=0; case ',': if (!inquotes && !inuri) { char *avalue; if (beg[0] == '\0') return OSIP_SUCCESS; /* empty header */ end = ptr; if (end - beg + 1 < 2) { beg=end+1; break; /* skip empty header */ } avalue = (char *) osip_malloc (end - beg + 1); if (avalue==NULL) return OSIP_NOMEM; osip_clrncpy (avalue, beg, end - beg); /* really store the header in the sip structure */ i = osip_message_set__header (sip, hname, avalue); osip_free (avalue); if (i != 0) return i; beg = end + 1; } if (*ptr == '\0') return OSIP_SUCCESS; break; default: break; } } }
/* return -1 on error */ int osip_uri_parse (osip_uri_t * url, const char *buf) { char *username; char *password; char *host; const char *port; const char *params; const char *headers; const char *tmp; /* basic tests */ if (buf == NULL || buf[0] == '\0') return -1; tmp = strchr (buf, ':'); if (tmp == NULL) return -1; if (tmp - buf < 2) return -1; url->scheme = (char *) osip_malloc (tmp - buf + 1); if (url->scheme == NULL) return -1; osip_strncpy (url->scheme, buf, tmp - buf); if (strlen (url->scheme) < 3 || (0 != osip_strncasecmp (url->scheme, "sip", 3) && 0 != osip_strncasecmp (url->scheme, "sips", 4))) { /* Is not a sipurl ! */ size_t i = strlen (tmp + 1); if (i < 2) return -1; url->string = (char *) osip_malloc (i + 1); if (url->string == NULL) return -1; osip_strncpy (url->string, tmp + 1, i); return 0; } /* law number 1: if ('?' exists && is_located_after '@') or if ('?' exists && '@' is not there -no username-) =====> HEADER_PARAM EXIST =====> start at index(?) =====> end at the end of url */ /* find the beginning of host */ username = strchr (buf, ':'); /* if ':' does not exist, the url is not valid */ if (username == NULL) return -1; host = strchr (buf, '@'); if (host == NULL) host = username; else if (username[1] == '@') /* username is empty */ host = username + 1; else /* username exists */ { password = next_separator (username + 1, ':', '@'); if (password == NULL) password = host; else /* password exists */ { if (host - password < 2) return -1; url->password = (char *) osip_malloc (host - password); if (url->password == NULL) return -1; osip_strncpy (url->password, password + 1, host - password - 1); __osip_uri_unescape (url->password); } if (password - username < 2) return -1; { url->username = (char *) osip_malloc (password - username); if (url->username == NULL) return -1; osip_strncpy (url->username, username + 1, password - username - 1); __osip_uri_unescape (url->username); } } /* search for header after host */ headers = strchr (host, '?'); if (headers == NULL) headers = buf + strlen (buf); else /* headers exist */ osip_uri_parse_headers (url, headers); /* search for params after host */ params = strchr (host, ';'); /* search for params after host */ if (params == NULL) params = headers; else /* params exist */ { char *tmpbuf; if (headers - params + 1 < 2) return -1; tmpbuf = osip_malloc (headers - params + 1); if (tmpbuf == NULL) return -1; tmpbuf = osip_strncpy (tmpbuf, params, headers - params); osip_uri_parse_params (url, tmpbuf); osip_free (tmpbuf); } port = params - 1; while (port > host && *port != ']' && *port != ':') port--; if (*port == ':') { if (host == port) port = params; else { if ((params - port < 2) || (params - port > 8)) return -1; /* error cases */ url->port = (char *) osip_malloc (params - port); if (url->port == NULL) return -1; osip_clrncpy (url->port, port + 1, params - port - 1); } } else port = params; /* adjust port for ipv6 address */ tmp = port; while (tmp > host && *tmp != ']') tmp--; if (*tmp == ']') { port = tmp; while (host < port && *host != '[') host++; if (host >= port) return -1; } if (port - host < 2) return -1; url->host = (char *) osip_malloc (port - host); if (url->host == NULL) return -1; osip_clrncpy (url->host, host + 1, port - host - 1); return 0; }
int eXosip_get_naptr(char *domain, char *protocol, char *srv_record, int max_length) { querybuf answer; /* answer buffer from nameserver */ int n; char zone[1024]; int ancount, qdcount; /* answer count and query count */ HEADER *hp; /* answer buffer header */ char hostbuf[256]; unsigned char *msg, *eom, *cp; /* answer buffer positions */ int dlen, type, aclass; long ttl; int answerno; char tr[100]; memset(srv_record, 0, max_length); if (domain == NULL || protocol == NULL) return OSIP_BADPARAMETER; if (strlen(domain) + strlen(protocol) > 1000) return OSIP_BADPARAMETER; if (strlen(protocol) >= 100) return OSIP_BADPARAMETER; snprintf(tr, 100, protocol); osip_tolower(tr); snprintf(zone, 1024, "%s", domain); OSIP_TRACE(osip_trace (__FILE__, __LINE__, OSIP_INFO2, NULL, "About to ask for '%s IN NAPTR\n", zone)); n = res_query(zone, C_IN, T_NAPTR, (unsigned char *) &answer, sizeof(answer)); if (n < (int) sizeof(HEADER)) { return OSIP_UNKNOWN_HOST; } /* browse message and search for DNS answers part */ hp = (HEADER *) & answer; qdcount = ntohs(hp->qdcount); ancount = ntohs(hp->ancount); msg = (unsigned char *) (&answer); eom = (unsigned char *) (&answer) + n; cp = (unsigned char *) (&answer) + sizeof(HEADER); while (qdcount-- > 0 && cp < eom) { n = dn_expand(msg, eom, cp, (char *) hostbuf, 256); if (n < 0) { OSIP_TRACE(osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "Invalid SRV record answer for '%s': bad format\n", zone)); return OSIP_UNDEFINED_ERROR; } cp += n + QFIXEDSZ; } /* browse DNS answers */ answerno = 0; /* loop through the answer buffer and extract SRV records */ while (ancount-- > 0 && cp < eom) { int len; typedef struct { unsigned short order; unsigned short pref; char flag[256]; char service[1024]; char regexp[1024]; char replacement[1024]; } osip_naptr_t; osip_naptr_t anaptr; n = dn_expand(msg, eom, cp, (char *) hostbuf, 256); if (n < 0) { OSIP_TRACE(osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "Invalid NAPTR answer for '%s': bad format\n", zone)); return OSIP_UNDEFINED_ERROR; } cp += n; #if defined(__NetBSD__) || defined(__OpenBSD__) ||\ defined(OLD_NAMESER) || defined(__FreeBSD__) type = _get_short(cp); cp += sizeof(u_short); #elif defined(__APPLE_CC__) GETSHORT(type, cp); #else NS_GET16(type, cp); #endif #if defined(__NetBSD__) || defined(__OpenBSD__) ||\ defined(OLD_NAMESER) || defined(__FreeBSD__) aclass = _get_short(cp); cp += sizeof(u_short); #elif defined(__APPLE_CC__) GETSHORT(aclass, cp); #else NS_GET16(aclass, cp); #endif #if defined(__NetBSD__) || defined(__OpenBSD__) ||\ defined(OLD_NAMESER) || defined(__FreeBSD__) ttl = _get_long(cp); cp += sizeof(u_long); #elif defined(__APPLE_CC__) GETLONG(ttl, cp); #else NS_GET32(ttl, cp); #endif #if defined(__NetBSD__) || defined(__OpenBSD__) ||\ defined(OLD_NAMESER) || defined(__FreeBSD__) dlen = _get_short(cp); cp += sizeof(u_short); #elif defined(__APPLE_CC__) GETSHORT(dlen, cp); #else NS_GET16(dlen, cp); #endif if (type != T_NAPTR) { cp += dlen; continue; } memset(&anaptr, 0, sizeof(osip_naptr_t)); memcpy((void *) &anaptr.order, cp, 2); anaptr.order = ntohs(anaptr.order); /*((unsigned short)cp[0] << 8) | ((unsigned short)cp[1]); */ cp += sizeof(unsigned short); memcpy((void *) &anaptr.pref, cp, 2); anaptr.pref = ntohs(anaptr.pref); /* ((unsigned short)cp[0] << 8) | ((unsigned short)cp[1]); */ cp += sizeof(unsigned short); len = *cp; cp++; strncpy(anaptr.flag, (char *) cp, len); anaptr.flag[len] = '\0'; cp += len; len = *cp; cp++; strncpy(anaptr.service, (char *) cp, len); anaptr.service[len] = '\0'; cp += len; len = *cp; cp++; strncpy(anaptr.regexp, (char *) cp, len); anaptr.regexp[len] = '\0'; cp += len; n = dn_expand(msg, eom, cp, anaptr.replacement, 1024 - 1); if (n < 0) break; cp += n; OSIP_TRACE(osip_trace (__FILE__, __LINE__, OSIP_INFO2, NULL, "NAPTR %s ->%i/%i/%s/%s/%s/%s\n", zone, anaptr.order, anaptr.pref, anaptr.flag, anaptr.service, anaptr.regexp, anaptr.replacement)); if (osip_strncasecmp(tr, "udp", 4) == 0 && osip_strncasecmp(anaptr.service, "SIP+D2U", 8) == 0) { snprintf(srv_record, max_length, "%s", anaptr.replacement); return OSIP_SUCCESS; } else if (osip_strncasecmp(tr, "tcp", 4) == 0 && osip_strncasecmp(anaptr.service, "SIP+D2T", 8) == 0) { snprintf(srv_record, max_length, "%s", anaptr.replacement); return OSIP_SUCCESS; } else if (osip_strncasecmp(tr, "udp-tls", 8) == 0 && osip_strncasecmp(anaptr.service, "SIPS+D2U", 9) == 0) { snprintf(srv_record, max_length, "%s", anaptr.replacement); return OSIP_SUCCESS; } else if (osip_strncasecmp(tr, "tls", 4) == 0 && osip_strncasecmp(anaptr.service, "SIPS+D2T", 9) == 0) { snprintf(srv_record, max_length, "%s", anaptr.replacement); return OSIP_SUCCESS; } else if (osip_strncasecmp(tr, "sctp", 5) == 0 && osip_strncasecmp(anaptr.service, "SIP+D2S", 8) == 0) { snprintf(srv_record, max_length, "%s", anaptr.replacement); return OSIP_SUCCESS; } answerno++; } if (answerno == 0) return OSIP_UNKNOWN_HOST; OSIP_TRACE(osip_trace (__FILE__, __LINE__, OSIP_INFO2, NULL, "protocol: %s is not supported by domain %s\n", protocol, domain)); return OSIP_SUCCESS; }
int eXosip_get_naptr(char *domain, char *protocol, char *srv_record, int max_length) { char zone[1024]; PDNS_RECORD answer, tmp; /* answer buffer from nameserver */ int n; char tr[100]; memset(srv_record, 0, max_length); if (domain == NULL || protocol == NULL) return OSIP_BADPARAMETER; if (strlen(domain) + strlen(protocol) > 1000) return OSIP_BADPARAMETER; if (strlen(protocol) >= 100) return OSIP_BADPARAMETER; snprintf(tr, 100, protocol); osip_tolower(tr); snprintf(zone, 1024, "%s", domain); OSIP_TRACE(osip_trace (__FILE__, __LINE__, OSIP_INFO2, NULL, "About to ask for '%s NAPTR'\n", zone)); if (DnsQuery(zone, DNS_TYPE_NAPTR, DNS_QUERY_STANDARD, NULL, &answer, NULL) != 0) { return OSIP_UNKNOWN_HOST; } n = 0; for (tmp = answer; tmp != NULL; tmp = tmp->pNext) { char *buf = (char *) &tmp->Data; int len; OSVERSIONINFOEX ovi; typedef struct { unsigned short order; unsigned short pref; char flag[256]; char service[1024]; char regexp[1024]; char replacement[1024]; } osip_naptr_t; osip_naptr_t anaptr; if (tmp->wType != DNS_TYPE_NAPTR) continue; memset(&anaptr, 0, sizeof(osip_naptr_t)); memset(&ovi, 0, sizeof(ovi)); ovi.dwOSVersionInfoSize = sizeof(ovi); GetVersionEx((LPOSVERSIONINFO) & ovi); /* Minimum: client: Windows 2000 Professional */ /* Minimum: server: Windows 2000 Server */ OSIP_TRACE(osip_trace (__FILE__, __LINE__, OSIP_INFO2, NULL, "check OS support for NAPTR: %i %i %i\n", ovi.dwMajorVersion, ovi.dwMinorVersion, ovi.dwBuildNumber)); if (ovi.dwMajorVersion > 5) { #if (_WIN32_WINNT >= 0x0600) /* RUN only on Vista? */ /* compile starting from SDK 6.0A? even on XP... */ anaptr.order = tmp->Data.NAPTR.wOrder; anaptr.pref = tmp->Data.NAPTR.wPreference; strncpy(anaptr.flag, tmp->Data.NAPTR.pFlags, sizeof(anaptr.flag) - 1); strncpy(anaptr.service, tmp->Data.NAPTR.pService, sizeof(anaptr.service) - 1); strncpy(anaptr.regexp, tmp->Data.NAPTR.pRegularExpression, sizeof(anaptr.regexp) - 1); strncpy(anaptr.replacement, tmp->Data.NAPTR.pReplacement, sizeof(anaptr.replacement) - 1); #endif } else { memcpy((void *) &anaptr.order, buf, 2); anaptr.order = ntohs(anaptr.order); /* ((unsigned short)buf[0] << 8) | ((unsigned short)buf[1]); */ buf += sizeof(unsigned short); memcpy((void *) &anaptr.pref, buf, 2); anaptr.pref = ntohs(anaptr.pref); /* ((unsigned short)buf[0] << 8) | ((unsigned short)buf[1]); */ buf += sizeof(unsigned short); len = *buf; if (len < 0 || len > 255) break; buf++; strncpy(anaptr.flag, buf, len); anaptr.flag[len] = '\0'; buf += len; len = *buf; if (len < 0 || len > 1023) break; buf++; strncpy(anaptr.service, buf, len); anaptr.service[len] = '\0'; buf += len; len = *buf; if (len < 0 || len > 1023) break; buf++; strncpy(anaptr.regexp, buf, len); anaptr.regexp[len] = '\0'; buf += len; len = _eX_dn_expand((char *) &tmp->Data, ((char *) &tmp->Data) + tmp->wDataLength, buf, anaptr.replacement, 1024 - 1); if (len < 0) break; buf += len; } OSIP_TRACE(osip_trace (__FILE__, __LINE__, OSIP_INFO2, NULL, "NAPTR %s ->%i/%i/%s/%s/%s/%s\n", zone, anaptr.order, anaptr.pref, anaptr.flag, anaptr.service, anaptr.regexp, anaptr.replacement)); if (osip_strncasecmp(tr, "udp", 4) == 0 && osip_strncasecmp(anaptr.service, "SIP+D2U", 8) == 0) { snprintf(srv_record, max_length, "%s", anaptr.replacement); DnsRecordListFree(answer, DnsFreeRecordList); return OSIP_SUCCESS; } else if (osip_strncasecmp(tr, "tcp", 4) == 0 && osip_strncasecmp(anaptr.service, "SIP+D2T", 8) == 0) { snprintf(srv_record, max_length, "%s", anaptr.replacement); DnsRecordListFree(answer, DnsFreeRecordList); return OSIP_SUCCESS; } else if (osip_strncasecmp(tr, "udp-tls", 8) == 0 && osip_strncasecmp(anaptr.service, "SIPS+D2U", 9) == 0) { snprintf(srv_record, max_length, "%s", anaptr.replacement); DnsRecordListFree(answer, DnsFreeRecordList); return OSIP_SUCCESS; } else if (osip_strncasecmp(tr, "tls", 4) == 0 && osip_strncasecmp(anaptr.service, "SIPS+D2T", 9) == 0) { snprintf(srv_record, max_length, "%s", anaptr.replacement); DnsRecordListFree(answer, DnsFreeRecordList); return OSIP_SUCCESS; } else if (osip_strncasecmp(tr, "sctp", 5) == 0 && osip_strncasecmp(anaptr.service, "SIP+D2S", 8) == 0) { snprintf(srv_record, max_length, "%s", anaptr.replacement); DnsRecordListFree(answer, DnsFreeRecordList); return OSIP_SUCCESS; } n++; } DnsRecordListFree(answer, DnsFreeRecordList); if (n == 0) return OSIP_UNKNOWN_HOST; OSIP_TRACE(osip_trace (__FILE__, __LINE__, OSIP_INFO2, NULL, "protocol: %s is not supported by domain %s\n", protocol, domain)); return OSIP_SUCCESS; }