int dst_is_blacklisted(struct dest_info* si, struct sip_msg* msg) { int ires; struct ip_addr ip; #ifdef DST_BLACKLIST_HOOKS unsigned char err_flags; int action; #endif su2ip_addr(&ip, &si->to); #ifdef DST_BLACKLIST_HOOKS err_flags=0; if (unlikely((action=(blacklist_run_hooks(&blst_search_cb, si, &err_flags, msg)) ) != DST_BLACKLIST_CONTINUE)){ if (action==DST_BLACKLIST_DENY) return 0; else /* if (action==DST_BLACKLIST_ACCEPT) */ return err_flags; } #endif ires=dst_is_blacklisted_ip(si->proto, &ip, su_getport(&si->to)); #ifdef USE_DST_BLACKLIST_STATS if (ires) dst_blacklist_stats[process_no].bkl_hit_cnt++; #endif return ires; }
static int ki_set_source_address(sip_msg_t *msg, str *saddr) { sr_phostp_t rp; union sockaddr_union faddr; char cproto; int ret; if(msg==NULL || saddr==NULL || saddr->len<=0) { LM_ERR("bad parameters\n"); return -1; } if(parse_protohostport(saddr, &rp)<0) { LM_ERR("failed to parse the address [%.*s]\n", saddr->len, saddr->s); return -1; } cproto = (char)rp.proto; ret = sip_hostport2su(&faddr, &rp.host, (unsigned short)rp.port, &cproto); if(ret!=0) { LM_ERR("failed to resolve address [%.*s]\n", saddr->len, saddr->s); return -1; } msg->rcv.src_su=faddr; su2ip_addr(&msg->rcv.src_ip, &faddr); msg->rcv.src_port=rp.port; return 1; }
/* * process_stun_msg(): * buf - incoming message * len - length of incoming message * ri - information about socket that received a message and * also information about sender (its IP, port, protocol) * * This function ensures processing of incoming message. It's common for both * TCP and UDP protocol. There is no other function as an interface. * * Return value: 0 if there is no environment error * -1 if there is some enviroment error such as insufficiency * of memory * */ int process_stun_msg(char* buf, unsigned len, struct receive_info* ri) { struct stun_msg msg_req; struct stun_msg msg_res; struct dest_info dst; struct stun_unknown_att* unknown; USHORT_T error_code; memset(&msg_req, 0, sizeof(msg_req)); memset(&msg_res, 0, sizeof(msg_res)); msg_req.msg.buf.s = buf; msg_req.msg.buf.len = len; unknown = NULL; error_code = RESPONSE_OK; if (stun_parse_header(&msg_req, &error_code) != 0) { goto error; } if (error_code == RESPONSE_OK) { if (stun_parse_body(&msg_req, &unknown, &error_code) != 0) { goto error; } } if (stun_create_response(&msg_req, &msg_res, ri, unknown, error_code) != 0) { goto error; } init_dst_from_rcv(&dst, ri); #ifdef EXTRA_DEBUG struct ip_addr ip; su2ip_addr(&ip, &dst.to); LOG(L_DBG, "DEBUG: process_stun_msg: decoded request from (%s:%d)\n", ip_addr2a(&ip), su_getport(&dst.to)); #endif /* send STUN response */ if (msg_send(&dst, msg_res.msg.buf.s, msg_res.msg.buf.len) != 0) { goto error; } #ifdef EXTRA_DEBUG LOG(L_DBG, "DEBUG: process_stun_msg: send response\n"); #endif clean_memory(&msg_req, &msg_res, unknown); return 0; error: #ifdef EXTRA_DEBUG LOG(L_DBG, "DEBUG: process_stun_msg: failed to decode request\n"); #endif clean_memory(&msg_req, &msg_res, unknown); return FATAL_ERROR; }
struct tcp_connection* tcpconn_connect(union sockaddr_union* server, int type) { int s; struct socket_info* si; union sockaddr_union my_name; socklen_t my_name_len; struct tcp_connection* con; struct ip_addr ip; s=socket(AF2PF(server->s.sa_family), SOCK_STREAM, 0); if (s==-1){ LOG(L_ERR, "ERROR: tcpconn_connect: socket: (%d) %s\n", errno, strerror(errno)); goto error; } if (init_sock_opt(s)<0){ LOG(L_ERR, "ERROR: tcpconn_connect: init_sock_opt failed\n"); goto error; } if (tcp_blocking_connect(s, &server->s, sockaddru_len(*server))<0){ LOG(L_ERR, "ERROR: tcpconn_connect: tcp_blocking_connect failed\n"); goto error; } my_name_len=sizeof(my_name); if (getsockname(s, &my_name.s, &my_name_len)!=0){ LOG(L_ERR, "ERROR: tcp_connect: getsockname failed: %s(%d)\n", strerror(errno), errno); si=0; /* try to go on */ } su2ip_addr(&ip, &my_name); #ifdef USE_TLS if (type==PROTO_TLS) si=find_si(&ip, 0, PROTO_TLS); else #endif si=find_si(&ip, 0, PROTO_TCP); if (si==0){ LOG(L_ERR, "ERROR: tcp_connect: could not find corresponding" " listening socket, using default...\n"); if (server->s.sa_family==AF_INET) si=sendipv4_tcp; #ifdef USE_IPV6 else si=sendipv6_tcp; #endif } con=tcpconn_new(s, server, si, type, S_CONN_CONNECT); if (con==0){ LOG(L_ERR, "ERROR: tcp_connect: tcpconn_new failed, closing the " " socket\n"); goto error; } return con; /*FIXME: set sock idx! */ error: if (s!=-1) close(s); /* close the opened socket */ return 0; }
int proto_sctp_read(struct socket_info *si, int* bytes_read) { struct receive_info ri; int len; #ifdef DYN_BUF char* buf; #else static char buf [BUF_SIZE+1]; #endif char *tmp; unsigned int fromlen; struct sctp_sndrcvinfo sinfo; #ifdef DYN_BUF buf=pkg_malloc(BUF_SIZE+1); if (buf==0) { LM_ERR(" could not allocate receive buffer in pkg memory\n"); goto error; } #endif fromlen=sockaddru_len(si->su); len = sctp_recvmsg(si->socket, buf, BUF_SIZE, &ri.src_su.s, &fromlen, &sinfo, 0); if (len==-1) { if (errno==EAGAIN) { LM_DBG("packet with bad checksum received\n"); return 0; } if ((errno==EINTR)||(errno==EWOULDBLOCK)|| (errno==ECONNREFUSED)) return -1; LM_ERR("sctp_recvmsg:[%d] %s\n", errno, strerror(errno)); return -2; } /* we must 0-term the messages, receive_msg expects it */ buf[len]=0; /* no need to save the previous char */ ri.bind_address = si; ri.dst_port = si->port_no; ri.dst_ip = si->address; ri.proto = si->proto; ri.proto_reserved1 = ri.proto_reserved2 = 0; su2ip_addr(&ri.src_ip, &ri.src_su); ri.src_port=su_getport(&ri.src_su); if (ri.src_port==0) { tmp=ip_addr2a(&ri.src_ip); LM_INFO("dropping 0 port packet from %s\n", tmp); return 0; } /* receive_msg must free buf too!*/ receive_msg(buf, len, &ri); return 0; }
struct tcp_connection* tcpconn_new(int sock, union sockaddr_union* su, struct socket_info* ba, int type, int state) { struct tcp_connection *c; c=(struct tcp_connection*)shm_malloc(sizeof(struct tcp_connection)); if (c==0){ LM_ERR("shared memory allocation failure\n"); goto error; } memset(c, 0, sizeof(struct tcp_connection)); /* zero init */ c->s=sock; c->fd=-1; /* not initialized */ if (lock_init(&c->write_lock)==0){ LM_ERR("init lock failed\n"); goto error; } c->rcv.src_su=*su; c->refcnt=0; su2ip_addr(&c->rcv.src_ip, su); c->rcv.src_port=su_getport(su); c->rcv.bind_address=ba; if (ba){ c->rcv.dst_ip=ba->address; c->rcv.dst_port=ba->port_no; } print_ip("tcpconn_new: new tcp connection to: ", &c->rcv.src_ip, "\n"); LM_DBG("on port %d, type %d\n", c->rcv.src_port, type); init_tcp_req(&c->req); c->id=(*connection_id)++; c->rcv.proto_reserved1=0; /* this will be filled before receive_message*/ c->rcv.proto_reserved2=0; c->state=state; c->extra_data=0; #ifdef USE_TLS if (type==PROTO_TLS){ if (tls_tcpconn_init(c, sock)==-1) goto error; }else #endif /* USE_TLS*/ { c->type=PROTO_TCP; c->rcv.proto=PROTO_TCP; c->timeout=get_ticks()+tcp_con_lifetime; } c->flags|=F_CONN_REMOVED; tcp_connections_no++; return c; error: if (c) shm_free(c); return 0; }
static struct tcp_connection* tcpconn_new(int sock, union sockaddr_union* su, struct socket_info* si, int state, int flags) { struct tcp_connection *c; c=(struct tcp_connection*)shm_malloc(sizeof(struct tcp_connection)); if (c==0){ LM_ERR("shared memory allocation failure\n"); return 0; } memset(c, 0, sizeof(struct tcp_connection)); /* zero init */ c->s=sock; c->fd=-1; /* not initialized */ if (lock_init(&c->write_lock)==0){ LM_ERR("init lock failed\n"); goto error0; } c->rcv.src_su=*su; c->refcnt=0; su2ip_addr(&c->rcv.src_ip, su); c->rcv.src_port=su_getport(su); c->rcv.bind_address = si; c->rcv.dst_ip = si->address; c->rcv.dst_port = si->port_no; print_ip("tcpconn_new: new tcp connection to: ", &c->rcv.src_ip, "\n"); LM_DBG("on port %d, proto %d\n", c->rcv.src_port, si->proto); c->id=(*connection_id)++; c->rcv.proto_reserved1=0; /* this will be filled before receive_message*/ c->rcv.proto_reserved2=0; c->state=state; c->extra_data=0; c->type = si->proto; c->rcv.proto = si->proto; /* start with the default conn lifetime */ c->lifetime = get_ticks()+tcp_con_lifetime; c->flags|=F_CONN_REMOVED|flags; if (protos[si->proto].net.conn_init && protos[si->proto].net.conn_init(c)<0) { LM_ERR("failed to do proto %d specific init for conn %p\n", si->proto,c); goto error1; } tcp_connections_no++; return c; error1: lock_destroy(&c->write_lock); error0: shm_free(c); return 0; }
struct tcp_conn *search_tcp_conn(unsigned int id, union sockaddr_union *to) { struct tcp_conn *conn; struct ip_addr ip; unsigned short port; unsigned int hash; port = su_getport(to); su2ip_addr( &ip, to); /* if an ID is available, search for it */ if (id!=0) { hash = tcp_hash( id, 0); lock_get( &hash_id_lock ); for( conn=hash_id_conns[hash] ; conn ; conn=conn->id_next ) { if (conn->id == id) { if (conn->state==TCP_CONN_TERM) break; /* validate the connection with ip and port! */ if ( ip_addr_cmp(&ip,&conn->rcv.src_ip) && (port==conn->rcv.src_port || port==conn->port_alias) ) { conn->ref++; lock_release( &hash_id_lock ); return conn; } /* conn id failed to match */ break; } } lock_release( &hash_id_lock ); /* conn id not found */ } /* search based on destination information (ip and port) */ hash = tcp_hash(ip.u.addr32[0],port); lock_get( &hash_ip_lock ); for( conn=hash_ip_conns[hash] ; conn ; conn=conn->ip_next ) { if ( conn->state!=TCP_CONN_TERM && ip_addr_cmp(&ip,&conn->rcv.src_ip) && (port==conn->rcv.src_port || port==conn->port_alias) ) { /* WARNING - take care, this is the only place where both * locks are taken in the same time - be aware of dead-locks! */ lock_get( &hash_id_lock ); conn->ref++; lock_release( &hash_id_lock ); lock_release( &hash_ip_lock ); return conn; } } lock_release( &hash_ip_lock ); return NULL; }
struct socket_info* find_tcp_si(union sockaddr_union* s) { int r; struct ip_addr ip; su2ip_addr(&ip, s); for (r=0; r<sock_no; r++) if (ip_addr_cmp(&ip, &tcp_info[r].address)){ /* found it, we use first match */ return &tcp_info[r]; } return 0; /* no match */ }
/** add dst to the blacklist, specifying the timeout. * @param err_flags - reason (bitmap) * @param si - destination (protocol, ip and port) * @param msg - sip message that triggered the blacklisting (can be 0 if * not known) * @param timeout - timeout in ticks * @return 0 on success, -1 on error */ int dst_blacklist_add_to(unsigned char err_flags, struct dest_info* si, struct sip_msg* msg, ticks_t timeout) { struct ip_addr ip; #ifdef DST_BLACKLIST_HOOKS if (unlikely (blacklist_run_hooks(&blst_add_cb, si, &err_flags, msg) == DST_BLACKLIST_DENY)) return 0; #endif su2ip_addr(&ip, &si->to); return dst_blacklist_add_ip(err_flags, si->proto, &ip, su_getport(&si->to), timeout); }
int pv_get_sndto(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) { struct onsend_info* snd_inf; struct ip_addr ip; str s; snd_inf=get_onsend_info(); if (! likely(snd_inf && snd_inf->send_sock)) return pv_get_null(msg, param, res); switch(param->pvn.u.isname.name.n) { case 1: /* af */ return pv_get_uintval(msg, param, res, (int)snd_inf->send_sock->address.af); case 2: /* port */ return pv_get_uintval(msg, param, res, (int)su_getport(snd_inf->to)); case 3: /* proto */ return pv_get_uintval(msg, param, res, (int)snd_inf->send_sock->proto); case 4: /* buf */ s.s = snd_inf->buf; s.len = snd_inf->len; return pv_get_strval(msg, param, res, &s); case 5: /* len */ return pv_get_uintval(msg, param, res, (int)snd_inf->len); case 6: /* sproto */ if(get_valid_proto_string((int)snd_inf->send_sock->proto, 0, 0, &s)<0) return pv_get_null(msg, param, res); return pv_get_strval(msg, param, res, &s); default: /* 0 - ip */ su2ip_addr(&ip, snd_inf->to); s.s = ip_addr2a(&ip); s.len = strlen(s.s); return pv_get_strval(msg, param, res, &s); } return 0; }
/** add dst to the blacklist, specifying the timeout. * (like @function dst_blacklist_add_to)= above, but uses * (proto, sockaddr_union) instead of struct dest_info) */ int dst_blacklist_su_to(unsigned char err_flags, unsigned char proto, union sockaddr_union* dst, struct sip_msg* msg, ticks_t timeout) { struct ip_addr ip; #ifdef DST_BLACKLIST_HOOKS struct dest_info si; init_dest_info(&si); si.to=*dst; si.proto=proto; if (unlikely (blacklist_run_hooks(&blst_add_cb, &si, &err_flags, msg) == DST_BLACKLIST_DENY)) return 0; #endif su2ip_addr(&ip, dst); return dst_blacklist_add_ip(err_flags, proto, &ip, su_getport(dst), timeout); }
/* returns 1 if the entry was deleted, 0 if not found */ int dst_blacklist_del(struct dest_info* si, struct sip_msg* msg) { unsigned short hash; struct ip_addr ip; ticks_t now; int ret; unsigned short port; ret=0; su2ip_addr(&ip, &si->to); port=su_getport(&si->to); now=get_ticks_raw(); hash=dst_blst_hash_no(si->proto, &ip, port); if (unlikely(dst_blst_hash[hash].first)){ LOCK_BLST(hash); ret=_dst_blacklist_del(hash, &ip, si->proto, port, now); UNLOCK_BLST(hash); } return ret; }
/*! \brief return a socket_info_pointer to the sending socket * \note As opposed to * get_send_socket(), which returns process's default socket, get_out_socket * attempts to determine the outbound interface which will be used; * it creates a temporary connected socket to determine it; it will * be very likely noticeably slower, but it can deal better with * multihomed hosts */ struct socket_info* get_out_socket(union sockaddr_union* to, int proto) { int temp_sock; socklen_t len; union sockaddr_union from; struct socket_info* si; struct ip_addr ip; if (proto!=PROTO_UDP) { LM_CRIT("can only be called for UDP\n"); return 0; } temp_sock=socket(to->s.sa_family, SOCK_DGRAM, 0 ); if (temp_sock==-1) { LM_ERR("socket() failed: %s\n", strerror(errno)); return 0; } if (connect(temp_sock, &to->s, sockaddru_len(*to))==-1) { LM_ERR("connect failed: %s\n", strerror(errno)); goto error; } len=sizeof(from); if (getsockname(temp_sock, &from.s, &len)==-1) { LM_ERR("getsockname failed: %s\n", strerror(errno)); goto error; } su2ip_addr(&ip, &from); si=find_si(&ip, 0, proto); if (si==0) goto error; close(temp_sock); LM_DBG("socket determined: %p\n", si ); return si; error: LM_ERR("no socket found\n"); close(temp_sock); return 0; }
static int add_node(clusterer_node_t **nodes, table_entry_value_t *head, int proto) { clusterer_node_t *new_node = NULL; struct ip_addr ip; new_node = pkg_malloc(sizeof *new_node); if (!new_node) { LM_ERR("no more pkg memory\n"); goto error; } new_node->next = NULL; new_node->description.s = NULL; new_node->machine_id = head->machine_id; new_node->state = head->state; new_node->proto = proto; memcpy(&new_node->addr, &head->addr, sizeof(head->addr)); new_node->description.s = pkg_malloc(head->description.len * sizeof(char)); if (!new_node->description.s) { LM_ERR("no more pkg memory\n"); goto error; } memcpy(new_node->description.s, head->description.s, head->description.len); su2ip_addr(&ip, &new_node->addr); new_node->description.len = head->description.len; if (*nodes) new_node->next = *nodes; *nodes = new_node; return 0; error: free_node(new_node); return -1; }
int parsing_hepv3_message(char *buf, unsigned int len) { union sockaddr_union from; union sockaddr_union to; struct receive_info ri; char *tmp; struct ip_addr dst_ip, src_ip; struct socket_info* si = 0; int tmp_len, i; char *payload = NULL; unsigned int payload_len = 0; struct hep_chunk *chunk; struct hep_generic_recv *hg; int totelem = 0; int chunk_vendor=0, chunk_type=0, chunk_length=0; int total_length = 0; hg = (struct hep_generic_recv*)pkg_malloc(sizeof(struct hep_generic_recv)); if(hg==NULL) { LM_ERR("no more pkg memory left for hg\n"); return -1; } memset(hg, 0, sizeof(struct hep_generic_recv)); memset(heptime, 0, sizeof(struct hep_timehdr)); /* HEADER */ hg->header = (hep_ctrl_t *) (buf); /*Packet size */ total_length = ntohs(hg->header->length); ri.src_port = 0; ri.dst_port = 0; dst_ip.af = 0; src_ip.af = 0; payload = NULL; correlation_id = NULL; authkey = NULL; i = sizeof(hep_ctrl_t); while(i < total_length) { /*OUR TMP DATA */ tmp = buf+i; chunk = (struct hep_chunk*) tmp; chunk_vendor = ntohs(chunk->vendor_id); chunk_type = ntohs(chunk->type_id); chunk_length = ntohs(chunk->length); /* if chunk_length */ if(chunk_length == 0) { /* BAD LEN we drop this packet */ goto error; } /* SKIP not general Chunks */ if(chunk_vendor != 0) { i+=chunk_length; } else { switch(chunk_type) { case 0: goto error; break; case 1: hg->ip_family = (hep_chunk_uint8_t *) (tmp); i+=chunk_length; totelem++; break; case 2: hg->ip_proto = (hep_chunk_uint8_t *) (tmp); i+=chunk_length; totelem++; break; case 3: hg->hep_src_ip4 = (hep_chunk_ip4_t *) (tmp); i+=chunk_length; src_ip.af=AF_INET; src_ip.len=4; src_ip.u.addr32[0] = hg->hep_src_ip4->data.s_addr; totelem++; break; case 4: hg->hep_dst_ip4 = (hep_chunk_ip4_t *) (tmp); i+=chunk_length; dst_ip.af=AF_INET; dst_ip.len=4; dst_ip.u.addr32[0] = hg->hep_dst_ip4->data.s_addr; totelem++; break; case 5: hg->hep_src_ip6 = (hep_chunk_ip6_t *) (tmp); i+=chunk_length; src_ip.af=AF_INET6; src_ip.len=16; memcpy(src_ip.u.addr, &hg->hep_src_ip6->data, 16); totelem++; break; case 6: hg->hep_dst_ip6 = (hep_chunk_ip6_t *) (tmp); i+=chunk_length; dst_ip.af=AF_INET6; dst_ip.len=16; memcpy(dst_ip.u.addr, &hg->hep_dst_ip6->data, 16); totelem++; break; case 7: hg->src_port = (hep_chunk_uint16_t *) (tmp); ri.src_port = ntohs(hg->src_port->data); i+=chunk_length; totelem++; break; case 8: hg->dst_port = (hep_chunk_uint16_t *) (tmp); ri.dst_port = ntohs(hg->dst_port->data); i+=chunk_length; totelem++; break; case 9: hg->time_sec = (hep_chunk_uint32_t *) (tmp); hg->time_sec->data = ntohl(hg->time_sec->data); heptime->tv_sec = hg->time_sec->data; i+=chunk_length; totelem++; break; case 10: hg->time_usec = (hep_chunk_uint32_t *) (tmp); hg->time_usec->data = ntohl(hg->time_usec->data); heptime->tv_usec = hg->time_usec->data; i+=chunk_length; totelem++; break; case 11: hg->proto_t = (hep_chunk_uint8_t *) (tmp); i+=chunk_length; totelem++; break; case 12: hg->capt_id = (hep_chunk_uint32_t *) (tmp); i+=chunk_length; heptime->captid = ntohs(hg->capt_id->data); totelem++; break; case 13: hg->keep_tm = (hep_chunk_uint16_t *) (tmp); i+=chunk_length; break; case 14: authkey = (char *) tmp + sizeof(hep_chunk_t); i+=chunk_length; break; case 15: hg->payload_chunk = (hep_chunk_t *) (tmp); payload = (char *) tmp+sizeof(hep_chunk_t); payload_len = chunk_length - sizeof(hep_chunk_t); i+=chunk_length; totelem++; break; case 17: correlation_id = (char *) tmp + sizeof(hep_chunk_t); i+=chunk_length; break; default: i+=chunk_length; break; } } } /* CHECK how much elements */ if(totelem < 9) { LM_ERR("Not all elements [%d]\n", totelem); goto done; } if ( dst_ip.af == 0 || src_ip.af == 0) { LM_ERR("NO IP's set\n"); goto done; } ip_addr2su(&to, &dst_ip, ri.dst_port); ip_addr2su(&from, &src_ip, ri.src_port); ri.src_su=from; su2ip_addr(&ri.src_ip, &from); su2ip_addr(&ri.dst_ip, &to); if(hg->ip_proto->data == IPPROTO_TCP) ri.proto=PROTO_TCP; else if(hg->ip_proto->data == IPPROTO_UDP) ri.proto=PROTO_UDP; /* a little bit memory */ si=(struct socket_info*) pkg_malloc(sizeof(struct socket_info)); if (si==0) { LOG(L_ERR, "ERROR: new_sock_info: memory allocation error\n"); goto error; } memset(si, 0, sizeof(struct socket_info)); si->address = ri.dst_ip; si->socket=-1; /* set port & proto */ si->port_no = ri.dst_port; if(hg->ip_proto->data == IPPROTO_TCP) si->proto=PROTO_TCP; else if(hg->ip_proto->data == IPPROTO_UDP) si->proto=PROTO_UDP; si->flags=0; si->addr_info_lst=0; si->address_str.s = ip_addr2a(&si->address);; si->address_str.len = strlen(si->address_str.s); si->port_no_str.s = int2str(si->port_no, &tmp_len); si->port_no_str.len = tmp_len; si->address_str.len = strlen(si->address_str.s); si->name.len = si->address_str.len; si->name.s = si->address_str.s; ri.bind_address=si; /*TIME*/ heptime->tv_sec = hg->time_sec->data; heptime->tv_usec = hg->time_usec->data; heptime->captid = ntohs(hg->capt_id->data); if(payload != NULL ) { /* and now recieve message */ if (hg->proto_t->data == 5) receive_logging_json_msg(payload, payload_len, hg, "rtcp_capture"); else if (hg->proto_t->data == 32) receive_logging_json_msg(payload, payload_len, hg, "report_capture"); else if (hg->proto_t->data == 99) receive_logging_json_msg(payload, payload_len, hg, "report_capture"); else if (hg->proto_t->data == 100) receive_logging_json_msg(payload, payload_len, hg, "logs_capture"); else receive_msg(payload, payload_len, &ri); } done: if(si) pkg_free(si); if(hg) pkg_free(hg); return 1; error: if(si) pkg_free(si); if(hg) pkg_free(hg); return -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; }
/** * Evaluate if next hop is a strict or loose router, by looking at the * retr. buffer of the original INVITE. * Assumes: * orig_inv is a parsed SIP message; * rtset is not NULL. * @return: * F_RB_NH_LOOSE : next hop was loose router; * F_RB_NH_STRICT: nh is strict; * 0 on error. */ static unsigned long nhop_type(sip_msg_t *orig_inv, rte_t *rtset, const struct dest_info *dst_inv, str *contact) { struct sip_uri puri, topr_uri, lastr_uri, inv_ruri, cont_uri; struct ip_addr *uri_ia; union sockaddr_union uri_sau; unsigned int uri_port, dst_port, inv_port, cont_port, lastr_port; rte_t *last_r; #ifdef TM_LOC_ACK_DO_REV_DNS struct ip_addr ia; struct hostent *he; char **alias; #endif #define PARSE_URI(_str_, _uri_) \ do { \ /* parse_uri() 0z the puri */ \ if (parse_uri((_str_)->s, \ (_str_)->len, _uri_) < 0) { \ LM_ERR("failed to parse route body '%.*s'.\n", STR_FMT(_str_)); \ return 0; \ } \ } while (0) #define HAS_LR(_rte_) \ ({ \ PARSE_URI(&(_rte_)->ptr->nameaddr.uri, &puri); \ puri.lr.s; \ }) #define URI_PORT(_puri_, _port) \ do { \ if (! (_port = uri2port(_puri_))) \ return 0; \ } while (0) /* examine the easy/fast & positive cases foremost */ /* [1] check if 1st route lacks ;lr */ LM_DBG("checking lack of ';lr' in 1st route.\n"); if (! HAS_LR(rtset)) return F_RB_NH_STRICT; topr_uri = puri; /* save 1st route's URI */ /* [2] check if last route shows ;lr */ LM_DBG("checking presence of ';lr' in last route.\n"); for (last_r = rtset; last_r->next; last_r = last_r->next) /* scroll down to last route */ ; if (HAS_LR(last_r)) return F_RB_NH_LOOSE; /* [3] 1st route has ;lr -> check if the destination of original INV * equals the address provided by this route; if does -> loose */ LM_DBG("checking INVITE's destination against its first route.\n"); URI_PORT(&topr_uri, uri_port); if (! (dst_port = su_getport(&dst_inv->to))) return 0; /* not really expected */ if (dst_port != uri_port) return F_RB_NH_STRICT; /* if 1st route contains an IP address, comparing it against .dst */ if ((uri_ia = str2ip(&topr_uri.host)) || (uri_ia = str2ip6(&topr_uri.host)) ) { /* we have an IP address in route -> comparison can go swiftly */ if (init_su(&uri_sau, uri_ia, uri_port) < 0) return 0; /* not really expected */ if (su_cmp(&uri_sau, &dst_inv->to)) /* ;lr and sent there */ return F_RB_NH_LOOSE; else /* ;lr and NOT sent there (probably sent to RURI address) */ return F_RB_NH_STRICT; } else { /*if 1st route contains a name, rev resolve the .dst and compare*/ LM_INFO("Failed to decode string '%.*s' in route set element as IP" " address. Trying name resolution.\n",STR_FMT(&topr_uri.host)); /* TODO: alternatively, rev name and compare against dest. IP. */ #ifdef TM_LOC_ACK_DO_REV_DNS ia.af = 0; su2ip_addr(&ia, (void *)&dst_inv->to); if (! ia.af) return 0; /* not really expected */ if ((he = rev_resolvehost(&ia))) { if ((strlen(he->h_name) == topr_uri.host.len) && (memcmp(he->h_name, topr_uri.host.s, topr_uri.host.len) == 0)) return F_RB_NH_LOOSE; for (alias = he->h_aliases; *alias; alias ++) if ((strlen(*alias) == topr_uri.host.len) && (memcmp(*alias, topr_uri.host.s, topr_uri.host.len) == 0)) return F_RB_NH_LOOSE; return F_RB_NH_STRICT; } else { LM_INFO("failed to resolve address '%s' to a name.\n", ip_addr2a(&ia)); } #endif } LM_WARN("failed to establish with certainty the type of next hop;" " trying an educated guess.\n"); /* [4] compare (possibly updated) remote target to original RURI; if * equal, a strict router's address wasn't filled in as RURI -> loose */ LM_DBG("checking remote target against INVITE's RURI.\n"); PARSE_URI(contact, &cont_uri); PARSE_URI(GET_RURI(orig_inv), &inv_ruri); URI_PORT(&cont_uri, cont_port); URI_PORT(&inv_ruri, inv_port); if ((cont_port == inv_port) && (cont_uri.host.len == inv_ruri.host.len) && (memcmp(cont_uri.host.s, inv_ruri.host.s, cont_uri.host.len) == 0)) return F_RB_NH_LOOSE; /* [5] compare (possibly updated) remote target to last route; if equal, * strict router's address might have been filled as RURI and remote * target appended to route set -> strict */ LM_DBG("checking remote target against INVITE's last route.\n"); PARSE_URI(&last_r->ptr->nameaddr.uri, &lastr_uri); URI_PORT(&lastr_uri, lastr_port); if ((cont_port == lastr_port) && (cont_uri.host.len == lastr_uri.host.len) && (memcmp(cont_uri.host.s, lastr_uri.host.s, lastr_uri.host.len) == 0)) return F_RB_NH_STRICT; LM_WARN("failed to establish the type of next hop;" " assuming loose router.\n"); return F_RB_NH_LOOSE; #undef PARSE_URI #undef HAS_LR #undef URI_PORT }
/* forwards a request to dst * parameters: * msg - sip msg * dst - destination name, if non-null it will be resolved and * send_info updated with the ip/port. Even if dst is non * null send_info must contain the protocol and if a non * default port or non srv. lookup is desired, the port must * be !=0 * port - used only if dst!=0 (else the port in send_info->to is used) * send_info - value/result partially filled dest_info structure: * - send_info->proto and comp are used * - send_info->to will be filled (dns) * - send_info->send_flags is filled from the message * - if the send_socket member is null, a send_socket will be * chosen automatically * WARNING: don't forget to zero-fill all the unused members (a non-zero * random id along with proto==PROTO_TCP can have bad consequences, same for * a bogus send_socket value) */ int forward_request(struct sip_msg* msg, str* dst, unsigned short port, struct dest_info* send_info) { unsigned int len; char* buf; char md5[MD5_LEN]; struct socket_info* orig_send_sock; /* initial send_sock */ int ret; struct ip_addr ip; /* debugging only */ char proto; #ifdef USE_DNS_FAILOVER struct socket_info* prev_send_sock; int err; struct dns_srv_handle dns_srv_h; prev_send_sock=0; err=0; #endif buf=0; orig_send_sock=send_info->send_sock; proto=send_info->proto; ret=0; if(dst){ #ifdef USE_DNS_FAILOVER if (cfg_get(core, core_cfg, use_dns_failover)){ dns_srv_handle_init(&dns_srv_h); err=dns_sip_resolve2su(&dns_srv_h, &send_info->to, dst, port, &proto, dns_flags); if (err!=0){ LOG(L_ERR, "ERROR: forward_request: resolving \"%.*s\"" " failed: %s [%d]\n", dst->len, ZSW(dst->s), dns_strerror(err), err); ret=E_BAD_ADDRESS; goto error; } }else #endif if (sip_hostport2su(&send_info->to, dst, port, &proto)<0){ LOG(L_ERR, "ERROR: forward_request: bad host name %.*s," " dropping packet\n", dst->len, ZSW(dst->s)); ret=E_BAD_ADDRESS; goto error; } }/* dst */ send_info->send_flags=msg->fwd_send_flags; /* calculate branch for outbound request; if syn_branch is turned off, calculate is from transaction key, i.e., as an md5 of From/To/CallID/ CSeq exactly the same way as TM does; good for reboot -- than messages belonging to transaction lost due to reboot will still be forwarded with the same branch parameter and will be match-able downstream if it is turned on, we don't care about reboot; we simply put a simple value in there; better for performance */ if (syn_branch ) { memcpy(msg->add_to_branch_s, "z9hG4bKcydzigwkX", 16); msg->add_to_branch_len=16; } else { if (!char_msg_val( msg, md5 )) { /* parses transaction key */ LOG(L_ERR, "ERROR: forward_request: char_msg_val failed\n"); ret=E_UNSPEC; goto error; } msg->hash_index=hash( msg->callid->body, get_cseq(msg)->number); if (!branch_builder( msg->hash_index, 0, md5, 0 /* 0-th branch */, msg->add_to_branch_s, &msg->add_to_branch_len )) { LOG(L_ERR, "ERROR: forward_request: branch_builder failed\n"); ret=E_UNSPEC; goto error; } } /* try to send the message until success or all the ips are exhausted * (if dns lookup is performed && the dns cache used ) */ #ifdef USE_DNS_FAILOVER do{ #endif if (orig_send_sock==0) /* no forced send_sock => find it **/ send_info->send_sock=get_send_socket(msg, &send_info->to, proto); if (send_info->send_sock==0){ LOG(L_ERR, "forward_req: ERROR: cannot forward to af %d, proto %d " "no corresponding listening socket\n", send_info->to.s.sa_family, proto); ret=ser_error=E_NO_SOCKET; #ifdef USE_DNS_FAILOVER /* continue, maybe we find a socket for some other ip */ continue; #else goto error; #endif } #ifdef USE_DNS_FAILOVER if (prev_send_sock!=send_info->send_sock){ /* rebuild the message only if the send_sock changed */ prev_send_sock=send_info->send_sock; #endif if (buf) pkg_free(buf); send_info->proto=proto; buf = build_req_buf_from_sip_req(msg, &len, send_info, 0); if (!buf){ LOG(L_ERR, "ERROR: forward_request: building failed\n"); ret=E_OUT_OF_MEM; /* most probable */ goto error; } #ifdef USE_DNS_FAILOVER } #endif /* send it! */ DBG("Sending:\n%.*s.\n", (int)len, buf); DBG("orig. len=%d, new_len=%d, proto=%d\n", msg->len, len, send_info->proto ); if (run_onsend(msg, send_info, buf, len)==0){ su2ip_addr(&ip, &send_info->to); LOG(L_INFO, "forward_request: request to %s:%d(%d) dropped" " (onsend_route)\n", ip_addr2a(&ip), su_getport(&send_info->to), send_info->proto); ser_error=E_OK; /* no error */ ret=E_ADM_PROHIBITED; #ifdef USE_DNS_FAILOVER continue; /* try another ip */ #else goto error; /* error ? */ #endif } #ifdef USE_DST_BLACKLIST if (cfg_get(core, core_cfg, use_dst_blacklist)){ if (dst_is_blacklisted(send_info, msg)){ su2ip_addr(&ip, &send_info->to); LOG(L_DBG, "DEBUG: blacklisted destination:%s:%d (%d)\n", ip_addr2a(&ip), su_getport(&send_info->to), send_info->proto); ret=ser_error=E_SEND; #ifdef USE_DNS_FAILOVER continue; /* try another ip */ #else goto error; #endif } } #endif if (msg_send(send_info, buf, len)<0){ ret=ser_error=E_SEND; #ifdef USE_DST_BLACKLIST (void)dst_blacklist_add(BLST_ERR_SEND, send_info, msg); #endif #ifdef USE_DNS_FAILOVER continue; /* try another ip */ #else goto error; #endif }else{ ret=ser_error=E_OK; /* sent requests stats */ STATS_TX_REQUEST( msg->first_line.u.request.method_value ); /* exit succcesfully */ goto end; } #ifdef USE_DNS_FAILOVER }while(dst && cfg_get(core, core_cfg, use_dns_failover) && dns_srv_handle_next(&dns_srv_h, err) && ((err=dns_sip_resolve2su(&dns_srv_h, &send_info->to, dst, port, &proto, dns_flags))==0)); if ((err!=0) && (err!=-E_DNS_EOR)){ LOG(L_ERR, "ERROR: resolving %.*s host name in uri" " failed: %s [%d] (dropping packet)\n", dst->len, ZSW(dst->s), dns_strerror(err), err); ret=ser_error=E_BAD_ADDRESS; goto error; } #endif error: STATS_TX_DROPS; end: #ifdef USE_DNS_FAILOVER if (dst && cfg_get(core, core_cfg, use_dns_failover)){ dns_srv_handle_put(&dns_srv_h); } #endif if (buf) pkg_free(buf); /* received_buf & line_buf will be freed in receive_msg by free_lump_list*/ #if defined STATS_REQ_FWD_OK || defined STATS_REQ_FWD_DROP if(ret==0) STATS_REQ_FWD_OK(); else STATS_REQ_FWD_DROP(); #endif /* STATS_REQ_FWD_* */ return ret; }
static void trace_sl_onreply_out( unsigned int types, struct sip_msg* req, struct sl_cb_param *sl_param) { static char fromip_buff[IP_ADDR_MAX_STR_SIZE+12]; static char toip_buff[IP_ADDR_MAX_STR_SIZE+12]; struct sip_msg* msg; int_str avp_value; struct usr_avp *avp; struct ip_addr to_ip; int len; char statusbuf[5]; if(req==NULL || sl_param==NULL) { LM_ERR("bad parameters\n"); goto error; } if( trace_is_off() ) { LM_DBG("trace off...\n"); return; } LM_DBG("trace slonreply out \n"); avp = NULL; if(traced_user_avp >= 0) avp=search_first_avp(traced_user_avp_type, traced_user_avp, &avp_value, 0); if((avp==NULL) && !flag_trace_is_set(req)) { LM_DBG("nothing to trace...\n"); return; } msg = req; if(parse_from_header(msg)==-1 || msg->from==NULL || get_from(msg)==NULL) { LM_ERR("cannot parse FROM header\n"); goto error; } if(parse_headers(msg, HDR_CALLID_F, 0)!=0) { LM_ERR("cannot parse call-id\n"); return; } db_vals[0].val.blob_val.s = (sl_param->buffer)?sl_param->buffer->s:""; db_vals[0].val.blob_val.len = (sl_param->buffer)?sl_param->buffer->len:0; /* check Call-ID header */ if(msg->callid==NULL || msg->callid->body.s==NULL) { LM_ERR("cannot find Call-ID header!\n"); goto error; } db_vals[1].val.str_val.s = msg->callid->body.s; db_vals[1].val.str_val.len = msg->callid->body.len; db_vals[2].val.str_val.s = msg->first_line.u.request.method.s; db_vals[2].val.str_val.len = msg->first_line.u.request.method.len; if(trace_local_ip.s && trace_local_ip.len > 0){ set_columns_to_trace_local_ip( db_vals[4], db_vals[5], db_vals[6]); } else { set_sock_columns( db_vals[4], db_vals[5], db_vals[6], fromip_buff, &msg->rcv.dst_ip, msg->rcv.dst_port, msg->rcv.proto); } strcpy(statusbuf, int2str(sl_param->code, &len)); db_vals[3].val.str_val.s = statusbuf; db_vals[3].val.str_val.len = len; memset(&to_ip, 0, sizeof(struct ip_addr)); if(sl_param->dst==0) { set_columns_to_any(db_vals[7], db_vals[8], db_vals[9]); } else { su2ip_addr(&to_ip, sl_param->dst); set_sock_columns( db_vals[7], db_vals[8],db_vals[9], toip_buff, &to_ip, (unsigned short)su_getport(sl_param->dst), req->rcv.proto); } db_vals[10].val.time_val = time(NULL); db_vals[11].val.string_val = "out"; db_vals[12].val.str_val.s = get_from(msg)->tag_value.s; db_vals[12].val.str_val.len = get_from(msg)->tag_value.len; if (save_siptrace(msg,avp,&avp_value,db_keys,db_vals) < 0) { LM_ERR("failed to save siptrace\n"); goto error; } #ifdef STATISTICS update_stat(siptrace_rpl, 1); #endif return; error: return; }
/* finds a tcpconn & sends on it */ int tcp_send(int type, char* buf, unsigned len, union sockaddr_union* to, int id) { struct tcp_connection *c; struct tcp_connection *tmp; struct ip_addr ip; int port; int fd; long response[2]; int n; port=0; if (to){ su2ip_addr(&ip, to); port=su_getport(to); c=tcpconn_get(id, &ip, port, TCP_CON_SEND_TIMEOUT); }else if (id){ c=tcpconn_get(id, 0, 0, TCP_CON_SEND_TIMEOUT); }else{ LOG(L_CRIT, "BUG: tcp_send called with null id & to\n"); return -1; } if (id){ if (c==0) { if (to){ /* try again w/o id */ c=tcpconn_get(0, &ip, port, TCP_CON_SEND_TIMEOUT); goto no_id; }else{ LOG(L_ERR, "ERROR: tcp_send: id %d not found, dropping\n", id); return -1; } }else goto get_fd; } no_id: if (c==0){ DBG("tcp_send: no open tcp connection found, opening new one\n"); /* create tcp connection */ if ((c=tcpconn_connect(to, type))==0){ LOG(L_ERR, "ERROR: tcp_send: connect failed\n"); return -1; } c->refcnt++; /* safe to do it w/o locking, it's not yet available to the rest of the world */ fd=c->s; /* send the new tcpconn to "tcp main" */ response[0]=(long)c; response[1]=CONN_NEW; n=send_all(unix_tcp_sock, response, sizeof(response)); if (n<=0){ LOG(L_ERR, "BUG: tcp_send: failed write: %s (%d)\n", strerror(errno), errno); n=-1; goto end; } n=send_fd(unix_tcp_sock, &c, sizeof(c), c->s); if (n<=0){ LOG(L_ERR, "BUG: tcp_send: failed send_fd: %s (%d)\n", strerror(errno), errno); n=-1; goto end; } goto send_it; } get_fd: /* todo: see if this is not the same process holding * c and if so send directly on c->fd */ DBG("tcp_send: tcp connection found (%p), acquiring fd\n", c); /* get the fd */ response[0]=(long)c; response[1]=CONN_GET_FD; n=send_all(unix_tcp_sock, response, sizeof(response)); if (n<=0){ LOG(L_ERR, "BUG: tcp_send: failed to get fd(write):%s (%d)\n", strerror(errno), errno); n=-1; goto release_c; } DBG("tcp_send, c= %p, n=%d\n", c, n); tmp=c; n=receive_fd(unix_tcp_sock, &c, sizeof(c), &fd); if (n<=0){ LOG(L_ERR, "BUG: tcp_send: failed to get fd(receive_fd):" " %s (%d)\n", strerror(errno), errno); n=-1; goto release_c; } if (c!=tmp){ LOG(L_CRIT, "BUG: tcp_send: get_fd: got different connection:" " %p (id= %d, refcnt=%d state=%d != " " %p (id= %d, refcnt=%d state=%d (n=%d)\n", c, c->id, c->refcnt, c->state, tmp, tmp->id, tmp->refcnt, tmp->state, n ); n=-1; /* fail */ goto end; } DBG("tcp_send: after receive_fd: c= %p n=%d fd=%d\n",c, n, fd); send_it: DBG("tcp_send: sending...\n"); lock_get(&c->write_lock); #ifdef USE_TLS if (c->type==PROTO_TLS) n=tls_blocking_write(c, fd, buf, len); else #endif n=tcp_blocking_write(c, fd, buf, len); lock_release(&c->write_lock); DBG("tcp_send: after write: c= %p n=%d fd=%d\n",c, n, fd); DBG("tcp_send: buf=\n%.*s\n", (int)len, buf); if (n<0){ LOG(L_ERR, "ERROR: tcp_send: failed to send\n"); /* error on the connection , mark it as bad and set 0 timeout */ c->state=S_CONN_BAD; c->timeout=0; /* tell "main" it should drop this (optional it will t/o anyway?)*/ response[0]=(long)c; response[1]=CONN_ERROR; n=send_all(unix_tcp_sock, response, sizeof(response)); /* CONN_ERROR will auto-dec refcnt => we must not call tcpconn_put !!*/ if (n<=0){ LOG(L_ERR, "BUG: tcp_send: error return failed (write):%s (%d)\n", strerror(errno), errno); n=-1; } close(fd); return n; /* error return, no tcpconn_put */ } end: close(fd); release_c: tcpconn_put(c); /* release c (lock; dec refcnt; unlock) */ return n; }
/*! \brief Finds a tcpconn & sends on it */ static int proto_ws_send(struct socket_info* send_sock, char* buf, unsigned int len, union sockaddr_union* to, int id) { struct tcp_connection *c; struct timeval get; struct ip_addr ip; int port = 0; int fd, n; reset_tcp_vars(tcpthreshold); start_expire_timer(get,tcpthreshold); if (to){ su2ip_addr(&ip, to); port=su_getport(to); n = tcp_conn_get(id, &ip, port, &c, &fd); }else if (id){ n = tcp_conn_get(id, 0, 0, &c, &fd); }else{ LM_CRIT("prot_tls_send called with null id & to\n"); get_time_difference(get,tcpthreshold,tcp_timeout_con_get); return -1; } if (n<0) { /* error during conn get, return with error too */ LM_ERR("failed to aquire connection\n"); get_time_difference(get,tcpthreshold,tcp_timeout_con_get); return -1; } /* was connection found ?? */ if (c==0) { if (tcp_no_new_conn) { return -1; } LM_DBG("no open tcp connection found, opening new one\n"); /* create tcp connection */ if ((c=ws_connect(send_sock, to, &fd))==0) { LM_ERR("connect failed\n"); return -1; } goto send_it; } get_time_difference(get, tcpthreshold, tcp_timeout_con_get); /* now we have a connection, let's what we can do with it */ /* BE CAREFUL now as we need to release the conn before exiting !!! */ if (fd==-1) { /* connection is not writable because of its state */ /* return error, nothing to do about it */ tcp_conn_release(c, 0); return -1; } send_it: LM_DBG("sending via fd %d...\n",fd); n = ws_req_write(c, fd, buf, len); stop_expire_timer(get, tcpthreshold, "WS ops",buf,(int)len,1); tcp_conn_set_lifetime( c, tcp_con_lifetime); LM_DBG("after write: c= %p n=%d fd=%d\n",c, n, fd); if (n<0){ LM_ERR("failed to send\n"); c->state=S_CONN_BAD; if (c->proc_id != process_no) close(fd); tcp_conn_release(c, 0); return -1; } /* only close the FD if not already in the context of our process either we just connected, or main sent us the FD */ if (c->proc_id != process_no) close(fd); tcp_conn_release(c, 0); return n; }
int hepv3_message_parse(char *buf, unsigned int len, sip_msg_t* msg) { union sockaddr_union from; union sockaddr_union to; char *tmp; struct ip_addr dst_ip, src_ip; struct socket_info* si = 0; int i; char *payload = NULL; unsigned int payload_len = 0; struct hep_chunk *chunk; struct hep_generic_recv *hg; int totelem = 0; int chunk_vendor=0, chunk_type=0, chunk_length=0; int total_length = 0; int ret = 0; hg = (struct hep_generic_recv*)pkg_malloc(sizeof(struct hep_generic_recv)); if(hg==NULL) { LM_ERR("no more pkg memory left for hg\n"); return -1; } memset(hg, 0, sizeof(struct hep_generic_recv)); memset(heptime, 0, sizeof(struct hep_timehdr)); /* HEADER */ hg->header = (hep_ctrl_t *) (buf); /*Packet size */ total_length = ntohs(hg->header->length); dst_ip.af = 0; src_ip.af = 0; payload = NULL; correlation_id = NULL; authkey = NULL; i = sizeof(hep_ctrl_t); while(i < total_length) { /*OUR TMP DATA */ tmp = buf+i; chunk = (struct hep_chunk*) tmp; chunk_vendor = ntohs(chunk->vendor_id); chunk_type = ntohs(chunk->type_id); chunk_length = ntohs(chunk->length); /* if chunk_length */ if(chunk_length == 0) { /* BAD LEN we drop this packet */ goto error; } /* SKIP not general Chunks */ if(chunk_vendor != 0) { i+=chunk_length; } else { switch(chunk_type) { case 0: goto error; break; case 1: hg->ip_family = (hep_chunk_uint8_t *) (tmp); i+=chunk_length; totelem++; break; case 2: hg->ip_proto = (hep_chunk_uint8_t *) (tmp); i+=chunk_length; totelem++; break; case 3: hg->hep_src_ip4 = (hep_chunk_ip4_t *) (tmp); i+=chunk_length; src_ip.af=AF_INET; src_ip.len=4; src_ip.u.addr32[0] = hg->hep_src_ip4->data.s_addr; totelem++; break; case 4: hg->hep_dst_ip4 = (hep_chunk_ip4_t *) (tmp); i+=chunk_length; dst_ip.af=AF_INET; dst_ip.len=4; dst_ip.u.addr32[0] = hg->hep_dst_ip4->data.s_addr; totelem++; break; case 5: hg->hep_src_ip6 = (hep_chunk_ip6_t *) (tmp); i+=chunk_length; src_ip.af=AF_INET6; src_ip.len=16; memcpy(src_ip.u.addr, &hg->hep_src_ip6->data, 16); totelem++; break; case 6: hg->hep_dst_ip6 = (hep_chunk_ip6_t *) (tmp); i+=chunk_length; dst_ip.af=AF_INET6; dst_ip.len=16; memcpy(dst_ip.u.addr, &hg->hep_dst_ip6->data, 16); totelem++; break; case 7: hg->src_port = (hep_chunk_uint16_t *) (tmp); msg->rcv.src_port = ntohs(hg->src_port->data); i+=chunk_length; totelem++; break; case 8: hg->dst_port = (hep_chunk_uint16_t *) (tmp); msg->rcv.dst_port = ntohs(hg->dst_port->data); i+=chunk_length; totelem++; break; case 9: hg->time_sec = (hep_chunk_uint32_t *) (tmp); hg->time_sec->data = ntohl(hg->time_sec->data); heptime->tv_sec = hg->time_sec->data; i+=chunk_length; totelem++; break; case 10: hg->time_usec = (hep_chunk_uint32_t *) (tmp); hg->time_usec->data = ntohl(hg->time_usec->data); heptime->tv_usec = hg->time_usec->data; i+=chunk_length; totelem++; break; case 11: hg->proto_t = (hep_chunk_uint8_t *) (tmp); i+=chunk_length; totelem++; break; case 12: hg->capt_id = (hep_chunk_uint32_t *) (tmp); i+=chunk_length; heptime->captid = ntohs(hg->capt_id->data); totelem++; break; case 13: hg->keep_tm = (hep_chunk_uint16_t *) (tmp); i+=chunk_length; break; case 14: authkey = (char *) tmp + sizeof(hep_chunk_t); i+=chunk_length; break; case 15: hg->payload_chunk = (hep_chunk_t *) (tmp); payload = (char *) tmp+sizeof(hep_chunk_t); payload_len = chunk_length - sizeof(hep_chunk_t); i+=chunk_length; totelem++; break; case 17: correlation_id = (char *) tmp + sizeof(hep_chunk_t); i+=chunk_length; break; default: i+=chunk_length; break; } } } /* CHECK how much elements */ if(totelem < 9) { LM_ERR("Not all elements [%d]\n", totelem); goto done; } if ( dst_ip.af == 0 || src_ip.af == 0) { LM_ERR("NO IP's set\n"); goto done; } ip_addr2su(&to, &dst_ip, msg->rcv.dst_port); ip_addr2su(&from, &src_ip, msg->rcv.src_port); msg->rcv.src_su=from; su2ip_addr(&msg->rcv.src_ip, &from); su2ip_addr(&msg->rcv.dst_ip, &to); if(hg->ip_proto->data == IPPROTO_TCP) msg->rcv.proto=PROTO_TCP; else if(hg->ip_proto->data == IPPROTO_UDP) msg->rcv.proto=PROTO_UDP; if(payload != NULL) ret = len - payload_len; /*TIME*/ heptime->tv_sec = hg->time_sec->data; heptime->tv_usec = hg->time_usec->data; heptime->captid = ntohs(hg->capt_id->data); done: //if(si) pkg_free(si); if(hg) pkg_free(hg); return ret; error: if(si) pkg_free(si); if(hg) pkg_free(hg); return -1; }
static int hep_udp_read_req(struct socket_info *si, int* bytes_read) { struct receive_info ri; int len; #ifdef DYN_BUF char* buf; #else static char buf [BUF_SIZE+1]; #endif char *tmp; unsigned int fromlen; str msg; struct hep_desc h; int ret = 0; #ifdef DYN_BUF buf=pkg_malloc(BUF_SIZE+1); if (buf==0){ LM_ERR("could not allocate receive buffer\n"); goto error; } #endif fromlen=sockaddru_len(si->su); len=recvfrom(bind_address->socket, buf, BUF_SIZE,0,&ri.src_su.s,&fromlen); if (len==-1){ if (errno==EAGAIN) return 0; if ((errno==EINTR)||(errno==EWOULDBLOCK)|| (errno==ECONNREFUSED)) return -1; LM_ERR("recvfrom:[%d] %s\n", errno, strerror(errno)); return -2; } if (len<MIN_UDP_PACKET) { LM_DBG("probing packet received len = %d\n", len); return 0; } /* we must 0-term the messages, receive_msg expects it */ buf[len]=0; /* no need to save the previous char */ ri.bind_address = si; ri.dst_port = si->port_no; ri.dst_ip = si->address; ri.proto = si->proto; ri.proto_reserved1 = ri.proto_reserved2 = 0; su2ip_addr(&ri.src_ip, &ri.src_su); ri.src_port=su_getport(&ri.src_su); msg.s = buf; msg.len = len; /* if udp we are sure that version 1 or 2 of the * protocol is used */ if (unpack_hepv2(buf, len, &h)) { LM_ERR("hep unpacking failed\n"); return -1; } /* run hep callbacks if looks like non-SIP message*/ if( !isalpha(msg.s[0]) ) { /* not-SIP related */ ret=run_hep_cbs(&h, &ri); if (ret < 0) { LM_ERR("failed to run hep callbacks\n"); return -1; } /* remove the hep header; leave only the payload */ memmove(buf, h.u.hepv12.payload, /* also copy '\0' character */ strlen(h.u.hepv12.payload)+1); msg.s = buf; msg.len = strlen(buf); } if (ri.src_port==0){ tmp=ip_addr2a(&ri.src_ip); LM_INFO("dropping 0 port packet for %s\n", tmp); return 0; } if (ret != HEP_SCRIPT_SKIP) { /* receive_msg must free buf too!*/ receive_msg( msg.s, msg.len, &ri); } return 0; }
struct socket_info* get_out_socket(union sockaddr_union* to, int proto) { int* temp_sock; socklen_t len; union sockaddr_union from; struct socket_info* si; struct ip_addr ip; union sockaddr_union uncon; memset(&uncon, 0, sizeof(union sockaddr_union)); uncon.sin.sin_family = AF_UNSPEC; if (unlikely(proto!=PROTO_UDP)) { LOG(L_CRIT, "BUG: get_out_socket can only be called for UDP\n"); return 0; } retry: switch(to->s.sa_family){ case AF_INET : { if(unlikely(sock_inet < 0)){ sock_inet = socket(AF_INET, SOCK_DGRAM, 0); if (sock_inet==-1) { LM_ERR("socket() failed: %s\n", strerror(errno)); return 0; } } temp_sock = &sock_inet; break; } #ifdef USE_IPV6 case AF_INET6 : { if(unlikely(sock_inet6 < 0)){ sock_inet6 = socket(AF_INET6, SOCK_DGRAM, 0); if (sock_inet6==-1) { LM_ERR("socket() failed: %s\n", strerror(errno)); return 0; } } temp_sock = &sock_inet6; break; } #endif /* USE_IPV6 */ default: { LM_ERR("Unknown protocol family \n"); return 0; } } if( !mhomed_sock_cache_disabled ){ /* some Linux kernel versions (all?) along with other UNIXes don't re-bound the sock if already bound */ /* to un-bound a socket set sin_family to AF_UNSPEC and zero out the rest*/ if (unlikely(connect(*temp_sock, &uncon.s, sockaddru_len(uncon)) < 0)) mhomed_sock_cache_disabled = 1; } if (unlikely(connect(*temp_sock, &to->s, sockaddru_len(*to))==-1)) { if (unlikely(errno==EISCONN && !mhomed_sock_cache_disabled)){ /* no multiple connects support on the same socket */ mhomed_sock_cache_disabled=1; if (sock_inet>=0){ close(sock_inet); sock_inet=-1; } #ifdef USE_IPV6 if (sock_inet6>=0){ close(sock_inet6); sock_inet6=-1; } #endif /* USE_IPV6 */ goto retry; } LOG(L_ERR, "ERROR: get_out_socket: connect failed: %s\n", strerror(errno)); goto error; } len=sizeof(from); if (unlikely(getsockname(*temp_sock, &from.s, &len)==-1)) { LOG(L_ERR, "ERROR: get_out_socket: getsockname failed: %s\n", strerror(errno)); goto error; } su2ip_addr(&ip, &from); si=find_si(&ip, 0, proto); if (si==0) goto error; DBG("DEBUG: get_out_socket: socket determined: %p\n", si ); if (unlikely(mhomed_sock_cache_disabled)){ close(*temp_sock); *temp_sock=-1; } return si; error: LOG(L_ERR, "ERROR: get_out_socket: no socket found\n"); if (unlikely(mhomed_sock_cache_disabled && *temp_sock >=0)){ close(*temp_sock); *temp_sock=-1; } return 0; }
static int hep_tcp_send (struct socket_info* send_sock, char *buf, unsigned int len, union sockaddr_union *to, int id) { struct tcp_connection *c; int port=0; struct ip_addr ip; int fd, n; if (to) { su2ip_addr(&ip, to); port=su_getport(to); n = tcp_conn_get(id,&ip, port, &c, &fd); } else if (id) { n = tcp_conn_get(id, 0, 0, &c, &fd); } else { LM_CRIT("tcp_send called with null id & to\n"); return -1; } if (n < 0) { /* error during conn get, return with error too */ LM_ERR("failed to aquire connection\n"); return -1; } /* was connection found ?? */ if (c==0) { if (tcp_no_new_conn) { return -1; } if (!to) { LM_ERR("Unknown destination - cannot open new tcp connection\n"); return -1; } LM_DBG("no open tcp connection found, opening new one, async = %d\n",hep_async); /* create tcp connection */ if (hep_async) { n = tcpconn_async_connect(send_sock, to, buf, len, &c, &fd); if ( n<0 ) { LM_ERR("async TCP connect failed\n"); return -1; } /* connect succeded, we have a connection */ if (n==0) { /* connect is still in progress, break the sending * flow now (the actual write will be done when * connect will be completed */ LM_DBG("Succesfully started async connection \n"); tcp_conn_release(c, 0); return len; } /* our first connect attempt succeeded - go ahead as normal */ } else if ((c=hep_sync_connect(send_sock, to, &fd))==0) { LM_ERR("connect failed\n"); return -1; } goto send_it; } /* now we have a connection, let's see what we can do with it */ /* BE CAREFUL now as we need to release the conn before exiting !!! */ if (fd==-1) { /* connection is not writable because of its state - can we append * data to it for later writting (async writting)? */ if (c->state==S_CONN_CONNECTING) { /* the connection is currently in the process of getting * connected - let's append our send chunk as well - just in * case we ever manage to get through */ LM_DBG("We have acquired a TCP connection which is still " "pending to connect - delaying write \n"); n = add_write_chunk(c,buf,len,1); if (n < 0) { LM_ERR("Failed to add another write chunk to %p\n",c); /* we failed due to internal errors - put the * connection back */ tcp_conn_release(c, 0); return -1; } /* we succesfully added our write chunk - success */ tcp_conn_release(c, 0); return len; } else { /* return error, nothing to do about it */ tcp_conn_release(c, 0); return -1; } } send_it: LM_DBG("sending via fd %d...\n",fd); n = _hep_write_on_socket(c, fd, buf, len); tcp_conn_set_lifetime( c, tcp_con_lifetime); LM_DBG("after write: c= %p n=%d fd=%d\n",c, n, fd); /* LM_DBG("buf=\n%.*s\n", (int)len, buf); */ if (n<0){ LM_ERR("failed to send\n"); c->state=S_CONN_BAD; if (c->proc_id != process_no) close(fd); tcp_conn_release(c, 0); return -1; } /* only close the FD if not already in the context of our process either we just connected, or main sent us the FD */ if (c->proc_id != process_no) close(fd); tcp_conn_release(c, (n<len)?1:0/*pending data in async mode?*/ ); return n; }
static void trace_msg_out(struct sip_msg* msg, str *sbuf, struct socket_info* send_sock, int proto, union sockaddr_union *to) { static char fromip_buff[IP_ADDR_MAX_STR_SIZE+12]; static char toip_buff[IP_ADDR_MAX_STR_SIZE+12]; int_str avp_value; struct usr_avp *avp; struct ip_addr to_ip; avp = NULL; if(traced_user_avp>=0) avp=search_first_avp(traced_user_avp_type, traced_user_avp, &avp_value, 0); if ( (avp==NULL) && !flag_trace_is_set(msg) ) { LM_DBG("trace off...\n"); return; } if(parse_from_header(msg)==-1 || msg->from==NULL || get_from(msg)==NULL) { LM_ERR("cannot parse FROM header\n"); goto error; } if(parse_headers(msg, HDR_CALLID_F, 0)!=0) { LM_ERR("cannot parse call-id\n"); return; } LM_DBG("trace msg out \n"); if(sbuf!=NULL && sbuf->len>0) { db_vals[0].val.blob_val.s = sbuf->s; db_vals[0].val.blob_val.len = sbuf->len; } else { db_vals[0].val.blob_val.s = "No request buffer"; db_vals[0].val.blob_val.len = sizeof("No request buffer")-1; } /* check Call-ID header */ if(msg->callid==NULL || msg->callid->body.s==NULL) { LM_ERR("cannot find Call-ID header!\n"); goto error; } db_vals[1].val.str_val.s = msg->callid->body.s; db_vals[1].val.str_val.len = msg->callid->body.len; if(sbuf!=NULL && sbuf->len > 7 && !strncasecmp(sbuf->s, "CANCEL ", 7)) { db_vals[2].val.str_val.s = "CANCEL"; db_vals[2].val.str_val.len = 6; } else { db_vals[2].val.str_val= REQ_LINE(msg).method; } db_vals[3].val.str_val.s = ""; db_vals[3].val.str_val.len = 0; memset(&to_ip, 0, sizeof(struct ip_addr)); if (trace_local_ip.s && trace_local_ip.len > 0){ set_columns_to_trace_local_ip( db_vals[4], db_vals[5], db_vals[6]); } else { if(send_sock==0 || send_sock->sock_str.s==0) { set_sock_columns( db_vals[4], db_vals[5], db_vals[6], fromip_buff, &msg->rcv.dst_ip, msg->rcv.dst_port, msg->rcv.proto); } else { char *nbuff = proto2str(send_sock->proto,fromip_buff); db_vals[4].val.str_val.s = fromip_buff; db_vals[4].val.str_val.len = nbuff - fromip_buff; db_vals[5].val.str_val = send_sock->address_str; db_vals[6].val.int_val = send_sock->port_no; } } if(to==0) { set_columns_to_any(db_vals[7], db_vals[8], db_vals[9]); } else { su2ip_addr(&to_ip, to); set_sock_columns( db_vals[7], db_vals[8], db_vals[9], toip_buff, &to_ip, (unsigned short)su_getport(to), proto); } db_vals[10].val.time_val = time(NULL); db_vals[11].val.string_val = "out"; db_vals[12].val.str_val.s = get_from(msg)->tag_value.s; db_vals[12].val.str_val.len = get_from(msg)->tag_value.len; if (save_siptrace(msg,avp,&avp_value,db_keys,db_vals) < 0) { LM_ERR("failed to save siptrace\n"); goto error; } #ifdef STATISTICS update_stat(siptrace_req, 1); #endif return; error: return; }
/* receive an ipv4 udp packet over a raw socket. * The packet is copied in *buf and *buf is advanced to point to the * payload. Fills from and to. * @param rsock - raw socket * @param buf - the packet will be written to where *buf points intially and * then *buf will be advanced to point to the udp payload. * @param len - buffer length (should be enough to hold at least the * ip and udp headers + 1 byte). * @param from - result parameter, filled with source address and port of the * packet. * @param from - result parameter, filled with destination (local) address and * port of the packet. * @param rf - filter used to decide whether or not the packet is * accepted/processed. If null, all the packets are accepted. * @return packet len or <0 on error (-1 and -2 on recv error @see recvpkt4, * -3 if the headers are invalid and -4 if the packet doesn't * match the filter). */ int raw_udp4_recv(int rsock, char** buf, int len, union sockaddr_union* from, union sockaddr_union* to, struct raw_filter* rf) { int n; unsigned short dst_port; unsigned short src_port; struct ip_addr dst_ip; char* end; char* udph_start; char* udp_payload; struct ip iph; struct udphdr udph; unsigned short udp_len; n=recvpkt4(rsock, *buf, len, from, to); if (unlikely(n<0)) goto error; end=*buf+n; if (unlikely(n<((sizeof(struct ip) * raw_ipip ? 2 : 1)+sizeof(struct udphdr)))) { n=-3; goto error; } if(raw_ipip) *buf = *buf + sizeof(struct ip); /* FIXME: if initial buffer is aligned, one could skip the memcpy and directly cast ip and udphdr pointer to the memory */ memcpy(&iph, *buf, sizeof(struct ip)); udph_start=*buf+iph.ip_hl*4; udp_payload=udph_start+sizeof(struct udphdr); if (unlikely(udp_payload>end)){ n=-3; goto error; } memcpy(&udph, udph_start, sizeof(struct udphdr)); udp_len=ntohs(udph.uh_ulen); if (unlikely((udph_start+udp_len)!=end)){ if ((udph_start+udp_len)>end){ n=-3; goto error; }else{ ERR("udp length too small: %d/%d\n", (int)udp_len, (int)(end-udph_start)); n=-3; goto error; } } /* advance buf */ *buf=udp_payload; n=(int)(end-*buf); /* fill ip from the packet (needed if no PKT_INFO is used) */ dst_ip.af=AF_INET; dst_ip.len=4; dst_ip.u.addr32[0]=iph.ip_dst.s_addr; /* fill dst_port */ dst_port=ntohs(udph.uh_dport); ip_addr2su(to, &dst_ip, dst_port); /* fill src_port */ src_port=ntohs(udph.uh_sport); su_setport(from, src_port); if (likely(rf)) { su2ip_addr(&dst_ip, to); if ( (dst_port && rf->port1 && ((dst_port<rf->port1) || (dst_port>rf->port2)) ) || (matchnet(&dst_ip, &rf->dst)!=1) ){ /* no match */ n=-4; goto error; } } error: return n; }
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; }
static void trace_onreply_out(struct cell* t, int type, struct tmcb_params *ps) { int faked = 0; static char fromip_buff[IP_ADDR_MAX_STR_SIZE+12]; static char toip_buff[IP_ADDR_MAX_STR_SIZE+12]; struct sip_msg* msg; struct sip_msg* req; int_str avp_value; struct usr_avp *avp; struct ip_addr to_ip; int len; char statusbuf[8]; str *sbuf; struct dest_info *dst; if (t==NULL || t->uas.request==0 || ps==NULL) { LM_DBG("no uas request, local transaction\n"); return; } LM_DBG("trace onreply out \n"); avp = NULL; if(traced_user_avp>=0) avp=search_first_avp(traced_user_avp_type, traced_user_avp, &avp_value, 0); req = ps->req; msg = ps->rpl; if(msg==NULL || msg==FAKED_REPLY) { msg = t->uas.request; faked = 1; } if(parse_from_header(msg)==-1 || msg->from==NULL || get_from(msg)==NULL) { LM_ERR("cannot parse FROM header\n"); goto error; } if(parse_headers(msg, HDR_CALLID_F, 0)!=0) { LM_ERR("cannot parse call-id\n"); return; } sbuf = (str*)ps->extra1; if(faked==0) { if(sbuf!=0 && sbuf->len>0) { db_vals[0].val.blob_val.s = sbuf->s; db_vals[0].val.blob_val.len = sbuf->len; } else if(t->uas.response.buffer.s!=NULL) { db_vals[0].val.blob_val.s = t->uas.response.buffer.s; db_vals[0].val.blob_val.len = t->uas.response.buffer.len; } else if(msg->len>0) { db_vals[0].val.blob_val.s = msg->buf; db_vals[0].val.blob_val.len = msg->len; } else { db_vals[0].val.blob_val.s = "No reply buffer"; db_vals[0].val.blob_val.len = sizeof("No reply buffer")-1; } } else { if(sbuf!=0 && sbuf->len>0) { db_vals[0].val.blob_val.s = sbuf->s; db_vals[0].val.blob_val.len = sbuf->len; } else if(t->uas.response.buffer.s==NULL) { db_vals[0].val.blob_val.s = "No reply buffer"; db_vals[0].val.blob_val.len = sizeof("No reply buffer")-1; } else { db_vals[0].val.blob_val.s = t->uas.response.buffer.s; db_vals[0].val.blob_val.len = t->uas.response.buffer.len; } } /* check Call-ID header */ if(msg->callid==NULL || msg->callid->body.s==NULL) { LM_ERR("cannot find Call-ID header!\n"); goto error; } db_vals[1].val.str_val.s = msg->callid->body.s; db_vals[1].val.str_val.len = msg->callid->body.len; db_vals[2].val.str_val.s = t->method.s; db_vals[2].val.str_val.len = t->method.len; if(trace_local_ip.s && trace_local_ip.len > 0){ set_columns_to_trace_local_ip(db_vals[4], db_vals[5], db_vals[6]); } else { set_sock_columns( db_vals[4], db_vals[5], db_vals[6], fromip_buff, &msg->rcv.dst_ip, msg->rcv.dst_port, msg->rcv.proto); } strcpy(statusbuf, int2str(ps->code, &len)); db_vals[3].val.str_val.s = statusbuf; db_vals[3].val.str_val.len = len; memset(&to_ip, 0, sizeof(struct ip_addr)); dst = (struct dest_info*)ps->extra2; if(dst==0) { set_columns_to_any( db_vals[7], db_vals[8], db_vals[9]); } else { su2ip_addr(&to_ip, &dst->to); set_sock_columns( db_vals[7], db_vals[8], db_vals[9], toip_buff, &to_ip, (unsigned long)su_getport(&dst->to), dst->proto); } db_vals[10].val.time_val = time(NULL); db_vals[11].val.string_val = "out"; db_vals[12].val.str_val.s = get_from(msg)->tag_value.s; db_vals[12].val.str_val.len = get_from(msg)->tag_value.len; if (save_siptrace(req,avp,&avp_value,db_keys,db_vals) < 0) { LM_ERR("failed to save siptrace\n"); goto error; } #ifdef STATISTICS update_stat(siptrace_rpl, 1); #endif return; error: return; }