Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Сети > Добавление маршрутов


Автор: Maks1509 23.10.2009, 22:24
Приветствую. Необходимо создать постоянный маршрут в системах Vista / 7. Под 2000 и XP все прекрасно создается, а тут загвоздка. Впринципе в таблицу маршрутизации маршрут добавляется, что подтверждается демо примером iphlpapi для Delphi, идущим с заголовочными модулями, но если в командной строке выполнить команду route print, список постоянных маршрутов пуст.

Код

function CreatePersistentRoute(network, netmask, gateway: AnsiString): Boolean;
var
  pRoute : MIB_IPFORWARDROW;
  dwError: DWORD;
  ifIndex: DWORD;
  fMetric: DWORD;
  szRoute: AnsiString;
  lResult: Integer;
begin

  // WriteLn('Enter your gateway IP...');
  // ReadLn(gateway);

  Result := FALSE;

  // первоначально выставляем индекс интерфейса чтобы после определить, нужно
  // ли выполнять последующие действия.

  ifIndex := DWORD(-1);

  // пытаемся узнать индекс интерфейса, котоырй имеет оптимальный маршрут до
  // указанного адреса IPv4.

  try
    dwError := GetBestInterface(inet_addr(@gateway[1]), ifIndex);
    case dwError of
      ERROR_SUCCESS:
        WriteLn('GetBestInterface: ERROR_SUCCESS');
      ERROR_NOT_SUPPORTED:
        WriteLn('GetBestInterface: ERROR_NOT_SUPPORTED');
      ERROR_CAN_NOT_COMPLETE:
        WriteLn('GetBestInterface: ERROR_CAN_NOT_COMPLETE');
      else
        WriteLn('GetBestInterface: Unknown ERROR - ' + IntToStr(dwError));
    end;
  except
    WriteLn('GetBestInterface: EXCEPT');
  end;

  // если индекс интерфейса не удалось узнать, то дальше ничего не выполняем.

  if (ifIndex = DWORD(-1)) then
    Exit;

  // проверяем адрес маски подсети и если он пуст, то автоматически его
  // указываем.

  try
    if (netmask = '') then
      netmask := '255.255.255.255';

    dwError := GetBestRoute(inet_addr(@network[1]), 0, pRoute);
    case dwError of
      NO_ERROR:
        WriteLn('GetBestRoute: NO_ERROR');
      else
        WriteLn('GetBestRoute: Unknown ERROR - ' + IntToStr(dwError));
    end;

    fMetric := pRoute.dwForwardMetric1;

    // MessageBox(0, PAnsiChar(gateway), nil, MB_OK);
    // Exit;

    // заполняем структуру MIB_IPFORWARDROW нужной информацией и создаем
    // маршрут в таблице маршрутов.

    ZeroMemory(@pRoute, SizeOf(MIB_IPFORWARDROW));

    pRoute.dwForwardDest      := inet_addr(@network[1]);
    pRoute.dwForwardMask      := inet_addr(@netmask[1]);
    pRoute.dwForwardPolicy    := 0;
    pRoute.dwForwardNextHop   := inet_addr(@gateway[1]);
    pRoute.dwForwardIfIndex   := ifIndex;
    pRoute.dwForwardType      := MIB_IPROUTE_TYPE_DIRECT;
    pRoute.dwForwardProto     := PROTO_IP_NETMGMT;
    pRoute.dwForwardAge       := 0;
    pRoute.dwForwardNextHopAS := 0;
    pRoute.dwForwardMetric1   := fMetric;
    pRoute.dwForwardMetric2   := DWORD(-1);
    pRoute.dwForwardMetric3   := DWORD(-1);
    pRoute.dwForwardMetric4   := DWORD(-1);
    pRoute.dwForwardMetric5   := DWORD(-1);

    dwError := CreateIpForwardEntry(@pRoute);
    lResult := GetLastError;
    case dwError of
      NO_ERROR:
        begin

          WriteLn('CreateIpForwardEntry: NO_ERROR');
          WriteLn('GetLastError: ' + IntToStr(lResult));
          // нам необходимо создать постоянный маршрут, поэтому нужно добавить
          // сведения о нем в соответствующий раздел реестра, а также заодно и
          // проверим возвращаемый результат от функции.

          szRoute := Format('%s,%s,%s,1', [network, netmask, gateway]);
          
          // запись в ключи ControlSet001 и ControlSet002 необходимо выполнять
          // только в системах Vista и 7. в предыдущих системах достаточно ключа
          // CurrentControlSet.

          if RegWriteString(HKEY_LOCAL_MACHINE, 'SYSTEM\ControlSet001\services\Tcpip\Parameters\PersistentRoutes', szRoute, '') then
            WriteLn('RegWriteString (1) - OK');
          if RegWriteString(HKEY_LOCAL_MACHINE, 'SYSTEM\ControlSet002\services\Tcpip\Parameters\PersistentRoutes', szRoute, '') then
            WriteLn('RegWriteString (2) - OK');
          if RegWriteString(HKEY_LOCAL_MACHINE, 'SYSTEM\CurrentControlSet\services\Tcpip\Parameters\PersistentRoutes', szRoute, '') then
            WriteLn('RegWriteString (3) - OK');

          Result := TRUE;

        end;
      ERROR_ACCESS_DENIED:
        WriteLn('CreateIpForwardEntry: ERROR_ACCESS_DENIED');
      ERROR_INVALID_PARAMETER:
        WriteLn('CreateIpForwardEntry: ERROR_INVALID_PARAMETER');
      ERROR_NOT_SUPPORTED:
        WriteLn('CreateIpForwardEntry: ERROR_NOT_SUPPORTED');
      else
        WriteLn('CreateIpForwardEntry: Unknown ERROR - ' + IntToStr(dwError));
    end;
  except
    WriteLn('CreateIpForwardEntry: EXCEPT');
  end;

  //route ADD 77.88.0.0 MASK 255.255.224.0 192.168.75.2 -P
  // if CreatePersistentRoute('77.88.0.0', '255.255.224.0', '192.168.75.2') then
  //  MessageBox(0, 'Route success create!', nil, MB_OK);
end;


Есть несколько вопросов:

1. Если не вызывать GetBestRoute для сохранения метрики интерфейса из заполненной структуры, почему-то CreateIpForwardEntry выдает ошибку 160, хотя GetLastError выдает при этом 0. До этого указывал метрику равную 1. Под XP и 2000 все прекрасно работает, а тут вообще непонятно какое значение подставить. Просто случайно обнаружил данный способ. Работает конечно, но как-то уж криво реализованный он, да и сомнение есть по этому поводу.

2. Проверяю код на виртуальнйо машине так как просто не хочу устанавливать Vista и 7. Может быть оно и работает как надо и только на виртуальной машине проявляется этот глюк. Просмотрел снимки реестра до и после работы системной программы route  с целью получения информации чтоже она доабвляет-то в реестр раз после ее манипуляций она показывает постоянный маршрут.

Код

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Nsi\{eb004a00-9b1a-11d4-9123-0050047759bc}\16]
"000000004d5800001300000000000000000000000000000000000000000000000000000000000000c0a84b0200000000"=hex:ff,\
  ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,01,00,00,00,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,\
  ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,\
  ff,ff,ff,ff,ff

[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\services\Tcpip\Parameters\PersistentRoutes]
"77.88.10.0,255.255.224.0,192.168.75.2,21"=""

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Nsi\{eb004a00-9b1a-11d4-9123-0050047759bc}\16]
"000000004d5800001300000000000000000000000000000000000000000000000000000000000000c0a84b0200000000"=hex:ff,\
  ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,01,00,00,00,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,\
  ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,\
  ff,ff,ff,ff,ff

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\Tcpip\Parameters\PersistentRoutes]
"77.88.10.0,255.255.224.0,192.168.75.2,21"=""


Если поудалять ключи {eb004a00-9b1a-11d4-9123-0050047759bc}, постоянных маршрутов не будет. что это за идентификатор или GUID или что вообще? От чего зависит сохранение постоянного маршрута в этих системах? Смотрел на различных форумах, но вообще глухо по этой теме.

Автор: developer2007 24.10.2009, 16:44
А зачем простите такие извращения? Ведь есть намного проще и красивее вариант в виду своей кроссвиндозности (пример для D2010):
Код

WinExec(PAnsiChar(AnsiString('route -p add 1.1.1.0 MASK 255.255.255.0 1.1.1.1')), SW_HIDE);

Да кстати, в Висте (и видно в 7) есть мега нововведение - не имея прав админа нельзя получить доступ к route add...

Автор: Maks1509 24.10.2009, 18:32
developer2007
Ну так я от запуска консоли и хочу отказаться, тем более требуется контролировать процесс добавления маршрута, а не тупое скрытие окна консоли с гаданием добавился он или нет. На привилегии администратора тоже есть проверки. Уж если есть Ip Helper, так почему бы полноценно его не использовать.

Автор: developer2007 24.10.2009, 19:21
Так смотри на ExitCode процесса и по нему определяй всё ли ок, ну и ещё в новых системах после добавления маршрута вроде ОК выводит.

Автор: Maks1509 24.10.2009, 19:26
И все равно хотелось бы через Ip Helper. Все бы хорошо, но большинство пользователей потихоньку перелезают на новые системы, а хочется обсепечить поддержку и там полноценную. Да и в JEDI что-то не торопяться новую версию заголовочных файлов делать.

Автор: developer2007 24.10.2009, 20:41
Ну так а я про что - необходимо использовать средства предоставленные самой системой без конкретной привязки к её архитектурным особенностям.

Автор: Maks1509 24.10.2009, 21:12
Мне еще требуется очищать маршруты перед добавлением. Пока тестировал на различных системах на виртуальной машине, обнаружил странный недочет. Весь процесс стопорится после route -f под Windows 2000, поэтому также не вижу смысла использовать в программе запуск комадной строки, показывать пользователю не хочется как все это делается, но в этом случае пользователь и не узнает из-за чего процесс добавления маршрутов виснет. Также работаю и со службами отдельно чтобы перезапускать их (например DHCP для возобновления работы после добавления маршрутов и обновления сетевых интерфейсов), да и больше гибкости в этом, знаешь что не так пойдет и что нужно показать пользователю этом случае. smile 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)