I have a question regarding packet sockets (2.4 kernel) being used to
receive a multicast pkt. It may be of interest to people familiar with
raw sockets and Layer2-level (LLC) pkts.
I am trying to receive multicast pkts with a specific mac address. But
the kernel is passing me _broadcast_ packets as well. This is
unexpected! Here's roughly what I do (in pseudocode):
Raw socket. (ETH_P_802_3 should not be relevant for
_receiving_):
socket(PF_PACKET, SOCK_RAW, htons(ETH_P_802_3));
Bind, as suggested by packet(7):
sockaddr_ll.sll_family = AF_PACKET;
sockaddr_ll.sll_protocol=htons(ETH_P_802_2);
sockaddr_ll.sll_addr[]=0x...; // eth0's mac#
bind(...);
Subscribe to the multicast address:
packet_mreq.mr_type = PACKET_MR_MULTICAST;
packet_mreq.mr_ifindex = 2;
packet_mreq.mr_alen = 6;
packet_mreq.mr_address[] = 0x...; //desired mcast mac#
setsockopt(... SOL_PACKET, PACKET_ADD_MEMBERSHIP,...);
I trust my confusion is apparent! :-)
Using socket(SOCK_DGRAM...), or skipping sll_addr, do not
help. Regardless of what I've tried, I still get this broadcast packet
which has only a few data bytes after its 802.2 hdr ie the bind is
working, but the setsockopt does not seem to be!
I do not know how to use, or set up, LSF/BPF filters. Nor am I
interested in libpcap. I'd just like to know what I am doing wrong.
Any assistance, insight, opinions, would be greatly appreciated.
Much regards,
Ali
P.S. I've already done my homework. UNPv12e, the kernel
Documentation/networking/ docs, google groups (thanks to Malware &
Jose Antonio Anta's posts), LDP, kernel list (to what extent
searchable), and (some cursory examination of) af_packet.c in the
kernel src.
P.P.S. ironic sig follows ...
--
UNIX: designed by programmers, for programmers.
Is this off-topic? If so, then I'll just post it elsewhere. But I
thought that this NG would be the place for linux systems
programming.
thanks much,
ali
P.S. I found work-arounds for this last week. Now, it's just a
curiousity! It _ought_ to have worked. I am trying to figure out why
it didn't.
you wrote:
> Bind, as suggested by packet(7):
> sockaddr_ll.sll_family = AF_PACKET;
> sockaddr_ll.sll_protocol=htons(ETH_P_802_2);
> sockaddr_ll.sll_addr[]=0x...; // eth0's mac#
> bind(...);
My version (not the latest probably) of the man-page packet(7) does
write:
: By default all packets of the specified protocol type are
: passed to a packet socket. To only get packets from a spe
: cific interface use bind(2) specifying an address in a
: struct sockaddr_ll to bind the packet socket to an inter
: face. Only the sll_protocol and the sll_ifindex address
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
: fields are used for purposes of binding.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The actual code of the version 2.4.18 does reflect this. From
af_packet.c:
static int packet_bind(struct socket *sock, struct sockaddr *uaddr,
int addr_len)
{
...
if (sll->sll_ifindex) {
err = -ENODEV;
dev = dev_get_by_index(sll->sll_ifindex);
if (dev == NULL)
goto out;
}
err = packet_do_bind(sk, dev, sll->sll_protocol ? : sk->num);
...
}
> Using socket(SOCK_DGRAM...), or skipping sll_addr, do not
> help. Regardless of what I've tried, I still get this broadcast packet
> which has only a few data bytes after its 802.2 hdr ie the bind is
> working, but the setsockopt does not seem to be!
>
> I do not know how to use, or set up, LSF/BPF filters. Nor am I
> interested in libpcap. I'd just like to know what I am doing wrong.
If you do not care about the wasted time just use recvfrom and check the
sll_pkttype field within the socket address returned.
Maybe
http://www2.linuxjournal.com/lj-issues/issue86/4659.html
is of help to you if you decide to use LSF rather. [Google returns more
promising links as result of a search on "Linux Socket Filter".]
Malware
Hi Malware,
thanks for the reply.
> > sockaddr_ll.sll_addr[]=0x...; // eth0's mac#
> > bind(...);
> : face. Only the sll_protocol and the sll_ifindex address
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> : fields are used for purposes of binding.
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
I know. (I was going to note this in the original post, but I opted
for brevity!) I _have_ tried without that line -- though I knew that
it would have no effect either way.
> If you do not care about the wasted time just use recvfrom and check the
> sll_pkttype field within the socket address returned.
I'm doing something effectively like this. It worked for my limited purposes.
But, at this point, my formal work is finished. The above issue (along with a
thread suspension issue which I am also investigating) is for my own
education. The setsockopt *ought* to have worked; I am trying to
figure out what my mistake was.
BTW, your 2000/05/06 post on the multicast list kept per-device and
per-socket was very informative. I located it in af_packet.c as
well. Thanks.
> http://www2.linuxjournal.com/lj-issues/issue86/4659.html
> is of help to you if you decide to use LSF rather. [Google returns more
Thanks. I doubt I'll have a use for it, though. I'm just trying to
figure out why my
setsockopt( SOL_PACKET and PACKET_MR_MULTICAST)
call had no apparent effect.
I may/not try a debug build of the kernel, just to see what the
device/socket multicast lists look like after I run the
setsockopt. /proc/net/raw is certainly showing nothing meaningful to
me. strace appears, to _my_ eyes, to show that everything's fine.
Much thanks,
ali
P.S. I've suffered a massive disk failure. Cleanup has/will take a
few days. Hence my mail is down. I'm posting from work.
you wrote:
> > > sockaddr_ll.sll_addr[]=0x...; // eth0's mac#
> > > bind(...);
>
> > : face. Only the sll_protocol and the sll_ifindex address
> > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> > : fields are used for purposes of binding.
> > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>
> I know. (I was going to note this in the original post, but I opted
> for brevity!) I _have_ tried without that line -- though I knew that
> it would have no effect either way.
Your conclusion path is probably to short.
Since bind() never uses the any other information than the protocol and
interface number, it does not implement a restriction on the destination
mac address. Any packets received by the interface with matching
protocol are given to the packet socket. This does naturally include
broadcast packets.
> education. The setsockopt *ought* to have worked; I am trying to
> figure out what my mistake was.
The setsockopt() adds you to a multicast group but by no way does
disable the receiving of unicast and broadcast packets. Since you did
not claim not to receive multicast packets it seem have done its work.
You have even to be prepared for the case the devices goes into
promiscuous mode by adding it to a multicast group. Some (or most) NICs
have an own multicast filter (of limited length) other none et all. The
work-around is to enable primiscous mode as soon as the filter of the
NIC can no longer handle the amount of multicast addresses.
Malware
> Since bind() never uses the any other information than the protocol and
> interface number, it does not implement a restriction on the destination
> mac address. Any packets received by the interface with matching
> protocol are given to the packet socket. This does naturally include
> broadcast packets.
This was my understanding, too.
> The setsockopt() adds you to a multicast group but by no way does
> disable the receiving of unicast and broadcast packets. Since you did
Good point. I overlooked this. I _assumed_ that I would get only
multicast packets when I ask for PACKET_MR_MULTICAST.
So, as you pointed out, it did behave correctly.
... A brief examination of the src code seems to confirm this,
too; there is no 'turning off' :-) of broadcast.
> work-around is to enable primiscous mode as soon as the filter of the
> NIC can no longer handle the amount of multicast addresses.
Great info. Thanks.
Thanks again for your help.
regards,
ali