int forward_sl_request(struct sip_msg *msg,str *uri,int proto) { struct dest_info dst; int ret; ret = -1; #ifdef USE_DNS_FAILOVER if ((uri2dst(NULL,&dst, msg, uri, proto)==0) || (dst.send_sock==0)) #else if ((uri2dst(&dst, msg, uri, proto)==0) || (dst.send_sock==0)) #endif { LOG(L_ERR, "forward_sl_request: no socket found\n"); return -1; } LM_DBG("Sending:\n%.*s.\n", (int)msg->len,msg->buf); if (msg_send(&dst, msg->buf,msg->len)<0){ LM_ERR("ERROR:seas:forward_sl_request: Error sending message !!\n"); return -1; } return ret; }
/* * The function creates an ACK to 200 OK. Route set will be created * and parsed and the dst parameter will contain the destination to which * the request should be send. The function is used by tm when it * generates local ACK to 200 OK (on behalf of applications using uac) */ char *build_dlg_ack(struct sip_msg* rpl, struct cell *Trans, unsigned int branch, str *hdrs, str *body, unsigned int *len, struct dest_info* dst) { char *req_buf, *p, *via; unsigned int via_len; char branch_buf[MAX_BRANCH_PARAM_LEN]; int branch_len; str branch_str; struct hostport hp; struct rte* list; str contact, ruri, *cont; str next_hop; str body_len; str _to, *to = &_to; #ifdef USE_DNS_FAILOVER struct dns_srv_handle dns_h; #endif #ifdef WITH_AS_SUPPORT /* With AS support, TM allows for external modules to generate building of * the ACK; in this case, the ACK's retransmission buffer is built once * and kept in memory (to help when retransmitted 2xx are received and ACK * must be resent). * Allocation of the string raw buffer that holds the ACK is piggy-backed * with allocation of the retransmission buffer (since both have the same * life-cycle): both the string buffer and retransm. buffer are placed * into the same allocated chunk of memory (retr. buffer first, string * buffer follows).In this case, the 'len' param is used as in-out * parameter: 'in' to give the extra space needed by the retr. buffer, * 'out' to return the lenght of the allocated string buffer. */ unsigned offset = *len; #endif if (parse_headers(rpl, HDR_EOH_F, 0) == -1 || !rpl->to) { LM_ERR("Error while parsing headers.\n"); return 0; } else { _to.s = rpl->to->name.s; _to.len = rpl->to->len; } if (get_contact_uri(rpl, &contact) < 0) { return 0; } if (eval_uac_routing(rpl, &Trans->uac[branch].request, &contact, &list, &ruri, &next_hop) < 0) { LM_ERR("failed to evaluate routing elements.\n"); return 0; } LM_DBG("ACK RURI: `%.*s', NH: `%.*s'.\n", STR_FMT(&ruri), STR_FMT(&next_hop)); if ((contact.s != ruri.s) || (contact.len != ruri.len)) { /* contact != ruri means that the next * hop is a strict router, cont will be non-zero * and print_routeset will append it at the end * of the route set */ cont = &contact; } else { /* Next hop is a loose router, nothing to append */ cont = 0; } /* method, separators, version: "ACK sip:[email protected] SIP/2.0" */ *len = SIP_VERSION_LEN + ACK_LEN + 2 /* spaces */ + CRLF_LEN; *len += ruri.len; /* dst */ switch(cfg_get(tm, tm_cfg, local_ack_mode)){ case 1: /* send the local 200 ack to the same dst as the corresp. invite*/ *dst=Trans->uac[branch].request.dst; break; case 2: /* send the local 200 ack to the same dst as the 200 reply source*/ init_dst_from_rcv(dst, &rpl->rcv); dst->send_flags=rpl->fwd_send_flags; break; case 0: default: /* rfc conformant behaviour: use the next_hop determined from the * contact and the route set */ #ifdef USE_DNS_FAILOVER if (cfg_get(core, core_cfg, use_dns_failover)){ dns_srv_handle_init(&dns_h); if ((uri2dst(&dns_h , dst, rpl, &next_hop, PROTO_NONE)==0) || (dst->send_sock==0)){ dns_srv_handle_put(&dns_h); LM_ERR("no socket found\n"); goto error; } dns_srv_handle_put(&dns_h); /* not needed any more */ }else{ if ((uri2dst(0 , dst, rpl, &next_hop, PROTO_NONE)==0) || (dst->send_sock==0)){ LM_ERR("no socket found\n"); goto error; } } #else /* USE_DNS_FAILOVER */ if ( (uri2dst( dst, rpl, &next_hop, PROTO_NONE)==0) || (dst->send_sock==0)){ LM_ERR("no socket found\n"); goto error; } #endif /* USE_DNS_FAILOVER */ break; } /* via */ if (!t_calc_branch(Trans, branch, branch_buf, &branch_len)) goto error; branch_str.s = branch_buf; branch_str.len = branch_len; set_hostport(&hp, 0); via = via_builder(&via_len, NULL, dst, &branch_str, 0, &hp); if (!via) { LM_ERR("No via header got from builder\n"); goto error; } *len+= via_len; /* headers */ *len += Trans->from.len + Trans->callid.len + to->len + Trans->cseq_n.len + 1 + ACK_LEN + CRLF_LEN; /* copy'n'paste Route headers */ *len += calc_routeset_len(list, cont); /* User Agent */ if (server_signature) *len += user_agent_hdr.len + CRLF_LEN; /* extra headers */ if (hdrs) *len += hdrs->len; /* body */ if (body) { body_len.s = int2str(body->len, &body_len.len); *len += body->len; } else { body_len.len = 0; body_len.s = NULL; /*4gcc*/ *len += 1; /* for the (Cont-Len:) `0' */ } /* Content Length, EoM */ *len += CONTENT_LENGTH_LEN + body_len.len + CRLF_LEN + CRLF_LEN; #if WITH_AS_SUPPORT req_buf = shm_malloc(offset + *len + 1); req_buf += offset; #else req_buf = shm_malloc(*len + 1); #endif if (!req_buf) { LM_ERR("Cannot allocate memory (%u+1)\n", *len); goto error01; } p = req_buf; append_str( p, ACK, ACK_LEN ); append_str( p, " ", 1 ); append_str(p, ruri.s, ruri.len); append_str( p, " " SIP_VERSION CRLF, 1 + SIP_VERSION_LEN + CRLF_LEN); /* insert our via */ append_str(p, via, via_len); /*other headers*/ append_str(p, Trans->from.s, Trans->from.len); append_str(p, Trans->callid.s, Trans->callid.len); append_str(p, to->s, to->len); append_str(p, Trans->cseq_n.s, Trans->cseq_n.len); append_str( p, " ", 1 ); append_str( p, ACK, ACK_LEN); append_str(p, CRLF, CRLF_LEN); /* Routeset */ p = print_rs(p, list, cont); /* User Agent header */ if (server_signature) { append_str(p, user_agent_hdr.s, user_agent_hdr.len); append_str(p, CRLF, CRLF_LEN); } /* extra headers */ if (hdrs) append_str(p, hdrs->s, hdrs->len); /* Content Length, EoH, (body) */ if (body) { append_str(p, CONTENT_LENGTH, CONTENT_LENGTH_LEN); append_str(p, body_len.s, body_len.len); append_str(p, /*end crr. header*/CRLF /*EoH*/CRLF, CRLF_LEN + CRLF_LEN); append_str(p, body->s, body->len); } else { append_str(p, CONTENT_LENGTH "0" CRLF CRLF, CONTENT_LENGTH_LEN + 1 + CRLF_LEN + CRLF_LEN); } /* EoM */ *p = 0; pkg_free(via); free_rte_list(list); return req_buf; error01: pkg_free(via); error: free_rte_list(list); return 0; }
static inline int t_uac_prepare(str* method, str* headers, str* body, dlg_t* dialog, transaction_cb cb, void* cbp, struct retr_buf **dst_req, struct cell **dst_cell) { struct dest_info dst; struct cell *new_cell; struct retr_buf *request; char* buf; int buf_len, ret, flags; unsigned int hi; int is_ack; #ifdef USE_DNS_FAILOVER struct dns_srv_handle dns_h; #endif ret=-1; hi=0; /* make gcc happy */ /*if (dst_req) *dst_req = NULL;*/ is_ack = (((method->len == 3) && (memcmp("ACK", method->s, 3)==0)) ? 1 : 0); /*** added by dcm * - needed by external ua to send a request within a dlg */ if (w_calculate_hooks(dialog)<0 && !dialog->hooks.next_hop) goto error2; if (!dialog->loc_seq.is_set) { /* this is the first request in the dialog, set cseq to default value now - Miklos */ dialog->loc_seq.value = DEFAULT_CSEQ; dialog->loc_seq.is_set = 1; } DBG("DEBUG:tm:t_uac: next_hop=<%.*s>\n",dialog->hooks.next_hop->len, dialog->hooks.next_hop->s); /* it's a new message, so we will take the default socket */ #ifdef USE_DNS_FAILOVER if (use_dns_failover){ dns_srv_handle_init(&dns_h); if ((uri2dst(&dns_h, &dst, 0, dialog->hooks.next_hop, PROTO_NONE)==0) || (dst.send_sock==0)){ dns_srv_handle_put(&dns_h); ser_error = E_NO_SOCKET; ret=ser_error; LOG(L_ERR, "t_uac: no socket found\n"); goto error2; } dns_srv_handle_put(&dns_h); /* not needed anymore */ }else{ if ((uri2dst(0, &dst, 0, dialog->hooks.next_hop, PROTO_NONE)==0) || (dst.send_sock==0)){ ser_error = E_NO_SOCKET; ret=ser_error; LOG(L_ERR, "t_uac: no socket found\n"); goto error2; } } #else if ((uri2dst(&dst, 0, dialog->hooks.next_hop, PROTO_NONE)==0) || (dst.send_sock==0)){ ser_error = E_NO_SOCKET; ret=ser_error; LOG(L_ERR, "t_uac: no socket found\n"); goto error2; } #endif new_cell = build_cell(0); if (!new_cell) { ret=E_OUT_OF_MEM; LOG(L_ERR, "t_uac: short of cell shmem\n"); goto error2; } /* init timers hack, new_cell->fr_timer and new_cell->fr_inv_timer * must be set, or else the fr will happen immediately * we can't call init_new_t() because we don't have a sip msg * => we'll ignore t_set_fr() or avp timer value and will use directly the * module params fr_inv_timer and fr_timer -- andrei */ new_cell->fr_timeout=fr_timeout; new_cell->fr_inv_timeout=fr_inv_timeout; /* better reset avp list now - anyhow, it's useless from * this point (bogdan) */ reset_avps(); /* add the callback the the transaction for LOCAL_COMPLETED event */ flags = TMCB_LOCAL_COMPLETED; /* Add also TMCB_LOCAL_REPLY_OUT if provisional replies are desired */ if (pass_provisional_replies) flags |= TMCB_LOCAL_RESPONSE_OUT; if(cb && insert_tmcb(&(new_cell->tmcb_hl), flags, cb, cbp)!=1){ ret=E_OUT_OF_MEM; LOG(L_ERR, "t_uac: short of tmcb shmem\n"); goto error2; } if (method->len==INVITE_LEN && memcmp(method->s, INVITE, INVITE_LEN)==0) new_cell->flags |= T_IS_INVITE_FLAG; new_cell->flags |= T_IS_LOCAL_FLAG; set_kr(REQ_FWDED); request = &new_cell->uac[0].request; request->dst = dst; if (!is_ack) { hi=dlg2hash(dialog); LOCK_HASH(hi); insert_into_hash_table_unsafe(new_cell, hi); UNLOCK_HASH(hi); } buf = build_uac_req(method, headers, body, dialog, 0, new_cell, &buf_len, &dst); if (!buf) { LOG(L_ERR, "t_uac: Error while building message\n"); ret=E_OUT_OF_MEM; goto error1; } new_cell->method.s = buf; new_cell->method.len = method->len; request->buffer = buf; request->buffer_len = buf_len; new_cell->nr_of_outgoings++; if (dst_req) *dst_req = request; if (dst_cell) *dst_cell = new_cell; return 1; error1: if (!is_ack) { LOCK_HASH(hi); remove_from_hash_table_unsafe(new_cell); UNLOCK_HASH(hi); } free_cell(new_cell); error2: return ret; }
int ipsec_forward(struct sip_msg* m, udomain_t* d) { struct pcontact_info ci; pcontact_t* pcontact = NULL; int ret = IPSEC_CMD_FAIL; // FAIL by default // // Find the contact // if(fill_contact(&ci, m) != 0) { LM_ERR("Error filling in contact data\n"); return ret; } ul.lock_udomain(d, &ci.via_host, ci.via_port, ci.via_prot); if (ul.get_pcontact(d, &ci, &pcontact) != 0) { LM_ERR("Contact doesn't exist\n"); goto cleanup; } if(pcontact->security_temp == NULL) { LM_ERR("No security parameters found in contact\n"); goto cleanup; } //get security parameters if(pcontact->security_temp->type != SECURITY_IPSEC ) { LM_ERR("Unsupported security type: %d\n", pcontact->security_temp->type); goto cleanup; } ipsec_t* s = pcontact->security_temp->data.ipsec; // Update the destination // // from sec-agree // v // sip:host:port // ^ // from URI //int uri_len = 4 /* strlen("sip:") */ + ci.via_host.len + 5 /* max len of port number */ ; if(m->dst_uri.s) { pkg_free(m->dst_uri.s); m->dst_uri.s = NULL; m->dst_uri.len = 0; } char buf[1024]; int buf_len = snprintf(buf, sizeof(buf) - 1, "sip:%.*s:%d", ci.via_host.len, ci.via_host.s, s->port_us); if((m->dst_uri.s = pkg_malloc(buf_len)) == NULL) { LM_ERR("Error allocating memory for dst_uri\n"); goto cleanup; } memcpy(m->dst_uri.s, buf, buf_len); m->dst_uri.len = buf_len; // Set send socket struct socket_info * client_sock = grep_sock_info(&ipsec_listen_addr, ipsec_client_port, PROTO_UDP); if(!client_sock) { LM_ERR("Error calling grep_sock_info() for ipsec client port in ipsec_forward\n"); return -1; } m->force_send_socket = client_sock; // Set destination info struct dest_info dst_info; dst_info.send_sock = client_sock; #ifdef USE_DNS_FAILOVER if (!uri2dst(NULL, &dst_info, m, &m->dst_uri, PROTO_UDP)) { #else if (!uri2dst(&dst_info, m, &m->dst_uri, PROTO_UDP)) { #endif LM_ERR("Error converting dst_uri (%.*s) to struct dst_info\n", m->dst_uri.len, m->dst_uri.s); goto cleanup; } // Update dst_info in message if(m->first_line.type == SIP_REPLY) { struct cell *t = tmb.t_gett(); if (!t) { LM_ERR("Error getting transaction\n"); goto cleanup; } t->uas.response.dst = dst_info; } LM_DBG("Destination changed to %.*s\n", m->dst_uri.len, m->dst_uri.s); ret = IPSEC_CMD_SUCCESS; // all good, return SUCCESS if(add_supported_secagree_header(m) != 0) { goto cleanup; } if(add_security_server_header(m, s) != 0) { goto cleanup; } ret = IPSEC_CMD_SUCCESS; // all good, set ret to SUCCESS, and exit cleanup: ul.unlock_udomain(d, &ci.via_host, ci.via_port, ci.via_prot); pkg_free(ci.received_host.s); return ret; } int ipsec_destroy(struct sip_msg* m, udomain_t* d) { struct pcontact_info ci; pcontact_t* pcontact = NULL; int ret = IPSEC_CMD_FAIL; // FAIL by default // // Find the contact // if(fill_contact(&ci, m) != 0) { LM_ERR("Error filling in contact data\n"); return ret; } ul.lock_udomain(d, &ci.via_host, ci.via_port, ci.via_prot); if (ul.get_pcontact(d, &ci, &pcontact) != 0) { LM_ERR("Contact doesn't exist\n"); goto cleanup; } if(pcontact->security_temp == NULL) { LM_ERR("No security parameters found in contact\n"); goto cleanup; } //get security parameters if(pcontact->security_temp->type != SECURITY_IPSEC ) { LM_ERR("Unsupported security type: %d\n", pcontact->security_temp->type); goto cleanup; } destroy_ipsec_tunnel(ci.received_host, pcontact->security_temp->data.ipsec); ret = IPSEC_CMD_SUCCESS; // all good, set ret to SUCCESS, and exit cleanup: ul.unlock_udomain(d, &ci.via_host, ci.via_port, ci.via_prot); pkg_free(ci.received_host.s); return ret; } int ipsec_cleanall() { struct mnl_socket* nlsock = init_mnl_socket(); if(!nlsock) { return -1; } if(clean_sa(nlsock) != 0) { LM_WARN("Error cleaning IPSec Security associations during startup.\n"); } if(clean_policy(nlsock) != 0) { LM_WARN("Error cleaning IPSec Policies during startup.\n"); } close_mnl_socket(nlsock); return 0; }
/** construct a "header block" from a header list. * * @return pkg_malloc'ed header block on success (with *l set to its length), * 0 on error. */ static char *get_hfblock(str *uri, struct hdr_field *hf, int proto, struct socket_info* ssock, int* l) { struct str_list sl, *last, *i, *foo; int p, frag_len, total_len; char *begin, *needle, *dst, *ret, *d; str *sock_name, *portname; struct dest_info di; ret = 0; /* pessimist: assume failure */ total_len = 0; last = &sl; last->next = 0; sock_name = 0; portname = 0; if (ssock){ si_get_signaling_data(ssock, &sock_name, &portname); } for (; hf; hf = hf->next) { if (tm_skip_hf(hf)) continue; begin = needle = hf->name.s; p = hf->len; /* substitution loop */ while(p) { d = q_memchr(needle, SUBST_CHAR, p); if (!d || d + 1 >= needle + p) { /* nothing to substitute */ if (!append_str_list(begin, p, &last, &total_len)) goto error; break; } else { frag_len = d - begin; d++; /* d not at the second substitution char */ switch(*d) { case SUBST_CHAR: /* double SUBST_CHAR: IP */ /* string before substitute */ if (!append_str_list(begin, frag_len, &last, &total_len)) goto error; /* substitute */ if (!sock_name) { if ( #ifdef USE_DNS_FAILOVER uri2dst(0, &di, 0, uri, proto) #else uri2dst(&di, 0, uri, proto) #endif /* USE_DNS_FAILOVER */ == 0 ){ LM_ERR("send_sock failed\n"); goto error; } si_get_signaling_data(di.send_sock, &sock_name, &portname); } if (!append_str_list(sock_name->s, sock_name->len, &last, &total_len)) goto error; /* inefficient - FIXME --andrei*/ if (!append_str_list(":", 1, &last, &total_len)) goto error; if (!append_str_list(portname->s, portname->len, &last, &total_len)) goto error; /* keep going ... */ begin = needle = d + 1; p -= frag_len + 2; continue; default: /* no valid substitution char -- keep going */ p -= frag_len + 1; needle = d; } } /* possible substitute */ } /* substitution loop */ LM_DBG("one more hf processed\n"); } /* header loop */ if(total_len==0) { LM_DBG("empty result for headers block\n"); goto error; } /* construct a single header block now */ ret = pkg_malloc(total_len); if (!ret) { LM_ERR("no pkg mem for hf block\n"); goto error; } i = sl.next; dst = ret; while(i) { foo = i; i = i->next; memcpy(dst, foo->s.s, foo->s.len); dst += foo->s.len; pkg_free(foo); } *l = total_len; return ret; error: i = sl.next; while(i) { foo = i; i = i->next; pkg_free(foo); } *l = 0; return 0; }