@@ -28,86 +28,37 @@ import assertString from './util/assertString';
2828 where the interface "ne0" belongs to the 1st link, "pvc1.3" belongs
2929 to the 5th link, and "interface10" belongs to the 10th organization.
3030 * * */
31- const ipv4Maybe = / ^ ( ( [ 0 - 9 ] | [ 1 - 9 ] [ 0 - 9 ] | 1 [ 0 - 9 ] { 2 } | 2 [ 0 - 4 ] [ 0 - 9 ] | 2 5 [ 0 - 5 ] ) \. ) { 3 } ( [ 0 - 9 ] | [ 1 - 9 ] [ 0 - 9 ] | 1 [ 0 - 9 ] { 2 } | 2 [ 0 - 4 ] [ 0 - 9 ] | 2 5 [ 0 - 5 ] ) $ / ;
32- const ipv6Block = / ^ [ 0 - 9 A - F ] { 1 , 4 } $ / i;
31+ const IPv4SegmentFormat = '(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])' ;
32+ const IPv4AddressFormat = `(${ IPv4SegmentFormat } [.]){3}${ IPv4SegmentFormat } ` ;
33+ const IPv4AddressRegExp = new RegExp ( `^${ IPv4AddressFormat } $` ) ;
34+
35+ const IPv6SegmentFormat = '(?:[0-9a-fA-F]{1,4})' ;
36+ const IPv6AddressRegExp = new RegExp ( '^(' +
37+ `(?:${ IPv6SegmentFormat } :){7}(?:${ IPv6SegmentFormat } |:)|` +
38+ `(?:${ IPv6SegmentFormat } :){6}(?:${ IPv4AddressFormat } |:${ IPv6SegmentFormat } |:)|` +
39+ `(?:${ IPv6SegmentFormat } :){5}(?::${ IPv4AddressFormat } |(:${ IPv6SegmentFormat } ){1,2}|:)|` +
40+ `(?:${ IPv6SegmentFormat } :){4}(?:(:${ IPv6SegmentFormat } ){0,1}:${ IPv4AddressFormat } |(:${ IPv6SegmentFormat } ){1,3}|:)|` +
41+ `(?:${ IPv6SegmentFormat } :){3}(?:(:${ IPv6SegmentFormat } ){0,2}:${ IPv4AddressFormat } |(:${ IPv6SegmentFormat } ){1,4}|:)|` +
42+ `(?:${ IPv6SegmentFormat } :){2}(?:(:${ IPv6SegmentFormat } ){0,3}:${ IPv4AddressFormat } |(:${ IPv6SegmentFormat } ){1,5}|:)|` +
43+ `(?:${ IPv6SegmentFormat } :){1}(?:(:${ IPv6SegmentFormat } ){0,4}:${ IPv4AddressFormat } |(:${ IPv6SegmentFormat } ){1,6}|:)|` +
44+ `(?::((?::${ IPv6SegmentFormat } ){0,5}:${ IPv4AddressFormat } |(?::${ IPv6SegmentFormat } ){1,7}|:))` +
45+ ')(%[0-9a-zA-Z-.:]{1,})?$' ) ;
3346
3447export default function isIP ( str , version = '' ) {
3548 assertString ( str ) ;
3649 version = String ( version ) ;
3750 if ( ! version ) {
3851 return isIP ( str , 4 ) || isIP ( str , 6 ) ;
39- } else if ( version === '4' ) {
40- if ( ! ipv4Maybe . test ( str ) ) {
52+ }
53+ if ( version === '4' ) {
54+ if ( ! IPv4AddressRegExp . test ( str ) ) {
4155 return false ;
4256 }
4357 const parts = str . split ( '.' ) . sort ( ( a , b ) => a - b ) ;
4458 return parts [ 3 ] <= 255 ;
45- } else if ( version === '6' ) {
46- let addressAndZone = [ str ] ;
47- // ipv6 addresses could have scoped architecture
48- // according to https://tools.ietf.org/html/rfc4007#section-11
49- if ( str . includes ( '%' ) ) {
50- addressAndZone = str . split ( '%' ) ;
51- if ( addressAndZone . length !== 2 ) {
52- // it must be just two parts
53- return false ;
54- }
55- if ( ! addressAndZone [ 0 ] . includes ( ':' ) ) {
56- // the first part must be the address
57- return false ;
58- }
59-
60- if ( addressAndZone [ 1 ] === '' ) {
61- // the second part must not be empty
62- return false ;
63- }
64- }
65-
66- const blocks = addressAndZone [ 0 ] . split ( ':' ) ;
67- let foundOmissionBlock = false ; // marker to indicate ::
68-
69- // At least some OS accept the last 32 bits of an IPv6 address
70- // (i.e. 2 of the blocks) in IPv4 notation, and RFC 3493 says
71- // that '::ffff:a.b.c.d' is valid for IPv4-mapped IPv6 addresses,
72- // and '::a.b.c.d' is deprecated, but also valid.
73- const foundIPv4TransitionBlock = isIP ( blocks [ blocks . length - 1 ] , 4 ) ;
74- const expectedNumberOfBlocks = foundIPv4TransitionBlock ? 7 : 8 ;
75-
76- if ( blocks . length > expectedNumberOfBlocks ) {
77- return false ;
78- }
79- // initial or final ::
80- if ( str === '::' ) {
81- return true ;
82- } else if ( str . substr ( 0 , 2 ) === '::' ) {
83- blocks . shift ( ) ;
84- blocks . shift ( ) ;
85- foundOmissionBlock = true ;
86- } else if ( str . substr ( str . length - 2 ) === '::' ) {
87- blocks . pop ( ) ;
88- blocks . pop ( ) ;
89- foundOmissionBlock = true ;
90- }
91-
92- for ( let i = 0 ; i < blocks . length ; ++ i ) {
93- // test for a :: which can not be at the string start/end
94- // since those cases have been handled above
95- if ( blocks [ i ] === '' && i > 0 && i < blocks . length - 1 ) {
96- if ( foundOmissionBlock ) {
97- return false ; // multiple :: in address
98- }
99- foundOmissionBlock = true ;
100- } else if ( foundIPv4TransitionBlock && i === blocks . length - 1 ) {
101- // it has been checked before that the last
102- // block is a valid IPv4 address
103- } else if ( ! ipv6Block . test ( blocks [ i ] ) ) {
104- return false ;
105- }
106- }
107- if ( foundOmissionBlock ) {
108- return blocks . length >= 1 ;
109- }
110- return blocks . length === expectedNumberOfBlocks ;
59+ }
60+ if ( version === '6' ) {
61+ return ! ! IPv6AddressRegExp . test ( str ) ;
11162 }
11263 return false ;
11364}
0 commit comments