lighty.io initializer
[transportpce.git] / debug_tools / netconf_terminal.pl
1 #!/usr/bin/env perl
2 ##############################################################################
3 #Copyright (c) 2017 Orange, Inc. and others.  All rights reserved.
4 #
5 # This program and the accompanying materials are made available under the
6 # terms of the Eclipse Public License v1.0 which accompanies this distribution,
7 # and is available at http://www.eclipse.org/legal/epl-v10.html
8 ##############################################################################
9 #
10 # debian dependecies: apt-get install libnet-openssh-perl libio-pty-perl
11 #
12
13 use strict;
14 use warnings;
15 #use diagnostics;  #uncomment this line for more details when encountering warnings
16 use Net::OpenSSH;
17 use FileHandle;
18 use Getopt::Long qw(:config no_ignore_case bundling);
19
20 my ($host, $help, $usage,  $capabilities, $login, $password, $kidpid, $hello_message);
21
22
23 GetOptions (
24     "h|help" =>\$help,
25     "C|capabilities=s"=>\$capabilities
26 );
27 $usage = "
28 USAGE: netconf_terminal.pl [-h|--help] [-C|--capabilities <custom_hello_file.xml>] <[login[:password]@]host[:port]> [login] [password]
29
30 Simple netconf terminal client that can be used as an alternative to 'openssh [-p port] <[login@]host> -s netconf'.
31 The main difference is the built-in handshake phase with hello capabilties that can be loaded from an external file.
32 This is particularly useful to avoid timeouts.
33
34 OPTIONS :
35
36         -C or --capabilities     use the given file to advertise a hello message with customized capabilities
37         -h or --help             print this help
38
39 ";
40
41 if ($help) {
42     print $usage;
43     exit(0);
44 }
45
46 unless (@ARGV >= 1) {
47     print $usage;
48     exit(0);
49 }
50
51 ($host, $login, $password) = @ARGV;
52
53 #netconf default port is no 22 but 830
54 if ($host !~ /:[0-9]+$/) {
55     $host.=':830';
56 }
57
58 my $connection_string=$host;
59 if ($password) {
60    $connection_string=$login.":".$password."@".$connection_string;
61 } elsif ($login) {
62    $connection_string=$login."@".$connection_string;
63 }
64
65 #retrieving hello custom file if any
66 if (defined ($capabilities)) {
67     open(CAPABILITIES,'<',$capabilities) or die ("can not open $capabilities") ;
68     while (<CAPABILITIES>) {
69         $hello_message .= $_;
70     }
71     chop $hello_message; # removing EOF
72     $hello_message.="\n]]>]]>\n";
73     close(CAPABILITIES);
74 }
75 #otherwise using a basic hello message
76 #EXI extension is not advertised by default since difficult to handle manually
77 else{
78     $hello_message='<?xml version="1.0" encoding="utf-8"?>
79 <hello xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
80 <capabilities>
81 <capability>urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring?module=ietf-netconf-monitoring&amp;revision=2010-10-04</capability>
82 <capability>urn:ietf:params:xml:ns:yang:ietf-netconf-notifications?module=ietf-netconf-notifications&amp;revision=2012-02-06</capability>
83 <capability>urn:ietf:params:xml:ns:netconf:base:1.0?module=ietf-netconf&amp;revision=2011-06-01</capability>
84 <capability>urn:ietf:params:xml:ns:yang:ietf-yang-types?module=ietf-yang-types&amp;revision=2013-07-15</capability>
85 <capability>urn:ietf:params:netconf:capability:candidate:1.0</capability>
86 <capability>urn:ietf:params:xml:ns:netconf:notification:1.0?module=notifications&amp;revision=2008-07-14</capability>
87 <capability>urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring-extension?module=ietf-netconf-monitoring-extension&amp;revision=2013-12-10</capability>
88 <capability>urn:ietf:params:netconf:base:1.0</capability>
89 <capability>urn:ietf:params:xml:ns:yang:iana-afn-safi?module=iana-afn-safi&amp;revision=2013-07-04</capability>
90 <capability>urn:ietf:params:xml:ns:yang:ietf-inet-types?module=ietf-inet-types&amp;revision=2013-07-15</capability>
91 </capabilities>
92 </hello>';
93     $hello_message.="\n]]>]]>\n";
94 }
95
96
97 print STDERR "connecting to ".$connection_string."\n";
98
99 my $ssh_handle= Net::OpenSSH->new($connection_string,
100                                   master_opts => [-o => 'StrictHostKeyChecking=no'],
101                                   timeout => 500, kill_ssh_on_timeout => 500);
102
103 #netconf requires a specific socket
104 my ($ssh_subsocket, $pid) = $ssh_handle->open2socket({ssh_opts => '-s'}, 'netconf');
105 die "can't establish connection: exiting\n" unless defined($ssh_subsocket);
106
107 print STDERR "[Connected]\n";
108
109 # split the program into two processes, identical twins
110 die "can't fork: $!" unless defined($kidpid = fork());
111
112
113 # the if{} block runs only in the parent process (terminal output)
114 if (!$kidpid) {
115
116     $|=1;
117
118     # copy the socket to standard output
119     my $buf;
120     my $nread;
121     #while (<$ssh_subsocket>) {
122     #buffer seems not totally flushed when using the syntax above (nor when using autoflush)
123     while ($nread = sysread($ssh_subsocket,$buf,150)) {
124         print $buf;
125         $ssh_subsocket->flush();
126     };
127
128     print;
129     kill("TERM", $kidpid);                  # send SIGTERM to child
130 }
131 # the else{} block runs only in the child process (terminal input)
132 else {
133
134    $ssh_subsocket->autoflush(1);
135    sleep 1;                                 # wait needed for ensuring STDOUT buffer is not melt
136
137    if (defined ($hello_message)) {
138        print $ssh_subsocket $hello_message;
139        sleep 1;
140    }
141
142    while (defined (my $line = <STDIN>)) {
143       print $ssh_subsocket $line;
144    }
145
146 }
147
148 sleep 2;
149 kill("TERM", $kidpid);                      # send SIGTERM to child
150 exit;