#!/usr/bin/perl -w
sub
ipv6_zeroize {
my
(
$s
) =
@_
;
if
(
$s
!~ /::/) {
return
$s
;
};
my
(
@double_colon_parts
) =
split
(/::/,
$s
);
return
undef
if
(
$#double_colon_parts
> 1);
my
(
@hextets
) =
split
(/:/,
$s
);
if
(
$#hextets
< 7) {
my
(
@full
) = ();
my
(
$found
) =
undef
;
foreach
(
@hextets
) {
if
(
$_
eq
''
) {
if
(
$found
) {
push
(
@full
,
'0'
);
}
else
{
push
(
@full
, (
'0'
) x (8 -
$#hextets
));
$found
= 1;
};
}
elsif
(
$_
ne
''
) {
s/^0+//g;
$_
=
'0'
if
(
$_
eq
''
);
push
(
@full
,
$_
);
};
};
push
(
@full
, (
'0'
) x (7 -
$#hextets
))
if
(!
$found
);
return
join
(
':'
,
@full
);
}
else
{
return
undef
;
};
};
sub
ipv6_normalize {
my
(
$s
) =
@_
;
$s
= ipv6_zeroize(
$s
)
if
(
$s
=~ /::/);
my
(
@hextets
) =
split
(/:/,
$s
);
return
undef
if
(
$#hextets
!= 7);
my
(
@trimmed_hextets
) = ();
my
(
@zero_run
);
my
(
$max_zero_run
) = 0;
foreach
(
@hextets
) {
s/^0//g;
$_
=
'0'
if
(
$_
eq
''
);
push
(
@trimmed_hextets
,
$_
);
my
(
$cur_zero_run
) = (
$_
ne
'0'
? 0 : (
$#zero_run
== -1 ? 1 :
$zero_run
[
$#zero_run
] + 1));
push
(
@zero_run
,
$cur_zero_run
);
$max_zero_run
=
$cur_zero_run
if
(
$cur_zero_run
>
$max_zero_run
);
};
return
join
(
':'
,
@trimmed_hextets
)
if
(
$max_zero_run
== 0);
my
(
@zero_runned_hextets
) = ();
my
$cur_zero_run
=
undef
;
my
$found_zero_run
=
undef
;
foreach
(0..
$#trimmed_hextets
) {
if
(
$zero_run
[
$_
]) {
$cur_zero_run
=
$zero_run
[
$_
];
}
else
{
if
(
defined
(
$cur_zero_run
)) {
if
(
$cur_zero_run
==
$max_zero_run
&& !
$found_zero_run
) {
$found_zero_run
= 1;
push
(
@zero_runned_hextets
, (
$#zero_runned_hextets
== -1 ?
':'
:
''
));
}
else
{
push
(
@zero_runned_hextets
, (
'0'
) x
$cur_zero_run
);
};
};
push
(
@zero_runned_hextets
,
$trimmed_hextets
[
$_
]);
$cur_zero_run
=
undef
;
};
};
if
(
defined
(
$cur_zero_run
)) {
if
(
$cur_zero_run
==
$max_zero_run
&& !
$found_zero_run
) {
$found_zero_run
= 1;
push
(
@zero_runned_hextets
, (
$#zero_runned_hextets
== -1 ?
'::'
:
':'
)); # trailing :
}
else
{
push
(
@zero_runned_hextets
, (
'0'
) x
$cur_zero_run
);
};
};
return
join
(
':'
,
@zero_runned_hextets
);
};
sub
_test_zero_fill {
my
(
$in
,
$out
) =
@_
;
my
(
$trial
) = ipv6_zeroize(
$in
);
$out
//=
"undef"
;
$trial
//=
"undef"
;
if
(
$trial
eq
$out
) {
print
"zf ok: $in -> $out\n"
;
}
else
{
print
"zf NO: $in -> $out but got $trial\n"
;
};
}
sub
_test_zero_remove {
my
(
$in
,
$out
) =
@_
;
return
if
(!
defined
(
$out
));
my
(
$trial
) = ipv6_normalize(
$in
);
$out
//=
"undef"
;
$trial
//=
"undef"
;
if
(
$trial
eq
$out
) {
print
"zr ok: $in -> $out\n"
;
}
else
{
print
"zr NO: $in -> $out but got $trial\n"
;
};
}
sub
_test_both {
my
(
$in
,
$out
) =
@_
;
_test_zero_fill(
$in
,
$out
);
_test_zero_remove(
$out
,
$in
);
};
sub
_test_ipv6 {
_test_both(
"1:2:3:4:5:6:7:8"
,
"1:2:3:4:5:6:7:8"
);
_test_zero_fill(
"1:2:3:4:5:6:7:0"
,
"1:2:3:4:5:6:7:0"
);
_test_both(
"1:2:3:4:5:6:7::"
,
"1:2:3:4:5:6:7:0"
);
_test_both(
"1:2:3:4:5:6::"
,
"1:2:3:4:5:6:0:0"
);
_test_zero_fill(
"1:002:3:4:5:6::"
,
"1:2:3:4:5:6:0:0"
);
_test_zero_fill(
"1:0000:3:4:5:6::"
,
"1:0:3:4:5:6:0:0"
);
_test_both(
"1:2:3:4:5::8"
,
"1:2:3:4:5:0:0:8"
);
_test_both(
"1:2:3:4::8"
,
"1:2:3:4:0:0:0:8"
);
_test_both(
"1:2:3:4::7:8"
,
"1:2:3:4:0:0:7:8"
);
_test_both(
"1::8"
,
"1:0:0:0:0:0:0:8"
);
_test_both(
"::1"
,
"0:0:0:0:0:0:0:1"
);
_test_both(
"1::"
,
"1:0:0:0:0:0:0:0"
);
_test_both(
"::"
,
"0:0:0:0:0:0:0:0"
);
_test_both(
"1:2::6:0:0:8"
,
"1:2:0:0:6:0:0:8"
);
_test_zero_remove(
"1:002::6:0:0:8"
,
"1:2:0:0:6:0:0:8"
);
_test_zero_fill(
"1:2:0:0:6::8"
,
"1:2:0:0:6:0:0:8"
);
_test_zero_fill(
"1:2::6::8"
,
undef
);
};
1;