/* plum3.1.0b18 用、複数のNICを持つ環境のためのパッチ 設定ファイルの変更 ----------------------- plum.bind_src: juggler.jp;0 IRCサーバに接続する際にソケットのソースアドレスを指定する。 アドレスとポートの組を1つだけ書ける。複数の指定には対応していない。 ポート番号にはたいていの場合0を指定することになるだろう。 複数のポート番号をカンマで区切るとランダムに選ばれる。 アドレスに0を指定するとデフォルトのネットワークインタフェースを選択することになるかもしれない。 plum.client: * juggler.jp;4567 changeme 空白で区切った引数が3つある場合は次のように解釈する。 client_mask listen_host;listen_port password listen_hostはIRCクライアントからの接続を待つアドレスまたはホスト名を指定する。 *と書くと任意のアドレスをlistenする。 制限: ポート番号ごとに1種類のアドレス(*を含む)しか指定できない。 同じポートと異なるアドレスの組み合わせは正常に動作しない。 追加したグローバル変数 ----------------------- @listen_host plum.clientに指定したlisten_host。@portと対になる。 property_change 関数内で用意される。 @bind_src 設定ファイルの plum.bind_src を記録する。 property_change 関数内で用意される。 履歴 ------------------- 03/03/16(日) 18:29:47 tateisu@smilemark.com とりあえず書いてみた。IPv6では試してない。 パッチ本体 ----------------------- /* *** plum Sun Dec 17 22:23:38 2000 --- plum3-bindsrc Sun Mar 16 20:21:55 2003 *************** *** 5,11 **** package plum; $NAME = 'plum'; ! $VERSION = '3.1.0b18'; $NIL = "\r"; $NOTRAILING = &'list('004', '215', '221', '324', '341', '367', 'MODE'); --- 5,11 ---- package plum; $NAME = 'plum'; ! $VERSION = '3.1.0b18-t1'; $NIL = "\r"; $NOTRAILING = &'list('004', '215', '221', '324', '341', '367', 'MODE'); *************** *** 664,671 **** } sub 'connect { ! local($no, $host, $port) = @_; local($addr, $family, $sin); $addr = &'address($host) || return 0; if (length($addr) == 4) { $family = $PF_INET || $AF_INET || 2; --- 664,690 ---- } sub 'connect { ! local($no, $host, $port,$bind_hostport) = @_; local($addr, $family, $sin); + local($bind_src,$bhost,$bport,$list,@port); + undef $bind_src; + if( defined $bind_hostport ){ + ($bhost,$list)=split /;/,$bind_hostport; + @port = split /\,/,($list || '0'); + $bport = $port[rand @port]; + if( length $bhost ){ + $addr = &'address($bhost) || return 0; + if(length($addr) == 4) { + if( defined(&pack_sockaddr_in) ){ + $bind_src = &pack_sockaddr_in($bport, $addr); + }else{ + $bind_src = pack($SOCKADDR, $AF_INET || $PF_INET || 2, $bport, $addr); + } + }elsif( length($addr) == 16 ){ + $bind_src = &pack_sockaddr_in6($bport, $addr) if defined &pack_sockaddr_in6; + } + } + } $addr = &'address($host) || return 0; if (length($addr) == 4) { $family = $PF_INET || $AF_INET || 2; *************** *** 685,709 **** return 0; } socket($'socket[$no], $family, $SOCK_STREAM || 1, $PROTO || 6) || return 0; connect($'socket[$no], $sin) || return 0; &setup($no); return 1; } sub 'listen { ! local($no, $port, $count) = @_; local($addr, $sin); socket($'socket[$no], $PF_INET || $AF_INET || 2, $SOCK_STREAM || 1, $PROTO || 6) || return 0; if (defined($SOL_SOCKET) && defined($SO_REUSEADDR)) { setsockopt($'socket[$no], $SOL_SOCKET, $SO_REUSEADDR, pack('l', 1)); } ! $addr = $INADDR_ANY || "\0" x 4; if (defined(&pack_sockaddr_in)) { $sin = &pack_sockaddr_in($port, $addr); } else { $sin = pack($SOCKADDR, $AF_INET || $PF_INET || 2, $port, $addr); } ! if (!bind($'socket[$no], $sin)) { close($'socket[$no]); return 0; } --- 704,736 ---- return 0; } socket($'socket[$no], $family, $SOCK_STREAM || 1, $PROTO || 6) || return 0; + defined($bind_src) && bind($'socket[$no],$bind_src); connect($'socket[$no], $sin) || return 0; &setup($no); return 1; } sub 'listen { ! local($no, $port, $count,$listen_host) = @_; local($addr, $sin); socket($'socket[$no], $PF_INET || $AF_INET || 2, $SOCK_STREAM || 1, $PROTO || 6) || return 0; if (defined($SOL_SOCKET) && defined($SO_REUSEADDR)) { setsockopt($'socket[$no], $SOL_SOCKET, $SO_REUSEADDR, pack('l', 1)); } ! ! if(defined($listen_host) and $listen_host ne '*'){ ! $addr = &'address($listen_host) || return 0; ! }else{ ! $addr = $INADDR_ANY || "\0" x 4; ! } ! if (defined(&pack_sockaddr_in)) { $sin = &pack_sockaddr_in($port, $addr); } else { $sin = pack($SOCKADDR, $AF_INET || $PF_INET || 2, $port, $addr); } ! if( !bind($'socket[$no], $sin) ){ ! warn "cant bind $listen_host;$port $!\n"; close($'socket[$no]); return 0; } *************** *** 713,726 **** } sub 'listen6 { ! local($no, $port, $count) = @_; local($addr, $sin); return 0 unless ($PF_INET6 || $AF_INET6); socket($'socket[$no], $PF_INET6 || $AF_INET6, $SOCK_STREAM || 1, $PROTO || 6) || return 0; if (defined($SOL_SOCKET) && defined($SO_REUSEADDR)) { setsockopt($'socket[$no], $SOL_SOCKET, $SO_REUSEADDR, pack('l', 1)); } ! $addr = $IN6ADDR_ANY || "\0" x 16; if (defined(&pack_sockaddr_in6)) { $sin = &pack_sockaddr_in6($port, $addr); } else { --- 740,759 ---- } sub 'listen6 { ! local($no, $port, $count,$listen_host) = @_; local($addr, $sin); return 0 unless ($PF_INET6 || $AF_INET6); socket($'socket[$no], $PF_INET6 || $AF_INET6, $SOCK_STREAM || 1, $PROTO || 6) || return 0; if (defined($SOL_SOCKET) && defined($SO_REUSEADDR)) { setsockopt($'socket[$no], $SOL_SOCKET, $SO_REUSEADDR, pack('l', 1)); } ! ! if(defined($listen_host) && $listen_host ne '*'){ ! $addr = &'address($listen_host) || return 0; ! }else{ ! $addr = $IN6ADDR_ANY || "\0" x 16; ! } ! if (defined(&pack_sockaddr_in6)) { $sin = &pack_sockaddr_in6($port, $addr); } else { *************** *** 1545,1551 **** sub property_change { local($userno) = @_; ! local($sno, $i, $mask, $pass, $host, $port, $lno); if (!$default[$userno]) { $sno = &'socket('S'); $default[$userno] = $sno; --- 1578,1584 ---- sub property_change { local($userno) = @_; ! local($sno, $i, $mask, $pass, $host, $port, $lno,$listen_host,@a); if (!$default[$userno]) { $sno = &'socket('S'); $default[$userno] = $sno; *************** *** 1562,1571 **** undef %auth; for ($i = 1; $i < @'username; $i++) { foreach $client (&'property($i, 'client')) { ! ($mask, $pass) = split(/\s+/, $client); ! ($host, $port) = split(/\;/, $mask); $port = $PORT unless $port; ! $auth{$port} = &'add($auth{$port}, join(';', $host, $i, $pass || '')); } } foreach $lno (&'array($listenlist)) { --- 1595,1612 ---- undef %auth; for ($i = 1; $i < @'username; $i++) { foreach $client (&'property($i, 'client')) { ! @a = split(/\s+/, $client); ! if(@a==3){ ! ($mask,$host,$pass) = @a; ! ($listen_host, $port) = split(/\;/, $host); ! $listen_host ||='*'; ! }else{ ! ($host, $pass) = @a; ! ($mask, $port) = split(/\;/, $host); ! $listen_host='*'; ! } $port = $PORT unless $port; ! $auth{$port} = &'add($auth{$port}, join(';', $mask, $i,$listen_host,($pass || ''))); } } foreach $lno (&'array($listenlist)) { *************** *** 1587,1593 **** --- 1628,1643 ---- $lno = &'socket('L'); $port[$lno] = $port; $listenwaitlist = &'add($listenwaitlist, $lno); + + my %listen_host; + for( &'array($auth{$port}) ){ + my $p = (split/;/,$_)[2]; + $listen_host{ $p }=1 if length $p; + } + warn "too many listen addr on port $port ",join(' ',sort map{ length $_?$_:'*' } keys %listen_host),"\n" if keys(%listen_host)>1 ; + $listen_host[$lno] = (keys %listen_host)[0]; } + $bind_src[$userno] = &'property($userno, 'bind_src'); } sub main_loop { *************** *** 1669,1675 **** local($socket, $userno, $pass, $sno); $socket = $'socket[$cno]; foreach $auth (&'array($auth[$cno])) { ! ($userno, $pass) = split(/\;/, $auth, 2); next if ($pass && $pass ne $pass[$cno]); if ($default[$userno]) { $sno = $default[$userno]; --- 1719,1725 ---- local($socket, $userno, $pass, $sno); $socket = $'socket[$cno]; foreach $auth (&'array($auth[$cno])) { ! ($userno,undef,$pass) = split(/\;/, $auth, 3); next if ($pass && $pass ne $pass[$cno]); if ($default[$userno]) { $sno = $default[$userno]; *************** *** 1721,1732 **** sub l_init { local($lno) = @_; if ($port[$lno] > 0) { ! if (!&'listen($lno, $port[$lno])) { &'alarm(-$INTERVAL); return; } } else { ! if (!&'listen6($lno, -$port[$lno])) { &'alarm(-$INTERVAL); return; } --- 1771,1782 ---- sub l_init { local($lno) = @_; if ($port[$lno] > 0) { ! if( !&'listen($lno, $port[$lno],undef,$listen_host[$lno]) ){ &'alarm(-$INTERVAL); return; } } else { ! if( !&'listen6($lno, -$port[$lno],undef,$listen_host[$lno]) ){ &'alarm(-$INTERVAL); return; } *************** *** 1745,1751 **** return unless $host; @port = split(/\,/, $list || ''); $sno = $default[$userno]; ! if (&'connect($sno, $addr, $port[rand(@port)] || $PORT)) { $'userno[$sno] = $userno; $status[$userno] = 1; $bufr[$sno] = ''; --- 1795,1801 ---- return unless $host; @port = split(/\,/, $list || ''); $sno = $default[$userno]; ! if( &'connect($sno, $addr,($port[rand(@port)] || $PORT),$bind_src[$userno]) ){ $'userno[$sno] = $userno; $status[$userno] = 1; $bufr[$sno] = '';