📄 proxy.c
字号:
* Route present? * If so, fetch address from topmost Route: header and remove it. */#endif /* * destination from SIP URI */ } else { /* get the destination from the SIP URI */ sts = get_ip_by_host(url->host, &sendto_addr); if (sts == STS_FAILURE) { DEBUGC(DBCLASS_PROXY, "proxy_request: cannot resolve URI [%s]", url->host); return STS_FAILURE; } if (url->port) { port=atoi(url->port); if ((port<=0) || (port>65535)) port=SIP_PORT; } else { port=SIP_PORT; } DEBUGC(DBCLASS_PROXY, "proxy_request: have SIP URI to %s:%i", url->host, port); } /* * RFC 3261, Section 16.6 step 8 * Proxy Behavior - Add a Via header field value */ /* add my Via header line (outbound interface)*/ if (type == REQTYP_INCOMING) { sts = sip_add_myvia(ticket, IF_INBOUND); if (sts == STS_FAILURE) { ERROR("adding my inbound via failed!"); } } else { sts = sip_add_myvia(ticket, IF_OUTBOUND); if (sts == STS_FAILURE) { ERROR("adding my outbound via failed!"); return STS_FAILURE; } } /* * RFC 3261, Section 16.6 step 9 * Proxy Behavior - Add a Content-Length header field if necessary */ /* not necessary, already in message and we do not support TCP */ /* * RFC 3261, Section 16.6 step 10 * Proxy Behavior - Forward the new request */ sts = sip_message_to_str(request, &buffer, &buflen); if (sts != 0) { ERROR("proxy_request: sip_message_to_str failed"); return STS_FAILURE; } sipsock_send(sendto_addr, port, ticket->protocol, buffer, buflen); osip_free (buffer); /* * RFC 3261, Section 16.6 step 11 * Proxy Behavior - Set timer C */ /* NOT IMPLEMENTED - does this really apply for stateless proxies? */ return STS_SUCCESS;}/* * 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 sts; int type; struct in_addr sendto_addr; osip_via_t *via; int port; char *buffer; size_t buflen; osip_message_t *response; DEBUGC(DBCLASS_PROXY,"proxy_response"); if (ticket==NULL) { ERROR("proxy_response: called with NULL ticket"); return STS_FAILURE; } response=ticket->sipmsg; /* * 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 */ sip_find_direction(ticket, NULL); type = ticket->direction;/* * 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:"*NULL*", response->from->url->host? response->from->url->host : "*NULL*");sts=sip_obscure_callid(ticket); /* * 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(ticket, 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. * also change the expiration timeout to the value returned by the * server. */ sts = register_set_expire(ticket); 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. * And 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 : "*NULL*", response->from->url->host ? response->from->url->host : "*NULL*");sts=sip_obscure_callid(ticket); /* Rewrite Contact header to represent the masqued address */ sip_rewrite_contact(ticket, DIR_OUTGOING); /* Masquerade the User-Agent if configured to do so */ proxy_rewrite_useragent(ticket); /* * 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(ticket, 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:"*NULL*", 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 */// let's try with Route header first#if 0 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) && (!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 if ((type == RESTYP_OUTGOING) && (!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 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. */#endif } 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); if ((port<=0) || (port>65535)) port=SIP_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;}/* * 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(sip_ticket_t *ticket, int direction){ osip_message_t *mymsg=ticket->sipmsg; osip_body_t *body; sdp_message_t *sdp; struct in_addr map_addr, addr_sess, addr_media, outside_addr, inside_addr; int sts; char *buff; size_t buflen; 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; int isrtp = 0 ; if (configuration.rtp_proxy_enable == 0) return STS_SUCCESS; /* * get SDP structure */ sts = osip_message_get_body(mymsg, 0, &body); if (sts != 0) { DEBUGC(DBCLASS_PROXY, "rewrite_invitation_body: " "no body found in message"); return STS_SUCCESS; } sts = sip_body_to_str(body, &buff, &buflen); if (sts != 0) { ERROR("rewrite_invitation_body: unable to sip_body_to_str"); return STS_FAILURE; } DEBUGC(-1, "rewrite_invitation_body: payload %ld bytes", (long)buflen); DUMP_BUFFER(-1, buff, buflen); sts = sdp_message_init(&sdp); sts = sdp_message_parse (sdp, buff); if (sts != 0) { ERROR("rewrite_invitation_body: unable to sdp_message_parse body"); DUMP_BUFFER(-1, buff, buflen); osip_free(buff); sdp_message_free(sdp); return STS_FAILURE; } osip_free(buff);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -