When working with quality of service configurations you’ll inevitably come across the need to perform packet markings with DSCP. With routers this is generally fairly simple. Performing the same function on a host is not always that simple. All the socket API’s were designed around type of service (ToS),as defined in RFC791, rather than DSCP as defined in RFC2474.
If you’re in a hurry, the conversion is simply ToS = DSCP * 4. If you have the time the rfc’s are full of interesting information. The DSCP field with the DS field contains six bits allowing for 64 possible codepoint values. RFC2474 defines 3 pools of DSCP values, one for standardised use and the other two for local/experimental use. The standardised pool has the least significant bit set to 0, which means only the even numbers from 0 to 62 are used. A cheat sheet with the standardised DSCP values and equivalent IP precedence and ToS values can be found here.
We can test the ToS/DSCP mapping using the ping program and specifying a ToS byte value. Using the windows ping program we specify the ToS byte as a numeric argument to the -v command line switch. In this example we specify the the ToS byte as 136 which corresponds to a DSCP value of 34 or AF41.
ping -n 1 -v 136 http://www.google.com
Performing a similar test for tcp connection requires a little bit of coding effort. Listing 1 shows some c# code to do a simple get request to http://www.google.com.au, using the SetSocketOption function to set the ToS byte to 136. The wireshark output for both tests is shown below. The lua script shown in listing 2 was used to extract the diffserv field and dscp values while running the capture with Tshark. It is worth noting that even though the socketoption is set prior to the connection, no dscp values are set on the two packets from the client during the TCP three way handshake (frame 5 and 7 below).
tshark -X lua_script:getdscp.lua -i 2 host http://www.google.com.au
Frame #1 Diffserv Field: 136 DSCP: 34
192.168.0.7 -> 74.125.19.103 ICMP Echo (ping) request
Frame #2 Diffserv Field: 0 DSCP: 0
74.125.19.103 -> 192.168.0.7 ICMP Echo (ping) reply
Frame #3 Diffserv Field: 136 DSCP: 34
192.168.0.7 -> 74.125.19.103 ICMP Echo (ping) request
Frame #4 Diffserv Field: 0 DSCP: 0
74.125.19.103 -> 192.168.0.7 ICMP Echo (ping) reply
Frame #5 Diffserv Field: 0 DSCP: 0
192.168.0.7 -> 74.125.19.103 TCP linx > http [SYN] Seq=0 Win=16384 Len=0 MSS=1260
Frame #6 Diffserv Field: 0 DSCP: 0
74.125.19.103 -> 192.168.0.7 TCP http > linx [SYN, ACK] Seq=0 Ack=1 Win=5720 Len=0 MSS=1430
Frame #7 Diffserv Field: 0 DSCP: 0
192.168.0.7 -> 74.125.19.103 TCP linx > http [ACK] Seq=1 Ack=1 Win=17640 Len=0
Frame #8 Diffserv Field: 136 DSCP: 34
192.168.0.7 -> 74.125.19.103 HTTP GET / HTTP/1.0
Frame #9 Diffserv Field: 0 DSCP: 0
74.125.19.103 -> 192.168.0.7 TCP http > linx [ACK] Seq=1 Ack=41 Win=5720 Len=0
Frame #10 Diffserv Field: 0 DSCP: 0
74.125.19.103 -> 192.168.0.7 TCP [TCP segment of a reassembled PDU]
Frame #11 Diffserv Field: 0 DSCP: 0
74.125.19.103 -> 192.168.0.7 TCP [TCP segment of a reassembled PDU]
Frame #12 Diffserv Field: 136 DSCP: 34
192.168.0.7 -> 74.125.19.103 TCP linx > http [ACK] Seq=41 Ack=2521 Win=17640 Len=0
Frame #13 Diffserv Field: 0 DSCP: 0
74.125.19.103 -> 192.168.0.7 TCP [TCP segment of a reassembled PDU]
Frame #14 Diffserv Field: 0 DSCP: 0
74.125.19.103 -> 192.168.0.7 TCP [TCP segment of a reassembled PDU]
Frame #15 Diffserv Field: 136 DSCP: 34
192.168.0.7 -> 74.125.19.103 TCP linx > http [ACK] Seq=41 Ack=5041 Win=17640 Len=0
Frame #16 Diffserv Field: 0 DSCP: 0
74.125.19.103 -> 192.168.0.7 TCP [TCP segment of a reassembled PDU]
Frame #17 Diffserv Field: 0 DSCP: 0
74.125.19.103 -> 192.168.0.7 HTTP HTTP/1.0 200 OK (text/html)
Frame #18 Diffserv Field: 136 DSCP: 34
192.168.0.7 -> 74.125.19.103 TCP linx > http [ACK] Seq=41 Ack=6611 Win=17640 Len=0
Frame #19 Diffserv Field: 136 DSCP: 34
192.168.0.7 -> 74.125.19.103 TCP linx > http [FIN, ACK] Seq=41 Ack=6611 Win=17640 Len=0
Frame #20 Diffserv Field: 0 DSCP: 0
74.125.19.103 -> 192.168.0.7 TCP http > linx [ACK] Seq=6611 Ack=42 Win=5720 Len=0
Listing 1
using System;
using System.Text;
using System.Net.Sockets;
namespace tcptos
{
class Program
{
public static void Main(string[] args)
{
Console.WriteLine("Testing DSCP packet marking.Wireshark should already be running!\n");
TcpClient cli = new TcpClient();
cli.Client.SetSocketOption(SocketOptionLevel.IP,
SocketOptionName.TypeOfService, 136);
cli.Connect("www.google.com.au",80);
byte[] buf = Encoding.ASCII.GetBytes("GET / HTTP/1.0\nHost: www.google.com.au\n\n");
byte[] readbuf = new byte[4096];
int bytesRead;
StringBuilder response = new StringBuilder();
NetworkStream mystream = cli.GetStream();
mystream.Write(buf,0,buf.Length);
do{
bytesRead = mystream.Read(readbuf, 0, readbuf.Length);
response.AppendFormat("{0}", Encoding.ASCII.GetString(readbuf, 0, bytesRead));
}
while(bytesRead > 0);
Console.Write(response.ToString());
Console.Write("\nPress any key to continue . . . ");
Console.ReadKey(true);
cli.Close();
}
}
}
Listing 2
local dsfield = Field.new("ip.dsfield")
local dscp = Field.new("ip.dsfield.dscp")
local fnum = Field.new("frame.number")
do
packets = 0;
local function init_listener()
local tap = Listener.new("frame","ip.version == 4")
function tap.reset()
end
function tap.packet(pinfo,tvb,ip)
local fnumber = tostring(fnum())
local diffserv = tostring(dsfield())
local codepoint = tostring(dscp())
local stroutput = "\nFrame #" .. fnumber .. "\tDiffserv Field: " ..
diffserv .. "\tDSCP: " ..codepoint
print(stroutput)
end
function tap.draw()
end
end
init_listener()
end