ip-navigator
Version:
A tool for IP address manipulation and calculation
246 lines (245 loc) • 9.29 kB
JavaScript
import { isValidIPAddress } from "../validation/index.js";
import { ipToInteger, integerToIP } from "../conversion/index.js";
// Pre-calculate private and special IP range boundaries for performance
const IP_RANGES = {
PRIVATE_10_START: ipToInteger("10.0.0.0"),
PRIVATE_10_END: ipToInteger("10.255.255.255"),
PRIVATE_172_START: ipToInteger("172.16.0.0"),
PRIVATE_172_END: ipToInteger("172.31.255.255"),
PRIVATE_192_START: ipToInteger("192.168.0.0"),
PRIVATE_192_END: ipToInteger("192.168.255.255"),
LOOPBACK_START: ipToInteger("127.0.0.0"),
LOOPBACK_END: ipToInteger("127.255.255.255"),
LINK_LOCAL_START: ipToInteger("169.254.0.0"),
LINK_LOCAL_END: ipToInteger("169.254.255.255"),
MULTICAST_START: ipToInteger("224.0.0.0"),
MULTICAST_END: ipToInteger("239.255.255.255"),
RESERVED_START: ipToInteger("240.0.0.0"),
RESERVED_END: ipToInteger("255.255.255.255"),
};
/**
* Returns the next IP address in sequential order.
*
* This function takes an IPv4 address and returns the next sequential IP address.
* It handles rollovers within octets and to the next octet.
*
* @param {string} ipAddress - The starting IP address.
* @returns {string} The next sequential IP address.
*
* @example
* getNextIPAddress('192.168.1.1'); // returns '192.168.1.2'
* getNextIPAddress('192.168.1.255'); // returns '192.168.2.0'
* getNextIPAddress('255.255.255.255'); // returns '0.0.0.0'
*
* @remarks
* - The function assumes that the input is a valid IPv4 address.
* - It correctly handles rollovers, including from 255 to 0 in any octet.
*/
export const getNextIPAddress = (ipAddress) => {
if (!isValidIPAddress(ipAddress)) {
throw new Error("Invalid IP address");
}
const intIP = ipToInteger(ipAddress);
if (intIP === 4294967295) {
return "0.0.0.0";
}
const nextIntIP = intIP + 1;
return integerToIP(nextIntIP);
};
/**
* Returns the previous IP address in sequential order.
*
* This function takes an IPv4 address and returns the previous sequential IP address.
* It handles rollovers within octets and to the previous octet.
*
* @param {string} ipAddress - The starting IP address.
* @returns {string} The previous sequential IP address.
*
* @example
* getPreviousIPAddress('192.168.1.1'); // returns '192.168.1.0'
* getPreviousIPAddress('192.168.2.0'); // returns '192.168.1.255'
* getPreviousIPAddress('0.0.0.0'); // returns '255.255.255.255'
*
* @remarks
* - The function assumes that the input is a valid IPv4 address.
* - It correctly handles rollovers, including from 0 to 255 in any octet.
*/
export const getPreviousIPAddress = (ipAddress) => {
if (!isValidIPAddress(ipAddress)) {
throw new Error("Invalid IP address");
}
const intIP = ipToInteger(ipAddress);
if (intIP === 0) {
return "255.255.255.255";
}
const prevIntIP = intIP - 1;
return integerToIP(prevIntIP);
};
/**
* Checks if an IP address is within a given subnet.
*
* This function determines whether a given IP address falls within the range
* defined by a network address and subnet mask.
*
* @param {string} ipAddress - The IP address to check.
* @param {string} networkAddress - The network address of the subnet.
* @param {string} subnetMask - The subnet mask of the network.
* @returns {boolean} True if the IP address is in the subnet, false otherwise.
*
* @example
* isIPAddressInSubnet('192.168.1.50', '192.168.1.0', '255.255.255.0'); // returns true
* isIPAddressInSubnet('192.168.2.1', '192.168.1.0', '255.255.255.0'); // returns false
*
* @remarks
* - The function assumes all inputs are valid IPv4 addresses or subnet masks.
* - It performs a bitwise AND operation between the IP and the subnet mask to determine if it's in the subnet.
*/
export const isIPAddressInSubnet = (ipAddress, networkAddress, subnetMask) => {
if (!isValidIPAddress(ipAddress) ||
!isValidIPAddress(networkAddress) ||
!isValidIPAddress(subnetMask)) {
throw new Error("Invalid IP address or subnet mask");
}
const ip = ipToInteger(ipAddress);
const network = ipToInteger(networkAddress);
const mask = ipToInteger(subnetMask);
return (ip & mask) === (network & mask);
};
/**
* Checks if an IP address is a public IP address.
*
* This function determines whether a given IP address is a public IP address,
* which is routable on the global Internet.
*
* @param {string} ipAddress - The IP address to check.
* @returns {boolean} True if the IP address is public, false otherwise.
*
* @example
* isPublicIP('8.8.8.8'); // returns true
* isPublicIP('192.168.1.1'); // returns false
*
* @remarks
* - The function assumes the input is a valid IPv4 address.
* - It checks against known ranges of private, loopback, and special-use IP addresses.
*/
export const isPublicIP = (ipAddress) => {
if (!isValidIPAddress(ipAddress)) {
throw new Error("Invalid IP address");
}
const ip = ipToInteger(ipAddress);
// Check against private IP ranges
if ((ip >= IP_RANGES.PRIVATE_10_START && ip <= IP_RANGES.PRIVATE_10_END) ||
(ip >= IP_RANGES.PRIVATE_172_START && ip <= IP_RANGES.PRIVATE_172_END) ||
(ip >= IP_RANGES.PRIVATE_192_START && ip <= IP_RANGES.PRIVATE_192_END)) {
return false;
}
// Check against loopback IP range
if (ip >= IP_RANGES.LOOPBACK_START && ip <= IP_RANGES.LOOPBACK_END) {
return false;
}
// Check against link-local IP range
if (ip >= IP_RANGES.LINK_LOCAL_START && ip <= IP_RANGES.LINK_LOCAL_END) {
return false;
}
// Check other special-use IP ranges
if (ip >= IP_RANGES.MULTICAST_START && ip <= IP_RANGES.MULTICAST_END) {
return false; // Multicast
}
if (ip >= IP_RANGES.RESERVED_START && ip <= IP_RANGES.RESERVED_END) {
return false; // Reserved
}
return true;
};
/**
* Checks if an IP address is a private IP address.
*
* This function determines whether a given IP address is a private IP address,
* which is used for local networks and not routable on the global Internet.
*
* @param {string} ipAddress - The IP address to check.
* @returns {boolean} True if the IP address is private, false otherwise.
*
* @example
* isPrivateIP('192.168.1.1'); // returns true
* isPrivateIP('8.8.8.8'); // returns false
*
* @remarks
* - The function assumes the input is a valid IPv4 address.
* - It checks against known ranges of private IP addresses (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16).
*/
export const isPrivateIP = (ipAddress) => {
if (!isValidIPAddress(ipAddress)) {
throw new Error("Invalid IP address");
}
const ip = ipToInteger(ipAddress);
return ((ip >= IP_RANGES.PRIVATE_10_START && ip <= IP_RANGES.PRIVATE_10_END) ||
(ip >= IP_RANGES.PRIVATE_172_START && ip <= IP_RANGES.PRIVATE_172_END) ||
(ip >= IP_RANGES.PRIVATE_192_START && ip <= IP_RANGES.PRIVATE_192_END));
};
/**
* Generates an array of IP addresses within a specified range.
*
* This function takes a start and end IP address and returns an array of all
* IP addresses within that range, inclusive.
*
* @param {string} startIP - The starting IP address of the range.
* @param {string} endIP - The ending IP address of the range.
* @returns {string[]} An array of IP addresses within the specified range.
*
* @example
* getIPRange('192.168.1.1', '192.168.1.3');
* // returns ['192.168.1.1', '192.168.1.2', '192.168.1.3']
*
* @remarks
* - The function assumes both inputs are valid IPv4 addresses.
* - The start IP should be less than or equal to the end IP.
* - For large ranges, be aware of potential memory usage.
*/
export const getIPRange = (startIP, endIP) => {
if (!isValidIPAddress(startIP) || !isValidIPAddress(endIP)) {
throw new Error("Invalid IP address");
}
const start = ipToInteger(startIP);
const end = ipToInteger(endIP);
if (start > end) {
throw new Error("Start IP must be less than or equal to end IP");
}
const range = [];
for (let i = start; i <= end; i++) {
range.push(integerToIP(i));
}
return range;
};
/**
* Compares two IP addresses.
*
* This function compares two IPv4 addresses and returns:
* -1 if the first IP is less than the second,
* 0 if they are equal,
* 1 if the first IP is greater than the second.
*
* @param {string} ip1 - The first IP address to compare.
* @param {string} ip2 - The second IP address to compare.
* @returns {-1 | 0 | 1} The result of the comparison.
*
* @example
* compareIPAddresses('192.168.1.1', '192.168.1.2'); // returns -1
* compareIPAddresses('192.168.1.1', '192.168.1.1'); // returns 0
* compareIPAddresses('192.168.1.2', '192.168.1.1'); // returns 1
*
* @remarks
* - The function assumes both inputs are valid IPv4 addresses.
* - It compares the IP addresses numerically, not lexicographically.
*/
export const compareIPAddresses = (ip1, ip2) => {
if (!isValidIPAddress(ip1) || !isValidIPAddress(ip2)) {
throw new Error("Invalid IP address");
}
const int1 = ipToInteger(ip1);
const int2 = ipToInteger(ip2);
if (int1 < int2)
return -1;
if (int1 > int2)
return 1;
return 0;
};