/*++ 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; idwNumEntries; 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; }