File Coverage

lib/Wireguard/WGmeta/Cli/Commands/Show.pm
Criterion Covered Total %
statement 39 151 25.8
branch 0 50 0.0
condition 0 9 0.0
subroutine 13 19 68.4
pod 3 3 100.0
total 55 232 23.7


line stmt bran cond sub pod time code
1             package Wireguard::WGmeta::Cli::Commands::Show;
2 1     1   6 use strict;
  1         6  
  1         31  
3 1     1   6 use warnings FATAL => 'all';
  1         3  
  1         32  
4 1     1   6 use experimental 'signatures';
  1         1  
  1         8  
5              
6 1     1   569 use parent 'Wireguard::WGmeta::Cli::Commands::Command';
  1         332  
  1         6  
7 1     1   44 use FindBin;
  1         3  
  1         42  
8              
9 1     1   461 use Wireguard::WGmeta::Cli::Human;
  1         3  
  1         60  
10 1     1   442 use Wireguard::WGmeta::Cli::TerminalHelpers;
  1         4  
  1         63  
11 1     1   547 use Wireguard::WGmeta::Wrapper::Config;
  1         2  
  1         71  
12 1     1   436 use Wireguard::WGmeta::Wrapper::Show;
  1         3  
  1         35  
13 1     1   6 use Wireguard::WGmeta::Wrapper::Bridge;
  1         2  
  1         54  
14 1     1   6 use Wireguard::WGmeta::Utils;
  1         1  
  1         55  
15 1     1   5 use Wireguard::WGmeta::Parser::Conf qw(INTERNAL_KEY_PREFIX);
  1         2  
  1         38  
16 1     1   5 use Wireguard::WGmeta::ValidAttributes qw(KNOWN_ATTRIBUTES);
  1         2  
  1         1478  
17              
18 0     0 1   sub new($class, @input_arguments) {
  0            
  0            
  0            
19 0           my $self = $class->SUPER::new(@input_arguments);
20              
21 0           my @default_attr_list_peer = (
22             'public-key',
23             'preshared-key',
24             'allowed-ips',
25             'endpoint',
26             'latest-handshake',
27             'transfer-rx',
28             'transfer-tx',
29             'persistent-keepalive',
30             'disabled',
31             'alias'
32             );
33              
34 0           my @default_attr_list_interface = (
35             'private-key',
36             'public-key',
37             'listen-port',
38             'fwmark',
39             'disabled',
40             'alias'
41             );
42 0           my %wg_show = (
43             'endpoint' => 1,
44             'transfer-rx' => 1,
45             'transfer-tx' => 1,
46             'latest-handshake' => 1,
47             );
48              
49             # register attribute converters here (no special prefix needed)
50 0           my %attr_converters = (
51             'latest-handshake' => \×tamp2human,
52             'transfer-rx' => \&bits2human,
53             'transfer-tx' => \&bits2human
54             );
55              
56 0           $self->{attr_converters} = \%attr_converters;
57 0           $self->{wg_show_lookup} = \%wg_show;
58 0           $self->{default_attr_list_peer} = \@default_attr_list_peer;
59 0           $self->{default_attr_list_interface} = \@default_attr_list_interface;
60              
61 0           bless $self, $class;
62 0           return $self;
63             }
64              
65 0     0 1   sub entry_point($self) {
  0            
  0            
66 0           $self->check_privileges();
67 0           my $len = @{$self->{input_args}};
  0            
68 0           my $is_dump = 0;
69 0           my $interface = 'all';
70 0 0         if ($len > 0) {
71 0           my $first_arg = $self->_retrieve_or_die($self->{input_args}, 0);
72 0 0         return $self->cmd_help() if $first_arg eq 'help';
73 0 0         $is_dump = 1 if $self->_retrieve_or_die($self->{input_args}, -1) eq 'dump';
74 0           $interface = $first_arg;
75 0 0         if ($len > 1) {
76 0           my @requested_attributes = @{$self->{input_args}}[1 .. $len - 1];
  0            
77 0           return $self->_run_command($interface, $is_dump, \@requested_attributes);
78             }
79             }
80             # Default case
81 0           $self->_run_command($interface, $is_dump, undef);
82             }
83              
84 0     0     sub _run_command($self, $interface, $is_dump, $ref_attr_list) {
  0            
  0            
  0            
  0            
  0            
85              
86 0 0 0       if (not $interface eq 'all' and not $self->wg_meta->is_valid_interface($interface)) {
87 0           die "Invalid interface `$interface`";
88             }
89 0           my $out;
90 0 0         if (defined $ENV{IS_TESTING}) {
91 0           $out = read_file($FindBin::Bin . '/../t/test_data/wg_show_dump');
92             }
93             else {
94 0           my @std_out = run_external('wg show all dump');
95 0           $out = join '', @std_out;
96             }
97 0           my $wg_show = Wireguard::WGmeta::Wrapper::Show->new($out);
98              
99 0           my $output = '';
100 0           my @interface_list;
101 0 0         if (not $interface eq 'all') {
102 0           @interface_list = ($interface);
103             }
104             else {
105 0           @interface_list = $self->wg_meta->get_interface_list()
106             }
107              
108 0 0         my $use_default = defined $ref_attr_list ? 0 : 1;
109 0           for my $printed_interface (sort @interface_list) {
110 0           my $interface_is_active = $wg_show->iface_exists($printed_interface);
111 0           my $state = 0;
112 0           for my $identifier ($self->wg_meta->get_section_list($printed_interface)) {
113 0 0         my %wg_show_section = ($interface_is_active) ? $wg_show->get_interface_section($printed_interface, $identifier) : ();
114 0           my %config_section = $self->wg_meta->get_interface_section($printed_interface, $identifier);
115 0           my $type = $config_section{INTERNAL_KEY_PREFIX . 'type'};
116 0 0         if ($use_default) {
117             $ref_attr_list = ($type eq 'Interface') ? $self->{default_attr_list_interface} : $self->{default_attr_list_peer}
118 0 0         }
119 0 0         if ($is_dump) {
120             $output .= "$printed_interface "
121             . $self->_get_dump_line(\%config_section, \%wg_show_section, $ref_attr_list)
122             . "\t"
123 0           . $config_section{INTERNAL_KEY_PREFIX . 'type'}
124             . "\n";
125             }
126             else {
127 0 0         $identifier = $config_section{'alias'} if exists $config_section{'alias'};
128              
129             # we only show a green dot when the peer appears in the show output
130 0 0 0       $state = ($interface_is_active and keys %wg_show_section > 1) ? 1 : 0;
131 0 0         my $state_marker = ($state == 1) ? BOLD . GREEN . '●' . RESET : BOLD . RED . '●' . RESET;
132 0           $output .= $state_marker . BOLD . lc($type) . ": " . RESET . $identifier . "\n";
133 0           $output .= $self->_get_pretty_line(\%config_section, \%wg_show_section, $ref_attr_list) . "\n\n";
134             }
135             }
136             }
137 0           print $output;
138             }
139              
140              
141 0     0     sub _get_pretty_line($self, $ref_config_section, $ref_show_section, $ref_attr_list) {
  0            
  0            
  0            
  0            
  0            
142 0           my @line;
143 0           for my $printed_attribute (@{$ref_attr_list}) {
  0            
144             # skip redundant information
145 0 0 0       next if $printed_attribute eq 'alias' or $printed_attribute eq 'disabled';
146              
147             # first lets check if we have to look in the show output
148 0           my $value = '(none)';
149 0 0         if (exists $self->{wg_show_lookup}{$printed_attribute}) {
150 0 0         $value = $ref_show_section->{$printed_attribute} if exists $ref_show_section->{$printed_attribute};
151             }
152             # any other case
153             else {
154 0 0         if (exists $ref_config_section->{$printed_attribute}) {
155 0           $value = $ref_config_section->{$printed_attribute}
156             }
157             else {
158             # Check if info maybe available in show output
159 0 0         $value = $ref_show_section->{$printed_attribute} if exists $ref_show_section->{$printed_attribute};
160             }
161             }
162             # apply attr converters if any
163 0 0         $value = &{$self->{attr_converters}{$printed_attribute}}($value) if exists $self->{attr_converters}{$printed_attribute};
  0            
164 0           push @line, ' ' . $printed_attribute . ': ' . $value;
165             }
166 0           return join("\n", @line);
167             }
168              
169 0     0     sub _get_dump_line($self, $ref_config_section, $ref_show_section, $ref_attr_list) {
  0            
  0            
  0            
  0            
  0            
170 0           my @line;
171 0           for my $printed_attribute (@{$ref_attr_list}) {
  0            
172             # first lets check if we have to look in the show output
173 0           my $value = ('none');
174 0 0         if (exists $self->{wg_show_lookup}{$printed_attribute}) {
175 0 0         $value = $ref_show_section->{$printed_attribute} if exists $ref_show_section->{$printed_attribute};
176 0           push @line, $value;
177             }
178             # any other case
179             else {
180 0 0         if (exists $ref_config_section->{$printed_attribute}) {
181 0           $value = $ref_config_section->{$printed_attribute}
182             }
183             else {
184             # Check if info maybe available in show output
185 0 0         $value = $ref_show_section->{$printed_attribute} if exists $ref_show_section->{$printed_attribute};
186             }
187 0           push @line, $value;
188             }
189             }
190 0           return join("\t", @line);
191             }
192              
193 0     0 1   sub cmd_help($self) {
  0            
  0            
194 0           print "Usage: wg-meta show {interface|all} [attribute1, attribute2, ...] [dump] \n"
195             . "Notes:\n"
196             . "A green dot indicates an interface/peer's 'real' state which means that its currently possible\n"
197             . "to connect to this interface/peer.\n"
198             . "A red dot on the other hand indicates that its not possible to connect. This could mean not applied changes, \n"
199             . "a disabled peer or the parent interface is down. \n"
200             }
201              
202             1;