DigiLoog

PC関係の事なら何でもいけるそんな処

VyOSでIPv6-Only IPSecVPN設定時に出るエラー回避方法

2020年08月08日(土) - 22:35 | カテゴリ: Network

“ns-lab BB”の自宅サーバとリモートで動いているVPS・専用サーバを繋ぐ為、
VyOSを使って拠点間IPSecVPNを構築してNW通信が出来る様にしてある。

従来はVPN専用に固定IPプロバイダを契約してIPv4 IPSecVPNを張っていたのだが、
費用とVPN冗長化の課題が出てきたので何とかしようと考えていた。
そんな中『PPPoEで大量に振ってくるIPv6を使えば専用プロバイダいらないのでは!?』
と思い立ったので、IPv6 IPSecVPNへ移行する事にした。

………

そうなると、IPv6アドレスのみ付与したインターフェースでIPSecを張る必要が出てくるのだが、
VyOS v1.2.Xに設定を投入するとこんなエラーが出てきた。

# commit
[ vpn ipsec site-to-site peer 2001:ffff:ffff:ffff::1 tunnel 1 ]
VPN configuration error: IPv4 over IPv6 IPsec is not supported

Warning: Local address 2001:0:0:0::1 specified for peer "2001:ffff:ffff:ffff::1"
is not configured on any of the ipsec-interfaces and is not the
clustering address.  IPsec must be re-started after address
has been configured.

VyOS公式でもバグ報告が上がっているのだが、優先度低になっており何時直るのか判らない状況。
コレが出来ないとIPv6環境に移行が出来ないのは勿論の事、修正を待って何もしないのもどうかと思ったので、
自力でVyOS内のIPSec設定スクリプトを直してみた。

………

修正箇所は次の通り。スクリプトがperlで書かれていたので読みやすかった。
どうやら、IPv6のみ付与したインターフェースでIPSecを設定しようとすると、
条件判定に引っかかってしまいエラーが出る様だった。
この問題は、VyOSのフォークとなるEdgeRouterでも発生するらしく、
先人の知恵も借りながら次の通りに修正してみた。

 

修正前:[/opt/vyatta/sbin/vpn-config.pl]

  550    # Check remote/local and peer protocol consistency
  551    # IPv6 over IPv6 scenario is actually supported by StrongS/WAN,
  552    # we do not allow it in this version because of design and QA issues.
  553    if (($conn_proto != 6) && ($leftsubnet_proto == 6)) {
  554        vpn_die(["vpn", "ipsec", "site-to-site", "peer", $peer, "tunnel", $tunnel],
                 "$vpn_cfg_err IPv6 over IPv4 IPsec is not supported");
  555    } elsif (($conn_proto == 6) && ($leftsubnet_proto != 6)) {
  556        vpn_die(["vpn", "ipsec", "site-to-site", "peer", $peer, "tunnel", $tunnel],
                 "$vpn_cfg_err IPv4 over IPv6 IPsec is not supported");
  557    }

 

修正後:[/opt/vyatta/sbin/vpn-config.pl]

  550    # Check remote/local and peer protocol consistency
  551    # IPv6 over IPv6 scenario is actually supported by StrongS/WAN,
  552    # we do not allow it in this version because of design and QA issues.
  553    if (($conn_proto != 6) && ($leftsubnet_proto != 0 and $leftsubnet_proto == 6)) {
  554        vpn_die(["vpn", "ipsec", "site-to-site", "peer", $peer, "tunnel", $tunnel],
                 "$vpn_cfg_err IPv6 over IPv4 IPsec is not supported");
  555    }
  556    if (($conn_proto == 6) && ($leftsubnet_proto != 0 and $leftsubnet_proto != 6)) {
  557        vpn_die(["vpn", "ipsec", "site-to-site", "peer", $peer, "tunnel", $tunnel],
                 "$vpn_cfg_err IPv4 over IPv6 IPsec is not supported");
  558    }

554行目と557行目は幅の関係で改行しているが実際は1行で書く。
実際の修正箇所は553行目と556行目の判定処理。
この改修を入れると、IPv6 IPSec VPNも設定が通る様になった。
だが、VyOSのアップグレードをすると元に戻る筈なので注意が必要。
そのうち公式修正で直ると思うが、それまではこの改修でお茶を濁そうと思う。

記事を公開した後に、違う不具合も見つけたので修正&追記

自力修正によってIPv6 IPSecVPNの設定が入る様になったが、
IPSecのIKEステータスを表示するとIKE SAが成立しているにも関わらず”down”と表示された。

$ show vpn ike sa | no-more
Peer ID / IP                            Local ID / IP
------------                            -------------
2001:ffff:ffff:ffff::1                  2001:0:0:0::1

    State  IKEVer  Encrypt  Hash    D-H Group      NAT-T  A-Time  L-Time
    -----  ------  -------  ----    ---------      -----  ------  ------
    down   IKEv2   aes256   sha1_96 2(MODP_1024)   no     -5640

色々とバグっているが、コレの原因は内部処理でハッシュキーが参照出来なくなっている為。
具体的には、VyOSのライブラリでIPv6アドレス判定を10進数でのみ評価しており、
16進数は例外処理に投げ込んでしまう為、コマンド実行時にアドレス不一致で値を取れなくなる。

解消する為には、ライブラリのIPv6判定をちゃんと16進数も評価する様に作れば直る。
ただし、RFC準拠で厳密に判定するとソレだけでライブラリになるので、今回は最低限に留める。

 

修正前:[/opt/vyatta/share/perl5/Vyatta/VPN/OPMode.pm]

  32  sub conv_id {
  33    my $peer = pop(@_);
  34    if ( $peer =~ /\d+\.\d+\.\d+\.\d+/ ){
  35      $peer = $peer;
  36    } elsif ($peer =~ /\d+\:\d+\:\d+\:\d+\:\d+\:\d+\:\d+\:\d+/){
  37      $peer = $peer;
  38    } elsif ($peer =~ /\%any/){
  39      $peer = "any";
  40    } else {
  41      $peer = "\@$peer";
  42    }
  43    return $peer;
  44  }

 

修正後:[/opt/vyatta/share/perl5/Vyatta/VPN/OPMode.pm]

  32  sub conv_id {
  33    my $peer = pop(@_);
  34    if ( $peer =~ /\d+\.\d+\.\d+\.\d+/ ){
  35      $peer = $peer;
  36    } elsif ($peer =~ /\d+\:\d+\:\d+\:\d+\:\d+\:\d+\:\d+\:\d+/){
  37      $peer = $peer;
  38    } elsif ($peer =~ /^(\:)?([0-9a-zA-Z]\:){0,8}(\:)?/){
  39      $peer = $peer;
  40    } elsif ($peer =~ /\%any/){
  41      $peer = "any";
  42    } else {
  43      $peer = "\@$peer";
  44    }
  45    return $peer;
  46  }

38~39行目を追加。適当だが、最低限動作するからヨシ!
何処かのタイミングで、修正のフォーラム投稿にチャレンジするのも良いかもしれない。





  • 応援中

    はじめるセカイの理想論 -goodbye world index-