Monday, May 26, 2014

Packet Generation at Layer 2

Packet generation / reception

Looking at different ways to generate the three basic types of layer-2 Ethernet traffic on a wired network:

1. Unicast: destination MAC address to a specific NIC
2. Multicast: destination MAC address starting with 01:00:5e
3. Broadcast: destination MAC address that is ff:ff:ff:ff:ff:ff

I found some tools that work well to send/receive various types of traffic.

 

 Background

Working on some course material for Wireshark, being able to create these three traffic types is useful to test various concepts related to

1. Promiscuous mode
2. IGMP snooping
3. Switching/bridging
4. Hubs
5. Broadcast domains
6. How CPU load varies with traffic type
7. OS and driver differences

 

Some tools

I categorize packet creation utilities into two broad categories - those that are raw packet generators, and those that utilize host services.  For instance, some tools will just create a raw frame and put it on the wire, so all fields must be defined.  This is an example of what a raw packet generator might do.  There are no OS defaults, as their really is no interaction with the host OS.  For instance, the typical programmer might decide to send data to another host, and would select that host by either hostname or IP address.  Even if a host name is used, DNS (or hosts file) will be used to lookup the IP address, so in either case, data is sent to an IP address.  However, with the next hop model of Ethernet and TCP/IP, to actually forward this frame along to another host some MAC address is required, so the sending host OS will lookup the destination IP in it's route table and determine the next hop.  To find the MAC address of the next hop, the sending host OS will usually use ARP to determine the MAC for a given IP address.  With the raw packet generation tools, none of this support infrastructure works - there is no DNS lookup, no route tables to consult, no ARP protocol with cache support, etc.

Contrast this with other tools that utilize some of the host OS's services.  Many of these are for packet generation, but will utilize host services to varying degrees to actually send and/or receive frames.  This includes use of ARP and the ARP cache, the host route table and gateways, etc.  

These lists are not exhaustive; they are just some of the tools that I have used with varying degrees of success.  Indeed, a google search will yield MANY options to send test data on a network for testing.

 

Pure Packet Generators

Ostinato - this is nice, and works on Windows and Linux.  Creates custom packets and can define streams to send.  Obviously limited to system resources, so really happy frame rates are difficult to sustain depending on PC hardware.  Concept of interface selection is not that obvious, either.  I have only used with the GUI, not sure if anything else is available.  Supports sending packets from a pcap file, but struggles with a file of any real size.  

packETH - similar to Ostinato, but looks native to Linux (there may be ports, but don't know how fresh they are for other OSs.)  Rather simple to use, and has GUI or CLI capability, and has capability to read pcap files (functionality not tested).

Colasoft Packet Builder - free Windows tool.

Smartbits, IXIA, and other hardware tools - these solutions tend to be the most expensive, but are purposed designed for this type of operation so have great capabilities.  Always nice to have one of these if you can fit it into the budget.

Bit-Twist - multi-OS support and will easily send pcap capture file packets on to the wire; actually this s my preferred tool for capture file replay.  Includes tool to edit capture files - say you want to change all the destination MAC addresses in a pcap trace file to replay them to a different host: this will allow us to easily make these types of changes.  Note that replay of TCP really is not effective without significant support that I have not seen in any of these tools (it may exist, but I have not seen nor verified it for replay).

 

Generators that utilize host OS services

netcat, ncat, nc - tool for sending and receiving either unicast or multicast traffic.  Would not work with broadcast traffic.  All these tools do so much more than my specific needs for this project so a search of the various features based on what you need is recommended.

iperf/jperf - command line (or Java GUI with jperf, which is recommended as it has graphing capability) for testing performance.  While doing performance testing over Ethernet for unicast or multicast, it is sending packets so could be used as a packet generator depending on what is required: if only layer 2 destination generation is important, than it could fit the bill.  If more customization is needed, then it might not work.  This runs on nearly all platforms, including Windows, Linux, RaspberryPi w/ Pidora, Android tablets and phones, Mac OS X...

hping3 - CLI tool to send and receive packets.  Functionally flexible, but has a somewhat unique capability to send unicast, multicast, and broadcast traffic.  Also has listener services, but these have never been tested here.

socat - CLI tool for Linux that makes a great generic server.  Will listen on a port and accept unicast, multicast or broadcast traffic and echo the contents to the shell.  The broadcast reception capability seems to be somewhat unique.

 

Test Setup



To see how other hosts might view the layer-2 test traffic under various configurations, we can attach other devices to the L2 switch and run Wireshark or other packet sniffing tool (tcpdump, OmniPeak, etc.).

On the server side, to be able to receive all three types of layer-2 traffic - unicast, multicast, or broadcast - we use the socat command:

[root]# socat - UDP4-RECV:54321,ip-add-membership=224.10.20.30:0.0.0.0,broadcast

and we can see an IGMP join is generated, for this group:


This command will accept data from UDP port 54321, whether it is sent via layer-2 unicast, multicast or broadcast.  Some diagnostic commands to see how things are going.  First, what multicast groups is the pidora server now listening to:

[root@pidora ~]# netstat -g
IPv6/IPv4 Group Memberships
Interface       RefCnt Group
--------------- ------ ---------------------
lo              1      all-systems.mcast.net
eth0            1      224.10.20.30
eth0            1      all-systems.mcast.net
lo              1      ff02::1
lo              1      ff01::1
eth0            1      ff02::1:ff0f:8b09
eth0            1      ff02::1

eth0            1      ff01::1

What UDP port is the pidora server listening on:

[root@pidora ~]# netstat -lnu
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State      
udp        0      0 0.0.0.0:46359           0.0.0.0:*                          
udp        0      0 0.0.0.0:54321           0.0.0.0:*                          
udp        0      0 127.0.0.1:323           0.0.0.0:*                          
udp        0      0 0.0.0.0:68              0.0.0.0:*                          
udp        0      0 0.0.0.0:123             0.0.0.0:*                          
udp6       0      0 ::1:323                 :::*                               
udp6       0      0 :::3690                 :::*                               
udp6       0      0 :::123                  :::*                           
                          
Now on the client side, we need different commands to create the different traffic streams.  If we use a pure traffic generator, we have to fill in all the information: source and destination MAC and IP addresses, select packet types, etc.  If we use a tool that can utilize host services, we need to provide less information.  As the command will utilize the routing table and ARP services/cache, we just need to worry about layer-3 information and above (destination IP, UDP port, etc.).

To create unicast traffic from the client:

[george@clt]$ hping3 192.168.10.101 -2 -c 100 -i u10000 -p 54321 -s 1025 -k -e 1
[open_sockraw] socket(): Operation not permitted
[main] can't open raw socket

Obviously this command results in an error - we need to be root:

[root@clt]# hping3 192.168.10.101 -2 -c 100 -i u10000 -p 54321 -s 1025 -k -e 1
HPING 192.168.10.101 (p16p1 192.168.10.101): udp mode set, 28 headers + 1 data bytes
[main] memlockall(): Success

Some of the options used:

Destination IP: 192.168.10.101
-2 for UDP mode
-c 100 as packet count, send 100 packets
-i u10000 as packet send delay, in microseconds, so send a packet every 10ms
-p 54321 is UDP destination port 
-s 1025 is UDP source port
-k is to fix the source port - if not used, each packet sent will increment source port by 1
-e 1 is the data to send - so the UDP segment will contain an ASCII value of 1, or 0x31

So this is better - we can now see traffic flow across the network, and the console prints out '1' on the pidora server side.  Note the display of '1's as packets come in - socat will display the UDP data sent with the -e switch as part of the hping3 command:

[root]# socat - UDP4-RECV:54321,ip-add-membership=224.10.20.30:0.0.0.0,broadcast
11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111

Note that the hping3 command gives frequent segmentation faults when running on this platform (Fedora20 in a VirtualBox VM, on a MacBook host with bridged networking to the Apple thunderbolt GigE adapter).

To create multicast traffic:

[root@clt]# hping3 224.10.20.30 -2 -c 100 -i u10000 -p 54321 -s 1025 -k -e 2
HPING 224.10.20.30 (p16p1 224.10.20.30): udp mode set, 28 headers + 1 data bytes
[main] memlockall(): Success

The only difference is we send an ASCII '2' as the data this time, as well as the destination IP address.  Note that since we are using a tool that can use OS services, specifying the IP as multicast will cause the packet to be generated to have the correct multicast MAC, per the RFC.  It does not need to be specified as the Linux kernel on the client knows how to do this, and will do it for us.  Also for broadcast traffic:

[root@clt]# hping3 192.168.10.255 -2 -c 100 -i u10000 -p 54321 -s 1025 -k -e 3
HPING 192.168.10.255 (p16p1 192.168.10.255): udp mode set, 28 headers + 1 data bytes
[main] memlockall(): Success

sending an ASCII '3' with this data set, and choosing a subnet broadcast address.  The host OS will map this subnet local broadcast IP address to a broadcast MAC of ff:ff:ff:ff:ff:ff.  Subnet local broadcast is defined by the IP address and the subnet mask, where the subnet mask here is class C, \24 or 255.255.255.0.  And the results from the server:

[root]# socat - UDP4-RECV:54321,ip-add-membership=224.10.20.30:0.0.0.0,broadcast
111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111122222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222223333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333

Here we can see all three packet type were accepted by the presence of the ASCII data sent.  

The broadcast address used is the subnet broadcast.  The Linux system client has two interfaces, and if the general broadcast address is used, I could not generate traffic, even if I specify the interface. Disabling the interface not used in the test: 

[root@clt]# ifconfig p7p1 down

allows this command to now work:

[root@clt]# hping3 255.255.255.255 -2 -c 100 -i u10000 -p 54321 -s 1025 -k -e 4
HPING 255.255.255.255 (p16p1 255.255.255.255): udp mode set, 28 headers + 1 data bytes
[main] memlockall(): Success

With these results:

[root]# socat - UDP4-RECV:54321,ip-add-membership=224.10.20.30:0.0.0.0,broadcast
1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222233333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333334444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444

Wireless

This proved to be much more difficult.  We need capability for packet injection, and required specific hardware support and the right software tools.  Next time, we will show how to inject wireless packets on Windows and Linux, and show some of the issues present when doing so.  Also up for discussion is the concept of sniffing traffic on 802.11 wireless interfaces, which can be challenging.