Прозрачный Squid с SSL-Bump для Gentoo с nft

    image

    Предыстория


    Недавно я взялся переводить межсетевой экран на своей РС с проверенных временем iptables на новенькие nftables. Для более углублённого изучения таблиц nf я поставил себе задачу: настроить прозрачный прокси-сервер (Squid) с разбором шифрованных соединений (HTTPS) для раздачи доступа в Интернет виртуальным машинам, РС «Raspberry Pi», а также своему смартфону (работающему с ОС «Android» 6-го выпуска) по беспроводному соединению (с помощью приложения hostapd).

    Обозначения


    Буквы равной ширины Приказы оболочки и содержимое конфигурационных файлов.
    Полужирные буквы Настройки, строго необходимые для прозрачного посредничества.
    Наклонные буквы Настройки, специфичные для моей установки (номера выпусков ПО, адреса канального и сетевого уровня, названия сетевых интерфейсов и т. п.). В вашем случае значения, как правило, будут другими.
    Подчёркнутые буквы Настройки, необходимые для работы разбора шифрованных соединений

    Дано


    Операционная система «Gentoo Linux» со службой запуска служб «OpenRC».
    Все дальнейшие настройки будут применимы к этой поставке
    Ядро sys-kernel/gentoo-sources-5.3.1
    USE=""
    Здесь и далее снятые USE-флаги не показаны
    Прокси-сервер net-proxy/squid-4.8
    USE="caps ssl ssl-crtd"
    Библиотека шифрования dev-libs/openssl-1.1.1c-r1
    USE=«asm test zlib»
    Приложение nft net-firewall/nftables-0.9.2
    USE=«doc gmp modern_kernel»
    Приложение ip sys-apps/iproute2-5.2.0-r1
    USE=«caps minimal»
    Служба записи в журнал app-admin/ulogd-2.0.7-r1
    USE=«nfct nflog»

    Настройка ядра


    image
    Тоже самое, но текстом
    [*] Networking support --->
    Networking options --->
    [*] TCP/IP networking
    [*] IP: advanced router
    [*] IP: policy routing
    [*] Network packet filtering framework (Netfilter) --->
    [*] Advanced netfilter configuration
    Core Netfilter Configuration --->
    # не обязательно, но пригодится для фильтрации пакетов на входе сетевых интерфейсов
    [*] Netfilter ingress support
    # не обязательно, но пригодится для отладки
    <*> Netfilter LOG over NFNETLINK interface
    <*> Netfilter connection tracking support
    <*> Netfilter nf_tables support
    <*> Netfilter nf_tables set infrastructure
    # не обязательно, но пригодится для фильтрации пакетов на входе сетевых интерфейсов
    [*] Netfilter nf_tables netdev tables support
    <*> Netfilter nf_tables conntrack module
    # не обязательно, но пригодится для отладки
    <*> Netfilter nf_tables counter module
    # не обязательно, но пригодится для отладки
    <*> Netfilter nf_tables log module
    <*> Netfilter nf_tables masquerade support
    <*> Netfilter nf_tables nat module
    <*> Netfilter nf_tables socket match support
    <*> Netfilter nf_tables tproxy support
    IP: Netfilter Configuration --->
    [*] IPv4 nf_tables support
    # не обязательно, но пригодится для фильтрации пакетов на канальном уровне
    <*> Ethernet Bridge nf_tables support --->


    Для справки привожу выдержку из /usr/src/linux/.config:

    CONFIG_NET=y
    CONFIG_INET=y
    <b>CONFIG_IP_ADVANCED_ROUTER=y
    CONFIG_IP_MULTIPLE_TABLES=y</b>
    CONFIG_NETFILTER=y
    CONFIG_NETFILTER_ADVANCED=y
    CONFIG_NETFILTER_INGRESS=y
    CONFIG_NETFILTER_NETLINK=y
    CONFIG_NETFILTER_NETLINK_LOG=y
    CONFIG_NF_CONNTRACK=y
    CONFIG_NF_TABLES=y
    CONFIG_NF_TABLES_SET=y
    CONFIG_NF_TABLES_NETDEV=y
    CONFIG_NFT_CT=y
    CONFIG_NFT_COUNTER=y
    CONFIG_NFT_LOG=y
    CONFIG_NFT_MASQ=y
    CONFIG_NFT_NAT=y
    <b>CONFIG_NFT_SOCKET=y
    CONFIG_NFT_TPROXY=y</b>
    CONFIG_NF_TABLES_BRIDGE=y
    

    Настройка сети


    Если служба net.lo не добавлена в уровень выполнения «boot», то её следует туда добавить:

    rc-config add net.lo boot

    Подобным же образом созданы и настроены на запуск для уровня выполнения «default» службы net.br0 (мост для виртуальных машин и смартфона), net.enp0s25 (проводной интерфейс) и net.wlp3s0 (беспроводной интерфейс), например:

    ln -s net.lo /etc/init.d/net.br0
    rc-config add net.br0 default
    

    Итоговый конфигурационный файл /etc/conf.d/net в нашем примере выглядит так (за вычетом не относящихся к нашей задаче настроек):

    image

    Тоже самое, но текстом
    # TProxy
    routes_lo='local default dev lo table 3128'
    
    # Qemu bridge
    bridge_force_br0=''
    mac_br0='XX:XX:XX:XX:XX:XX'
    config_br0='192.168.120.1/24'
    
    # Ethernet
    config_enp0s25='dhcp'
    modules_enp0s25='udhcpc'
    dhcp_enp0s25='release nontp'
    udhcpc_enp0s25='--retries 8 --timeout 10'
    fallback_enp0s25='10.a.b.c/16'
    fallback_routes_enp0s25='default via 10.a.0.1'
    
    # Wi-Fi
    if [[ -f /var/lib/misc/hostapd ]]; then
      modules_wlp3s0="!ifconfig !iwconfig !wpa_supplicant"
      config_wlp3s0='null'
    else
      config_wlp3s0='dhcp'
      modules_wlp3s0='udhcpc'
      wpa_supplicant_wlp3s0='-Dnl80211'
    fi
    
    postup() {
      if [ "${IFACE}" == lo ]; then
        ip rule add fwmark 3128 lookup 3128
      fi
      return 0
    }
    


    Выделенные строки добавляют новую таблицу маршрутизации, в данном примере под номером 3128, и ворота — по умолчанию для неё (интерфейс «loopback»), и правило — по которому пакеты, помеченные межсетевым экраном меткой номер 3128 (десятичные числа в обоих случаях), будут обслуживаться этим расписанием.

    Чтобы направляемые пакеты не были отброшены из-за несоответствия адресов сетевого уровня (при прозрачном проксировании пакеты сохраняются в первозданном виде!) необходимо добавить в /etc/sysctl.conf следующие строки (или изменить уже имеющиеся):

    image

    Если нужно применить эти настройки до перезагрузки, то следует дополнительно задать их для обоих сетевых интерфейсов с доступом в Интернет:

    sysctl net.ipv4.conf.enp0s25.rp_filter=0
    sysctl net.ipv4.conf.wlp3s0.rp_filter=0

    Настройка прокси-сервера


    Поскольку обычный (непрозрачный) порт прокси-сервера у нас будет закреплён на адресе моста (192.168.120.1), добавим следующую строку в /etc/rc.conf:

    rc_squid_need="net.br0"

    Следующие настройки прокси-сервера в рамках этой статьи рассмотрены не будут:

    • Проверка личности пользователей на обычном (непрозрачном) порту;
    • ICAP для объединения с устройством предотвращения утечек данных (например, InfoWatch Traffic Monitor);
    • Выработка ключей шифрования и создание сертификата.

    Конфигурационный файл /etc/squid/squid.conf в итоге выглядит так (на всякий случай привожу полностью):

    image

    image

    Тоже самое, но текстом
    	# Задаём перечень виртуальных машин
    1	acl virtual_machines src 192.168.120.0/24
    2	acl SSL_ports port 443
    	# Пример добавления необычного для соединений HTTPS порта
    3	acl SSL_ports port 1012        # для badssl.com
    	# Пример добавления необычного для соединений HTTPS порта
    4	acl SSL_ports port 33443       # getcourse.ru для artlinerschool.ru
    5	acl Safe_ports port 21         # ftp
    6	acl Safe_ports port 80         # http
    7	acl Safe_ports port 443        # https
    	# Пример добавления необычного привилегированного порта
    8	acl Safe_ports port 1012       # для badssl.com
    9	acl Safe_ports port 1025-65535 # непривилегированные порты
    10	acl CONNECT method CONNECT 
    11	http_access deny !Safe_ports
    12	http_access deny CONNECT !SSL_ports
    13	http_access allow localhost manager
    14	http_access deny manager
    15	http_access allow localhost
    	# Разрешаем подключение виртуальных машин к прокси-серверу
    16	http_access allow virtual_machines
    17	http_access deny all
    	# Настраиваем обычный (непрозрачный) порт. Используем адрес моста, на случай прямого подключения виртуальных машин (например, как к прокси-серверу FTP)
    18	http_port 192.168.120.1:3128 ssl-bump options=ALL:NO_SSLv3:NO_TLSv1 cert=/etc/squid/squid.pem
    	# Настраиваем прозрачный порт для нешифрованных соединений. Тут используем адрес интерфейса «loopback», поскольку на него указывает таблица маршрутизации под номером 3128, настроенное ранее, и на него же будут указывать правила межсетевого экрана
    19	http_port 127.0.0.1:3129 tproxy
    	# Настраиваем прозрачный порты для шифрованных соединений. Тут используем адрес интерфейса «loopback», поскольку на него указывает таблица маршрутизации под номером 3128, настроенное ранее, и на него же будут указывать правила межсетевого экрана
    20	https_port 127.0.0.1:3130 tproxy ssl-bump options=ALL:NO_SSLv3:NO_TLSv1 cert=/etc/squid/squid.pem
    	# прокси-сервер выходит в сеть напрямую, без других прокси-серверов
    21	always_direct allow all
    	# Задаём перечень проверенных страниц, имеющим самоподписанный сертификат
    22	acl BrokenButTrustedServers dstdomain "/etc/squid/selfsigned.txt"
    	# Разрешаем подключение только к проверенным страницам, имеющим самоподписанный сертификат
    23	sslproxy_cert_error allow BrokenButTrustedServers
    24	sslproxy_cert_error deny all
    	# Для безопасности разрешаем только свежайшие выпуски TLS
    25	tls_outgoing_options min-version=1.2
    	# Задаём перечень непотребных страниц
    26	acl blocked ssl::server_name "/etc/squid/blocked_domains.txt"
    	# Задаём перечень страниц, которые перестают работать из-за подмены сертификата (в первую очередь это касается виртуальных частных сетей на основе SSL)
    27	acl fragile dstdomain "/etc/squid/fragile_domains.txt"
    28	acl step1 at_step SslBump1
    29	ssl_bump peek step1
    	# Запрещаем подключения к непотребным страницам
    30	ssl_bump terminate blocked
    	# Делаем исключения из разбора шифрования для страниц, которые перестают работать из-за подмены сертификата
    31	ssl_bump splice fragile
    	# Все остальные шифрованные соединения разбираем, подменяя сертификата
    32	ssl_bump bump all
    	# Настраиваем хранилище подменных сертификатов
    33	sslcrtd_program /usr/libexec/squid/security_file_certgen -s /var/lib/squid/ssl -M 4MB
    34	cache_dir rock /var/cache/squid-r 512 max-size=32768
    35	cache_dir aufs /var/cache/squid 512 64 1024 min-size=32768
    36	coredump_dir /var/tmp/squid
    37	refresh_pattern    ^ftp:          1440 20% 10080
    38	refresh_pattern -i (/cgi-bin/|\?) 0    0%  0
    39	refresh_pattern    .              0    20% 4320
    40	memory_replacement_policy heap GDSF
    41	cache_replacement_policy LFUDA
    42	maximum_object_size 32 MB
    43	logfile_rotate 3
    44	debug_options ALL,1,rotate=3
    45	cache_mem 512 MB
    46	visible_hostname host.shadow.amn
    47	udp_incoming_address 127.0.0.1
    48	pinger_enable off
    


    Настройка межсетевого экрана


    Настроим запуск на уровне выполнения «default» служб nftables и ulogd (последняя нужна для уведомления о пакетах):

    rc-config add nftables default
    rc-config add ulogd default

    Поскольку в настройках межсетевого экрана будет присутствовать мост, добавим следующую строку в /etc/rc.conf:

    rc_nftables_need="net.br0"

    Для работы уведомления в /etc/sysctl.conf необходимо добавить следующую строку:

    net.netfilter.nf_log.2 = nfnetlink_log

    Чтобы конфигурационный файл находился в папке /etc/nftables, внесём такое изменение в /etc/conf.d/nftables:

    NFTABLES_SAVE="/etc/nftables/rules-save"

    Чтобы временные изменения не сохранялись в конфигурационном файле, внесём ещё одно изменение в /etc/conf.d/nftables:

    SAVE_ON_STOP="no"

    Опишу задачи, поставленные перед межсетевым экраном:

    1. Правила по умолчанию во всех цепочках таблицы ip filter должны пакеты удалять (даже в цепочке output!). Аналогично для таблиц netdev filter;
    2. Обмен любого вида, кроме IPv4 и относящегося к нему служебного обмена (например, ARP), пресекается насколько возможно раньше (ни IPv4, ни IPSec не используются);
    3. Многоадресные пакеты IPv4 также удаляются насколько возможно раньше;
    4. Для защиты Android-смартфона (при подключении к мосту с помощью приложения hostapd) широковещательный обмен, производимый виртуальными машинами работающими под управлением ОС «Microsoft Windows», не должен передаваться на беспроводной интерфейс.
    5. Пользоваться нашим Wi-Fi можно только устройствами с известными MAC-адресами.

    Конфигурационный файл /etc/nftables/rules-save в итоге выглядит так (за вычетом большинства пояснений):

    image

    image

    image

    image

    image

    image

    Тоже самое, но текстом
    1	#!/sbin/nft -f
    	# Задаём переменные, которые будут использоваться в правилах
    2	define icmp_types = { destination-unreachable, time-exceeded, parameter-problem, echo-request, echo-reply }
    3	define host = 192.168.120.1
    4	define br = br0
    5	define my_br_mac = XX:XX:XX:XX:XX:XX
    6	define eth = enp0s25
    7	define my_eth_mac = YY:YY:YY:YY:YY:YY
    8	define wifi = wlp3s0
    9	define my_wifi_mac = WW:WW:WW:WW:WW:WW
    10	define my_phone = TT:TT:TT:TT:TT:TT
    11	define virtual_machines = 192.168.120.0/24
    12	define privileged_vm = { 192.168.120.22, 192.168.120.129 }
    13	define dhcp_client = 192.168.120.224/27
    14	define transmission_port = 51413
    15	define no_track = { microsoft-ds, ms-wbt-server }
    16	define vm_ssh = 192.168.120.70
    17	define infowatch_pc = { 10.a.0.0/16, 10.h.0.0/16 }
    18	define infowatch_my = 10.a.b.c
    19	define squid_normal = 3128
    20	define squid_transp = 3129
    21	define squid_trassl = 3130
    22	define sslvpn.infowatch.com = 46.148.194.86
    23	define files.infowatch.ru = 178.16.25.15
    24	define iwprint.infowatch.ru = 10.d.e.f
    25	define s163.getcourses.ru = 95.213.153.163
    26	define tls-v1-2.badssl.com = 104.154.89.105
    27	flush ruleset
    28	table ip raw {
    29	  chain prerouting {
    30	    type filter hook prerouting priority -300;
    	    # Пытаемся облегчить работу межсетевого экрана тем, что соединения с самым большим объёмом пакетов отслеживаться не будут
    31	    meta l4proto { tcp, udp } th dport $transmission_port notrack
    32	    tcp sport $no_track ip saddr != $iwprint.infowatch.ru notrack
    33	    ip saddr { $sslvpn.infowatch.com, $files.infowatch.ru } tcp sport https notrack
    34	  }
    35	}
    36	table ip filter {
    37	  chain input {
    38	    type filter hook input priority 0; policy drop;
    	    # Поскольку в этой цепочке правило по умолчанию удаляет пакеты, то необходимо разрешить все пакеты на интерфейс «loopback»
    39	    iif lo accept
    	    # Разрешаем пакеты ICMP только необходимых видов для обхода возможных уязвимостей, связанных с редкими и неиспользуемыми видами ICMP
    40	    icmp type $icmp_types accept
    	    # Удаляем битые пакеты
    41	    ct state invalid counter drop
    	    # Обход падения ядра, связанного с избирательным подтверждением (SACK) пакетов TCP. Падения эти уже устранены в свежих выпусках ядра, но данное правило оставлено на всякий случай
    42	    tcp flags syn tcp option maxseg size < 999 counter drop
    	    # Полностью разрешаем Bittorrent, поскольку мы исключили его из отслеживания в строке 31
    43	    iif $eth meta l4proto { tcp, udp } th dport $transmission_port accept
    	    # Удаляем пакеты, начинающие соединение, и заносим о них запись в дннвник, если они пришли с неотслеживаемых соединений
    44	    tcp flags & (syn | ack) == syn ct state untracked log prefix "Untracked:" group 2 counter counter drop
    	    # Разрешаем пакеты с портов, которые мы исключили из отслеживания в строке 32
    45	    tcp sport $no_track accept
    	    # Разрешаем пакеты с адресов, которые мы исключили из отслеживания в строке 33
    46	    ip saddr { $sslvpn.infowatch.com, $files.infowatch.ru } tcp sport https accept
    	    # Разрешаем пакеты от виртуальных машин, помеченные меткой 3128 (десятичное число)
    47	    iif $br ip saddr $virtual_machines mark set 3128 counter accept
    	    # Разрешаем виртуальным машинам подключаться к некоторым службам, в том числе к обычному (непрозрачному) порту прокси-сервера
    48	    iif $br ip daddr $host ip saddr $virtual_machines tcp dport { domain, http, microsoft-ds, nfs, $squid_normal } accept
    	    # Разрешаем все законные отслеженные соединения
    49	    ct state { established, related } accept
    	    # Разрешаем виртуальным машинам подключаться к некоторым службам, подразумевающим широковещательный обмен
    50	    iif $br udp dport { domain, bootps, tftp, 4011 } counter accept
    	    # Производим подсчёт удалённых пакетов, так как следующим правилом будет правило по умолчанию, удаляющее пакеты (см. строку 38)
    51	    counter comment "Считаем выброшенные пакеты"
    52	  }
    53	  chain output {
    54	    type filter hook output priority 100; policy drop;
    	    # Поскольку в этой цепочке правило по умолчанию удаляет пакеты, то необходимо разрешить все пакеты со интерфейса «loopback»
    55	    oif lo accept
    	    # Разрешаем пакеты ICMP только необходимых видов для обхода возможных уязвимостей, связанных с редкими и неиспользуемыми видами ICMP
    56	    icmp type $icmp_types counter accept
    	    # Разрешаем службам отправлять пакеты виртуальным машинам с привилегированных портов (сравните со строками 48 и 50)
    57	    oif { $eth, $wifi } udp dport . udp sport { bootps . bootpc } counter accept
    58	    oif $br ip saddr $host ip daddr { $dhcp_client, 255.255.255.255 } udp sport . udp dport { bootps . bootpc } counter accept
    59	    oif $br ip saddr $host ip daddr $virtual_machines udp sport { domain, tftp } counter accept
    60	    oif $br ip saddr $host ip daddr $virtual_machines tcp sport { domain, http, microsoft-ds } accept
    	    # Разрешаем прокси-серверу отправлять пакеты потребителям от имени страниц всемирной паутины с привилегированных портов. Если используется необычный порт для HTTPS вне привилегированного промежутка, то он подпадёт под следующее правило и его указывать здесь не нужно
    61	    oif $br ip daddr $virtual_machines tcp sport { http, https, 1012 } counter accept
    	    # Разрешаем отправку любых пакетов с портов, имеющих номера вне привилегированного промежутка, то есть выше 1024
    62	    meta l4proto { tcp, udp } th sport >= 1025 accept
    	    # Производим подсчёт удалённых пакетов, так как следующим правилом будет правило по умолчанию, удаляющее пакеты (см. строку 54)
    63	    counter comment "Считаем выброшенные пакеты"
    64	  }
    65	  chain forward {
    66	    type filter hook forward priority 0; policy drop;
    	    # Помогаем виртуальным машинам с настройкой размера пакетов (MTU)
    67	    tcp flags syn tcp option maxseg size set rt mtu counter
    	    # Запрещаем виртуальным машинам обращаться к чужим службам разрешения имён
    68	    iif $br ip daddr != $host meta l4proto { tcp, udp } th dport domain drop
    	    # Разрешаем обмен с внешним миром (помимо прокси-сервера) только некоторым виртуальным машинам и всем, получившим временный адрес сетевого уровня, как правило, это будет смартфон. Эти правила не означают, что подключение ко всемирной паутине (порты 80 и 443) произойдёт для них без прокси-сервера, так как цепочка divert имеет более высокое первенство по сравнению с цепочкой forward (сравните строки 66 и 81). Кроме того, в строке 96 мы не преобразуем адрес сетевого уровня, если номер порта назначения равен 80 или 443
    69	    iif $br ip saddr { $privileged_vm, $dhcp_client } accept
    70	    oif $br ip daddr { $privileged_vm, $dhcp_client } accept
    	    # Производим подсчёт удалённых пакетов, так как следующим правилом будет правило по умолчанию, удаляющее пакеты (см. строку 66)
    71	    counter comment "Считаем выброшенные пакеты"
    72	  }
    	  # Создаём набор пар «адрес канального уровня • порт» для случаев использования соединениями HTTPS номеров портов, отличающихся от 443
    73	  set nonstandard_https {
    74	    type ipv4_addr . inet_service;
    75	    elements = {
    76	      $s163.getcourses.ru . 33443, # для страницы artlinerschool.ru
    77	      $tls-v1-2.badssl.com . 1012, # для страницы badssl.com
    78	  }
    79	}
    80	  chain divert {
    81	    type filter hook prerouting priority -150; policy accept;
    	    # Помечаем меткой 3128 (дес. ч.) все пакеты TCP, отправляющиеся из сокета, имеющего свойство прозрачности (свойство задаётся прокси-сервером)
    82	    meta l4proto tcp socket transparent 1 mark set 3128 accept
    	    # Помечаем меткой 3128 (дес. ч.) все пакеты TCP с портом назначения, имеющим номер 80. Одновременно заворачиваем их на прозрачного прокси-сервера
    83	    ip daddr != { 127.0.0.1, $host } tcp dport http tproxy to 127.0.0.1:$squid_transp mark set 3128 counter accept
    	    # Помечаем меткой 3128 (дес. ч.) все пакеты TCP с портом назначения, имеющим номер 443. Одновременно заворачиваем их на прозрачного прокси-сервера
    84	    ip daddr != { 127.0.0.1, $host } tcp dport https tproxy to 127.0.0.1:$squid_trassl mark set 3128 counter accept
    	    #  Помечаем меткой 3128 (дес. ч.) все пакеты TCP с адресами и портами назначения из набора nonstandard_https (см. строки 76 и 77 для примера). Одновременно заворачиваем их на прозрачного прокси-сервера
    85	    ip daddr . tcp dport @nonstandard_https tproxy to 127.0.0.1:$squid_trassl mark set 3128 counter accept
    86	  }
    87	}
    88	table ip nat {
    89	  chain prerouting {
    90	    type nat hook prerouting priority 0; policy accept;
    	    # Разрешаем другим РС из рабочей сети подключаться к одной из виртуальных машин с помощью SSH
    91	    iif $eth ip daddr $infowatch_my ip saddr $infowatch_pc tcp dport ssh counter dnat $vm_ssh
    92	  }
    93	  chain postrouting {
    94	    type nat hook postrouting priority 100; policy accept;
    	    # Преобразуем адреса сетевого уровня в пакетах, отправляемых вовне прокси-сервером, так как он отправляет их от лица виртуальных машин. Принадлежность прокси-серверу определяем с помощью свойств UID и GID сокета
    95	    oif { $eth, $wifi } ip saddr $virtual_machines skuid . skgid { squid . squid } counter masquerade
    	    # Преобразуем адреса сетевого уровня в пакетах, отправляемых вовне некоторыми виртуальными машинами, и всеми, получившими временный адрес сетевого уровня, (сравните со строками 69 и 70). При этом ведём им учёт, занося в общий журнал, с целью выявления необычных для соединений HTTPS портов. После выявления таковых заносим их вместе с адресами в набор nonstandard_https (см. строки 76 и 77 для примера).
    96	    oif { $eth, $wifi } ip saddr { $privileged_vm, $dhcp_client } tcp dport != { http, https } log prefix "NAT:" group 2 counter masquerade
    97	  }
    98	}
    	
    99	table bridge filter {
      # Решаем задачу №5: Разрешаем передавать данные нашему Wi-Fi только известным устройствам
    100	  chain input {
        type filter hook input priority -200; policy accept;
        iif $wifi ether saddr != $my_phone counter drop
      }
      # Решаем задачу №4: защита смартфона от всего, не связанного с IPv4, и от ненужных ему широковещательных рассылок
      chain forward {
    101	    type filter hook forward priority -200; policy accept;
    102	    oif $wifi ether type arp accept
    103	    oif $wifi ip protocol { icmp, tcp, udp } ip daddr != 192.168.120.255 accept
    104	    oif $wifi drop
    105	  }
      # Решаем задачу №5: Разрешаем нашему Wi-Fi отдавать данные только известным устройствам
    106	  chain output {
        type filter hook input priority 200; policy accept;
        oif $wifi ether daddr != $my_phone counter drop
      }
    }
    	# Решаем задачу №2: удаление на входах интерфейсов всего, не связанного с IPv4
    107	table netdev filter {
    108	  chain enp0s25 {
    109	    type filter hook ingress device enp0s25 priority 0; policy drop;
    110	    ether type arp accept
    111	    ether daddr $my_eth_mac ip protocol { icmp, tcp, udp, gre } accept
    112	  }
    113	  chain wlp3s0 {
    114	    type filter hook ingress device wlp3s0 priority 0; policy drop;
    	    # Разрешаем ARP и EAPOL на случай, когда подключение к Интернету происходит через беспроводной интерфейс
    115	    ether type { arp, 0x888e } accept
    	    # Поскольку беспроводный интерфейс будет подключаться к мосту, здесь необходимо указать адреса канального уровня как самого интерфейса, так и моста
    116	    ether daddr { $my_br_mac, $my_wifi_mac, ff:ff:ff:ff:ff:ff } ip protocol { icmp, tcp, udp, gre } accept
    117	  }
    118	}
    


    Настройка потребителей


    На самой РС


    Для более основательных испытаний прозрачного прокси-сервера я решил использовать его и для всех приложений (за некоторыми исключениями, о чём дальше) на самой РС.

    Добавим сертификат прокси-сервера в общее хранилище:

    mkdir -p /usr/local/share/ca-certificates
    cp /etc/squid/squid.pem /usr/local/share/ca-certificates/squid.crt

    Обновим хранилище:

    update-ca-certificates

    Приложения — веб-браузеры «Firefox» и «Chromium» не используют общее хранилище сертификатов, поэтому его следует добавлять в соответствующие хранилища этих приложений.

    Создадим конфигурационный файл /etc/env.d/38proxy с такими строками:

    http_proxy=http://192.168.120.1:3128
    https_proxy=http://192.168.120.1:3128
    ftp_proxy=http://192.168.120.1:3128
    

    Обновим переменные окружения:

    env-update

    После повторного входа настройки будут применены для всех приложений.

    Об исключениях:

    1. На всякий случай оставим веб-браузер «Chromium», он будет всегда подключаться к сети напрямую, без прокси-сервера, для этого конфигурационный файл /etc/chromium/default изменим таким образом:

      CHROMIUM_FLAGS="--enable-seccomp-sandbox —no-proxy-server"
    2. Приложение xfreerdp при наличии переменной окружения https_proxy пытается подключаться через прокси-сервера, поэтому в конфигурационный файл оболочки добавим следующую строку:

      alias xfreerdp='https_proxy= xfreerdp'
    3. Приложение youtube-dl не может проверить сертификат, вероятно, из-за особенностей хранилища сертификатов языка Python. Постоянное решение пока не найдено, поэтому в конфигурационный файл оболочки добавим следующую строку:

      alias youtube-dl='youtube-dl --no-check-certificate'

    На виртуальных машинах с ОС «Red Hat Enterprise Linux» 6-го и 7-го выпуска


    На виртуальной машине включаем работу с сертификатами PEM:

    update-ca-trust force-enable

    Переписываем с РС сертификат прокси-сервера на виртуальную машину:

    scp squid.crt root@192.168.120.66:/etc/pki/ca-trust/source/anchors/

    На виртуальной машине обновляем сертификата:

    update-ca-trust extract

    На виртуальных машинах с ОС «Microsoft Windows» разных выпусков


    Сертификат загружается в общее хранилище сертификатов машины (не пользователя!) в раздел «Доверенные корневые...». Веб-браузер «Firefox» не использует общее хранилище сертификатов, поэтому сертификат следует добавлять в соответствующее хранилище этого приложения.

    На РС «Raspberry Pi» с ОС «Raspbian»


    Обновление приложений прошло успешно без установки сертификата.

    На смартфонах с ОС «Android»


    Сертификат предварительно загружается на устройство, затем устанавливается с помощью приложения по управлению сертификатами. После этого у пользователя будет запрошено усиление безопасности входа в устройство (если это ещё не сделано) с помощью графического ключа или пароля.

    Вывод


    Новый брандмауэр в линуксе (nft) представляет собой прекрасный образчик свободного ПО, хорошо сочетающийся со Squid’ом, де-факто стандартом свободного прокси-сервера.

    Первоисточники


    1. http://wiki.squid-cache.org/Features/Tproxy4
    2. /usr/src/linux/Documentation/networking/tproxy.txt
    3. http://wiki.nftables.org
    4. nft(8)
    5. https://www.bounca.org/tutorials/install_root_certificate.html

    Автор: Шамиль Саитов Nikodim_Tychoblin
    InfoWatch
    Компания

    Похожие публикации

    Комментарии 6

      +1
      А вы не хотели бы переделать картинки с текстом на просто текст?
      В очень крайнем случае, приложить в конце поста ссылку на pdf файл с вашим любимым и обязательным форматированием текста.
        0
        Просто текст есть под картинками, скрытый в ссылке
        –1
        Стоп.
        Зачем сертификаты-то принудительно ставить клиентам? Сквид же умеет и в transparent и SslPeekAndSplice — wiki.squid-cache.org/Features/SslPeekAndSplice?
        Пользую Pfsense с пакетами squid + squidguard. Там достаточно только CA отдельный сгенерировать для сквида. Плюс можно и к LDAP\AD SSO прикрутить с kerberos.
          0
          Сертификаты раздавались принудительно, так как не было цели широкомасштабного внедрения на большое количество клиентов. Естественно, в инфраструктуре предприятия будет свой CA и сертификат Сквида будет подписан им, что избавит от необходимости устанавливать отдельный сертификат прокси-сервера. Настройка работы с LDAP, Kerberos и т. п. выходит за рамки статьи
          0
          Если настраиваем прозрачный режим — зачем это:
          http_proxy=http://192.168.120.1:3128
          https_proxy=http://192.168.120.1:3128
          ftp_proxy=http://192.168.120.1:3128
            0
            Дело в том, что прозрачный режим в моей установке применяется только для виртуальных машин и для телефона. Для самого хоста я решил не использовать прозрачный режим, поэтому прописал такие переменные окружения. Правда, от них пришлось впоследствии отказаться, когда выяснилось, что youtube-dl не хочет скачивать видео с подменным сертификатом, а разбираться с питоном было некогда :)

          Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

          Самое читаемое