<

VPN: use default gateway AND access your local network

Published on
18,567 Points
12,467 Views
1 Endorsement
Last Modified:
Approved
Sometimes, you want your microsoft VPN to route all the traffic to the remote network. Usually your employer network. This makes it possible to access all the nodes inside this remote LAN, even if they have no "public DNS" entries.
To do so, you would configure the VPN connexion so that it becomes your "default gateway".
Nice.
It works great, you can connect to all the nodes in the remote LAN.
But now you need to print something on your local printer. It's a networked printer, on YOUR LAN.
Since all your traffic is routed to the remote LAN, you'll never reach anything on YOUR LAN.
This example uses a networked printer but it can be a network attached storage, a file server, a media server... Anything that is available on your LAN.
So what you usually do?
You disconnect the VPN, and voila.
But know, when you realize that you need to connect to your remote LAN again, you loose the connection to your own LAN.
Especially frustrating if you need to access some Intranet. You would have to make local copies (or print web pages to pdf...), disconnect, use the local copies. It can even become a security concern, because things that should not leave the Intranet are now on your LAN.

The problem is that with a VPN that uses the default gateway on the remote network, this forces the use of the remote gateway as the default gateway and this sets the route to this default gateway to use a metric of 1.

Fortunately, there is at least one solution:

Basically, what I do is that I set a standard VPN connection, that I customize so that it will not use the remote LAN default gateway. And then I change the routing table so that my default gateway stays my home router (or the hotel router) and at the same time, all the traffic to my employers network go through the VPN link.

My employers owns 2 C-Class Internet ranges so the routing to my employer's network is easy to figure out.

OTOH, when specifying a route in Windows, one must know the IP address and ID of the interface to use for these packets. And a VPN interface (actually a WAN PPP interface) has the nasty habit of changing its ID each time it is launched, and usually, it will also get a different IP address each time. So I developed a small utility to recover this ID and store it in an environment variable.

Then, I just have to invoke the corresponding "route change" or "route add" commands to add the routes to my employers C-Class and to make these route using the VPN interface.

It may seem more complicated than it is.

1st thing:
Create the VPN connexion using standard MS Windows VPN.
In my case, my employer uses a simple PPTP tunnel, so it is very easy. But L2TP should be as easy. IPSEC might be a little more complex, but if you use IPSEC, you might skip this step and just change the routing as described below.

In order to set a Windows based VPN, you can use this tutorial:
https://people.chem.umass.edu/wiki/index.php?title=VPN_-_Connect_from_Windows_XP

One thing you must NOT forget is to uncheck the "Use default gateway on remote network":

400px-Winxp-tcpip-advanced-gatew.png

This is the last screen of the tutorial mentioned above... If you do not know how to get there, just follow the tutorial above.


2nd thing:
Change the routing table

I use a .bat file like this one (I changed the real network classes...) :

NICIndex.exe /IPPrefix=193.105.13. /Type=PPP > %temp%\SetPPP.bat
if exist %temp%\SetPPP.bat call %temp%\SetPPP.bat
route add 192.105.13.0 MASK 255.255.255.0 %NICIP% Metric 50 IF %NICIDX%
route add 192.105.14.0 MASK 255.255.255.0 %NICIP% Metric 50 IF %NICIDX%

Open in new window

What you miss is my NICIndex tool that can be downloaded from this site, just following the link above.
It is a Delphi program which uses WMI to get the network adapters information.
It gets the ID of the first interface it founds which IP address begins with the parameter passed to it. In the example above:
NICIndex.exe /IPPrefix=193.105.13. /type=PPP
will get the interface ID of the first network interface which type is "PPP" (Point to point protocol, which is the type of VPN interfaces. The other types that you might use are "Ethernet" and, maybe, "TokenRing"...) that has an IP address beginning with 193.105.13
It will display this ID in the form
SET NICIDX=

for instance SET NICIDX=0x2000A
It also displays the interface IP address in the form
SET NICIP=193.195.13.127

Actually, NICPPPIndex.exe displays something like
SET NICIDX=
SET NICIP=
SET NICIP=193.195.13.127
SET NICIDX=0x2000A

So calling it this way:

NICIndex.exe /IPPrefix=193.105.13. /Type=PPP > %temp%\SetPPP.bat

Open in new window


you create a SetPPP.bat file in your temp folder.
When you call this SetPPP.bat file, you create the NICIP and NICIDX environment variables that you need to tune your routing table.
Thus my "VPNRoute.bat" file:

NICIndex.exe /IPPrefix=193.105.13. /Type=PPP > %temp%\SetPPP.bat
if exist %temp%\SetPPP.bat call %temp%\SetPPP.bat
route add 192.105.13.0 MASK 255.255.255.0 %NICIP% Metric 50 IF %NICIDX%
route add 192.105.14.0 MASK 255.255.255.0 %NICIP% Metric 50 IF %NICIDX%

Open in new window

In order for this to work, you need the NICIndex.exe file. And it must be in your PATH.


3rd thing:
Now connect it !

The only thing you have to do is to launch the VPN connection. When it is OK, launch the VPNRoute.bat file (for instance copy it on your desktop, after having modified it to suit your particular networking configuration)


Open Source !

My NICIndex source file, in Delphi, is here. Very simple.
NICIndex Source is available for download here:
http://www.filefactory.com/file/b13g5c3/n/NICIndex.dpr

I also include the full source text hereafter

program NICIndex;


{$APPTYPE CONSOLE}

uses
  SysUtils,
  Windows;

const
  MAX_ADAPTER_NAME_LENGTH        = 256;
  MAX_ADAPTER_DESCRIPTION_LENGTH = 128;
  MAX_ADAPTER_ADDRESS_LENGTH     = 8;

  TnTYPE:array[0..28] of AnsiString=('','','','','','','Ethernet','','','Token ring','','','','','','FDDI','','','','','','','','PPP','Loopback','','','','Slip');

type
  PrIP_ADDRESS=^TrIP_ADDRESS;
  TrIP_ADDRESS=record
    Next:PrIP_ADDRESS;
    IpAddress:array[0..15] of Char;
    IpMask:array[0..15] of Char;
    Context:DWORD;
  end;

  PrADAPTER=^TrADAPTER;
  TrADAPTER=record
    FNext:PrADAPTER;
    FComboIndex:DWORD;
    FAdapterName:array[0..MAX_ADAPTER_NAME_LENGTH+3] of Char;
    FDescription:array[0..MAX_ADAPTER_DESCRIPTION_LENGTH+3] of Char;
    FAddrLen:UINT;
    FAddress:array[0..MAX_ADAPTER_ADDRESS_LENGTH-1] of Byte;
    FIndex:DWORD;
    FType:UINT;
    FDHCPEnabled:UINT;
    FCurrentIpAddress:PrIP_ADDRESS;
    FIpAddressList:TrIP_ADDRESS;
    FGatewayList:TrIP_ADDRESS;
    FDHCPServer:TrIP_ADDRESS;
    FHaveWins:BOOL;
    FPrimaryWinsServer:TrIP_ADDRESS;
    FSecondaryWinsServer:TrIP_ADDRESS;
    FLeaseObtained:Longint;
    FLeaseExpires:Longint;
  end;

function GetAdaptersInfo(pAdapterInfo:PrADAPTER;pOutputBuffer:PULONG):DWORD;stdcall;external 'IPHlpAPI.dll' name 'GetAdaptersInfo';


var
  Size:DWORD;
  Info,P:PrADAPTER;
  Found:Boolean=False;
  PPPIP: string;
  IPPrefix, NICType: string;
  I: byte;


begin
  Writeln(ErrOutput,ExtractFileName(ParamStr(0))+'   Usage: ');
  Writeln(ErrOutput,ExtractFileName(ParamStr(0))+'   [/IPPREFIX=<IP address Prefix> | /Type=<Interface Type>]');
  Writeln(ErrOutput,'Examples: '+ExtractFileName(ParamStr(0))+' /IPPREFIX=192.168.4.');
  Writeln(ErrOutput,'          '+ExtractFileName(ParamStr(0))+' /Type=Ethernet');
  Writeln(ErrOutput,'          '+ExtractFileName(ParamStr(0))+' /IPPREFIX=192.168.6. /Type=PPP');

  Size:=0;
  P:=nil;
  GetAdaptersInfo(P,@Size);
  GetMem(P,Size);
  GetAdaptersInfo(P,@Size);
  writeln('SET NICIDX=');
  writeln('SET NICIP=');
  PPPIP:='';
  IPPrefix:='';;
  NICType:='';
  for I:=1 to ParamCount do
  begin
    if Uppercase(Copy(ParamStr(I),1,Length('/IPPREFIX=')))='/IPPREFIX=' then IPPREFIX:=Copy(ParamStr(I),Length('/IPPREFIX=')+1,Length(ParamStr(I))-Length('/IPPREFIX='));
    if Uppercase(Copy(ParamStr(I),1,Length('/Type=')))='/TYPE=' then NICType:=Copy(ParamStr(I),Length('/Type=')+1,Length(ParamStr(I))-Length('/Type='));
  end;
{$IFDEF DEBUG}
  Writeln(ErrOutput,'IPPrefix='+IPPrefix);
  Writeln(ErrOutput,'NICType='+NICType);
{$ENDIF}
  try
    Info:=P;
    if Assigned(P) then
// just printout - not needed
    repeat
      PPPIP:=PChar(@Info^.FIpAddressList.IpAddress);
      if (IPPrefix<>'') and (NICType<>'') then Found:= (UpperCase(TnTYPE[Info^.FType])=UpperCase(NICType)) and (Pos(IPPrefix,PPPIP)=1)
      else
      begin
       if NICType<>'' then Found:=(UpperCase(TnTYPE[Info^.FType])=UpperCase(NICType))
       else if IPPrefix<>'' then Found:=(Pos(IPPrefix,PPPIP)=1);
      end;

      if (Found) then
      begin
        writeln('SET NICIP=',PPPIP);
        writeln('SET NICIDX=',Format('0x%x',[Info^.FIndex]));
        exit;
      end;
      Info:=Info^.FNext;
    until not Assigned(Info);
  finally
    FreeMem(P);
  end;
end.

Open in new window


 NICIndex.zip
1
Author:vivigatt
Enjoy this complimentary article view.

Get unlimited access to our entire library of technical procedures, guides, and tutorials written by certified industry professionals.

Get 7 days free
Click here to view the full article

Using this article for work? Experts Exchange can benefit your whole team.

Learn More
COLLABORATE WITH CERTIFIED PROFESSIONALS
Experts Exchange is a tech solutions provider where users receive personalized tech help from vetted certified professionals. These industry professionals also write and publish relevant articles on our site.
Ask questions about what you read
If you have a question about something within an article, you can receive help directly from the article author. Experts Exchange article authors are available to answer questions and further the discussion.
Learn from the best.