Ssh

使用 nohup(Ubuntu/Debian 64 位)從控制台分離時,netcat 無法按預期工作

  • February 26, 2014

我試圖讓 netcat 執行並關閉 ssh 會話(甚至停止 ssh 守護程序)。但它會在所有數據寫入之前退出。我正在非 ssh(本地)控制台中進行測試:

nohup nc -l -p 4000  | dd of=/home/myname/test.txt 2>/run/user/myname/stderr  1>/run/user/myname/stdout &

為了測試它,我關閉了控制台並在另一個控制台中轉儲了一個文件:

dd if=/var/log/Xorg.0.log  |  nc localhost 4000

/home/myname/test.txt 中沒有寫入任何內容。但是如果我刪除 nohup 命令,test.txt 會包含所有轉儲的數據。如何讓 netcat 工作並與控制台分離?

好的,我把它挖出來了:nohup使用從 /dev/null重定向的標準輸入執行程序。所以 dd 命令不會從 nc 得到任何東西,並且 nc 可能會在第一次嘗試寫入時無法寫入並關閉自身。所以首先我們需要創建一個命名管道來通過以下方式路由 I/O:

mkfifo my.pipe

然後使用管道中的輸入文件執行 dd:

nohup dd if=./my.pipe of=./test.txt 2>/run/user/myname/stderr  1>/run/user/myname/stdout &

現在我們可以向管道提供來自網路的數據。不幸的是 netcat 不會這樣做,因為它寫入標準輸出,而這在 nohup 下不可用。我必須修改netcat的來源。為了更容易(不帶 C 編譯器),我將使用 perl 鬆散埠連接到 netcat,也稱為“窮人的 Netcat”…好吧.. 我重寫了它,添加了帶有 -f 參數的文件 I/O 功能. 所以這裡是來源:

#! /usr/bin/perl
# Poor man's Netcat, the famous "TCP/IP swiss army knife"
# Only the basic functions are replicated : 
# - TCP only
# - only : "hostname port" or "-l" with "-p port" 
# but with *extended* functionality for direct file I/O by "-f file"

use strict;
use warnings;

use IO::Socket;
use Getopt::Long;

my $help='';
my $verbose;

my $local_port;
my $listen='';
$main::file_io='';

$SIG{CHLD} = 'IGNORE';

my $result = GetOptions(
       "help|h" => \$help,
       "verbose|v" => \$verbose,
   "local-port|p=i" => \$local_port,
   "listen|l" => \$listen,
       "file-io|f=s" => \$main::file_io,
      );
if ($help eq '' && $listen eq '' && (scalar @ARGV < 2) ) {$help = 1;}
if ($help) {
       print STDERR "Perl loose port of netcat(1)\n";
       print STDERR "usage : $0 [-p local_port] hostname port [-f file-for-input] (client)\n";
       print STDERR "   or : $0 -l -p local_port [-f file-for-output] (server)\n";
       exit(1);
}

# No need to close the socks as they are closed 
# when going out-of-scope
if ($listen) 
 { if (! $local_port) { die "You must specify the port to listen to in server mode\n";}
   # server mode
   my $l_sock = IO::Socket::INET->new(
       Proto => "tcp",
       LocalPort => $local_port,
       Listen => 1,
       Reuse => 1,
   ) or die "Could not create socket: $!";

   my $a_sock = $l_sock->accept(); 
   $l_sock->shutdown(SHUT_RDWR);
   read_from_network($a_sock); #server mode - calling read_data 
 } else 
    { #client mode
   if (scalar @ARGV < 2) { die "You must specify where to connect in client mode\n";}
   my ($remote_host, $remote_port) = @ARGV;
   my $c_sock = IO::Socket::INET->new(
       Proto => "tcp",
       LocalPort => $local_port,
       PeerAddr => $remote_host,
       PeerPort => $remote_port,
   ) or die "Could not create socket, reason: $!";
   write_to_network($c_sock);
   }

sub read_from_network 
{
   my ($socket) = @_;  my $output_fh;
       if($main::file_io ne '') 
      {
            open($output_fh, ">", $main::file_io) or die "Can't open $main::file_io : $!";
          } else { $output_fh = *STDOUT;}
   close(STDIN);
   copy_data_mono($socket, $output_fh);# *STDOUT
       $socket->shutdown(SHUT_RD); 
       close($output_fh); close(STDOUT);
}


sub write_to_network 
{
   my ($socket) = @_;
       my $input_fh;
       if($main::file_io ne '') 
      {
            open($input_fh, "<", $main::file_io) or die "Can't open $main::file_io : $!";
          } else { $input_fh = *STDIN;}
   close(STDOUT);
   copy_data_mono($input_fh,$socket);
       $socket->shutdown(SHUT_WR); 
       close($input_fh);close(STDIN);
}

sub copy_data_mono {
   my ($src, $dst) = @_;
   my $buf;
       print STDERR "copy_data_mono: output: $dst \n";
   while (my $read_len = sysread($src, $buf, 4096)) 
       {
       my $write_len = $read_len;
       while ($write_len) 
               {
        my $written_len = syswrite($dst, $buf);
        return unless $written_len; # $dst is closed
        $write_len -= $written_len;
       }
   }
}

當然現在可以跳過 dd 和命名管道,但是我沒有檢查這段程式碼在寫入物理分區時是否正常工作……現在所有命令都是(假設程式碼保存到 netcat_g.pl):

mkfifo my.pipe #create a fifo, @ writable FS
nohup dd if=./my.pipe of=./test.txt & 
nohup ./netcat_g.pl -l -p 4000 -f ./my.pipe  &

並且可以關閉控制台。主要缺點是不能連結另一個命令,除非它們支持文件 I/O 並創建新的命名管道。

引用自:https://unix.stackexchange.com/questions/86503