[Voyage-linux] wlan0/hostap/kernel drops packets dst for 224.0.0.2 when the src addr does not match the subnet of the listening interface?
LEE, Yui-wah (Clement)
(spam-protected)
Thu Jan 26 05:51:17 HKT 2006
Hi,
I am using voyage-linux (0.1sarge) on soekris 4521 and
hit the following strange phenomenon. Either I did
something wrong, or I may have hit a strange bug
somewhere in the kernel, the wlan0 driver, or hostap.
I have a program "ma" that listens on all the packets
destined to 224.0.0.2 (ALL-ROUTERS.MCAST.NET.) on
wlan0, which is configured to be of address
10.0.0.1/24. The program issues the usual setsockopt()
call (SOL_IP and IP_ADD_MEMBERSHIP) to tell the
interface to join the multicast group. The call
completed without any complains from the system. After
that, the program ma sits on a select() loop waiting
from some packets from the socket.
Then, I noticed that if the client sends a packet
destinated to 224.0.0.2 with a source address that is
in the subnet of 10.0.0.1/24 (e.g. 10.0.0.106), ma
would get the packet. If, on the other hand, the
client sends a similar packet but with a source address
that is OUTSIDE of the subnet (e.g. 10.0.1.106), then
ma would NOT get the packets.
I tried two different versions of kernels (2.6.8 and
2.4.26) and both gave the same result.
I think this may be a bug somewhere in the wlan0 (or
hostap) or the kernel, because
1. I tried the same program ma on another soekris
machine running a Redhat (7.0) system with kernel
2.4.18, and the above problem did NOT occur (i.e. ma
gets all packets irrespective of the source address)
2. I tried running ma on another interface ("eth0"
instead of "wlan0"), and the above problem did NOT
occur.
3. The "ma" expected behavior is required for a
Mobile-IP mobility agent (RFC3344, Section 2.3, 2nd
last paragraph of Page 23 -- in case you are
interested). Also, I think the multicast join is
based on the *interface* but not on the *interface
address*, right?
I also verified that when ma was run, "ip maddr show
wlan0" showed
workit1:~# ip maddr show wlan0
5: wlan0
link 01:00:5e:00:00:02
link 01:00:5e:00:00:01
inet 224.0.0.2
inet 224.0.0.1
indicating that the multicast join instruction had been
made through to the kernel.
I attached my test program ma2.cc in case someone want
to look at the code.
Thanks!
Clement
-------------- next part --------------
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/select.h>
#include <stdio.h>
#include <string.h>
#include <systools/utils.hh>
#include <net/if.h>
typedef struct {
unsigned int ipi_ifindex;
struct in_addr ipi_spec_dst;
struct in_addr ipi_addr;
} linux_pktinfo;
void processIcmp(int s) {
unsigned char rawbuf[1024];
struct sockaddr_in from;
struct msghdr msg;
struct iovec iov[1];
memset(&msg, 0, sizeof(msghdr));
linux_pktinfo *pktinfo = NULL;
msg.msg_name = (char *)&from;
msg.msg_namelen = sizeof(from);
struct cmsghdr *cmptr;
union {
struct cmsghdr cm;
char control[CMSG_SPACE(sizeof(*pktinfo))];
} ctrl;
msg.msg_control = ctrl.control;
msg.msg_controllen = sizeof(ctrl.control);
memset(rawbuf, 0, sizeof(rawbuf));
iov[0].iov_base = rawbuf;
iov[0].iov_len = sizeof(rawbuf);
msg.msg_iov = iov;
msg.msg_iovlen = 1;
int r = recvmsg(s, &msg, 0);
if ( r<0 ) {
printf("recvfrom error.\n");
} else {
printf("recvfrom got %d byte\n", r);
}
}
int main(int argc, char *argv[]) {
int s;
char *listenIfaceString;
if (argc!=2) {
printf("Usage: %s [<iface_to_listen_on>]\n", argv[0]);
return -1;
}
listenIfaceString = argv[1];
if ( (s = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0 ) {
perror("could not open RAW socket");
return -1;
}
long bcast = 1;
if ( setsockopt(s, SOL_SOCKET, SO_BROADCAST, (char *)&bcast,
sizeof(long)) == -1 ) {
perror("could not setsockopt bcast");
return -1;
}
u_char loop = 0;
if ( setsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP, (char *)&loop,
sizeof(u_char)) == -1 ) {
perror("could not setsockopt ip_multicast_loop");
return -1;
}
/* SOL_IP, IP_PKTINFO ? */
long icmp_pktinfo = 1;
if ( setsockopt(s, SOL_IP, IP_PKTINFO, (char *)&icmp_pktinfo,
sizeof(long)) < 0 ) {
perror("could not setsockopt ip_pktinfo");
return -1;
}
struct ip_mreqn imrn;
memset(&imrn, 0, sizeof(imrn));
imrn.imr_multiaddr.s_addr = inet_addr("224.0.0.2");
imrn.imr_ifindex = if_nametoindex(listenIfaceString);
if ( setsockopt(s, SOL_IP, IP_ADD_MEMBERSHIP, (char *)&imrn,
sizeof(imrn)) < 0 ) {
perror("could not join mcast grp 224.0.0.2");
return -1;
}
for(;;) {
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(s, &readfds);
Tval next = Tval(0, 50000);
if ( select(FD_SETSIZE, &readfds, NULL, NULL, &next) < 0 ) {
perror("error in select");
}
if (FD_ISSET(s, &readfds)) {
printf("select() returned on icmp socket\n");
processIcmp(s);
}
}
}
More information about the Voyage-linux
mailing list