自用ssh命令总结

最近工作有涉及ssh相关,学习中会不断更新修改

通过cgywin,xshell,linux,堡垒机等连接ssh ,具体方法之后会补充 

  1. SSH可以连接到远程主机; 

  2. SCP后面是 /开头是本地地址, xx@xxxx: 用户名@ip地址+ / remote地址 ; 

  3. ssh -i +(直接拖动来的证书文件)+ ip ( 物理ip还是虚拟ip?)
    例如 ssh -i xxx.xxx.xxx.xxx:./ ; 

  4. 本地拷贝到远程设备:scp -i +(直接拖动来的证书)+ (带地址的本地文件,直接拖动来)
    +要移动的ip:路径(绝对路径或者相对路径)

    例如 scp -i xx/xx/id_rsa.rsa ../xx/test.lua xxx.xxx.xxx.xxx:./:./ ; 

  5. 远程主机下载到本机,将远程ip的文件和本机文件调换位置即可; 

  6. ssh连接远程主机后,可以用logcat监控当前安卓设备的操作,例如点击进入某个app,通过logcat看包名; 

  7. ssh后, getevent -l 可以查看当前鼠标在安卓设备上点击的位置(注意坐标点,和16进制需要转换);

  8. 可以在安卓手机的设置里面查看ip地址 

  9. ls:当前路径下的文件, pwd:当前目录所在路径, cat:查看文件, cgywin修改文件需要下载vim模块,
    ifconfig: 注意是if而不是ip,查看ip等信息 ,有时候scp和安装需要调整权限

  10. 可以通过ssh查看当前设备的ip等信息: 例如 /data/lxc/bin/lxc-info -n 0 

  11. 有时候ssh连接需要将证书放到cgywin的bin目录下跑一次

Mac使用ssh公钥登录Linux

ssh登录Linux通常有两种方法:用户名密码登录、用户名公钥登录;使用用户名密码登录每次都要输入密码,相当麻烦,而使用用户名公钥登录则可以避免这个问题。

创建公钥私钥文件
打开本地终端,执行 ssh-keygen 命令创建密钥对:

ssh-keygen -t rsa -C  'your [email protected]'

-t 指定密钥类型,默认即 rsa ,可以省略
-C 设置注释文字,比如你的邮箱,可以省略

生成过程中会提示输入密码两次,如果不想在使用公钥的时候输入密码,可以回车跳过;
密钥默认保存位置在 ~/.ssh 目录下,打开后会看到私钥文件 id_rsa 和公钥文件 id_rsa.pub;

未分类

复制公钥至服务器
使用 scp 命令将本地的公钥文件 id_rsa.pub 复制到需要连接的Linux服务器:

scp ~/.ssh/id_rsa.pub <用户名>@<ip地址>:/home/id_rsa.pub

如果修改了ssh默认连接端口的话,需要加上端口信息:

scp -P <端口号> ~/.ssh/id_rsa.pub <用户名>@<ip地址>:/home/id_rsa.pub

把公钥追加到服务器ssh认证文件中:

cat /home/id_rsa.pub >> ~/.ssh/authorized_keys

未分类

这时候在本地终端中使用用户名和ip登录就不需要密码了:

ssh <用户名>@<ip>

未分类

如果修改了ssh默认连接端口的话,需要加上端口信息:

ssh -p <端口号> <用户名>@<ip地址>

未分类

配置快捷登录
即使不用输入密码,这样每次登录还要输入用户名ip端口信息还是有点麻烦,我们可以配置ssh快捷登录更方便的登录Linux;
在本地 ~/.ssh/config 配置文件中添加ssh服务器信息,格式:

Host            alias            #自定义别名
HostName        hostname         #替换为你的ssh服务器ip或domain
Port            port             #ssh服务器端口,默认为22
User            user             #ssh服务器用户名
IdentityFile    ~/.ssh/id_rsa    #第一个步骤生成的公钥文件对应的私钥文件

未分类

这时候就可以使用配置文件中自定义的别名来登录了:

未分类

让一个端口同时做两件事:http/https和ssh

相信很多人都在YY:能不能让80端口分析连接协议,如果是http协议就让服务器交给http服务程序(如Apache、Nginx等)处理,如果是ssh协议就交给ssh服务程序(如OpenSSH Server)处理呢?

答案显然是有的。

首先,配置http服务程序监听8080端口或者让https服务监听8443端口,配置ssh服务程序监听22端口。具体不再赘述,如果这都不懂就不用往下看了,因为肯定会搞不定的。

然后,安装一个叫haproxy的强大工具。步骤如下。

下载源代码:

wget http://haproxy.1wt.eu/download/1.4/src/haproxy-1.4.16.tar.gz

查看当前内核版本:

uname -r

然后进入目录编译安装:

cd haproxy-1.4.16
make TARGET=linux26 PREFIX=/usr/local/blog.creke.net/haproxy
make install PREFIX=/usr/local/blog.creke.net/haproxy

其中,第二行的“TARGET”参数要和内核版本一致。第二、三行的“PREFIX”是安装位置。

最后,配置haproxy。

如果要监听80端口,检测到http协议就转发给8080端口使用HTTP,否则转发给22端口使用ssh。配置如下:

#By http://blog.creke.net/
global 
    maxconn 5120  
    chroot /usr/local/blog.creke.net/haproxy   
    daemon 
    quiet 
    nbproc 2 
    pidfile /usr/local/blog.creke.net/haproxy/haproxy.pid
defaults 
    timeout connect 5s 
    timeout client 50s 
    timeout server 20s
listen http 
    bind :80 
    timeout client 1h 
    tcp-request inspect-delay 2s 
    acl is_http req_proto_http 
    tcp-request content accept if is_http 
    server server-http :8080 
    use_backend ssh if !is_http
backend ssh 
    mode tcp 
    timeout server 1h 
    server server-ssh :22

如果还有监听443端口,检测到https协议就转发到8443端口使用HTTPS,否则转发给22端口使用ssh。则配置如下:

global 
    maxconn 5120  
    chroot /usr/local/blog.creke.net/haproxy   
    daemon 
    quiet 
    nbproc 2 
    pidfile /usr/local/blog.creke.net/haproxy/haproxy.pid
defaults 
    timeout connect 5s 
    timeout client 50s 
    timeout server 20s
listen https 
    bind :443 
    timeout client 1h 
    tcp-request inspect-delay 2s 
    acl is_ssl req_ssl_ver 2:3.1 
    tcp-request content accept if is_ssl 
    server server-https :8443 
    use_backend ssh if !is_ssl
backend ssh 
    mode tcp 
    timeout server 1h 
    server server-ssh :22

把内容保存为“/usr/local/blog.creke.net/haproxy/etc/haproxy.conf”,执行命令:

/usr/local/blog.creke.net/haproxy/sbin/haproxy -f /usr/local/blog.creke.net/haproxy/etc/haproxy.conf

即可运行。

好了,大家应该可以举一反三,起码也可以依葫芦画瓢吧。

centos 7下SSH的一些安全配置

0、说明

0.1、实验环境系统为Centos 7.4系统,最小化安装后未做任何配置

1、修改SSH默认连接端口

1.1、确保SELinux处于关闭状态

[root@imzcy ~]# setenforce 0
[root@imzcy ~]# sed -i 's/SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config

1.2、编辑sshd_config配置文件,修改默认端口(17行左右)。并重启sshd服务使配置生效

[root@imzcy ~]# grep ^Port /etc/ssh/sshd_config 
Port 10022
[root@imzcy ~]# systemctl restart sshd

1.3、firewalld防火墙添加规则,放行tcp/10022端口

#添加防火墙规则
[root@imzcy ~]# firewall-cmd --permanent --zone=public --add-port=10022/tcp
[root@imzcy ~]# firewall-cmd --reload

#确认配置
[root@imzcy ~]# firewall-cmd --list-all |grep 10022
  ports: 10022/tcp

这时候就可以使用10022端口连接ssh服务器了。
可能遇到的问题:

如果修改完ssh端口号,重启sshd服务报错,然后注释掉之前的更改就能正常重启,请使用getenforce命令检查下selinux状态是否为关闭

2、禁止root用户远程登录

#2.1、修改sshd_config配置文件(38行左右)
[root@imzcy ~]# grep ^PermitRootLogin /etc/ssh/sshd_config 
PermitRootLogin no
[root@imzcy ~]# 

#2.2、重启sshd服务,使配置立即生效
[root@imzcy ~]# systemctl restart sshd

3、限制ssh访问服务器的源IP

#编辑hosts.allow配置文件,追加一行内容
[root@imzcy ~]# echo "sshd:192.168.43.226:allow" >>/etc/hosts.allow

#编辑hosts.deny配置文件,追加一行内容
[root@imzcy ~]# echo "sshd:ALL" >>/etc/hosts.deny

这里只写了一种方法,还可以通过修改sshd_config配置文件来限制源IP,也可以使用firewalld来限制源IP

4、限制ssh访问服务器的用户名

#修改sshd_config配置文件,允许zcy用户ssh访问服务器(以空格分开用户;添加完允许,默认拒绝其他所有用户)
[root@imzcy ~]# echo "AllowUsers zcy" >>/etc/ssh/sshd_config

#重启sshd服务,使配置立即生效
[root@imzcy ~]# systemctl restart sshd

5、修改telnet ssh端口时显示的版本号

#5.1、查看sshd位置
[root@imzcy ~]# whereis sshd
sshd: /usr/sbin/sshd /usr/share/man/man8/sshd.8.gz

#5.2、查看SSH版本
[root@imzcy ~]# ssh -V
OpenSSH_7.4p1, OpenSSL 1.0.2k-fips  26 Jan 2017

#5.3、查看sshd程序关于版本的信息
[root@imzcy ~]# strings /usr/sbin/sshd |grep OpenSSH_7.4
OpenSSH_7.4p1-RHEL7-7.4p1-11
OpenSSH_7.4
OpenSSH_7.4p1

#5.4、使用sed替换版本(记得一定要先备份下)
[root@imzcy ~]# cp -p /usr/sbin/sshd ./
[root@imzcy ~]# sed -i 's/OpenSSH_7.4/OpenSSH_2.3/g' /usr/sbin/sshd

#5.5、重启下sshd服务,没有报错即可
[root@imzcy ~]# systemctl restart sshd

再使用telnet连接ssh端口,显示的版本则为:SSH-2.0-OpenSSH_2.3

记一次SSH配置相关问题

今天新租了一VPS,在解决了IP被屏蔽等问题后,着手解决使用XShell连接SSH时存在的问题。如图:

未分类

同时连接速度也肉眼可见地慢。。。慢。。慢。

于是百度、Google 说是安装不完全,于是就安装

yum -y install xorg-x11-xauth

但是仍然有问题,报出这样的问题

/usr/bin/xauth: file /root/.Xauthority does not exist

最终把ssh配置的AllowAgentForwarding也改为yes就OK了(去掉注释)
前提是X11Forwarding yes这一条配置也要yes,不过默认应该都是的
我ssh的配置文件路径/etc/ssh/sshd_config
至此问题就完美解决了。

git-bash设置ssh心跳包防超时断开

Windows中使用git-bash作为日常终端工具,在使用ssh命令连接到服务器后,如果较长时间没进行交互时,ssh会断开,导致的现象就是终端卡住,你只能等待它退出,或直接关闭窗口重建连接,很麻烦。

使用ssh命令时,可以增加ServerAliveInterval参数设置心跳时间,比如设置60秒发送一次心跳包

ssh -o ServerAliveInterval=60 [email protected]

想一劳永逸,可以在ssh-config中配置全局参数
在git安装目录下的etc/ssh/ssh_config文件中,增加一行

ServerAliveInterval 60

现在再使用ssh时,就可以一直保存ssh连接在线了。

配置多个ssh密钥对并且永久多ssh管理

这两天捣腾SSH,一直对其使用一知半解,由于要把博客迁移,弄来弄去发现还是部署到国内的coding吧
之前也弄过,但是由于重新安装了git-for-windows客户端,所以一开始用hexo d命令部署的时候报错了
趁着这次迁移也好好弄了一下本地的ssh管理,虽然还有些问题,但是至少比之前清晰一些了,这里也记录一下过程中遇到的问题

我的目的,将hexo生成的静态文件同时部署到github与coding上

安装git-for-windows客户端

下载地址 https://git-scm.com/download/win
无论是github还是coding都需要上传你的公钥,这两个地方可以上传相同的公钥,但也可以像我这样闲的蛋疼上传不同的公钥。

创建密钥对

使用ssh-keygen 来创建密钥对,命令为 ssh-keygen -t rsa -C “[email protected]”,其实这里-C 后面的email地址无所谓,可以随便写,只是为了你方便而已。
输入完该命令以后,首先会让你给密钥文件起个名字,这个是文件名,叫什么随心情

未分类

接下来让你输入密码,我这里直接回车,不用密码
然后它就会生成一个密钥对,像我这个设置就会生成yyxtest和yyxtest_pub两个文件,yyxtest.pub是公钥,谁都可以给,但是你私钥要自已保存好,谁拿到了你私钥就呵呵了。

上传公钥到github与coding中

根据github上的提示将公钥上传到github上你的个人账户中的ssh中

未分类

同样的操作再生成一对密钥,将公钥上传到coding中,注意我这里是为了测试,你完全没有必要重新生成,你当然可以上传刚才生成的yyxtest.pub这个公钥,当然后面会有一些问题,之后再详细说明。

上传文件到github上

赶紧上传个文件到github上试试吧(使用hexo d 来部署),其实你可以先不用上传文件,可以用ssh -vT [email protected] 来查看一下信息
这里你不用试了,肯定是不行的…… 抗都被我踩了

未分类

提示Permission denied,原因是你现在用的私钥还是id_rsa,并不是刚才生成的yyxtest,
ssh默认使用id_rsa,如果连id_rsa都没有,那你还不赶紧生成一个默认的。

添加yyxtest私钥到git bash中

根据github上的提示generate SSH keys 先将yyxtest添加到git bash中,
使用ssh-add ~/.ssh/yyxtest ,然后顺利提交代码成功,但是在提交文件到coding时又不行了,提示

Error: [email protected]: Permission denied (publickey).
fatal: Could not read from remote repository.

没办法,再用刚才的ssh-add 命令将用于coding的私钥也添加到git bash中,这次coding也可以提交了

配置ssh本地的config文件

试试关掉这个git bash,然后再试着用hexo d 提交一些文件,这次又不行了,还是提示Permission denied,这怎么能行,总不能每次提交更新都输入ssh-add 添加各种私钥吧,这时就要用到config这个文件了。
如果git安装是默认的话,将会把生成的公钥保存在C:Usersusername.ssh目录中(我用的是windows,不丢人),里面如果没有config文件,自已生成一个,里面写一些配置信息,各种字段说明如下

Host:代码托管平台的别名,但是这个别名和后面要用到的ssh链接 [email protected]:xxx/xxx.git 中的 @ 符号后面的内容要一致,而一般来说github默认提供的就是[email protected],因此为了方便,github的Host写github.com即可,别取别名了
HostName:代码托管平台真正的IP地址或域名,写域名就行,
IdentityFile:对应的密钥文件路径。必须写绝对路径,windows下可以写 C:Usersxxx.sshyyxtest
PreferredAuthentications:配置登录时用什么权限认证。可设为publickey,password publickey,keyboard-interactive等
User:对应的用户名。

我这里有两个私钥,所以我的配置文件如下

Host git.coding.net
    HostName git.coding.net
    IdentityFile C:Userskevin.sshrsa_coding
    PreferredAuthentications publickey
    User yangyanxing
Host github.com
    HostName github.com
    IdentityFile C:Userskevin.sshyyx
    PreferredAuthentications publickey
    User kevinkelin

之前说过,你没有必要为不同的网站生成不同的密钥,用同一份也可以,如果用同一份,这里IdentityFile也要写一样的
保存之后先不用着急提交,使用ssh -vT 查看一下连接是否有问题
github 提示 Hi kevinkelin! You’ve successfully authenticated, but GitHub does not provide shell access.
coding提示 yangyanxing,你好,你已经通过 SSH 协议认证 Coding.net 服务,这是一个个人公钥
这样就可以直接使用hexo d来提交文件更新了!

注意的问题

  • config文件中的host 配置是区分大小写的,github.com 和github.COM是不同的,一定要写对
  • coding的host是git.coding.net 而不是coding.net

遗留问题

git bash客户端,如果在非C盘上右键的方式启动,那么还是不行,它会寻找当前盘的中的.ssh目录,根本不存在的目录,所有找私钥肯定也找不到,只能先启动git bash,然后cd 到操作的目录中,这个我再研究研究怎么回事。

Ubuntu 16.04 LTS ssh安装和配置

第一步:获取root权限

sudo -i

根据提示输入密码

第二步:更新源列表

sudo apt-get update

第三步:安装ssh

sudo apt-get install openssh-server

第四步:配置ssh

gedit /etc/ssh/ssh_config

注释掉 PermitRootLogin without-password
加入 PermitRootLogin yes

第五步:启动ssh服务

service ssh start

温馨提示:ssh默认端口号为22

CentOS监控ssh免密登录

ssh免密登录在带来方便的同时也带来一些问题,那就是不知道什么时间什么人利用ssh免密通道登录服务器了,为此我们需要在sshd的配置文件里设置好详细日志,以便日后回溯。

在CentOS里,sshd的日志文件是保存在/var/log/secure里的,如果不进行特殊设置的话,它只记录一些最简单的信息,比如什么时间哪个账号被人用免密登录的方式登录了,如果这个账号的authorized_keys里有很多key的话,这样的log没有办法告诉你客户到底是用哪个key登录的。

所以,我们需要在sshd的配置文件/etc/ssh/sshd_config文件里找到以下项LogLevel并把它改成LogLevel VERBOSE,这一项的缺省值是INFO,不够详细,所以我们需要把它改成啰嗦模式,这样可以记录更多信息。

改成VERBOSE并重启sshd(service sshd restart)后,我们会在日志文件里看到类似于这样的记录:

Apr 1 10:37:06 hostname sshd[5903]: Found matching RSA key: 83:67:b5:c7:bb:17:4d:06:ca:dc:8b:ca:85:cc:0c:b1

但这样的信息明显不同于我们在authorized_keys里存放的信息,那该怎么办呢?实际上,在sshd的日志文件里存储的只是我们authorized_keys的指纹信息fingerprint,不是真正的key,必须从authorized_keys反算出fingerprint来,才能做对比:

ssh-keygen -E md5 -lf /home/someuser/.ssh/authorized_keys

但是这样依然很麻烦,有没有办法直接告诉我日志里到底是谁登录的呢?为此我们还需要引入一个用Perl写的小程序点击预览。(原作者写的略有问题,在新版的CentOS里必须要求附加md5参数,为此我做了一些小的修改):

#!/usr/bin/perl -w
use strict;
use diagnostics;
use File::Temp;

# Matches Fingerprints from sshd logs (sshd on loglevel VERBOSE) against
# authorized_keys for the respective user.

die "Please specify input file!n" unless ($ARGV[0]);

my $fingerprints;

my $nav = File::Navigate->new($ARGV[0]);
# Store publickey login events
my @lines = @{$nav->find(qr/sshd[d+]: Accepted publickey for .+ from .+ port d+/)};

# Process all publickey login events
foreach(@lines){
    $nav->cursor($_);
    my $line = $nav->get();
    $line =~ /^(.{15}).+sshd[(d+)]: Accepted publickey for (.+) from (.+) port (d+)/;
    my $date = $1;
    my $pid  = $2;
    my $user = $3;
    my $ip   = $4;
    my $port = $5;
    my $fp   = "unknown"; # (yet)
    # Seek backwards to find matching fingerprint line
    my $sought = 0;
    while ((my $seekline = $nav->getprev()) and ($sought++ < 1000)){
        if ($seekline =~ /sshd[$pid]: Found matching .+ key: (.+)/){
            $fp = $1;
            last;
        }elsif($line =~ /sshd[$pid]: Connection from $ip port $port/){
            last;
        }
    }
    my $key = get_key($fp, $user);
    print ""$date";"$user";"$fp";"$key"n";
}

sub get_key{
    my $fp   = shift;
    $fp = "MD5:" . $fp;
    my $user = shift;

    # See if FP is cached
    if ($fingerprints->{$user}){
        if ($fingerprints->{$user}->{$fp}){
            return $fingerprints->{$user}->{$fp};
        }else{
            return "No matching key found.";
        }
    }

    # Else, generate fingerprints from users authorized_keys
    print STDERR "------> Reading keys for user $usern";
    my $home = (getpwnam($user))[7];
    open my $fh_in, "<$home/.ssh/authorized_keys" or warn "No such file: $home/.ssh/authorized_keysn";
    while (<$fh_in>){
        chomp;
        next unless (/^ssh-/);
        my $out_fh = File::Temp->new();
        print $out_fh "$_n";
        close $out_fh;
        my $fp_raw = `ssh-keygen -E md5 -lf $out_fh`;
        # Second field of output has the fingerpring
        my $fp = (split /s+/, $fp_raw)[1];
        $fingerprints->{$user}->{$fp} = $_;
    }
    if ($fingerprints->{$user}->{$fp}){
        return $fingerprints->{$user}->{$fp};
    }else{
        return "No matching key found.";
    }
}

package File::Navigate;
use strict;
use warnings;

=head1 NAME

File::Navigate - Navigate freely inside a text file

=head1 DESCRIPTION

The module is a glorified wrapper for tell() and seek().

It aims to simplify the creation of logfile analysis tools by
providing a facility to jump around freely inside the contents
of large files without creating the need to slurp excessive
amounts of data.

=head1 SYNOPSIS

  use File::Navigate;
  my $nav = File::Navigate->new('/var/log/messages');

  # Read what's below the "cursor":
  my $first = $nav->get;

  # Advance the cursor before reading:
  my $second = $nav->getnext;
  my $third  = $nav->getnext;

  # Advance the cursor by hand:
  $nav->next;
  my $fourth = $nav->get;

  # Position the cursor onto an arbitrary line:
  $nav->cursor(10);
  my $tenth  = $nav->get;

  # Reverse the cursor one line backward:
  $nav->prev;
  my $ninth  = $nav->get;

  # Reverse the cursor before reading:
  my $eigth  = $nav->getprev;

  # Read an arbitrary line:
  my $sixth  = $nav->get(6);

=cut

our @ISA       = qw(Exporter);
our @EXPORT_OK = qw();
our $VERSION   = '1.0';

=head1 CLASS METHODS

=head2 I<new()>

Open the file and create an index of the lines inside of it.

  my $mapper = File::Navigate->new($filename);

=cut

sub new($){
    my $class = shift;
    my $file;
    unless ($file = shift){
        die "No file specifiedn";
    }
    unless (-e $file){
        die "File not found: $filen";
    }
    unless (-r $file){
        die "File not readable: $filen";
    }
    my $self = {};
       $self->{'cursor'}         = 1;
       $self->{'lineindex'}      = {};
       $self->{'lineindex'}->{1} = 0;
    open my $fh, "$file"
        or die "Can't open $file: $!n";
    while (<$fh>){
        my $thisline = $.;
        my $nextline = $thisline + 1;
        $self->{'lineindex'}->{$nextline} = tell $fh;
    }
    $self->{'length'} = scalar(keys %{$self->{'lineindex'}}) - 1 ;
    $self->{'fh'} = $fh;
    bless $self;
}

=head1 OBJECT METHODS

=head2 I<count()>

Returns the number of lines in the file ("wc -l")

  my $lines = $nav->count;

=cut

sub length(){
    my $self = shift;
    return $self->{'length'};
}

=head2 I<cursor()>

Returns the current cursor position and/or sets the cursor.

  my $cursor = $nav->cursor();   # Query cursor position.
  my $cursor = $nav->cursor(10); # Set cursor to line 10

=cut

sub cursor($){
    my $self = shift;
    if (my $goto = shift){
        $self->{'cursor'} = $goto;
    }
    return $self->{'cursor'};
}

=head2 I<get()>

Gets the line at the cursor position or at the given position.

  my $line = $nav->get();   # Get line at cursor
  my $line = $nav->get(10); # Get line 10

=cut

sub get($){
    my $self = shift;
    my $fh   = $self->{'fh'};

    my $getline;
    $getline = $self->{'cursor'} unless ($getline = shift);

    if ($getline < 1){
        warn "WARNING: Seek before first line.";
        return undef;
    }elsif($getline > $self->{'length'}){
        warn "WARNING: Seek beyond last line.";
        return undef;
    }
    seek ($fh, $self->{'lineindex'}->{$getline}, 0);
    my $gotline = <$fh>;
    chomp $gotline;
    return $gotline;
}

=head2 I<next()>

Advance the cursor position by one line. Returns the new cursor position.
Returns I<undef> if the cursor is already on the last line.

  my $newcursor = $nav->next();

=cut

sub next(){
    my $self = shift;
    if ($self->{'cursor'} == $self->{'length'}){
        return undef;
    }
    $self->{'cursor'}++;
    return $self->{'cursor'};
}

=head2 I<prev()>

Reverse the cursor position by one line. Returns the new cursor position.
Returns I<undef> if the cursor is already on line 1.

  my $newcursor = $nav->prev();

=cut

sub prev(){
    my $self = shift;
    if ($self->{'cursor'} == 1){
        return undef;
    }
    $self->{'cursor'}--;
    return $self->{'cursor'};
}

=head2 I<getnext()>

Advance to the next line and return it.
Returns I<undef> if the cursor is already on the last line.

  my $newcursor = $nav->getnext();

=cut

sub getnext(){
    my $self = shift;
    $self->next or return undef;
    return $self->get;
}

=head2 I<getprev()>

Reverse to the previous line and return it:
Returns I<undef> if the cursor is already on line 1.

  my $newcursor = $nav->getprev();

=cut

sub getprev(){
    my $self = shift;
    $self->prev or return undef;
    return $self->get;
}

=head2 I<find()>

Find lines containing given regex. Returns array with line numbers.

  my @lines = @{$nav->find(qr/foo/)};

=cut

sub find($){
    my $self = shift;
    my $regex = shift;

    my @results;
    for (my $lineno = 1; $lineno <= $self->{'length'}; $lineno++){
        my $line = $self->get($lineno);
            if ($line =~ $regex){
            push @results, $lineno;
        }
    }
    return @results;
}

sub DESTROY(){
    my $self = shift;
    close $self->{'fh'};
}

=head1 EXAMPLE

I<tac>, the opposite of I<cat>, in Perl using File::Navigate:

  #!/usr/bin/perl -w
  use strict;
  use File::Navigate;

  foreach my $file (reverse(@ARGV)){
          my $nav = File::Navigate->new($file);
          # Force cursor beyond last line
          $nav->cursor($nav->length()+1);
          print $nav->get()."n" while $nav->prev();
  }

=head1 BUGS

Seems to lack proper error handling.

=head1 LIMITATIONS

Works only on plain text files. Sockets, STDIO etc. are not supported.

=head1 PREREQUISITES

Tested on Perl 5.6.1.

=head1 STATUS

Mostly harmless.

=head1 AUTHOR

Martin Schmitt <mas at scsy dot de>

=cut

1;

为此我们给它起名叫match-ssh-keys,赋予它可执行权限(chmod +x match-ssh-keys),然后把它搬到/usr/local/bin里(mv match-ssh-keys /usr/local/bin/),这样我们以后再想查谁通过sshd免密登录过服务器就方便了,我们只需要执行:

match-ssh-keys /var/log/secure

就可以了。

解决内网ssh连接速度很慢的解决方案

服务器相互ping是延时小,但ssh -p 端口号 内网IP 时发现很慢,好长时间才返回。把服务器改按以下方法修改相应配置,再ssh相互连接发现很快:

# vi /etc/ssh/sshd_conf
UseDNS no

GSSAPIAuthentication no

保存退出

#service sshd restart