In an attempt to set DSCP bit on outgoing UDP packets, I used the QoS
Traffic control API and was successful.
The problem is that it works only for ALL outgoing UDP packets. I want to be
able to mark UDP packets going to a specific port only.
See the code for GenericFilter, where IP_PATTERN structure is filled in for
filtering only UDP packets for port 5000.
Is this a bug in QoS API or am I doing something wrong? All the help will be
appreciated.
Thanks.
#include <winsock2.h>
#include <ws2tcpip.h>
#include <qos.h>
#include <ntddndis.h>
#include <traffic.h>
#include <qossp.h>
#define IPPROTO_UDP 17
#include <tcerror.h> // for traffic control error codes
// Call back function for traffic control. We are not using it, but required
for API call.
void MyClNotifyHandler( HANDLE ClRegCtx,
HANDLE ClIfcCtx,
ULONG Event,
HANDLE SubCode,
ULONG BufSize,
PVOID Buffer
)
{
}
int main(int argc, char *argv[])
{
DWORD destPort;
PCHAR destAddress;
if ( argc == 3)
{
destAddress = argv[1];
destPort = atoi(argv[2]);
}
else
{
printf("Usage: %s destaddress destport", argv[0]);
exit (-1);
}
// Intialization of Winsock API
int err;
WSADATA WSAData;
// Startup Winsock
err = WSAStartup(MAKEWORD(2,2), &WSAData);
if (err)
{
printf("WSAStartup Failed (%d) Exiting\n", err);
exit(err);
}
/* ================================================== */
HANDLE ClientHandle;
HANDLE IfcHandle;
HANDLE flowHandle;
HANDLE FilterHandle;
// Initialize call back functions. We dont' need these, but is required for
TcRegisterClient API
TCI_CLIENT_FUNC_LIST QoSFunctions;
QoSFunctions.ClAddFlowCompleteHandler = NULL;
QoSFunctions.ClDeleteFlowCompleteHandler = NULL;
QoSFunctions.ClModifyFlowCompleteHandler = NULL;
QoSFunctions.ClNotifyHandler = (TCI_NOTIFY_HANDLER)MyClNotifyHandler;
// Register the client with Traffic control interface.
long result = TcRegisterClient(CURRENT_TCI_VERSION, NULL,
&QoSFunctions,&ClientHandle);
if (result == NO_ERROR)
{
TC_IFC_DESCRIPTOR InterfaceBuffer[12];
PTC_IFC_DESCRIPTOR pInterfaceBuffer = &InterfaceBuffer[0];
ULONG BufferSize = 12 * sizeof(TC_IFC_DESCRIPTOR);
// Find traffic control enabled interfaces on the cmachine
result = TcEnumerateInterfaces(ClientHandle, &BufferSize,
pInterfaceBuffer);
if (result == NO_ERROR)
{
if (BufferSize == 0)
{
printf("no traffic control interfaces are available\n");
}
TCHAR interfaceName[500];
// function maps a wide-character string to a new character string
WideCharToMultiByte(CP_ACP, 0,
InterfaceBuffer[0].pInterfaceName, -1,interfaceName, sizeof(interfaceName),
0, 0 );
// The TcOpenInterface function identifies and opens an interface based
on its text
// string, which is available from a call to TcEnumerateInterfaces
result = TcOpenInterface(interfaceName, ClientHandle, NULL, &IfcHandle);
if (result == NO_ERROR)
{
// Creating of Traffic flow headers
int curSize = sizeof (TC_GEN_FLOW )+ sizeof (QOS_DS_CLASS) +
sizeof(QOS_OBJECT_HDR);
char *bufFlow = new char[curSize];
PTC_GEN_FLOW newFlow = (PTC_GEN_FLOW) bufFlow;
// Create the new temp flow.
LPQOS_OBJECT_HDR objHdr = NULL;
//Set the Flow Spec
newFlow->ReceivingFlowspec.DelayVariation = QOS_NOT_SPECIFIED;
newFlow->ReceivingFlowspec.Latency = QOS_NOT_SPECIFIED;
newFlow->ReceivingFlowspec.MaxSduSize = QOS_NOT_SPECIFIED;
newFlow->ReceivingFlowspec.MinimumPolicedSize = QOS_NOT_SPECIFIED;
newFlow->ReceivingFlowspec.PeakBandwidth = QOS_NOT_SPECIFIED;
newFlow->ReceivingFlowspec.ServiceType =
SERVICETYPE_GUARANTEED;//SERVICETYPE_CONTROLLEDLOAD;
newFlow->ReceivingFlowspec.TokenBucketSize = QOS_NOT_SPECIFIED;
newFlow->ReceivingFlowspec.TokenRate = 10000;
newFlow->SendingFlowspec.DelayVariation = QOS_NOT_SPECIFIED;
newFlow->SendingFlowspec.Latency = QOS_NOT_SPECIFIED;
newFlow->SendingFlowspec.MaxSduSize = 344;
newFlow->SendingFlowspec.MinimumPolicedSize = 12;
newFlow->SendingFlowspec.PeakBandwidth = 32000;
newFlow->SendingFlowspec.ServiceType =
SERVICETYPE_GUARANTEED;//SERVICETYPE_CONTROLLEDLOAD;
newFlow->SendingFlowspec.TokenBucketSize = 680;
newFlow->SendingFlowspec.TokenRate = 10000; //a guess - set to MTU
newFlow->TcObjectsLength = sizeof QOS_DS_CLASS + sizeof QOS_OBJECT_HDR;
// Set DSCP.
LPQOS_DS_CLASS pQOSClass = (LPQOS_DS_CLASS)(&(newFlow->TcObjects[0]));
pQOSClass->ObjectHdr.ObjectType = QOS_OBJECT_DS_CLASS;
pQOSClass->ObjectHdr.ObjectLength = sizeof QOS_DS_CLASS;
pQOSClass->DSField = 0x2E;
objHdr = (LPQOS_OBJECT_HDR)((char *)&(newFlow->TcObjects[0]) +
sizeof(QOS_DS_CLASS));
// Set the end of the list
objHdr->ObjectType = QOS_OBJECT_END_OF_LIST;
objHdr->ObjectLength = sizeof QOS_OBJECT_HDR;
// adds a new flow on the specified interface. The flow is like a
channel,
// that determines how to shape the traffic if it tunnelled through it.
int retCode = TcAddFlow(IfcHandle, NULL, 0, newFlow, &flowHandle);
// Create a filter. All traffic matching the filter will pass through
the flow
TC_GEN_FILTER GenericFilter;
IP_PATTERN Pattern, Mask;
memset(&Pattern,0,sizeof(IP_PATTERN));
memset(&Mask,0,sizeof(IP_PATTERN));
GenericFilter.AddressType = NDIS_PROTOCOL_ID_TCP_IP; // Protocol stack
is TCP/IP
GenericFilter.PatternSize = sizeof(IP_PATTERN);
GenericFilter.Pattern = &Pattern; // pattern to match, defined below
GenericFilter.Mask = &Mask;
// Filter pattern. This is where you can tweak the flow filter
parameters
// configured to match on all outgoing UDP packets.
Pattern.Reserved1 = 0;
Pattern.Reserved2 = 0;
Pattern.SrcAddr = 0; //IP_ADDRESS(10,0,1,10);
Pattern.DstAddr = 0; //IP_ADDRESS(10,0,1,11);
Pattern.tcSrcPort = 0;
Pattern.tcDstPort = 5000;
Pattern.ProtocolId = IPPROTO_UDP; // UDP
Pattern.Reserved3[0] = 0;
Pattern.Reserved3[1] = 0;
Pattern.Reserved3[2] = 0;
// Patterns mask
Mask.Reserved1 = 0;
Mask.Reserved2 = 0;
Mask.SrcAddr = 0; //0xFFFFFFFF;
Mask.DstAddr = 0; //0xFFFFFFFF;
Mask.tcSrcPort = 0; //0xFFFF;
Mask.tcDstPort = 0xFFFF;
Mask.ProtocolId = 0xFF;
Mask.Reserved3[0] = 0;
Mask.Reserved3[1] = 0;
Mask.Reserved3[2] = 0;
// Add filter to the flow. This point onwards all traffic matching the
filter,
// will pass through the flow.
retCode = TcAddFilter(flowHandle, &GenericFilter, &FilterHandle);
if(retCode != NO_ERROR)
{
switch(retCode)
{
case ERROR_SIGNAL_PENDING:
printf("The function is being executed asynchronously; the client will
be called back through the client-exposed ClAddFlowComplete function when
the flow has been added or when the process has been completed.\n");
break;
case ERROR_INVALID_HANDLE:
printf("The interface handle is invalid.\n");
break;
case ERROR_NOT_ENOUGH_MEMORY:
printf("The system is out of memory.\n");
break;
case ERROR_INVALID_PARAMETER:
printf("A parameter is invalid.\n");
break;
case ERROR_INVALID_SERVICE_TYPE:
printf("An unspecified or bad INTSERV service type has been
provided.\n");
break;
case ERROR_INVALID_TOKEN_RATE:
printf("An unspecified or bad TOKENRATE value has been provided.\n");
break;
case ERROR_INVALID_PEAK_RATE:
printf("The PEAKBANDWIDTH value is invalid.\n");
break;
case ERROR_INVALID_SD_MODE:
printf("The SHAPEDISCARDMODE is invalid.\n");
break;
case ERROR_INVALID_QOS_PRIORITY:
printf("The priority value is invalid.\n");
break;
case ERROR_INVALID_TRAFFIC_CLASS:
printf("The traffic class value is invalid.\n");
break;
case ERROR_NO_SYSTEM_RESOURCES:
printf("There are not enough resources to accommodate the requested
flow.\n");
break;
case ERROR_TC_OBJECT_LENGTH_INVALID:
printf("Bad length specified for the TC objects.\n");
break;
case ERROR_INVALID_DIFFSERV_FLOW:
printf("Applies to Diffserv flows. Indicates that the QOS_DIFFSERV
object was passed with an invalid parameter.\n");
break;
case ERROR_DS_MAPPING_EXISTS:
printf("Applies to Diffserv flows. Indicates that the
QOS_DIFFSERV_RULE specified in TC_GEN_FLOW already applies to an existing
flow on the interface.\n");
break;
case ERROR_INVALID_SHAPE_RATE:
printf("The QOS_SHAPING_RATE object was passed with an invalid
ShapeRate.\n");
break;
case ERROR_INVALID_DS_CLASS:
printf("The QOS_DS_CLASS is invalid.\n");
break;
case ERROR_NETWORK_UNREACHABLE:
printf("The network cable is not plugged into the adapter.\n");
break;
}
printf("TcAddFlow: ERROR: %lu\n",retCode);
// printf("Handle was %d\n", (int)IfcHandle);
return -1;
}
//check flows
//EnumFlows(IfcHandle);
}
else
{
printf("TcOpenInterface returned 0x%x\n", result);
return -1;
}
}
else
{
switch(result)
{
case NO_ERROR:
printf("The function executed without errors.\n");
break;
case ERROR_INVALID_HANDLE:
printf("The client handle is invalid.\n");
break;
case ERROR_INVALID_PARAMETER:
printf("One of the parameters is NULL.\n");
break;
case ERROR_INSUFFICIENT_BUFFER:
printf("The buffer is too small to enumerate all interfaces. If this
error is returned, the correct (required) size of the buffer is passed back
in pBufferSize.\n");
printf("Size required: %d\n", BufferSize);
break;
case ERROR_NOT_ENOUGH_MEMORY:
printf("The system is out of memory.\n");
break;
}
printf("TcEnumerateInterfaces returned 0x%x\n", result);
return -1;
}
}
else
{
printf("TcRegisterClient returned 0x%x\n", result);
return -1;
}
// Create a normal UDP socket for sending data
SOCKET sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sd == INVALID_SOCKET)
{
err = GetLastError();
printf("\"Socket\" failed with error %d\n", err);
return 1;
}
SOCKADDR_IN destAddr;
memset (&destAddr, 0, sizeof(SOCKADDR_IN));
destAddr.sin_family = AF_INET;
destAddr.sin_port = htons(destPort);
destAddr.sin_addr.s_addr = inet_addr(destAddress); // this is our test
destination IP
char buf[1000];
int nRet;
nRet = sendto( sd, buf, 1000, 0, (sockaddr*)&destAddr,sizeof(SOCKADDR_IN));
// nRet should have the number of bytes successfully sent.
//char buff[1000];
//scanf("%s",buff);
// CLEANUP
result = TcDeleteFilter(FilterHandle);
if (result != NO_ERROR)
{
printf("Error deleting filter\n");
}
// Delete flow associated with the network interface
result = TcDeleteFlow(flowHandle);
if (result != NO_ERROR)
{
printf("Error deleting flow\n");
}
// Close the Traffic control interface opened earlier.
result = TcCloseInterface(IfcHandle);
if (result != NO_ERROR)
{
switch(result)
{
case ERROR_INVALID_HANDLE:
printf("The interface handle is invalid.\n");
break;
case ERROR_TC_SUPPORTED_OBJECTS_EXIST:
printf("Not all flows have been deleted for this interface.");
}
printf("Error closing interface\n");
}
// Unregister the client.
result = TcDeregisterClient(ClientHandle);
if (result != NO_ERROR)
{
switch(result)
{
case ERROR_INVALID_HANDLE:
printf("Invalid interface handle, or the handle was set to NULL.\n");
break;
case ERROR_TC_SUPPORTED_OBJECTS_EXIST:
printf("Interfaces are still open for this client. all interfaces must be
closed to deregister a client.\n");
}
printf("Error degresitering client\n");
}
// shutdown the socket
shutdown(sd, SD_BOTH);
closesocket(sd);
WSACleanup();
return 0;
}
--
Imran Ali Rashid
"Imran Ali Rashid" <imran....@online.nospam> wrote in message
news:0134031E-75D7-4C9B...@microsoft.com...
Yes, we had a look at your posting in the Platform Ng Group. I believe you
asked us to specify the source port as well. We're going to try that however
we were wondering if there was a way to catch all packets without the need
to specify the source port?
On your crosspost comment, I posted to this group separately as I realized
(after a little while) that we had posted to a non-managed newsgroup
(reference: http://msdn.microsoft.com/newsgroups/managed/). If I was
planning to post to 2 groups, I would have crossposted. Thanks for the note
though.
Regards,
Imran Ali Rashid
"Arkady Frenkel" <ark...@hotmailxdotx.com> wrote in message
news:O4%23l5w06...@TK2MSFTNGP12.phx.gbl...
"Imran Ali Rashid" <imran....@online.nospam> wrote in message
news:OB25PE16...@TK2MSFTNGP11.phx.gbl...
Thanks,
Rhett Gong [MSFT]
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security
http://support.microsoft.com/default.aspx?scid=/servicedesks/msdn/nospam.asp&SD=msdn
This posting is provided "AS IS" with no warranties and confers no rights.
Sorry about the late reply. Just thought I would post the following in case
it ever helps anyone.
I never actually got down to solving this problem, however a colleague of
mine managed to solve it. He mentioned that the destination port specified in
the filter needs to be different in terms of big and little endian.
So, this line: Pattern.tcDstPort = 5000;
should be: Pattern.tcDstPort = 0x8813;
Note: I haven't personally verified this solution. If anyone does, please do
let the group know.
Regards,
Imran Ali Rashid
Pattern.tcDstPort = htons(5000);
--
=====================================
Alexander Nickolov
Microsoft MVP [VC], MCSD
email: agnic...@mvps.org
MVP VC FAQ: http://www.mvps.org/vcfaq
=====================================
"Imran Ali Rashid" <imran....@online.nospam> wrote in message
news:4FB0A9EC-B470-4AE9...@microsoft.com...
Best Regards,
Terry Fei [MSFT]
Microsoft Community Support
Get Secure! www.microsoft.com/security
(This posting is provided "AS IS", with no warranties, and confers no
rights.)
--------------------
>Thread-Topic: Problem QoS Traffic API - Setting Filter
>thread-index: AcYbc3veFLHlidaPRxq33zBVeyWACg==
>X-WBNR-Posting-Host: 202.142.180.1
>From: "=?Utf-8?B?SW1yYW4gQWxpIFJhc2hpZA==?=" <imran....@online.nospam>
>References: <0134031E-75D7-4C9B...@microsoft.com>
<O4#l5w06F...@TK2MSFTNGP12.phx.gbl>
<OB25PE16...@TK2MSFTNGP11.phx.gbl>
>Subject: Re: Problem QoS Traffic API - Setting Filter
>Date: Tue, 17 Jan 2006 06:37:04 -0800
>Lines: 17
>Message-ID: <5D04115E-33E1-4C50...@microsoft.com>
>MIME-Version: 1.0
>Content-Type: text/plain;
> charset="Utf-8"
>Content-Transfer-Encoding: 7bit
>X-Newsreader: Microsoft CDO for Windows 2000
>Content-Class: urn:content-classes:message
>Importance: normal
>Priority: normal
>X-MimeOLE: Produced By Microsoft MimeOLE V6.00.3790.0
>Newsgroups: microsoft.public.win32.programmer.networks
>NNTP-Posting-Host: TK2MSFTNGXA03.phx.gbl 10.40.2.250
>Path: TK2MSFTNGXA02.phx.gbl!TK2MSFTNGP08.phx.gbl!TK2MSFTNGXA03.phx.gbl
>Xref: TK2MSFTNGXA02.phx.gbl
microsoft.public.win32.programmer.networks:27853
>X-Tomcat-NG: microsoft.public.win32.programmer.networks