In my previous blog article, I pointed out that in a workgroup environment, Windows XP has the force guest policy on and it prevents agents and clients connecting to the controller.
In this post, I want to expand on this and talk a bit more about VSTT controller and agent setup. Particularly, I will talk about the user account requirements on the machines running controller, agent and the client.
Ed Glas already talked about the setup in general at http://blogs.msdn.com/edglas/pages/load-agent-and-load-controller-installation-and-configuration-guide.aspx, where he has a list of user account and password requirements on the machines running controller and agent. In this post, I want to drill down further into the reasons behind those user account requirements. I will do this by walking you through the installation process of a controller, agent and a client and troubleshooting the authentication issues.
To start with, I have 3 machines. VSTTClient, VSTTController and VSTTAgent1. I have Windows XP SP2 on all the 3 machines. They are all in a workgroup TESTRIG. I have intentionally made the administrator password different on all the 3 machines. The idea is not accidentally authenticate to another box as an Admin. Other than this, all the machines are clean and no other setup has been done.
Before we proceed to the installation, I want to go over a few things.
1. Workgroup authentication
In a Windows domain environment, there is a central authority to validate credentials. In a workgroup environment, there is no such central authority. Still, we should be able to have computers in a workgroup talk to each other and authenticate users. To enable this, local accounts have a special characteristic that allows the local security authority on the computer to authenticate a "principal" in a special way.
If you have two computers and a principal "UserXYZ" on both machines the security identifiers are different for MACHINE1\UserXYZ and MACHINE2\UserXYZ and for all practical purposes they are two completely different "Principals". However if the passwords are the same for them on each of these computers, the local security authority treats them as the
same principal.
So when MACHINE1\UserXYZ tries to authenticate to MACHINE2\UserXYZ, and if the passwords are the same, then on MACHINE2, the UserXYZ is authenticated successfully and
is treated as MACHINE2\UserXYZ. Note the last sentence. The user MACHINE1\UserXYZ
is authenticated as MACHINE2\UserXYZ if the passwords are the same.
2. Force Guest
As I mentioned in the previous article, in a default Windows XP workgroup environment, the force guest policy is on by default. You can quickly check this out by mapping a share from a one machine to the other. Here, I am trying to map a share from the VSTTController to VSTTAgent1 and I am forced to login as a Guest, and the User Name box is grayed out.
If the force guest policy is on, it does not matter if you have the same users and passwords, you can not authenticate to the machine as any other principal than the Guest. You can turn it off using Regedt32, HKLM\System\CurrentControlSet\Control\Lsa and editing the forceguest value to 0.
3. Security Audit
If you are having authentication issues and don't know what is happening, the security audit policy is your good friend. Normally security audit is turned off and hence you will not see the events in the event viewer.
To turn the security auditing, open mmc, add group policy object editor, select local computer. Then Select Local Computer Policy\Computer Configuration\Windows Settings\Security settings\Local Policies\AuditPolicy and turn on Success and Failure auditing for the events of interest. For troubleshooting purposes, I turn on the audit for everything here. Granted this generates a lot of auditing but at least I know what is going on and once I am done troubleshooting, I can turn the auditing off.
Once done, on a command prompt, run gpupdate /force to apply the policy.
Installing the Controller and Agent
Now that we have the basics covered, I started the installation process with the VSTTController box on which I intend to install the Controller. The first thing is to turn off the force guest policy since I already know that the agent and the client needs to connect and authenticate to the controller. Then I added a user CSUser. This is the user the controller service will run as. During the installation process, you need to pick a user under which the controller service runs under and I picked the CSUser.
After the installation of the controller, I have, on the VSTTController machine,
- A user account CSUser
- An empty TeamTestAgentService group
- An empty TeamTestControllerAdmins group
- An empty TeamTestControllerUsers group.
At this point the controller service seems to be running, so I am happy so far.
The next step then is to go to the VSTTAgent1 machine and install the Agent. Note that on this machine I did not yet turn the ForceGuest policy off on VSTTAgent1. The reason, once again, is that I wanted to understand the minimal stuff that I need to do get this rig working.
Before I started the agent installation, I added the user AgentUser to the machine. This is the identity under which the agent process will run. I logged in as Administrator on this box and started the agent installation. The installation process asks for the user identity of the agent process and I specified the identity as AgentUser. About 15 seconds in into the process, the agent installation has trouble. Apparently connecting to the controller failed.
To start troubleshooting, I switched to the VSTTController machine, turn on the security auditing on the VSTTController machine as described above and then switched back to the VSTTAgent1 machine and clicked Retry on the dialog. As expected it fails again. Now when I switched to the VSTTController box and looked at the Event Viewer, under Security folder, I see the following event.
The VSTTController machine is rejecting the logon VSTTAgent1\Administrator. This is for good reason. The Administrator passwords are intentionally not the same!
It is easy to see why the agent installation connects to the controller box under the identity of the person who is installing the Agent. The user that is installing the agent is supposed to be part of the Administrators that administer the controller and agents. The act of installing an Agent and connecting to a controller makes the agent to be registered with the controller.
This needs special permissions.
One thing we can do now is to adjust the administrator passwords to be the same. I don't particularly like the idea, since I don't want Administrators of one box to automatically connect to other boxes.
So what I decided to do is to add a user AgentAdmin on the VSTTAgent1 machine and add it to the Administrators group. The idea is that I will restart the Agent installation as AgentAdmin, not as Administrator. Since AgentAdmin is part of the Administrators group on VSTTAgent1 machine, the installation should work fine. On the VSTTController machine,
I need to add the same user AgentAdmin with the same password. However VSTTController\AgentAdmin will not be part of the Administrators group on VSTTController box. The idea is to not unnecessarily grant permissions that are not required.
So at this point, here is what I have on each box
| VSTTController | VSTTAgent1 |
| ForceGuest Off | ForceGuest ON |
| AgentAdmin as a normal user | AgentAdmin user part of the Administrators group |
| CSUser as a normal user. The controller service is running under this user | AgentUser as a normal user. This is the intended identity under which the agent should be running |
| An empty TeamTestAgentService group An empty TeamTestControllerAdmins group An empty TeamTestControllerUsers group | N/A |
| Security Audit turned on | Security Audit off |
With this arrangement, I logged off as an Administrator on the VSTTAgent1 box and then logged in back as a AgentAdmin.
But before I proceed, I will let you in on a cool trick. The .NET tracing's default trace listener writes the trace using the API called OutputDebugString and you can view the output in real time using a tool called DebugView. DebugView is a tool that is freely downloadable from the Technet. Go here to download.What this means is that you don't need to configure file based trace listeners, and keep refreshing the file editor to see the latest contents. Since I wanted to see the controller's trace messages, I switched to the VSTTController box, edited the QtController.exe.Config file (under <rootdrive>:\Program Files\Microsoft Visual Studio 9.0 Team Test Load Agent\LoadTest), and adjusted the EqtTraceLevel to a value of "4" like shown below, saved the file and restarted the controller service for the settings to take effect.
<switches>
<!-- You must use integral values for "value".
Use 0 for off, 1 for error, 2 for warn, 3 for info, and 4 for verbose. -->
<add name="EqtTraceLevel" value="4" />
</switches>
Once I did this, I fired up the DebugView. You should see something like this on the VSTTController box.

Now that I have both the security audit and the controller tracing on the VSTTController box, I came back to the VSTTAgent1 box and started the install process. Remember that now I am logged in on the VSTTAgent1 Box as AgentAdmin, which is part of the VSTTAgent1\Administrators group.
The Agent installation fails again. On the VSTTController box, I look at the event viewer. I see a successful logon of the AgentAdmin. The Logon type = 3 which means that this is a network logon. So we made progress. We are able to authenticate to the VSTTContoller machine as VSTTController\AgentAdmin from VSTTAgent1 machine using VSTTAgent1\AgentAdmin principal.
The next thing to look at is the QtController's trace messages from the DebugView tool. The trace messages show that the controller service is checking for group membership of this authenticated principal (user) AgentAdmin. It is checking to see if the AgentAdmin is a member of TestTestControllerUsers or TeamTestControllerAdmins group. Since I did not add the AgentAdmin as part of any group on the VSTTController box, the membership check fails and controller returns an error which is showing up as an installation failure on VSTTAgent1 machine.
To fix the error it is not clear to me as to what group I need to add the AgentAdmin user to
on the VSTTController box. At first I tried adding the AgentAdmin to the TeamTestControllerUsers group, went back to the VSTTAgent1 box and retried the installation. Even though the installation was successful, the agent was never registered with the controller. I could have tried to fix through other means, but decided to try this through the user scenario. So I added the AgentAdmin as part of the TestTestControllerAdmins group on the VSTTController box. I turned the security auditing on on the VSTTAgent1 machine too, just to aid in debugging.
I uninstalled the agent from the VSTTAgent1 box and attempted a reinstall of the Agent.
Here is what I have just before the reinstall of the Agent on VSTTAgent1 machine
| VSTTController | VSTTAgent1 |
| ForceGuest Off | ForceGuest ON |
AgentAdmin as a normal user and part of the TeamTestControllerAdmins | AgentAdmin user part of the Administrators group |
| CSUser as a normal user. The controller service is running under this user | AgentUser as a normal user. This is the intended identity under which the agent should be running |
| Empty TeamTestAgentService group TeamTestControllerAdmins group has AgentAdmin as a member Empty TeamTestControllerUsers | N/A |
| Security Audit turned on | Security Audit ON |
The installation seems to be successful. On the VSTTController machine I see trace messages showing that the installation went well and the VSTTAGENT1 is added to the AgentManager. So far so good.
Now that the installation of the agent is successful, I really don't see the point of having the AgentAdmin as a user on the VSTTController machine or on the VSTTAgent1 machine. I want to delete this account so that I can reduce any unnecessary user accounts with the same passwords floating around. So I deleted the AgentAdmin account from both the VSTTController and VSTTAgent1 machines ( first I need to logoff as AgentAdmin on the VSTTAgent1 box, log back in as Administrator before deleting the AgentAdmin user). With the AgentAdmin account deleted from both the machines, here is the configuration
| VSTTController | VSTTAgent1 |
| ForceGuest Off | ForceGuest ON |
| CSUser as a normal user. The controller service is running under this user | AgentUser as a normal user. This is the intended identity under which the agent should be running |
| Empty TeamTestAgentService group Empty TeamTestControllerAdmins group Empty TeamTestControllerUsers group | N/A |
| Security Audit turned on | Security Audit ON |
The Agent installation suggested a reboot after the installation so I did that.
After the reboot when I logged into the VSTTAgent1 box as an Administrator and opened the event viewer. I am expecting that the Agent service will not be able to connect to the controller. Why? The agent is running as VSTTAgent1\AgentUser and there is no corresponding user on the VSTTController box. So Agent should fail to connect.
Sure enough the event viewer on VSTTAGent1 machine and the event viewer on the VSTTController machine both point to the failed logon of VSTTAgent1\AgentUser on VSTTController machine.
Since we need the agent to connect to controller, we must add the AgentUser to the VSTTController machine with the same password as it has on VSTTAgent1 machine.
Even after adding this, the agent is still not happy since it still can't connect yo the controller service. Looking at the debug view, you can figure out that the AgentUser needs to be part of the TeamTestAgentService group. So I added the AgentUser to the TeamTestAgentService group. Still no success.
Looking at the Event viewer on VSTTAgent1, I find that the VSTTController\CSUser is trying to authenticate to VSTTAgent1 machine. This because the controller wants to callback to the agent on a different connection and that connection needs to be authenticated.
The auth fails due to the fact that we have force guest on and we don't have CSUser as a local user on VSTTAgent1. Lets fix this now. After fixing, and rebooting, this is what I have for configuration
| VSTTController | VSTTAgent1 |
| ForceGuest Off | ForceGuest Off |
| CSUser as a normal user. The controller service is running under this user | CSUser as a normal user. |
| The AgentUser as a normal user. | AgentUser as a normal user. This is the intended identity under which the agent should be running |
| TeamTestAgentService group contains the AgentUser Empty TeamTestControllerAdmins TeamTestControllerUsers group contains AgentUser | N/A |
| Security Audit turned on | Security Audit ON |
That does it. The agent and controller are now happy and are communicating to each other.
Installing the Client and getting it to connect to the controller
I created a ClientUser on the VSTTClient machine. I installed VSTT, logged off and logged in back again a VSTTClient\ClientUser. I fired up VS, created a test project, specified VSTTController as the remote controller and started a run. As expected, the VS is trying to
open an authenticated connection to the VSTTControlelr as VSTTClient\ClientUser. Since that user is not defined on the VSTTController machine, the logon fails.
The fix is to add the ClientUser to the VSTTController box and then to the TeamTestControllerUsers group.
Even after doing that you would still find that you are able to execute tests.
Following the same troubleshooting techniques and turning on the security audit on the
VSTTClient, the VSTTController\CSUser is failing to authenticate to the VSTTClient.
So the fix is to turn off the force guest poilicy and create the CSUser on the VSTTClient machine.
Now I can run tests in my multi machine workgroup topology....
Here is the final recipe for the VSTT Client, Controller and agent setup
- On all machines in the workgroup, turn off the ForceGuest policy.
- Determine the user account under which the controller is going to run under [CSUser]
Add this account to *all* the machines - client, controller and agent machines [VSTTClient, VSTTController, and VSTTAgent1 in my case] - On the controller machine, install the controller. When you install the controller it will
create a set of user groups mentioned above. - Determine the account under which the agent is going to run under [AgentUser]. Add the account to the controller machine and to the TeamSystemAgentService Group.
- On the agent machine, create a temporary account called AgentAdmin. Add the account to the Administrators group. Add the AgentAdmin account to the controller machine and to the TeamSystemControllerAdmins user group
- Login to the Agent machine as the AgentAdmin
Install the agent, specify AgentUser as the user underwhich the server is going to run under - Once the install is complete, on the Agent machine, logoff as AgentAdmin, log back in as Administator and delete the AgentAdmin account. Delete the AgentAdmin account on the Controller machine. There is no need for this account any more.
- Determine the account under which you are going to run the Visual Studio on the
client machine. [ClientUser on VSTTClient]. Add the account to the controller machine with the same password. On the controller machine, add the client user to the TeamSystemControllerUsers group.
Thats it. I hope this article showed you in detail how to install controller and agent in a workgroup and troubleshoot any authentication issues using the DebugView and Security Audit policy.
In Rosario Team Foundation Server, significant new functionality is added for liking work item types
http://blogs.msdn.com/bharry/archive/2007/08/06/work-item-tracking-enhancements-in-the-aug-rosario-ctp.aspx
http://blogs.msdn.com/teams_wit_tools/archive/tags/Rosario/default.aspx
Here, I will try to describe how to query on link through the work item API.
First let’s get a list of work item types in the server.
After the obligatory logging in into the TFS and getting the Work Item Store, you need to go to a
specific project and then get the work item types defined for that project. Here is a code snippet
that prints all the work item types in a project
TeamFoundationServer TFS;
WorkItemStore WIStore;
TFS = TeamFoundationServerFactory.GetServer(http://"<your tfs server>:<port typically = 8080>");
WIStore = TFS.GetService(typeof(WorkItemStore)) as WorkItemStore;
Project TeamProject = WIStore.Projects["MyProject"];
WorkItemTypeCollection workItemTypes = TeamProject.WorkItemTypes;
foreach (WorkItemType workItemType in workItemTypes)
{
Console.WriteLine(workItemType.Name);
} |
Now that we know how to get the work item types, we can look at the work item link types
While the work item types are project specific, work item link types are global to all projects.
The code snippet below shows how to get the work item link types.
WorkItemLinkTypeCollection worItemLinkTypes = WIStore.WorkItemLinkTypes;
foreach (WorkItemLinkType workItemLinkType in worItemLinkTypes)
{
Console.WriteLine("-----------------------------------------");
Console.WriteLine("Base ReferenceName: {0}", workItemLinkType.BaseReferenceName);
Console.WriteLine("Id: {0}", workItemLinkType.Id);
Console.WriteLine("Name: {0}", workItemLinkType.Name);
Console.WriteLine("IsDirectional: {0}", workItemLinkType.IsDirectional);
Console.WriteLine("IsForwardLink: {0}", workItemLinkType.IsForwardLink);
Console.WriteLine("IsNonCircular: {0}", workItemLinkType.IsNonCircular);
Console.WriteLine("IsOneToMany: {0}", workItemLinkType.IsOneToMany);
Console.WriteLine("LinkTopology: {0}", workItemLinkType.LinkTopology.ToString());
WorkItemLinkType workItemLinkTypeReverse = workItemLinkType.Reverse;
Console.WriteLine("\t....");
Console.WriteLine("\tId: {0}", workItemLinkTypeReverse.Id);
Console.WriteLine("\tName: {0}", workItemLinkTypeReverse.Name);
Console.WriteLine("\tIsDirectional: {0}", workItemLinkTypeReverse.IsDirectional);
Console.WriteLine("\tIsForwardLink: {0}", workItemLinkTypeReverse.IsForwardLink);
Console.WriteLine("\tIsNonCircular: {0}", workItemLinkTypeReverse.IsNonCircular);
Console.WriteLine("\tIsOneToMany: {0}", workItemLinkTypeReverse.IsOneToMany);
Console.WriteLine("\tLinkTopology: {0}", workItemLinkTypeReverse.LinkTopology.ToString());
}
|
When you run the code it prints something like
Base ReferenceName: Microsoft.VSTS.Common.Produces
Id: 4
Name: Produces
IsDirectional: True
IsForwardLink: True
IsNonCircular: True
IsOneToMany: False
....
Id: -4
Name: Is Produced By
IsDirectional: True
IsForwardLink: False
IsNonCircular: True
IsOneToMany: False
So it seems that a “Relation” is represented by two “Work Item Link Type” instances. Each direction of the “relation” is a work item link type. The other direction is the “reverse” work item link type.
Let’s take a concrete example:
A feature is produced by one or more deliverables. A deliverable produces one or more features.
This relation is a many to many relation. This relation has a BaseReferenceName – “Produces” and is represented by two work item link type instances.
Features Is Produced by Deliverable
Deliverable Produces Feature.
Each work item link type has a “Reverse” property that points to its counterpart.
Once I got the work item types and work item link types, I tried to see if there are constraints on what link types a work item type can have. For example, can a feature have a parent as a deliverable?
Can a deliverable have a parent Task? It seems that given a set of work item types, only certain relations are valid for a work item of a give type. Unfortunately, as of now, this feature is not implemented.
So any work item type can have any relation or link type as you desire. The team foundation server team is apparently thinking about adding this in the subsequent CTP releases, but nothing is guaranteed.
Querying on Links
Let’s take a look at how to query the work item links.
The WorkItemLinks property will give you all the work item links. Since there could be other types of links, the BaseLinkType property is looked at to make sure that this is the work item link. By querying the WorkItemLink.SourceId and TargetId properties, you can discover what the work item is on the other side of the relation. In this case, my feature 9999, is hooked up to a deliverable via a “Produces” relation
and with a “Is Produced By “directional link.
WorkItem wiFeatureGroup = WIStore.GetWorkItem(9999);
foreach (WorkItemLink wiLink in wiFeatureGroup.WorkItemLinks)
{
if (wiLink.BaseType == BaseLinkType.WorkItemLink)
{
if(wiLink.LinkType.BaseReferenceName == "Microsoft.VSTS.Common.Produces" && wiLink.LinkType.Name == "Is Produced By")
{
WorkItem wiDeliverable = WIStore.GetWorkItem(wiLink.TargetId);
Console.WriteLine("The target WorkItemID is {0} and its type is {1}", wiDeliverable.Id, wiDeliverable.Type.Name);
}
}
} |
Adding a link
Adding a link is simple. You create a link and add it to the collection, then save the work item
WorkItem wiFeatureGroup = WIStore.GetWorkItem(9999);
WorkItemLink wiLink = new WorkItemLink(WIStore.WorkItemLinkTypes["Is Produced By"], 9999, 8888);
wiFeatureGroup.WorkItemLinks.Add(wiLink);
wiFeatureGroup.Save();
|
Deleting a link
To delete a link, you would need to identity the link you want to delete and call the Remove() method on that. Note that you need to save the WorkItem to persist the changes.
WorkItem wiFeatureGroup = WIStore.GetWorkItem(642);
foreach (WorkItemLink wiLink in wiFeatureGroup.WorkItemLinks)
{
if (wiLink.BaseType == BaseLinkType.WorkItemLink)
{
if(wiLink.LinkType.BaseReferenceName == "Microsoft.VSTS.Common.Produces" && wiLink.LinkType.Name == "Is Produced By")
{
WorkItem wiDeliverable = WIStore.GetWorkItem(wiLink.TargetId);
if (wiDeliverable.Id == 887)
{
wiFeatureGroup.WorkItemLinks.Remove(wiLink);
wiFeatureGroup.Save();
break;
}
}
}
} |
All in all, you will generally find that querying, adding and deleting work item links are easy and intuitive.
The ability to add “relations” to work items opens tremendous flexibility and gives you the ability to write cool new applications that use the power of TFS work item store.
So I moved from the networking group to Visual Studio Team System Test. Recently, I was investigating an issue where the client, controller and agent are not working together
when in a workgroup topology. In other words, the machines that are running the client, controller service, and agent service are *non* domain joined and are
part of a workgroup. In this situation, the client is simply failing to connect to the controller. The client gets the message
"The server rejected the client's credentials - Log on failed".
For this discussion let’s say I have Machine CLEINT with user Tony. The machine that is running controller (lets say CONTROLLER) has the same user and password Tony.
I started investigating this issue by enabling the security audit in the security policy. In examining the security audit log, I found that the user on the client
machine was rejected. The message goes like "Bad user name or password, user Tony, Domain CLIENT". On the first thought it kind of makes sense that the user
CLIENT\Tony will be unknown to CONTROLLER. However, the windows workgroup security needs to enable this scenario since there is no central
domain controller. So CLIENT\Tony should be able to authenticate to CONTROLLER as CONTROLLER\Tony. This scenario should work. So what gives?
The next thing I tried is to simply map a network share from CLIENT to CONTROLLER, something like \\controller\c$. Since both CLIENT and CONTROLLER
have Tony as the interactive user, this file share mapping should work. (I already enabled the firewall for this). What I got is a dialog box asking me for credentials.
The strange thing is that the user box is grayed out and says CONTROLLER\Guest. I wondered why it is forcing me to login as guest. A quick call to
the security team gave me the clue.
For Windows XP, in a workgroup situation, there is a setting that forces all NETWORK logins as GUEST. Which means that even if you
are trying to authenticate with a legitimate user and password credentials, it will force you to login as GUEST. Clearly, this is failing
because I am trying to login as Tony and not as Guest.
The fix is to edit the registry HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\ForceGuest
and set the value to 0. This will remove the restriction of forcing the network logins as "Guest". Once I set this value to 0 on *all* the machines (client, controller and agent) and rebooted
the machines, it all worked perfectly.
To recap,
1. Windows XP "ForceGuest" is on by default in a workgroup scenario, which means all network logins are allowed as Guest only..
2. Set the registry key to HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\ForceGuest to 0 to remove this restriction
3. Reboot after applying the security setting
I will post a more detailed article on the controller, agent and client setup, users and permissions shortly.
These days connected applications are everywhere. Web Services and Indigo based applications are used to hook up various services over the internet. When something goes wrong you can debug all you want but ultimately you need to look at what is really going on the wire. Network Monitor is your friend. I am surprised how many people are not really aware of this tool called Network Monitor. Many people who have heard about it think that it is too complex to capture network traffic and understand the traffic.
In this article I would like explain in easy to understand terms, how to install a network monitor, how to capture traffic, how to save it and how to interpret it. My belief is that once you understand this and used the tool, you will wonder how you ever lived without it. Let’s jump in.
1. How to install a Network Monitor.
You might want to know that Network Monitor is a free tool.
Go to Control Panel, Add Remove Programs applet.
Then choose Add Remove Windows Components
Then Select Management and Monitoring Tools and click details.
Choose Network Monitor and proceed with the installation.
You may be prompted for the Windows Installation CD
After the installation, you will see the Network Monitor in the Administrative Tools.
2. Launching the Network Monitor for the first time.
When you launch the Network Monitor for the first time you will see a dialog that says “Please specify the network on which you want to capture the data”.
What does this mean?
Network Monitor captures data on a SPECIFIC network adapter. Even if you have only one physical network card, you may have more than one adapter. Don’t worry about this. It will be clear in a second.
Click OK to this dialog.
The dialog that pops up next [You can access the same dialog through the Capture/Networks menu option] is the one where you pick the “Network” you want to monitor. Expand the Local Computer node. You will see one or more Networks.
Which one to choose? Well it depends.
If you have a computer with one network card, simply choose the LAN Connection and click OK
If you have a computer with more than one network card, you have to choose one.
Open a command prompt and type IPCONFIG /all. Then for each Network interface, note down the physical address or MAC address. Once you know the MAC Address,
in the properties windows of the “Select a network” dialog we are talking about,
choose the network whose MAC address matches the MAC address of the network you want to monitor. Then Click OK.
3. Using Network Monitor.
Once you have selected a network to monitor, simply press the button that looks like the PLAY button on the toolbar or choose Capture/Start or press F10.
You should see some activity in the Frames per second and other bars. Launch a browser and go to a site. You should see some more activity. If you don’t see any activity on the screen, then you have selected a wrong network. Repeat #2.
At this point you can run any application including the one you want to debug.
The traffic generated by the application is captured. When you are ready to stop
capturing press the stop button or select Capture/Stop or press F11.
To display what you just captured, press F12.
To save the capture use File/Save as.
That’s it you have a capture file. You can send it to other people or look at it later.
4. What is in a capture file?
You might be wondering what exactly is in a capture file. The capture file contains every single frame that the computer received or sent on the “network” you chose. Even if you capture for a very small amount of time, you can get a LOT of frames.
But you don’t need to worry. Network Monitor has a lot of capabilities to filter and sort.
5. How do I find what I want in the capture file?
When you are looking at a capture you will find that there are several columns. First is the frame number. When you are explaining the issue to someone you can say something like “I see something interesting in frame 999”. Then you can see the Time, Source MAC Address, Dest MAC address, Protocol, Description, etc. You may not find the columns exactly in the order I described but you can order the columns by drag and drop.
The protocol column is very interesting. This column tells you what the protocol is for the frame captured. On a network a lot of things are going on. On my computer I see HTTTP, BONE, ARP, RARP, DNS, TCP, ICMP6 among many other things.
Let’s say you are having an issue with one of your HTTP requests. You want to only
look at the HTTP requests and filter out the noise
Click on the funnel toolbar or choose Display/Filter or press F8. You will see a filter dialog. Double click on Protocol=Any line. Click Disable All. AT this point all the protocols are disabled. Then Click on HTTP [Use the scroll bars to find HTTP] and enable the protocol. Click OK.
Now you should see Protocol=HTTP. This means that the current filter only shows HTTP protocol. Now you can see only HTTP frames. Note that all the other protocols are still there in the capture, you are only seeing the HTTP frames. There is a way to not EVEN CAPTURE other protocols – this is achieved by the CAPTURE filter. We will not discuss that now.
OK now you are looking at HTTP frames. How to make sense of these? At this point You need to have knowledge on HTTP protocol and how to interpret the protocol.
If you double click it shows you the complete details of the HTTP protocol information in each packet.
Let me know if this is helpful and if you need more information.
Some people have asked me how to get the SubnetMask for the network interfafce.
The subnet mask is valid only for IPv4.
The solution may not jump at you since there is no property called SubnetMask,
however there is a property called IPv4Mask.
Here is the code to get the subnet mask for each IPv4 address on the box
using System;
using System.Net.NetworkInformation;
public class test
{
public static void Main()
{
NetworkInterface[] Interfaces = NetworkInterface.GetAllNetworkInterfaces();
foreach(NetworkInterface Interface in Interfaces)
{
if(Interface.NetworkInterfaceType == NetworkInterfaceType.Loopback) continue;
Console.WriteLine(Interface.Description);
UnicastIPAddressInformationCollection UnicastIPInfoCol = Interface.GetIPProperties().UnicastAddresses;
foreach(UnicastIPAddressInformation UnicatIPInfo in UnicastIPInfoCol)
{
Console.WriteLine("\tIP Address is {0}", UnicatIPInfo.Address);
Console.WriteLine("\tSubnet Mask is {0}", UnicatIPInfo.IPv4Mask);
}
}
}
}
In Whidbey (.NET Framework 2.0) System.Net has a new feature called Tracing.
This uses the builtin CLR Tracing functionality. What is interesting about the System.Net Tracing is that
You can easily see the data that is being sent or received without having to use the NETMON.
If you have used Network Monitor tools like NETMON/Ethereal you will find that
there is so much noise that you need to weed through. This can be partially addressed through
capture filters and display filters. But then looking at a frame in the capture you can't
easily determine which process issued that request. Similarly if there are multiple threads,
you can't easily determine which thread issued that request. One more thing is that if the
client and server are on the same machine you can;t capture the loop back traffic. Perhaps the most limiting of all
is that if the application is using SSL (https or FTP with SSL) then it is not possible to look at the traffic.
You can at most see the TCP frames with encrypted payload. Not much of use. Right?
With System.Net, we addressed all these issues. System.Net tracing is
1) Per process
2) Shows threads
3) Works for SSL
4) Works for Loopback.
5) You don't need to recompile the code
With all these advantages I find the System.Net tracing a very compelling feature that will not be able to live without.
Lets look at some examples.
1. Consider the following code
//JScript.Net
import System;
import System.Net;
(new WebClient()).DownloadString(http://www.microsoft.com/office);
I wrote the above JScript.Net code. You can compile the code with Jsc <filename>
What if you really want to see the trace for that code and see what is going on the wire?
You can use the following configuration file. Save this file as app.exe.config file.
<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
<system.diagnostics>
<trace autoflush="true" />
<sources>
<source name="System.Net" maxdatasize="1024">
<listeners>
<add name="MyTraceFile"/>
</listeners>
</source>
</sources>
<sharedListeners>
<add
name="MyTraceFile"
type="System.Diagnostics.TextWriterTraceListener"
initializeData="System.Net.trace.log"
/>
</sharedListeners>
<switches>
<add name="System.Net" value="Verbose" />
</switches>
</system.diagnostics>
</configuration>
<!--
You can use these two attributes on the Trace Sources
tracemode="protocolonly"
maxdatasize="1024"
-->
<!--
You can choose from 4 sources
<source name="System.Net" maxdatasize="1024">
<listeners>
<add name="MyTraceFile"/>
</listeners>
</source>
<source name="System.Net.Sockets">
<listeners>
<add name="MyTraceFile"/>
</listeners>
</source>
<source name="System.Net.Cache">
<listeners>
<add name="MyTraceFile"/>
</listeners>
</source>
<source name="System.Net.HttpListener">
<listeners>
<add name="MyTraceFile"/>
</listeners>
</source>
-->
Now when you run the application you will find the log file as System.Net.Trace.Log file
System.Net Information: 0 : [3560] HttpWebRequest#33736294 - Request: GET /office HTTP/1.1
System.Net Information: 0 : [3560] ConnectStream#31914638 - Sending headers
{
Host: www.microsoft.com
Connection: Keep-Alive
}.
System.Net Information: 0 : [3560] Connection#48285313 - Received status line: Version=1.1, StatusCode=301, StatusDescription=Moved Permanently.
System.Net Information: 0 : [3560] Connection#48285313 - Received headers
{
Connection: Keep-Alive
Proxy-Connection: Keep-Alive
Content-Length: 155
Content-Type: text/html
Date: Mon, 12 Sep 2005 21:51:00 GMT
Location: http://www.microsoft.com/office/
P3P: CP="ALL IND DSP COR ADM CONo CUR CUSo IVAo IVDo PSA PSD TAI TELo OUR SAMo CNT COM INT NAV ONL PHY PRE PUR UNI"
Server: Microsoft-IIS/6.0
Via: 1.1 MSCORPGATE12
X-Powered-By: ASP.NET
}.
You can see that the log file shows what is being sent on the wire and what headers are being received.
You don't need to use NETMON any more to see what traffic is being sent on the wire. Very good indeed.
You can also see that we show the objects and hash codes for each object so you can follow an object
using this log file. You can also see [3560]as the thread id of the thread that is issuing the request.
2.What about SSL? What about Local Host?
Lets consider the following code
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.IO;
using System.Net.Security;
using System.Security.Policy;
using System.Security.Cryptography.X509Certificates;
using System.Security.Cryptography;
class Program
{
static void Main(string[] args)
{
Stream s = null;
StreamReader sr = null;
HttpWebResponse res = null;
try{
//Hook a callback to verify the remote certificate
ServicePointManager.ServerCertificateValidationCallback =
new RemoteCertificateValidationCallback(MyCertValidationCb);
HttpWebRequest req
= (HttpWebRequest)
WebRequest.Create("https://localhost/SecureNoClientCerts/test.htm");
req.Proxy = null;
res = req.GetResponse() as HttpWebResponse;
s = res.GetResponseStream();
sr = new StreamReader(s, Encoding.UTF8);
Console.WriteLine(sr.ReadToEnd());
}
catch(Exception ex){
Console.WriteLine(ex);
}
finally{
if(res != null) res.Close();
if(s != null) s.Close();
if(sr != null) sr.Close();
}
}
public static bool MyCertValidationCb(
object sender,
X509Certificate certificate,
X509Chain chain,
SslPolicyErrors sslPolicyErrors)
{
if ((sslPolicyErrors & SslPolicyErrors.RemoteCertificateChainErrors)
== SslPolicyErrors.RemoteCertificateChainErrors)
{
return false;
}
else if ((sslPolicyErrors & SslPolicyErrors.RemoteCertificateNameMismatch)
== SslPolicyErrors.RemoteCertificateNameMismatch)
{
Zone z;
z = Zone.CreateFromUrl(((HttpWebRequest)sender).RequestUri.ToString());
if (z.SecurityZone == System.Security.SecurityZone.Intranet
|| z.SecurityZone == System.Security.SecurityZone.MyComputer)
{
return true;
}
return false;
}
return false;
}
}
This code is trying to make an SSL request to the local host. You will also find that the
RemoteCertificationCallback sample.
You can enable both the Sockets and System.Net sources with the following config file
<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
<system.diagnostics>
<trace autoflush="true" />
<sources>
<source name="System.Net" maxdatasize="1024">
<listeners>
<add name="MyTraceFile"/>
</listeners>
</source>
<source name="System.Net.Sockets" maxdatasize="1024">
<listeners>
<add name="MyTraceFile"/>
</listeners>
</source>
</sources>
<sharedListeners>
<add
name="MyTraceFile"
type="System.Diagnostics.TextWriterTraceListener"
initializeData="System.Net.trace.log"
/>
</sharedListeners>
<switches>
<add name="System.Net" value="Verbose" />
<add name="System.Net.Sockets" value="Verbose" />
</switches>
</system.diagnostics>
</configuration>
Here is the log file produced
System.Net Verbose: 0 : [3848] WebRequest::Create(https://localhost/SecureNoClientCerts/test.htm)
System.Net Verbose: 0 : [3848] HttpWebRequest#33574638::HttpWebRequest(https://localhost/SecureNoClientCerts/test.htm#1109589874)
System.Net Verbose: 0 : [3848] Exiting HttpWebRequest#33574638::HttpWebRequest()
System.Net Verbose: 0 : [3848] Exiting WebRequest::Create() -> HttpWebRequest#33574638
System.Net Information: 0 : [3848] Associating HttpWebRequest#33574638 with ServicePoint#33736294
System.Net Verbose: 0 : [3848] HttpWebRequest#33574638::GetResponse()
System.Net Information: 0 : [3848] Associating Connection#35191196 with HttpWebRequest#33574638
System.Net.Sockets Verbose: 0 : [3848] Socket#48285313::Socket(InterNetwork#2)
System.Net.Sockets Verbose: 0 : [3848] Exiting Socket#48285313::Socket()
System.Net.Sockets Verbose: 0 : [3848] Socket#48285313::Connect(1:443#16777668)
System.Net.Sockets Verbose: 0 : [3848] Exiting Socket#48285313::Connect()
System.Net Information: 0 : [3848] TlsStream#31914638::.ctor(host=localhost, #certs=0)
System.Net Information: 0 : [3848] Associating HttpWebRequest#33574638 with ConnectStream#18796293
System.Net Information: 0 : [3848] HttpWebRequest#33574638 - Request: GET /SecureNoClientCerts/test.htm HTTP/1.1
System.Net Information: 0 : [3848] SecureChannel#34948909::.ctor(hostname=localhost, #clientCertificates=0)
System.Net Information: 0 : [3848] Enumerating security packages:
System.Net Information: 0 : [3848] Negotiate
System.Net Information: 0 : [3848] Kerberos
System.Net Information: 0 : [3848] NTLM
System.Net Information: 0 : [3848] Microsoft Unified Security Protocol Provider
System.Net Information: 0 : [3848] Schannel
System.Net Information: 0 : [3848] WDigest
System.Net Information: 0 : [3848] DPA
System.Net Information: 0 : [3848] Digest
System.Net Information: 0 : [3848] MSN
System.Net Information: 0 : [3848] SecureChannel#34948909 - Left with 0 client certificates to choose from.
System.Net Information: 0 : [3848] AcquireCredentialsHandle(package = Microsoft Unified Security Protocol Provider, intent = Outbound, scc = System.Net.SecureCredential)
System.Net Information: 0 : [3848] InitializeSecurityContext(credential = System.Net.SafeFreeCredential_SECURITY, context = (null), targetName = localhost, inFlags = ReplayDetect, SequenceDetect, Confidentiality, AllocateMemory, InitManualCredValidation)
System.Net Information: 0 : [3848] InitializeSecurityContext(In-Buffer length=0, Out-Buffer length=70, returned code=ContinueNeeded).
System.Net.Sockets Verbose: 0 : [3848] Socket#48285313::Send()
System.Net.Sockets Verbose: 0 : [3848] Data from Socket#48285313::Send
System.Net.Sockets Verbose: 0 : [3848] 00000000 : 16 03 00 00 41 01 00 00-3D 03 00 43 26 02 90 83 : ....A...=..C&...
System.Net.Sockets Verbose: 0 : [3848] 00000010 : 33 F1 48 D6 4B 74 DB E2-47 6E 7A 3D 55 D2 43 E2 : 3.H.Kt..Gnz=U.C.
System.Net.Sockets Verbose: 0 : [3848] 00000020 : FC 02 CF 0B AF D4 E0 83-40 59 33 00 00 16 00 04 : ........@Y3.....
System.Net.Sockets Verbose: 0 : [3848] 00000030 : 00 05 00 0A 00 09 00 64-00 62 00 03 00 06 00 13 : .......d.b......
System.Net.Sockets Verbose: 0 : [3848] 00000040 : 00 12 00 63 01 00 : ...c..
System.Net.Sockets Verbose: 0 : [3848] Exiting Socket#48285313::Send() -> 70#70
System.Net.Sockets Verbose: 0 : [3848] Socket#48285313::Receive()
System.Net.Sockets Verbose: 0 : [3848] Data from Socket#48285313::Receive
System.Net.Sockets Verbose: 0 : [3848] 00000000 : 16 03 00 06 09 : .....
System.Net.Sockets Verbose: 0 : [3848] Exiting Socket#48285313::Receive() -> 5#5
System.Net.Sockets Verbose: 0 : [3848] Socket#48285313::Receive()
System.Net.Sockets Verbose: 0 : [3848] Data from Socket#48285313::Receive
System.Net.Sockets Verbose: 0 : [3848] (printing 1024 out of 1545)
System.Net.Sockets Verbose: 0 : [3848] 00000005 : 02 00 00 46 03 00 43 26-02 90 92 8B 0F 1A 72 76 : ...F..C&......rv
System.Net.Sockets Verbose: 0 : [3848] 00000015 : A2 48 A6 F3 3D 43 22 ED-D5 63 15 8E E3 BD 4F AD : .H..=C"..c....O.
System.Net.Sockets Verbose: 0 : [3848] 00000025 : DD 5A F4 42 B3 72 20 2B-0D 00 00 A7 86 54 E0 9B : .Z.B.r +.....T..
System.Net.Sockets Verbose: 0 : [3848] 00000035 : C7 9A 00 FB 5D 3C AC DD-3E D9 50 FC 08 D8 AD 9F : ....]<..>.P.....
System.Net.Sockets Verbose: 0 : [3848] 00000045 : 14 C7 97 AB 56 98 D4 00-04 00 0B 00 05 B7 00 05 : ....V...........
System.Net.Sockets Verbose: 0 : [3848] 00000055 : B4 00 05 B1 30 82 05 AD-30 82 04 95 A0 03 02 01 : ....0...0.......
System.Net.Sockets Verbose: 0 : [3848] 00000065 : 02 02 0A 34 74 D0 6D 00-02 00 00 01 2B 30 0D 06 : ...4t.m.....+0..
System.Net.Sockets Verbose: 0 : [3848] 00000075 : 09 2A 86 48 86 F7 0D 01-01 05 05 00 30 77 31 13 : .*.H........0w1.
System.Net.Sockets Verbose: 0 : [3848] 00000085 : 30 11 06 0A 09 92 26 89-93 F2 2C 64 01 19 16 03 : 0.....&...,d....
System.Net.Sockets Verbose: 0 : [3848] 00000095 : 63 6F 6D 31 19 30 17 06-0A 09 92 26 89 93 F2 2C : com1.0.....&...,
System.Net.Sockets Verbose: 0 : [3848] 000000A5 : 64 01 19 16 09 6D 69 63-72 6F 73 6F 66 74 31 14 : d....microsoft1.
System.Net.Sockets Verbose: 0 : [3848] 000000B5 : 30 12 06 0A 09 92 26 89-93 F2 2C 64 01 19 16 04 : 0.....&...,d....
System.Net.Sockets Verbose: 0 : [3848] 000000C5 : 63 6F 72 70 31 17 30 15-06 0A 09 92 26 89 93 F2 : corp1.0.....&...
System.Net.Sockets Verbose: 0 : [3848] 000000D5 : 2C 64 01 19 16 07 72 65-64 6D 6F 6E 64 31 16 30 : ,d....redmond1.0
System.Net.Sockets Verbose: 0 : [3848] 000000E5 : 14 06 03 55 04 03 13 0D-4E 43 4C 43 45 52 54 53 : ...U....NCLCERTS
System.Net.Sockets Verbose: 0 : [3848] 000000F5 : 45 52 56 45 52 30 1E 17-0D 30 35 30 38 32 31 30 : ERVER0...0508210
System.Net.Sockets Verbose: 0 : [3848] 00000105 : 30 33 30 32 35 5A 17 0D-30 36 30 38 32 31 30 30 : 03025Z..06082100
System.Net.Sockets Verbose: 0 : [3848] 00000115 : 34 30 32 35 5A 30 2E 31-2C 30 2A 06 03 55 04 03 : 4025Z0.1,0*..U..
System.Net.Sockets Verbose: 0 : [3848] 00000125 : 13 23 64 67 6F 72 74 69-6C 74 2E 72 65 64 6D 6F : .#dgortilt.redmo
System.Net.Sockets Verbose: 0 : [3848] 00000135 : 6E 64 2E 63 6F 72 70 2E-6D 69 63 72 6F 73 6F 66 : nd.corp.microsof
System.Net.Sockets Verbose: 0 : [3848] 00000145 : 74 2E 63 6F 6D 30 81 9F-30 0D 06 09 2A 86 48 86 : t.com0..0...*.H.
System.Net.Sockets Verbose: 0 : [3848] 00000155 : F7 0D 01 01 01 05 00 03-81 8D 00 30 81 89 02 81 : ...........0....
System.Net.Sockets Verbose: 0 : [3848] 00000165 : 81 00 CF E2 93 87 AF 2A-19 56 47 CF E0 2F E3 13 : .......*.VG../..
System.Net.Sockets Verbose: 0 : [3848] 00000175 : B8 4F B7 20 C7 FA 1A 55-5F B0 3E 6E B6 4B 9B DC : .O. ...U_.>n.K..
System.Net.Sockets Verbose: 0 : [3848] 00000185 : 50 1F 7E A7 5A 13 49 6D-8B 4A B1 27 50 91 47 51 : P.~.Z.Im.J.'P.GQ
System.Net.Sockets Verbose: 0 : [3848] 00000195 : 6A 8D 21 D1 DC 6C C2 AD-1D 38 E2 20 8A 1A 75 24 : j.!..l...8. ..u$
System.Net.Sockets Verbose: 0 : [3848] 000001A5 : F3 8F 51 E9 BD E7 F9 FE-8D 11 C9 3A 9E 88 B4 D0 : ..Q........:....
System.Net.Sockets Verbose: 0 : [3848] 000001B5 : A3 A9 C7 A6 7B C0 91 D9-1D 10 AE 00 38 C6 A9 8E : ....{.......8...
System.Net.Sockets Verbose: 0 : [3848] 000001C5 : 27 52 A5 48 5D DD DF 4B-BF F8 D0 43 AE 43 11 0F : 'R.H]..K...C.C..
System.Net.Sockets Verbose: 0 : [3848] 000001D5 : 0D A5 5E 2C A6 0A 37 9C-EF 9B 5A 30 FC D3 8A 54 : ..^,..7...Z0...T
System.Net.Sockets Verbose: 0 : [3848] 000001E5 : 55 33 02 03 01 00 01 A3-82 03 06 30 82 03 02 30 : U3.........0...0
System.Net.Sockets Verbose: 0 : [3848] 000001F5 : 0E 06 03 55 1D 0F 01 01-FF 04 04 03 02 04 F0 30 : ...U...........0
System.Net.Sockets Verbose: 0 : [3848] 00000205 : 44 06 09 2A 86 48 86 F7-0D 01 09 0F 04 37 30 35 : D..*.H.......705
System.Net.Sockets Verbose: 0 : [3848] 00000215 : 30 0E 06 08 2A 86 48 86-F7 0D 03 02 02 02 00 80 : 0...*.H.........
System.Net.Sockets Verbose: 0 : [3848] 00000225 : 30 0E 06 08 2A 86 48 86-F7 0D 03 04 02 02 00 80 : 0...*.H.........
System.Net.Sockets Verbose: 0 : [3848] 00000235 : 30 07 06 05 2B 0E 03 02-07 30 0A 06 08 2A 86 48 : 0...+....0...*.H
System.Net.Sockets Verbose: 0 : [3848] 00000245 : 86 F7 0D 03 07 30 1D 06-03 55 1D 0E 04 16 04 14 : .....0...U......
System.Net.Sockets Verbose: 0 : [3848] 00000255 : 25 9C 39 A7 F3 81 B2 20-79 95 22 C4 BD E3 2E A3 : %.9.... y.".....
System.Net.Sockets Verbose: 0 : [3848] 00000265 : 01 98 E6 AF 30 13 06 03-55 1D 25 04 0C 30 0A 06 : ....0...U.%..0..
System.Net.Sockets Verbose: 0 : [3848] 00000275 : 08 2B 06 01 05 05 07 03-01 30 1F 06 03 55 1D 23 : .+.......0...U.#
System.Net.Sockets Verbose: 0 : [3848] 00000285 : 04 18 30 16 80 14 53 FA-E2 5F A8 9E B1 10 55 65 : ..0...S.._....Ue
System.Net.Sockets Verbose: 0 : [3848] 00000295 : E3 53 13 1B 9E EF 2B 23-D8 F5 30 82 01 56 06 03 : .S....+#..0..V..
System.Net.Sockets Verbose: 0 : [3848] 000002A5 : 55 1D 1F 04 82 01 4D 30-82 01 49 30 82 01 45 A0 : U.....M0..I0..E.
System.Net.Sockets Verbose: 0 : [3848] 000002B5 : 82 01 41 A0 82 01 3D 86-81 A8 6C 64 61 70 3A 2F : ..A...=...ldap:/
System.Net.Sockets Verbose: 0 : [3848] 000002C5 : 2F 2F 43 4E 3D 4E 43 4C-43 45 52 54 53 45 52 56 : //CN=NCLCERTSERV
System.Net.Sockets Verbose: 0 : [3848] 000002D5 : 45 52 28 32 29 2C 43 4E-3D 77 69 74 34 2C 43 4E : ER(2),CN=wit4,CN
System.Net.Sockets Verbose: 0 : [3848] 000002E5 : 3D 43 44 50 2C 43 4E 3D-50 75 62 6C 69 63 25 32 : =CDP,CN=Public%2
System.Net.Sockets Verbose: 0 : [3848] 000002F5 : 30 4B 65 79 25 32 30 53-65 72 76 69 63 65 73 2C : 0Key%20Services,
System.Net.Sockets Verbose: 0 : [3848] 00000305 : 43 4E 3D 53 65 72 76 69-63 65 73 2C 44 43 3D 55 : CN=Services,DC=U
System.Net.Sockets Verbose: 0 : [3848] 00000315 : 6E 61 76 61 69 6C 61 62-6C 65 43 6F 6E 66 69 67 : navailableConfig
System.Net.Sockets Verbose: 0 : [3848] 00000325 : 44 4E 3F 63 65 72 74 69-66 69 63 61 74 65 52 65 : DN?certificateRe
System.Net.Sockets Verbose: 0 : [3848] 00000335 : 76 6F 63 61 74 69 6F 6E-4C 69 73 74 3F 62 61 73 : vocationList?bas
System.Net.Sockets Verbose: 0 : [3848] 00000345 : 65 3F 6F 62 6A 65 63 74-43 6C 61 73 73 3D 63 52 : e?objectClass=cR
System.Net.Sockets Verbose: 0 : [3848] 00000355 : 4C 44 69 73 74 72 69 62-75 74 69 6F 6E 50 6F 69 : LDistributionPoi
System.Net.Sockets Verbose: 0 : [3848] 00000365 : 6E 74 86 48 66 69 6C 65-3A 2F 2F 5C 5C 77 69 74 : nt.Hfile://\\wit
System.Net.Sockets Verbose: 0 : [3848] 00000375 : 34 2E 72 65 64 6D 6F 6E-64 2E 63 6F 72 70 2E 6D : 4.redmond.corp.m
System.Net.Sockets Verbose: 0 : [3848] 00000385 : 69 63 72 6F 73 6F 66 74-2E 63 6F 6D 5C 43 65 72 : icrosoft.com\Cer
System.Net.Sockets Verbose: 0 : [3848] 00000395 : 74 45 6E 72 6F 6C 6C 5C-4E 43 4C 43 45 52 54 53 : tEnroll\NCLCERTS
System.Net.Sockets Verbose: 0 : [3848] 000003A5 : 45 52 56 45 52 28 32 29-2E 63 72 6C 86 46 68 74 : ERVER(2).crl.Fht
System.Net.Sockets Verbose: 0 : [3848] 000003B5 : 74 70 3A 2F 2F 77 69 74-34 2E 72 65 64 6D 6F 6E : tp://wit4.redmon
System.Net.Sockets Verbose: 0 : [3848] 000003C5 : 64 2E 63 6F 72 70 2E 6D-69 63 72 6F 73 6F 66 74 : d.corp.microsoft
System.Net.Sockets Verbose: 0 : [3848] 000003D5 : 2E 63 6F 6D 2F 43 65 72-74 45 6E 72 6F 6C 6C 2F : .com/CertEnroll/
System.Net.Sockets Verbose: 0 : [3848] 000003E5 : 4E 43 4C 43 45 52 54 53-45 52 56 45 52 28 32 29 : NCLCERTSERVER(2)
System.Net.Sockets Verbose: 0 : [3848] 000003F5 : 2E 63 72 6C 30 81 FA 06-08 2B 06 01 05 05 07 01 : .crl0....+......
System.Net.Sockets Verbose: 0 : [3848] Exiting Socket#48285313::Receive() -> 1545#1545
System.Net Information: 0 : [3848] InitializeSecurityContext(credential = System.Net.SafeFreeCredential_SECURITY, context = 185a20:daf80, targetName = localhost, inFlags = ReplayDetect, SequenceDetect, Confidentiality, AllocateMemory, InitManualCredValidation)
System.Net Information: 0 : [3848] InitializeSecurityContext(In-Buffer length=1550, Out-Buffer length=204, returned code=ContinueNeeded).
System.Net.Sockets Verbose: 0 : [3848] Socket#48285313::Send()
System.Net.Sockets Verbose: 0 : [3848] Data from Socket#48285313::Send
System.Net.Sockets Verbose: 0 : [3848] 00000000 : 16 03 00 00 84 10 00 00-80 32 CB FC 3B 3B A6 67 : .........2..;;.g
System.Net.Sockets Verbose: 0 : [3848] 00000010 : BF F8 89 3F 40 CE 20 E4-79 92 4C 9C 8D 84 4C 77 : ...?@. .y.L...Lw
System.Net.Sockets Verbose: 0 : [3848] 00000020 : E6 BC 1D EA 59 95 F5 FA-E6 7B 35 40 68 EA 97 23 : ....Y....{5@h..#
System.Net.Sockets Verbose: 0 : [3848] 00000030 : 89 20 DD A5 E1 DD 2C 48-98 2F 2E C5 C3 4B 87 59 : . ....,H./...K.Y
System.Net.Sockets Verbose: 0 : [3848] 00000040 : C8 86 7F BA 85 CF BC B0-5C 26 1C E7 AA A6 C3 54 : ........\&.....T
System.Net.Sockets Verbose: 0 : [3848] 00000050 : 55 59 AE B3 3B 04 24 40-18 D5 B3 C8 57 02 83 E2 : UY..;.$@....W...
System.Net.Sockets Verbose: 0 : [3848] 00000060 : 46 2E 2B EA 1B C1 8E 6D-4A 3C E5 C7 5E 2E 47 24 : F.+....mJ<..^.G$
System.Net.Sockets Verbose: 0 : [3848] 00000070 : 13 DB 03 30 76 CB C4 19-FA D1 85 11 BD 5B AC A6 : ...0v........[..
System.Net.Sockets Verbose: 0 : [3848] 00000080 : 0D 60 9D E4 FB 6A BA 33-CB 14 03 00 00 01 01 16 : .`...j.3........
System.Net.Sockets Verbose: 0 : [3848] 00000090 : 03 00 00 38 B9 4C CA CF-CD C2 FF 20 61 43 8E 02 : ...8.L..... aC..
System.Net.Sockets Verbose: 0 : [3848] 000000A0 : 54 03 55 7D 6F 84 BE F9-B2 5D 44 31 1D FF B1 1F : T.U}o....]D1....
System.Net.Sockets Verbose: 0 : [3848] 000000B0 : 0F 45 04 81 ED 09 3A 2E-72 44 3E 37 B1 F6 CE 56 : .E....:.rD>7...V
System.Net.Sockets Verbose: 0 : [3848] 000000C0 : DB 67 11 8A E8 CE 35 23-DF 0B F5 3E : .g....5#...>
System.Net.Sockets Verbose: 0 : [3848] Exiting Socket#48285313::Send() -> 204#204
System.Net.Sockets Verbose: 0 : [3848] Socket#48285313::Receive()
System.Net.Sockets Verbose: 0 : [3848] Data from Socket#48285313::Receive
System.Net.Sockets Verbose: 0 : [3848] 00000000 : 14 03 00 00 01 : .....
System.Net.Sockets Verbose: 0 : [3848] Exiting Socket#48285313::Receive() -> 5#5
System.Net.Sockets Verbose: 0 : [3848] Socket#48285313::Receive()
System.Net.Sockets Verbose: 0 : [3848] Data from Socket#48285313::Receive
System.Net.Sockets Verbose: 0 : [3848] 00000005 : 01 : .
System.Net.Sockets Verbose: 0 : [3848] Exiting Socket#48285313::Receive() -> 1#1
System.Net Information: 0 : [3848] InitializeSecurityContext(credential = System.Net.SafeFreeCredential_SECURITY, context = 185a20:daf80, targetName = localhost, inFlags = ReplayDetect, SequenceDetect, Confidentiality, AllocateMemory, InitManualCredValidation)
System.Net Information: 0 : [3848] InitializeSecurityContext(In-Buffer length=6, Out-Buffer length=0, returned code=ContinueNeeded).
System.Net.Sockets Verbose: 0 : [3848] Socket#48285313::Receive()
System.Net.Sockets Verbose: 0 : [3848] Data from Socket#48285313::Receive
System.Net.Sockets Verbose: 0 : [3848] 00000000 : 16 03 00 00 38 : ....8
System.Net.Sockets Verbose: 0 : [3848] Exiting Socket#48285313::Receive() -> 5#5
System.Net.Sockets Verbose: 0 : [3848] Socket#48285313::Receive()
System.Net.Sockets Verbose: 0 : [3848] Data from Socket#48285313::Receive
System.Net.Sockets Verbose: 0 : [3848] 00000005 : 51 35 A8 FC 48 38 37 66-51 6D A3 A7 0C 10 95 93 : Q5..H87fQm......
System.Net.Sockets Verbose: 0 : [3848] 00000015 : 6B FF 8A 41 00 38 42 F4-B8 AA 0F C9 DB 71 16 46 : k..A.8B......q.F
System.Net.Sockets Verbose: 0 : [3848] 00000025 : 67 CA 04 20 F4 EF EB 31-EE BB C7 AD E8 7E B5 76 : g.. ...1.....~.v
System.Net.Sockets Verbose: 0 : [3848] 00000035 : 8D 63 96 99 96 63 53 3C- : .c...cS<
System.Net.Sockets Verbose: 0 : [3848] Exiting Socket#48285313::Receive() -> 56#56
System.Net Information: 0 : [3848] InitializeSecurityContext(credential = System.Net.SafeFreeCredential_SECURITY, context = 185a20:daf80, targetName = localhost, inFlags = ReplayDetect, SequenceDetect, Confidentiality, AllocateMemory, InitManualCredValidation)
System.Net Information: 0 : [3848] InitializeSecurityContext(In-Buffer length=61, Out-Buffer length=0, returned code=OK).
System.Net Information: 0 : [3848] Remote certificate: [Version]
V3
[Subject]
CN=dgortilt.redmond.corp.microsoft.com
Simple Name: dgortilt.redmond.corp.microsoft.com
DNS Name: dgortilt.redmond.corp.microsoft.com
[Issuer]
CN=NCLCERTSERVER, DC=redmond, DC=corp, DC=microsoft, DC=com
Simple Name: NCLCERTSERVER
DNS Name: NCLCERTSERVER
[Serial Number]
3474D06D00020000012B
[Not Before]
8/20/2005 5:30:25 PM
[Not After]
8/20/2006 5:40:25 PM
[Thumbprint]
19E34D7F445E49ACBD5EEECFF606F10197098F16
[Signature Algorithm]
sha1RSA(1.2.840.113549.1.1.5)
[Public Key]
Algorithm: RSA
Length: 1024
Key Blob: 30 81 89 02 81 81 00 cf e2 93 87 af 2a 19 56 47 cf e0 2f e3 13 b8 4f b7 20 c7 fa 1a 55 5f b0 3e 6e b6 4b 9b dc 50 1f 7e a7 5a 13 49 6d 8b 4a b1 27 50 91 47 51 6a 8d 21 d1 dc 6c c2 ad 1d 38 e2 20 8a 1a 75 24 f3 8f 51 e9 bd e7 f9 fe 8d 11 c9 3a 9e 88 b4 d0 a3 a9 c7 a6 7b c0 91 d9 1d 10 ae 00 38 c6 a9 8e 27 52 a5 48 5d dd df 4b bf f8 d0 43 ae 43 11 0f 0d a5 5e 2c a6 0a 37 9c ef 9b 5a 30 fc d3 8a 54 55 33 02 03 01 ....
System.Net Information: 0 : [3848] SecureChannel#34948909 - Remote certificate has errors:
System.Net Information: 0 : [3848] SecureChannel#34948909 - Certificate name mismatch.
System.Net Information: 0 : [3848] SecureChannel#34948909 - Remote certificate was verified as valid by the user.
System.Net.Sockets Verbose: 0 : [3848] Socket#48285313::Send()
System.Net.Sockets Verbose: 0 : [3848] Data from Socket#48285313::Send
System.Net.Sockets Verbose: 0 : [3848] 00000000 : 17 03 00 00 67 79 FD 10-7F A4 92 38 C5 80 38 EE : ....gy.....8..8.
System.Net.Sockets Verbose: 0 : [3848] 00000010 : 3A 6C 66 B7 0C CC C7 29-0C EC 3C 3B 88 D0 BE 94 : :lf....)..<;....
System.Net.Sockets Verbose: 0 : [3848] 00000020 : 6E C6 0D 7D B4 12 29 BD-ED 86 05 8C 17 CA 1B 9D : n..}..).........
System.Net.Sockets Verbose: 0 : [3848] 00000030 : D6 1A D7 65 D9 77 AD 5A-7C 17 E7 1A 78 69 90 B0 : ...e.w.Z|...xi..
System.Net.Sockets Verbose: 0 : [3848] 00000040 : DB 68 89 D8 F3 56 C2 D4-F8 52 CF EB 4B 1E 38 4B : .h...V...R..K.8K
System.Net.Sockets Verbose: 0 : [3848] 00000050 : D4 0D AA 5A 5C A4 C4 15-E8 AF F2 79 93 E0 06 37 : ...Z\......y...7
System.Net.Sockets Verbose: 0 : [3848] 00000060 : 10 CA 42 A9 49 8C B2 AC-33 85 68 80 : ..B.I...3.h.
System.Net.Sockets Verbose: 0 : [3848] Exiting Socket#48285313::Send() -> 108#108
System.Net Information: 0 : [3848] ConnectStream#18796293 - Sending headers
{
Host: localhost
Connection: Keep-Alive
}.
You can see clearly that
1) The Remote Certificate is being clearly presented in the log file.
2) Any errors in the remote certificate are logged.
3) In this case we are returning true for NAME MISMATCH if the server is local or intranet [Please see the
remore certificate validation callback code]
4) The fact that we accepted the certificate is also logged.
5) Then at the sockets level you can see encrypted data being sent
6) At the System.Net level (application level) you can see the decrypted data.
You can see now how easy it is to debug SSL apps using the system.Net tracing.
Let me know your comments
Durgaprasad Gorti
Test Lead
System.Net
Microsoft