Discussion:
pcap_inject() on loopback (FreeBSD)
Fernando Gont
2014-06-15 12:23:55 UTC
Permalink
Folks,

I'm trying to send an IPv6 packet with pcap_inject() on the loopback
interface of a FreeBSD 9.2 system.

What I write with pcap_inect() is the IPv6 packet, preceded with the
4-byte AF header (which I set to PF_INET6 (which is 28) in host byte order).

However, pcap_inject() fails with
"send: Address family not supported by protocol family"

and I also get this message on the console::
"looutput: af=31 unexpected"

which would seem to indicate that pcap_inject() is overwriting the value
I set with something else (pseudo_AF_HDRCMPLT?).

Any thoughts?

Thanks!

Best regards,
--
Fernando Gont
e-mail: ***@gont.com.ar || ***@si6networks.com
PGP Fingerprint: 7809 84F5 322E 45C7 F1C9 3945 96EE A9EF D076 FFF1
Guy Harris
2014-06-15 18:07:36 UTC
Permalink
Post by Fernando Gont
I'm trying to send an IPv6 packet with pcap_inject() on the loopback
interface of a FreeBSD 9.2 system.
What I write with pcap_inect() is the IPv6 packet, preceded with the
4-byte AF header (which I set to PF_INET6 (which is 28) in host byte order).
However, pcap_inject() fails with
"send: Address family not supported by protocol family"
"looutput: af=31 unexpected"
which would seem to indicate that pcap_inject() is overwriting the value
I set with something else (pseudo_AF_HDRCMPLT?).
It indicates that *some* piece of code is overwriting that value.

However, pcap_inject(), on systems with BPF, is:

static int
pcap_inject_bpf(pcap_t *p, const void *buf, size_t size)
{
int ret;

ret = write(p->fd, buf, size);
#ifdef __APPLE__

a bunch of code only used on OS X/iOS

#endif /* __APPLE__ */
if (ret == -1) {
snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send: %s",
pcap_strerror(errno));
return (PCAP_ERROR);
}
return (ret);
}

so it's not what's setting pseudo_AF_HDRCMPLT.

The offending code is in bpfwrite():

if (d->bd_hdrcmplt)
dst.sa_family = pseudo_AF_HDRCMPLT;

"dst" is handed to looutput() in sys/net/if_loop.c, which does

/* BPF writes need to be handled specially. */
if (dst->sa_family == AF_UNSPEC)
bcopy(dst->sa_data, &af, sizeof(af));
else
af = dst->sa_family;

The common code for Ethernet sends (ether_output()) explicitly handles both AF_UNSPEC *and* pseudo_AF_HDRCMPLT; the loopback driver needs to handle it as well, e.g. either

/* BPF writes need to be handled specially. */
if (dst->sa_family == pseudo_AF_HDRCMPLT)
bcopy(dst->sa_data, &af, sizeof(af));
else
af = dst->sa_family;

or

/* BPF writes need to be handled specially. */
if (dst->sa_family == pseudo_AF_HDRCMPLT || dst->sa_family == AF_UNSPEC)
bcopy(dst->sa_data, &af, sizeof(af));
else
af = dst->sa_family;

As the person who came across this bug, you should file a bug on this; if you can, CC me on it, or, if not, let me know what bug ID it gets assigned so that I can try to CC myself on it.
Fernando Gont
2014-06-15 20:56:34 UTC
Permalink
Hi, Guy,

First of all, thanks so much for your help and detailed explanation! --
I really appreciate it...
Post by Guy Harris
Post by Fernando Gont
which would seem to indicate that pcap_inject() is overwriting the
value I set with something else (pseudo_AF_HDRCMPLT?).
It indicates that *some* piece of code is overwriting that value.
Yep. Apologies for being sloppy....


[....]
Post by Guy Harris
/* BPF writes need to be handled specially. */ if (dst->sa_family ==
pseudo_AF_HDRCMPLT || dst->sa_family == AF_UNSPEC)
bcopy(dst->sa_data, &af, sizeof(af)); else af = dst->sa_family;
As the person who came across this bug, you should file a bug on
this; if you can, CC me on it, or, if not, let me know what bug ID it
gets assigned so that I can try to CC myself on it.
I will certainly file a bug report, and CC you. My understanding is that
this should be filled in most (if not all) of the BSD variants? (because
besides the error message one obtains, it seems that in several flavors
of them, pcap_inject() fails for the same reason).

Thanks!

Best regards,
--
Fernando Gont
e-mail: ***@gont.com.ar || ***@si6networks.com
PGP Fingerprint: 7809 84F5 322E 45C7 F1C9 3945 96EE A9EF D076 FFF1
Guy Harris
2014-06-16 09:50:04 UTC
Permalink
Post by Fernando Gont
I will certainly file a bug report, and CC you. My understanding is that
this should be filled in most (if not all) of the BSD variants? (because
besides the error message one obtains, it seems that in several flavors
of them, pcap_inject() fails for the same reason).
NetBSD, OpenBSD, and Dragonfly BSD appear not to even have the

/* BPF writes need to be handled specially. */
if (dst->sa_family == AF_UNSPEC)
bcopy(dst->sa_data, &af, sizeof(af));
else
af = dst->sa_family;

code, so

/* BPF writes need to be handled specially. */
if (dst->sa_family == pseudo_AF_HDRCMPLT)
bcopy(dst->sa_data, &af, sizeof(af));
else
af = dst->sa_family;

code needs to be added, and the subsequent switch needs to be changed from

switch (dst->sa_family) {

to

switch (af) {

with a

u_int32_t af;

added to looutput().

Darwin's code path is very different, and I haven't followed the twisty little maze of code paths into xnu:bsd/net/dlil.c and through if_loop.c to see whether this bug exists or not (and haven't written code to test it).
Guy Harris
2014-06-16 10:17:41 UTC
Permalink
Post by Fernando Gont
I will certainly file a bug report, and CC you. My understanding is that
this should be filled in most (if not all) of the BSD variants? (because
besides the error message one obtains, it seems that in several flavors
of them, pcap_inject() fails for the same reason).
NetBSD, OpenBSD, and Dragonfly BSD appear not to even have the ...
...and OpenBSD may need to do

/* BPF writes need to be handled specially. */
if (dst->sa_family == pseudo_AF_HDRCMPLT) {
bcopy(dst->sa_data, &af, sizeof(af));
af = ntohl(af);
} else
af = dst->sa_family;

as its loopback device has a DLT_ of DLT_LOOP rather than DLT_NULL and, with DLT_LOOP, the 4-byte AF_ header of the packet is in *network* byte order rather than *host* byte order.
Loading...