Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 21 Oct 1998 07:15:19 +0930
From:      Leigh Hart <hart@dotat.com>
To:        beekey@clark.net
Cc:        freebsd-hackers@FreeBSD.ORG
Subject:   Re: bpf write overwrites link level header? 
Message-ID:  <199810202145.HAA07214@at.dotat.com>
In-Reply-To: Your message of "Tue, 20 Oct 1998 12:16:16 -0400." <362CB750.5ECC@clark.net> 

next in thread | previous in thread | raw e-mail | index | archive | help
Hi Beekey,

beekey@clark.net wrote:
>
> I'm currently working on some code that generates raw TCP/UDP packets. 
> using the write capability of bpf to dump them onto the wire.  Based on
> tcpdump output from another machine, they appear to be constructed with
> proper IP and TCP or UDP headers.  
> 
> However, somewhere in the depths, despite my building the Ethernet
> header and specifying both MAC addresses, the packets always end up on
> the wire with the sending host's correct source MAC address, rather than
> the one I specified in the code (yes the source IP is being spoofed and
> it comes out correct).  Looking briefly at the code in
> /usr/src/sys/net/bpf.c, it appears that bpf may add its own link level
> header.

It isn't bpf.c - read on.

> Anyone have any experience or fixes/workarounds for this?  I don't think
> that it is a NIC limitation due to some testing under NT.

I havn't got a recent enough kernel to give you a patch, but in if you
look in /sys/net/if_ethersubr.c in the function ether_output() a switch
statement determines which protocol family you are trying to transmit a
frame from, but when you are writing a raw frame via the bpf interface,
the family is set to AF_UNSPEC - and there it copies the ether_dhost
from the packet you wish to send into the edst variable, and when the
code below the switch then does the final sending of the packet, it
inserts your outbound interface's MAC address into the frame src fild
and puts the packet into the outgoing queue.

You need to change (roughly) this code:

        case AF_UNSPEC:
                eh = (struct ether_header *)dst->sa_data;
                (void)memcpy(edst, eh->ether_dhost, sizeof (edst));
                type = eh->ether_type;
                break;

into this

        case AF_UNSPEC:
                eh = (struct ether_header *)dst->sa_data;
                (void)memcpy(edst, eh->ether_dhost, sizeof (edst));
                (void)memcpy(esrc, eh->ether_shost, sizeof (esrc));
                type = eh->ether_type;
                break;

Don't forget to declare esrc at the beginning of the function, the
same type as edst.

Then change this, a bit further down

        (void)memcpy(eh->ether_dhost, edst, sizeof (edst));
        (void)memcpy(eh->ether_shost, ac->ac_enaddr,
            sizeof(eh->ether_shost));

into

        (void)memcpy(eh->ether_dhost, edst, sizeof (edst));
	if(dst->sa_family==AF_UNSPEC)
		(void)memcpy(eh->ether_shost, esrc, sizeof(esrc));
	else
		(void)memcpy(eh->ether_shost, ac->ac_enaddr,
		    sizeof(eh->ether_shost));

This will only affect AF_UNSPEC frames, which should leave all the
other protocols alone :-)

Cheers

Leigh
-- 
| "By the time they had diminished | Leigh Hart, <hart@dotat.com> |
|  from 50 to 8, the other dwarves | Dotat Communications Pty Ltd |
|  began to suspect 'Hungry' ..."  | GPO Box 487 Adelaide SA 5001 |
|   -- Gary Larson, "The Far Side" |  http://www.dotat.com/hart/  |

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-hackers" in the body of the message



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199810202145.HAA07214>