Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 3 Mar 2023 00:12:39 +0100
From:      Michael Tuexen <michael.tuexen@lurchi.franken.de>
To:        "Rodney W. Grimes" <freebsd-rwg@gndrsh.dnsmgr.net>
Cc:        "Scheffenegger, Richard" <rscheff@FreeBSD.org>, "freebsd-net@freebsd.org" <freebsd-net@FreeBSD.org>
Subject:   Re: BPF to filter/mod ARP
Message-ID:  <93749673-2939-4A38-BA37-2AEBEF5764D0@lurchi.franken.de>
In-Reply-To: <202303021720.322HK0FY062742@gndrsh.dnsmgr.net>
References:  <202303021720.322HK0FY062742@gndrsh.dnsmgr.net>

next in thread | previous in thread | raw e-mail | index | archive | help
> On 2. Mar 2023, at 18:20, Rodney W. Grimes =
<freebsd-rwg@gndrsh.dnsmgr.net> wrote:
>=20
>>> On 2. Mar 2023, at 02:24, Rodney W. Grimes =
<freebsd-rwg@gndrsh.dnsmgr.net> wrote:
>>>=20
>>>> Hi group,
>>>>=20
>>>> Maybe someone can help me with this question - as I am usually only=20=

>>>> looking at L4 and the top side of L3 ;)
>>>>=20
>>>> In order to validate a peculiar switches behavior, I want to adjust =
some=20
>>>> fields in gracious arps sent out by an interface, after a new IP is=20=

>>>> assigned or changed.
>>>=20
>>> Gracious or Gratuitous?
>>>=20
>>>>=20
>>>> I believe BPF can effectively filter on arbitrary bit patterns and=20=

>>>> modify packets on the fly.
>>>=20
>>> It can.
>>>=20
>>>>=20
>>>> However, as ARP doesn't seem to be accessible in the ipfw=20
>>>> infrastructure, I was wondering how to go about setting up an BPF =
to=20
>>>> tweak (temporarily) some of these ARPs to validate how the switch =
will=20
>>>> behave.
>>>=20
>>> ipfw is IP firewall, a layer 3 function.  Arp is a layer 2 protocol,
>>> so very hard to do much with it in ipfw, but perhaps the layer2
>>> keyword, and some use of mac-type can get it to match an arp
>>> packet.  Arp is ethernet type 0x806.
>>>=20
>>> ipfw add 111 count log all from any to any layer2 mac-type arp
>>> That does seem to work
>>> ipfw -a list 111
>>> 00111    4       0 count log ip from any to any layer2 mac-type =
0x0806
>>>=20
>>> Also normally ipfw does NOT pick packets up early enough to see
>>> them, to get the layer2 option to work you need:
>>> sysctl net.link.ether.ipfw=3D1 so that the filters at ether_demux
>>> get turned on.
>>>=20
>>> So perhaps use a divert rule and send them to a socket where
>>> a program can mangle them, and then return them to ipfw
>>> and hopefully the kernel does what you want after that...
>> I thought that you receive/send an IP packet on a divert socket, not
>> an ethernet frame. Am I wrong?
>=20
> That is unclear to me, technically it should just be a binary
> blob and the kernel and userland just have to agree as to
> what it is.  Understand that ipfw originally only had IP layer
> functionality.  The ability to muck with layer2 was added
> later, so I suspect the documentation about what is sent
> over the divert socket may be out of date.  Simple enough
> to test though, just setup as I show above only change
> to:
> ipfw add 111 divert 4444 all from any to any layer2 mac-type arp
> and write a program to dump what you get on the divert socket.
> I suspect you get an ethernet frame.
>=20
> And finally divert(4) says: NAME: divert kernel packet diversion =
mechanism
> That says packet, so again, IMHO, it should be arbitrary to what =
layer.
> It also later says "Divert sockets are similar to raw IP sockets",
> I think similar is the key aspect here, they are not identical.
I can confirm that using
sudo sysctl net.link.ether.ipfw=3D1
sudo ipfw add 111 count log all from any to any layer2 mac-type arp
... wait some time and observe ARP traffic via tcpdump
sudo ipfw show
00111   22      0 count log logamount 5 ip from any to any layer2 =
mac-type 0x0806
65535 7892 849004 allow ip from any to any
So the rule is hit.

However, now doing
sudo ipfw delete 111
sudo ipfw add 111 divert 1234 all from any to any layer2 mac-type arp
... wait some time and observe ARP traffic via tcpdump
tuexen@head:~ % sudo ipfw show
00111     0       0 divert 1234 ip from any to any layer2 mac-type =
0x0806
65535 10048 1000948 allow ip from any to any
So this time, rule 111 is not hit. I also ran

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

#define BUFFER_SIZE (1<<16)
#define PORT        1234

int
main(void)
{
	char buffer[BUFFER_SIZE];
	struct sockaddr_in addr;
	ssize_t n;
	int fd;

	if ((fd =3D socket(PF_DIVERT, SOCK_RAW, 0)) < 0) {
		perror("socket()");
	}
	bzero(&addr, sizeof(addr));
	addr.sin_family      =3D AF_INET;
	addr.sin_len         =3D sizeof(struct sockaddr_in);
	addr.sin_addr.s_addr =3D INADDR_ANY;
	addr.sin_port        =3D htons(PORT);

	if (bind(fd, (struct sockaddr *)&addr, (socklen_t)sizeof(struct =
sockaddr_in)) < 0) {
		perror("bind()");
	}
	for (;;) {
		n =3D recv(fd, buffer, sizeof(buffer), 0);
		printf("Received %zd bytes.\n", n);
	}
	if (close(fd) < 0) {
		perror("close()");
	}
	return (0);
}

but nothing was printed...

Best regards
Michael
>=20
>>=20
>> Best regards
>> Michael
>>>=20
>>>> (I need to validate, if there is some difference when the target=20
>>>> hardware address doesn't conform to RFC5227 - which states it =
SHOULD be=20
>>>> zero and is ignored on the receiving side; i have reasons to =
believe=20
>>>> that the switch needs either a target hardware address of=20
>>>> ff:ff:ff:ff:ff:ff or the local interface MAC, to properly update =
it's=20
>>>> entries.)
>>>>=20
>>>> Thanks a lot!
>>>>=20
>>>> Richard
>>>>=20
>>>=20
>>> --=20
>>> Rod Grimes                                                 =
rgrimes@freebsd.org
>>>=20
>>=20
>>=20
>>=20
>=20
> --=20
> Rod Grimes                                                 =
rgrimes@freebsd.org




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?93749673-2939-4A38-BA37-2AEBEF5764D0>