|
|
@@ -1,6 +1,73 @@
|
|
|
import {AddressType, CommandReplyType, CommandType} from "./constants.js";
|
|
|
import ipaddr from 'ipaddr.js';
|
|
|
|
|
|
+function parseAddress(chunk: Buffer):[string, number] {
|
|
|
+ let address = [], port;
|
|
|
+ const addressType = chunk.readUint8(3);
|
|
|
+
|
|
|
+ switch (addressType) {
|
|
|
+ case AddressType.IPv4:
|
|
|
+ address.push(chunk.readUint8(4).toString());
|
|
|
+ address.push(chunk.readUint8(5).toString());
|
|
|
+ address.push(chunk.readUint8(6).toString());
|
|
|
+ address.push(chunk.readUint8(7).toString());
|
|
|
+ port = chunk.readUInt16BE(8);
|
|
|
+ return [address.join('.'), port];
|
|
|
+ case AddressType.Domain:
|
|
|
+ const domainLength: number = chunk.readUint8(4);
|
|
|
+ let i:number;
|
|
|
+ for(i = 5; i < 5 + domainLength; i++) {
|
|
|
+ address.push(String.fromCharCode(chunk.readUint8(i)));
|
|
|
+ }
|
|
|
+ port = chunk.readUInt16BE(i);
|
|
|
+ return [address.join(''), port];
|
|
|
+ case AddressType.IPv6:
|
|
|
+ let byteArray: number[] = [];
|
|
|
+ for(let i = 4; i < 20; i++) {
|
|
|
+ byteArray.push(chunk.readUint8(i));
|
|
|
+ }
|
|
|
+ const ipv6Addr = ipaddr.fromByteArray(byteArray);
|
|
|
+ port = chunk.readUInt16BE(20);
|
|
|
+ return [ipv6Addr.toString(), port];
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ return ['', 0];
|
|
|
+}
|
|
|
+
|
|
|
+function host2Buffer(chunk: Buffer, host: string): number {
|
|
|
+ let nextOffset: number = -1;
|
|
|
+ let offset = 4; // all command host started at index of 4
|
|
|
+ const addressType = chunk.readUint8(3);
|
|
|
+
|
|
|
+ switch (addressType) {
|
|
|
+ case AddressType.IPv4:
|
|
|
+ host.split('.').forEach((seg: string) => {
|
|
|
+ chunk.writeUint8(Number.parseInt(seg), offset++);
|
|
|
+ });
|
|
|
+ nextOffset = 8;
|
|
|
+ break;
|
|
|
+ case AddressType.Domain:
|
|
|
+ chunk.writeUint8(host.length, 4);
|
|
|
+ offset += 1;
|
|
|
+ [...host].forEach((c, i) => {
|
|
|
+ chunk.writeUint8(host.charCodeAt(i), offset++);
|
|
|
+ });
|
|
|
+ nextOffset = 4 + 1 + host.length;
|
|
|
+ break;
|
|
|
+ case AddressType.IPv6:
|
|
|
+ const bytes = ipaddr.parse(host).toByteArray();
|
|
|
+ bytes.map((byte) => {
|
|
|
+ chunk.writeUint8(byte, offset++);
|
|
|
+ });
|
|
|
+ nextOffset = 20;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ return nextOffset;
|
|
|
+}
|
|
|
+
|
|
|
export class Command {
|
|
|
public version: number;
|
|
|
public commandType: CommandType;
|
|
|
@@ -14,38 +81,10 @@ export class Command {
|
|
|
this.commandType = chunk.readUint8(1) as CommandType;
|
|
|
this.addressType = chunk.readUint8(3) as AddressType;
|
|
|
|
|
|
- [this.host, this.port] = this.parseAddress(chunk);
|
|
|
+ [this.host, this.port] = parseAddress(chunk);
|
|
|
}
|
|
|
+}
|
|
|
|
|
|
- private parseAddress(chunk: Buffer):[string, number] {
|
|
|
- let address = [], port;
|
|
|
- switch (this.addressType) {
|
|
|
- case AddressType.IPv4:
|
|
|
- address.push(chunk.readUint8(4).toString());
|
|
|
- address.push(chunk.readUint8(5).toString());
|
|
|
- address.push(chunk.readUint8(6).toString());
|
|
|
- address.push(chunk.readUint8(7).toString());
|
|
|
- port = chunk.readUInt16BE(8);
|
|
|
- return [address.join('.'), port];
|
|
|
- case AddressType.Domain:
|
|
|
- const domainLength: number = chunk.readUint8(4);
|
|
|
- let i:number;
|
|
|
- for(i = 5; i < 5 + domainLength; i++) {
|
|
|
- address.push(String.fromCharCode(chunk.readUint8(i)));
|
|
|
- }
|
|
|
- port = chunk.readUInt16BE(i);
|
|
|
- return [address.join(''), port];
|
|
|
- case AddressType.IPv6:
|
|
|
- let byteArray: number[] = [];
|
|
|
- for(let i = 4; i < 20; i++) {
|
|
|
- byteArray.push(chunk.readUint8(i));
|
|
|
- }
|
|
|
- const ipv6Addr = ipaddr.fromByteArray(byteArray);
|
|
|
- port = chunk.readUInt16BE(20);
|
|
|
- return [ipv6Addr.toString(), port];
|
|
|
- default:
|
|
|
- break;
|
|
|
- }
|
|
|
|
|
|
return ['', 0];
|
|
|
}
|
|
|
@@ -78,38 +117,9 @@ export class CommandReply {
|
|
|
chunk.writeUint8(this.commandReplyType.valueOf(), 1);
|
|
|
chunk.writeUint8(0, 2);
|
|
|
chunk.writeUint8(this.addressType.valueOf(), 3);
|
|
|
- const nextOffset: number = this.Host2Buffer(chunk, 4);
|
|
|
+ const nextOffset: number = host2Buffer(chunk, this.host);
|
|
|
chunk.writeUInt16BE(this.port, nextOffset);
|
|
|
|
|
|
return chunk;
|
|
|
}
|
|
|
-
|
|
|
- private Host2Buffer(chunk: Buffer, offset: number): number {
|
|
|
- let nextOffset: number = -1;
|
|
|
- switch (this.addressType) {
|
|
|
- case AddressType.IPv4:
|
|
|
- this.host.split('.').forEach((seg: string) => {
|
|
|
- chunk.writeUint8(Number.parseInt(seg), offset++);
|
|
|
- });
|
|
|
- nextOffset = 8;
|
|
|
- break;
|
|
|
- case AddressType.Domain:
|
|
|
- chunk.writeUint8(this.host.length, 4);
|
|
|
- offset += 1;
|
|
|
- [...this.host].forEach((c, i) => {
|
|
|
- chunk.writeUint8(this.host.charCodeAt(i), offset++);
|
|
|
- });
|
|
|
- nextOffset = 4 + 1 + this.host.length;
|
|
|
- break;
|
|
|
- case AddressType.IPv6:
|
|
|
- const bytes = ipaddr.parse(this.host).toByteArray();
|
|
|
- bytes.map((byte) => {
|
|
|
- chunk.writeUint8(byte, offset++);
|
|
|
- });
|
|
|
- nextOffset = 20;
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- return nextOffset;
|
|
|
- }
|
|
|
}
|