int forward_sl_request(struct sip_msg *msg,struct proxy_l *proxy,int proto) { union sockaddr_union *to; struct socket_info *send_sock; int ret; to = (union sockaddr_union*)pkg_malloc(sizeof(union sockaddr_union)); ret = -1; hostent2su(to, &proxy->host, proxy->addr_idx, (proxy->port)?proxy->port:SIP_PORT); do { send_sock=get_send_socket(msg, to, proto); if (send_sock==0){ LM_ERR( "cannot forward to af %d, " "proto %d no corresponding listening socket\n", to->s.sa_family, proto); continue; } LM_DBG("Sending:\n%.*s.\n", (int)msg->len,msg->buf); if (msg_send(send_sock, proto, to, 0, msg->buf,msg->len)<0){ LM_ERR("ERROR:seas:forward_msg: Error sending message !!\n"); continue; } ret = 0; break; }while( get_next_su( proxy, to, 0)==0 ); pkg_free(to); return ret; }
static int trace_send_duplicate(char *buf, int len) { union sockaddr_union* to; struct socket_info* send_sock; struct proxy_l * p; int proto; int ret; if(buf==NULL || len <= 0) return -1; if(dup_uri_str.s==0 || dup_uri==NULL) return 0; to=(union sockaddr_union*)pkg_malloc(sizeof(union sockaddr_union)); if (to==0){ LM_ERR("out of pkg memory\n"); return -1; } /* create a temporary proxy*/ proto = PROTO_UDP; p=mk_proxy(&dup_uri->host, (dup_uri->port_no)?dup_uri->port_no:SIP_PORT, proto, 0); if (p==0){ LM_ERR("bad host name in uri\n"); pkg_free(to); return -1; } hostent2su(to, &p->host, p->addr_idx, (p->port)?p->port:SIP_PORT); ret = -1; do { send_sock=get_send_socket(0, to, proto); if (send_sock==0){ LM_ERR("can't forward to af %d, proto %d no corresponding listening socket\n", to->s.sa_family,proto); continue; } if (msg_send(send_sock, proto, to, 0, buf, len, NULL)<0){ LM_ERR("cannot send duplicate message\n"); continue; } ret = 0; break; }while( get_next_su( p, to, 0)==0 ); free_proxy(p); /* frees only p content, not p itself */ pkg_free(p); pkg_free(to); return ret; }
static inline int do_dns_failover(struct cell *t) { static struct sip_msg faked_req; struct sip_msg *shmem_msg; struct ua_client *uac; int ret; shmem_msg = t->uas.request; uac = &t->uac[picked_branch]; /* check if the DNS resolver can get at least one new IP */ if ( get_next_su( uac->proxy, &uac->request.dst.to, 1)!=0 ) return -1; LM_DBG("new destination available\n"); if (!fake_req(&faked_req, shmem_msg, &t->uas, uac)) { LM_ERR("fake_req failed\n"); return -1; } /* fake also the env. conforming to the fake msg */ faked_env( t, &faked_req); ret = -1; /* set info as current destination */ if ( set_ruri( &faked_req, &uac->uri)!= 0) goto done; setb0flags( uac->br_flags ); faked_req.force_send_socket = shmem_msg->force_send_socket; /* send it out */ if (t_forward_nonack( t, &faked_req, uac->proxy)==1) ret = 0; done: /* restore original environment and free the fake msg */ faked_env( t, 0); free_faked_req(&faked_req,t); return ret; }
int add_lb_dsturi( struct lb_data *data, int id, int group, char *uri, char* resource, unsigned int flags) { struct lb_res_str_list *lb_rl; struct lb_res_str *r; struct lb_dst *dst; struct lb_resource *res; struct sip_uri puri; struct proxy_l *proxy; union sockaddr_union sau; int len; int i; LM_DBG("uri=<%s>, grp=%d, res=<%s>\n",uri, group, resource); /* check uri */ len = strlen(uri); if(parse_uri(uri, len, &puri)!=0 ) { LM_ERR("bad uri [%.*s] for destination\n", len, uri); return -1; } /* parse the resources string */ lb_rl = parse_resources_list( resource, 1); if (lb_rl==NULL) { LM_ERR("failed to parse resourse string <%s>\n",resource); return -1; } /*add new destination */ dst = (struct lb_dst*)shm_malloc( sizeof(struct lb_dst) + lb_rl->n*sizeof(struct lb_resource_map) + len + (3+2*sizeof(struct lb_dst*))); if (dst==NULL) { LM_ERR("failed to get shmem\n"); goto error; } memset( dst, 0, sizeof(struct lb_dst)+ lb_rl->n*sizeof(struct lb_resource_map) + len + (3+2*sizeof(struct lb_dst*)) ); dst->rmap = (struct lb_resource_map*)(dst+1); dst->uri.s = (char*)(dst->rmap + lb_rl->n); dst->uri.len = len; memcpy( dst->uri.s , uri, len); dst->profile_id.s = dst->uri.s + len; dst->profile_id.len = snprintf(dst->profile_id.s, 2+2*sizeof(struct lb_dst*), "%X", id); dst->id = id; dst->group = group; dst->rmap_no = lb_rl->n; dst->flags = flags; /* add or update resource list */ for( i=0 ; i<lb_rl->n ; i++) { r = lb_rl->resources + i; LM_DBG(" setting for uri=<%s> (%d) resource=<%.*s>, val=%d\n", uri, data->dst_no+1, r->name.len, r->name.s, r->val); res = get_resource_by_name( data, &r->name); if (res==NULL) { /* add new resource */ res = add_lb_resource(data, &r->name); if (res==NULL) { LM_ERR("failed to create new resource\n"); goto error; } } /* set the proper bit in the resource */ if (lb_set_resource_bitmask( res, data->dst_no)==-1 ) { LM_ERR("failed to set destination bit\n"); goto error; } /* set the pointer and the max load */ dst->rmap[i].resource = res; dst->rmap[i].max_load = r->val; } /* Do a SIP wise DNS-Lookup for the domain part */ proxy = mk_proxy( &puri.host, puri.port_no, puri.proto, (puri.type==SIPS_URI_T)); if (proxy==NULL) { LM_ERR("could not resolve %.*s\n", puri.host.len, puri.host.s); goto error; } hostent2ip_addr( &dst->ips[0], &proxy->host, proxy->addr_idx); dst->ports[0] = proxy->port; dst->ips_cnt = 1; LM_DBG("first dst ip addr [%s]:%d\n", ip_addr2a(&dst->ips[0]), dst->ports[0]); /* get the next available IPs from DNS */ while (dst->ips_cnt<LB_MAX_IPS && (get_next_su( proxy, &sau, 0)==0) ) { su2ip_addr( &dst->ips[dst->ips_cnt], &sau); dst->ports[dst->ips_cnt] = proxy->port; LM_DBG("additional dst ip addr [%s]:%d\n", ip_addr2a(&dst->ips[dst->ips_cnt]), dst->ports[dst->ips_cnt]); /* one more IP found */ dst->ips_cnt++; } /* free al the helper structures */ free_proxy(proxy); pkg_free(proxy); /* link at the end */ if (data->last_dst==NULL) { data->dsts = data->last_dst = dst; } else { data->last_dst->next = dst; data->last_dst = dst; } data->dst_no++; pkg_free(lb_rl); return 0; error: shm_free(dst); pkg_free(lb_rl); return -1; }
/* function returns: * 1 - forward successful * -1 - error during forward */ int t_forward_nonack( struct cell *t, struct sip_msg* p_msg , struct proxy_l * proxy, int reset_bcounter, int locked) { str reply_reason_487 = str_init("Request Terminated"); str backup_uri; str backup_dst; int branch_ret, lowest_ret; str current_uri; branch_bm_t added_branches; int i, q; struct cell *t_invite; int success_branch; str dst_uri; struct socket_info *bk_sock; unsigned int br_flags, bk_bflags; int idx; str path; str bk_path; /* make -Wall happy */ current_uri.s=0; /* before doing enything, update the t flags from msg */ t->uas.request->flags = p_msg->flags; if (p_msg->REQ_METHOD==METHOD_CANCEL) { t_invite=t_lookupOriginalT( p_msg ); if (t_invite!=T_NULL_CELL) { t_invite->flags |= T_WAS_CANCELLED_FLAG; cancel_invite( p_msg, t, t_invite, locked ); return 1; } } /* do not forward requests which were already cancelled*/ if (no_new_branches(t)) { LM_INFO("discarding fwd for a 6xx transaction\n"); ser_error = E_NO_DESTINATION; return -1; } if (was_cancelled(t)) { /* is this the first attempt of sending a branch out ? */ if (t->nr_of_outgoings==0) { /* if no other signalling was performed on the transaction * and the transaction was already canceled, better * internally generate the 487 reply here */ if (locked) t_reply_unsafe( t, p_msg , 487 , &reply_reason_487); else t_reply( t, p_msg , 487 , &reply_reason_487); } LM_INFO("discarding fwd for a cancelled transaction\n"); ser_error = E_NO_DESTINATION; return -1; } /* backup current uri, sock and flags... add_uac changes it */ backup_uri = p_msg->new_uri; backup_dst = p_msg->dst_uri; bk_sock = p_msg->force_send_socket; bk_path = p_msg->path_vec; bk_bflags = p_msg->ruri_bflags; /* advertised address/port are not changed */ /* check if the UAS retranmission port needs to be updated */ if ( (p_msg->msg_flags ^ t->uas.request->msg_flags) & FL_FORCE_RPORT ) su_setport( &t->uas.response.dst.to, p_msg->rcv.src_port ); /* if no more specific error code is known, use this */ lowest_ret=E_BUG; /* branches added */ added_branches=0; /* branch to begin with */ if (reset_bcounter) { t->first_branch=t->nr_of_outgoings; /* check if the previous branch is a PHONY one and if yes * keep it in the set of active branches; that means the * transaction had a t_wait_for_new_branches() call prior to relay() */ if ( t->first_branch>0 && (t->uac[t->first_branch-1].flags & T_UAC_IS_PHONY) ) t->first_branch--; } /* as first branch, use current uri */ current_uri = *GET_RURI(p_msg); branch_ret = add_uac( t, p_msg, ¤t_uri, &backup_dst, getb0flags(p_msg), &p_msg->path_vec, proxy); if (branch_ret>=0) added_branches |= 1<<branch_ret; else lowest_ret=branch_ret; /* ....and now add the remaining additional branches */ for( idx=0; (current_uri.s=get_branch( idx, ¤t_uri.len, &q, &dst_uri, &path, &br_flags, &p_msg->force_send_socket))!=0 ; idx++ ) { branch_ret = add_uac( t, p_msg, ¤t_uri, &dst_uri, br_flags, &path, proxy); /* pick some of the errors in case things go wrong; note that picking lowest error is just as good as any other algorithm which picks any other negative branch result */ if (branch_ret>=0) added_branches |= 1<<branch_ret; else lowest_ret=branch_ret; } /* consume processed branches */ clear_branches(); /* restore original stuff */ p_msg->new_uri=backup_uri; p_msg->parsed_uri_ok = 0;/* just to be sure; add_uac may parse other uris*/ p_msg->dst_uri = backup_dst; p_msg->force_send_socket = bk_sock; p_msg->path_vec = bk_path; p_msg->ruri_bflags = bk_bflags; /* update on_branch, _only_ if modified, otherwise it overwrites * whatever it is already in the transaction */ if (get_on_branch()) t->on_branch = get_on_branch(); /* update flags, if changed in branch route */ t->uas.request->flags = p_msg->flags; /* things went wrong ... no new branch has been fwd-ed at all */ if (added_branches==0) { LM_ERR("failure to add branches\n"); ser_error = lowest_ret; return lowest_ret; } /* send them out now */ success_branch=0; for (i=t->first_branch; i<t->nr_of_outgoings; i++) { if (added_branches & (1<<i)) { if (t->uac[i].br_flags & tcp_no_new_conn_bflag) tcp_no_new_conn = 1; do { if (check_blacklists( t->uac[i].request.dst.proto, &t->uac[i].request.dst.to, t->uac[i].request.buffer.s, t->uac[i].request.buffer.len)) { LM_DBG("blocked by blacklists\n"); ser_error=E_IP_BLOCKED; } else { run_trans_callbacks(TMCB_PRE_SEND_BUFFER, t, p_msg, 0, i); if (SEND_BUFFER( &t->uac[i].request)==0) { ser_error = 0; break; } LM_ERR("sending request failed\n"); ser_error=E_SEND; } /* get next dns entry */ if ( t->uac[i].proxy==0 || get_next_su( t->uac[i].proxy, &t->uac[i].request.dst.to, (ser_error==E_IP_BLOCKED)?0:1)!=0 ) break; t->uac[i].request.dst.proto = t->uac[i].proxy->proto; /* update branch */ if ( update_uac_dst( p_msg, &t->uac[i] )!=0) break; }while(1); tcp_no_new_conn = 0; if (ser_error) { shm_free(t->uac[i].request.buffer.s); t->uac[i].request.buffer.s = NULL; t->uac[i].request.buffer.len = 0; continue; } success_branch++; start_retr( &t->uac[i].request ); set_kr(REQ_FWDED); /* successfully sent out -> run callbacks */ if ( has_tran_tmcbs( t, TMCB_REQUEST_BUILT|TMCB_MSG_SENT_OUT) ) { set_extra_tmcb_params( &t->uac[i].request.buffer, &t->uac[i].request.dst); run_trans_callbacks( TMCB_REQUEST_BUILT|TMCB_MSG_SENT_OUT, t, p_msg, 0, 0); } } } return (success_branch>0)?1:-1; }
int add_dst( rt_data_t *r, /* id */ char *id, /* ip address */ char* ip, /* strip len */ int strip, /* pri prefix */ char* pri, /* dst type*/ int type, /* dst attrs*/ char* attrs, /* probe_mode */ int probing, /* socket */ struct socket_info *sock, /* state */ int state ) { static unsigned id_counter = 0; pgw_t *pgw=NULL, *tmp=NULL; struct sip_uri uri; int l_ip,l_pri,l_attrs,l_id; #define GWABUF_MAX_SIZE 512 char gwabuf[GWABUF_MAX_SIZE]; union sockaddr_union sau; struct proxy_l *proxy; unsigned int sip_prefix; str gwas; if (NULL==r || NULL==ip) { LM_ERR("invalid parametres\n"); goto err_exit; } l_id = strlen(id); l_ip = strlen(ip); l_pri = pri?strlen(pri):0; l_attrs = attrs?strlen(attrs):0; /* check if GW address starts with 'sip' or 'sips' */ if (l_ip>5) { if ( strncasecmp("sip:", ip, 4)==0) sip_prefix = 4; else if ( strncasecmp("sips:", ip, 5)==0) sip_prefix = 5; else sip_prefix = 0; } else sip_prefix = 0; if( sip_prefix==0 ) { if(l_ip+4>=GWABUF_MAX_SIZE) { LM_ERR("GW address (%d) longer " "than %d\n",l_ip+4,GWABUF_MAX_SIZE); goto err_exit; } memcpy(gwabuf, "sip:", 4); memcpy(gwabuf+4, ip, l_ip); gwas.s = gwabuf; gwas.len = 4+l_ip; } else { gwas.s = ip; gwas.len = l_ip; } /* parse the normalized address as a SIP URI */ memset(&uri, 0, sizeof(struct sip_uri)); if(parse_uri(gwas.s, gwas.len, &uri)!=0) { LM_ERR("invalid uri <%.*s>\n", gwas.len, gwas.s); goto err_exit; } /* update the sip_prefix to skip to domain part */ if (uri.user.len) sip_prefix += uri.host.s - uri.user.s; /* allocate new structure */ pgw = (pgw_t*)shm_malloc(sizeof(pgw_t) + l_id + (l_ip-sip_prefix) + l_pri + l_attrs); if (NULL==pgw) { LM_ERR("no more shm mem (%u)\n", (unsigned int)(sizeof(pgw_t)+l_id+l_ip-sip_prefix+l_pri +l_attrs)); goto err_exit; } memset(pgw,0,sizeof(pgw_t)); /* set probing related flags */ switch(probing) { case 0: break; case 1: pgw->flags |= DR_DST_PING_DSBL_FLAG; break; case 2: pgw->flags |= DR_DST_PING_PERM_FLAG; break; default: goto err_exit; } /* set state related flags */ switch(state) { case 0: break; case 1: pgw->flags |= DR_DST_STAT_DSBL_FLAG|DR_DST_STAT_NOEN_FLAG; break; case 2: pgw->flags |= DR_DST_STAT_DSBL_FLAG; break; default: goto err_exit; } /* set outbound socket */ pgw->sock = sock; pgw->_id = ++id_counter; pgw->id.len= l_id; pgw->id.s = (char*)(pgw+1); memcpy(pgw->id.s, id, l_id); pgw->ip_str.len= l_ip-sip_prefix; pgw->ip_str.s = (char*)(pgw+1)+l_id; memcpy(pgw->ip_str.s, ip+sip_prefix, l_ip-sip_prefix); if (pri) { pgw->pri.len = l_pri; pgw->pri.s = ((char*)(pgw+1))+l_id+l_ip-sip_prefix; memcpy(pgw->pri.s, pri, l_pri); } if (attrs) { pgw->attrs.len = l_attrs; pgw->attrs.s = ((char*)(pgw+1))+l_id+l_ip-sip_prefix+l_pri; memcpy(pgw->attrs.s, attrs, l_attrs); } pgw->strip = strip; pgw->type = type; /* add address in the global list of destinations/GWs */ proxy = mk_proxy(&uri.host,uri.port_no,uri.proto,(uri.type==SIPS_URI_T)); if (proxy==NULL) { if(dr_force_dns) { LM_ERR("cannot resolve <%.*s>\n", uri.host.len, uri.host.s); goto err_exit; } else { LM_DBG("cannot resolve <%.*s> - won't be used" " by is_from_gw()\n", uri.host.len, uri.host.s); goto done; } } hostent2ip_addr( &pgw->ips[0], &proxy->host, proxy->addr_idx); pgw->ports[0] = proxy->port; LM_DBG("first gw ip addr [%s]\n", ip_addr2a(&pgw->ips[0])); pgw->ips_no = 1; while (pgw->ips_no<DR_MAX_IPS && (get_next_su( proxy, &sau, 0)==0) ) { su2ip_addr( &pgw->ips[pgw->ips_no], &sau); pgw->ports[pgw->ips_no] = proxy->port; LM_DBG("additional gw ip addr [%s]\n", ip_addr2a( &pgw->ips[pgw->ips_no] ) ); pgw->ips_no++; } free_proxy(proxy); pkg_free(proxy); done: if(NULL==r->pgw_l) r->pgw_l = pgw; else { tmp = r->pgw_l; while(NULL != tmp->next) tmp = tmp->next; tmp->next = pgw; } return 0; err_exit: if(NULL!=pgw) shm_free(pgw); return -1; }
/* function returns: * 1 - forward successful * -1 - error during forward */ int t_forward_nonack( struct cell *t, struct sip_msg* p_msg , struct proxy_l * proxy) { str backup_uri; str backup_dst; int branch_ret, lowest_ret; str current_uri; branch_bm_t added_branches; int i, q; struct cell *t_invite; int success_branch; str dst_uri; struct socket_info *bk_sock; unsigned int br_flags; unsigned int bk_br_flags; int idx; str path; str bk_path; /* make -Wall happy */ current_uri.s=0; /* before doing enything, update the t falgs from msg */ t->uas.request->flags = p_msg->flags; if (p_msg->REQ_METHOD==METHOD_CANCEL) { t_invite=t_lookupOriginalT( p_msg ); if (t_invite!=T_NULL_CELL) { t_invite->flags |= T_WAS_CANCELLED_FLAG; cancel_invite( p_msg, t, t_invite ); return 1; } } /* do not forward requests which were already cancelled*/ if (was_cancelled(t) || no_new_branches(t)) { LM_ERR("discarding fwd for a cancelled/6xx transaction\n"); ser_error = E_NO_DESTINATION; return -1; } /* backup current uri, sock and flags... add_uac changes it */ backup_uri = p_msg->new_uri; backup_dst = p_msg->dst_uri; bk_sock = p_msg->force_send_socket; bk_br_flags = getb0flags(); bk_path = p_msg->path_vec; /* check if the UAS retranmission port needs to be updated */ if ( (p_msg->msg_flags ^ t->uas.request->msg_flags) & FL_FORCE_RPORT ) su_setport( &t->uas.response.dst.to, p_msg->rcv.src_port ); /* if no more specific error code is known, use this */ lowest_ret=E_BUG; /* branches added */ added_branches=0; /* branch to begin with */ t->first_branch=t->nr_of_outgoings; /* as first branch, use current uri */ current_uri = *GET_RURI(p_msg); branch_ret = add_uac( t, p_msg, ¤t_uri, &backup_dst, &p_msg->path_vec, proxy); if (branch_ret>=0) added_branches |= 1<<branch_ret; else lowest_ret=branch_ret; /* ....and now add the remaining additional branches */ for( idx=0; (current_uri.s=get_branch( idx, ¤t_uri.len, &q, &dst_uri, &path, &br_flags, &p_msg->force_send_socket))!=0 ; idx++ ) { setb0flags(br_flags); branch_ret = add_uac( t, p_msg, ¤t_uri, &dst_uri, &path, proxy); /* pick some of the errors in case things go wrong; note that picking lowest error is just as good as any other algorithm which picks any other negative branch result */ if (branch_ret>=0) added_branches |= 1<<branch_ret; else lowest_ret=branch_ret; } /* consume processed branches */ clear_branches(); /* restore original stuff */ p_msg->new_uri=backup_uri; p_msg->parsed_uri_ok = 0;/* just to be sure; add_uac may parse other uris*/ p_msg->dst_uri = backup_dst; p_msg->force_send_socket = bk_sock; p_msg->path_vec = bk_path; setb0flags(bk_br_flags); /* update on_branch, if modified */ t->on_branch = get_on_branch(); /* update flags, if changed in branch route */ t->uas.request->flags = p_msg->flags; /* things went wrong ... no new branch has been fwd-ed at all */ if (added_branches==0) { LM_ERR("failure to add branches\n"); ser_error = lowest_ret; return lowest_ret; } /* send them out now */ success_branch=0; for (i=t->first_branch; i<t->nr_of_outgoings; i++) { if (added_branches & (1<<i)) { #ifdef USE_TCP if (t->uac[i].br_flags & tcp_no_new_conn_bflag) tcp_no_new_conn = 1; #endif do { if (check_blacklists( t->uac[i].request.dst.proto, &t->uac[i].request.dst.to, t->uac[i].request.buffer.s, t->uac[i].request.buffer.len)) { LM_DBG("blocked by blacklists\n"); ser_error=E_IP_BLOCKED; } else { if (SEND_BUFFER( &t->uac[i].request)==0) { ser_error = 0; break; } LM_ERR("sending request failed\n"); ser_error=E_SEND; } /* get next dns entry */ if ( t->uac[i].proxy==0 || get_next_su( t->uac[i].proxy, &t->uac[i].request.dst.to, (ser_error==E_IP_BLOCKED)?0:1)!=0 ) break; t->uac[i].request.dst.proto = t->uac[i].proxy->proto; /* update branch */ if ( update_uac_dst( p_msg, &t->uac[i] )!=0) break; }while(1); #ifdef USE_TCP tcp_no_new_conn = 0; #endif if (ser_error) { shm_free(t->uac[i].request.buffer.s); t->uac[i].request.buffer.s = NULL; t->uac[i].request.buffer.len = 0; continue; } success_branch++; start_retr( &t->uac[i].request ); set_kr(REQ_FWDED); /* successfully sent out -> run callbacks */ if ( has_tran_tmcbs( t, TMCB_REQUEST_BUILT) ) { set_extra_tmcb_params( &t->uac[i].request.buffer, &t->uac[i].request.dst); run_trans_callbacks( TMCB_REQUEST_BUILT, t, p_msg,0, -p_msg->REQ_METHOD); } } } return (success_branch>0)?1:-1; }
static int trace_send_hep_duplicate(str *body, str *fromproto, str *fromip, unsigned short fromport, str *toproto, str *toip, unsigned short toport) { struct proxy_l * p=NULL /* make gcc happy */; int ret; union sockaddr_union from_su; union sockaddr_union to_su; unsigned int proto; struct socket_info* send_sock; union sockaddr_union* to = NULL; int heplen; char *hepbuf; if(body->s==NULL || body->len <= 0) return -1; if(dup_uri_str.s==0 || dup_uri==NULL) return 0; /* Convert proto:ip:port to sockaddress union SRC IP */ if (pipport2su(fromproto, fromip, fromport, &from_su, &proto)==-1 || (pipport2su(toproto, toip, toport, &to_su, &proto)==-1)) goto error; /* check if from and to are in the same family*/ if(from_su.s.sa_family != to_su.s.sa_family) { LM_ERR("ERROR: trace_send_hep_duplicate: interworking detected ?\n"); goto error; } /* create a temporary proxy*/ proto = PROTO_UDP; p=mk_proxy(&dup_uri->host, (dup_uri->port_no)?dup_uri->port_no:SIP_PORT,proto, 0); if (p==0){ LM_ERR("bad host name in uri\n"); return -1; } to=(union sockaddr_union*)pkg_malloc(sizeof(union sockaddr_union)); if (to==0){ LM_ERR("out of pkg memory\n"); return -1; } hostent2su(to, &p->host, p->addr_idx, (p->port)?p->port:SIP_PORT); if (hep_api.pack_hep(&from_su, to, proto, body->s, body->len, &hepbuf, &heplen)) { LM_ERR("failed to do hep packing\n"); return -1; } ret = -1; do { send_sock=get_send_socket(0, to, proto); if (send_sock==0){ LM_ERR("can't forward to af %d, proto %d no corresponding listening socket\n", to->s.sa_family,proto); continue; } if (msg_send(send_sock, PROTO_HEP, to, 0, hepbuf, heplen, NULL)<0){ LM_ERR("cannot send duplicate message\n"); continue; } ret = 0; break; }while( get_next_su( p, to, 0)==0 ); free_proxy(p); /* frees only p content, not p itself */ pkg_free(p); pkg_free(to); pkg_free(hepbuf); return ret; error: if(p) { free_proxy(p); /* frees only p content, not p itself */ pkg_free(p); } if(to) pkg_free(to); return -1; }
int forward_request( struct sip_msg* msg, struct proxy_l * p) { union sockaddr_union to; unsigned int len; char* buf; struct socket_info* send_sock; struct socket_info* last_sock; str *branch; buf=0; /* calculate branch for outbound request - if the branch buffer is already * set (maybe by an upper level as TM), used it; otherwise computes * the branch for stateless fwd. . According to the latest discussions * on the topic, you should reuse the latest statefull branch * --bogdan */ if ( msg->add_to_branch_len==0 ) { branch = get_sl_branch(msg); if (branch==0) { LM_ERR("unable to compute branch\n"); goto error; } msg->add_to_branch_len = branch->len; memcpy( msg->add_to_branch_s, branch->s, branch->len); } msg_callback_process(msg, REQ_PRE_FORWARD, (void *)p); hostent2su( &to, &p->host, p->addr_idx, (p->port)?p->port:SIP_PORT); last_sock = 0; if (getb0flags() & tcp_no_new_conn_bflag) tcp_no_new_conn = 1; do { send_sock=get_send_socket( msg, &to, p->proto); if (send_sock==0){ LM_ERR("cannot forward to af %d, proto %d no corresponding" "listening socket\n", to.s.sa_family, p->proto); ser_error=E_NO_SOCKET; continue; } if ( last_sock!=send_sock ) { if (buf) pkg_free(buf); buf = build_req_buf_from_sip_req(msg, &len, send_sock, p->proto, 0); if (!buf){ LM_ERR("building req buf failed\n"); tcp_no_new_conn = 0; goto error; } last_sock = send_sock; } if (check_blacklists( p->proto, &to, buf, len)) { LM_DBG("blocked by blacklists\n"); ser_error=E_IP_BLOCKED; continue; } /* send it! */ LM_DBG("sending:\n%.*s.\n", (int)len, buf); LM_DBG("orig. len=%d, new_len=%d, proto=%d\n", msg->len, len, p->proto ); if (msg_send(send_sock, p->proto, &to, 0, buf, len)<0){ ser_error=E_SEND; continue; } run_fwd_callbacks( msg, buf, len, send_sock, p->proto, &to); ser_error = 0; break; }while( get_next_su( p, &to, (ser_error==E_IP_BLOCKED)?0:1)==0 ); tcp_no_new_conn = 0; if (ser_error) { update_stat( drp_reqs, 1); goto error; } /* sent requests stats */ update_stat( fwd_reqs, 1); pkg_free(buf); /* received_buf & line_buf will be freed in receive_msg by free_lump_list*/ return 0; error: if (buf) pkg_free(buf); return -1; }
static inline int do_dns_failover(struct cell *t) { static struct sip_msg faked_req; struct sip_msg *shmem_msg; struct sip_msg *req; struct ua_client *uac; dlg_t dialog; int ret, sip_msg_len; uac = &t->uac[picked_branch]; /* check if the DNS resolver can get at least one new IP */ if ( get_next_su( uac->proxy, &uac->request.dst.to, 1)!=0 ) return -1; LM_DBG("new destination available\n"); if (t->uas.request==NULL) { if (!is_local(t)) { LM_CRIT("BUG: proxy transaction without UAS request :-/\n"); return -1; } /* create the cloned SIP msg -> first create a new SIP msg */ memset( &dialog, 0, sizeof(dialog)); dialog.send_sock = uac->request.dst.send_sock; dialog.hooks.next_hop = &uac->uri; req = buf_to_sip_msg(uac->request.buffer.s, uac->request.buffer.len, &dialog); if (req==NULL) { LM_ERR("failed to generate SIP msg from previous buffer\n"); return -1; } /* now do the actual cloning of the SIP message */ t->uas.request = sip_msg_cloner( req, &sip_msg_len, 1); if (t->uas.request==NULL) { LM_ERR("cloning failed\n"); free_sip_msg(req); return -1; } t->uas.end_request = ((char*)t->uas.request) + sip_msg_len; /* free the actual SIP message, keep the clone only */ free_sip_msg(req); /* the sip_msg structure is static in buf_to_sip_msg, so no need to free it */ } shmem_msg = t->uas.request; if (!fake_req(&faked_req, shmem_msg, &t->uas, uac, 1/*with dst_uri*/)) { LM_ERR("fake_req failed\n"); return -1; } /* fake also the env. conforming to the fake msg */ faked_env( t, &faked_req); ret = -1; /* set info as current destination */ if ( set_ruri( &faked_req, &uac->uri)!= 0) goto done; setb0flags( &faked_req, uac->br_flags ); faked_req.force_send_socket = shmem_msg->force_send_socket; /* send it out */ if (t_forward_nonack( t, &faked_req, uac->proxy)==1) ret = 0; done: /* restore original environment and free the fake msg */ faked_env( t, 0); free_faked_req(&faked_req,t); return ret; }
int add_dst( rt_data_t *r, /* id */ int id, /* ip address */ char* ip, /* strip len */ int strip, /* pri prefix */ char* pri, /* dst type*/ int type, /* dst attrs*/ char* attrs, /* probe_mode */ int probing ) { pgw_t *pgw=NULL, *tmp=NULL; struct sip_uri uri; int l_ip,l_pri,l_attrs; #define GWABUF_MAX_SIZE 512 char gwabuf[GWABUF_MAX_SIZE]; union sockaddr_union sau; struct proxy_l *proxy; str gwas; if (NULL==r || NULL==ip) { LM_ERR("invalid parametres\n"); goto err_exit; } l_ip = strlen(ip); l_pri = pri?strlen(pri):0; l_attrs = attrs?strlen(attrs):0; pgw = (pgw_t*)shm_malloc(sizeof(pgw_t) + l_ip + l_pri + l_attrs); if (NULL==pgw) { LM_ERR("no more shm mem (%u)\n", (unsigned int)(sizeof(pgw_t)+l_ip+l_pri +l_attrs)); goto err_exit; } memset(pgw,0,sizeof(pgw_t)); switch(probing) { case 0: pgw->flags = 0; break; case 1: pgw->flags = DR_DST_PING_DSBL_FLAG; break; case 2: pgw->flags = DR_DST_PING_PERM_FLAG; break; default: goto err_exit; } pgw->ip_str.len= l_ip; pgw->ip_str.s = (char*)(pgw+1); memcpy(pgw->ip_str.s, ip, l_ip); if (pri) { pgw->pri.len = l_pri; pgw->pri.s = ((char*)(pgw+1))+l_ip; memcpy(pgw->pri.s, pri, l_pri); } if (attrs) { pgw->attrs.len = l_attrs; pgw->attrs.s = ((char*)(pgw+1))+l_ip+l_pri; memcpy(pgw->attrs.s, attrs, l_attrs); } pgw->id = id; pgw->strip = strip; pgw->type = type; /* add address in the list */ if(pgw->ip_str.len<5 || (strncasecmp("sip:", ip, 4) && strncasecmp("sips:", ip, 5))) { if(pgw->ip_str.len+4>=GWABUF_MAX_SIZE) { LM_ERR("GW address (%d) longer " "than %d\n",pgw->ip_str.len+4,GWABUF_MAX_SIZE); goto err_exit; } memcpy(gwabuf, "sip:", 4); memcpy(gwabuf+4, ip, l_ip); gwas.s = gwabuf; gwas.len = 4+l_ip; } else { gwas.s = ip; gwas.len = l_ip; } memset(&uri, 0, sizeof(struct sip_uri)); if(parse_uri(gwas.s, gwas.len, &uri)!=0) { LM_ERR("invalid uri <%.*s>\n", gwas.len, gwas.s); goto err_exit; } proxy = mk_proxy(&uri.host,uri.port_no,uri.proto,(uri.type==SIPS_URI_T)); if (proxy==NULL) { if(dr_force_dns) { LM_ERR("cannot resolve <%.*s>\n", uri.host.len, uri.host.s); goto err_exit; } else { LM_DBG("cannot resolve <%.*s> - won't be used" " by is_from_gw()\n", uri.host.len, uri.host.s); goto done; } } hostent2ip_addr( &pgw->ips[0], &proxy->host, proxy->addr_idx); pgw->port = uri.port_no; LM_DBG("first gw ip addr [%s]\n", ip_addr2a(&pgw->ips[0])); pgw->ips_no = 1; while (pgw->ips_no<DR_MAX_IPS && (get_next_su( proxy, &sau, 0)==0) ) { su2ip_addr( &pgw->ips[pgw->ips_no], &sau); LM_DBG("additional gw ip addr [%s]\n", ip_addr2a( &pgw->ips[pgw->ips_no] ) ); pgw->ips_no++; } free_proxy(proxy); pkg_free(proxy); done: if(NULL==r->pgw_l) r->pgw_l = pgw; else { tmp = r->pgw_l; while(NULL != tmp->next) tmp = tmp->next; tmp->next = pgw; } return 0; err_exit: if(NULL!=pgw) shm_free(pgw); return -1; }
int add_dest2list(int id, str uri, struct socket_info *sock, int flags, int weight, str attrs, int list_idx, int * setn) { ds_dest_p dp = NULL; ds_set_p sp = NULL; struct sip_uri puri; /* For DNS-Lookups */ struct proxy_l *proxy; union sockaddr_union sau; /* check uri */ if(parse_uri(uri.s, uri.len, &puri)!=0 || puri.host.len>254) { LM_ERR("bad uri [%.*s]\n", uri.len, uri.s); goto err; } /* get dest set */ sp = ds_lists[list_idx]; while(sp) { if(sp->id == id) break; sp = sp->next; } if(sp==NULL) { sp = (ds_set_p)shm_malloc(sizeof(ds_set_t)); if(sp==NULL) { LM_ERR("no more memory.\n"); goto err; } memset(sp, 0, sizeof(ds_set_t)); sp->next = ds_lists[list_idx]; ds_lists[list_idx] = sp; *setn = *setn+1; } sp->id = id; sp->nr++; dp = (ds_dest_p)shm_malloc(sizeof(ds_dest_t)); if(dp==NULL) { LM_ERR("no more memory!\n"); goto err; } memset(dp, 0, sizeof(ds_dest_t)); /* store uri and attrs strings */ dp->uri.s = (char*)shm_malloc( (uri.len+1+attrs.len+1)*sizeof(char)); if(dp->uri.s==NULL) { LM_ERR("no more shm memory!\n"); goto err; } memcpy(dp->uri.s, uri.s, uri.len); dp->uri.s[uri.len]='\0'; dp->uri.len = uri.len; if (attrs.len) { dp->attrs.s = dp->uri.s + dp->uri.len + 1; memcpy(dp->attrs.s, attrs.s, attrs.len); dp->attrs.s[attrs.len]='\0'; dp->attrs.len = attrs.len; } /* copy flags, weight & socket */ dp->flags = flags; dp->weight = weight; dp->sock = sock; /* Do a DNS-Lookup for the Host-Name: */ proxy = mk_proxy( &puri.host, puri.port_no, puri.proto, (puri.type==SIPS_URI_T)); if (proxy==NULL) { LM_ERR("could not resolve %.*s, skipping it\n", puri.host.len, puri.host.s); goto err; } hostent2ip_addr( &dp->ips[0], &proxy->host, proxy->addr_idx); dp->ports[0] = proxy->port; dp->ips_cnt = 1; LM_DBG("first gw ip addr [%s]:%d\n", ip_addr2a(&dp->ips[0]), dp->ports[0]); /* get the next available IPs from DNS */ while (dp->ips_cnt<DS_MAX_IPS && (get_next_su( proxy, &sau, 0)==0) ) { su2ip_addr( &dp->ips[dp->ips_cnt], &sau); dp->ports[dp->ips_cnt] = proxy->port; LM_DBG("additional gw ip addr [%s]:%d\n", ip_addr2a(&dp->ips[dp->ips_cnt]), dp->ports[dp->ips_cnt]); /* one more IP found */ dp->ips_cnt++; } /* free al the helper structures */ free_proxy(proxy); pkg_free(proxy); dp->next = sp->dlist; sp->dlist = dp; LM_DBG("dest [%d/%d] <%.*s> successfully loaded\n", sp->id, sp->nr, dp->uri.len, dp->uri.s); return 0; err: /* free allocated memory */ if(dp!=NULL) { if(dp->uri.s!=NULL) shm_free(dp->uri.s); shm_free(dp); } return -1; }