/** initializes a net structure from a string. * @param dst - net structure that will be filled * @param s - string of the form "ip", "ip/mask_len" or "ip/ip_mak". * @return -1 on error, 0 on succes */ int mk_net_str(struct net* dst, str* s) { struct ip_addr* t; char* p; struct ip_addr ip; str addr; str mask; unsigned int bitlen; /* test for ip only */ t = str2ip(s); if (unlikely(t == 0)) t = str2ip6(s); if (likely(t)) return mk_net_bitlen(dst, t, t->len*8); /* not a simple ip, maybe an ip/netmask pair */ p = q_memchr(s->s, '/', s->len); if (likely(p)) { addr.s = s->s; addr.len = (int)(long)(p - s->s); mask.s = p + 1; mask.len = s->len - (addr.len + 1); /* allow '/' enclosed by whitespace */ trim_trailing(&addr); trim_leading(&mask); t = str2ip(&addr); if (likely(t)) { /* it can be a number */ if (str2int(&mask, &bitlen) == 0) return mk_net_bitlen(dst, t, bitlen); ip = *t; t = str2ip(&mask); if (likely(t)) return mk_net(dst, &ip, t); /* error */ return -1; } else { t = str2ip6(&addr); if (likely(t)) { /* it can be a number */ if (str2int(&mask, &bitlen) == 0) return mk_net_bitlen(dst, t, bitlen); ip = *t; t = str2ip6(&mask); if (likely(t)) return mk_net(dst, &ip, t); /* error */ return -1; } } } return -1; }
/* Adds a new entry to the blacklist */ void dst_blst_add(rpc_t* rpc, void* ctx) { str ip; int port, proto, flags; unsigned char err_flags; struct ip_addr *ip_addr; if (!cfg_get(core, core_cfg, use_dst_blacklist)){ rpc->fault(ctx, 500, "dst blacklist support disabled"); return; } if (rpc->scan(ctx, "Sddd", &ip, &port, &proto, &flags) < 4) return; err_flags = (unsigned char)flags; /* sanity checks */ if ((unsigned char)proto > PROTO_SCTP) { rpc->fault(ctx, 400, "Unknown protocol"); return; } if (err_flags & BLST_IS_IPV6) { #ifdef USE_IPV6 /* IPv6 address is specified */ ip_addr = str2ip6(&ip); #else /* USE_IPV6 */ rpc->fault(ctx, 400, "IPv6 support disabled"); return; #endif /* USE_IPV6 */ } else { /* try IPv4 first, than IPv6 */ ip_addr = str2ip(&ip); if (!ip_addr) { #ifdef USE_IPV6 ip_addr = str2ip6(&ip); err_flags |= BLST_IS_IPV6; #else /* USE_IPV6 */ rpc->fault(ctx, 400, "Malformed or IPv6 ip address"); return; #endif /* USE_IPV6 */ } } if (!ip_addr) { rpc->fault(ctx, 400, "Malformed ip address"); return; } if (dst_blacklist_add_ip(err_flags, proto, ip_addr, port, S_TO_TICKS(cfg_get(core, core_cfg, blst_timeout)))) rpc->fault(ctx, 400, "Failed to add the entry to the blacklist"); }
static int parse_ipv6(struct ip_addr* ip, cfg_token_t* token, cfg_parser_t* st) { int ret; cfg_token_t t; struct ip_addr* ipv6; str ip6_str; while(1) { ret = cfg_get_token(&t, st, 0); if (ret != 0) goto err; if (t.type == ']') break; if (t.type != CFG_TOKEN_ALPHA && t.type != ':') goto err; } ip6_str.s = t.val.s; ip6_str.len = (int)(long)(t.val.s - ip6_str.s); ipv6 = str2ip6(&ip6_str); if (ipv6 == 0) goto err; *ip = *ipv6; return 0; err: ERR("%s:%d:%d: Invalid IPv6 address\n", st->file, token->start.line, token->start.col); return -1; }
static int parse_ipv6(struct ip_addr* ip, cfg_token_t* token, cfg_parser_t* st) { int ret; cfg_token_t t; struct ip_addr* ipv6; str ip6_str; char ip6_buff[IP_ADDR_MAX_STR_SIZE+3]; ip6_buff[0] = '\0'; while(1) { ret = cfg_get_token(&t, st, 0); if (ret != 0) goto err; if (t.type == ']') break; if (t.type != CFG_TOKEN_ALPHA && t.type != ':') goto err; strncat(ip6_buff, t.val.s, t.val.len); } ip6_str.s = ip6_buff; ip6_str.len = strlen(ip6_buff); LM_DBG("found IPv6 address [%.*s]\n", ip6_str.len, ip6_str.s); ipv6 = str2ip6(&ip6_str); if (ipv6 == 0) goto err; *ip = *ipv6; return 0; err: LM_ERR("%s:%d:%d: Invalid IPv6 address\n", st->file, token->start.line, token->start.col); return -1; }
/** internal sip naptr resolver function: resolves a host name trying: * - NAPTR lookup if the address is not an ip and *proto==0 and *port==0. * The result of the NAPTR query will be used for a SRV lookup * - SRV lookup if the address is not an ip *port==0. The result of the SRV * query will be used for an A/AAAA lookup. * - normal A/AAAA lookup (either fallback from the above or if *port!=0 * and *proto!=0 or port==0 && proto==0) * when performing SRV lookup (*port==0) it will use proto to look for * tcp or udp hosts, otherwise proto is unused; if proto==0 => no SRV lookup * returns: hostent struct & *port filled with the port from the SRV record; * 0 on error */ struct hostent* naptr_sip_resolvehost(str* name, unsigned short* port, char* proto) { struct hostent* he; struct ip_addr* ip; static char tmp[MAX_DNS_NAME]; /* tmp. buff. for SRV lookups and null. term strings */ struct rdata* l; struct rdata* naptr_head; char n_proto; str srv_name; naptr_bmp_t tried_bmp; /* tried bitmap */ char origproto; if(proto) origproto = *proto; naptr_head=0; he=0; if (name->len >= MAX_DNS_NAME) { LM_ERR("domain name too long\n"); goto end; } /* try NAPTR if no port or protocol is specified and NAPTR lookup is * enabled */ if (port && proto && (*proto==0) && (*port==0)){ *proto=PROTO_UDP; /* just in case we don't find another */ if ( ((ip=str2ip(name))!=0) || ((ip=str2ip6(name))!=0) ){ /* we are lucky, this is an ip address */ he=ip_addr2he(name,ip); *port=SIP_PORT; goto end; } memcpy(tmp, name->s, name->len); tmp[name->len] = '\0'; naptr_head=get_record(tmp, T_NAPTR, RES_AR); naptr_iterate_init(&tried_bmp); while((l=naptr_sip_iterate(naptr_head, &tried_bmp, &srv_name, &n_proto))!=0){ if ((he=srv_sip_resolvehost(&srv_name, 1, port, proto, 1, l))!=0){ *proto=n_proto; return he; } } /*clean up on exit*/ LM_DBG("no NAPTR record found for %.*s, trying SRV lookup...\n", name->len, name->s); } /* fallback to srv lookup */ if(proto) *proto = origproto; he=no_naptr_srv_sip_resolvehost(name,port,proto); /* fallback all the way down to A/AAAA */ if (he==0) { he=dns_get_he(name,dns_flags); } end: if (naptr_head) free_rdata_list(naptr_head); return he; }
static inline ip_addr_t *strtoipX(str *ips) { /* try to figure out INET class */ if(ips->s[0] == '[' || memchr(ips->s, ':', ips->len)!=NULL) { /* IPv6 */ return str2ip6(ips); } else { /* IPv4 */ return str2ip(ips); } }
/** * 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 }
/*! \brief Initialize sipcapture module */ static int mod_init(void) { struct ip_addr *ip = NULL; #ifdef STATISTICS /* register statistics */ if (register_module_stats(exports.name, sipcapture_stats)!=0) { LM_ERR("failed to register core statistics\n"); return -1; } #endif if(register_mi_mod(exports.name, mi_cmds)!=0) { LM_ERR("failed to register MI commands\n"); return -1; } if(sipcapture_init_rpc()!=0) { LM_ERR("failed to register RPC commands\n"); return -1; } db_url.len = strlen(db_url.s); table_name.len = strlen(table_name.s); hash_source.len = strlen (hash_source.s); mt_mode.len = strlen(mt_mode.s); date_column.len = strlen(date_column.s); micro_ts_column.len = strlen(micro_ts_column.s); method_column.len = strlen(method_column.s); reply_reason_column.len = strlen(reply_reason_column.s); ruri_column.len = strlen(ruri_column.s); ruri_user_column.len = strlen(ruri_user_column.s); from_user_column.len = strlen(from_user_column.s); from_tag_column.len = strlen(from_tag_column.s); to_user_column.len = strlen(to_user_column.s); pid_user_column.len = strlen(pid_user_column.s); contact_user_column.len = strlen(contact_user_column.s); auth_user_column.len = strlen(auth_user_column.s); callid_column.len = strlen(callid_column.s); via_1_column.len = strlen(via_1_column.s); via_1_branch_column.len = strlen(via_1_branch_column.s); cseq_column.len = strlen(cseq_column.s); diversion_column.len = strlen(diversion_column.s); reason_column.len = strlen(reason_column.s); content_type_column.len = strlen(content_type_column.s); authorization_column.len = strlen(authorization_column.s); user_agent_column.len = strlen(user_agent_column.s); source_ip_column.len = strlen(source_ip_column.s); source_port_column.len = strlen(source_port_column.s); dest_ip_column.len = strlen(dest_ip_column.s); dest_port_column.len = strlen(dest_port_column.s); contact_ip_column.len = strlen(contact_ip_column.s); contact_port_column.len = strlen(contact_port_column.s); orig_ip_column.len = strlen(orig_ip_column.s); orig_port_column.len = strlen(orig_port_column.s); proto_column.len = strlen(proto_column.s); family_column.len = strlen(family_column.s); type_column.len = strlen(type_column.s); rtp_stat_column.len = strlen(rtp_stat_column.s); node_column.len = strlen(node_column.s); msg_column.len = strlen(msg_column.s); capture_node.len = strlen(capture_node.s); if(raw_socket_listen.s) raw_socket_listen.len = strlen(raw_socket_listen.s); if(raw_interface.s) raw_interface.len = strlen(raw_interface.s); /* Find a database module */ if (db_bind_mod(&db_url, &db_funcs)) { LM_ERR("unable to bind database module\n"); return -1; } if (!DB_CAPABILITY(db_funcs, DB_CAP_INSERT)) { LM_ERR("database modules does not provide all functions needed" " by module\n"); return -1; } /*Check the table name*/ if(!table_name.len) { LM_ERR("ERROR: sipcapture: mod_init: table_name is not defined or empty\n"); return -1; } if (mt_init () <0) { return -1; } if(db_insert_mode) { LM_INFO("INFO: sipcapture: mod_init: you have enabled INSERT DELAYED \ Make sure your DB can support it\n"); } capture_on_flag = (int*)shm_malloc(sizeof(int)); if(capture_on_flag==NULL) { LM_ERR("no more shm memory left\n"); return -1; } *capture_on_flag = capture_on; /* register DGRAM event */ if(sr_event_register_cb(SREV_NET_DGRAM_IN, hep_msg_received) < 0) { LM_ERR("failed to register SREV_NET_DGRAM_IN event\n"); return -1; } if(ipip_capture_on && moni_capture_on) { LM_ERR("only one RAW mode is supported. Please disable ipip_capture_on or moni_capture_on\n"); return -1; } /* raw processes for IPIP encapsulation */ if (ipip_capture_on || moni_capture_on) { register_procs(raw_sock_children); if(extract_host_port() && (((ip=str2ip(&raw_socket_listen)) == NULL) #ifdef USE_IPV6 && ((ip=str2ip6(&raw_socket_listen)) == NULL) #endif )) { LM_ERR("sipcapture mod_init: bad RAW IP: %.*s\n", raw_socket_listen.len, raw_socket_listen.s); return -1; } if(moni_capture_on && !moni_port_start) { LM_ERR("ERROR:sipcapture:mod_init: Please define port/portrange in 'raw_socket_listen', before \ activate monitoring capture\n"); return -1; }
/*! * \brief Convert a STR [proto:]ip[:port] into socket address. * [proto:]ip[:port] * \param pipport (udp:127.0.0.1:5060 or tcp:2001:0DB8:AC10:FE01:5060) * \param tmp_su target structure * \param proto uint protocol type * \return success / unsuccess */ static int pipport2su (str *sproto, str *ip, unsigned short port, union sockaddr_union *tmp_su, unsigned int *proto) { struct ip_addr *ip_a; str host_uri; /*parse protocol */ if(strncmp(sproto->s, "udp",3) == 0) *proto = IPPROTO_UDP; else if(strncmp(sproto->s, "tcp",3) == 0) *proto = IPPROTO_TCP; else if(strncmp(sproto->s, "tls",3) == 0) *proto = IPPROTO_IDP; /* fake proto type */ else if(strncmp(sproto->s, "sctp",4) == 0) *proto = IPPROTO_SCTP; else if(strncmp(sproto->s, "any",3) == 0) *proto = IPPROTO_UDP; else if(strncmp(sproto->s, "ws",2) == 0) *proto = IPPROTO_ESP; /* fake proto type */ else { LM_ERR("bad protocol %.*s\n", sproto->len, sproto->s); return -1; } /*check if ip is not null*/ if (ip->len == 0) { LM_ERR("malformed ip address\n"); return -1; } if (port == 0) { port = SIP_PORT; } else{ /*the address contains a port number*/ if (port<1024 || port>65536) { LM_ERR("invalid port number; must be in [1024,65536]\n"); return -1; } } LM_DBG("proto %d, host %.*s , port %d \n",*proto, ip->len, ip->s, port); /* now IPv6 address has no brakets. It should be fixed! */ host_uri = *ip; if (host_uri.s[0] == '[') { if(host_uri.s[host_uri.len-1] != ']') { LM_ERR("bracket not closed\n"); return -1; } host_uri.s++; host_uri.len -= 2; } /* check if it's an ip address */ if (((ip_a = str2ip(&host_uri)) != 0) || ((ip_a = str2ip6 (&host_uri)) != 0) ) { ip_addr2su(tmp_su, ip_a, ntohs(port)); return 0; } LM_ERR("host <%.*s> is not an IP\n",host_uri.len,host_uri.s); return -1; }
static int w_lb_count_call(struct sip_msg *req, char *ip, char *port, char *grp, char *rl, char *dir) { struct lb_grp_param *lbgp = (struct lb_grp_param *)grp; struct lb_res_str_list *lb_rl; struct lb_res_parse *lbp; struct ip_addr *ipa; pv_value_t val; pv_elem_t *model; int grp_no; int port_no; str dest; int ret; /* get the ip address */ if (pv_get_spec_value( req, (pv_spec_t*)ip, &val)!=0) { LM_ERR("failed to get IP value from PV\n"); return -1; } if ( (val.flags&PV_VAL_STR)==0 ) { LM_ERR("IP PV val is not string\n"); return -1; } if ( (ipa=str2ip( &val.rs ))==NULL && (ipa=str2ip6( &val.rs ))==NULL) { LM_ERR("IP val is not IP <%.*s>\n",val.rs.len,val.rs.s); return -1; } /* get the port */ if (port) { if (fixup_get_ivalue( req, (gparam_p)port, &port_no)!=0) { LM_ERR("failed to get PORT value from PV\n"); return -1; } } else { port_no = 0; } /* get the group */ if (lbgp->grp_pv) { if (pv_get_spec_value( req, (pv_spec_p)lbgp->grp_pv, &val)!=0) { LM_ERR("failed to get PV value\n"); return -1; } if ( (val.flags&PV_VAL_INT)==0 ) { LM_ERR("PV vals is not integer\n"); return -1; } grp_no = val.ri; } else { grp_no = lbgp->grp_no; } /* get the resources list */ lbp = (struct lb_res_parse *)rl; if (lbp->type & RES_ELEM) { model = (pv_elem_p)lbp->param; if (pv_printf_s(req, model, &dest) || dest.len <= 0) { LM_ERR("cannot create resource string\n"); return -1; } lb_rl = parse_resources_list(dest.s, 0); if (!lb_rl) { LM_ERR("cannot create resource list\n"); return -1; } } else lb_rl = (struct lb_res_str_list *)lbp->param; lock_start_read( ref_lock ); ret = lb_count_call( *curr_data, req, ipa, port_no, grp_no, lb_rl, dir ? (int)*(unsigned int *)dir : 0); lock_stop_read( ref_lock ); if (lbp->type & RES_ELEM) pkg_free(lb_rl); if (ret<0) return ret; return 1; }
int w_is_first_hop(sip_msg_t *msg, char *p1, char *p2) { int ret; rr_t* r = NULL; sip_uri_t puri; struct ip_addr *ip; if(msg==NULL) return -1; if(msg->first_line.type == SIP_REQUEST) { if (parse_headers( msg, HDR_VIA2_F, 0 )<0 || (msg->via2==0) || (msg->via2->error!=PARSE_OK)) { /* sip request: if more than one via, then not first hop */ /* no second via or error */ LM_DBG("no 2nd via found - first hop\n"); return 1; } return -1; } else if(msg->first_line.type == SIP_REPLY) { /* sip reply: if top record-route is myself * and not received from myself (loop), then is first hop */ if (parse_headers( msg, HDR_EOH_F, 0 )<0) { LM_DBG("error parsing headers\n"); return -1; } if(msg->record_route==NULL) { LM_DBG("no record-route header - first hop\n"); return 1; } if(parse_rr(msg->record_route)<0) { LM_DBG("failed to parse first record-route header\n"); return -1; } r = (rr_t*)msg->record_route->parsed; if(parse_uri(r->nameaddr.uri.s, r->nameaddr.uri.len, &puri)<0) { LM_DBG("failed to parse uri in first record-route header\n"); return -1; } if (((ip = str2ip(&(puri.host))) == NULL) && ((ip = str2ip6(&(puri.host))) == NULL)) { LM_DBG("uri host is not an ip address\n"); return -1; } ret = check_self(&puri.host, (puri.port.s)?puri.port_no:0, (puri.transport_val.s)?puri.proto:0); if(ret!=1) { LM_DBG("top record route uri is not myself\n"); return -1; } if (ip_addr_cmp(ip, &(msg->rcv.src_ip)) && ((msg->rcv.src_port == puri.port_no) || ((puri.port.len == 0) && (msg->rcv.src_port == 5060))) && (puri.proto==msg->rcv.proto || (puri.proto==0 && msg->rcv.proto==PROTO_UDP)) ) { LM_DBG("source address matches top record route uri - loop\n"); return -1; } /* todo - check spirals */ return 1; } else { return -1; } }
int ip_set_add_ip_s(struct ip_set *ip_set, str ip_s, str mask_s){ int fl; struct ip_addr *ip, ip_buff; unsigned int prefix, i; if ( ((ip = str2ip(&ip_s))==0) && ((ip = str2ip6(&ip_s))==0) ){ ERR("ip_set_add_ip_s: string to ip conversion error '%.*s'\n", ip_s.len, ip_s.s); return -1; } ip_buff = *ip; if (mask_s.len > 0) { i = 0; fl = 0; while (i < mask_s.len && ((mask_s.s[i] >= '0' && mask_s.s[i] <= '9') || (mask_s.s[i] >= 'a' && mask_s.s[i] <= 'f') || (mask_s.s[i] >= 'A' && mask_s.s[i] <= 'F') || mask_s.s[i] == '.' || mask_s.s[i] == ':' || mask_s.s[i] == '[' || mask_s.s[i] == ']' ) ) { fl |= mask_s.s[i] < '0' || mask_s.s[i] > '9'; i++; } if (fl) { /* 255.255.255.0 format */ if ( ((ip = str2ip(&mask_s))==0) && ((ip = str2ip6(&mask_s))==0) ){ ERR("ip_set_add_ip_s: string to ip mask conversion error '%.*s'\n", mask_s.len, mask_s.s); return -1; } if (ip_buff.af != ip->af) { ERR("ip_set_add_ip_s: IPv4 vs. IPv6 near '%.*s' vs. '%.*s'\n", ip_s.len, ip_s.s, mask_s.len, mask_s.s); return -1; } fl = 0; prefix = 0; for (i=0; i<ip->len; i++) { unsigned char msk; msk = 0x80; while (msk) { if ((ip->u.addr[i] & msk) != 0) { if (fl) { ERR("ip_set_add_ip_s: bad IP mask '%.*s'\n", mask_s.len, mask_s.s); return -1; } prefix++; } else { fl = 1; } msk /= 2; } } } else { /* 24 format */ if (str2int(&mask_s, &prefix) < 0) { ERR("ip_set_add_ip_s: cannot convert mask '%.*s'\n", mask_s.len, mask_s.s); return -1; } } } else { prefix = ip_buff.len*8; } if (ip_set_add_ip(ip_set, &ip_buff, prefix) < 0) { ERR("ip_set_add_ip_s: cannot add IP into ip set\n"); return -1; } return 0; }
/** Resolves SRV if no naptr found. * It reuse dns_pref values and according that resolves supported protocols. * If dns_pref are equal then it use udp,tcp,tls,sctp order. * returns: hostent struct & *port filled with the port from the SRV record; * 0 on error */ struct hostent* no_naptr_srv_sip_resolvehost(str* name, unsigned short* port, char* proto) { struct dns_srv_proto srv_proto_list[PROTO_LAST]; struct hostent* he; struct ip_addr* ip; str srv_name; static char tmp_srv[MAX_DNS_NAME]; /* tmp. buff. for SRV lookups */ size_t i,list_len; /* init variables */ he=0; /* check if it's an ip address */ if (((ip=str2ip(name))!=0) || ((ip=str2ip6(name))!=0) ){ /* we are lucky, this is an ip address */ /* set proto if needed - default udp */ if ((proto)&&(*proto==PROTO_NONE)) *proto=PROTO_UDP; /* set port if needed - default 5060/5061 */ if ((port)&&(*port==0)) *port=((proto) && (*proto==PROTO_TLS))?SIPS_PORT:SIP_PORT; he=ip_addr2he(name, ip); return he; } if ((name->len+SRV_MAX_PREFIX_LEN+1)>MAX_DNS_NAME){ LM_WARN("domain name too long (%d), unable to perform SRV lookup\n", name->len); } else { /* looping on the ordered list until we found a protocol what has srv record */ list_len = create_srv_pref_list(proto, srv_proto_list); for (i=0; i<list_len;i++) { switch (srv_proto_list[i].proto) { case PROTO_UDP: case PROTO_TCP: case PROTO_TLS: case PROTO_SCTP: create_srv_name(srv_proto_list[i].proto, name, tmp_srv); break; default: LM_CRIT("unknown proto %d\n", (int)srv_proto_list[i].proto); return 0; } /* set default port */ if ((port)&&(*port==0)){ *port=(srv_proto_list[i].proto==PROTO_TLS)?SIPS_PORT:SIP_PORT; /* just in case we don't find another */ } if ((proto)&&(*proto==0)){ *proto = PROTO_UDP; } srv_name.s=tmp_srv; srv_name.len=strlen(tmp_srv); #ifdef USE_DNS_CACHE he=dns_srv_get_he(&srv_name, port, dns_flags); #else he=srv_sip_resolvehost(&srv_name, 0, port, proto, 1, 0); #endif if (he!=0) { if(proto) *proto = srv_proto_list[i].proto; return he; } } } return 0; }
/* internal sip srv resolver: resolves a host name trying: * - SRV lookup if the address is not an ip *port==0. The result of the SRV * query will be used for an A/AAAA lookup. * - normal A/AAAA lookup (either fallback from the above or if *port!=0 * and *proto!=0 or port==0 && proto==0) * when performing SRV lookup (*port==0) it will use *proto to look for * tcp or udp hosts, otherwise proto is unused; if proto==0 => no SRV lookup * If zt is set, name will be assumed to be 0 terminated and some copy * operations will be avoided. * If is_srv is set it will assume name has the srv prefixes for sip already * appended and it's already 0-term'ed; if not it will append them internally. * If ars !=0, it will first try to look through them and only if the SRV * record is not found it will try doing a DNS query (ars will not be * freed, the caller should take care of them) * returns: hostent struct & *port filled with the port from the SRV record; * 0 on error */ struct hostent* srv_sip_resolvehost(str* name, int zt, unsigned short* port, char* proto, int is_srv, struct rdata* ars) { struct hostent* he; struct ip_addr* ip; static char tmp[MAX_DNS_NAME]; /* tmp. buff. for SRV lookups and null. term strings */ struct rdata* l; struct srv_rdata* srv; struct rdata* srv_head; char* srv_target; char srv_proto; /* init */ srv_head=0; srv_target=0; if (name->len >= MAX_DNS_NAME) { LOG(L_ERR, "sip_resolvehost: domain name too long\n"); he=0; goto end; } #ifdef RESOLVE_DBG DBG("srv_sip_resolvehost: %.*s:%d proto=%d\n", name->len, name->s, port?(int)*port:-1, proto?(int)*proto:-1); #endif if (is_srv){ /* skip directly to srv resolving */ srv_proto=(proto)?*proto:0; *port=(srv_proto==PROTO_TLS)?SIPS_PORT:SIP_PORT; if (zt){ srv_target=name->s; /* name.s must be 0 terminated in this case */ }else{ memcpy(tmp, name->s, name->len); tmp[name->len] = '\0'; srv_target=tmp; } goto do_srv; /* skip to the actual srv query */ } if (proto){ /* makes sure we have a protocol set*/ if (*proto==0) *proto=srv_proto=PROTO_UDP; /* default */ else srv_proto=*proto; }else{ srv_proto=PROTO_UDP; } /* try SRV if no port specified (draft-ietf-sip-srv-06) */ if ((port)&&(*port==0)){ *port=(srv_proto==PROTO_TLS)?SIPS_PORT:SIP_PORT; /* just in case we don't find another */ /* check if it's an ip address */ if (((ip=str2ip(name))!=0) #ifdef USE_IPV6 || ((ip=str2ip6(name))!=0) #endif ){ /* we are lucky, this is an ip address */ he=ip_addr2he(name, ip); goto end; } if ((name->len+SRV_MAX_PREFIX_LEN+1)>MAX_DNS_NAME){ LOG(L_WARN, "WARNING: sip_resolvehost: domain name too long (%d)," " unable to perform SRV lookup\n", name->len); }else{ switch(srv_proto){ case PROTO_NONE: /* no proto specified, use udp */ if (proto) *proto=PROTO_UDP; /* no break */ case PROTO_UDP: memcpy(tmp, SRV_UDP_PREFIX, SRV_UDP_PREFIX_LEN); memcpy(tmp+SRV_UDP_PREFIX_LEN, name->s, name->len); tmp[SRV_UDP_PREFIX_LEN + name->len] = '\0'; break; case PROTO_TCP: memcpy(tmp, SRV_TCP_PREFIX, SRV_TCP_PREFIX_LEN); memcpy(tmp+SRV_TCP_PREFIX_LEN, name->s, name->len); tmp[SRV_TCP_PREFIX_LEN + name->len] = '\0'; break; case PROTO_TLS: memcpy(tmp, SRV_TLS_PREFIX, SRV_TLS_PREFIX_LEN); memcpy(tmp+SRV_TLS_PREFIX_LEN, name->s, name->len); tmp[SRV_TLS_PREFIX_LEN + name->len] = '\0'; break; case PROTO_SCTP: memcpy(tmp, SRV_SCTP_PREFIX, SRV_SCTP_PREFIX_LEN); memcpy(tmp+SRV_SCTP_PREFIX_LEN, name->s, name->len); tmp[SRV_SCTP_PREFIX_LEN + name->len] = '\0'; break; default: LOG(L_CRIT, "BUG: sip_resolvehost: unknown proto %d\n", srv_proto); he=0; goto end; } srv_target=tmp; do_srv: /* try to find the SRV records inside previous ARs first*/ for (l=ars; l; l=l->next){ if (l->type!=T_SRV) continue; srv=(struct srv_rdata*) l->rdata; if (srv==0){ LOG(L_CRIT, "sip_resolvehost: BUG: null rdata\n"); /* cleanup on exit only */ break; } he=resolvehost(srv->name); if (he!=0){ /* we found it*/ #ifdef RESOLVE_DBG DBG("sip_resolvehost: found SRV(%s) = %s:%d in AR\n", srv_target, srv->name, srv->port); #endif *port=srv->port; /* cleanup on exit */ goto end; } } srv_head=get_record(srv_target, T_SRV, RES_ONLY_TYPE); for(l=srv_head; l; l=l->next){ if (l->type!=T_SRV) continue; /*should never happen*/ srv=(struct srv_rdata*) l->rdata; if (srv==0){ LOG(L_CRIT, "sip_resolvehost: BUG: null rdata\n"); /* cleanup on exit only */ break; } he=resolvehost(srv->name); if (he!=0){ /* we found it*/ #ifdef RESOLVE_DBG DBG("sip_resolvehost: SRV(%s) = %s:%d\n", srv_target, srv->name, srv->port); #endif *port=srv->port; /* cleanup on exit */ goto end; } } if (is_srv){ /* if the name was already into SRV format it doesn't make * any sense to fall back to A/AAAA */ he=0; goto end; } /* cleanup on exit */ #ifdef RESOLVE_DBG DBG("sip_resolvehost: no SRV record found for %.*s," " trying 'normal' lookup...\n", name->len, name->s); #endif } } /*skip_srv:*/ if (likely(!zt)){ memcpy(tmp, name->s, name->len); tmp[name->len] = '\0'; he=resolvehost(tmp); }else{ he=resolvehost(name->s); } end: #ifdef RESOLVE_DBG DBG("srv_sip_resolvehost: returning %p (%.*s:%d proto=%d)\n", he, name->len, name->s, port?(int)*port:-1, proto?(int)*proto:-1); #endif if (srv_head) free_rdata_list(srv_head); return he; }
/* checks if the proto: host:port is one of the address we listen on * and returns the corresponding socket_info structure. * if port==0, the port number is ignored * if proto==0 (PROTO_NONE) the protocol is ignored * returns 0 if not found * WARNING: uses str2ip6 so it will overwrite any previous * unsaved result of this function (static buffer) */ struct socket_info* grep_sock_info(str* host, unsigned short port, unsigned short proto) { char* hname; int h_len; struct socket_info* si; struct socket_info** list; unsigned short c_proto; #ifdef USE_IPV6 struct ip_addr* ip6; #endif h_len=host->len; hname=host->s; #ifdef USE_IPV6 if ((h_len>2)&&((*hname)=='[')&&(hname[h_len-1]==']')){ /* ipv6 reference, skip [] */ hname++; h_len-=2; } #endif c_proto=proto?proto:PROTO_UDP; do{ /* get the proper sock_list */ if (c_proto==PROTO_NONE) list=&udp_listen; else list=get_sock_info_list(c_proto); if (list==0){ LOG(L_WARN, "WARNING: grep_sock_info: " "unknown proto %d\n", c_proto); goto not_found; /* false */ } for (si=*list; si; si=si->next){ DBG("grep_sock_info - checking if host==us: %d==%d && " " [%.*s] == [%.*s]\n", h_len, si->name.len, h_len, hname, si->name.len, si->name.s ); if (port) { DBG("grep_sock_info - checking if port %d matches port %d\n", si->port_no, port); if (si->port_no!=port) { continue; } } if ( (h_len==si->name.len) && (strncasecmp(hname, si->name.s, si->name.len)==0) /*slower*/) /* comp. must be case insensitive, host names * can be written in mixed case, it will also match * ipv6 addresses if we are lucky*/ goto found; /* check if host == ip address */ #ifdef USE_IPV6 /* ipv6 case is uglier, host can be [3ffe::1] */ ip6=str2ip6(host); if (ip6){ if (ip_addr_cmp(ip6, &si->address)) goto found; /* match */ else continue; /* no match, but this is an ipv6 address so no point in trying ipv4 */ } #endif /* ipv4 */ if ( (!(si->flags&SI_IS_IP)) && (h_len==si->address_str.len) && (memcmp(hname, si->address_str.s, si->address_str.len)==0) ) goto found; } }while( (proto==0) && (c_proto=next_proto(c_proto)) ); not_found: return 0; found: return si; }
static int w_ip_is_trusted(struct sip_msg* msg, char* _ip_set, char* _ip) { str ip_set_s, ip_s; struct ip_addr *ip, ip_buf; struct ip_set new_ip_set, *ip_set; struct ip_set_list_item *isli = NULL; int kind; kind = ((struct ip_set_param*)_ip_set)->kind; if (kind == IP_SET_PARAM_KIND_LOCAL) { if (get_str_fparam(&ip_set_s, msg, ((struct ip_set_param*)_ip_set)->u.local.fparam) < 0) { ERR(MODULE_NAME": ip_is_trusted: Error while obtaining ip_set parameter value\n"); return -1; } if (is_ip_set_name(&ip_set_s)) { isli = ip_set_list_find_by_name(ip_set_s); if (!isli) { ERR(MODULE_NAME": ip_is_trusted: ip set '%.*s' is not declared\n", ip_set_s.len, ip_set_s.s); return -1; } kind = IP_SET_PARAM_KIND_GLOBAL; goto force_global; } ip_set = &((struct ip_set_param*)_ip_set)->u.local.ip_set; } else { isli = ((struct ip_set_param*)_ip_set)->u.global.ip_set; force_global: if (!isli->ip_set) return -1; /* empty ip set */ if (unlikely(isli->ip_set != ip_set_list_local[isli->idx])) { /* global ip set has changed ? */ if (ip_set_list_local[isli->idx]) { if (atomic_dec_and_test(&ip_set_list_local[isli->idx]->refcnt)) { ip_set_destroy(&ip_set_list_local[isli->idx]->ip_set); shm_free(ip_set_list_local[isli->idx]); ip_set_list_local[isli->idx] = NULL; } } lock_get(&isli->read_lock); atomic_inc(&isli->ip_set->refcnt); ip_set_list_local[isli->idx] = isli->ip_set; lock_release(&isli->read_lock); } ip_set = &ip_set_list_local[isli->idx]->ip_set; } if (get_str_fparam(&ip_s, msg, (fparam_t*)_ip) < 0) { ERR(MODULE_NAME": ip_is_trusted: Error while obtaining ip parameter value\n"); return -1; } if (!ip_s.len || !ip_set_s.len) return -1; switch (ip_s.s[0]) { case 's': /* src */ case 'S': ip = &msg->rcv.src_ip; break; case 'd': /* dst */ case 'D': ip = &msg->rcv.dst_ip; break; case 'r': /* rcv */ case 'R': ip = &msg->rcv.bind_address->address; break; default: /* string -> ip */ if ( ((ip = str2ip(&ip_s))==0) && ((ip = str2ip6(&ip_s))==0) ){ ERR(MODULE_NAME": ip_is_trusted: string to ip conversion error '%.*s'\n", ip_s.len, ip_s.s); return -1; } ip_buf = *ip; ip = &ip_buf; /* value has been in static buffer */ break; } /* test if ip_set string has changed since last call */ if (kind == IP_SET_PARAM_KIND_LOCAL) { if (((struct ip_set_param*)_ip_set)->u.local.s.len != ip_set_s.len || memcmp(((struct ip_set_param*)_ip_set)->u.local.s.s, ip_set_s.s, ip_set_s.len) != 0) { ip_set_init(&new_ip_set, 0); if (ip_set_add_list(&new_ip_set, ip_set_s) < 0) { ip_set_destroy(&new_ip_set); return -1; }; if (((struct ip_set_param*)_ip_set)->u.local.sz < ip_set_s.len) { void *p; p = pkg_realloc(((struct ip_set_param*)_ip_set)->u.local.s.s, ip_set_s.len); if (!p) { ip_set_destroy(&new_ip_set); return E_OUT_OF_MEM; } ((struct ip_set_param*)_ip_set)->u.local.s.s = p; ((struct ip_set_param*)_ip_set)->u.local.sz = ip_set_s.len; } memcpy(((struct ip_set_param*)_ip_set)->u.local.s.s, ip_set_s.s, ip_set_s.len); ((struct ip_set_param*)_ip_set)->u.local.s.len = ip_set_s.len; ip_set_destroy(&((struct ip_set_param*)_ip_set)->u.local.ip_set); ((struct ip_set_param*)_ip_set)->u.local.ip_set = new_ip_set; } } /* ip_set_print(stderr, &ip_set); */ switch (ip_set_ip_exists(ip_set, ip)) { case IP_TREE_FIND_FOUND: case IP_TREE_FIND_FOUND_UPPER_SET: return 1; default: return -1; } }
struct hostent* no_naptr_srv_sip_resolvehost(str* name, unsigned short* port, char* proto) { struct dns_srv_proto_t { char proto; int proto_pref; } srv_proto_list[PROTO_LAST], tmp_srv_element; struct hostent* he; struct ip_addr* ip; str srv_name; static char tmp_srv[MAX_DNS_NAME]; /* tmp. buff. for SRV lookups */ int len; unsigned char i,j,max,default_order=0,list_len=0; /* init variables */ he=0; len=0; /* check if it's an ip address */ if (((ip=str2ip(name))!=0) #ifdef USE_IPV6 || ((ip=str2ip6(name))!=0) #endif ){ /* we are lucky, this is an ip address */ /* set proto if needed - default udp */ if ((proto)&&(*proto==PROTO_NONE)) *proto=PROTO_UDP; /* set port if needed - default 5060/5061 */ if ((port)&&(*port==0)) *port=((proto) && (*proto==PROTO_TLS))?SIPS_PORT:SIP_PORT; he=ip_addr2he(name, ip); return he; } if ((name->len+SRV_MAX_PREFIX_LEN+1)>MAX_DNS_NAME){ LOG(L_WARN, "WARNING: no_naptr_srv_sip_resolvehost: domain name too long" " (%d), unable to perform SRV lookup\n", name->len); } else { /* if proto available, then add only the forced protocol to the list */ if (proto && *proto!=PROTO_NONE){ srv_proto_list[0].proto=*proto; list_len=1; } else { /*get protocols and preference scores, and add availble protocol(s) and score(s) to the list*/ for (i=PROTO_UDP; i<PROTO_LAST;i++) { tmp_srv_element.proto_pref = proto_pref_score(i); /* if -1 so disabled continue with next protocol*/ if (naptr_proto_supported(i) == 0 ) { continue; } else { srv_proto_list[i-1].proto_pref=tmp_srv_element.proto_pref; srv_proto_list[i-1].proto=i; list_len++; } }; /* if all protocol prefence scores equal, then set the perference to default values: udp,tcp,tls,sctp */ for (i=1; i<list_len;i++) { if(srv_proto_list[0].proto_pref!=srv_proto_list[i].proto_pref){ default_order=0; } } if (default_order){ for (i=0; i<list_len;i++) { switch ( srv_proto_list[i].proto) { case PROTO_UDP: srv_proto_list[i].proto_pref=4; break; case PROTO_TCP: srv_proto_list[i].proto_pref=3; break; case PROTO_TLS: srv_proto_list[i].proto_pref=2; break; case PROTO_SCTP: srv_proto_list[i].proto_pref=1; break; } } } /* sorting the list */ for (i=0;i<list_len-1;i++) { max=i; for (j=i+1;j<list_len;j++) { if (srv_proto_list[j].proto_pref>srv_proto_list[max].proto_pref) { max=j; } } if (i!=max) { tmp_srv_element=srv_proto_list[i]; srv_proto_list[i]=srv_proto_list[max]; srv_proto_list[max]=tmp_srv_element; } } } /* looping on the ordered list until we found a protocol what has srv record */ for (i=0; i<list_len;i++) { switch (srv_proto_list[i].proto) { case PROTO_NONE: /* no proto specified, use udp */ if (proto) *proto=PROTO_UDP; /* no break */ case PROTO_UDP: memcpy(tmp_srv, SRV_UDP_PREFIX, SRV_UDP_PREFIX_LEN); memcpy(tmp_srv+SRV_UDP_PREFIX_LEN, name->s, name->len); tmp_srv[SRV_UDP_PREFIX_LEN + name->len] = '\0'; len=SRV_UDP_PREFIX_LEN + name->len; break; case PROTO_TCP: memcpy(tmp_srv, SRV_TCP_PREFIX, SRV_TCP_PREFIX_LEN); memcpy(tmp_srv+SRV_TCP_PREFIX_LEN, name->s, name->len); tmp_srv[SRV_TCP_PREFIX_LEN + name->len] = '\0'; len=SRV_TCP_PREFIX_LEN + name->len; break; case PROTO_TLS: memcpy(tmp_srv, SRV_TLS_PREFIX, SRV_TLS_PREFIX_LEN); memcpy(tmp_srv+SRV_TLS_PREFIX_LEN, name->s, name->len); tmp_srv[SRV_TLS_PREFIX_LEN + name->len] = '\0'; len=SRV_TLS_PREFIX_LEN + name->len; break; case PROTO_SCTP: memcpy(tmp_srv, SRV_SCTP_PREFIX, SRV_SCTP_PREFIX_LEN); memcpy(tmp_srv+SRV_SCTP_PREFIX_LEN, name->s, name->len); tmp_srv[SRV_SCTP_PREFIX_LEN + name->len] = '\0'; len=SRV_SCTP_PREFIX_LEN + name->len; break; default: LOG(L_CRIT, "BUG: sip_resolvehost: unknown proto %d\n", (int)srv_proto_list[i].proto); return 0; } /* set default port */ if ((port)&&(*port==0)){ *port=(srv_proto_list[i].proto==PROTO_TLS)?SIPS_PORT:SIP_PORT; /* just in case we don't find another */ } srv_name.s=tmp_srv; srv_name.len=len; #ifdef USE_DNS_CACHE he=dns_srv_get_he(&srv_name, port, dns_flags); #else he=srv_sip_resolvehost(&srv_name, 0, port, proto, 1, 0); #endif if (he!=0) { return he; } } } return 0; }
/*! * \brief Convert a STR [proto:]ip[:port] into socket address. * [proto:]ip[:port] * \param pipport (udp:127.0.0.1:5060 or tcp:2001:0DB8:AC10:FE01:5060) * \param tmp_su target structure * \param proto uint protocol type * \return success / unsuccess */ static int pipport2su (char *pipport, union sockaddr_union *tmp_su, unsigned int *proto) { unsigned int port_no, cutlen = 4; struct ip_addr *ip; char *p, *host_s; str port_str, host_uri; unsigned len = 0; char tmp_piport[256]; /*parse protocol */ if(strncmp(pipport, "udp:",4) == 0) *proto = IPPROTO_UDP; else if(strncmp(pipport, "tcp:",4) == 0) *proto = IPPROTO_TCP; else if(strncmp(pipport, "tls:",4) == 0) *proto = IPPROTO_IDP; /* fake proto type */ else if(strncmp(pipport, "ws:",3) == 0) *proto = IPPROTO_IDP; /* fake proto type */ else if(strncmp(pipport, "wss:",4) == 0) *proto = IPPROTO_IDP; /* fake proto type */ #ifdef USE_SCTP else if(strncmp(pipport, "sctp:",5) == 0) cutlen = 5, *proto = IPPROTO_SCTP; #endif else if(strncmp(pipport, "any:",4) == 0) *proto = IPPROTO_UDP; else { LM_ERR("bad protocol %s\n", pipport); return -1; } if((len = strlen(pipport)) >= 256) { LM_ERR("too big pipport\n"); goto error; } /* our tmp string */ strncpy(tmp_piport, pipport, len+1); len = 0; /*separate proto and host */ p = tmp_piport+cutlen; if( (*(p)) == '\0') { LM_ERR("malformed ip address\n"); goto error; } host_s=p; if( (p = strrchr(p+1, ':')) == 0 ) { LM_DBG("no port specified\n"); port_no = 0; } else { /*the address contains a port number*/ *p = '\0'; p++; port_str.s = p; port_str.len = strlen(p); LM_DBG("the port string is %s\n", p); if(str2int(&port_str, &port_no) != 0 ) { LM_ERR("there is not a valid number port\n"); goto error; } *p = '\0'; } /* now IPv6 address has no brakets. It should be fixed! */ if (host_s[0] == '[') { len = strlen(host_s + 1) - 1; if(host_s[len+1] != ']') { LM_ERR("bracket not closed\n"); goto error; } memmove(host_s, host_s + 1, len); host_s[len] = '\0'; } host_uri.s = host_s; host_uri.len = strlen(host_s); /* check if it's an ip address */ if (((ip=str2ip(&host_uri))!=0) || ((ip=str2ip6(&host_uri))!=0) ) { ip_addr2su(tmp_su, ip, ntohs(port_no)); return 0; } error: return -1; }