Adding nftables nat rules with libnftnl APIs - nat

I want to add following snat and dnat rules using nftables:
nft add rule nat post udp sport 29000 ip saddr 192.168.101.102 udp dport 40000 ip daddr 192.168.101.102 snat 192.168.101.55:35000
nft add rule nat pre udp sport 29000 ip saddr 192.168.101.103 udp dport 32000 ip daddr 192.168.101.55 dnat 192.168.101.102:40000
Here, pre and post is name of the chains in the nat table and I have added those with the following commands:
nft add table nat
nft add chain nat pre { type nat hook prerouting priority 0 \; }
nft add chain nat post { type nat hook postrouting priority 100 \; }
I have already checked it with the nft command and it is working perfectly.
I want to achieve the same with API approach from my application. There are some examples and test program provided in the libnftnl library. From the reference of nft-rule-add.c and nft-expr_nat-test.c I have made a test application for the same as follows:
/* Packets coming from */
#define SADDR "192.168.1.103"
#define SPORT 29000
/* Packets coming to (the machine on which nat happen) */
#define DADDR "192.168.101.55"
#define DPORT 32000
/* Packets should go from (the machine on which nat happen) */
#define SNATADDR DADDR
#define SNATPORT 35000
/* Packets should go to */
#define DNATADDR SADDR
#define DNATPORT 38000
static void add_payload(struct nftnl_rule *rRule, uint32_t base, uint32_t dreg,
uint32_t offset, uint32_t len)
{
struct nftnl_expr *tExpression = nftnl_expr_alloc("payload");
if (tExpression == NULL) {
perror("expr payload oom");
exit(EXIT_FAILURE);
}
nftnl_expr_set_u32(tExpression, NFTNL_EXPR_PAYLOAD_BASE, base);
nftnl_expr_set_u32(tExpression, NFTNL_EXPR_PAYLOAD_DREG, dreg);
nftnl_expr_set_u32(tExpression, NFTNL_EXPR_PAYLOAD_OFFSET, offset);
nftnl_expr_set_u32(tExpression, NFTNL_EXPR_PAYLOAD_LEN, len);
nftnl_rule_add_expr(rRule, tExpression);
}
static void add_cmp(struct nftnl_rule *rRule, uint32_t sreg, uint32_t op,
const void *data, uint32_t data_len)
{
struct nftnl_expr *tExpression = nftnl_expr_alloc("cmp");
if (tExpression == NULL) {
perror("expr cmp oom");
exit(EXIT_FAILURE);
}
nftnl_expr_set_u32(tExpression, NFTNL_EXPR_CMP_SREG, sreg);
nftnl_expr_set_u32(tExpression, NFTNL_EXPR_CMP_OP, op);
nftnl_expr_set(tExpression, NFTNL_EXPR_CMP_DATA, data, data_len);
nftnl_rule_add_expr(rRule, tExpression);
}
static void add_nat(struct nftnl_rule *rRule, uint32_t sreg,
const void *ip, uint32_t ip_len,
const void *port, uint32_t port_len)
{
struct nftnl_expr *tExpression = nftnl_expr_alloc("nat");
if (tExpression == NULL) {
perror("expr cmp oom");
exit(EXIT_FAILURE);
}
/* Performing snat */
nftnl_expr_set_u32(tExpression, NFTNL_EXPR_NAT_TYPE, NFT_NAT_SNAT);
/* Nat family IPv4 */
nftnl_expr_set_u32(tExpression, NFTNL_EXPR_NAT_FAMILY, NFPROTO_IPV4);
/* Don't know what to do with these four calls */
/* How to add IP address and port that should be used in snat */
// nftnl_expr_set_u32(tExpression, NFTNL_EXPR_NAT_REG_ADDR_MIN, NFT_REG_1);
// nftnl_expr_set_u32(tExpression, NFTNL_EXPR_NAT_REG_ADDR_MAX, NFT_REG_3);
// nftnl_expr_set_u32(tExpression, NFTNL_EXPR_NAT_REG_PROTO_MIN, 0x6124385);
// nftnl_expr_set_u32(tExpression, NFTNL_EXPR_NAT_REG_PROTO_MAX, 0x2153846);
nftnl_rule_add_expr(rRule, tExpression);
}
static struct nftnl_rule *setup_rule(uint8_t family, const char *table,
const char *chain, const char *handle)
{
struct nftnl_rule *rule = NULL;
uint8_t proto = 0;
uint16_t dport = 0, sport = 0, sNatPort = 0, dNatPort = 0;
uint8_t saddr[sizeof(struct in6_addr)]; /* Packets coming from */
uint8_t daddr[sizeof(struct in6_addr)]; /* Packets coming to (the machine on which nat happens) */
uint8_t snataddr[sizeof(struct in6_addr)]; /* Packets should go from (the machine on which nat happens) */
uint8_t dnataddr[sizeof(struct in6_addr)]; /* Packets should go to */
uint64_t handle_num;
rule = nftnl_rule_alloc();
if (rule == NULL) {
perror("OOM");
exit(EXIT_FAILURE);
}
nftnl_rule_set(rule, NFTNL_RULE_TABLE, table);
nftnl_rule_set(rule, NFTNL_RULE_CHAIN, chain);
nftnl_rule_set_u32(rule, NFTNL_RULE_FAMILY, family);
if (handle != NULL) {
handle_num = atoll(handle);
nftnl_rule_set_u64(rule, NFTNL_RULE_POSITION, handle_num);
}
/* Declaring tcp port or udp port */
proto = IPPROTO_UDP;
add_payload(rule, NFT_PAYLOAD_NETWORK_HEADER, NFT_REG_1,
offsetof(struct iphdr, protocol), sizeof(uint8_t));
add_cmp(rule, NFT_REG_1, NFT_CMP_EQ, &proto, sizeof(uint8_t));
/* Declaring dport */
dport = htons(DPORT);
add_payload(rule, NFT_PAYLOAD_TRANSPORT_HEADER, NFT_REG_1,
offsetof(struct udphdr, dest), sizeof(uint16_t));
add_cmp(rule, NFT_REG_1, NFT_CMP_EQ, &dport, sizeof(uint16_t));
/* Declaring dest ip */
add_payload(rule, NFT_PAYLOAD_NETWORK_HEADER, NFT_REG_1,
offsetof(struct iphdr, daddr), sizeof(daddr));
inet_pton(AF_INET, DADDR, daddr);
add_cmp(rule, NFT_REG_1, NFT_CMP_EQ, daddr, sizeof(daddr));
/* Declaring sport */
sport = htons(SPORT);
add_payload(rule, NFT_PAYLOAD_TRANSPORT_HEADER, NFT_REG_1,
offsetof(struct udphdr, source), sizeof(uint16_t));
add_cmp(rule, NFT_REG_1, NFT_CMP_EQ, &sport, sizeof(uint16_t));
/* Declaring src ip */
add_payload(rule, NFT_PAYLOAD_NETWORK_HEADER, NFT_REG_1,
offsetof(struct iphdr, saddr), sizeof(saddr));
inet_pton(AF_INET, SADDR, saddr);
add_cmp(rule, NFT_REG_1, NFT_CMP_EQ, saddr, sizeof(saddr));
/* Addding snat params */
inet_pton(AF_INET, SNATADDR, snataddr);
sNatPort = htons(SNATPORT);
add_nat(rule, NFT_REG_1, snataddr, sizeof(snataddr), &sNatPort, sizeof(uint16_t));
return rule;
}
int main(int argc, char *argv[])
{
struct mnl_socket *nl;
struct nftnl_rule *r;
struct nlmsghdr *nlh;
struct mnl_nlmsg_batch *batch;
uint8_t family;
char buf[MNL_SOCKET_BUFFER_SIZE];
uint32_t seq = time(NULL);
int ret, batching;
if (argc < 4 || argc > 5) {
fprintf(stderr, "Usage: %s <family> <table> <chain>\n", argv[0]);
exit(EXIT_FAILURE);
}
if (strcmp(argv[1], "ip") == 0)
family = NFPROTO_IPV4;
else if (strcmp(argv[1], "ip6") == 0)
family = NFPROTO_IPV6;
else {
fprintf(stderr, "Unknown family: ip, ip6\n");
exit(EXIT_FAILURE);
}
// Now creating rule
if (argc != 5)
r = setup_rule(family, argv[2], argv[3], NULL);
else
r = setup_rule(family, argv[2], argv[3], argv[4]);
// Now adding rule through mnl socket
nl = mnl_socket_open(NETLINK_NETFILTER);
if (nl == NULL) {
perror("mnl_socket_open");
exit(EXIT_FAILURE);
}
if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
perror("mnl_socket_bind");
exit(EXIT_FAILURE);
}
batching = nftnl_batch_is_supported();
if (batching < 0) {
perror("cannot talk to nfnetlink");
exit(EXIT_FAILURE);
}
batch = mnl_nlmsg_batch_start(buf, sizeof(buf));
if (batching) {
nftnl_batch_begin(mnl_nlmsg_batch_current(batch), seq++);
mnl_nlmsg_batch_next(batch);
}
nlh = nftnl_rule_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch),
NFT_MSG_NEWRULE,
nftnl_rule_get_u32(r, NFTNL_RULE_FAMILY),
NLM_F_APPEND|NLM_F_CREATE|NLM_F_ACK, seq++);
nftnl_rule_nlmsg_build_payload(nlh, r);
nftnl_rule_free(r);
mnl_nlmsg_batch_next(batch);
if (batching) {
nftnl_batch_end(mnl_nlmsg_batch_current(batch), seq++);
mnl_nlmsg_batch_next(batch);
}
ret = mnl_socket_sendto(nl, mnl_nlmsg_batch_head(batch),
mnl_nlmsg_batch_size(batch));
if (ret == -1) {
perror("mnl_socket_sendto");
exit(EXIT_FAILURE);
}
mnl_nlmsg_batch_stop(batch);
ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
if (ret == -1) {
perror("mnl_socket_recvfrom");
exit(EXIT_FAILURE);
}
ret = mnl_cb_run(buf, ret, 0, mnl_socket_get_portid(nl), NULL, NULL);
if (ret < 0) {
perror("mnl_cb_run");
exit(EXIT_FAILURE);
}
mnl_socket_close(nl);
return EXIT_SUCCESS;
}
Here, main() function calls setup_rule() where whole rule is built. setup_rule() calls add_nat() where expression for snat is built. The IP and Port that should be used for snat or dnat are passed as args to add_nat().
As I understand, the phylosophy of building a rule is that a rule is built with various expressions. In add_nat() an expression is built for doing snat and that's where I start to fumble. Don't know what to do with NFTNL_EXPR_NAT_REG_ADDR_MIN and NFTNL_EXPR_NAT_REG_PROTO_MIN kind of macros. How to pass IP Address and Port Address which will be used in snat or dnat.
I run the above test application as follows:
./application ip nat pre
And with the following command
nft list table nat -a
got the output as follows:
table ip nat {
chain pre {
type nat hook prerouting priority 0; policy accept;
udp dport 32000 ip daddr 192.168.101.55 #nh,160,96 541307071 udp sport 29000 ip saddr 192.168.1.103 ip daddr 0.0.0.0 #nh,160,64 3293205175 snat to # handle 250
} # handle 33
chain post {
type nat hook postrouting priority 100; policy accept;
} # handle 34
} # handle 0
May be the approach is wrong, but, as shown above, it displayed snat to in the end. And that gives me the hope that this is the way forward. I also digged in the nftables utility code but to no avail.
So to list all queries:
How to add snat or dnat rules with nftable apis?
What is with NFT_REG_1? How these registers should be used and where it should be used?
What is written after # in the output of the nft list table nat -a command? When I apply rules with nft command than it does not show info after # in the output of nft list table
Also, there is an extra ip addr 0.0.0.0 displayed in the output of nft list table nat -a command. Where does that get added?

Related

netfilter_queue ipv4 optional header removal

I'm implementing netfilter_queue-based user program that deletes ipv4 optional header 'Time Stamp'
ping works well with this program, because it uses ICMP transmission.
But TCP-based applications doesn't work. I've checked it with wireshark, and this program deletes timestamp well. Instead, TCP-based application doesn't send ACK for that packet, and remote server retransmits the same packet indefinitely.
Is there any missing procedures for TCP packet processing? I just modified IPv4 header part only. Then why the tcp transmission doesn't work at all?
My main code is:
static int cb(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg,
struct nfq_data *nfa, void *data)
{
unsigned int timestamp = 0;
bool ptype = true;
int pnow = 20;
int plast = 20;
int ihl;
struct nfqnl_msg_packet_hdr *ph = nfq_get_msg_packet_hdr(nfa);
unsigned char* rawBuff = NULL;
int len;
len = nfq_get_payload(nfa, &rawBuff);
if(len < 0) printf("Failed to get payload");
struct pkt_buff* pkBuff = pktb_alloc(AF_INET, rawBuff, len, 0x20);
struct iphdr* ip = nfq_ip_get_hdr(pkBuff);
ihl = ip->ihl;
uint8_t* buff = NULL;
if( (ip->daddr != 0x0101007f) && (ip->daddr != 0x0100007f) && (ip->daddr != 0x0100A9C0) && (ip->saddr != 0x0100A9C0)) { // filter_out dns
if(ip->version == 4) {
if(ihl != 5) { // if ipv4 packet header is longer than default packet header
buff = pktb_data(pkBuff); // packet buffer
plast = ihl * 4;
while(pnow != plast) {
if(buff[pnow] == 0x44) { // timestamp type
ptype = false;
break;
}
else {
if(buff[pnow+1] == 0) {
pnow = pnow + 4;
}
else {
pnow = pnow + buff[pnow+1];
}
}
}
}
if(!ptype) {
timestamp = buff[pnow + 4] << 24 | buff[pnow + 5] << 16 | buff[pnow + 6] << 8 | buff[pnow + 7];
if(timestamp > 100000) { // if TS is big, delete it.
ip->ihl -= 2;
nfq_ip_mangle(pkBuff, pnow, 0, 8, "", 0);
}
}
}
}
nfq_ip_set_checksum(ip);
if(nfq_ip_set_transport_header(pkBuff, ip) < 0) printf("Failed to set transport header");
int result = 0;
result = nfq_set_verdict(qh, ntohl(ph->packet_id), NF_ACCEPT, pktb_len(pkBuff), pktb_data(pkBuff));
pktb_free(pkBuff);
return result;
}
iptables setting is:
sudo iptables -t mangle -A PREROUTING -j NFQUEUE -p all --queue-num 0
sudo iptables -t mangle -A POSTROUTING -j NFQUEUE -p all --queue-num 0
It seems that netfilter_queue is malfunctioning. After debugging Kernel, I could identify that skbuff's network_header pointer is not updated even I changed netfilter_queue's equivalent pointer. Mangled packet is dropped by packet length checking code.
Shouldn't you place the TCP header just after the IP header?
0...............20.........28..........48..........
+---------------+----------+-----------+-----------+
|IP HEADER |IP OPTIONS| TCP HEADER|TCP OPTIONS|
+---------------+----------+-----------+-----------+
So, decreasing ihl value, you're creating a gap between IP header and TCP header.
You need to use memmove along with decreasing ihl value.

While STM32 runs the LwIP protocol,How to implement 5 TCP connections?

Now,I am working with STM32F107+lwip.The aim is making a gateway which is used to exchange datas between ETHERNET and CAN. The UDP server is tested well.And now I want to increase the TCP server function,which can be permitted to establish 5 TCP connections.
My questions:
1 TCP connnection is tested ok,How to implement 5 TCP connections?
First,PC send data to STM32 by TCP connections. STM32 receives it and send it to CAN.Then,when STM32 receives datas from CAN ,it will send the datas to PC by all the TCP connections.Now,my idea is that typedef a structure,when STM32 received the data from PC,it will record the pcb,remote ip and remote port. And receiving data from CAN ,STM32 will send it through the recording data.The result is the data will be sent slowly when STM32 invokes the "tcp_write()" and "tcp_output"frequently.
So I wonder the solutions to implement multiple TCP connections.
#define TCP_WORKING 0xaa
#define TCP_FREE 0xa5
typedef struct Cmd_TCPData
{
unsigned char TCP_STATUS;
unsigned char cmd_flag;
unsigned short remote_port;
unsigned short data_len;
struct ip_addr remote_ip;
unsigned char *pData;
struct tcp_pcb *TCP_pcb;
}Cmd_TCPData;
Cmd_TCPData cmd_tcp;
Cmd_TCPData tcp_list[5];
static u8 TcpListNum;
void TCP_server_init(void)
{
struct tcp_pcb *pcb;
err_t err;
/*****************************************************/
pcb = tcp_new();
if (!pcb)
{
return ;
}
err = tcp_bind(pcb,IP_ADDR_ANY,devInfo.udpPort);
if(err != ERR_OK)
{
return ;
}
pcb = tcp_listen(pcb);
tcp_accept(pcb,tcp_server_accept);
}
static err_t tcp_server_accept(void *arg,struct tcp_pcb *pcb,err_t err)
{
tcp_setprio(pcb, TCP_PRIO_MIN);
tcp_recv(pcb,tcp_server_recv);
err = ERR_OK;
return err;
}
static err_t tcp_server_recv(void *arg, struct tcp_pcb *pcb,struct pbuf *p,err_t err)
{
struct pbuf *p_temp = p;
int nPos=0;
u8 searchtemp=0;
//TCP_pcbA=pcb;
while(tcp_list[searchtemp].TCP_STATUS==TCP_WORKING)
{
if(tcp_list[searchtemp].remote_ip.addr!= pcb->remote_ip.addr)
{
searchtemp++;
}
else
break;
if(searchtemp==5)
{
searchtemp=0;
break;
}
}
/******copy*******************/
tcp_list[searchtemp].TCP_pcb=pcb;
tcp_list[searchtemp].pData = TCPRecvBuf;
tcp_list[searchtemp].remote_port=pcb->remote_port;
tcp_list[searchtemp].remote_ip = pcb->remote_ip;
tcp_setprio(tcp_list[searchtemp].TCP_pcb, TCP_PRIO_MIN+searchtemp);
if(p_temp != NULL)
{
tcp_recved(pcb, p_temp->tot_len);
while(p_temp != NULL)
{
// tcp_write(pcb,p_temp->payload,p_temp->len,TCP_WRITE_FLAG_COPY);
// tcp_output(pcb);
memcpy(tcp_list[searchtemp].pData+nPos,p_temp->payload,p_temp->len);
nPos += p_temp->len;
p_temp = p_temp->next;
}
}
else
{
tcp_close(pcb);
}
tcp_list[searchtemp].data_len = nPos;
flash_led_tcp = 1;
tcp_list[searchtemp].TCP_STATUS= TCP_WORKING;
TcpListNum=searchtemp;
pbuf_free(p);
err = ERR_OK;
return err;
}
void send_tcp_data(u8_t *pPtr,u16_t data_len)
{
u8 x=0;
while(x<5)
{
if(tcp_list[x].TCP_STATUS==TCP_WORKING)
{
//TCP_pcbA->remote_port=tcp_list[x].remote_port;
//TCP_pcbA->remote_ip= tcp_list[x].remote_ip;
tcp_write(tcp_list[x].TCP_pcb,pPtr,data_len,TCP_WRITE_FLAG_COPY);
tcp_output(tcp_list[x].TCP_pcb);
}
OSTimeDlyHMSM(0, 0, 0, 250);//250ms
x++;
}
}
The tcp_server_accept() will contain the newly created connection. To this connection you can attach your context.
struct myclient_t
{
struct tcp_pcb *pcb;
/* all the variables uniqe for tracking this specific connection.. parser-state, receive/send buffers, statistics... */
int foo;
int bar;
};
static err_t tcp_server_accept(void *arg,struct tcp_pcb *pcb,err_t err)
{
err_t ret_err;
struct struct myclient_t *context = 0;
int i;
context = new_client();
if (!context )
{
return ERR_MEM;
}
context->pcb = pcb;
/* pass newly allocated es structure as argument to newpcb */
tcp_arg(newpcb, context); /* recv, sent, error and poll callbacks will have context their argument, which is uniqe for each connection */
/* initialize lwip tcp_recv callback function for newpcb */
tcp_recv(newpcb, tcp_server_recv
tcp_sent(newpcb, tcp_server_sent);
/* initialize lwip tcp_err callback function for newpcb */
tcp_err(newpcb, tcp_server_error);
/* initialize lwip tcp_poll callback function for newpcb */
tcp_poll(newpcb, tcp_server_poll, 1);
return ERR_OK;
}

Raspberry PI: endianness CROSS COMPILE

I use buildroot cross toolchain to compile Raspberry application from my computer (Ubuntu X86).
I'm developping a TCP serveur that allows a connection on 5003 (0x138B) TCP port number. When I'm start the server, that's right but my server wait a connection on 35603 (0x8B13) TCP port number (check with netstat -a).
It seems to be an endianness problem but I don't know how to resolve.
Can you help me please?
Thanks.
thanks for your answer.
I agree it's very strange. I don't think the code is the problem. It's working well on other platform.
Please find the code below:
/*Create the server */
int CreateServeur (unsigned short port, int *sock_srv, int nb_connect)
{
int l_ret = -1;
struct sockaddr_in l_srv_addr;
/* address initialisation */
printf("creation serveur port %i\n", port);
memset ((char*) &l_srv_addr,0, sizeof (struct sockaddr_in));
l_srv_addr.sin_family = PF_INET;
l_srv_addr.sin_port = port;
l_srv_addr.sin_addr.s_addr = htonl (INADDR_ANY);
/* main socket creation */
if ((*sock_srv = socket (PF_INET, SOCK_STREAM, 0)) <= 0)
{
printf("server socket creation error");
}
else
{
if (bind (*sock_srv, (struct sockaddr *) &l_srv_addr, sizeof (struct sockaddr_in)) == -1)
{
close (*sock_srv);
printf("bind socket error");
}
else
{
if (listen (*sock_srv, nb_connect) == ERROR)
{
close (*sock_srv);
printf("listen socket error");
}
else
{
l_ret = 0;
}
}
}
return (l_ret);
}
This function doesn't return any error. The first log (printf("creation serveur port %i\n", port);) display the good port (5003) but the server wait connexion on port 35603 (netstat -a).
If it's not a endianness problem, I don't understand.

IP address from getifaddrs and ipconfig don't match

On my mac, I did a command line
ipconfig getifaddr en1
and it shows
10.0.0.2
However when I use the
struct ifaddrs *id;
int success=0;
success=getifaddrs(&id);
printf("Network Address of %s :- %d\n",id->ifa_name,id->ifa_addr);
it shows
Network Address of lo0 :- 8393376
So, how does the 10.0.0.2 relate to 8393376?
Seems like they don't match from the two ways of finding the IP address.
id->ifa_addr
Is some kind of struct sockaddr (e.g. a struct sockaddr_in), which contains the type of
the address (e.g. IPv4, IPv6, Ethernet MAC address, or similar), and the
binary representation of the address. It is not a string that you can print with printf's %s.
You might be able to use this:
void
print_sockaddr(struct sockaddr* addr,const char *name)
{
char addrbuf[128] ;
addrbuf[0] = 0;
if(addr->sa_family == AF_UNSPEC)
return;
switch(addr->sa_family) {
case AF_INET:
inet_ntop(addr->sa_family,&((struct sockaddr_in*)addr)->sin_addr,
addrbuf,sizeof(struct sockaddr_in));
break;
case AF_INET6:
inet_ntop(addr->sa_family, &((struct sockaddr_in6*)addr)->sin6_addr,
addrbuf,sizeof(struct sockaddr_in6));
break;
default:
sprintf(addrbuf,"Unknown family (%d)",(int)addr->sa_family);
break;
}
printf("%-16s %s\n",name,addrbuf);
}
...
print_sockaddr(id->ifa_addr,id->ifa_name);
getifaddrs returns a linked list of struct ifaddrs , representing each interface.
You'll need to do:
struct ifaddrs *addrs,*tmp;
if(getifaddrs(&addrs) != 0) {
perror("getifaddrs");
return 1;
}
for(tmp = addrs; tmp ; tmp = tmp->ifa_next) {
print_sockaddr(tmp->ifa_addr, tmp->ifa_name);
}
freeifaddrs(addrs);
Dude, to print the IP you need do this:
struct sockaddr_in * ip;
ip = (struct sockaddr_in *) id->ifa_addr;
if (ip->sin_family == AF_INET)
printf("Network Address: %s\n",inet_ntoa(ip->sin_addr));
try do this.

Problem in listening to multicast in C++ with multiple NICs

I am trying to write a multicast client on a machine with two NICs, and I can't make it work. I can see with a sniffer that once I start the program the NIC (eth4) start receiving the multicast datagrams, However, I can't recieve() any in my program.
When running "tshark -i eth4 -R udp.port==xxx (multicast port)"
I get:
1059.435483 y.y.y.y. (some ip) -> z.z.z.z (multicast ip, not my eth4 NIC IP) UDP Source port: kkk (some other port) Destination port: xxx (multicast port)
Searched the web for some examples/explanations, but it seems like I do what everybody else does. Any help will be appreciated. (anything to do with route/iptables/code?)
bool connectionManager::sendMulticastJoinRequest()
{
struct sockaddr_in localSock;
struct ip_mreqn group;
char* mc_addr_str = SystemManager::Instance()->getTCP_IP_CHT();
char* local_addr_str = SystemManager::Instance()->getlocal_IP_TOLA();
int port = SystemManager::Instance()->getTCP_Port_CHT();
/* Create a datagram socket on which to receive. */
CHT_UDP_Feed_sock = socket(AF_INET, SOCK_DGRAM, 0);
if(CHT_UDP_Feed_sock < 0)
{
perror("Opening datagram socket error");
return false;
}
/* application to receive copies of the multicast datagrams. */
{
int reuse = 1;
if(setsockopt(CHT_UDP_Feed_sock, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) < 0)
{
perror("Setting SO_REUSEADDR error");
close(CHT_UDP_Feed_sock);
return false;
}
}
/* Bind to the proper port number with the IP address */
/* specified as INADDR_ANY. */
memset((char *) &localSock, 0, sizeof(localSock));
localSock.sin_family = AF_INET;
localSock.sin_port = htons(port);
localSock.sin_addr.s_addr =inet_addr(local_addr_str); // htonl(INADDR_ANY); //
if(bind(CHT_UDP_Feed_sock, (struct sockaddr*)&localSock, sizeof(localSock)))
{
perror("Binding datagram socket error");
close(CHT_UDP_Feed_sock);
return false;
}
/* Join the multicast group mc_addr_str on the local local_addr_str */
/* interface. Note that this IP_ADD_MEMBERSHIP option must be */
/* called for each local interface over which the multicast */
/* datagrams are to be received. */
group.imr_ifindex = if_nametoindex("eth4");
if (setsockopt(CHT_UDP_Feed_sock, SOL_SOCKET, SO_BINDTODEVICE, "eth4", 5) < 0)
return false;
group.imr_multiaddr.s_addr = inet_addr(mc_addr_str);
group.imr_address.s_addr = htonl(INADDR_ANY); //also tried inet_addr(local_addr_str); instead
if(setsockopt(CHT_UDP_Feed_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&group, sizeof(group)) < 0)
{
perror("Adding multicast group error");
close(CHT_UDP_Feed_sock);
return false;
}
// Read from the socket.
char databuf[1024];
int datalen = sizeof(databuf);
if(read(CHT_UDP_Feed_sock, databuf, datalen) < 0)
{
perror("Reading datagram message error");
close(CHT_UDP_Feed_sock);
return false;
}
else
{
printf("Reading datagram message...OK.\n");
printf("The message from multicast server is: \"%s\"\n", databuf);
}
return true;
}
Just a thought, (I've not done much work with multicast), but could it be because you're binding to a specific IP address? The socket could be only accepting packets destined for it's bound IP address and rejecting the multicast ones?
Well, there is some time ago since I didn't play with multicast. Don't you need root/admin rights to use it? did you enable them when launching your program?

Resources