Корона внесла неожиданные изменения в нашу работу, приходится подстраиваться. Крупные организации, или кого не зацепило спокойно скупили ноутбуки сотрудникам и радуются жизни. В нашем случае пришлось искать другие пути.
Кто-то пользуется Teamviewer`ом, ну что ж, флаг им в руки, а я буду держаться подальше по следующим причинам:
Кто-то пользуется Teamviewer`ом, ну что ж, флаг им в руки, а я буду держаться подальше по следующим причинам:
- Программа платная (использование за пределами одной сети = коммерческое использование)
- Использование 3 точки в цепочке
- Повышенная нагрузка на сервис
- Режим работы без блокировки монитора
- и т.д.
- Нужно иметь сервер терминалов или подключаться к пользовательским ПК
- Проброс порта RDP не помеха для сканера, гигантская дыра в безопасности
- Пробросить порты на RDP на 5 машин можно, но на 50+ и без статики на тачках - такое себе
- и т.д.
На ум напрашивается VPN и пущай пользователь как-то подключается к ресурсу (тот же Teamviewer,LiteManager, RDP)
На всех объектах используется роутер Mikrotik.
Я избрал следующий путь для одного объекта:
- Настраиваем ПК пользователей
- Включаем Wake-On-LAN и проверяем
- Персонифицируем имена компьютеров (допустим по фамилии сотрудника)
- Включаем RDP (напоминаю, он есть только в редакциях PRO и выше)
- Проверяем настройки файервола и антивируса, чтобы они не блокировали трафик для удаленного доступа от пула адресов VPN сервера
- Настраиваем роутер:
- Пул DHCP сервера должен быть отличен от 192.168.Х.Х, т.к. у пользователей дома именно такая сеть.
- Фиксируем лизы для компьютеров
- Настраиваем L2TP IPsec PSK (или другой VPN сервер на роутере)
- Создаем пользователей (имя пользователя соответствует имени его ПК)
- Проверяем настройки файервола, чтобы трафик из сети VPN ходил в сеть организации
- В разделе PPP>Profiles>НашПрофиль>вкладка Scripts, здесь мы пишем скрипт в On Up (получаем MAC,шлем магический пакет):
:local macAddress [/ip dhcp-server lease get [/ip dhcp-server lease find host-name=$user] mac-address]; tool wol interface=bridge mac=$macAddress :log info message=("User " . $user . " connetcted. Sending magic packet for MAC=" . $macAddress)
- Настраиваем подключение с личного ПК пользователя, обязательно отключаем "Использовать как основной шлюз"
На другом объекте машин 50+, и DHCP сервер находится на контроллере домена, хоть шлюзом и выступает Mikrotik. Почесав репу, вспомнил что список MAC-NAME_PC у меня есть на сервере для бэкапов. Вот и решил его использовать. Логика остается та же:
- Имя пользователя ПК=имени ПК=имя пользователя VPN
- При подключении находим MAC, отправляем магический пакет
- Если через 60 секунд машина не пингуется, то сбросить подключение
- Иначе добавить правило в файервол, разрешающее трафик на порт 3389 от конкретного пользователя к конкретному ПК
- При отключении удалить правило
Мысль огонь, мне зашло как надо, но в ходе реализации я столкнулся с кучей проблем:
- Язык Mikrotik оставляет желать лучшего, аналога awk нету
- Область действия переменных. Т.к. итоговый скрипт длинный, я решил его записать в разделе System>Script, но для того чтобы его вызвать при подключении пользователя, нужно объявить переменные (параметры для скрипта) как глобальные. Глобальные переменные работают на все подключения и тут возникает гигантская коллизия. Пришлось при получении параметра сразу уничтожать глобальную переменную.
- Попытка разбора файла на сервере с UNIX системой потерпела фиаско из-за требования входить на сервер по сертификату
- и т.д.
В итоге листинг скрипта:
#get name user, resolve, wol, ping, add rule
#Example run
#:global Iuser $user;:global IremoteAddress $"remote-address";/system script run plug_user_local
#Two input param
:global Iuser;
:global IremoteAddress;
:put ("Input: " .$Iuser. " ". $IremoteAddress)
:local user [$Iuser]
:local remoteAddress [$IremoteAddress];
# Remove global var
/system script environment remove IremoteAddress
/system script environment remove Iuser
:local dnsServer "10.20.0.2"
:local HOST ($user . ".mydomain.ru");
:local PINGCOUNT "2";
:local CodeExitPing;
:local ipAdr;
:local macAddr;
:local patern $user;
:local FileName "compoff2.txt";
:local StatusCode "1"
:put ("LocalInput: " .$user. " ". $remoteAddress)
:put ("plug: " . $HOST . " ". $PINGCOUNT . " ". $dnsServer)
#####################
##FUNC##
###GETMAC
:local getMac do={
:local macAddr "";
:do { [/file get [/file find name=$FileName]]} on-error={:set macAddr "0"}
:put ("FN " . $FileName . " " .$patern)
if ([ :len $FileName]!=0 and [ :len $patern ]!=0 and [/file get [/file find name=$FileName] size] != 0 and $macAddr="") do={
:put ("getMac begin")
:local content [/file get [/file find name=$FileName] contents] ;
:local contentLen [ :len $content ] ;
:local lineEnd 0;
:local line "";
:local lastEnd 0;
:do {
:set lineEnd [:find $content "\n" $lastEnd ] ;
:set line [:pick $content $lastEnd $lineEnd] ;
:set lastEnd ( $lineEnd + 1 ) ;
:if ( [:pick $line 0 1] != "#" ) do={
:local entry [:pick $line 0 $lineEnd ]
:if ( [:len $entry ] > 0 ) do={
if ([:find $entry $patern]>0) do={
:set macAddr [:pick $entry ([:len $entry]-20) ([:len $entry]-3)]
#break
:set lastEnd ( $contentLen + 1 ) ;
}
}
}
} while ($lastEnd < $contentLen)
}
if ($macAddr="") do={:set macAddr "0"}
:return $macAddr
}
###checkPing
:local checkPing do={
:put ("ping: " . $HOST ." ". $PINGCOUNT ." ". $dnsServer)
:local ipAdr;
:local CodeExitPing;
if ( $HOST != "" and $PINGCOUNT != "" and $dnsServer != "") do={
:do {:set ipAdr [:resolve $HOST server=$dnsServer]} on-error={:set ipAdr "0"};
if ($ipAdr=0) do={
:set CodeExitPing "0"
} else {
:set CodeExitPing [/ping $ipAdr interval=1 count=$PINGCOUNT];
}
} else={
:set CodeExitPing "0";
:put "Empty param"
}
:return $CodeExitPing
}
###FUNC##
#####################
:set CodeExitPing [$checkPing HOST=$HOST PINGCOUNT=$PINGCOUNT dnsServer=$dnsServer]
:put ("Exit code " . $CodeExitPing);
if ($CodeExitPing=0) do={
set macAddr [$getMac patern=$patern FileName=$FileName]
:put ("macAddr " . $macAddr)
if ($macAddr != 0) do={
:put ("|" . $macAddr . "|")
/tool wol mac=$macAddr interface=LAN_Bridge
:put "Delay 60s"
:log info message=("Send magic packet on mac:".$macAddr.", for user ".$patern)
:delay delay-time=60
:set CodeExitPing [$checkPing HOST=$HOST PINGCOUNT=$PINGCOUNT dnsServer=$dnsServer]
if ($CodeExitPing>0) do={
:set StatusCode "0"
}
}
} else={
:put "if else"
:set StatusCode "0"
}
:put ("Pre error" . $StatusCode)
if ($StatusCode = 0) do={
:set ipAdr [:resolve $HOST server=$dnsServer]
:local email "it@mydomain.ru"
/tool e-mail send to=$email subject="[VPN_RDP] User $user connected" body="User $user connected at $[/system clock get time].\r\nIP-address - $"caller-id".\r\nInfo - http://apps.db.ripe.net/search/query.html?searchtext=$"caller-id""
:log info message=("Conected " . $user . " ip pc_office" . $ipAdr . " ip pc_vpn " . $remoteAddress)
:local p [/ip firewall filter find comment~"VPN_AUTO_END"]; #Специально созданное правило-метка (оно еще разрешает DNS запросы)
:local comm ("VPN_auto.".$user . "." . $remoteAddress) #унифицированная метка правила
/ip firewall filter add action=accept chain=forward comment=$comm dst-port=3389 out-interface=LAN_Bridge protocol=tcp src-address=$remoteAddress dst-address=$ipAdr
/ip firewall filter add action=accept chain=forward comment=$comm dst-port=3389 out-interface=LAN_Bridge protocol=udp src-address=$remoteAddress dst-address=$ipAdr
/ip firewall filter move [find comment=$comm] destination=$p
} else={
:log info message=("PC not found" . $remoteAddress)
/ppp active remove [find where name=$user]
}
И собственно в On up:
:global Iuser $user;
:global IremoteAddress $"remote-address";
/system script run plug_user_local
И собственно в On down:
:local email "it@mydomain.ru"
/tool e-mail send to=$email subject="[VPN_RDP] User $user disconnected" body="User $user disconnected at $[/system clock get time]."
:local comm ("VPN_auto.".$user . "." . $"remote-address"); /ip firewall filter remove [find comment=$comm]
UP 27/05/2020
Забыл добавить, в последнем варианте при помощи GPO включается RDP на клиентских машинах и в локальную группу "Пользователи удаленного рабочего стола" добавляется разрешенный пользователь.
Именно для этого и было создано соответствие Имя Пользователя ПК (домена)=Имени ПК
Политика нацелена на ПК входящие в группу разрешенных и логика выглядит так:
Если ПК в группе Разрешенные, то добавить пользователя с именем mydomain\%computername% в группу
Комментариев нет:
Отправить комментарий