ゲストホットスポットの管理の難しさ。 練習(パート2)

以前の記事で、私はisc-dhcpdのステータスを追跡する方法について話しました。今ではこのスキームを適用する実用的な方法について話しました。



負荷の高いゲストWi-Fiネットワークで作業する場合、外部サービスへの高度なアクセス権を持つクライアントを追跡および追加する問題があります。 最適なオプションはMACアドレスによるアクセス制御(dhcpd.confに多数のアドレスを入力する)ですが、実際に示すように、非常に不便です。 設定にすでに入力されているホストのステータスとその操作を実際に制御することはできません。



また、多数のランダムデバイスにより、リース期間を短縮するか、発行されたIPアドレスの範囲を拡大する必要があり、その結果、目的のホストの検索が遅くなります。 MACアドレスを監視して静的アドレスを発行すると、特定の問題が発生する可能性があります。 会社に2つのWi-Fiサブネットがあり、マルチアクセスポイントから2つの仮想ネットワーク(VLAN)が分散しているとします。 この場合、1つのWi-Fiネットワークが開いており、2つ目はパスワードで保護されています。

クライアントが正しく機能するためには、デバイスのMACアドレスを2つのプールに同時に追加する必要があります。 これにより、構成と管理の問題が混乱します。



詳細な説明を読むには、pf、squid、isc-dhcpd、およびWebサーバーがどのように機能するかについて少なくとも基本的な理解が必要です。




出口は何ですか?



解決策は少しわかりにくいですが、非常に簡単です。 dhcpd自体がネットワークへのユーザーアクセスを制御しないのはなぜですか?

したがって、isc-dhcpdがあります。ファイアウォールのサービスが表示されたときにアクセスを開き、表示されなくなったときにアクセスを無効にする必要があるクライアントのリストがあります。

クライアントのMACアドレスのデータベース、クライアントをすばやく追加するための便利なWeb銃口、設定を手動で編集せずにリモートで制御できるファイアウォール、および少しの忍耐が必要です。



まず、システムを準備する必要があります。

私はFreeBSDのサポーターです。そのため、私はすべての主要なプロジェクトを行っています。 多くのシステムコンポーネントには便利なコントロールがあります。 ファイアウォールとして、たくさんのpfpftabledを使用します。 pfファイアウォールは、基本的なルールを変更せずに変更できる動的テーブルを備えているという点で、他のファイアウォールと比べて有利です。 pftabledは、特別に細工されたパッケージを使用してこれらのテーブルの状態を制御できるデーモンです。



おおよそのpf.conf構成


int_if="em0" ext_if="em1" table <androids> table <private_nets> persist { 10.0.0.0/8, 172.16.0.0/16, 192.168.0.0/16 } # nat      ! nat on $ext_if from { <private_nets> } to { !<private_nets> } -> ($ext_if) #     .        <androids>    squid  transparent . no rdr on $int_if from <androids> to any #       apache      wpad.dat rdr on $int_if from ($int_if:network) to { any, !($int_if) } port { 80,8080 } -> 127.0.0.1 port 3129 # Allow DHCP pass in on $int_if proto udp from any port bootpc to any port bootps pass out on $int_if proto udp from any port bootps to any port bootpc # Allow DNS pass in on $int_if proto udp from ($int_if:network) to ($int_if) port domain keep state pass out on $int_if proto udp from ($int_if) to ($int_if:network) port domain # Allow Proxy access pass in on $int_if proto tcp from ($int_if:network) to ($int_if) port 3128 flags S/SA keep state pass in on $int_if proto tcp from ($int_if:network) to 127.0.0.1 port 3129 flags S/SA keep state # Allow access to local HTTP Server pass in on $int_if proto tcp from ($int_if:network) to ($int_if) port 80 flags S/SA keep state # Allow access from <androids> to any services pass in from <androids> to any keep state pass out on $ext_if from ($ext_if) to any keep state pass out on $ext_if proto icmp from any to any keep state
      
      







説明されている構成は何を提供しますか?




ポート80.8080のみを許可するのはなぜですか? 他のポートを開くと、ネットワークの使用を制御できなくなります。

回路が正しく機能するためには、ローカルwpadサービスを構成する必要があります。 設定するには、DNSサーバーにIN Aレコードを作成し、WebサーバーのアドレスをIPアドレスとして指定する必要があります。 以下は、Webサーバーのルートにあるwpad.datファイルの設定例です。

 function FindProxyForURL(url, host) { if( isPlainHostName(host) || dnsDomainIs(host, ".conf.local") || localHostOrDomainIs(host, "127.0.0.1") ){ return "DIRECT"; } if ( isInNet(host, "172.16.0.0", "255.255.0.0") || isInNet(host, "192.168.0.0", "255.255.0.0") || isInNet(host, "10.0.0.0", "255.0.0.0") || isInNet(host, "127.0.0.0", "255.255.255.0") ){ return "DIRECT"; } if ( isInNet(myIpAddress(), "192.168.0.0", "255.255.0.0")) return "PROXY 192.168.0.1:3128"; else return "DIRECT"; }
      
      





ファイルの内容は次のとおりです。



透明モードでsquidを設定する方法はここで読むのが一番です



さて、準備作業は完了です。 その後、システムカーネルの動作を確認できます。

dhcpdがユーザーのホストに正しく設定を与え、「プロキシサーバー設定の自動検出」設定を有効にすると、ブラウザーはwpad.datファイルを要求し、すべての要求をプロキシサーバー経由で送信します。 ホストをandroidsテーブルに追加すると、すべてのトラフィックがプロキシサーバーを通過します。



仕事用のデータベースを作成します



最も簡単で高速なデータ処理オプションは、発行されたアドレスの現在の設定を高速アクセスでアクセス可能な場所に保存することです。 Memcachedは私にとってこのような場所です。 一般的に、データベースやファイルストレージは、あなたの心が望むものなら何でも使用できます。 ポピーアドレスのローカルベースには、通常のパールバーDB_Fileを使用します。



最初の投稿で説明したように、発行済みアドレスのデータベースを作成するには、イベントハンドラーをdhcpdに接続する必要があります。 以下は私のハンドラーのテキストです。

 #!/usr/bin/perl use strict; use warnings; use DB_File; use IO::Socket; use Digest::HMAC_SHA1 qw(hmac_sha1); use Cache::Memcached::Fast; use Sys::Syslog; use vars qw/ $keyfile $key $lease_base $pftabled %macs/; use constant PFTBLPORT => 56789; use constant pfip => "127.0.0.1"; use constant PFTBLVERSION => 2; use constant PFTABLED_CMD_ADD => 1; use constant PFTABLED_CMD_DEL => 2; use constant PFTABLED_CMD_FLUSH => 3; use constant PFTBLCOMMAND => 1; use constant PFTBLMASK => 32; use constant SHA1_DIGEST_LENGTH => 20; use constant PFTBLNAME => "androids"; my $command = shift; my $ip = shift; my $mac = shift; my $pid = fork(); if($pid == 0) { $pftabled = IO::Socket::INET->new(Proto => 'udp', PeerPort => PFTBLPORT, PeerAddr => pfip) or die "Creating socket: $!\n"; openlog("publish-ip-mac","ndelay"); &load_key; &open_memcached; if($command eq 'commit') { &commit_address; } elsif($command eq 'release') { &release_address; } elsif($command eq 'expiry') { &release_address; } elsif($command eq 'hostname') { &commit_hostname; } else { syslog("info|local6","Unknown operation $command for $ip and $mac"); #print STDERR "Unknown operation $command for $ip and $mac\n"; } closelog; } exit(0); sub commit_address { $mac = join(":",map { sprintf("%02s",$_); } split(":",$mac)); #print STDERR "Host ".$ip." with MAC ".$mac." is alive\n"; syslog("info|local6","Host ".$ip." with MAC ".$mac." is alive"); $lease_base->set('ip/'.$mac,$ip,19200); $lease_base->set('mac/'.$ip,$mac,19200); $lease_base->set('lease_start/'.$ip,time(),19200); $lease_base->set('lease_end/'.$ip,time()+19200,19200); tie %macs, 'DB_File', '/var/db/macs.db', O_RDONLY, 0666, $DB_HASH or die "Cannot open file '/var/db/macs.db': $!\n"; syslog("info|local6","Mac: $mac Table Mac: $macs{$mac}"); if(exists $macs{$mac}) { syslog("info|local6","IP $ip put to pftable"); &pftabled_operations(PFTABLED_CMD_ADD,$ip); } untie %macs; } sub commit_hostname { $lease_base->set('name/'.$ip,$mac,19200); } sub release_address { if($mac = $lease_base->get('mac/'.$ip)) { syslog("info|local6","Host ".$ip." with MAC ".$mac." released or expired"); # print STDERR "Host ".$ip." with MAC ".$mac." released or expired\n"; $lease_base->delete('ip/'.$mac); $lease_base->delete('mac/'.$ip); $lease_base->delete('name/'.$ip); $lease_base->delete('lease_start/'.$ip); $lease_base->delete('lease_end/'.$ip); } else { # print STDERR "Host ".$ip." without MAC info released or expired\n"; syslog("info|local6","Host ".$ip." without MAC info released or expired"); } &pftabled_operations(PFTABLED_CMD_DEL,$ip); } sub check_access_table { } sub pftabled_operations { my $command = shift; my $iparray = shift; #print @iparray; foreach my $addip (split("\0",$iparray)) { my $addr = inet_aton($addip); my $time = time(); my $block = pack("C1 S1 C1",PFTBLVERSION,$command,PFTBLMASK).$addr.pack("a32 N*",PFTBLNAME,$time); my $digest = hmac_sha1($block, $key); $block .= $digest; $pftabled->send($block); } } sub load_key { my $keyfile = "/usr/local/etc/pftabled.key"; if (! -r $keyfile) { print STDERR "Cannot Read KeyFile $keyfile\n"; exit 1; } open(KEY, "<$keyfile"); sysread KEY, $key, SHA1_DIGEST_LENGTH; close KEY; } sub open_memcached { $lease_base = new Cache::Memcached::Fast({ servers => [ { address => 'localhost:11211', noreply => 1 } ], }); }
      
      







ファイル/usr/local/etc/pftabled.keyには、pftabledを使用するキーが含まれている必要があります。

/var/db/macs.dbファイルには、DB_File HASHの形式でMACアドレスのベースが含まれている必要があります。

dhcpdからcommitコマンドが表示されると、受信したMACアドレスがアドレスベースと照合され、アドレスベースに存在する場合、パケットがpftabledに送信され、macに対応するandroidsテーブルにipアドレスが追加されます。 releaseまたはexpire-ipコマンドが表示されると、androidsテーブルのIPアドレスが自動的に削除されます。



memcachedおよびpftabledのデータ有効期間は19200秒(約5時間)に設定され、同じ時間がmaximum-lease-timeパラメーターのdhcpd.conf構成に設定されます。 これは、memcachedおよびpfのホストが失われないようにするためです。



pftabledは、次のパラメーターで開始する必要があります。

pftabled_flags = "-d -a 127.0.0.1 -k /usr/local/etc/pftabled.key -t 19200"

crontabでは、次の行を追加する必要があります

* / 5 * * * * / sbin / pfctl -t androids -T expire 19200> / dev / null 2>&1



注意!!! /usr/local/etc/pftabled.keyは0444でなければなりません



実際、最後の部分はWebアクセスルールです。

コードはシンプルで気取らず、仕事には十分です。 したがって、可愛さとフリルなし。



 #!/usr/bin/perl use POSIX qw(strftime); use DB_File; use strict; use IO::Socket; use Digest::HMAC_SHA1 qw(hmac_sha1); use Cache::Memcached::Fast; use vars qw/%sv %form %cookie %macs $lease_base $pftabled $key/; use constant PFTBLPORT => 56789; use constant pfip => "127.0.0.1"; use constant PFTBLVERSION => 2; use constant PFTABLED_CMD_ADD => 1; use constant PFTABLED_CMD_DEL => 2; use constant PFTABLED_CMD_FLUSH => 3; use constant PFTBLCOMMAND => 1; use constant PFTBLMASK => 32; use constant SHA1_DIGEST_LENGTH => 20; use constant PFTBLNAME => "androids"; require "functions.pm"; #BEGIN { Net::ISC::DHCPd::OMAPI::_DEBUG = sub { 1 } } $lease_base = new Cache::Memcached::Fast({ servers => [ { address => 'localhost:11211', noreply => 1 } ], }); &systeminit; tie %macs, 'DB_File', '/var/db/macs.db', O_CREAT|O_RDWR, 0666, $DB_HASH or die "Cannot open file '/var/db/macs.db': $!\n"; print "Content-Type: text/html;\r\n\r\n"; print << "[end]"; <HTML> <HEAD> <meta http-equiv="Content-Type" content="text/html;"> <TITLE>DHCP State</TITLE> <STYLE> TD { font:14px Courier; border-left:0px; border-top:0px; border-right:1px; border-bottom:1px; border-style: dashed; text-align: center;} BODY { font:14px Courier; } INPUT[type=button] { width: 100px; font: Verdana, Tahoma; } TR.red { background-color: #A0A0A0; } TR.head { background-color: #808080; } TR.green { background-color: #00C000; } TABLE { } </STYLE> </HEAD> <BODY> <script> function subm(id) { if(confirm("Really toggle access type for " + id)) { document.toggle.mac.value=id; document.toggle.submit(); } } </script> [end] #print "Macs list: ",join (",",keys %macs),"\n"; if($form{"mac"}) { &load_key; $pftabled = IO::Socket::INET->new(Proto => 'udp', PeerPort => PFTBLPORT, PeerAddr => pfip) or die "Creating socket: $!\n"; my $ip = $lease_base->get("ip/".$form{"mac"}); # print "Form list: ",join (",",keys %form),"\n"; if(defined($macs{$form{"mac"}})) { delete($macs{$form{"mac"}}); &pftabled_operations(PFTABLED_CMD_DEL,$ip); print STDERR "MAC Address ".$form{"mac"}." with IP $ip removed from full access\n"; } else { print STDERR "MAC Address ".$form{"mac"}." with IP $ip added to full access\n"; &pftabled_operations(PFTABLED_CMD_ADD,$ip); $macs{$form{"mac"}} = 'full'; } } print << "[end]"; <table width=100% border=0 cellspacing=0 cellpadding=1> <form name="toggle" method=POST> <input type=hidden name="mac" value=""> </form> [end] for(my $network=0;$network<255;$network++) { print << "[end]"; <tr><th colspan=6>Network $network</th></tr> <tr class="head"><td>IP</td><td>MAC</td><td>Access</td><td>Hostname</td><td>Last Seen/Lease Start</td><td>Planned Expire</td></tr> [end] for(my $i=0;$i<256;$i++) { my $ip_address = "192.168.$network.$i"; my $mac_address = $lease_base->get('mac/'.$ip_address) || next; #print Dumper($lease); my $hostname = $lease_base->get('name/'.$ip_address); my $checkboxvalue = ($macs{$mac_address}) ? "Back to normal" : "Switch to full"; my $style = ($macs{$mac_address}) ? "green" : "red"; my $checkboxfield = ($mac_address) ? "<input type=button name=\"".$mac_address."\" value=\"$checkboxvalue\" onclick=\"subm(this.name)\">" : " "; print "<tr class=\"$style\"><td>"; print join ("</td><td>",$ip_address,$mac_address||" ",$checkboxfield,$hostname||" ",time_expand($lease_base->get('lease_start/'.$ip_address)),time_expand($lease_base->get('lease_end/'.$ip_address))); print "</tr>\n"; } print "<tr><td colspan=6> </td></tr>\n"; } print << "[end]"; <tr><th colspan=6>Registered Mac Addresses</td></tr> [end] foreach my $mac (keys %macs) { print << "[end]"; <tr><td class="red" colspan=2>$mac -> $macs{$mac}</td><td colspan=4> </td></tr> [end] } print "</table></html></body>"; untie %macs; exit(0); sub time_expand { my $time = shift; #($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($time); my $now = strftime "%a %b %e %H:%M:%S %Y", localtime($time); return($now); } sub pftabled_operations { my $command = shift; my $iparray = shift; #print @iparray; foreach my $addip (split("\0",$iparray)) { my $addr = inet_aton($addip); my $time = time(); my $block = pack("C1 S1 C1",PFTBLVERSION,$command,PFTBLMASK).$addr.pack("a32 N*",PFTBLNAME,$time); my $digest = hmac_sha1($block, $key); $block .= $digest; $pftabled->send($block); } } sub load_key { my $keyfile = "/usr/local/etc/pftabled.key"; if (! -r $keyfile) { print STDERR "Cannot Read KeyFile $keyfile\n"; exit 1; } open(KEY, "<$keyfile"); sysread KEY, $key, SHA1_DIGEST_LENGTH; close KEY; }
      
      







まあ、それは基本的にそれです。

この読書があなたにとって有益であり、あなたの会社のシステムの改善の可能性についてのある種の考えにつながることを願っています。



PS:ユーザー自身によるアクセスを開くことができるホットスポットを作成するには、初期プロキシリダイレクトを認証フォームを使用してWebサーバーへのリダイレクトに置き換え、そこからisc-dhcpdを使用せずにpftabledにホストを追加します。

PPS:最後のファイルで「functions.pm」を使用すると、フォームと環境変数の入力プロセッサになります。 変数チェックはCGIで書き直すことができます。 ご希望の方には、モジュール「functions.pm」の機能コードとソースコードをレイアウトできます



Aborche 2011








All Articles