[RESOLVED] Серфинг на забитом канале
Дано:
- квартирная сеть: linux-роутер на базе старого PC и несколько рабочих станций;
- безлимитный интернет с ограничением полосы пропускания;
- файлы круглосуточно качает роутер; для серфинга используются рабочие станции.
Проблема.
Роутер занимает весь канал, NAT-трафик не может пробиться к потребителям. Останавливать закачки на время серфинга — простое, но слишком хлопотное решение.
Непредвиденные обстоятельства.
Разумеется, нужно привлекать iproute2 для приоритезации трафика и перенаправлять входящий трафик на псевдоустройство ifb. Однако возникает неожиданное препятствие: трафик, пришедший на ifb успевает классифицироваться до того, как пройдет через правила iptables. Таким образом, с помощью iptables невозможно выделить NAT-трафик и пометить пакеты до классификации на ifb. Средствами же iproute нельзя задать фильтр, который может узнать по ip_conntrack, является ли роутер окончательным адресатом пакета или он будет обработан NAT-ом и передан в локальную сеть.
Решение.
При маскарадинге пакетов можно явно задать диапазон портов, которыми будут заменяться оригинальные dport. Этим можно воспользоваться для отличения NATed-пакетов от обычных, попадающих в INPUT. Так, можно задать достаточно высокий диапазон портов для NAT:
$IPTABLES -t nat -A POSTROUTING -o $PPP_IFACE -p TCP -j MASQUERADE \
--to-ports 16384-65535
$IPTABLES -t nat -A POSTROUTING -o $PPP_IFACE -p UDP -j MASQUERADE \
--to-ports 16384-65535
$IPTABLES -t nat -A POSTROUTING -o $PPP_IFACE -j MASQUERADE
Обычные (не NAT) пакеты с большой вероятностью будут иметь порт назначения ниже отметки 16384.
Классифицировать входящие пакеты по dport не составляет труда (классификатор u32).
P.S. Полные скрипты из работающей конфигурации могут быть выложены при наличии интереса к теме.
UPD. Залил архив со скриптами и конфигами (все файлы из Debian Lenny, поэтому пути к ним соответствующие):
- /etc/init.d/priotraff — поднимает IFB-интерфейс при старте системы (не забудьте про update-rc.d).
- /etc/ppp/peers/dsl-provider — настройки PPP-соединения, нас интересует только имя провайдера в последней строчке, «my-isp».
- /etc/ppp/ip-up — интересны последние три строки: скрипт будет запущен, если имя PPP-соединения «my-isp».
- /etc/ppp/ip-up.d/add-ppp-ingress — собственно скрипт, настраивающий приоритезацию.
Аццкий конструктор IPSec
До настройки OpenSwan я думал, что имею представление о Linux-шаманстве. Но это чудо, усыпанное независимыми ручками настройки, тумблерочками и кнопочками, бьет все рекорды. И, что характерно для подобных продуктов, уже отлаженный, рабочий конфиг выглядит настолько очевидным и логичным, что поневоле удивляешься: с чем там можно было бороться столько дней подряд?
Но все закончилось хорошо. IPSec с сертификатами и L2TP-туннель заработали, офисная сеть открылась избранным (roadwarriors).
P.S. Почему у l2tpns нельзя указать локальный IP и как это хозяйство роутить — осталось загадкой. Пришлось ставить обратно l2tpd.
UPD: Судя по рейтингам поста, людей интересует сам конфиг. Исправляю упущение.
Задача: открыть доступ к ресурсам корпоративной сети для сотрудников, которые находятся дома или в командировке.
Подзадача: создать безопасный канал связи между роутером корпоративной сети (внешний адрес, для определенности, 80.80.80.219/29) и компьютером сотрудника.
Листинг /etc/ipsec.conf:
version 2.0
config setup
nat_traversal=yes # для тех, кто за NAT-ом
interfaces=%defaultroute
virtual_private=%v4:80.80.80.216/29 # подсеть, в которую входит наш секурный хост
conn %default
keyingtries=1
compress=yes
disablearrivalcheck=no
authby=rsasig
leftrsasigkey=%cert
rightrsasigkey=%cert
conn roadwarrior-l2tp # имя соединения произвольное, т.к. соединение
# выбирается опенсваном по параметрам
left=80.80.80.219 # должен быть в virtual_private
leftnexthop=80.80.80.217 # инет-роутер подсети
leftcert=mydomain.ru.pem # сертификат должен лежать в /etc/ipsec.d/certs
leftprotoport=17/1701
right=%any # принимаем соединения с любого адреса
rightsubnet=vhost:%no,%priv
rightprotoport=17/1701
pfs=no
auto=add
type=transport
include /etc/ipsec.d/examples/no_oe.conf
conn block
auto=ignore
conn private-or-clear
auto=ignore
conn clear-or-private
auto=ignore
conn clear
auto=ignore
conn packetdefault
auto=ignoreP. P. S. OpenSwan ничего не знает ни о настройках L2TP, ни о топологии внутренней подсети, к которой предполагается открыть доступ через VPN. Подобные тонкости не фигурируют в ipsec.conf. Применительно к L2TP, задача IPSec только в создании безопасного транспорта между двумя хостами.
Бубном по Active Directory
Legacy-контроллеры домена снова обрадовали неведомыми глюками. Сегодня — отказом службы репликации файлов. Нечеловеческими усилиями удалось найти рецепт, который помог. Краткое изложение оригинала:
1) выбираем контроллер, который инициирует процесс;
2) идем в HKLM\SYSTEM\CurrentControlSet\Services\NtFrs\Parameters\Backup/Restore\Process at Startup, меняем значение BurFlags на «d4».
3) грохаем содержимое C:\WINDOWS\SYSVOL\domain\NtFrs_PreExisting___See_EventLog
4) перезапускаем службу репликации («net stop ntfrs», «net start ntfrs»).
Убеждаемся, что в журнале событий отразились изменения к лучшему. Можно проверить работоспособность контроллеров с помощью dcdiag.
Модуль аутентификации к Jetty
Для написания своего Login Module документация по JAAS в Jetty отправляет к соответствующим исходникам и намекает, что нужно всего лишь накодировать метод getUserInfo. Это чистая правда, но пока врубишься что к чему, Jetty наплюет не один килобайт логов с ошибками. Итак, что получилось:
package levi.ainv;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.mortbay.jetty.plus.jaas.spi.AbstractLoginModule;
import org.mortbay.jetty.plus.jaas.spi.UserInfo;
import org.mortbay.jetty.security.Credential;
public class DBLoginModule extends AbstractLoginModule {
@Override
public UserInfo getUserInfo(String userName) throws Exception {
// в моем случае используется Singleton-объект Engine,
// который хранит хэшмап с юзерами
User user = Engine.itself().selectUser(userName);
// на нет и суда нет
if(user == null) {
return null;
}
// заливаем роли в список
List<String> roles = new ArrayList<String>();
Iterator<Role> userRoles = user.getRoles().iterator();
while(userRoles.hasNext()) {
roles.add(userRoles.next().getName());
}
// ключевой момент - возвращаем имя юзера,
// креденшл, изготовленный из простого строкового пароля, и список с ролями --
// дальше родительский класс сам сравнит пароли и роли,
// которые мы предоставили для заданного имени юзера и решит
// пущать или не пущать
return new UserInfo(userName, Credential.getCredential(user.getPassword()), roles);
}
}То есть, нужно из своего супер-секретного-хранилища юзерских аккаунтов, где бы оно ни было, вытащить аккаунт с заданным именем, запаковать в объект UserInfo и return его. Больше ни о чем думать не требуется.
