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.
... | ... |
@@ -305,6 +305,7 @@ XAVPVIAPARAMS xavp_via_params |
305 | 305 |
XAVPVIAFIELDS xavp_via_fields |
306 | 306 |
LISTEN listen |
307 | 307 |
ADVERTISE advertise|ADVERTISE |
308 |
+VIRTUAL virtual |
|
308 | 309 |
STRNAME name|NAME |
309 | 310 |
ALIAS alias |
310 | 311 |
SR_AUTO_ALIASES auto_aliases |
... | ... |
@@ -741,6 +742,7 @@ IMPORTFILE "import_file" |
741 | 742 |
<INITIAL>{XAVPVIAFIELDS} { yylval.strval=yytext; return XAVPVIAFIELDS; } |
742 | 743 |
<INITIAL>{LISTEN} { count(); yylval.strval=yytext; return LISTEN; } |
743 | 744 |
<INITIAL>{ADVERTISE} { count(); yylval.strval=yytext; return ADVERTISE; } |
745 |
+<INITIAL>{VIRTUAL} { count(); yylval.strval=yytext; return VIRTUAL; } |
|
744 | 746 |
<INITIAL>{STRNAME} { count(); yylval.strval=yytext; return STRNAME; } |
745 | 747 |
<INITIAL>{ALIAS} { count(); yylval.strval=yytext; return ALIAS; } |
746 | 748 |
<INITIAL>{SR_AUTO_ALIASES} { count(); yylval.strval=yytext; |
... | ... |
@@ -328,6 +328,7 @@ extern char *default_routename; |
328 | 328 |
%token XAVPVIAFIELDS |
329 | 329 |
%token LISTEN |
330 | 330 |
%token ADVERTISE |
331 |
+%token VIRTUAL |
|
331 | 332 |
%token STRNAME |
332 | 333 |
%token ALIAS |
333 | 334 |
%token SR_AUTO_ALIASES |
... | ... |
@@ -1503,6 +1504,19 @@ assign_stm: |
1503 | 1504 |
} |
1504 | 1505 |
free_socket_id_lst($3); |
1505 | 1506 |
} |
1507 |
+ | LISTEN EQUAL id_lst VIRTUAL { |
|
1508 |
+ for(lst_tmp=$3; lst_tmp; lst_tmp=lst_tmp->next) { |
|
1509 |
+ lst_tmp->flags |= SI_IS_VIRTUAL; |
|
1510 |
+ if (add_listen_iface( lst_tmp->addr_lst->name, |
|
1511 |
+ lst_tmp->addr_lst->next, |
|
1512 |
+ lst_tmp->port, lst_tmp->proto, |
|
1513 |
+ lst_tmp->flags)!=0) { |
|
1514 |
+ LM_CRIT("cfg. parser: failed to add listen address\n"); |
|
1515 |
+ break; |
|
1516 |
+ } |
|
1517 |
+ } |
|
1518 |
+ free_socket_id_lst($3); |
|
1519 |
+ } |
|
1506 | 1520 |
| LISTEN EQUAL id_lst STRNAME STRING { |
1507 | 1521 |
for(lst_tmp=$3; lst_tmp; lst_tmp=lst_tmp->next) { |
1508 | 1522 |
if (add_listen_iface_name(lst_tmp->addr_lst->name, |
... | ... |
@@ -1515,6 +1529,19 @@ assign_stm: |
1515 | 1529 |
} |
1516 | 1530 |
free_socket_id_lst($3); |
1517 | 1531 |
} |
1532 |
+ | LISTEN EQUAL id_lst STRNAME STRING VIRTUAL { |
|
1533 |
+ for(lst_tmp=$3; lst_tmp; lst_tmp=lst_tmp->next) { |
|
1534 |
+ lst_tmp->flags |= SI_IS_VIRTUAL; |
|
1535 |
+ if (add_listen_iface_name(lst_tmp->addr_lst->name, |
|
1536 |
+ lst_tmp->addr_lst->next, |
|
1537 |
+ lst_tmp->port, lst_tmp->proto, $5, |
|
1538 |
+ lst_tmp->flags)!=0) { |
|
1539 |
+ LM_CRIT("cfg. parser: failed to add listen address\n"); |
|
1540 |
+ break; |
|
1541 |
+ } |
|
1542 |
+ } |
|
1543 |
+ free_socket_id_lst($3); |
|
1544 |
+ } |
|
1518 | 1545 |
| LISTEN EQUAL id_lst ADVERTISE listen_id COLON NUMBER { |
1519 | 1546 |
for(lst_tmp=$3; lst_tmp; lst_tmp=lst_tmp->next) { |
1520 | 1547 |
if (add_listen_advertise_iface( lst_tmp->addr_lst->name, |
... | ... |
@@ -1528,6 +1555,20 @@ assign_stm: |
1528 | 1555 |
} |
1529 | 1556 |
free_socket_id_lst($3); |
1530 | 1557 |
} |
1558 |
+ | LISTEN EQUAL id_lst ADVERTISE listen_id COLON NUMBER VIRTUAL { |
|
1559 |
+ for(lst_tmp=$3; lst_tmp; lst_tmp=lst_tmp->next) { |
|
1560 |
+ lst_tmp->flags |= SI_IS_VIRTUAL; |
|
1561 |
+ if (add_listen_advertise_iface( lst_tmp->addr_lst->name, |
|
1562 |
+ lst_tmp->addr_lst->next, |
|
1563 |
+ lst_tmp->port, lst_tmp->proto, |
|
1564 |
+ $5, $7, |
|
1565 |
+ lst_tmp->flags)!=0) { |
|
1566 |
+ LM_CRIT("cfg. parser: failed to add listen address\n"); |
|
1567 |
+ break; |
|
1568 |
+ } |
|
1569 |
+ } |
|
1570 |
+ free_socket_id_lst($3); |
|
1571 |
+ } |
|
1531 | 1572 |
| LISTEN EQUAL id_lst ADVERTISE listen_id COLON NUMBER STRNAME STRING { |
1532 | 1573 |
for(lst_tmp=$3; lst_tmp; lst_tmp=lst_tmp->next) { |
1533 | 1574 |
if (add_listen_advertise_iface_name(lst_tmp->addr_lst->name, |
... | ... |
@@ -1541,6 +1582,20 @@ assign_stm: |
1541 | 1582 |
} |
1542 | 1583 |
free_socket_id_lst($3); |
1543 | 1584 |
} |
1585 |
+ | LISTEN EQUAL id_lst ADVERTISE listen_id COLON NUMBER STRNAME STRING VIRTUAL { |
|
1586 |
+ for(lst_tmp=$3; lst_tmp; lst_tmp=lst_tmp->next) { |
|
1587 |
+ lst_tmp->flags |= SI_IS_VIRTUAL; |
|
1588 |
+ if (add_listen_advertise_iface_name(lst_tmp->addr_lst->name, |
|
1589 |
+ lst_tmp->addr_lst->next, |
|
1590 |
+ lst_tmp->port, lst_tmp->proto, |
|
1591 |
+ $5, $7, $9, |
|
1592 |
+ lst_tmp->flags)!=0) { |
|
1593 |
+ LM_CRIT("cfg. parser: failed to add listen address\n"); |
|
1594 |
+ break; |
|
1595 |
+ } |
|
1596 |
+ } |
|
1597 |
+ free_socket_id_lst($3); |
|
1598 |
+ } |
|
1544 | 1599 |
| LISTEN EQUAL id_lst ADVERTISE listen_id { |
1545 | 1600 |
for(lst_tmp=$3; lst_tmp; lst_tmp=lst_tmp->next) { |
1546 | 1601 |
if (add_listen_advertise_iface( lst_tmp->addr_lst->name, |
... | ... |
@@ -1554,6 +1609,20 @@ assign_stm: |
1554 | 1609 |
} |
1555 | 1610 |
free_socket_id_lst($3); |
1556 | 1611 |
} |
1612 |
+ | LISTEN EQUAL id_lst ADVERTISE listen_id VIRTUAL { |
|
1613 |
+ for(lst_tmp=$3; lst_tmp; lst_tmp=lst_tmp->next) { |
|
1614 |
+ lst_tmp->flags |= SI_IS_VIRTUAL; |
|
1615 |
+ if (add_listen_advertise_iface( lst_tmp->addr_lst->name, |
|
1616 |
+ lst_tmp->addr_lst->next, |
|
1617 |
+ lst_tmp->port, lst_tmp->proto, |
|
1618 |
+ $5, 0, |
|
1619 |
+ lst_tmp->flags)!=0) { |
|
1620 |
+ LM_CRIT("cfg. parser: failed to add listen address\n"); |
|
1621 |
+ break; |
|
1622 |
+ } |
|
1623 |
+ } |
|
1624 |
+ free_socket_id_lst($3); |
|
1625 |
+ } |
|
1557 | 1626 |
| LISTEN EQUAL id_lst ADVERTISE listen_id STRNAME STRING { |
1558 | 1627 |
for(lst_tmp=$3; lst_tmp; lst_tmp=lst_tmp->next) { |
1559 | 1628 |
if (add_listen_advertise_iface_name(lst_tmp->addr_lst->name, |
... | ... |
@@ -1567,6 +1636,20 @@ assign_stm: |
1567 | 1636 |
} |
1568 | 1637 |
free_socket_id_lst($3); |
1569 | 1638 |
} |
1639 |
+ | LISTEN EQUAL id_lst ADVERTISE listen_id STRNAME STRING VIRTUAL { |
|
1640 |
+ for(lst_tmp=$3; lst_tmp; lst_tmp=lst_tmp->next) { |
|
1641 |
+ lst_tmp->flags |= SI_IS_VIRTUAL; |
|
1642 |
+ if (add_listen_advertise_iface_name(lst_tmp->addr_lst->name, |
|
1643 |
+ lst_tmp->addr_lst->next, |
|
1644 |
+ lst_tmp->port, lst_tmp->proto, |
|
1645 |
+ $5, 0, $7, |
|
1646 |
+ lst_tmp->flags)!=0) { |
|
1647 |
+ LM_CRIT("cfg. parser: failed to add listen address\n"); |
|
1648 |
+ break; |
|
1649 |
+ } |
|
1650 |
+ } |
|
1651 |
+ free_socket_id_lst($3); |
|
1652 |
+ } |
|
1570 | 1653 |
| LISTEN EQUAL error { yyerror("ip address, interface name or" |
1571 | 1654 |
" hostname expected"); } |
1572 | 1655 |
| ALIAS EQUAL id_lst { |
... | ... |
@@ -562,6 +562,66 @@ struct socket_info** get_sock_info_list(unsigned short proto) |
562 | 562 |
return 0; |
563 | 563 |
} |
564 | 564 |
|
565 |
+/* Check list of active local IPs for grep_sock_info |
|
566 |
+ * This function is only used for sockets with the SI_IS_VIRTUAL flag set. This |
|
567 |
+ * is so floating (virtual) IPs that are not currently local, are not returned |
|
568 |
+ * as matches by grep_sock_info. |
|
569 |
+ * |
|
570 |
+ * Params: |
|
571 |
+ * - si - Socket info of socket that has been flagged with SI_IS_VIRTUAL, |
|
572 |
+ * that we want to check if it's actually local right now. |
|
573 |
+ * |
|
574 |
+ * Returns 1 if socket is local, or 0 if not. |
|
575 |
+ */ |
|
576 |
+static int check_local_addresses(struct socket_info* si) |
|
577 |
+{ |
|
578 |
+ struct hostent* he; |
|
579 |
+ struct utsname myname; |
|
580 |
+ |
|
581 |
+ if (si == NULL) { |
|
582 |
+ LM_ERR("Socket info is NULL. Returning no match.\n"); |
|
583 |
+ return 0; |
|
584 |
+ } |
|
585 |
+ |
|
586 |
+ if (!(si->flags & SI_IS_VIRTUAL)) { |
|
587 |
+ LM_ERR("Have been passed a socket without the virtual flag set. This should " |
|
588 |
+ "not happen. Returning a match to maintain standard behaviour.\n"); |
|
589 |
+ return 1; |
|
590 |
+ } |
|
591 |
+ |
|
592 |
+ if (uname(&myname) <0){ |
|
593 |
+ LM_ERR("Cannot determine hostname. Guessing a not local virtual IP.\n"); |
|
594 |
+ return 0; |
|
595 |
+ } |
|
596 |
+ |
|
597 |
+ //Should return a list of local IPs |
|
598 |
+ he = _resolvehost(myname.nodename); |
|
599 |
+ if (he == NULL) { |
|
600 |
+ LM_ERR("Cannot get list of local IPs. Guessing not a local virtual IP.\n"); |
|
601 |
+ return 0; |
|
602 |
+ } |
|
603 |
+ char** paddrlist = he->h_addr_list; |
|
604 |
+ int i = 0; |
|
605 |
+ while (*paddrlist != NULL) |
|
606 |
+ { |
|
607 |
+ struct ip_addr local_addr; |
|
608 |
+ hostent2ip_addr(&local_addr, he, i); |
|
609 |
+ |
|
610 |
+ LM_DBG("Checking local address: %s\n", ip_addr2a(&local_addr)); |
|
611 |
+ if (ip_addr_cmp(&si->address, &local_addr)) { |
|
612 |
+ LM_DBG("Found matching local IP for virtual socket: %s\n", ip_addr2a(&local_addr)); |
|
613 |
+ return 1; |
|
614 |
+ } |
|
615 |
+ |
|
616 |
+ i++; |
|
617 |
+ paddrlist++; |
|
618 |
+ } |
|
619 |
+ |
|
620 |
+ //Default to not local if no match is found |
|
621 |
+ LM_DBG("No matching local IP found.\n"); |
|
622 |
+ return 0; |
|
623 |
+} |
|
624 |
+ |
|
565 | 625 |
|
566 | 626 |
/* helper function for grep_sock_info |
567 | 627 |
* params: |
... | ... |
@@ -653,7 +713,16 @@ retry: |
653 | 713 |
} |
654 | 714 |
if (si_hname_cmp(&hname, &si->name, &si->address_str, |
655 | 715 |
&si->address, si->flags)==0) { |
656 |
- goto found; |
|
716 |
+ if (si->flags & SI_IS_VIRTUAL) { |
|
717 |
+ LM_DBG("Checking virtual socket: [%.*s]\n", si->name.len, si->name.s); |
|
718 |
+ if (check_local_addresses(si)) { |
|
719 |
+ goto found; |
|
720 |
+ } else { |
|
721 |
+ LM_DBG("Skipping virtual socket that is not local.\n"); |
|
722 |
+ } |
|
723 |
+ } else { |
|
724 |
+ goto found; |
|
725 |
+ } |
|
657 | 726 |
} |
658 | 727 |
if(si->useinfo.name.s!=NULL) { |
659 | 728 |
LM_DBG("checking advertise if host==us:" |
... | ... |
@@ -2071,10 +2140,11 @@ void print_all_socket_lists() |
2071 | 2140 |
for (ai=si->addr_info_lst; ai; ai=ai->next) { |
2072 | 2141 |
printf(", %s", ai->address_str.s); |
2073 | 2142 |
} |
2074 |
- printf("):%s%s%s\n", |
|
2143 |
+ printf("):%s%s%s%s\n", |
|
2075 | 2144 |
si->port_no_str.s, |
2076 |
- si->flags & SI_IS_MCAST ? " mcast" : "", |
|
2077 |
- si->flags & SI_IS_MHOMED? " mhomed" : ""); |
|
2145 |
+ si->flags & SI_IS_MCAST ? " mcast" : "", |
|
2146 |
+ si->flags & SI_IS_MHOMED ? " mhomed" : "", |
|
2147 |
+ si->flags & SI_IS_VIRTUAL? " virtual" : ""); |
|
2078 | 2148 |
}else{ |
2079 | 2149 |
printf(" %s: %s", |
2080 | 2150 |
get_valid_proto_name(proto), |
... | ... |
@@ -2082,10 +2152,11 @@ void print_all_socket_lists() |
2082 | 2152 |
if (!(si->flags & SI_IS_IP)) { |
2083 | 2153 |
printf(" [%s]", si->address_str.s); |
2084 | 2154 |
} |
2085 |
- printf( ":%s%s%s", |
|
2155 |
+ printf( ":%s%s%s%s", |
|
2086 | 2156 |
si->port_no_str.s, |
2087 |
- si->flags & SI_IS_MCAST ? " mcast" : "", |
|
2088 |
- si->flags & SI_IS_MHOMED? " mhomed" : ""); |
|
2157 |
+ si->flags & SI_IS_MCAST ? " mcast" : "", |
|
2158 |
+ si->flags & SI_IS_MHOMED ? " mhomed" : "", |
|
2159 |
+ si->flags & SI_IS_VIRTUAL? " virtual" : ""); |
|
2089 | 2160 |
if (si->sockname.s) { |
2090 | 2161 |
printf(" name %s", si->sockname.s); |
2091 | 2162 |
} |