Add get_ip_from_interface function

This commit is contained in:
David Kerr 2020-08-02 22:30:00 -04:00
parent bafe142692
commit 213cf6ad09
6 changed files with 412 additions and 36 deletions

View file

@ -71,6 +71,7 @@ AM_PL_LOG_FLAGS = -Mstrict -w \
-I'$(abs_top_srcdir)'/t/lib \
-MDevel::Autoflush
handwritten_tests = \
t/get_ip_from_if.pl \
t/geturl_ssl.pl \
t/is-and-extract-ipv4.pl \
t/is-and-extract-ipv6.pl \

View file

@ -2461,9 +2461,7 @@ sub get_ip {
$arg = 'ip';
} elsif ($use eq 'if') {
$reply = `command -v ip >/dev/null && ip address show dev $arg`;
$reply = `command -v ifconfig >/dev/null && ifconfig $arg` if $?;
$reply = '' if $?;
$ip = get_ip_from_interface($arg);
} elsif ($use eq 'cmd') {
if ($arg) {
@ -2696,6 +2694,123 @@ sub extract_ipv6_global {
return $ip;
}
######################################################################
## Regex that matches an IPv6 address that is unique local (ULA).
## Accepts embedded leading zeros.
######################################################################
my $regex_ipv6_ula = qr{
(?= # Address starts with
f[cd][0-9a-f]{2}: # fc00::/7 RFC4193 ULA
)
$regex_ipv6 # And is a valid IPv6 address
}xi;
######################################################################
## get_ip_from_interface() finds an IPv4 or IPv6 address from a network
## interface. Defaults to IPv4 unless '6' passed as 2nd parameter.
######################################################################
sub get_ip_from_interface {
my $interface = shift;
my $ipver = int(shift // 4); ## Defaults to IPv4 if not specified
my $scope = lc(shift // "gua"); ## "gua" or "ula"
my $reply = shift // ''; ## Pass in data for unit testing purposes only
my $MacOS = shift // 0; ## For testing can set to 1 if input data is MacOS/FreeBSD format
my $count = 0;
my $cmd = "test";
if (($ipver != 4) && ($ipver != 6)) {
warning("get_ip_from_interface() invalid IP version: %s", $ipver);
return undef;
}
if ($reply eq '') { ## skip if test data passed in.
return undef if !defined($interface);
}
if ($ipver == 4) {
if (!$reply) { ## skip if test data passed in.
## Try ip first, then ifconfig.
$cmd = "ip -4 -o addr show dev $interface scope global"; $reply = qx{$cmd 2>/dev/null};
if ($?) { $cmd = "ifconfig $interface"; $reply = qx{$cmd 2>/dev/null}; }
if ($?) { $cmd = "missing ip or ifconfig command";
failed("Unable to obtain information for '%s' -- %s", $interface, $cmd);
}
}
debug("Reply from '%s' :\n------\n%s------", $cmd, $reply);
## IPv4 is simple, we just need to find the first IPv4 address returned in the list.
my @reply = split(/\n/, $reply);
@reply = grep(/\binet\b/, @reply); # Select only IPv4 entries
return extract_ipv4($reply[0]);
}
## From this point on we only looking for IPv6 address.
if (($scope ne "gua") && ($scope ne "ula")) {
warning("get_ip_from_interface() invalid IPv6 scope: %s, using type GUA", $scope);
$scope = "gua";
}
$cmd = "test data";
if (!$reply) { ## skip if test data passed in.
## Try ip first, then ifconfig with -L for MacOS/FreeBSD then finally ifconfig for everything else
$cmd = "ip -6 -o addr show dev $interface scope global"; $reply = qx{$cmd 2>/dev/null}; # Linux
if ($?) { $cmd = "ifconfig -L $interface"; $MacOS = 1; $reply = qx{$cmd 2>/dev/null}; } # MacOS/FreeBSD
if ($?) { $cmd = "ifconfig $interface"; $reply = qx{$cmd 2>/dev/null}; } # Anything without iproute2 or -L
if ($?) { $cmd = "missing ip or ifconfig command";
failed("Unable to obtain information for '%s' -- %s", $interface, $cmd);
}
}
debug("Reply from '%s' :\n------\n%s------", $cmd, $reply);
## IPv6 is more complex than IPv4. Start by filtering on only "inet6" addresses
## Then remove deprecated or temporary addresses and finally seleect on global or local addresses
my @reply = split(/\n/, $reply);
@reply = grep(/\binet6\b/, @reply); # Select only IPv6 entries
@reply = grep(!/\bdeprecated\b|\btemporary\b/, @reply); # Remove deprecated and temporary
@reply = ($scope eq "gua") ? grep(/$regex_ipv6_global/, @reply) # Select only global addresses
: grep(/$regex_ipv6_ula/, @reply); # or only ULA addresses
debug("Raw IPv6 after filtering for %s addresses %s: (%s)\r\n%s", uc($scope), $interface, scalar(@reply), join("\n", @reply));
## If we filter down to zero or one result then we are done...
return undef if (($count = scalar(@reply)) == 0);
return extract_ipv6($reply[0]) if ($count == 1);
## If there are more than one we need to select the "best".
## First choice would be a static address.
my @static = ($MacOS == 1) ? grep(!/^.*\bvltime\b.*$/i, @reply) # MacOS/FreeBSD, no 'vltime'
: grep(/^.*\bvalid_lft.\bforever\b.*$/i, @reply); # Everything else 'forever' life
$count = scalar(@static);
debug("Possible Static IP addresses %s: (%s)\r\n%s", $interface, $count, join("\n", @static));
## If only one result then we are done. If there are more than one static addresses
## then we will replace our original list with the list of statics and sort on them.
## If zero static addresses we fall through with our original list.
return extract_ipv6($static[0]) if ($count == 1);
@reply = @static if ($count > 1);
## Sort what we have by the prefix length, IP address "length" and finally valid life.
my @sorted = sort {
## We give preference to IP addressess with the longest prefix... so we prefer a /128 over a /64
## this is a decimal (\d+) either after the word "prefixlen" or after a forward slash.
(($b =~ /(?:\bprefixlen\b\s*|\/)(\d+)/i)[0] // 0) <=> (($a =~ /(?:\bprefixlen\b\s*|\/)(\d+)/i)[0] // 0)
## If there are multiple the same then we prefer "shorter" IP addresses in the
## theory that a shorter address is more likely assigned by DHCPv6 than SLAAC.
## E.g. 2001:db8:4341:0781::8214/64 is preferable to 2001:db8:4341:0781:34a6:c329:c52e:8ba6/64
## So we count the number () of groups of [0-9a-f] blocks in the IP address.
|| (()= (extract_ipv6($a) // '') =~ /[0-9A-F]+/gi) <=> (()= (extract_ipv6($b) // '') =~ /[0-9A-F]+/gi)
## Finally we check remaining valid lifetime and prefer longer remaining life.
## This is a desimal (\d+) after the word "valid_lft" or "vltime". Only available
## from iproute2 or MacOS/FreeBSD version of ifconfig (-L parameter).
|| (($b =~ /(?:\bvalid_lft\b\s*|\bvltime\b\s*)(\d+)/i)[0] // 0) <=> (($a =~ /(?:\bvalid_lft\b\s*|\bvltime\b\s*)(\d+)/i)[0] // 0)
} @reply;
debug("Sorted list of IP addresss for %s: (%s)\r\n%s", $interface, scalar(@sorted), join("\n", @sorted));
## Whatever sorted to the top is the best choice for IPv6 address
return extract_ipv6($sorted[0]);
}
######################################################################
## group_hosts_by
######################################################################

29
t/get_ip_from_if.pl Normal file
View file

@ -0,0 +1,29 @@
use Test::More;
use ddclient::t;
SKIP: { eval { require Test::Warnings; } or skip($@, 1); }
eval { require 'ddclient'; } or BAIL_OUT($@);
# To aid in debugging, uncomment the following lines. (They are normally left commented to avoid
# accidentally interfering with the Test Anything Protocol messages written by Test::More.)
#STDOUT->autoflush(1);
#$ddclient::globals{'debug'} = 1;
subtest "get_ip_from_interface tests" => sub {
for my $sample (@ddclient::t::interface_samples) {
# interface name is undef as we are passing in test data
if (defined($sample->{want_ipv4_from_if})) {
my $ip = ddclient::get_ip_from_interface(undef, 4, undef, $sample->{text}, $sample->{MacOS});
is($ip, $sample->{want_ipv4_from_if}, $sample->{name});
}
if (defined($sample->{want_ipv6gua_from_if})) {
my $ip = ddclient::get_ip_from_interface(undef, 6, 'gua', $sample->{text}, $sample->{MacOS});
is($ip, $sample->{want_ipv6gua_from_if}, $sample->{name});
}
if (defined($sample->{want_ipv6ula_from_if})) {
my $ip = ddclient::get_ip_from_interface(undef, 6, 'ula', $sample->{text}, $sample->{MacOS});
is($ip, $sample->{want_ipv6ula_from_if}, $sample->{name});
}
}
};
done_testing();

View file

@ -56,9 +56,11 @@ subtest "extract_ipv6_global()" => sub {
subtest "interface config samples" => sub {
for my $sample (@ddclient::t::interface_samples) {
if (defined($sample->{want_extract_ipv6_global})) {
my $got = ddclient::extract_ipv6_global($sample->{text});
is($got, $sample->{want_extract_ipv6_global}, $sample->{name});
}
}
};
done_testing();

View file

@ -422,16 +422,20 @@ subtest "extract_ipv6() of valid addr with adjacent non-word char" => sub {
subtest "interface config samples" => sub {
for my $sample (@ddclient::t::interface_samples) {
if (defined($sample->{want_extract_ipv6_global})) {
subtest $sample->{name} => sub {
my $ip = ddclient::extract_ipv6($sample->{text});
ok(ddclient::is_ipv6($ip), "extract_ipv6() returns an IPv6 address");
};
foreach my $line (split(/\n/, $sample->{text})) {
my $ip = ddclient::extract_ipv6($line);
if ($ip) { ## Test cases may have lines that do not contain IPv6 address.
ok(ddclient::is_ipv6($ip),
sprintf("extract_ipv6(%s) returns an IPv6 address", perlstring($line)));
}
}
}
}
};
done_testing();

View file

@ -3,54 +3,62 @@ require v5.10.1;
use strict;
use warnings;
######################################################################
## Outputs from ip addr and ifconfig commands to find IP address from IF name
## Samples from Ubuntu 20.04, RHEL8, Buildroot, Busybox, MacOS 10.15, FreeBSD
## NOTE: Any tabs/whitespace at start or end of lines are intentional to match real life data.
######################################################################
our @interface_samples = (
# Sample output from:
# ip -6 -o addr show dev <interface> scope global
# This seems to be consistent accross platforms. The last line is from Ubuntu of a static
# assigned IPv6.
{
name => 'ip -6 -o addr show dev <interface> scope global',
text => <<'EOF',
2: ens160 inet6 fdb6:1d86:d9bd:1::8214/128 scope global dynamic noprefixroute \ valid_lft 63197sec preferred_lft 63197sec
2: ens160 inet6 2001:DB8:4341:0781::8214/128 scope global dynamic noprefixroute \ valid_lft 63197sec preferred_lft 63197sec
2: ens160 inet6 2001:DB8:4341:0781:89b9:4b1c:186c:a0c7/64 scope global temporary dynamic \ valid_lft 85954sec preferred_lft 21767sec
2: ens160 inet6 2001:db8:4341:0781::8214/128 scope global dynamic noprefixroute \ valid_lft 63197sec preferred_lft 63197sec
2: ens160 inet6 2001:db8:4341:0781:89b9:4b1c:186c:a0c7/64 scope global temporary dynamic \ valid_lft 85954sec preferred_lft 21767sec
2: ens160 inet6 fdb6:1d86:d9bd:1:89b9:4b1c:186c:a0c7/64 scope global temporary dynamic \ valid_lft 85954sec preferred_lft 21767sec
2: ens160 inet6 fdb6:1d86:d9bd:1:34a6:c329:c52e:8ba6/64 scope global temporary deprecated dynamic \ valid_lft 85954sec preferred_lft 0sec
2: ens160 inet6 fdb6:1d86:d9bd:1:b417:fe35:166b:4816/64 scope global dynamic mngtmpaddr noprefixroute \ valid_lft 85954sec preferred_lft 85954sec
2: ens160 inet6 2001:DB8:4341:0781:34a6:c329:c52e:8ba6/64 scope global temporary deprecated dynamic \ valid_lft 85954sec preferred_lft 0sec
2: ens160 inet6 2001:DB8:4341:0781:f911:a224:7e69:d22/64 scope global dynamic mngtmpaddr noprefixroute \ valid_lft 85954sec preferred_lft 85954sec
2: ens160 inet6 2001:DB8:4341:0781::100/128 scope global noprefixroute \ valid_lft forever preferred_lft forever
2: ens160 inet6 2001:db8:4341:0781:34a6:c329:c52e:8ba6/64 scope global temporary deprecated dynamic \ valid_lft 85954sec preferred_lft 0sec
2: ens160 inet6 2001:db8:4341:0781:f911:a224:7e69:d22/64 scope global dynamic mngtmpaddr noprefixroute \ valid_lft 85954sec preferred_lft 85954sec
2: ens160 inet6 2001:db8:4341:0781::100/128 scope global noprefixroute \ valid_lft forever preferred_lft forever
EOF
want_extract_ipv6_global => '2001:DB8:4341:781::8214',
want_extract_ipv6_global => '2001:db8:4341:781::8214',
want_ipv6gua_from_if => "2001:db8:4341:781::100",
want_ipv6ula_from_if => "fdb6:1d86:d9bd:1::8214",
},
# Sample output from MacOS:
# ifconfig <interface> | grep -w "inet6"
# (Yes, there is a tab at start of each line.) The last two lines are with a manually
# (Yes, there is a tab at start of each line.) The last lines is with a manually
# configured static GUA.
{
name => 'MacOS: ifconfig <interface> | grep -w inet6',
MacOS => 1,
text => <<'EOF',
inet6 fe80::1419:abd0:5943:8bbb%en0 prefixlen 64 secured scopeid 0xa
inet6 fdb6:1d86:d9bd:1:142c:8e9e:de48:843e prefixlen 64 autoconf secured
inet6 fdb6:1d86:d9bd:1:7447:cf67:edbd:cea4 prefixlen 64 autoconf temporary
inet6 fdb6:1d86:d9bd:1::c5b3 prefixlen 64 dynamic
inet6 2001:DB8:4341:0781:141d:66b9:2ba1:b67d prefixlen 64 autoconf secured
inet6 2001:DB8:4341:0781:64e1:b68f:e8af:5d6e prefixlen 64 autoconf temporary
inet6 fe80::1419:abd0:5943:8bbb%en0 prefixlen 64 secured scopeid 0xa
inet6 2001:DB8:4341:0781::101 prefixlen 64
inet6 2001:db8:4341:0781:141d:66b9:2ba1:b67d prefixlen 64 autoconf secured
inet6 2001:db8:4341:0781:64e1:b68f:e8af:5d6e prefixlen 64 autoconf temporary
inet6 2001:db8:4341:0781::101 prefixlen 64
EOF
want_extract_ipv6_global => '2001:DB8:4341:781:141d:66b9:2ba1:b67d',
want_extract_ipv6_global => '2001:db8:4341:781:141d:66b9:2ba1:b67d',
want_ipv6gua_from_if => "2001:db8:4341:781::101",
want_ipv6ula_from_if => "fdb6:1d86:d9bd:1::c5b3",
},
{
name => 'RHEL: ifconfig <interface> | grep -w inet6',
text => <<'EOF',
inet6 2001:DB8:4341:0781::dc14 prefixlen 128 scopeid 0x0<global>
inet6 2001:db8:4341:0781::dc14 prefixlen 128 scopeid 0x0<global>
inet6 fe80::cd48:4a58:3b0f:4d30 prefixlen 64 scopeid 0x20<link>
inet6 2001:DB8:4341:0781:e720:3aec:a936:36d4 prefixlen 64 scopeid 0x0<global>
inet6 2001:db8:4341:0781:e720:3aec:a936:36d4 prefixlen 64 scopeid 0x0<global>
inet6 fdb6:1d86:d9bd:1:9c16:8cbf:ae33:f1cc prefixlen 64 scopeid 0x0<global>
inet6 fdb6:1d86:d9bd:1::dc14 prefixlen 128 scopeid 0x0<global>
EOF
want_extract_ipv6_global => '2001:DB8:4341:781::dc14',
want_extract_ipv6_global => '2001:db8:4341:781::dc14',
want_ipv6gua_from_if => "2001:db8:4341:781::dc14",
want_ipv6ula_from_if => "fdb6:1d86:d9bd:1::dc14",
},
{
name => 'Ubuntu: ifconfig <interface> | grep -w inet6',
@ -60,19 +68,236 @@ EOF
inet6 fdb6:1d86:d9bd:1::8214 prefixlen 128 scopeid 0x0<global>
inet6 fdb6:1d86:d9bd:1:b417:fe35:166b:4816 prefixlen 64 scopeid 0x0<global>
inet6 fe80::5b31:fc63:d353:da68 prefixlen 64 scopeid 0x20<link>
inet6 2001:DB8:4341:0781::8214 prefixlen 128 scopeid 0x0<global>
inet6 2001:DB8:4341:0781:34a6:c329:c52e:8ba6 prefixlen 64 scopeid 0x0<global>
inet6 2001:DB8:4341:0781:89b9:4b1c:186c:a0c7 prefixlen 64 scopeid 0x0<global>
inet6 2001:DB8:4341:0781:f911:a224:7e69:d22 prefixlen 64 scopeid 0x0<global>
inet6 2001:db8:4341:0781::8214 prefixlen 128 scopeid 0x0<global>
inet6 2001:db8:4341:0781:34a6:c329:c52e:8ba6 prefixlen 64 scopeid 0x0<global>
inet6 2001:db8:4341:0781:89b9:4b1c:186c:a0c7 prefixlen 64 scopeid 0x0<global>
inet6 2001:db8:4341:0781:f911:a224:7e69:d22 prefixlen 64 scopeid 0x0<global>
EOF
want_extract_ipv6_global => '2001:DB8:4341:781::8214',
want_extract_ipv6_global => '2001:db8:4341:781::8214',
want_ipv6gua_from_if => "2001:db8:4341:781::8214",
want_ipv6ula_from_if => "fdb6:1d86:d9bd:1::8214",
},
{
name => 'Busybox: ifconfig <interface> | grep -w inet6',
text => <<'EOF',
inet6 addr: fe80::4362:31ff:fe08:61b4/64 Scope:Link
inet6 addr: 2001:DB8:4341:0781:ed44:eb63:b070:212f/128 Scope:Global
inet6 addr: 2001:db8:4341:781:ed44:eb63:b070:212f/128 Scope:Global
EOF
want_extract_ipv6_global => '2001:DB8:4341:781:ed44:eb63:b070:212f',
want_extract_ipv6_global => '2001:db8:4341:781:ed44:eb63:b070:212f',
want_ipv6gua_from_if => "2001:db8:4341:781:ed44:eb63:b070:212f",
},
{ name => "ip -4 -o addr show dev ens33 scope global (most linux IPv4)",
text => <<EOF,
2: ens33 inet 198.51.100.33/24 brd 198.51.100.255 scope global dynamic noprefixroute ens33\ valid_lft 77760sec preferred_lft 77760sec
EOF
want_ipv4_from_if => "198.51.100.33",
},
{ name => "ip -6 -o addr show dev ens33 scope global (most linux)",
text => <<EOF,
2: ens33 inet6 2001:db8:450a:e723:adee:be82:7fba:ffb2/64 scope global temporary dynamic \ valid_lft 86282sec preferred_lft 81094sec
2: ens33 inet6 fdb6:1d86:d9bd:3:adee:be82:7fba:ffb2/64 scope global temporary dynamic \ valid_lft 86282sec preferred_lft 81094sec
2: ens33 inet6 fdb6:1d86:d9bd:3::21/128 scope global dynamic noprefixroute \ valid_lft 76832sec preferred_lft 76832sec
2: ens33 inet6 2001:db8:450a:e723::21/128 scope global dynamic noprefixroute \ valid_lft 76832sec preferred_lft 76832sec
2: ens33 inet6 fdb6:1d86:d9bd:3:514:cbd9:c55f:8e2a/64 scope global temporary deprecated dynamic \ valid_lft 86282sec preferred_lft 0sec
2: ens33 inet6 fdb6:1d86:d9bd:3:a1fd:1ed9:6211:4268/64 scope global dynamic mngtmpaddr noprefixroute \ valid_lft 86282sec preferred_lft 86282sec
2: ens33 inet6 2001:db8:450a:e723:514:cbd9:c55f:8e2a/64 scope global temporary deprecated dynamic \ valid_lft 86282sec preferred_lft 0sec
2: ens33 inet6 2001:db8:450a:e723:dbc5:1c4e:9e9b:97a2/64 scope global dynamic mngtmpaddr noprefixroute \ valid_lft 86282sec preferred_lft 86282sec
EOF
want_extract_ipv6_global => "2001:db8:450a:e723:adee:be82:7fba:ffb2",
want_ipv6gua_from_if => "2001:db8:450a:e723::21",
want_ipv6ula_from_if => "fdb6:1d86:d9bd:3::21",
},
{ name => "ip -6 -o addr show dev ens33 scope global (most linux static IPv6)",
text => <<EOF,
2: ens33 inet6 2001:db8:450a:e723::101/64 scope global noprefixroute \ valid_lft forever preferred_lft forever
EOF
want_extract_ipv6_global => "2001:db8:450a:e723::101",
want_ipv6gua_from_if => "2001:db8:450a:e723::101",
},
{ name => "ifconfig ens33 (most linux autoconf IPv6 and DHCPv6)",
text => <<EOF,
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 198.51.100.33 netmask 255.255.255.0 broadcast 198.51.100.255
inet6 fdb6:1d86:d9bd:3::21 prefixlen 128 scopeid 0x0<global>
inet6 fe80::32c0:b270:245b:d3b4 prefixlen 64 scopeid 0x20<link>
inet6 fdb6:1d86:d9bd:3:a1fd:1ed9:6211:4268 prefixlen 64 scopeid 0x0<global>
inet6 2001:db8:450a:e723:adee:be82:7fba:ffb2 prefixlen 64 scopeid 0x0<global>
inet6 2001:db8:450a:e723::21 prefixlen 128 scopeid 0x0<global>
inet6 fdb6:1d86:d9bd:3:adee:be82:7fba:ffb2 prefixlen 64 scopeid 0x0<global>
inet6 2001:db8:450a:e723:dbc5:1c4e:9e9b:97a2 prefixlen 64 scopeid 0x0<global>
ether 00:00:00:da:24:b1 txqueuelen 1000 (Ethernet)
RX packets 3782541 bytes 556082941 (556.0 MB)
RX errors 0 dropped 513 overruns 0 frame 0
TX packets 33294 bytes 6838768 (6.8 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
EOF
want_extract_ipv6_global => "2001:db8:450a:e723:adee:be82:7fba:ffb2",
want_ipv6gua_from_if => "2001:db8:450a:e723::21",
want_ipv6ula_from_if => "fdb6:1d86:d9bd:3::21",
want_ipv4_from_if => "198.51.100.33",
},
{ name => "ifconfig ens33 (most linux DHCPv6)",
text => <<EOF,
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 198.51.100.33 netmask 255.255.255.0 broadcast 198.51.100.255
inet6 fdb6:1d86:d9bd:3::21 prefixlen 128 scopeid 0x0<global>
inet6 fe80::32c0:b270:245b:d3b4 prefixlen 64 scopeid 0x20<link>
inet6 2001:db8:450a:e723::21 prefixlen 128 scopeid 0x0<global>
ether 00:00:00:da:24:b1 txqueuelen 1000 (Ethernet)
RX packets 3781554 bytes 555602847 (555.6 MB)
RX errors 0 dropped 513 overruns 0 frame 0
TX packets 32493 bytes 6706131 (6.7 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
EOF
want_extract_ipv6_global => "2001:db8:450a:e723::21",
want_ipv6gua_from_if => "2001:db8:450a:e723::21",
want_ipv6ula_from_if => "fdb6:1d86:d9bd:3::21",
want_ipv4_from_if => "198.51.100.33",
},
{ name => "ifconfig ens33 (most linux static IPv6)",
text => <<EOF,
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 198.51.100.33 netmask 255.255.255.0 broadcast 198.51.100.255
inet6 fe80::32c0:b270:245b:d3b4 prefixlen 64 scopeid 0x20<link>
inet6 2001:db8:450a:e723::101 prefixlen 64 scopeid 0x0<global>
ether 00:00:00:da:24:b1 txqueuelen 1000 (Ethernet)
RX packets 3780219 bytes 554967876 (554.9 MB)
RX errors 0 dropped 513 overruns 0 frame 0
TX packets 31556 bytes 6552122 (6.5 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
EOF
want_extract_ipv6_global => "2001:db8:450a:e723::101",
want_ipv6gua_from_if => "2001:db8:450a:e723::101",
want_ipv4_from_if => "198.51.100.33",
},
{ name => "ifconfig en0 (MacOS IPv4)",
text => <<EOF,
en0: flags=8963<UP,BROADCAST,SMART,RUNNING,PROMISC,SIMPLEX,MULTICAST> mtu 9000
options=50b<RXCSUM,TXCSUM,VLAN_HWTAGGING,AV,CHANNEL_IO>
ether 00:00:00:90:32:8f
inet6 fe80::85b:d150:cdd9:3198%en0 prefixlen 64 secured scopeid 0x4
inet6 2001:db8:450a:e723:1c99:99e2:21d0:79e6 prefixlen 64 autoconf secured
inet6 2001:db8:450a:e723:808d:d894:e4db:157e prefixlen 64 deprecated autoconf temporary
inet6 fdb6:1d86:d9bd:3:837:e1c7:4895:269e prefixlen 64 autoconf secured
inet6 fdb6:1d86:d9bd:3:a0b3:aa4d:9e76:e1ab prefixlen 64 deprecated autoconf temporary
inet 198.51.100.5 netmask 0xffffff00 broadcast 198.51.100.255
inet6 2001:db8:450a:e723:2474:39fd:f5c0:6845 prefixlen 64 autoconf temporary
inet6 fdb6:1d86:d9bd:3:2474:39fd:f5c0:6845 prefixlen 64 autoconf temporary
inet6 fdb6:1d86:d9bd:3::8076 prefixlen 64 dynamic
nd6 options=201<PERFORMNUD,DAD>
media: 1000baseT <full-duplex,flow-control,energy-efficient-ethernet>
status: active
EOF
want_extract_ipv6_global => "2001:db8:450a:e723:1c99:99e2:21d0:79e6",
want_ipv6gua_from_if => "2001:db8:450a:e723:1c99:99e2:21d0:79e6",
want_ipv6ula_from_if => "fdb6:1d86:d9bd:3::8076",
want_ipv4_from_if => "198.51.100.5",
},
{ name => "ifconfig em0 (FreeBSD IPv4)",
text => <<EOF,
em0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500
options=81009b<RXCSUM,TXCSUM,VLAN_MTU,VLAN_HWTAGGING,VLAN_HWCSUM,VLAN_HWFILTER>
ether 00:00:00:9f:c5:32
inet6 fe80::20c:29ff:fe9f:c532%em0 prefixlen 64 scopeid 0x1
inet6 2001:db8:450a:e723:20c:29ff:fe9f:c532 prefixlen 64 autoconf
inet6 fdb6:1d86:d9bd:3:20c:29ff:fe9f:c532 prefixlen 64 autoconf
inet 198.51.100.207 netmask 0xffffff00 broadcast 198.51.100.255
media: Ethernet autoselect (1000baseT <full-duplex>)
status: active
nd6 options=23<PERFORMNUD,ACCEPT_RTADV,AUTO_LINKLOCAL>
EOF
want_extract_ipv6_global => "2001:db8:450a:e723:20c:29ff:fe9f:c532",
want_ipv6gua_from_if => "2001:db8:450a:e723:20c:29ff:fe9f:c532",
want_ipv6ula_from_if => "fdb6:1d86:d9bd:3:20c:29ff:fe9f:c532",
want_ipv4_from_if => "198.51.100.207",
},
{ name => "ifconfig -L en0 (MacOS autoconf IPv6)",
MacOS => 1,
text => <<EOF,
en0: flags=8963<UP,BROADCAST,SMART,RUNNING,PROMISC,SIMPLEX,MULTICAST> mtu 9000
options=50b<RXCSUM,TXCSUM,VLAN_HWTAGGING,AV,CHANNEL_IO>
ether 00:00:00:90:32:8f
inet6 fe80::85b:d150:cdd9:3198%en0 prefixlen 64 secured scopeid 0x4
inet6 2001:db8:450a:e723:1c99:99e2:21d0:79e6 prefixlen 64 autoconf secured pltime 86205 vltime 86205
inet6 2001:db8:450a:e723:808d:d894:e4db:157e prefixlen 64 deprecated autoconf temporary pltime 0 vltime 86205
inet6 fdb6:1d86:d9bd:3:837:e1c7:4895:269e prefixlen 64 autoconf secured pltime 86205 vltime 86205
inet6 fdb6:1d86:d9bd:3:a0b3:aa4d:9e76:e1ab prefixlen 64 deprecated autoconf temporary pltime 0 vltime 86205
inet 198.51.100.5 netmask 0xffffff00 broadcast 198.51.100.255
inet6 2001:db8:450a:e723:2474:39fd:f5c0:6845 prefixlen 64 autoconf temporary pltime 76882 vltime 86205
inet6 fdb6:1d86:d9bd:3:2474:39fd:f5c0:6845 prefixlen 64 autoconf temporary pltime 76882 vltime 86205
inet6 fdb6:1d86:d9bd:3::8076 prefixlen 64 dynamic pltime 78010 vltime 78010
nd6 options=201<PERFORMNUD,DAD>
media: 1000baseT <full-duplex,flow-control,energy-efficient-ethernet>
status: active
EOF
want_extract_ipv6_global => "2001:db8:450a:e723:1c99:99e2:21d0:79e6",
want_ipv6gua_from_if => "2001:db8:450a:e723:1c99:99e2:21d0:79e6",
want_ipv6ula_from_if => "fdb6:1d86:d9bd:3::8076",
want_ipv4_from_if => "198.51.100.5",
},
{ name => "ifconfig -L en0 (MacOS static IPv6)",
MacOS => 1,
text => <<EOF,
en1: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
options=400<CHANNEL_IO>
ether 00:00:00:42:96:eb
inet 198.51.100.199 netmask 0xffffff00 broadcast 198.51.100.255
inet6 fe80::1445:78b9:1d5c:11eb%en1 prefixlen 64 secured scopeid 0x5
inet6 2001:db8:450a:e723::100 prefixlen 64
nd6 options=201<PERFORMNUD,DAD>
media: autoselect
status: active
EOF
want_extract_ipv6_global => "2001:db8:450a:e723::100",
want_ipv6gua_from_if => "2001:db8:450a:e723::100",
want_ipv4_from_if => "198.51.100.199",
},
{ name => "ifconfig -L em0 (FreeBSD autoconf IPv6)",
MacOS => 1,
text => <<EOF,
em0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500
options=81009b<RXCSUM,TXCSUM,VLAN_MTU,VLAN_HWTAGGING,VLAN_HWCSUM,VLAN_HWFILTER>
ether 00:00:00:9f:c5:32
inet6 fe80::20c:29ff:fe9f:c532%em0 prefixlen 64 scopeid 0x1
inet6 2001:db8:450a:e723:20c:29ff:fe9f:c532 prefixlen 64 autoconf pltime 86114 vltime 86114
inet6 fdb6:1d86:d9bd:3:20c:29ff:fe9f:c532 prefixlen 64 autoconf pltime 86114 vltime 86114
inet 198.51.100.207 netmask 0xffffff00 broadcast 198.51.100.255
media: Ethernet autoselect (1000baseT <full-duplex>)
status: active
nd6 options=23<PERFORMNUD,ACCEPT_RTADV,AUTO_LINKLOCAL>
EOF
want_extract_ipv6_global => "2001:db8:450a:e723:20c:29ff:fe9f:c532",
want_ipv6gua_from_if => "2001:db8:450a:e723:20c:29ff:fe9f:c532",
want_ipv6ula_from_if => "fdb6:1d86:d9bd:3:20c:29ff:fe9f:c532",
want_ipv4_from_if => "198.51.100.207",
},
{ name => "ip -4 -o addr show dev eth0 scope global (Buildroot IPv4)",
text => <<EOF,
2: eth0 inet 198.51.157.237/22 brd 255.255.255.255 scope global eth0\ valid_lft forever preferred_lft forever
EOF
want_ipv4_from_if => "198.51.157.237",
},
{ name => "ip -6 -o addr show dev eth0 scope global (Buildroot IPv6)",
text => <<EOF,
2: eth0 inet6 2001:db8:450b:13f:ed44:eb63:b070:212f/128 scope global \ valid_lft forever preferred_lft forever
EOF
want_extract_ipv6_global => "2001:db8:450b:13f:ed44:eb63:b070:212f",
want_ipv6gua_from_if => "2001:db8:450b:13f:ed44:eb63:b070:212f",
},
{ name => "ifconfig eth0 (Busybox)",
text => <<EOF,
eth0 Link encap:Ethernet HWaddr 00:00:00:08:60:B4
inet addr:198.51.157.237 Bcast:255.255.255.255 Mask:255.255.252.0
inet6 addr: fe80::4262:31ff:fe08:60b4/64 Scope:Link
inet6 addr: 2001:db8:450b:13f:ed44:eb63:b070:212f/128 Scope:Global
UP BROADCAST RUNNING MULTICAST MTU:9000 Metric:1
RX packets:33209620 errors:0 dropped:0 overruns:0 frame:0
TX packets:14638979 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:41724254079 (38.8 GiB) TX bytes:3221012240 (2.9 GiB)
EOF
want_extract_ipv6_global => "2001:db8:450b:13f:ed44:eb63:b070:212f",
want_ipv6gua_from_if => "2001:db8:450b:13f:ed44:eb63:b070:212f",
want_ipv4_from_if => "198.51.157.237",
},
);