UTM реализация "прямого доступа"


reddoggad - Posted on 14 Март 2010

Совсем не давно, возникла трудность, необходимо было реализовать доступ в Интернет, клиентам, используя в качестве билинга UTM5(В принципе по ходу будет ясно, что версия билинга вовсе не важна). Реализовать используя VPN или что то в этом духе не хотелось, нужно было сделать все так: клиент включает компьютер, и сразу же у него работает Интернет, а в личном кабинете можно было в любой момент приостановить доступ в сеть.
Для этого мне поднадобилось две машины, первая что бы использовать под билинг, вторая для NAS(он выступает в качестве шлюза для клиентов).

И так две машины, на сервере с UTM(в дальнейшем STAT) достаточно иметь одну сетевую карту, на него и повесим 192.168.110.2, а вот на NAS сервере лучше всего поставить две сетевых карты, одна для входящего канала(Интернет), вторая для клиентов.
И так вешаем на STAT ip 192.168.110.2 на NAS север вешаем на первую сетевую карту, ip нашего провайдера 111.111.111.111, а на вторую, которая смотрит в сторону локальной сети 192.168.110.1.

У меня NAS сервер вериться FreeBSD, на самом деле лучше его и использовать, потому как придеться работать с большим список IP адресов.
Далее нам понадобиться несколько «костылей» написаные Ильей Евсеевым, за что ему отдельная благодарность.
Но прежде нужно установить p5-Config-General, p5-DBI, p5-DBD-mysql.

$ sudo portinstall p5-Config-General
$ sudo portinstall p5-DBI
$ sudo portinstall p5-DBD-mysql

Теперь создадим несколько скриптов например в каталоге /usr/inet/

$ sudo mkdir /usr/inet
$ sudo ee /usr/inet/inetacls_generate

Туда запихиваем следующий код(естественно правим при необходимости путь к ipfw):

#!/usr/bin/perl —w
#
#  Turn on firewall rules for UTM users having persistent connections.
#  Should be called at startup from /etc/rc.local like following:
#     /root/scripts/enable_persistent_users | sh
#
#  Tested with UTM 3 and ipfw under FreeBSD 5.x on nas.sertolovo.ru.
#
#  Note: this script doesn't call ipfw, but simply displays needed commands.
#        You should manually pass they to shell input via pipe.
#        This is protection against dummy admin.
#
#  Written by Evseev/EBCEEB at Jan 2006
#  Rewritten on Perl at Apr 2006
#  Rewritten using DBI at Sep 2006
#  Rewritten for UTM5 at May 2008
#
# portinstall p5-Config-General
# portinstall p5-DBI
# portinstall p5-DBD-mysql
 
use strict;
use warnings;
 
use FindBin;
use lib "$FindBin::Bin";
use functions;
 
my $cfg = getconfig();
my $dbh = dbconnect();
 
my $rule_num  = $cfg- >{PERSIST_RULENUM} || '999';
my $table_num = $cfg- >{PERSIST_TABLE}   ||   '1';
 
our $check_tariff = $cfg- >{TARIFF_BLOCKED};
    $check_tariff = "and tariff != $check_tariff" if $check_tariff;
 
my $ipfw = "/sbin/ipfw —q";
 
my %allowed_ipaddrs;
 
#-  Routines  -#
 
sub handle_subnet(;$$)
{
        my $query = "SELECT INET_NTOA(4294967295 & ip_groups.ip) AS IP"
                . " FROM ip_groups, iptraffic_service_links, service_links, accounts"
                . " WHERE accounts.int_status != '0'";
        $query .= " AND (4294967295 & ip_groups.ip) >= INET_ATON(?)" if $_[0];  #..ipstart
        $query .= " AND (4294967295 & ip_groups.ip) < = INET_ATON(?)" if $_[1];  #..ipend
        $query .= " AND ip_groups.is_deleted = '0'"
                . " AND iptraffic_service_links.ip_group_id = ip_groups.ip_group_id"
                . " AND iptraffic_service_links.is_deleted = '0'"
                . " AND service_links.id = iptraffic_service_links.id"
                . " AND service_links.is_deleted = '0'"
                . " AND service_links.account_id = accounts.id"
                . " AND accounts.is_deleted = '0'";
 
        my $sth = dbquery($dbh, $query, @_);
 
        $allowed_ipaddrs{$_} = 1 while ($_) = $sth- >fetchrow_array;
}
 
#-  Main routine  -#
 
handle_subnet();
 
my $new_count = &ipfw_table_sync($table_num, \%allowed_ipaddrs);
if ($new_count) {
        print "$ipfw list $rule_num 2 >&1 | grep —q '$rule_num allow ip from table($table_num) to any' || $ipfw add $rule_num allow all from 'table($table_num)' to any\n" ;
        print "$ipfw list $rule_num 2 >&1 | grep —q '$rule_num allow ip from any to table($table_num)' || $ipfw add $rule_num allow all from any to 'table($table_num)'\n" ;
} else {
        print "$ipfw delete $rule_num 2 >/dev/null || echo \"Old rule $rule_num can't be deleted. Probably it's normal.\"\n" ;
}
 
## EOF ##

Необходимо также создать файл с функциями

$ sudo ee /usr/inet/functions.pm

Туда нужно всунуть это:

#/usr/bin/perl
 
use strict;
use warnings;
 
use DBI;
use FindBin;
use Config::General;
 
sub getconfig(;$) {
        my $fname = shift || "$FindBin::Bin/options";
        my $conf = new Config::General($fname);
        my %all = $conf- >getall;
        \%all;
}
 
sub dbconnect(;$) {
        my $cfg = shift || getconfig();
 
        my $dbhost = $cfg- >{UTM_DBHOST} || 'localhost';
        my $dbuser = $cfg- >{UTM_DBUSER};
        my $dbpass = $cfg- >{UTM_DBPASS};
        my $dbname = $cfg- >{UTM_DBNAME};
 
        my $dbh = DBI- >connect("DBI:mysql:database=$dbname:host=$dbhost", $dbuser, $dbpass)
                or die "Cannot connect to database $dbhost:$dbname : ".$DBI::errstr."\n";
        $dbh;
}
 
sub dbquery($$;@) {
        my $dbh = shift;
        my $query = shift;
        my $sth = $dbh- >prepare($query)
                or die "Cannot prepare query \"$query\": ".$dbh- >errstr."\n";
        $sth- >execute(@_)
                or die "Cannot execute query \"$query\": ".$dbh- >errstr."\n";
        $sth;
}
 
sub ipfw_table_sync($$)
{
        my ($table_num, $newdata_ref) = (@_);
        my %old;
        my $ipfw = '/sbin/ipfw';
        my $result = 0;
 
        open F, "$ipfw table $table_num list |"
                or die "ipfw_sync_table: $!\n";
 
        while(< F >) {
                chomp;
                next unless /^(\d+\.\d+\.\d+\.\d+)\/\d+\s+(\d+)$/;
                #print "DEBUG: line = \"$_\", A = \“".($1||'undef')."\", B = \“".($2||'undef')."\"\n";
                if (defined $1 and defined $2) {
                        $old{$1} = $2;
                } else {
                        print "# Wrong table line: $_\n";
                }
        }
 
        close F;
 
        while (my ($k,$v) = each %$newdata_ref) {
                $result++;
                #next if defined $old{$k} and $old{$k} eq $v;
                system("$ipfw —q table $table_num add $k $v \n"); # && echo —n \".\"\n";
        }
 
        while (my ($k,$v) = each %old) {
                next if defined $$newdata_ref{$k};
                system("$ipfw —q table $table_num delete $k 2 >/dev/null\n"); # && echo —n \"-\"\n";
        }
 
        print "echo\n";
        $result;
}
 
1;
 
## EOF ##

Теперь необходимо создать файл конфигурации.

$ sudo ee /usr/inet/options

И вставляем туда следующие:

#!/bin/sh
 
UTM_DBHOST="192.168.110.2"
UTM_DBUSER="UTM5"
UTM_DBNAME="utm5"
UTM_DBPASS="my password"
 
PERSIST_RULENUM=999
PERSIST_TABLE=1
 
## EOF ##

Меняем настройки:
UTM_DBHOST - Адрес сервера с MYSQL базой UTM5 может находиться как на локальном компьютере так и на удаленном.
UTM_DBUSER - Имя пользователя для подключения к MySQL.
UTM_DBNAME - Имя базы на сервере.
UTM_DBPASS - Пароль для подключения.

И так а теперь мы не забыли дать соответствующие права скриптам, после чего перешли плавно на STAT сервер, для настройки удаленного доступа к базе.
И так подключаемся к базе и делаем запрос:

mysql> GRANT ALL PRIVILEGES ON utm5.* TO  IDENTIFIED BY "my password";

И так проверяем с NAS(192.168.110.1) подключения к удаленной базе STAT(192.168.110.2).
После чего выполняем выши написаные скрипты:

$ sudo /usr/inet/inetacls_generate > /usr/inet/inetacls_apply
$ sudo /usr/inet/inetacls_apply

А теперь если все верно сделали, и в базе есть несколько абонетов для проверки, то смотрим ipfw.

$ sudo ipfw show 999

вывод этой команды должен быть такой:

00999  18969165   2069893966 allow ip from table(1) to any
00999   6179982   2669213084 allow ip from any to table(1)

А теперь посмотри кому же наш скриптик разрешил доступ в Интернет:

$ sudo ipfw table 1 list
192.168.110.10/32 1
192.168.110.11/32 1
192.168.110.13/32 1
192.168.110.16/32 1
192.168.110.17/32 1
192.168.110.23/32 1
192.168.110.25/32 1

Если лист пуст, то скорее всего просто у всех кончились деньги на счету :(

И так а теперь разберем момент номер правил фаервола можно поменять в скрипте в любой момент для этого достаточно изменить переменную в /usr/inet/options
PERSIST_RULENUM=999
А если необходимо изменить номер таблици(у нас используется 1) то меняем переменную:
PERSIST_TABLE=1

Осталось только дать людям интернет для этого нужно сделать NAT:

ipfw nat 1 config ip 111.111.111.111
ipfw 00400 add nat 1 ip from 'table(1)' to any out via vr0
ipfw 00400 add nat 1 ip from any to 111.111.111.111 in via vr0

Интерфейс vr0 смотри с строну нашего провайдера. 111.111.111.111 это ip адрес который мы получили у провайдера и которы настроили на vr0.

Учет трафика можно вести используя NetFlow.
Теперь осталось повесить скрипты на cron и собственно все. :)

Осталось предупредить, что есть большой минус данной реализации, если хотите избежать подменны ip адреса клиента, нужно иметь свитчи(L3) с возможность port_security и ip_mac_binding
тогда проблем будет существенно меньше. А если возможности реализовать этого нет, то использовать программу которая бы сама показывала вам, что подменили ip и когда, например утилита arpwatch

0
Ваша оценка: Ничего

Помогите найти скрипт просмотр ПК utm5.

Отличная статья! Жаль она не была у меня перед глазами год назад :(

Отправить комментарий

Google Friend Connect (leave a quick comment)
loading...
Содержание этого поля является приватным и не предназначено к показу.