Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions packages/discv5/test/unit/util/ip.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,27 @@ describe("get/set SocketAddress on ENR", () => {
expect(getSocketAddressOnENR(enr, {ip4: true, ip6: false})).to.deep.equal(addr);
});

it("accepts a one-byte UDP port from a remote ENR", () => {
const enr = SignableENR.createV4(generateKeypair("secp256k1").privateKey);
enr.set("ip", Uint8Array.from([127, 0, 0, 1]));
enr.set("udp", Uint8Array.from([53]));

expect(getSocketAddressOnENR(enr, {ip4: true, ip6: false})).to.deep.equal({
ip: {octets: Uint8Array.from([127, 0, 0, 1]), type: 4},
port: 53,
});
});

it("ignores an invalid UDP port from a remote ENR", () => {
const enr = SignableENR.createV4(generateKeypair("secp256k1").privateKey);
enr.set("ip", Uint8Array.from([127, 0, 0, 1]));

for (const port of [new Uint8Array(), Uint8Array.from([0]), Uint8Array.from([1, 2, 3])]) {
enr.set("udp", port);
expect(getSocketAddressOnENR(enr, {ip4: true, ip6: false})).to.be.undefined;
}
});

it("returns the requested family from the ENR", () => {
const addr4: SocketAddress = {
ip: {
Expand Down
33 changes: 11 additions & 22 deletions packages/enr/src/enr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -182,20 +182,9 @@ export function getIPValue(

export function getProtocolValue(kvs: ReadonlyMap<ENRKey, ENRValue>, key: string): number | undefined {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this be renamed to getPortValue? or otherwise could rename the port variable below if we think this will return anything other than a port in the future

const raw = kvs.get(key);
if (raw) {
if (raw.length < 2) {
throw new Error("Encoded protocol length should be 2");
}
return (raw[0] << 8) + raw[1];
}
return undefined;
}

function normalizePortBytes(raw: Uint8Array | undefined): Uint8Array | undefined {
if (!raw || raw.length === 0 || raw.length > 2) return undefined;
if (raw[0] === 0) return undefined;
if (raw.length === 1) return new Uint8Array([0, raw[0]]);
return raw;
const port = raw.length === 1 ? raw[0] : (raw[0] << 8) + raw[1];
return port === 0 ? undefined : port;
}

export function portToBuf(port: number): Uint8Array {
Expand Down Expand Up @@ -344,38 +333,38 @@ export abstract class BaseENR {
};

if (isUdp) {
const protoVal = normalizePortBytes(isIpv6 ? this.kvs.get("udp6") : this.kvs.get("udp"));
if (!protoVal) {
const port = getProtocolValue(this.kvs, isIpv6 ? "udp6" : "udp");
if (port === undefined) {
return undefined;
}
const protoComponent: Component = {
code: udp.code,
name: udp.name,
value: udp.bytesToValue?.(toNewUint8Array(protoVal)),
value: port.toString(),
};
return multiaddr([ipComponent, protoComponent]);
}
if (isTcp) {
const protoVal = normalizePortBytes(isIpv6 ? this.kvs.get("tcp6") : this.kvs.get("tcp"));
if (!protoVal) {
const port = getProtocolValue(this.kvs, isIpv6 ? "tcp6" : "tcp");
if (port === undefined) {
return undefined;
}
const protoComponent: Component = {
code: tcp.code,
name: tcp.name,
value: tcp.bytesToValue?.(toNewUint8Array(protoVal)),
value: port.toString(),
};
return multiaddr([ipComponent, protoComponent]);
}
if (isQuic) {
const protoVal = normalizePortBytes(isIpv6 ? this.kvs.get("quic6") : this.kvs.get("quic"));
if (!protoVal) {
const port = getProtocolValue(this.kvs, isIpv6 ? "quic6" : "quic");
if (port === undefined) {
return undefined;
}
const protoComponent: Component = {
code: udp.code,
name: udp.name,
value: udp.bytesToValue?.(toNewUint8Array(protoVal)),
value: port.toString(),
};
return multiaddr([ipComponent, protoComponent]).encapsulate("/quic-v1");
}
Expand Down
32 changes: 32 additions & 0 deletions packages/enr/test/unit/enr.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,38 @@ describe("ENR multiaddr support", () => {
record = SignableENR.createV4(privateKey);
});

describe("port values", () => {
beforeEach(() => {
record.ip = "127.0.0.1";
});

it("should decode a one-byte port", () => {
record.set("udp", new Uint8Array([80]));

expect(record.udp).to.equal(80);
expect(record.getLocationMultiaddr("udp")?.toString()).to.equal("/ip4/127.0.0.1/udp/80");
});

it("should decode a two-byte low port", () => {
record.udp = 80;

expect(record.kvs.get("udp")).to.deep.equal(new Uint8Array([0, 80]));
expect(record.udp).to.equal(80);
expect(record.getLocationMultiaddr("udp")?.toString()).to.equal("/ip4/127.0.0.1/udp/80");
});

it("should ignore invalid port values", () => {
const invalidPorts = [new Uint8Array(), new Uint8Array([0]), new Uint8Array([0, 0]), new Uint8Array([1, 2, 3])];

for (const port of invalidPorts) {
record.set("udp", port);

expect(record.udp).to.be.undefined;
expect(record.getLocationMultiaddr("udp")).to.be.undefined;
}
});
});

it("should get / set UDP multiaddr", () => {
const multi0 = multiaddr("/ip4/127.0.0.1/udp/30303");
const components0 = multi0.getComponents();
Expand Down
Loading