Skip to content

Commit

Permalink
core: listen can now have a "virtual" flag to check for nonlocal floa…
Browse files Browse the repository at this point in the history
…ting IPs.

A new option to "listen" has been added called "virtual". This sets a flag on the listening socket to modify the behaviour of grep_sock_info.
When this flag is set, grep_sock_info will only consider the listening IP a match if the IP is found in the system's current list of
local IP addresses. If the IP is not currently local, then the matching IP is ignored.
If the virtual flag is not set on the socket then existing behaviour used instead.

This is useful in scenarios with an active/active cluster where Kamailio must know if a floating IP is currently local or not.
  • Loading branch information
rhys-hanrahan authored and miconda committed Jan 7, 2022
1 parent 60c5a87 commit e93640e
Show file tree
Hide file tree
Showing 4 changed files with 164 additions and 7 deletions.
2 changes: 2 additions & 0 deletions src/core/cfg.lex
Expand Up @@ -305,6 +305,7 @@ XAVPVIAPARAMS xavp_via_params
XAVPVIAFIELDS xavp_via_fields
LISTEN listen
ADVERTISE advertise|ADVERTISE
VIRTUAL virtual
STRNAME name|NAME
ALIAS alias
SR_AUTO_ALIASES auto_aliases
Expand Down Expand Up @@ -741,6 +742,7 @@ IMPORTFILE "import_file"
<INITIAL>{XAVPVIAFIELDS} { yylval.strval=yytext; return XAVPVIAFIELDS; }
<INITIAL>{LISTEN} { count(); yylval.strval=yytext; return LISTEN; }
<INITIAL>{ADVERTISE} { count(); yylval.strval=yytext; return ADVERTISE; }
<INITIAL>{VIRTUAL} { count(); yylval.strval=yytext; return VIRTUAL; }
<INITIAL>{STRNAME} { count(); yylval.strval=yytext; return STRNAME; }
<INITIAL>{ALIAS} { count(); yylval.strval=yytext; return ALIAS; }
<INITIAL>{SR_AUTO_ALIASES} { count(); yylval.strval=yytext;
Expand Down
83 changes: 83 additions & 0 deletions src/core/cfg.y
Expand Up @@ -328,6 +328,7 @@ extern char *default_routename;
%token XAVPVIAFIELDS
%token LISTEN
%token ADVERTISE
%token VIRTUAL
%token STRNAME
%token ALIAS
%token SR_AUTO_ALIASES
Expand Down Expand Up @@ -1503,6 +1504,19 @@ assign_stm:
}
free_socket_id_lst($3);
}
| LISTEN EQUAL id_lst VIRTUAL {
for(lst_tmp=$3; lst_tmp; lst_tmp=lst_tmp->next) {
lst_tmp->flags |= SI_IS_VIRTUAL;
if (add_listen_iface( lst_tmp->addr_lst->name,
lst_tmp->addr_lst->next,
lst_tmp->port, lst_tmp->proto,
lst_tmp->flags)!=0) {
LM_CRIT("cfg. parser: failed to add listen address\n");
break;
}
}
free_socket_id_lst($3);
}
| LISTEN EQUAL id_lst STRNAME STRING {
for(lst_tmp=$3; lst_tmp; lst_tmp=lst_tmp->next) {
if (add_listen_iface_name(lst_tmp->addr_lst->name,
Expand All @@ -1515,6 +1529,19 @@ assign_stm:
}
free_socket_id_lst($3);
}
| LISTEN EQUAL id_lst STRNAME STRING VIRTUAL {
for(lst_tmp=$3; lst_tmp; lst_tmp=lst_tmp->next) {
lst_tmp->flags |= SI_IS_VIRTUAL;
if (add_listen_iface_name(lst_tmp->addr_lst->name,
lst_tmp->addr_lst->next,
lst_tmp->port, lst_tmp->proto, $5,
lst_tmp->flags)!=0) {
LM_CRIT("cfg. parser: failed to add listen address\n");
break;
}
}
free_socket_id_lst($3);
}
| LISTEN EQUAL id_lst ADVERTISE listen_id COLON NUMBER {
for(lst_tmp=$3; lst_tmp; lst_tmp=lst_tmp->next) {
if (add_listen_advertise_iface( lst_tmp->addr_lst->name,
Expand All @@ -1528,6 +1555,20 @@ assign_stm:
}
free_socket_id_lst($3);
}
| LISTEN EQUAL id_lst ADVERTISE listen_id COLON NUMBER VIRTUAL {
for(lst_tmp=$3; lst_tmp; lst_tmp=lst_tmp->next) {
lst_tmp->flags |= SI_IS_VIRTUAL;
if (add_listen_advertise_iface( lst_tmp->addr_lst->name,
lst_tmp->addr_lst->next,
lst_tmp->port, lst_tmp->proto,
$5, $7,
lst_tmp->flags)!=0) {
LM_CRIT("cfg. parser: failed to add listen address\n");
break;
}
}
free_socket_id_lst($3);
}
| LISTEN EQUAL id_lst ADVERTISE listen_id COLON NUMBER STRNAME STRING {
for(lst_tmp=$3; lst_tmp; lst_tmp=lst_tmp->next) {
if (add_listen_advertise_iface_name(lst_tmp->addr_lst->name,
Expand All @@ -1541,6 +1582,20 @@ assign_stm:
}
free_socket_id_lst($3);
}
| LISTEN EQUAL id_lst ADVERTISE listen_id COLON NUMBER STRNAME STRING VIRTUAL {
for(lst_tmp=$3; lst_tmp; lst_tmp=lst_tmp->next) {
lst_tmp->flags |= SI_IS_VIRTUAL;
if (add_listen_advertise_iface_name(lst_tmp->addr_lst->name,
lst_tmp->addr_lst->next,
lst_tmp->port, lst_tmp->proto,
$5, $7, $9,
lst_tmp->flags)!=0) {
LM_CRIT("cfg. parser: failed to add listen address\n");
break;
}
}
free_socket_id_lst($3);
}
| LISTEN EQUAL id_lst ADVERTISE listen_id {
for(lst_tmp=$3; lst_tmp; lst_tmp=lst_tmp->next) {
if (add_listen_advertise_iface( lst_tmp->addr_lst->name,
Expand All @@ -1554,6 +1609,20 @@ assign_stm:
}
free_socket_id_lst($3);
}
| LISTEN EQUAL id_lst ADVERTISE listen_id VIRTUAL {
for(lst_tmp=$3; lst_tmp; lst_tmp=lst_tmp->next) {
lst_tmp->flags |= SI_IS_VIRTUAL;
if (add_listen_advertise_iface( lst_tmp->addr_lst->name,
lst_tmp->addr_lst->next,
lst_tmp->port, lst_tmp->proto,
$5, 0,
lst_tmp->flags)!=0) {
LM_CRIT("cfg. parser: failed to add listen address\n");
break;
}
}
free_socket_id_lst($3);
}
| LISTEN EQUAL id_lst ADVERTISE listen_id STRNAME STRING {
for(lst_tmp=$3; lst_tmp; lst_tmp=lst_tmp->next) {
if (add_listen_advertise_iface_name(lst_tmp->addr_lst->name,
Expand All @@ -1567,6 +1636,20 @@ assign_stm:
}
free_socket_id_lst($3);
}
| LISTEN EQUAL id_lst ADVERTISE listen_id STRNAME STRING VIRTUAL {
for(lst_tmp=$3; lst_tmp; lst_tmp=lst_tmp->next) {
lst_tmp->flags |= SI_IS_VIRTUAL;
if (add_listen_advertise_iface_name(lst_tmp->addr_lst->name,
lst_tmp->addr_lst->next,
lst_tmp->port, lst_tmp->proto,
$5, 0, $7,
lst_tmp->flags)!=0) {
LM_CRIT("cfg. parser: failed to add listen address\n");
break;
}
}
free_socket_id_lst($3);
}
| LISTEN EQUAL error { yyerror("ip address, interface name or"
" hostname expected"); }
| ALIAS EQUAL id_lst {
Expand Down
1 change: 1 addition & 0 deletions src/core/ip_addr.h
Expand Up @@ -84,6 +84,7 @@ typedef enum si_flags {
SI_IS_MCAST = (1<<2),
SI_IS_ANY = (1<<3),
SI_IS_MHOMED = (1<<4),
SI_IS_VIRTUAL = (1<<5),
} si_flags_t;

typedef struct addr_info {
Expand Down
85 changes: 78 additions & 7 deletions src/core/socket_info.c
Expand Up @@ -562,6 +562,66 @@ struct socket_info** get_sock_info_list(unsigned short proto)
return 0;
}

/* Check list of active local IPs for grep_sock_info
* This function is only used for sockets with the SI_IS_VIRTUAL flag set. This
* is so floating (virtual) IPs that are not currently local, are not returned
* as matches by grep_sock_info.
*
* Params:
* - si - Socket info of socket that has been flagged with SI_IS_VIRTUAL,
* that we want to check if it's actually local right now.
*
* Returns 1 if socket is local, or 0 if not.
*/
static int check_local_addresses(struct socket_info* si)
{
struct hostent* he;
struct utsname myname;

if (si == NULL) {
LM_ERR("Socket info is NULL. Returning no match.\n");
return 0;
}

if (!(si->flags & SI_IS_VIRTUAL)) {
LM_ERR("Have been passed a socket without the virtual flag set. This should "
"not happen. Returning a match to maintain standard behaviour.\n");
return 1;
}

if (uname(&myname) <0){
LM_ERR("Cannot determine hostname. Guessing a not local virtual IP.\n");
return 0;
}

//Should return a list of local IPs
he = _resolvehost(myname.nodename);
if (he == NULL) {
LM_ERR("Cannot get list of local IPs. Guessing not a local virtual IP.\n");
return 0;
}
char** paddrlist = he->h_addr_list;
int i = 0;
while (*paddrlist != NULL)
{
struct ip_addr local_addr;
hostent2ip_addr(&local_addr, he, i);

LM_DBG("Checking local address: %s\n", ip_addr2a(&local_addr));
if (ip_addr_cmp(&si->address, &local_addr)) {
LM_DBG("Found matching local IP for virtual socket: %s\n", ip_addr2a(&local_addr));
return 1;
}

i++;
paddrlist++;
}

//Default to not local if no match is found
LM_DBG("No matching local IP found.\n");
return 0;
}


/* helper function for grep_sock_info
* params:
Expand Down Expand Up @@ -653,7 +713,16 @@ struct socket_info* grep_sock_info(str* host, unsigned short port,
}
if (si_hname_cmp(&hname, &si->name, &si->address_str,
&si->address, si->flags)==0) {
goto found;
if (si->flags & SI_IS_VIRTUAL) {
LM_DBG("Checking virtual socket: [%.*s]\n", si->name.len, si->name.s);
if (check_local_addresses(si)) {
goto found;
} else {
LM_DBG("Skipping virtual socket that is not local.\n");
}
} else {
goto found;
}
}
if(si->useinfo.name.s!=NULL) {
LM_DBG("checking advertise if host==us:"
Expand Down Expand Up @@ -2071,21 +2140,23 @@ void print_all_socket_lists()
for (ai=si->addr_info_lst; ai; ai=ai->next) {
printf(", %s", ai->address_str.s);
}
printf("):%s%s%s\n",
printf("):%s%s%s%s\n",
si->port_no_str.s,
si->flags & SI_IS_MCAST ? " mcast" : "",
si->flags & SI_IS_MHOMED? " mhomed" : "");
si->flags & SI_IS_MCAST ? " mcast" : "",
si->flags & SI_IS_MHOMED ? " mhomed" : "",
si->flags & SI_IS_VIRTUAL? " virtual" : "");
}else{
printf(" %s: %s",
get_valid_proto_name(proto),
si->name.s);
if (!(si->flags & SI_IS_IP)) {
printf(" [%s]", si->address_str.s);
}
printf( ":%s%s%s",
printf( ":%s%s%s%s",
si->port_no_str.s,
si->flags & SI_IS_MCAST ? " mcast" : "",
si->flags & SI_IS_MHOMED? " mhomed" : "");
si->flags & SI_IS_MCAST ? " mcast" : "",
si->flags & SI_IS_MHOMED ? " mhomed" : "",
si->flags & SI_IS_VIRTUAL? " virtual" : "");
if (si->sockname.s) {
printf(" name %s", si->sockname.s);
}
Expand Down

0 comments on commit e93640e

Please sign in to comment.