"балансировка" ISP & vpn (Packet Filter)

Простые/общие вопросы по UNIX системам. Спросите здесь, если вы новичок

Модераторы: vadim64, terminus

Правила форума
Убедительная просьба юзать теги [cоde] при оформлении листингов.
Сообщения не оформленные должным образом имеют все шансы быть незамеченными.
DuoMorph
рядовой
Сообщения: 46
Зарегистрирован: 2010-02-03 21:07:49

"балансировка" ISP & vpn (Packet Filter)

Непрочитанное сообщение DuoMorph » 2015-12-07 17:37:51

Приветству, коллеги. Требую вашего совета :)
Есть такая ситуевина: роутер (дестктоп с фряхой и PF), на котором помимо инета от прова, так же есть коннект до сервера openvpn, через который необходимо локальные хосты пускать на некоторые сайты из некоторого списка, вопрос всей этой реализации.

Изначально моя задумка была следующей: создать у pf файл-таблицу куда складывать домены необходимых ресурсов, скоре оказалось, что это неосуществимо, т.к. мне либо прийдется переписывать дефолтный маршрут провайдера дефолтным маршрутом впн иначе трафик не идет.

Код: Выделить всё

int_if="em0"
ext_if="em1"
work_vpn = "tun0"
vps_if="tun5"
whoer="162.159.247.58"
whoer2="162.159.246.58"
#       to inet                 #
nat on $ext_if from $int_if:network to { !$work_local, !$whoer }  -> ($ext_if)
#       from openvpn            #
nat on $work_vpn from $int_if:network to $work_local -> ($work_vpn)
#       for blocked sites       #
nat on $vps_if from any to $whoer -> ($vps_if)
Как вариант для каждого домена резолвить ipшник (который может быть ещё и не один) и добавлять его в маршруты при подключении к vpn, но этот вариант мне не особо нравится...

Так же поглядывал в сторону FIB, но как работать с ним в связке с PF, я найти не смог. Вскоре после FIB докатился до "PF: Address Pools and Load Balancing", но на обычное правило "match out on $ext_if from $int_if:network nat-to ($ext_if)" pfctl -nf говорит, что у меня ошибка в данной строке, без каких либо подробностей... В общем беда))))))

Подскажите, как бы поступить?

P.S. Общая инфа:
FreeBSD 10.2-RELEASE-p7 amd64

Отправлено спустя 1 час 5 минут 31 секунду:
А ну и ещё как вариант прозрачный проксик поставить на серваке с vpn, но чегото мне тоже както не по душе эта затея, но как вариант...

Хостинговая компания Host-Food.ru
Хостинг HostFood.ru
 

Услуги хостинговой компании Host-Food.ru

Хостинг HostFood.ru

Тарифы на хостинг в России, от 12 рублей: https://www.host-food.ru/tariffs/hosting/
Тарифы на виртуальные сервера (VPS/VDS/KVM) в РФ, от 189 руб.: https://www.host-food.ru/tariffs/virtualny-server-vps/
Выделенные сервера, Россия, Москва, от 2000 рублей (HP Proliant G5, Intel Xeon E5430 (2.66GHz, Quad-Core, 12Mb), 8Gb RAM, 2x300Gb SAS HDD, P400i, 512Mb, BBU):
https://www.host-food.ru/tariffs/vydelennyi-server-ds/
Недорогие домены в популярных зонах: https://www.host-food.ru/domains/

Аватара пользователя
Alex Keda
стреляли...
Сообщения: 35456
Зарегистрирован: 2004-10-18 14:25:19
Откуда: Made in USSR
Контактная информация:

"балансировка" ISP & vpn (Packet Filter)

Непрочитанное сообщение Alex Keda » 2015-12-15 8:25:27

Прокси - чем не вариант-то?
Убей их всех! Бог потом рассортирует...

DuoMorph
рядовой
Сообщения: 46
Зарегистрирован: 2010-02-03 21:07:49

"балансировка" ISP & vpn (Packet Filter)

Непрочитанное сообщение DuoMorph » 2015-12-15 17:21:28

Alex Keda писал(а):Прокси - чем не вариант-то?
Лишний слой инкапсуляции трафика, как минимум. В общем задачу решил с помочью второй таблицы маршрутизации:

pf.conf

Код: Выделить всё

int_if="em0"
ext_if="em1"
vps_if="tun5"
tu = "{tcp udp}"
icmp_types = "echoreq"
table <blocked_sites> persist file "/etc/sitesunblock/block_sites"

set block-policy drop #return
set skip on lo
scrub in all
scrub in all fragment reassemble
scrub out all random-id #max-mss 1460
scrub on $vps_if max-mss 1300

#+++++++++++++++++++++++++++++++++++++++#
#       NAT RULES                       #
#+++++++++++++++++++++++++++++++++++++++#
#       to inet                         #
nat on $ext_if from $int_if:network to any -> ($ext_if)
#       from openvpn                    #
nat on $vps_if from $int_if:network to <blocked_sites> -> ($vps_if)

#+++++++++++++++++++++++++++++++++++++++#
#       FIREWALL RULES                  #
#+++++++++++++++++++++++++++++++++++++++#
block all
#pass in all
pass out all
pass on tun5 all
pass on $int_if from $int_if:network to any

#       for ping                        #
#pass in inet proto icmp all icmp-type $icmp_types keep state
#pass in proto udp from any to any port 33433 >< 33626 keep state

#       pass to blocked sites via vps   #
pass quick from $int_if:network to <blocked_sites> rtable 1
rc.local

Код: Выделить всё

# set default route for openvpn_vps
setfib 1 route add <ip_впн_сервера> <шлюз_провайдера> 255.255.255.255
в ядро добавляем поддержку двух таблиц маршрутизации:

Код: Выделить всё

options         ROUTETABLES=2
openvpn.conf

Код: Выделить всё

client
dev tun5
proto tcp
remote <vpn_server_ip> 1194
resolv-retry infinite
nobind
persist-key
persist-tun
ca vps/ca.crt
cert vps/desk.crt
key vps/desk.key
tls-auth vps/ta.key 1
cipher DES-EDE3-CBC
ns-cert-type server
comp-lzo
log openvpn_vps.log
verb 3

route 0.0.0.0 0.0.0.0 10.8.1.1
, где 10.8.1.1 - адрес vpn сервера доступный через созданный vpn тунел.

netstat -rn - покажет первую таблицу маршрутизации
setfib 1 netstat -rn - покажет вторую таблицу маршрутизации
операции с маршрутами в этих таблицах осуществляется аналогично их выводу, т.е. добавить маршрут во вторую таблицу можно следующим образом: setfib 1 route add ...

Ну и небольшой скриптец для выкачки, валидации заблокированных РКН ipшников:

Код: Выделить всё

#!/usr/bin/env python3
import urllib.request
import re
import datetime
import subprocess as s
import shlex
import socket

#   Variable
root = '/etc/sitesunblock/'
console_cp = 'utf-8'
additionals_sites = ['whoer.net']
exclude_subnets = ('127.','192.168','10.','169.254.','0.','192.0.2.','198.51.100.','203.0.113.','255.')
exclude_subnets_regexp = '(172\.(1[6-9]|2[0-9]|3[0-2])|2(2[4-9]|3[0-2]|3[5-9]))\.'
path2listIP = '/etc/sitesunblock/block_sites'
logfile = '/etc/sitesunblock/getBlockedIP.log'
cmd = 'pfctl -nf /etc/pf.conf && pfctl -f /etc/pf.conf && echo 1'
# End Variable

def getListIP1():
    try:
        url='http://reestr.rublacklist.net/api/ips'
        f = urllib.request.urlopen(url)
        page = f.read().decode('utf-8')
        ip_list = page.replace('"','').split(';')
        return ip_list
    except Exception as error:
        print(error.args)
        return None

def getListIP2():
    pass

def writeResult(ip_list):
    global path2listIP
    try:
        file = open(path2listIP,'w')
        file.write('\n'.join(ip_list))
        file.close()
    except Exception as error:
        writeStatus('Error write results. excepted:'+str(error.args))
        print('Error write results. excepted:'+str(error.args))

def writeStatus(data):
    global logfile
    try:
        file = open(logfile,'a+')
        file.write(str(data)+'\n')
        file.close()
    except Exception as error:
        writeStatus('Error write status. excepted:'+str(error.args))
        print('Error write status. excepted:'+str(error.args))

def CmdExec(cmd):
    global console_cp
    try:
        p = s.check_output(cmd, shell=True)
        output = p.decode(console_cp)
        if output.replace("\r","").replace("\n","")[-1]=='1':
            writeStatus('Cmd execute successful: '+str(cmd))
            print('Cmd execute successful: '+str(cmd))
        else:
            writeStatus('Error execute?: "'+str(cmd)+'" stdout:'+output)
            print('Error execute?: "'+str(cmd)+'" stdout:'+output)
    except Exception as error:
        writeStatus('"'+str(cmd)+'" except:'+str(error.args))
        print('"'+str(cmd)+'" excepted:'+str(error.args))

def ValidateIPlist(ip_list):
    result_list = []
    global exclude_subnets_regexp
    global exclude_subnets
    regexp_exclude_subnets = re.compile(exclude_subnets_regexp)
    for ip in ip_list:
        try:
            socket.inet_aton(ip)
            if not ip.startswith(exclude_subnets):
                regexp_match = regexp_exclude_subnets.match(ip)
                if not regexp_match:
                    result_list.append(ip)
                elif not regexp_match.start()==0:
                    result_list.append(ip)
                else:
                    writeStatus(ip)
                    print('Removed: '+ip)
            else:
                writeStatus(ip)
                print('Removed: '+ip)
        except Exception as error:
            if ip!='':
                writeStatus('"'+ip+'" excepted:'+str(error.args))
                print('"'+ip+'" excepted:'+str(error.args))
    print('\n\nBlocked sites: '+str(len(result_list)))
    return result_list

writeStatus('\nDatetime: '+str(datetime.datetime.now()))
print('Log:')
ip_list = getListIP1()
if ip_list:
    writeResult(ValidateIPlist(ip_list)+additionals_sites)
else:
    print('Error fetching IP list.')
    exit(1)
CmdExec(cmd)
print('Done!')

Аватара пользователя
dekloper
ст. лейтенант
Сообщения: 1331
Зарегистрирован: 2008-02-24 15:43:19
Откуда: давно здесь сидим..
Контактная информация:

"балансировка" ISP & vpn (Packet Filter)

Непрочитанное сообщение dekloper » 2015-12-16 6:49:11

DuoMorph писал(а): в ядро добавляем поддержку двух таблиц
можно не добавлять
в /boot/loader.conf втыкаем net.fibs=2 и всё
ТОВАгИЩИ! БгАТЬЯ И СЕСТгЫ! ДОЛОЙ гАВНОДУШИЕ!

DuoMorph
рядовой
Сообщения: 46
Зарегистрирован: 2010-02-03 21:07:49

"балансировка" ISP & vpn (Packet Filter)

Непрочитанное сообщение DuoMorph » 2015-12-16 12:34:20

dekloper писал(а):можно не добавлять
в /boot/loader.conf втыкаем net.fibs=2 и всё
Можно, но если все равно ребутаться, почему бы не добавить в ядро? :)

еще забыл: в rc.conf

Код: Выделить всё

openvpn_vps_fib="1"
P.S. На сколько я знаю, так можно только с фряхи версии >9