source: node_modules/ip-address/src/ipv4.ts@ 81bc7da

finki-main main
Last change on this file since 81bc7da was 81bc7da, checked in by Klimentina Efremova <klimentina08642@…>, 3 months ago

Initial commit

  • Property mode set to 100644
File size: 9.5 KB
Line 
1/* eslint-disable no-param-reassign */
2
3import * as common from './common';
4import * as constants from './v4/constants';
5import { AddressError } from './address-error';
6
7/**
8 * Represents an IPv4 address
9 * @class Address4
10 * @param {string} address - An IPv4 address string
11 */
12export class Address4 {
13 address: string;
14 addressMinusSuffix?: string;
15 groups: number = constants.GROUPS;
16 parsedAddress: string[] = [];
17 parsedSubnet: string = '';
18 subnet: string = '/32';
19 subnetMask: number = 32;
20 v4: boolean = true;
21
22 constructor(address: string) {
23 this.address = address;
24
25 const subnet = constants.RE_SUBNET_STRING.exec(address);
26
27 if (subnet) {
28 this.parsedSubnet = subnet[0].replace('/', '');
29 this.subnetMask = parseInt(this.parsedSubnet, 10);
30 this.subnet = `/${this.subnetMask}`;
31
32 if (this.subnetMask < 0 || this.subnetMask > constants.BITS) {
33 throw new AddressError('Invalid subnet mask.');
34 }
35
36 address = address.replace(constants.RE_SUBNET_STRING, '');
37 }
38
39 this.addressMinusSuffix = address;
40
41 this.parsedAddress = this.parse(address);
42 }
43
44 static isValid(address: string): boolean {
45 try {
46 // eslint-disable-next-line no-new
47 new Address4(address);
48
49 return true;
50 } catch (e) {
51 return false;
52 }
53 }
54
55 /*
56 * Parses a v4 address
57 */
58 parse(address: string) {
59 const groups = address.split('.');
60
61 if (!address.match(constants.RE_ADDRESS)) {
62 throw new AddressError('Invalid IPv4 address.');
63 }
64
65 return groups;
66 }
67
68 /**
69 * Returns the correct form of an address
70 * @memberof Address4
71 * @instance
72 * @returns {String}
73 */
74 correctForm(): string {
75 return this.parsedAddress.map((part) => parseInt(part, 10)).join('.');
76 }
77
78 /**
79 * Returns true if the address is correct, false otherwise
80 * @memberof Address4
81 * @instance
82 * @returns {Boolean}
83 */
84 isCorrect = common.isCorrect(constants.BITS);
85
86 /**
87 * Converts a hex string to an IPv4 address object
88 * @memberof Address4
89 * @static
90 * @param {string} hex - a hex string to convert
91 * @returns {Address4}
92 */
93 static fromHex(hex: string): Address4 {
94 const padded = hex.replace(/:/g, '').padStart(8, '0');
95 const groups = [];
96 let i;
97
98 for (i = 0; i < 8; i += 2) {
99 const h = padded.slice(i, i + 2);
100
101 groups.push(parseInt(h, 16));
102 }
103
104 return new Address4(groups.join('.'));
105 }
106
107 /**
108 * Converts an integer into a IPv4 address object
109 * @memberof Address4
110 * @static
111 * @param {integer} integer - a number to convert
112 * @returns {Address4}
113 */
114 static fromInteger(integer: number): Address4 {
115 return Address4.fromHex(integer.toString(16));
116 }
117
118 /**
119 * Return an address from in-addr.arpa form
120 * @memberof Address4
121 * @static
122 * @param {string} arpaFormAddress - an 'in-addr.arpa' form ipv4 address
123 * @returns {Adress4}
124 * @example
125 * var address = Address4.fromArpa(42.2.0.192.in-addr.arpa.)
126 * address.correctForm(); // '192.0.2.42'
127 */
128 static fromArpa(arpaFormAddress: string): Address4 {
129 // remove ending ".in-addr.arpa." or just "."
130 const leader = arpaFormAddress.replace(/(\.in-addr\.arpa)?\.$/, '');
131
132 const address = leader.split('.').reverse().join('.');
133
134 return new Address4(address);
135 }
136
137 /**
138 * Converts an IPv4 address object to a hex string
139 * @memberof Address4
140 * @instance
141 * @returns {String}
142 */
143 toHex(): string {
144 return this.parsedAddress.map((part) => common.stringToPaddedHex(part)).join(':');
145 }
146
147 /**
148 * Converts an IPv4 address object to an array of bytes
149 * @memberof Address4
150 * @instance
151 * @returns {Array}
152 */
153 toArray(): number[] {
154 return this.parsedAddress.map((part) => parseInt(part, 10));
155 }
156
157 /**
158 * Converts an IPv4 address object to an IPv6 address group
159 * @memberof Address4
160 * @instance
161 * @returns {String}
162 */
163 toGroup6(): string {
164 const output = [];
165 let i;
166
167 for (i = 0; i < constants.GROUPS; i += 2) {
168 output.push(
169 `${common.stringToPaddedHex(this.parsedAddress[i])}${common.stringToPaddedHex(
170 this.parsedAddress[i + 1],
171 )}`,
172 );
173 }
174
175 return output.join(':');
176 }
177
178 /**
179 * Returns the address as a `bigint`
180 * @memberof Address4
181 * @instance
182 * @returns {bigint}
183 */
184 bigInt(): bigint {
185 return BigInt(`0x${this.parsedAddress.map((n) => common.stringToPaddedHex(n)).join('')}`);
186 }
187
188 /**
189 * Helper function getting start address.
190 * @memberof Address4
191 * @instance
192 * @returns {bigint}
193 */
194 _startAddress(): bigint {
195 return BigInt(`0b${this.mask() + '0'.repeat(constants.BITS - this.subnetMask)}`);
196 }
197
198 /**
199 * The first address in the range given by this address' subnet.
200 * Often referred to as the Network Address.
201 * @memberof Address4
202 * @instance
203 * @returns {Address4}
204 */
205 startAddress(): Address4 {
206 return Address4.fromBigInt(this._startAddress());
207 }
208
209 /**
210 * The first host address in the range given by this address's subnet ie
211 * the first address after the Network Address
212 * @memberof Address4
213 * @instance
214 * @returns {Address4}
215 */
216 startAddressExclusive(): Address4 {
217 const adjust = BigInt('1');
218 return Address4.fromBigInt(this._startAddress() + adjust);
219 }
220
221 /**
222 * Helper function getting end address.
223 * @memberof Address4
224 * @instance
225 * @returns {bigint}
226 */
227 _endAddress(): bigint {
228 return BigInt(`0b${this.mask() + '1'.repeat(constants.BITS - this.subnetMask)}`);
229 }
230
231 /**
232 * The last address in the range given by this address' subnet
233 * Often referred to as the Broadcast
234 * @memberof Address4
235 * @instance
236 * @returns {Address4}
237 */
238 endAddress(): Address4 {
239 return Address4.fromBigInt(this._endAddress());
240 }
241
242 /**
243 * The last host address in the range given by this address's subnet ie
244 * the last address prior to the Broadcast Address
245 * @memberof Address4
246 * @instance
247 * @returns {Address4}
248 */
249 endAddressExclusive(): Address4 {
250 const adjust = BigInt('1');
251 return Address4.fromBigInt(this._endAddress() - adjust);
252 }
253
254 /**
255 * Converts a BigInt to a v4 address object
256 * @memberof Address4
257 * @static
258 * @param {bigint} bigInt - a BigInt to convert
259 * @returns {Address4}
260 */
261 static fromBigInt(bigInt: bigint): Address4 {
262 return Address4.fromHex(bigInt.toString(16));
263 }
264
265 /**
266 * Convert a byte array to an Address4 object
267 * @memberof Address4
268 * @static
269 * @param {Array<number>} bytes - an array of 4 bytes (0-255)
270 * @returns {Address4}
271 */
272 static fromByteArray(bytes: Array<number>): Address4 {
273 if (bytes.length !== 4) {
274 throw new AddressError('IPv4 addresses require exactly 4 bytes');
275 }
276
277 // Validate that all bytes are within valid range (0-255)
278 for (let i = 0; i < bytes.length; i++) {
279 if (!Number.isInteger(bytes[i]) || bytes[i] < 0 || bytes[i] > 255) {
280 throw new AddressError('All bytes must be integers between 0 and 255');
281 }
282 }
283
284 return this.fromUnsignedByteArray(bytes);
285 }
286
287 /**
288 * Convert an unsigned byte array to an Address4 object
289 * @memberof Address4
290 * @static
291 * @param {Array<number>} bytes - an array of 4 unsigned bytes (0-255)
292 * @returns {Address4}
293 */
294 static fromUnsignedByteArray(bytes: Array<number>): Address4 {
295 if (bytes.length !== 4) {
296 throw new AddressError('IPv4 addresses require exactly 4 bytes');
297 }
298
299 const address = bytes.join('.');
300 return new Address4(address);
301 }
302
303 /**
304 * Returns the first n bits of the address, defaulting to the
305 * subnet mask
306 * @memberof Address4
307 * @instance
308 * @returns {String}
309 */
310 mask(mask?: number): string {
311 if (mask === undefined) {
312 mask = this.subnetMask;
313 }
314
315 return this.getBitsBase2(0, mask);
316 }
317
318 /**
319 * Returns the bits in the given range as a base-2 string
320 * @memberof Address4
321 * @instance
322 * @returns {string}
323 */
324 getBitsBase2(start: number, end: number): string {
325 return this.binaryZeroPad().slice(start, end);
326 }
327
328 /**
329 * Return the reversed ip6.arpa form of the address
330 * @memberof Address4
331 * @param {Object} options
332 * @param {boolean} options.omitSuffix - omit the "in-addr.arpa" suffix
333 * @instance
334 * @returns {String}
335 */
336 reverseForm(options?: common.ReverseFormOptions): string {
337 if (!options) {
338 options = {};
339 }
340
341 const reversed = this.correctForm().split('.').reverse().join('.');
342
343 if (options.omitSuffix) {
344 return reversed;
345 }
346
347 return `${reversed}.in-addr.arpa.`;
348 }
349
350 /**
351 * Returns true if the given address is in the subnet of the current address
352 * @memberof Address4
353 * @instance
354 * @returns {boolean}
355 */
356 isInSubnet = common.isInSubnet;
357
358 /**
359 * Returns true if the given address is a multicast address
360 * @memberof Address4
361 * @instance
362 * @returns {boolean}
363 */
364 isMulticast(): boolean {
365 return this.isInSubnet(new Address4('224.0.0.0/4'));
366 }
367
368 /**
369 * Returns a zero-padded base-2 string representation of the address
370 * @memberof Address4
371 * @instance
372 * @returns {string}
373 */
374 binaryZeroPad(): string {
375 return this.bigInt().toString(2).padStart(constants.BITS, '0');
376 }
377
378 /**
379 * Groups an IPv4 address for inclusion at the end of an IPv6 address
380 * @returns {String}
381 */
382 groupForV6(): string {
383 const segments = this.parsedAddress;
384
385 return this.address.replace(
386 constants.RE_ADDRESS,
387 `<span class="hover-group group-v4 group-6">${segments
388 .slice(0, 2)
389 .join('.')}</span>.<span class="hover-group group-v4 group-7">${segments
390 .slice(2, 4)
391 .join('.')}</span>`,
392 );
393 }
394}
Note: See TracBrowser for help on using the repository browser.