windows-nt/Source/XPSP1/NT/net/rras/netsh/ip/ipmon/route.c

908 lines
21 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1998-1999 Microsoft Corporation
Module Name:
routing\netsh\ip\route.c
--*/
#include "precomp.h"
#pragma hdrstop
DWORD
AddSetDelRtmRouteInfo(
IN PINTERFACE_ROUTE_INFO pRoute,
IN LPCWSTR pwszIfName,
IN DWORD dwCommand,
IN DWORD dwFlags
)
/*++
Routine Description:
Adds/deletes normal (read as non persistant)
routes on interfaces.
Arguments:
pRoute - route to add/set/delete
pwszIfName - Interface Name
dwCommand - Add, set, or delete
Return Value:
NO_ERROR
--*/
{
ULONG dwOutEntrySize;
DWORD dwRes, i;
PMIB_IPDESTTABLE lpTable;
PMIB_IPDESTROW pEntry;
MIB_OPAQUE_QUERY QueryBuff[3]; // more than enough
MIB_OPAQUE_QUERY *pQuery = QueryBuff;
PMIB_OPAQUE_INFO pInfo;
DEFINE_MIB_BUFFER(pRouteInfo, MIB_IPDESTROW, pRouteRow);
if (!pRoute->dwRtInfoIfIndex)
{
//
// Get the interface index from friendly name
//
dwRes = IpmontrGetIfIndexFromFriendlyName(g_hMIBServer,
pwszIfName,
&pRoute->dwRtInfoIfIndex);
if (dwRes != NO_ERROR)
{
return dwRes;
}
//
// The interface probably is disconnected
//
if (pRoute->dwRtInfoIfIndex == 0)
{
DisplayMessage(g_hModule, EMSG_INTERFACE_INVALID_OR_DISC);
return ERROR_INVALID_PARAMETER;
}
}
//
// Use MprAdmin api to add, del or set entry
//
switch(dwCommand)
{
case ADD_COMMAND:
case SET_COMMAND:
//
// Does this route already exist in the router ?
//
// Get all this protocol routes on dest
pQuery->dwVarId = ROUTE_MATCHING;
pQuery->rgdwVarIndex[0] = pRoute->dwRtInfoDest;
pQuery->rgdwVarIndex[1] = pRoute->dwRtInfoMask;
pQuery->rgdwVarIndex[2] = RTM_VIEW_MASK_ANY;
pQuery->rgdwVarIndex[3] = pRoute->dwRtInfoProto;
pInfo = NULL;
dwRes = MibGet(PID_IP,
IPRTRMGR_PID,
(PVOID) pQuery,
sizeof(MIB_OPAQUE_QUERY) + 3 * sizeof(DWORD),
(PVOID *) &pInfo,
&dwOutEntrySize);
if ( dwRes isnot NO_ERROR )
{
DisplayMessage(g_hModule, MSG_IP_DIM_ERROR, dwRes );
return dwRes;
}
if ( pInfo isnot NULL )
{
//
// Search for a matching route
//
lpTable = (PMIB_IPDESTTABLE)(pInfo->rgbyData);
for (i=0; i<lpTable->dwNumEntries; i++)
{
pEntry = &lpTable->table[i];
if ((pEntry->dwForwardIfIndex == pRoute->dwRtInfoIfIndex) &&
(pEntry->dwForwardNextHop == pRoute->dwRtInfoNextHop))
{
break;
}
}
if (i == lpTable->dwNumEntries)
{
//
// No matching route found - quit if set
//
if (dwCommand == SET_COMMAND)
{
MprAdminMIBBufferFree((PVOID)pInfo);
return ERROR_NOT_FOUND;
}
}
else
{
//
// A matching route found - quit if add
//
if (dwCommand == ADD_COMMAND)
{
MprAdminMIBBufferFree((PVOID)pInfo);
return ERROR_OBJECT_ALREADY_EXISTS;
}
}
}
else
{
//
// No matching routes found - quit if set
//
if (dwCommand == SET_COMMAND)
{
return ERROR_NOT_FOUND;
}
}
//
// Convert the route to a ip route row format
//
pRouteInfo->dwId = ROUTE_MATCHING;
pRouteRow->dwForwardDest = pRoute->dwRtInfoDest;
pRouteRow->dwForwardMask = pRoute->dwRtInfoMask;
pRouteRow->dwForwardPolicy = 0;
pRouteRow->dwForwardNextHop = pRoute->dwRtInfoNextHop;
pRouteRow->dwForwardIfIndex = pRoute->dwRtInfoIfIndex;
pRouteRow->dwForwardType = 0;
pRouteRow->dwForwardProto = pRoute->dwRtInfoProto;
pRouteRow->dwForwardAge = INFINITE;
pRouteRow->dwForwardNextHopAS = 0;
pRouteRow->dwForwardMetric1 = pRoute->dwRtInfoMetric1;
pRouteRow->dwForwardMetric2 = pRoute->dwRtInfoMetric2;
pRouteRow->dwForwardMetric3 = pRoute->dwRtInfoMetric3;
pRouteRow->dwForwardMetric4 = MIB_IPROUTE_METRIC_UNUSED;
pRouteRow->dwForwardMetric5 = MIB_IPROUTE_METRIC_UNUSED;
pRouteRow->dwForwardPreference = pRoute->dwRtInfoPreference;
pRouteRow->dwForwardViewSet = pRoute->dwRtInfoViewSet;
if (dwCommand == ADD_COMMAND)
{
dwRes = MprAdminMIBEntryCreate(g_hMIBServer,
PID_IP,
IPRTRMGR_PID,
(PVOID)pRouteInfo,
MIB_INFO_SIZE(MIB_IPDESTROW));
}
else
{
if (dwFlags & FIELDS_NOT_SPECIFIED)
{
//
// Get the old preference, metric, or view
//
if (dwFlags & PREF_NOT_SPECIFIED)
{
pRouteRow->dwForwardPreference=pEntry->dwForwardPreference;
}
if (dwFlags & METRIC_NOT_SPECIFIED)
{
pRouteRow->dwForwardMetric1 = pEntry->dwForwardMetric1;
}
if (dwFlags & VIEW_NOT_SPECIFIED)
{
pRouteRow->dwForwardViewSet = pEntry->dwForwardViewSet;
}
}
dwRes = MprAdminMIBEntrySet(g_hMIBServer,
PID_IP,
IPRTRMGR_PID,
(PVOID)pRouteInfo,
MIB_INFO_SIZE(MIB_IPDESTROW));
}
// Free the old route information obtained
if (pInfo)
{
MprAdminMIBBufferFree((PVOID)pInfo);
}
break;
case DELETE_COMMAND:
{
DWORD rgdwInfo[6];
PMIB_OPAQUE_QUERY pIndex = (PMIB_OPAQUE_QUERY)rgdwInfo;
pIndex->dwVarId = ROUTE_MATCHING;
pIndex->rgdwVarIndex[0] = pRoute->dwRtInfoDest;
pIndex->rgdwVarIndex[1] = pRoute->dwRtInfoMask;
pIndex->rgdwVarIndex[2] = pRoute->dwRtInfoIfIndex;
pIndex->rgdwVarIndex[3] = pRoute->dwRtInfoNextHop;
pIndex->rgdwVarIndex[4] = pRoute->dwRtInfoProto;
dwRes = MprAdminMIBEntryDelete(g_hMIBServer,
PID_IP,
IPRTRMGR_PID,
(PVOID)pIndex,
sizeof(rgdwInfo));
break;
}
default:
dwRes = ERROR_INVALID_PARAMETER;
}
return dwRes;
}
DWORD
AddSetDelPersistentRouteInfo(
IN PINTERFACE_ROUTE_INFO pRoute,
IN LPCWSTR pwszIfName,
IN DWORD dwCommand,
IN DWORD dwFlags
)
/*++
Routine Description:
Adds/deletes persitant routes on interfaces.
Arguments:
route - route to add/set/delete
pwszIfName - Interface Name
dwCommand - Add, set, or delete
Return Value:
ERROR_OKAY
--*/
{
DWORD dwRes;
PINTERFACE_ROUTE_INFO pOldTable, pNewTable;
DWORD dwIfType, dwSize, dwCount;
pNewTable = NULL;
do
{
dwRes = IpmontrGetInfoBlockFromInterfaceInfo(pwszIfName,
IP_ROUTE_INFO,
(PBYTE *) &pOldTable,
&dwSize,
&dwCount,
&dwIfType);
if((dwRes is ERROR_NOT_FOUND) &&
dwCommand is ADD_COMMAND)
{
//
// No route info but we are asked to add
//
pOldTable = NULL;
dwRes = NO_ERROR;
dwCount = 0;
}
if(dwRes isnot NO_ERROR)
{
break;
}
//
// These take the old table and return a new one in its stead
//
switch(dwCommand)
{
case ADD_COMMAND:
dwRes = AddRoute(pOldTable,
pRoute,
dwIfType,
&dwCount,
&pNewTable);
break;
case DELETE_COMMAND:
dwRes = DeleteRoute(pOldTable,
pRoute,
dwIfType,
&dwCount,
&pNewTable);
break;
case SET_COMMAND:
dwRes = SetRoute(pOldTable,
pRoute,
dwIfType,
dwFlags,
&dwCount);
pNewTable = pOldTable;
pOldTable = NULL;
break;
}
if(dwRes != NO_ERROR)
{
break;
}
//
// Set the new info back
//
dwRes = IpmontrSetInfoBlockInInterfaceInfo(pwszIfName,
IP_ROUTE_INFO,
(PBYTE)pNewTable,
sizeof(INTERFACE_ROUTE_INFO),
dwCount);
if(dwRes != NO_ERROR)
{
break;
}
pNewTable = NULL;
} while ( FALSE );
if(pOldTable)
{
FREE_BUFFER(pOldTable);
}
if(pNewTable)
{
HeapFree(GetProcessHeap(),
0,
pNewTable);
pNewTable = NULL;
}
switch(dwRes)
{
case NO_ERROR:
{
dwRes = ERROR_OKAY;
break;
}
case ERROR_NOT_FOUND:
{
WCHAR wszBuffer[MAX_INTERFACE_NAME_LEN+1];
DWORD dwSizeTemp = sizeof(wszBuffer);
IpmontrGetFriendlyNameFromIfName( pwszIfName, wszBuffer, &dwSizeTemp);
DisplayMessage(g_hModule, EMSG_IP_NO_ROUTE_INFO, wszBuffer);
dwRes = ERROR_SUPPRESS_OUTPUT;
break;
}
case ERROR_NOT_ENOUGH_MEMORY:
{
DisplayMessage(g_hModule, MSG_IP_NOT_ENOUGH_MEMORY);
dwRes = ERROR_SUPPRESS_OUTPUT;
break;
}
}
return dwRes;
}
DWORD
SetRoute(
IN PINTERFACE_ROUTE_INFO pTable,
IN PINTERFACE_ROUTE_INFO pRoute,
IN DWORD dwIfType,
IN DWORD dwFlags,
IN OUT PDWORD pdwCount
)
{
ULONG ulIndex, i;
//
// If the count is 0, the function will return false
// and we will error out
//
if(!IsRoutePresent(pTable,
pRoute,
dwIfType,
*pdwCount,
&ulIndex))
{
return ERROR_NOT_FOUND;
}
if (dwFlags & FIELDS_NOT_SPECIFIED)
{
//
// Preserve the old values if not specified
//
if (dwFlags & PREF_NOT_SPECIFIED)
{
pRoute->dwRtInfoPreference = pTable[ulIndex].dwRtInfoPreference;
}
if (dwFlags & METRIC_NOT_SPECIFIED)
{
pRoute->dwRtInfoMetric1 = pTable[ulIndex].dwRtInfoMetric1;
}
if (dwFlags & VIEW_NOT_SPECIFIED)
{
pRoute->dwRtInfoViewSet = pTable[ulIndex].dwRtInfoViewSet;
}
}
pTable[ulIndex] = *pRoute;
return NO_ERROR;
}
DWORD
AddRoute(
IN PINTERFACE_ROUTE_INFO pOldTable,
IN PINTERFACE_ROUTE_INFO pRoute,
IN DWORD dwIfType,
IN OUT PDWORD pdwCount,
OUT INTERFACE_ROUTE_INFO **ppNewTable
)
/*++
Routine Description:
Adds a route to the current info
Arguments:
Return Value:
NO_ERROR
--*/
{
ULONG ulIndex, i;
if(IsRoutePresent(pOldTable,
pRoute,
dwIfType,
*pdwCount,
&ulIndex))
{
return ERROR_OBJECT_ALREADY_EXISTS;
}
//
// Just create a block with size n + 1
//
*ppNewTable = HeapAlloc(GetProcessHeap(),
0,
((*pdwCount) + 1) * sizeof(INTERFACE_ROUTE_INFO));
if(*ppNewTable is NULL)
{
return ERROR_NOT_ENOUGH_MEMORY;
}
for(i = 0; i < *pdwCount; i++)
{
//
// structure copy
//
(*ppNewTable)[i] = pOldTable[i];
}
//
// copy the new route
//
(*ppNewTable)[i] = *pRoute;
*pdwCount += 1;
return NO_ERROR;
}
DWORD
DeleteRoute(
IN PINTERFACE_ROUTE_INFO pOldTable,
IN PINTERFACE_ROUTE_INFO pRoute,
IN DWORD dwIfType,
IN OUT PDWORD pdwCount,
OUT INTERFACE_ROUTE_INFO **ppNewTable
)
/*++
Routine Description:
Deletes a route from an interface
Arguments:
Return Value:
NO_ERROR
--*/
{
ULONG ulIndex, i, j;
//
// If the count is 0, the function will return false
// and we will error out
//
if(!IsRoutePresent(pOldTable,
pRoute,
dwIfType,
*pdwCount,
&ulIndex))
{
return ERROR_NOT_FOUND;
}
//
// If the count is 1
//
*pdwCount -= 1;
if(*pdwCount is 0)
{
*ppNewTable = NULL;
return NO_ERROR;
}
//
// delete the route
//
*ppNewTable = HeapAlloc(GetProcessHeap(),
0,
(*pdwCount) * sizeof(INTERFACE_ROUTE_INFO));
if(*ppNewTable is NULL)
{
return ERROR_NOT_ENOUGH_MEMORY;
}
i = j = 0;
while(i <= *pdwCount)
{
if(i == ulIndex)
{
i++;
continue;
}
//
// structure copy
//
(*ppNewTable)[j] = pOldTable[i];
i++;
j++;
}
return NO_ERROR;
}
BOOL
IsRoutePresent(
IN PINTERFACE_ROUTE_INFO pTable,
IN PINTERFACE_ROUTE_INFO pRoute,
IN DWORD dwIfType,
IN ULONG ulCount,
OUT PULONG pulIndex
)
/*++
Routine Description:
Checks to see if interface is already present
Arguments:
Return Value:
NO_ERROR
--*/
{
ULONG i;
BOOL bDontMatchNHop;
if((dwIfType is ROUTER_IF_TYPE_DEDICATED) or
(dwIfType is ROUTER_IF_TYPE_INTERNAL))
{
bDontMatchNHop = FALSE;
}
else
{
bDontMatchNHop = TRUE;
}
// Do this check just to keep the prefix checker happy
if (pTable is NULL)
{
return FALSE;
}
for(i = 0; i < ulCount; i++)
{
if((pTable[i].dwRtInfoDest is pRoute->dwRtInfoDest) and
(pTable[i].dwRtInfoMask is pRoute->dwRtInfoMask) and
#if 0
(pTable[i].dwRtInfoProto is pRoute->dwRtInfoProto) and
#endif
(bDontMatchNHop or
(pTable[i].dwRtInfoNextHop is pRoute->dwRtInfoNextHop)))
{
*pulIndex = i;
return TRUE;
}
}
return FALSE;
}
DWORD
ShowIpPersistentRoute(
IN HANDLE hFile, OPTIONAL
IN LPCWSTR pwszIfName,
IN OUT PDWORD pdwNumRows
)
/*++
Routine Description:
Show the static (persistent) routes on the interface
Arguments:
pwszIfName - Interface name
Return Value:
NO_ERROR
--*/
{
PINTERFACE_ROUTE_INFO pRoutes;
DWORD dwErr, dwBlkSize, dwCount, dwIfType, dwNumParsed, i;
WCHAR wszNextHop[ADDR_LENGTH + 1];
WCHAR wszIfDesc[MAX_INTERFACE_NAME_LEN + 1];
PWCHAR pwszProto, pwszToken, pwszQuoted;
WCHAR wszViews[3];
dwErr = GetInterfaceDescription(pwszIfName,
wszIfDesc,
&dwNumParsed);
if (!dwNumParsed)
{
wcscpy(wszIfDesc, pwszIfName);
}
//
// Retrieve the routes
//
dwErr = IpmontrGetInfoBlockFromInterfaceInfo(pwszIfName,
IP_ROUTE_INFO,
(PBYTE *) &pRoutes,
&dwBlkSize,
&dwCount,
&dwIfType);
if (dwErr != NO_ERROR)
{
return dwErr;
}
if((pRoutes == NULL) ||
(dwCount == 0))
{
return NO_ERROR;
}
if(hFile == NULL)
{
if (*pdwNumRows is 0)
{
DisplayMessage(g_hModule, MSG_RTR_ROUTE_HDR);
}
pwszQuoted = NULL;
}
else
{
pwszQuoted = MakeQuotedString(wszIfDesc);
}
for(i = 0; i < dwCount; i++)
{
wszViews[0] = (pRoutes[i].dwRtInfoViewSet & RTM_VIEW_MASK_UCAST)? 'U':' ';
wszViews[1] = (pRoutes[i].dwRtInfoViewSet & RTM_VIEW_MASK_MCAST)? 'M':' ';
wszViews[2] = '\0';
switch(pRoutes[i].dwRtInfoProto)
{
case PROTO_IP_NT_AUTOSTATIC:
{
pwszProto = MakeString(g_hModule, STRING_NT_AUTOSTATIC);
pwszToken = TOKEN_VALUE_AUTOSTATIC;
break;
}
case PROTO_IP_NT_STATIC:
{
pwszProto = MakeString(g_hModule, STRING_STATIC);
pwszToken = TOKEN_VALUE_STATIC;
break;
}
case PROTO_IP_NT_STATIC_NON_DOD:
{
pwszProto = MakeString(g_hModule, STRING_NONDOD);
pwszToken = TOKEN_VALUE_NONDOD;
break;
}
default:
{
pwszProto = MakeString(g_hModule, STRING_PROTO_UNKNOWN);
pwszToken = NULL;
break;
}
}
MakeUnicodeIpAddr(wszNextHop,
inet_ntoa(*((struct in_addr *)&(pRoutes[i].dwRtInfoNextHop))));
if(hFile)
{
if(pwszToken)
{
WCHAR wszMask[ADDR_LENGTH + 1], wszDest[ADDR_LENGTH + 1];
PWCHAR pwszView = NULL;
MakeUnicodeIpAddr(wszDest,
inet_ntoa(*((struct in_addr *)&(pRoutes[i].dwRtInfoDest))));
MakeUnicodeIpAddr(wszMask,
inet_ntoa(*((struct in_addr *)&(pRoutes[i].dwRtInfoMask))));
switch (pRoutes[i].dwRtInfoViewSet)
{
case RTM_VIEW_MASK_UCAST: pwszView=TOKEN_VALUE_UNICAST ; break;
case RTM_VIEW_MASK_MCAST: pwszView=TOKEN_VALUE_MULTICAST; break;
case RTM_VIEW_MASK_UCAST
|RTM_VIEW_MASK_MCAST: pwszView=TOKEN_VALUE_BOTH; break;
}
if (pwszView)
{
DisplayMessageT( DMP_IP_ADDSET_PERSISTENTROUTE,
wszDest,
wszMask,
pwszQuoted,
wszNextHop,
pwszToken,
pRoutes[i].dwRtInfoPreference,
pRoutes[i].dwRtInfoMetric1,
pwszView );
}
}
}
else
{
WCHAR wcszBuffer[80];
MakePrefixStringW( wcszBuffer,
pRoutes[i].dwRtInfoDest,
pRoutes[i].dwRtInfoMask );
DisplayMessage(g_hModule,
MSG_RTR_ROUTE_INFO,
wcszBuffer,
pwszProto,
pRoutes[i].dwRtInfoPreference,
pRoutes[i].dwRtInfoMetric1,
wszNextHop,
wszViews,
wszIfDesc);
(*pdwNumRows)++;
}
FreeString(pwszProto);
}
if(pwszQuoted)
{
FreeQuotedString(pwszQuoted);
}
HeapFree(GetProcessHeap(),
0,
pRoutes);
return NO_ERROR;
}