Fix point-to-point VPN tunnel sockets for BACnet/IP by using IFF_POINTTOPOINT flag when getting the broadcast address. (#1066)

This commit is contained in:
Steve Karg
2025-08-12 08:50:30 -05:00
committed by GitHub
parent 6b6dfab10e
commit 3a3d7fcc13
+72 -42
View File
@@ -32,6 +32,8 @@ static struct in_addr BIP_Broadcast_Addr;
/* broadcast binding mechanism */ /* broadcast binding mechanism */
static bool BIP_Broadcast_Binding_Address_Override; static bool BIP_Broadcast_Binding_Address_Override;
static struct in_addr BIP_Broadcast_Binding_Address; static struct in_addr BIP_Broadcast_Binding_Address;
/* point-to-point interface flag - uses the unicast socket for broadcast */
static bool BIP_Point_To_Point = false;
/* enable debugging */ /* enable debugging */
static bool BIP_Debug = false; static bool BIP_Debug = false;
/* interface name */ /* interface name */
@@ -449,11 +451,15 @@ bool bip_get_addr_by_name(const char *host_name, BACNET_IP_ADDRESS *addr)
static void *get_addr_ptr(struct sockaddr *sockaddr_ptr) static void *get_addr_ptr(struct sockaddr *sockaddr_ptr)
{ {
void *addr_ptr = NULL; void *addr_ptr = NULL;
if (sockaddr_ptr->sa_family == AF_INET) {
addr_ptr = &((struct sockaddr_in *)sockaddr_ptr)->sin_addr; if (sockaddr_ptr) {
} else if (sockaddr_ptr->sa_family == AF_INET6) { if (sockaddr_ptr->sa_family == AF_INET) {
addr_ptr = &((struct sockaddr_in6 *)sockaddr_ptr)->sin6_addr; addr_ptr = &((struct sockaddr_in *)sockaddr_ptr)->sin_addr;
} else if (sockaddr_ptr->sa_family == AF_INET6) {
addr_ptr = &((struct sockaddr_in6 *)sockaddr_ptr)->sin6_addr;
}
} }
return addr_ptr; return addr_ptr;
} }
@@ -492,7 +498,9 @@ int bip_get_local_address_ioctl(
char rv = '\0'; /* return value */ char rv = '\0'; /* return value */
struct ifaddrs *ifaddrs_ptr; struct ifaddrs *ifaddrs_ptr;
void *addr_ptr = NULL;
int status; int status;
status = getifaddrs(&ifaddrs_ptr); status = getifaddrs(&ifaddrs_ptr);
if (status == -1) { if (status == -1) {
fprintf( fprintf(
@@ -500,17 +508,25 @@ int bip_get_local_address_ioctl(
} }
while (ifaddrs_ptr) { while (ifaddrs_ptr) {
if ((ifaddrs_ptr->ifa_addr->sa_family == AF_INET) && if ((ifaddrs_ptr->ifa_addr->sa_family == AF_INET) &&
(strcmp(ifaddrs_ptr->ifa_name, ifname) == 0)) { (ifname && strcmp(ifaddrs_ptr->ifa_name, ifname) == 0)) {
void *addr_ptr = NULL;
if (!ifaddrs_ptr->ifa_addr) {
return rv;
}
switch (request) { switch (request) {
case SIOCGIFADDR: case SIOCGIFADDR:
addr_ptr = get_addr_ptr(ifaddrs_ptr->ifa_addr); addr_ptr = get_addr_ptr(ifaddrs_ptr->ifa_addr);
break; break;
case SIOCGIFBRDADDR: case SIOCGIFBRDADDR:
addr_ptr = get_addr_ptr(ifaddrs_ptr->ifa_broadaddr); /* Depending on whether the bit
IFF_BROADCAST or IFF_POINTOPOINT is set
in ifa_flags (only one can be set at a time),
either ifa_broadaddr will contain the broadcast
address associated with ifa_addr or ifa_dstaddr
will contain the destination address of the
point-to-point interface.*/
if (ifaddrs_ptr->ifa_flags & IFF_POINTOPOINT) {
BIP_Point_To_Point = true;
addr_ptr = get_addr_ptr(ifaddrs_ptr->ifa_dstaddr);
} else {
addr_ptr = get_addr_ptr(ifaddrs_ptr->ifa_broadaddr);
}
break; break;
case SIOCGIFNETMASK: case SIOCGIFNETMASK:
addr_ptr = get_addr_ptr(ifaddrs_ptr->ifa_netmask); addr_ptr = get_addr_ptr(ifaddrs_ptr->ifa_netmask);
@@ -525,6 +541,7 @@ int bip_get_local_address_ioctl(
ifaddrs_ptr = ifaddrs_ptr->ifa_next; ifaddrs_ptr = ifaddrs_ptr->ifa_next;
} }
freeifaddrs(ifaddrs_ptr); freeifaddrs(ifaddrs_ptr);
return rv; return rv;
} }
@@ -571,6 +588,9 @@ void bip_set_interface(const char *ifname)
struct in_addr broadcast_address; struct in_addr broadcast_address;
int rv = 0; int rv = 0;
local_address.s_addr = 0;
broadcast_address.s_addr = 0;
BIP_Point_To_Point = false;
/* setup local address */ /* setup local address */
rv = bip_get_local_address_ioctl(ifname, &local_address, SIOCGIFADDR); rv = bip_get_local_address_ioctl(ifname, &local_address, SIOCGIFADDR);
if (rv < 0) { if (rv < 0) {
@@ -611,8 +631,11 @@ void bip_set_interface(const char *ifname)
if (rv < 0) { if (rv < 0) {
BIP_Broadcast_Addr.s_addr = ~0; BIP_Broadcast_Addr.s_addr = ~0;
} else { } else {
BIP_Broadcast_Addr = local_address; if (BIP_Point_To_Point) {
BIP_Broadcast_Addr.s_addr = broadcast_address.s_addr; BIP_Broadcast_Addr.s_addr = local_address.s_addr;
} else {
BIP_Broadcast_Addr.s_addr = broadcast_address.s_addr;
}
} }
#endif #endif
if (BIP_Debug) { if (BIP_Debug) {
@@ -626,6 +649,11 @@ void bip_set_interface(const char *ifname)
} }
} }
const char *bip_get_interface(void)
{
return BIP_Interface_Name;
}
static int createSocket(const struct sockaddr_in *sin) static int createSocket(const struct sockaddr_in *sin)
{ {
int status = 0; /* return from socket lib calls */ int status = 0; /* return from socket lib calls */
@@ -710,49 +738,51 @@ bool bip_init(char *ifname)
fflush(stderr); fflush(stderr);
return false; return false;
} }
sin.sin_family = AF_INET; sin.sin_family = AF_INET;
sin.sin_port = BIP_Port; sin.sin_port = BIP_Port;
memset(&(sin.sin_zero), '\0', sizeof(sin.sin_zero)); memset(&(sin.sin_zero), '\0', sizeof(sin.sin_zero));
sin.sin_addr.s_addr = BIP_Address.s_addr; sin.sin_addr.s_addr = BIP_Address.s_addr;
sock_fd = createSocket(&sin); sock_fd = createSocket(&sin);
BIP_Socket = sock_fd; BIP_Socket = sock_fd;
if (sock_fd < 0) { if (sock_fd < 0) {
return false; return false;
} }
if (BIP_Point_To_Point) {
broadcast_sin_config.sin_family = AF_INET; /* point-to-point interface flag
broadcast_sin_config.sin_port = BIP_Port; uses the unicast socket for broadcast */
memset(
&(broadcast_sin_config.sin_zero), '\0',
sizeof(broadcast_sin_config.sin_zero));
if (BIP_Broadcast_Binding_Address_Override) {
broadcast_sin_config.sin_addr.s_addr =
BIP_Broadcast_Binding_Address.s_addr;
} else {
#if defined(BACNET_IP_BROADCAST_USE_INADDR_ANY)
broadcast_sin_config.sin_addr.s_addr = htonl(INADDR_ANY);
#elif defined(BACNET_IP_BROADCAST_USE_INADDR_BROADCAST)
broadcast_sin_config.sin_addr.s_addr = htonl(INADDR_BROADCAST);
#else
broadcast_sin_config.sin_addr.s_addr = BIP_Broadcast_Addr.s_addr;
#endif
}
if (broadcast_sin_config.sin_addr.s_addr == BIP_Address.s_addr) {
/* handle the case when a network interface on the system
reports the interface's unicast IP address as being
the same as its broadcast IP address */
BIP_Broadcast_Socket = BIP_Socket; BIP_Broadcast_Socket = BIP_Socket;
} else { } else {
broadcast_sock_fd = createSocket(&broadcast_sin_config); broadcast_sin_config.sin_family = AF_INET;
BIP_Broadcast_Socket = broadcast_sock_fd; broadcast_sin_config.sin_port = BIP_Port;
if (broadcast_sock_fd < 0) { memset(
bip_cleanup(); &(broadcast_sin_config.sin_zero), '\0',
return false; sizeof(broadcast_sin_config.sin_zero));
if (BIP_Broadcast_Binding_Address_Override) {
broadcast_sin_config.sin_addr.s_addr =
BIP_Broadcast_Binding_Address.s_addr;
} else {
#if defined(BACNET_IP_BROADCAST_USE_INADDR_ANY)
broadcast_sin_config.sin_addr.s_addr = htonl(INADDR_ANY);
#elif defined(BACNET_IP_BROADCAST_USE_INADDR_BROADCAST)
broadcast_sin_config.sin_addr.s_addr = htonl(INADDR_BROADCAST);
#else
broadcast_sin_config.sin_addr.s_addr = BIP_Broadcast_Addr.s_addr;
#endif
}
if (broadcast_sin_config.sin_addr.s_addr == BIP_Address.s_addr) {
/* handle the case when a network interface on the system
reports the interface's unicast IP address as being
the same as its broadcast IP address */
BIP_Broadcast_Socket = BIP_Socket;
} else {
broadcast_sock_fd = createSocket(&broadcast_sin_config);
BIP_Broadcast_Socket = broadcast_sock_fd;
if (broadcast_sock_fd < 0) {
bip_cleanup();
return false;
}
} }
} }
bvlc_init(); bvlc_init();
return true; return true;