#587 #561 update pseudo devices to better support ssh arpnip

this patch resets all pseudo devices to have no layer3 support but adds a
feature to the pseudo devices admin panel to enable layer3 support. it also
changes arpnip and arpwalk behaviour to always permit the action if layer3
is available (ignoring the vendor).

documentation will need updating to tell users to create pseudo devices
with layer3 support when they want to arpnip an unsupported platform.

arpnip with ssh/cli against a supported platform (one that can be discovered)
will continue to work normally.

Squashed commit of the following:

commit 9dad5be81d
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Tue Sep 3 09:03:53 2019 +0100

    allow pseudo with layer 3 to run arpnip

commit 7d97943fcd
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Tue Sep 3 08:59:10 2019 +0100

    allow pseudo devices with layer 2/3 capability

commit d1fdf574e3
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Tue Sep 3 08:55:41 2019 +0100

    move pseudo and layer checks to is_able from is_able_now

commit e0f72ef67d
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Tue Sep 3 08:51:42 2019 +0100

    ports defaults to one

commit 86ba01270c
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Tue Sep 3 08:50:45 2019 +0100

    add tooltip for arpnip toggle

commit cdd2470228
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Tue Sep 3 08:34:46 2019 +0100

    simplify template

commit 46236d68ea
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Sun Sep 1 23:53:56 2019 +0100

    a fix up for pseudo devices which need layer 3

commit 016d249efc
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Sun Sep 1 20:37:11 2019 +0100

    do not wrap buttons

commit 1ec1402e0c
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Sun Sep 1 20:33:03 2019 +0100

    implement user settable layer-three service for pseudo devices

commit a267efa3d8
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Sun Sep 1 18:39:22 2019 +0100

    only set layer if successful action

commit b108be5e23
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Sun Sep 1 18:32:19 2019 +0100

    should defer SNMP against pseudo devices

commit 897ba3a629
Merge: e0ddbaab a7348900
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Sun Sep 1 14:54:36 2019 +0100

    Merge branch 'master' into og-pseudo-vs-cli-arpnip

commit e0ddbaab08
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Mon Aug 26 11:35:13 2019 +0100

    as last commit, for discover

commit 61f9c89040
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Sun Aug 25 23:55:38 2019 +0100

    move pseudo and layer checks into is_*able functions

commit 8b010d4023
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Sun Aug 25 18:38:11 2019 +0100

    any device completing macsuck/arpnip must have that layer

commit a11bce7863
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Sun Aug 25 18:33:27 2019 +0100

    clean up device layers

commit d2661bff61
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Sun Aug 25 18:18:02 2019 +0100

    first make arpnip behave like other jobs towards pseudo devices
This commit is contained in:
Oliver Gorwits
2019-09-03 09:09:55 +01:00
parent a734890055
commit 2897eda684
13 changed files with 99 additions and 39 deletions

View File

@@ -79,6 +79,19 @@ sub jq_warm_thrusters {
actionset => $actionset{$_},
}, { key => 'primary' }) for keys %actionset;
});
# fix up the pseudo devices which need layer 3
# TODO remove this after next release
schema('netdisco')->txn_do(sub {
my @hosts = grep { defined }
map { schema('netdisco')->resultset('Device')->search_for_device($_->{only}) }
grep { exists $_->{only} and ref '' eq ref $_->{only} }
grep { exists $_->{driver} and $_->{driver} eq 'cli' }
@{ setting('device_auth') };
$_->update({ layers => \[q{overlay(layers placing '1' from 6 for 1)}] })
for @hosts;
});
}
sub jq_getsome {

View File

@@ -58,8 +58,11 @@ Returns C<undef> if the connection fails.
sub reader_for {
my ($class, $ip, $useclass) = @_;
my $device = get_device($ip) or return undef;
return undef if $device->in_storage and $device->is_pseudo;
my $readers = $class->instance->readers or return undef;
return $readers->{$device->ip} if exists $readers->{$device->ip};
debug sprintf 'snmp reader cache warm: [%s]', $device->ip;
return ($readers->{$device->ip}
= _snmp_connect_generic('read', $device, $useclass));
@@ -104,8 +107,11 @@ Returns C<undef> if the connection fails.
sub writer_for {
my ($class, $ip, $useclass) = @_;
my $device = get_device($ip) or return undef;
return undef if $device->in_storage and $device->is_pseudo;
my $writers = $class->instance->writers or return undef;
return $writers->{$device->ip} if exists $writers->{$device->ip};
debug sprintf 'snmp writer cache warm: [%s]', $device->ip;
return ($writers->{$device->ip}
= _snmp_connect_generic('write', $device, $useclass));

View File

@@ -158,6 +158,8 @@ If C<$device_type> is also given, then C<discover_no_type> will be checked.
Also respects C<discover_phones> and C<discover_waps> if either are set to
false.
Also checks if the device is a pseudo device (vendor is C<netdisco>).
Returns false if the host is not permitted to discover the target device.
=cut
@@ -168,6 +170,9 @@ sub is_discoverable {
$remote_type ||= '';
$remote_cap ||= [];
return _bail_msg("is_discoverable: $device is pseudo-device")
if $device->is_pseudo;
return _bail_msg("is_discoverable: $device matches wap_platforms but discover_waps is not enabled")
if ((not setting('discover_waps')) and
(match_to_setting($remote_type, 'wap_platforms') or
@@ -192,9 +197,8 @@ sub is_discoverable {
=head2 is_discoverable_now( $ip, $device_type? )
Same as C<is_discoverable>, but also checks the last_discover field if the
device is in storage, and returns false if that host has been too recently
discovered.
Same as C<is_discoverable>, but also compares the C<last_discover> field
of the C<device> to the C<discover_min_age> configuration.
Returns false if the host is not permitted to discover the target device.
@@ -222,6 +226,8 @@ the local configuration to arpnip the device.
The configuration items C<arpnip_no> and C<arpnip_only> are checked
against the given IP.
Also checks if the device reports layer 3 capability.
Returns false if the host is not permitted to arpnip the target device.
=cut
@@ -230,6 +236,9 @@ sub is_arpnipable {
my $ip = shift;
my $device = get_device($ip) or return 0;
return _bail_msg("is_arpnipable: $device has no layer 3 capability")
unless $device->has_layer(3);
return _bail_msg("is_arpnipable: $device matched arpnip_no")
if check_acl_no($device, 'arpnip_no');
@@ -241,9 +250,8 @@ sub is_arpnipable {
=head2 is_arpnipable_now( $ip )
Same as C<is_arpnipable>, but also checks the last_arpnip field if the
device is in storage, and returns false if that host has been too recently
arpnipped.
Same as C<is_arpnipable>, but also compares the C<last_arpnip> field
of the C<device> to the C<arpnip_min_age> configuration.
Returns false if the host is not permitted to arpnip the target device.
@@ -271,6 +279,8 @@ the local configuration to macsuck the device.
The configuration items C<macsuck_no> and C<macsuck_only> are checked
against the given IP.
Also checks if the device reports layer 2 capability.
Returns false if the host is not permitted to macsuck the target device.
=cut
@@ -279,6 +289,9 @@ sub is_macsuckable {
my $ip = shift;
my $device = get_device($ip) or return 0;
return _bail_msg("is_macsuckable: $device has no layer 2 capability")
unless $device->has_layer(2);
return _bail_msg("is_macsuckable: $device matched macsuck_no")
if check_acl_no($device, 'macsuck_no');
@@ -290,9 +303,8 @@ sub is_macsuckable {
=head2 is_macsuckable_now( $ip )
Same as C<is_macsuckable>, but also checks the last_macsuck field if the
device is in storage, and returns false if that host has been too recently
macsucked.
Same as C<is_macsuckable>, but also compares the C<last_macsuck> field
of the C<device> to the C<macsuck_min_age> configuration.
Returns false if the host is not permitted to macsuck the target device.

View File

@@ -36,7 +36,7 @@ ajax '/ajax/control/admin/pseudodevice/add' => require_role admin => sub {
ip => param('ip'),
dns => param('dns'),
vendor => 'netdisco',
layers => '00000100',
layers => param('layers'),
last_discover => \'now()',
});
return unless $device;
@@ -87,6 +87,9 @@ ajax '/ajax/control/admin/pseudodevice/update' => require_role admin => sub {
})->delete;
}
}
# also set layers
$device->update({layers => param('layers')});
});
};

View File

@@ -16,9 +16,6 @@ register_worker({ phase => 'check' }, sub {
return Status->error("arpnip skipped: $device not yet discovered")
unless $device->in_storage;
return Status->info("arpnip skipped: $device has no layer 3 capability")
unless $device->has_layer(3);
return Status->info("arpnip skipped: $device is not arpnipable")
unless is_arpnipable_now($device);

View File

@@ -55,6 +55,7 @@ register_worker({ phase => 'main', driver => 'snmp' }, sub {
push @{ vars->{'v6arps'} },
@{get_arps_snmp($device, $snmp->ipv6_n2p_mac, $snmp->ipv6_n2p_addr) };
$device->update({layers => \[q{overlay(layers placing '1' from 6 for 1)}]});
return Status->done("Gathered arp caches from $device");
});
@@ -99,6 +100,7 @@ register_worker({ phase => 'main', driver => 'cli' }, sub {
push @{ vars->{'v6arps'} },
grep { NetAddr::IP::Lite->new($_->{ip})->bits == 128 } @arps;
$device->update({layers => \[q{overlay(layers placing '1' from 6 for 1)}]});
return Status->done("Gathered arp caches from $device");
});

View File

@@ -16,9 +16,6 @@ register_worker({ phase => 'check' }, sub {
return Status->error("discover failed: no device param (need -d ?)")
if $device->ip eq '0.0.0.0';
return Status->info("discover skipped: $device is pseudo-device")
if $device->is_pseudo;
# runner has already called get_device to promote $job->device
return $job->cancel("fresh discover cancelled: $device already known")
if $device->in_storage

View File

@@ -16,12 +16,6 @@ register_worker({ phase => 'check' }, sub {
return Status->error("macsuck skipped: $device not yet discovered")
unless $device->in_storage;
return Status->info("macsuck skipped: $device is pseudo-device")
if $device->is_pseudo;
return Status->info("macsuck skipped: $device has no layer 2 capability")
unless $device->has_layer(2);
return Status->info("macsuck skipped: $device is not macsuckable")
unless is_macsuckable_now($device);

View File

@@ -245,6 +245,13 @@ td > form.nd_inline-form {
text-decoration: none;
}
/* badge for pseudo devices layer three toggle */
.nd_layer-three-link {
text-decoration: none !important;
display: inline-block;
margin-left: -4px;
}
/* for the job control admin page play/pause links */
#nd_countdown-refresh:hover, #nd_countdown-control:hover {
text-decoration: none;

View File

@@ -2,4 +2,10 @@ BEGIN;
ALTER TABLE users ADD COLUMN "radius" boolean DEFAULT false;
UPDATE device SET layers = NULL WHERE vendor = 'netdisco';
UPDATE device SET layers = '00000000' WHERE layers IS NULL;
ALTER TABLE device ALTER layers SET DEFAULT '00000000';
COMMIT;

View File

@@ -4,6 +4,7 @@
<th class="nd_center-cell">Device Name</th>
<th class="nd_center-cell">Device IP</th>
<th class="nd_center-cell">Number of Ports</th>
<th class="nd_center-cell">Services</th>
<th class="nd_center-cell">Action</th>
</tr>
</thead>
@@ -11,7 +12,12 @@
<tr>
<td class="nd_center-cell"><input data-form="add" name="dns" type="text"></td>
<td class="nd_center-cell"><input data-form="add" name="ip" type="text"></td>
<td class="nd_center-cell"><input data-form="add" name="ports" type="number"></td>
<td class="nd_center-cell"><input data-form="add" name="ports" type="number" value="1"></td>
<td class="nd_center-cell">
<span class="badge">&nbsp;</span><span class="badge">&nbsp;</span>
<a class="nd_layer-three-link" href="#" rel="tooltip" data-placement="bottom" data-offset="3" data-title="Enable Arpnip"><span class="badge">3</span></a><span class="badge">&nbsp;</span><span class="badge">&nbsp;</span><span class="badge">&nbsp;</span><span class="badge">&nbsp;</span>
<input data-form="add" name="layers" type="hidden" value="00000000">
</td>
<td class="nd_center-cell">
<button class="btn btn-small nd_adminbutton" name="add" type="submit"><i class="icon-plus-sign"></i> Add</button>
</td>
@@ -26,6 +32,11 @@
<td class="nd_center-cell">
<input data-form="update" name="ports" type="number" value="[% row.port_count | html_entity %]">
</td>
<td class="nd_center-cell">
<span class="badge">&nbsp;</span><span class="badge">&nbsp;</span>
<a class="nd_layer-three-link" href="#" rel="tooltip" data-placement="bottom" data-offset="3" data-title="Enable Arpnip"><span class="badge[% ' badge-success' IF row.layers.substr(5,1) %]">3</span></a><span class="badge">&nbsp;</span><span class="badge">&nbsp;</span><span class="badge">&nbsp;</span><span class="badge">&nbsp;</span>
<input data-form="update" name="layers" type="hidden" value="[% row.layers | html_entity %]">
</td>
<td class="nd_center-cell">
<input data-form="update" name="dns" type="hidden" value="[% row.dns | html_entity %]">
<input data-form="update" name="ip" type="hidden" value="[% row.ip | html_entity %]">
@@ -68,6 +79,17 @@ $(document).ready(function() {
} ],
[% INCLUDE 'ajax/datatabledefaults.tt' -%]
} );
$('.nd_layer-three-link').click(function() {
var badge = $(this).children('span').first();
var layers = $(this).parent().children('input').first();
$(badge).toggleClass('badge-success');
if ($(badge).hasClass('badge-success')) {
$(layers).attr('value', '00000100');
}
else {
$(layers).attr('value', '00000000');
}
});
} );
</script>

View File

@@ -26,7 +26,7 @@
<td class="nd_center-cell"></td>
<td class="nd_center-cell"></td>
<td class="nd_center-cell"><input class="span2" data-form="add" name="note" type="text"></td>
<td class="nd_center-cell">
<td nowrap class="nd_center-cell">
<button class="btn btn-small nd_adminbutton" name="add" type="submit"><i class="icon-plus-sign"></i> Add</button>
</td>
</tr>
@@ -62,7 +62,7 @@
<input class="span2" data-form="update" name="note" type="text" value="[% row.note | html_entity %]">
</td>
<td class="nd_center-cell">
<td nowrap class="nd_center-cell">
<button class="btn nd_adminbutton" name="update" type="submit"><i class="icon-save text-warning"></i></button>
<button class="btn" data-toggle="modal"

View File

@@ -71,8 +71,9 @@
,minLength: 0
});
// activate modals
// activate modals and tooltips
$('.nd_modal').modal({show: false});
$("[rel=tooltip]").tooltip({live: true});
}
// on load, establish global delegations for now and future