通过bash连接CISCO Anyconnect VPN

时间:2014-06-13 16:29:41

标签: bash vpn cisco

正如标题所说,试图通过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将启动,但不会输入任何命令(即connect vpn,username,password)。从我读到的-s选项将允许传递用户名/密码。 救命啊!

5 个答案:

答案 0 :(得分:11)

我不得不下载expect软件包(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

答案 1 :(得分:9)

虽然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进行了测试。

答案 2 :(得分:0)

c#solution ...在这种情况下,配置文件是组名。

//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! ...");

答案 3 :(得分:0)

基于Brayden Hancock的答案,我构建了一个从macOS钥匙串读取密码的解决方案。 第一步,我通过Keychain Access应用程序添加了一个新的密码项目,其中account字段设置为mycompany-vpn。脚本的第一部分从钥匙串中读取该项目,并使用ruby片段提取密码,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

答案 4 :(得分:0)

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

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

  1. foobar对保存在名称为fookey的钥匙串中(不是iCloud登录)
  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进入非交互模式。
  • << EOM ... EOM称为here-docs,它使用字符串替换文件。通过将每个响应写为新行来编写交互式CLI的脚本非常有用。
  • security是一个很好的工具,可从命令行访问您的钥匙串。