2023-07-21 服务器外网连接技巧

2023-08-12  本文已影响0人  麦冬花儿

首先要有公网的服务器
ssh -f -N -R 52813:lcoalhost:22 train@chenlianfu.com

[train@MiWiFi-R3P-srv ~]$ cat sshToAliyun.pl 
#!/usr/bin/perl
use strict;
use Getopt::Long;

my $usage = <<USAGE;
Usage:
    $0 [options]

    本程序用于创建一个到Aliyun服务器(chenlianfu.com)的反向隧道。必须使用普通用户运行本程序,即可持续维持该隧道。本程序可以随意多次运行,对前面运行的程序没有影响,对隧道的稳定连接没有影响。
    特别注意:为了保护Aliyun服务器服务器的安全,一定要使用自己的用户,且该用户名一定要是自己姓名的全拼,和文件www.chenlianfu.com/public/information/Ports_for_sshToAliyun.txt中的用户名一致。否则,即使成功运行该程序后,陈连福也会不定期查看ssh授权文件并根据用户姓名进行清理,或定期自动清理名单中不存在的用户,导致使用Aliyun服务器进行的端口影射失效。所以,欲使用本程序,一定要联系陈连福报备端口信息。

    程序运行原理:(1)首先,生成一对ssh密钥,然后将公钥写入到aliyun服务器,第一次运行本程序时,该过程可能需要输入密码。(2)生成一个创建反向隧道的perl程序。该perl程序先检测能否通过Aliyun服务器的指定端口连接到服务器自身。检测方法是通过ssh命令使用Aliyun的指定端口登录到本服务器的当前用户。由于一般服务器禁止root用户远程登录,所以当前使用本程序的用户不能是root,否则该检测会失败。若检测不能通过aliyun服务器连接到服务器自身,则重新创建反向隧道。(3)使用crontab例行程序方法每隔一段时间(半个小时)就会自动运行该perl程序,从而保持反向隧道的连接。

    --user_name <string>    default: train
    设置使用的Aliyun服务器上的用户。

    --sshToAliyun <string>    default: \$HOME/.sshToAliyun
    程序生成一个perl程序文件,用于构建到Aliyun服务器的反向隧道。设置该文件的路径和名称。

    --port_aliyun <int>    default: None
    设置反向隧道所使用的端口号。该端口时映射到Aliyun服务器,在Aliyun服务器上占用的端口。该端口号理论上是可以随便填写的,推荐使用52000-53000区段的端口,这些端口已经在Aliyun服务器(chenlianfu.com)上开放了。使用这些端口,则可以输入一个ssh命令直接登陆内网服务器。若填写其它端口号,则需要先登录到aliyun服务器,然后再从aliyun服务器登录到内网服务器,需要输入两次ssh命令。为了防止和他人发生端口冲突,请联系陈连福报备端口号。陈连福会将各位老师的用户名和端口号信息填写在网址文件www.chenlianfu.com/public/information/Ports_for_sshToAliyun.txt中。

    --port_intranet <int>    default: 22
    设置内网服务器的ssh登录所使用的端口。

    --aliyun_noPasswd_To_intranet    default: None
    设置该参数,则会将Aliyun的公钥上传到内网服务器,可以从Aliyun服务器直接无密码登录内网服务器。为了内网服务器的安全,不推荐使用该参数。

    --help
    打印帮助信息。

USAGE

my ($user_name, $sshToAliyun, $help, $port_aliyun, $port_intranet, $aliyun_noPasswd_To_intranet);
GetOptions (
    "user_name:s" => \$user_name,
    "sshToAliyun:s" => \$sshToAliyun,
    "help!" => \$help,
    "port_aliyun:i" => \$port_aliyun,
    "port_intranet:i" => \$port_intranet,
    "aliyun_noPasswd_To_intranet!" => \$aliyun_noPasswd_To_intranet,
);
if ($help){die $usage}
unless ($port_aliyun) {die "\nThe parameter --port_aliyun was required!\n\n$usage";}

my $home = `echo \$HOME`;
my $whoami = `whoami`;
chomp($home);
chomp($whoami);
$sshToAliyun ||= "$home/.sshToAliyun";
$user_name ||= "train";
$port_intranet ||= 22;

# 创建一对rsa密钥,并和Aliyun服务器交换密钥
my $cmdString;
unless (-e "$home/.ssh/id_rsa") {
    $cmdString = 'ssh-keygen -t rsa -P "" -f ~/.ssh/id_rsa';
    print STDERR "CMD: $cmdString\n";
    system($cmdString);
    $cmdString = 'cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys; chmod 600 ~/.ssh/authorized_keys';
    print STDERR "CMD: $cmdString\n";
    system($cmdString);
}

$cmdString = "ssh -o PreferredAuthentications=publickey -o StrictHostKeyChecking=no -o ConnectTimeout=10 $user_name\@chenlianfu.com cd";
print STDERR "CMD: $cmdString\n";

if ( system($cmdString) == 0 ) {
    print STDERR "The intranet server can connect to Aliyun server without password.\n";
}
else {
    $cmdString = "ssh-copy-id -i ~/.ssh/id_rsa.pub $user_name\@chenlianfu.com";
    print STDERR "CMD: $cmdString\n";
    system($cmdString);

    if ($aliyun_noPasswd_To_intranet) {
        $cmdString = "ssh -o PreferredAuthentications=publickey -o StrictHostKeyChecking=no -o ConnectTimeout=10 $user_name\@chenlianfu.com 'cat ~/.ssh/id_rsa.pub' >> ~/.ssh/authorized_keys";
        print STDERR "CMD: $cmdString\n";
        system($cmdString);
    }

    $cmdString = "ssh -o PreferredAuthentications=publickey -o StrictHostKeyChecking=no -o ConnectTimeout=10 $user_name\@chenlianfu.com cd";
    print STDERR "CMD: $cmdString\n";

    if ( system($cmdString) == 0 ) {
        print STDERR "The intranet server can connect to Aliyun server without password.\n";
    }
    else {
        die "Error: The intranet server can not connect to Aliyun server without password!\n";
    }
}

# 生成创建反向隧道的perl程序
open OUT, ">", $sshToAliyun or die "Can not create file $sshToAliyun, $!";
my $out ='#!/usr/bin/perl
use strict;

unlink "/tmp/sshOKOKOKssh" if -e "/tmp/sshOKOKOKssh";
my $cmdString = \'ssh -o PreferredAuthentications=publickey -o StrictHostKeyChecking=no -o ConnectTimeout=10 -p ' . "$port_aliyun $whoami" . '@chenlianfu.com "touch /tmp/sshOKOKOKssh"\';
#print STDERR "CMD: $cmdString\n";
system($cmdString);

if (-e "/tmp/sshOKOKOKssh") {
    unlink "/tmp/sshOKOKOKssh";
    #print STDERR "反向隧道正常联通中...\n";
}
else {
    #print STDERR "反向隧道不能联通...\n";
    $cmdString = \'/usr/bin/ps -aux | grep -P "ssh.*-f -N -R ' . $port_aliyun . ':"\';
    #print STDERR "CMD: $cmdString\n";
    my $ssh_out = `$cmdString`;
    foreach (split /\n/, $ssh_out) {
        @_ = split /\s+/;
        $cmdString = "kill -s 9 $_[1]";
        #print STDERR "CMD: $cmdString\n";
        system($cmdString);
    }
    $cmdString = \'ssh -o PreferredAuthentications=publickey -o StrictHostKeyChecking=no -o ConnectTimeout=10 -f -N -R ' . $port_aliyun . ':localhost:' . "$port_intranet $user_name" . '@chenlianfu.com\';
    #print STDERR "CMD: $cmdString\n";
    if ( system($cmdString) == 0 ) {
        #print STDERR "反向隧道重建成功...\n";
    }
    else {
        die "反向隧道重建失败...请检测内网服务器是否联网,再检测Aliyun服务器是否联网...\n";
    }
}';
print OUT "$out\n";
close OUT;
print STDERR "The perl script $sshToAliyun was created.\n";

$cmdString = "chmod 755 $sshToAliyun";
print STDERR "CMD: $cmdString\n";
system($cmdString);
$cmdString = $sshToAliyun;
print STDERR "CMD: $cmdString\n";
system($cmdString);

open OUT, ">", "$home/.crontab" or die "Can not create file $home/.crontab\n";
$cmdString = 'crontab -l';
my $cron = `$cmdString`;
my %cron;
foreach (split /\n/, $cron) {
    $cron{$_} = 1 if $_;
}
$cron{"1\t*\t*\t*\t*\t$sshToAliyun"} = 1;
$cron{"31\t*\t*\t*\t*\t$sshToAliyun"} = 1;
foreach (sort keys %cron) {
    print OUT "$_\n";
}
close OUT;
$cmdString = "crontab $home/.crontab";
print STDERR "CMD: $cmdString\n";
system($cmdString);
上一篇下一篇

猜你喜欢

热点阅读