void delete_sock_info(struct socket_info* sock,int proto) { struct socket_info** list; list=get_sock_info_list(proto); sock_listrm(list, sock); free_sock_info(sock); }
/* adds a sock_info structure to the corresponding proto list * return 0 on success, -1 on error */ int add_listen_iface(char* name, unsigned short port, unsigned short proto, enum si_flags flags) { struct socket_info** list; unsigned short c_proto; c_proto=(proto)?proto:PROTO_UDP; do{ list=get_sock_info_list(c_proto); if (list==0){ LOG(L_ERR, "ERROR: add_listen_iface: get_sock_info_list failed\n"); goto error; } if (port==0){ /* use default port */ port= #ifdef USE_TLS ((c_proto)==PROTO_TLS)?tls_port_no: #endif port_no; } #ifdef USE_TLS else if ((c_proto==PROTO_TLS) && (proto==0)){ /* -l ip:port => on udp:ip:port; tcp:ip:port and tls:ip:port+1? */ port++; } #endif if (new_sock2list(name, port, c_proto, flags, list)<0){ LOG(L_ERR, "ERROR: add_listen_iface: new_sock2list failed\n"); goto error; } }while( (proto==0) && (c_proto=next_proto(c_proto))); return 0; error: return -1; }
/* checks if the proto: ip:port is one of the address we listen on * and returns the corresponding socket_info structure. * (same as grep_socket_info, but use ip addr instead) * 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* find_si(struct ip_addr* ip, unsigned short port, unsigned short proto) { struct socket_info* si; struct socket_info** list; unsigned short c_proto; 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){ if (port) { if (si->port_no!=port) { continue; } } if (ip_addr_cmp(ip, &si->address)) goto found; } }while( (proto==0) && (c_proto=next_proto(c_proto)) ); not_found: return 0; found: return si; }
void print_all_socket_lists() { struct socket_info *si; struct socket_info** list; unsigned short proto; proto=PROTO_UDP; do{ list=get_sock_info_list(proto); for(si=list?*list:0; si; si=si->next){ printf(" %s: %s [%s]:%s%s\n", get_proto_name(proto), si->name.s, si->address_str.s, si->port_no_str.s, si->flags & SI_IS_MCAST ? " mcast" : ""); } }while((proto=next_proto(proto))); }
/* * RPC command to list the listening sockets */ static void corex_rpc_list_sockets(rpc_t* rpc, void* ctx) { void* th; void* ih; struct socket_info *si; struct socket_info** list; struct addr_info* ai; unsigned short proto; proto=PROTO_UDP; do { list=get_sock_info_list(proto); for(si=list?*list:0; si; si=si->next) { /* add structure node */ if (rpc->add(ctx, "{", &th) < 0) { rpc->fault(ctx, 500, "Internal error socket structure"); return; } if(rpc->struct_add(th, "ss{", "PROTO", get_valid_proto_name(proto), "NAME", si->name.s, "ADDRLIST", &ih)<0) { rpc->fault(ctx, 500, "Internal error address list structure"); return; } if(rpc->struct_add(ih, "s", "ADDR", si->address_str.s)<0) { rpc->fault(ctx, 500, "Internal error address structure"); return; } if (si->addr_info_lst) { for (ai=si->addr_info_lst; ai; ai=ai->next) { if(rpc->struct_add(ih, "s", "ADDR", ai->address_str.s)<0) { rpc->fault(ctx, 500, "Internal error extra address structure"); return; } } } if(rpc->struct_add(th, "ssss", "PORT", si->port_no_str.s, "MCAST", si->flags & SI_IS_MCAST ? "yes" : "no", "MHOMED", si->flags & SI_IS_MHOMED? "yes" : "no", "ADVERTISE", si->useinfo.name.s?si->useinfo.name.s:"-")<0) { rpc->fault(ctx, 500, "Internal error attrs structure"); return; } } } while((proto=next_proto(proto))); return; }
/*! * This function will retrieve a list of all ip addresses and ports that Kamailio * is listening on, with respect to the transport protocol specified with * 'protocol'. This function supports both IPv4 and IPv6 * * The first parameter, ipList, is a pointer to a pointer. It will be assigned a * new block of memory holding the IP Addresses and ports being listened to with * respect to 'protocol'. The array maps a 2D array into a 1 dimensional space, * and is layed out as follows: * * The first NUM_IP_OCTETS indices will be the IP address, and the next index * the port. So if NUM_IP_OCTETS is equal to 4 and there are two IP addresses * found, then: * * - ipList[0] will be the first octet of the first ip address * - ipList[3] will be the last octet of the first ip address. * - iplist[4] will be the port of the first ip address * - * - iplist[5] will be the first octet of the first ip address, * - and so on. */ int get_socket_list_from_proto_and_family(int **ipList, int protocol, int family) { struct socket_info *si; struct socket_info** list; int num_ip_octets = family == AF_INET ? NUM_IP_OCTETS : NUM_IPV6_OCTETS; int numberOfSockets = 0; int currentRow = 0; /* I hate to use #ifdefs, but this is necessary because of the way * get_sock_info_list() is defined. */ #ifndef USE_TCP if (protocol == PROTO_TCP) { return 0; } #endif #ifndef USE_TLS if (protocol == PROTO_TLS) { return 0; } #endif #ifndef USE_SCTP if (protocol == PROTO_SCTP) { return 0; } #endif /* We have no "interfaces" for websockets */ if (protocol == PROTO_WS || protocol == PROTO_WSS) return 0; /* Retrieve the list of sockets with respect to the given protocol. */ list=get_sock_info_list(protocol); /* Find out how many sockets are in the list. We need to know this so * we can malloc an array to assign to ipList. */ for(si=list?*list:0; si; si=si->next) { if (si->address.af == family) { numberOfSockets++; } } /* There are no open sockets with respect to the given protocol. */ if (numberOfSockets == 0) { return 0; } *ipList = pkg_malloc(numberOfSockets * (num_ip_octets + 1) * sizeof(int)); /* We couldn't allocate memory for the IP List. So all we can do is * fail. */ if (*ipList == NULL) { LM_ERR("no more pkg memory"); return 0; } /* We need to search the list again. So find the front of the list. */ list=get_sock_info_list(protocol); /* Extract out the IP Addresses and ports. */ for(si=list?*list:0; si; si=si->next) { int i; /* We currently only support IPV4. */ if (si->address.af != family) { continue; } for (i = 0; i < num_ip_octets; i++) { (*ipList)[currentRow*(num_ip_octets + 1) + i ] = si->address.u.addr[i]; } (*ipList)[currentRow*(num_ip_octets + 1) + i] = si->port_no; currentRow++; } return numberOfSockets; }
/* 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; }
/* * This function will retrieve a list of all ip addresses and ports that OpenSER * is listening on, with respect to the transport protocol specified with * 'protocol'. * * The first parameter, ipList, is a pointer to a pointer. It will be assigned a * new block of memory holding the IP Addresses and ports being listened to with * respect to 'protocol'. The array maps a 2D array into a 1 dimensional space, * and is layed out as follows: * * The first NUM_IP_OCTETS indices will be the IP address, and the next index * the port. So if NUM_IP_OCTETS is equal to 4 and there are two IP addresses * found, then: * * - ipList[0] will be the first octet of the first ip address * - ipList[3] will be the last octet of the first ip address. * - iplist[4] will be the port of the first ip address * - * - iplist[5] will be the first octet of the first ip address, * - and so on. * * The function will return the number of sockets which were found. This can be * used to index into ipList. * * NOTE: This function assigns a block of memory equal to: * * returnedValue * (NUM_IP_OCTETS + 1) * sizeof(int); * * Therefore it is CRUCIAL that you free ipList when you are done with its * contents, to avoid a nasty memory leak. */ int get_socket_list_from_proto(int **ipList, int protocol) { struct socket_info *si; struct socket_info** list; int num_ip_octets = 4; int numberOfSockets = 0; int currentRow = 0; /* I hate to use #ifdefs, but this is necessary because of the way * get_sock_info_list() is defined. */ #ifndef USE_TCP if (protocol == PROTO_TCP) { return 0; } #endif #ifndef USE_TLS if (protocol == PROTO_TLS) { return 0; } #endif /* Retrieve the list of sockets with respect to the given protocol. */ list=get_sock_info_list(protocol); /* Find out how many sockets are in the list. We need to know this so * we can malloc an array to assign to ipList. */ for(si=list?*list:0; si; si=si->next){ /* We only support IPV4 at this point. */ if (si->address.af == AF_INET) { numberOfSockets++; } } /* There are no open sockets with respect to the given protocol. */ if (numberOfSockets == 0) { return 0; } *ipList = pkg_malloc(numberOfSockets * (num_ip_octets + 1) * sizeof(int)); /* We couldn't allocate memory for the IP List. So all we can do is * fail. */ if (*ipList == NULL) { LM_ERR("no more pkg memory"); return 0; } /* We need to search the list again. So find the front of the list. */ list=get_sock_info_list(protocol); /* Extract out the IP Addresses and ports. */ for(si=list?*list:0; si; si=si->next){ /* We currently only support IPV4. */ if (si->address.af != AF_INET) { continue; } (*ipList)[currentRow*(num_ip_octets + 1) ] = si->address.u.addr[0]; (*ipList)[currentRow*(num_ip_octets + 1)+1] = si->address.u.addr[1]; (*ipList)[currentRow*(num_ip_octets + 1)+2] = si->address.u.addr[2]; (*ipList)[currentRow*(num_ip_octets + 1)+3] = si->address.u.addr[3]; (*ipList)[currentRow*(num_ip_octets + 1)+4] = si->port_no; currentRow++; } return numberOfSockets; }