@@ -306,12 +306,26 @@ ip.isEqual = function (a, b) {
306306} ;
307307
308308ip . isPrivate = function ( addr ) {
309- return / ^ ( : : f { 4 } : ) ? 1 0 \. ( [ 0 - 9 ] { 1 , 3 } ) \. ( [ 0 - 9 ] { 1 , 3 } ) \. ( [ 0 - 9 ] { 1 , 3 } ) $ / i
310- . test ( addr )
309+ // check loopback addresses first
310+ if ( ip . isLoopback ( addr ) ) {
311+ return true ;
312+ }
313+
314+ // ensure the ipv4 address is valid
315+ if ( ! ip . isV6Format ( addr ) ) {
316+ const ipl = ip . normalizeToLong ( addr ) ;
317+ if ( ipl < 0 ) {
318+ throw new Error ( 'invalid ipv4 address' ) ;
319+ }
320+ // normalize the address for the private range checks that follow
321+ addr = ip . fromLong ( ipl ) ;
322+ }
323+
324+ // check private ranges
325+ return / ^ ( : : f { 4 } : ) ? 1 0 \. ( [ 0 - 9 ] { 1 , 3 } ) \. ( [ 0 - 9 ] { 1 , 3 } ) \. ( [ 0 - 9 ] { 1 , 3 } ) $ / i. test ( addr )
311326 || / ^ ( : : f { 4 } : ) ? 1 9 2 \. 1 6 8 \. ( [ 0 - 9 ] { 1 , 3 } ) \. ( [ 0 - 9 ] { 1 , 3 } ) $ / i. test ( addr )
312327 || / ^ ( : : f { 4 } : ) ? 1 7 2 \. ( 1 [ 6 - 9 ] | 2 \d | 3 0 | 3 1 ) \. ( [ 0 - 9 ] { 1 , 3 } ) \. ( [ 0 - 9 ] { 1 , 3 } ) $ / i
313328 . test ( addr )
314- || / ^ ( : : f { 4 } : ) ? 1 2 7 \. ( [ 0 - 9 ] { 1 , 3 } ) \. ( [ 0 - 9 ] { 1 , 3 } ) \. ( [ 0 - 9 ] { 1 , 3 } ) $ / i. test ( addr )
315329 || / ^ ( : : f { 4 } : ) ? 1 6 9 \. 2 5 4 \. ( [ 0 - 9 ] { 1 , 3 } ) \. ( [ 0 - 9 ] { 1 , 3 } ) $ / i. test ( addr )
316330 || / ^ f [ c d ] [ 0 - 9 a - f ] { 2 } : / i. test ( addr )
317331 || / ^ f e 8 0 : / i. test ( addr )
@@ -324,9 +338,16 @@ ip.isPublic = function (addr) {
324338} ;
325339
326340ip . isLoopback = function ( addr ) {
341+ // If addr is an IPv4 address in long integer form (no dots and no colons), convert it
342+ if ( ! / \. / . test ( addr ) && ! / : / . test ( addr ) ) {
343+ addr = ip . fromLong ( Number ( addr ) ) ;
344+ }
345+
327346 return / ^ ( : : f { 4 } : ) ? 1 2 7 \. ( [ 0 - 9 ] { 1 , 3 } ) \. ( [ 0 - 9 ] { 1 , 3 } ) \. ( [ 0 - 9 ] { 1 , 3 } ) /
328347 . test ( addr )
329- || / ^ f e 8 0 : : 1 $ / . test ( addr )
348+ || / ^ 0 1 7 7 \. / . test ( addr )
349+ || / ^ 0 x 7 f \. / i. test ( addr )
350+ || / ^ f e 8 0 : : 1 $ / i. test ( addr )
330351 || / ^ : : 1 $ / . test ( addr )
331352 || / ^ : : $ / . test ( addr ) ;
332353} ;
@@ -420,3 +441,51 @@ ip.fromLong = function (ipl) {
420441 ipl >> 8 & 255 } .${
421442 ipl & 255 } `) ;
422443} ;
444+
445+ ip . normalizeToLong = function ( addr ) {
446+ const parts = addr . split ( '.' ) . map ( part => {
447+ // Handle hexadecimal format
448+ if ( part . startsWith ( '0x' ) || part . startsWith ( '0X' ) ) {
449+ return parseInt ( part , 16 ) ;
450+ }
451+ // Handle octal format (strictly digits 0-7 after a leading zero)
452+ else if ( part . startsWith ( '0' ) && part !== '0' && / ^ [ 0 - 7 ] + $ / . test ( part ) ) {
453+ return parseInt ( part , 8 ) ;
454+ }
455+ // Handle decimal format, reject invalid leading zeros
456+ else if ( / ^ [ 1 - 9 ] \d * $ / . test ( part ) || part === '0' ) {
457+ return parseInt ( part , 10 ) ;
458+ }
459+ // Return NaN for invalid formats to indicate parsing failure
460+ else {
461+ return NaN ;
462+ }
463+ } ) ;
464+
465+ if ( parts . some ( isNaN ) ) return - 1 ; // Indicate error with -1
466+
467+ let val = 0 ;
468+ const n = parts . length ;
469+
470+ switch ( n ) {
471+ case 1 :
472+ val = parts [ 0 ] ;
473+ break ;
474+ case 2 :
475+ if ( parts [ 0 ] > 0xff || parts [ 1 ] > 0xffffff ) return - 1 ;
476+ val = ( parts [ 0 ] << 24 ) | ( parts [ 1 ] & 0xffffff ) ;
477+ break ;
478+ case 3 :
479+ if ( parts [ 0 ] > 0xff || parts [ 1 ] > 0xff || parts [ 2 ] > 0xffff ) return - 1 ;
480+ val = ( parts [ 0 ] << 24 ) | ( parts [ 1 ] << 16 ) | ( parts [ 2 ] & 0xffff ) ;
481+ break ;
482+ case 4 :
483+ if ( parts . some ( part => part > 0xff ) ) return - 1 ;
484+ val = ( parts [ 0 ] << 24 ) | ( parts [ 1 ] << 16 ) | ( parts [ 2 ] << 8 ) | parts [ 3 ] ;
485+ break ;
486+ default :
487+ return - 1 ; // Error case
488+ }
489+
490+ return val >>> 0 ;
491+ } ;
0 commit comments