I'm trying an experiment with keepalived and the VRRP protocol. I have keepalived running on computer A, and from computer B I want to read the multicast VRRP messages to find the the Virtual IP address that computer A is advertising. The computers are connected to the same network switch. Similar questions here on SO are answered by "call setsocketopt with IP_ADD_MEMBERSHIP", that is not the problem here.
My code for reading on a multicast socket is not working for the VRRP multicast IP and port (224.0.0.18:112). Note, it works if I try to read mDNS (224.0.0.251:5353), but for VRRP doesn't ever receive any data, it just hangs in recvfrom
.
I have confirmed with tcpdump (sudo tcpdump -i enp39s0 net 224.0.0.18
) that computer B is actually receiving the messages.
I realize 112 is in the privileged port range, so I run the app with sudo. It seems that if sudo tcpdump -i enp39s0 net 224.0.0.18
can see the messages, this code should be able to receive the messages as well.
When running my app I can see that the port is open and the multicast group has been joined:
$ netstat -lu | grep 112; netstat -g | grep vrrp
udp 0 0 0.0.0.0:112 0.0.0.0:*
enp39s0 2 vrrp.mcast
What am I missing?
Code for receiving multicast messages (error handling removed for simplicity). This code is obviously for Linux, but I've also tried the equivalent on Windows with the same result.
#include <cstring>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#define VRRP_MULTICAST_ADDR "224.0.0.18" // VRRP multicast address
#define VRRP_PORT 112 // VRRP default port
//#define VRRP_MULTICAST_ADDR "224.0.0.251"
//#define VRRP_PORT 5353
int main()
{
sockaddr_in addr;
ip_mreq mreq;
char buffer[256];
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
unsigned int opt_on = 1;
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char*) &opt_on, sizeof(opt_on));
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(VRRP_PORT);
bind(sockfd, (sockaddr *)&addr, sizeof(addr));
mreq.imr_multiaddr.s_addr = inet_addr(VRRP_MULTICAST_ADDR);
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
ssize_t nbytes = recvfrom(sockfd, buffer, sizeof(buffer), 0, NULL, NULL);
printf("Received %ld bytes\n", nbytes);
// HexDump(buffer, nbytes); // HexDump from
close(sockfd);
return 0;
}
I'm trying an experiment with keepalived and the VRRP protocol. I have keepalived running on computer A, and from computer B I want to read the multicast VRRP messages to find the the Virtual IP address that computer A is advertising. The computers are connected to the same network switch. Similar questions here on SO are answered by "call setsocketopt with IP_ADD_MEMBERSHIP", that is not the problem here.
My code for reading on a multicast socket is not working for the VRRP multicast IP and port (224.0.0.18:112). Note, it works if I try to read mDNS (224.0.0.251:5353), but for VRRP doesn't ever receive any data, it just hangs in recvfrom
.
I have confirmed with tcpdump (sudo tcpdump -i enp39s0 net 224.0.0.18
) that computer B is actually receiving the messages.
I realize 112 is in the privileged port range, so I run the app with sudo. It seems that if sudo tcpdump -i enp39s0 net 224.0.0.18
can see the messages, this code should be able to receive the messages as well.
When running my app I can see that the port is open and the multicast group has been joined:
$ netstat -lu | grep 112; netstat -g | grep vrrp
udp 0 0 0.0.0.0:112 0.0.0.0:*
enp39s0 2 vrrp.mcast
What am I missing?
Code for receiving multicast messages (error handling removed for simplicity). This code is obviously for Linux, but I've also tried the equivalent on Windows with the same result.
#include <cstring>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#define VRRP_MULTICAST_ADDR "224.0.0.18" // VRRP multicast address
#define VRRP_PORT 112 // VRRP default port
//#define VRRP_MULTICAST_ADDR "224.0.0.251"
//#define VRRP_PORT 5353
int main()
{
sockaddr_in addr;
ip_mreq mreq;
char buffer[256];
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
unsigned int opt_on = 1;
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char*) &opt_on, sizeof(opt_on));
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(VRRP_PORT);
bind(sockfd, (sockaddr *)&addr, sizeof(addr));
mreq.imr_multiaddr.s_addr = inet_addr(VRRP_MULTICAST_ADDR);
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
ssize_t nbytes = recvfrom(sockfd, buffer, sizeof(buffer), 0, NULL, NULL);
printf("Received %ld bytes\n", nbytes);
// HexDump(buffer, nbytes); // HexDump from https://stackoverflow/a/73630740/443766
close(sockfd);
return 0;
}
Share
Improve this question
asked Mar 18 at 15:14
MatthewMatthew
1,6302 gold badges13 silver badges25 bronze badges
1
- I've never had a question downvoted. What's wrong with this one? – Matthew Commented Mar 19 at 21:11
1 Answer
Reset to default 0The trick is VRRP (112) is the protocol, it is not UDP, so raw sockets have to be used.
// VRRP is the protocol, not UDP.
int sockfd = socket(AF_INET, SOCK_RAW, VRRP_PORT);