【问题标题】:Connect CISCO Anyconnect VPN via bash通过 bash 连接 CISCO Anyconnect VPN
【发布时间】:2014-08-04 06:52:48
【问题描述】:

正如标题所说,尝试通过 bash 连接 vpn。以下脚本似乎最接近我正在寻找的答案:

#!/bin/bash
/opt/cisco/anyconnect/bin/vpn -s << EOF
connect https://your.cisco.vpn.hostname/vpn_name
here_goes_your_username
here_goes_your_passwordy
EOF

当我运行它时,vpn 会启动,但随后退出且没有错误且没有连接。这似乎是由 -s 引起的。如果我删除此参数,VPN 将启动,但不会输入任何命令(即连接 vpn、用户名、密码)。从我读到的 -s 选项将允许传递用户名/密码。 救命!

【问题讨论】:

  • 如果您正在尝试编写交互式程序脚本,您可能需要查看expect(1)
  • 谢谢!让它使用期望工作。如果其他人有类似的问题,这里是我使用的教程(我什至不知道期望,所以它非常基本):thegeekstuff.com/2010/10/expect-examples
  • 这也是您可以使用 OpenConnect 而不是使用官方 AnyConnect 客户端轻松完成的事情。

标签: bash vpn cisco


【解决方案1】:

我必须下载期望的软件包(yum install expect)。这是我用来自动化 vpn 连接的代码

#!/usr/bin/expect

eval spawn /opt/cisco/anyconnect/bin/vpn connect vpn.domain.com

expect "Username: " { send "username\r" }
expect "Password: " { send "password\r" }

set timeout 60
expect "VPN>"

真的很简单! :D

【讨论】:

    【解决方案2】:

    虽然expect 可以更干净,但并非绝对必要。假设 /opt/cisco/anyconnect/bin/vpnagentd 自动运行:

    连接

    printf "USERNAME\nPASSWORD\ny" | /opt/cisco/anyconnect/bin/vpn -s connect HOST
    

    替换 USERNAMEPASSWORDHOST。最后的\ny 是接受登录横幅 - 这是特定于我的主机的,因此您可能不需要它。

    我了解此方法存在明显的安全问题;仅供参考。

    要获得状态

    /opt/cisco/anyconnect/bin/vpn state
    

    断开连接

    /opt/cisco/anyconnect/bin/vpn disconnect
    

    这是使用 AnyConnect v3.1.05160 测试的。

    【讨论】:

    • 参考:在我的 vpn cli 手动选项中,“-s 从标准输入读取命令示例:vpncli.exe -s
    • 我很好奇管道“|”在这里工作。为什么“vpn connect HOST”会从管道中读取密码?我尝试对 ssh 使用相同的方法。但它没有用。 "printf "password" | ssh user@HOST " 给出错误 "伪终端将不会被分配,因为 stdin 不是终端。"
    • 后来我发现,对于SSH来说,这是因为它的安全特性可以防止它从不安全的来源读取密码,比如文件或println
    【解决方案3】:

    如果您使用的是 macOS,我建议将您的 vpn 密码保存在 Keychain 中,然后从您的 Anyconnect 脚本中请求它。

    例如,假设我想使用帐户 foo 和密码 bar 连接到 foo.bar.com

    1. foobar 对保存在钥匙串中(登录而不是 iCloud),名称为 fookey
    2. 运行以下 bash 脚本进行连接
    /opt/cisco/anyconnect/bin/vpn connect foo.bar.com -s << EOM
    0    # foo.bar.com doesn't require two factor authorization
    foo  # vpn account
    $(sudo security find-generic-password -ws fookey)  # vpn password
    EOM
    

    使用这种方法,您无需每次都输入您的 vpn 密码,也不会将密码写入未加密的文件中。

    如果您不熟悉 bash 脚本,请阅读以下说明:


    • /opt/cisco/anyconnect/bin/vpn connect -s 进入非交互模式。
    • &lt;&lt; EOM ... EOM 称为here-docs,它使用字符串替换文件。编写交互式 CLI 脚本非常有用,通过将每个响应编写为新行。
    • security 是从命令行访问钥匙串的好工具。

    【讨论】:

      【解决方案4】:

      c# 解决方案...在这种情况下 profile 是组名。

      //file = @"C:\Program Files (x86)\Cisco\Cisco AnyConnect Secure Mobility Client\vpncli.exe"
      var file = vpnInfo.ExecutablePath;
      var host = vpnInfo.Host;
      var profile = vpnInfo.ProfileName;
      var user = vpnInfo.User;
      var pass = vpnInfo.Password;
      var confirm = "y";
      
      var proc = new Process
      {
          StartInfo = new ProcessStartInfo
          {
              FileName = file,
              Arguments = string.Format("-s"),
              UseShellExecute = false,
              RedirectStandardInput = true,
              RedirectStandardOutput = true,
              RedirectStandardError = true,
          }
      };
      
      proc.OutputDataReceived += (s, a) => stdOut.AppendLine(a.Data);
      proc.ErrorDataReceived += (s, a) => stdOut.AppendLine(a.Data);
      
      //make sure it is not running, otherwise connection will fail
      var procFilter = new HashSet<string>() { "vpnui", "vpncli" };
      var existingProcs = Process.GetProcesses().Where(p => procFilter.Contains(p.ProcessName));
      if (existingProcs.Any())
      {
          foreach (var p in existingProcs)
          {
              p.Kill();
          }
      }
      
      proc.Start();
      proc.BeginOutputReadLine();
      
      //simulate profile file
      var simProfile = string.Format("{1}{0}{2}{0}{3}{0}{4}{0}{5}{0}"
          , Environment.NewLine
          , string.Format("connect {0}", host)
          , profile
          , user
          , pass
          , confirm
          );
      
      proc.StandardInput.Write(simProfile);
      proc.StandardInput.Flush();
      
      //todo: these should be configurable values
      var waitTime = 500; //in ms
      var maxWait = 10;
      
      var count = 0;
      var output = stdOut.ToString();
      while (!output.Contains("state: Connected"))
      {
          if (count > maxWait)
              throw new Exception("Unable to connect to VPN.");
      
          Thread.Sleep(waitTime);
          output = stdOut.ToString();
          count++;
      }
      stdOut.Append("VPN connection established! ...");
      

      【讨论】:

        【解决方案5】:

        基于 Brayden Hancock 的回答,我构建了一个从 macOS 钥匙串读取密码的解决方案。 作为第一步,我通过 Keychain Access 应用程序添加了一个新密码项,其中 account 字段设置为 mycompany-vpn。脚本的第一部分从钥匙串中读取该项目并使用 ruby​​ sn-p 提取密码,expect 脚本部分完成其余部分。

        #!/usr/bin/env bash
        get_pw () {
            security 2>&1 >/dev/null find-generic-password -ga mycompany-vpn \
            |ruby -e 'print $1 if STDIN.gets =~ /^password: "(.*)"$/'
        }
        
        USER=username
        ADDR=vpn.company.com
        PASSWORD=$(get_pw)
        
        /usr/bin/expect -f - <<EOD
        set timeout 10
        
        spawn /opt/cisco/anyconnect/bin/vpn connect $ADDR
        expect "\r\nUsername:*" {send -- "$USER\r"}
        expect "Password: " {send -- "$PASSWORD\r"}
        expect "Connected"
        EOD
        
        

        【讨论】:

          猜你喜欢
          • 2017-07-31
          • 2014-04-03
          • 2017-11-17
          • 2012-07-06
          • 1970-01-01
          • 2013-08-16
          • 2020-11-07
          • 1970-01-01
          • 2016-02-08
          相关资源
          最近更新 更多