Click here to Skip to main content
15,891,529 members
Articles / Programming Languages / C#
Article

Raw Ethernet Packet Sending

Rate me:
Please Sign up or sign in to vote.
4.92/5 (86 votes)
24 Oct 20035 min read 580.6K   10.6K   150   135
This article explains how to send a raw Ethernet packet using C# and a NDIS Protocol Driver.

Sample Image - "SendRawPacket.jpg

Introduction

This purpose of this article is to explain how to send a raw Ethernet packet using C# on a Microsoft platform. A raw Ethernet packet is the complete Layer 2 network frame that is sent to the physical wire. Sending a frame like this allows you to manipulate the target and source MAC addresses and the Layer 3 protocol fields.

Background

You may be thinking, "Why would anyone want to do this?". Well, I was trying to create an application (using C#) that would make a typical Windows computer with 2 NICs act as a Layer 2 Network device. My goal was to listen for packets on a network interface and send the exact same packet out of the opposite interface, basically a packet repeater. To do this, I needed to be able to read a raw Ethernet packet (easy) and then write that same raw Ethernet packet (difficult). The sent packet needed to be exactly like the read packet, Ethernet header and all. I did a great deal of research online, and did not find a whole lot of info, just a few hints here and there.

The first problem was that Windows does not include a way to programmatically send a raw Ethernet packet. After some research, I realized that I needed to create a NDIS Protocol Driver (PassThru and Intermediate drivers will also work) to interface with the network adapters at a very low level. Luckily, the Windows Driver Development Kits (DDKs) included samples that would accomplish this for me. Great, the hard part down right......yeah, that is what I thought too. Now I had to interface with the driver from managed C# code.

Well, enough of the background.....on to the code.....

Part 1 - NDIS Protocol Driver

So, like I said, the DDK provides a suitable NDIS driver for sending raw packets. I compiled this, creating the .inf and .sys files for the driver (I have included the compiled driver, altered to fit my needs, in the attached zip file). After running a few test, I found that I could:

  1. Only receive packets destined for me and
  2. I could only send packets with a source address of my adapter.

Well, this was not acceptable. I needed to receive any packets on my LAN segment, and send those same packets regardless of the source address. So after looking through the driver code, I figured out how to accomplish that.

To receive any packets, the driver had to be set to Promiscuous mode. The following code segment was what was altered to accomplish this.

// ndisprot.h
// line 177
// Add NDIS_PACKET_TYPE_PROMISCUOUS to support promiscuous mode reading

#define NUIOO_PACKET_FILTER  (NDIS_PACKET_TYPE_DIRECTED|    \
                              NDIS_PACKET_TYPE_MULTICAST|   \
                              NDIS_PACKET_TYPE_BROADCAST|   \
                              NDIS_PACKET_TYPE_PROMISCUOUS)     // **Added**

To send any packets, the following code segment had to be commented out

// send.c
// line 136
// Comment out to support sending packets from any MAC source address

     // To prevent applications from sending packets with spoofed
     // mac address, we will do the following check to make sure the source 
     // address in the packet is same as the current MAC address of the NIC.
     //
     if ((pIrp->RequestorMode == UserMode) && 
          !NPROT_MEM_CMP(pEthHeader->SrcAddr, 
          pOpenContext->CurrentAddress, NPROT_MAC_ADDR_LEN))
     {
            DEBUGP(DL_WARN, ("Write: Failing with invalid Source address"));
            NtStatus = STATUS_INVALID_PARAMETER;
            break;
     }

Once those changes were made, the NDIS Driver performed perfect for what I needed.

Part 2 - C# RawEthernet Application

The code for the RawEthernet application is commented fairly well, so I am not going to go into a lot of detail on the code here. I am just going to highlight the important steps in the code.

Writing information to a device driver is somewhat similar to writing to a file. We open the driver file by calling the CreateFile API. This returns a handle that we can use to write to and read from the driver. Next, we can bind the driver handle to a specific adapter by using the DeviceIoControl API. Binding the adapter lets us access the NDIS Driver on a specific network adapter. After all this, the writing is simple. We use the WriteFile API. The ReadFile API can be used in a similar manner to read incoming network data as well.

To send a packet, we have to create a byte representation on the packet that we want to send. The following shows the Ethernet header (first 14 bytes of packet) in byte format

DD DD DD DD DD DD SS SS SS SS SS SS PP PP <data follows>
  • D = Destination MAC Address
  • S = Source MAC Address
  • P = Next Layer Protocol (0800 = IP)

You can use a packet sniffer (Ethereal, Snoop, EtherPeeks) to verify that you are sending a raw data packet on the network medium. The packet that this application currently sends is a very simple data packet that served no purpose other than to show the concept. This can easily be changed to reflect a real packet, such as a ping or anything else that you can think of.

Running the sample

NDIS Driver

You can install the NDIS Driver by opening your network adapter properties and clicking the "Install" button, selecting "Protocol", and then choosing "Have Disk". Then browse to the .inf file and click "OK". This will then load the driver onto every adapter that you have in your system.

Important - Make sure that it is enabled, there should be a check in the box next to "Raw Packet NDIS Protocol Driver".

Important - Open a command prompt and type "net start ndisprot" to start the driver service.

Note - The beauty of having this driver is that you can disable every other protocol in the Adapter's protocol list (i.e. Internet Protocol) and you will still be able to send and receive packets. Your machine will not even have an address, but because we are working at Layer 2, you don't need one. (This driver will work even if you keep all of the other protocols enabled)

RawEthernet application

The zip file contains the source and compiled binary for the RawEthernet application. Once the driver is installed and enabled, simply run the EXE to see the packets being sent.

Other items

I have been working on getting this to work asynchronously so that I can send and receive on the same adapter at the same time. When I get some more time, I will put out an article on how async file works.

That is about it for now...if you have any questions or comments, feel free to contact me.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
United States United States
MCSE, MCSD, MCDBA, CCNA

Comments and Discussions

 
GeneralCE version Pin
lupolupin10-Jun-05 6:10
lupolupin10-Jun-05 6:10 
GeneralError 127 Urgent Pin
Mohan vijay10-Jun-05 1:31
Mohan vijay10-Jun-05 1:31 
GeneralRe: Error 127 Urgent Pin
Anonymous10-Jun-05 5:21
Anonymous10-Jun-05 5:21 
GeneralRe: Error 127 Urgent Pin
Anonymous10-Jun-05 18:05
Anonymous10-Jun-05 18:05 
GeneralRe: Error 127 Urgent Pin
Mohan vijay13-Jun-05 21:00
Mohan vijay13-Jun-05 21:00 
GeneralRe: Error 127 Urgent Pin
GapDragon19-Oct-05 6:48
GapDragon19-Oct-05 6:48 
Questionhow to get iocontrol code constants ? Pin
knopper13-Apr-05 6:08
knopper13-Apr-05 6:08 
AnswerRe: how to get iocontrol code constants ? Pin
Anonymous15-Aug-05 7:21
Anonymous15-Aug-05 7:21 
GeneralIPSec implementation Pin
Member 16237861-Jan-05 10:45
Member 16237861-Jan-05 10:45 
QuestionHow to read your ethernet address with this? Pin
Member 13449916-Sep-04 5:20
Member 13449916-Sep-04 5:20 
AnswerRe: How to read your ethernet address with this? Pin
pmarth3-Jan-05 6:52
pmarth3-Jan-05 6:52 
Generalreceiving packets Pin
Albert Burbea5-Sep-04 3:43
Albert Burbea5-Sep-04 3:43 
GeneralRe: receiving packets Pin
Syst3m Crash3r 48025-Jun-06 20:07
Syst3m Crash3r 48025-Jun-06 20:07 
QuestionHow can I use this sample to receive any data Pin
xinxindotnet17-Jun-04 21:20
xinxindotnet17-Jun-04 21:20 
AnswerRe: How can I use this sample to receive any data Pin
Anonymous9-Nov-04 19:21
Anonymous9-Nov-04 19:21 
GeneralRe: How can I use this sample to receive any data Pin
Rajat Gogri21-Jun-05 23:10
Rajat Gogri21-Jun-05 23:10 
GeneralRe: How can I use this sample to receive any data Pin
A6un26-Mar-06 5:47
A6un26-Mar-06 5:47 
AnswerRe: How can I use this sample to receive any data Pin
Eduard Gomolyako15-May-06 6:38
Eduard Gomolyako15-May-06 6:38 
GeneralRe: How can I use this sample to receive any data Pin
Syst3m Crash3r 48027-Jun-06 3:16
Syst3m Crash3r 48027-Jun-06 3:16 
GeneralRe: How can I use this sample to receive any data Pin
Jakke2k28-Jun-06 9:30
Jakke2k28-Jun-06 9:30 
Generalhack Pin
Taha Elsayed14-Jun-04 15:48
Taha Elsayed14-Jun-04 15:48 
GeneralCreatefile Code snippets Pin
toor24-May-04 21:07
toor24-May-04 21:07 
GeneralRe: Createfile Code snippets Pin
Nigel de Costa26-May-04 20:20
Nigel de Costa26-May-04 20:20 
GeneralOpening NDIS device from multiple applications Pin
Nigel de Costa24-May-04 5:20
Nigel de Costa24-May-04 5:20 
GeneralRe: Opening NDIS device from multiple applications Pin
Anonymous26-May-04 5:24
Anonymous26-May-04 5:24 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.