fix BACnet/IP on OS to bind broadcast to specific port (#489)
* Fixes #346 by binding the broadcast socket to the port specific broadcast address rather than INADDR_ANY or INADDR_BROADCAST. Added additional compile and environment options for those who might need them. * Changed the define USE_CLASSADDR to BACNET_IP_BROADCAST_USE_CLASSADDR to help manage namespaces. * Added BACNET_IP_BROADCAST_BIND_ADDR environment variable to override the default broadcast binding address. --------- Co-authored-by: Steve Karg <skarg@users.sourceforge.net>
This commit is contained in:
+62
-8
@@ -73,6 +73,9 @@ static uint16_t BIP_Port;
|
||||
static struct in_addr BIP_Address;
|
||||
/* IP broadcast address - stored here in network byte order */
|
||||
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;
|
||||
/* enable debugging */
|
||||
static bool BIP_Debug = false;
|
||||
/* interface name */
|
||||
@@ -409,9 +412,11 @@ uint16_t bip_receive(
|
||||
debug_print_ipv4(
|
||||
"Received MPDU->", &sin.sin_addr, sin.sin_port, received_bytes);
|
||||
/* pass the packet into the BBMD handler */
|
||||
offset = socket == BIP_Socket ?
|
||||
bvlc_handler(&addr, src, npdu, received_bytes) :
|
||||
bvlc_broadcast_handler(&addr, src, npdu, received_bytes);
|
||||
if (socket == BIP_Socket) {
|
||||
offset = bvlc_handler(&addr, src, npdu, received_bytes);
|
||||
} else {
|
||||
offset = bvlc_broadcast_handler(&addr, src, npdu, received_bytes);
|
||||
}
|
||||
if (offset > 0) {
|
||||
npdu_len = received_bytes - offset;
|
||||
debug_print_ipv4(
|
||||
@@ -749,6 +754,20 @@ int bip_get_local_netmask(struct in_addr *netmask)
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the broadcast socket binding address
|
||||
* @param baddr The broadcast socket binding address, in host order.
|
||||
* @return 0 on success
|
||||
*/
|
||||
int bip_set_broadcast_binding(
|
||||
const char *ip4_broadcast)
|
||||
{
|
||||
BIP_Broadcast_Binding_Address.s_addr = inet_addr(ip4_broadcast);
|
||||
BIP_Broadcast_Binding_Address_Override = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Gets the local IP address and local broadcast address from the system,
|
||||
* and saves it into the BACnet/IP data structures.
|
||||
*
|
||||
@@ -773,6 +792,29 @@ void bip_set_interface(char *ifname)
|
||||
fflush(stderr);
|
||||
}
|
||||
/* setup local broadcast address */
|
||||
#ifdef BACNET_IP_BROADCAST_USE_CLASSADDR
|
||||
long broadcast_address;
|
||||
long net_address;
|
||||
|
||||
broadcast_address = 0;
|
||||
net_address = local_address.s_addr;
|
||||
if (IN_CLASSA(ntohl(net_address))) {
|
||||
broadcast_address =
|
||||
(ntohl(net_address) & ~IN_CLASSA_HOST) | IN_CLASSA_HOST;
|
||||
} else if (IN_CLASSB(ntohl(net_address))) {
|
||||
broadcast_address =
|
||||
(ntohl(net_address) & ~IN_CLASSB_HOST) | IN_CLASSB_HOST;
|
||||
} else if (IN_CLASSC(ntohl(net_address))) {
|
||||
broadcast_address =
|
||||
(ntohl(net_address) & ~IN_CLASSC_HOST) | IN_CLASSC_HOST;
|
||||
} else if (IN_CLASSD(ntohl(net_address))) {
|
||||
broadcast_address =
|
||||
(ntohl(net_address) & ~IN_CLASSD_HOST) | IN_CLASSD_HOST;
|
||||
} else {
|
||||
broadcast_address = INADDR_BROADCAST;
|
||||
}
|
||||
BIP_Broadcast_Addr.s_addr = htonl(broadcast_address);
|
||||
#else
|
||||
rv = bip_get_local_address_ioctl(ifname, &netmask, SIOCGIFNETMASK);
|
||||
if (rv < 0) {
|
||||
BIP_Broadcast_Addr.s_addr = ~0;
|
||||
@@ -780,6 +822,7 @@ void bip_set_interface(char *ifname)
|
||||
BIP_Broadcast_Addr = local_address;
|
||||
BIP_Broadcast_Addr.s_addr |= (~netmask.s_addr);
|
||||
}
|
||||
#endif
|
||||
if (BIP_Debug) {
|
||||
fprintf(stderr, "BIP: Broadcast Address: %s\n",
|
||||
inet_ntoa(BIP_Broadcast_Addr));
|
||||
@@ -817,9 +860,11 @@ static int createSocket(struct sockaddr_in *sin)
|
||||
return status;
|
||||
}
|
||||
/* Bind to the proper interface to send without default gateway */
|
||||
setsockopt(sock_fd, SOL_SOCKET, SO_BINDTODEVICE, BIP_Interface_Name,
|
||||
strlen(BIP_Interface_Name));
|
||||
|
||||
status = setsockopt(sock_fd, SOL_SOCKET, SO_BINDTODEVICE,
|
||||
BIP_Interface_Name, strlen(BIP_Interface_Name));
|
||||
if (status < 0) {
|
||||
perror("SO_BINDTODEVICE: ");
|
||||
}
|
||||
/* bind the socket to the local port number and IP address */
|
||||
status =
|
||||
bind(sock_fd, (const struct sockaddr *)sin, sizeof(struct sockaddr));
|
||||
@@ -876,8 +921,17 @@ bool bip_init(char *ifname)
|
||||
if (sock_fd < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
sin.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
if (BIP_Broadcast_Binding_Address_Override) {
|
||||
sin.sin_addr.s_addr = BIP_Broadcast_Binding_Address.s_addr;
|
||||
} else {
|
||||
#if defined(BACNET_IP_BROADCAST_USE_INADDR_ANY)
|
||||
sin.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
#elif defined(BACNET_IP_BROADCAST_USE_INADDR_BROADCAST)
|
||||
sin.sin_addr.s_addr = htonl(INADDR_BROADCAST);
|
||||
#else
|
||||
sin.sin_addr.s_addr = BIP_Broadcast_Addr.s_addr;
|
||||
#endif
|
||||
}
|
||||
sock_fd = createSocket(&sin);
|
||||
BIP_Broadcast_Socket = sock_fd;
|
||||
if (sock_fd < 0) {
|
||||
|
||||
Reference in New Issue
Block a user