From 3a3d7fcc13ab20b18e55c1119caec66120429ad9 Mon Sep 17 00:00:00 2001 From: Steve Karg Date: Tue, 12 Aug 2025 08:50:30 -0500 Subject: [PATCH] Fix point-to-point VPN tunnel sockets for BACnet/IP by using IFF_POINTTOPOINT flag when getting the broadcast address. (#1066) --- ports/bsd/bip-init.c | 114 +++++++++++++++++++++++++++---------------- 1 file changed, 72 insertions(+), 42 deletions(-) diff --git a/ports/bsd/bip-init.c b/ports/bsd/bip-init.c index 181c1684..9a3a5661 100644 --- a/ports/bsd/bip-init.c +++ b/ports/bsd/bip-init.c @@ -32,6 +32,8 @@ static struct in_addr BIP_Broadcast_Addr; /* broadcast binding mechanism */ static bool BIP_Broadcast_Binding_Address_Override; 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 */ static bool BIP_Debug = false; /* 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) { void *addr_ptr = NULL; - if (sockaddr_ptr->sa_family == AF_INET) { - 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; + + if (sockaddr_ptr) { + if (sockaddr_ptr->sa_family == AF_INET) { + 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; } @@ -492,7 +498,9 @@ int bip_get_local_address_ioctl( char rv = '\0'; /* return value */ struct ifaddrs *ifaddrs_ptr; + void *addr_ptr = NULL; int status; + status = getifaddrs(&ifaddrs_ptr); if (status == -1) { fprintf( @@ -500,17 +508,25 @@ int bip_get_local_address_ioctl( } while (ifaddrs_ptr) { if ((ifaddrs_ptr->ifa_addr->sa_family == AF_INET) && - (strcmp(ifaddrs_ptr->ifa_name, ifname) == 0)) { - void *addr_ptr = NULL; - if (!ifaddrs_ptr->ifa_addr) { - return rv; - } + (ifname && strcmp(ifaddrs_ptr->ifa_name, ifname) == 0)) { switch (request) { case SIOCGIFADDR: addr_ptr = get_addr_ptr(ifaddrs_ptr->ifa_addr); break; 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; case SIOCGIFNETMASK: 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; } freeifaddrs(ifaddrs_ptr); + return rv; } @@ -571,6 +588,9 @@ void bip_set_interface(const char *ifname) struct in_addr broadcast_address; int rv = 0; + local_address.s_addr = 0; + broadcast_address.s_addr = 0; + BIP_Point_To_Point = false; /* setup local address */ rv = bip_get_local_address_ioctl(ifname, &local_address, SIOCGIFADDR); if (rv < 0) { @@ -611,8 +631,11 @@ void bip_set_interface(const char *ifname) if (rv < 0) { BIP_Broadcast_Addr.s_addr = ~0; } else { - BIP_Broadcast_Addr = local_address; - BIP_Broadcast_Addr.s_addr = broadcast_address.s_addr; + if (BIP_Point_To_Point) { + BIP_Broadcast_Addr.s_addr = local_address.s_addr; + } else { + BIP_Broadcast_Addr.s_addr = broadcast_address.s_addr; + } } #endif 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) { int status = 0; /* return from socket lib calls */ @@ -710,49 +738,51 @@ bool bip_init(char *ifname) fflush(stderr); return false; } - sin.sin_family = AF_INET; sin.sin_port = BIP_Port; memset(&(sin.sin_zero), '\0', sizeof(sin.sin_zero)); - sin.sin_addr.s_addr = BIP_Address.s_addr; sock_fd = createSocket(&sin); BIP_Socket = sock_fd; if (sock_fd < 0) { return false; } - - broadcast_sin_config.sin_family = AF_INET; - broadcast_sin_config.sin_port = BIP_Port; - 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 */ + if (BIP_Point_To_Point) { + /* point-to-point interface flag + uses the unicast socket for broadcast */ 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; + broadcast_sin_config.sin_family = AF_INET; + broadcast_sin_config.sin_port = BIP_Port; + 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; + } 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(); return true;