Skip to content

Commit

Permalink
Merge pull request #1 from earthstar-project/get-own-address
Browse files Browse the repository at this point in the history
Make it possible to determine own external local address
  • Loading branch information
sgwilym authored May 16, 2023
2 parents e42222e + 6362a63 commit 91a97b3
Show file tree
Hide file tree
Showing 9 changed files with 157 additions and 145 deletions.
13 changes: 6 additions & 7 deletions examples/advertise_http.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
import { advertise } from "../src/dns_sd/advertise.ts";

import { MulticastInterface } from "../src/mdns/multicast_interface.ts";

const host = Deno.networkInterfaces().find((netInterface) => {
return netInterface.family === "IPv4" &&
netInterface.netmask === "255.255.255.0";
})?.address || "127.0.0.1";
const multicastInterface = new MulticastInterface();

console.log(`Advertising "My Web Server" on ${host}:8080`);
console.log(
`Advertising "My Web Server" on ${multicastInterface.hostname}:8080`,
);

await advertise({
service: {
host: host,
name: "My Web Server",
port: 8080,
protocol: "tcp",
type: "http",
txt: {},
},
multicastInterface: new MulticastInterface(),
multicastInterface,
});
14 changes: 11 additions & 3 deletions src/dns_sd/advertise.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,21 @@ import {
ResourceRecordTXT,
ResourceType,
} from "../decode/types.ts";
import { getOwnAddress } from "../mdns/get_own_address.ts";
import { MulticastInterface } from "../mdns/multicast_interface.ts";
import { respond } from "../mdns/responder.ts";

export type AdvertiseOpts = {
service: {
/** Unique name, e.g. "My Computer" */
name: string;
/** The type of the service, e.g. http. */
type: string;
/** A list of identifiers further identifying the kind of service provided, e.g. ["printer"]. */
subtypes?: string[];
protocol: "tcp" | "udp";
host: string;
/** The address to advertise on. Automatically determined if omitted. */
host?: string;
port: number;
txt: Record<string, true | Uint8Array | null>;
};
Expand All @@ -35,6 +40,9 @@ export async function advertise(opts: AdvertiseOpts) {
let attemptsInLastTenSeconds = 0;
const removalTimers: number[] = [];

const hostToUse = opts.service.host ||
await getOwnAddress(opts.multicastInterface);

let renameAttempts = 1;

if (opts.signal) {
Expand Down Expand Up @@ -114,8 +122,8 @@ export async function advertise(opts: AdvertiseOpts) {
TTL: 120,
isUnique: true,
RDATA: opts.multicastInterface.family === "IPv4"
? opts.service.host.split(".").map((strNum) => parseInt(strNum))
: opts.service.host,
? hostToUse.split(".").map((strNum) => parseInt(strNum))
: hostToUse,
RDLENGTH: 1,
} as (ResourceRecordA | ResourceRecordAAAA);

Expand Down
6 changes: 5 additions & 1 deletion src/mdns/default_driver.node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ import {
RemoteInfo,
Socket,
} from "https://deno.land/[email protected]/node/dgram.ts";
import { networkInterfaces } from "https://deno.land/[email protected]/node/os.ts";
import {
hostname,
networkInterfaces,
} from "https://deno.land/[email protected]/node/os.ts";
import { Buffer } from "https://deno.land/[email protected]/node/buffer.ts";
import { FastFIFO } from "../fast_fifo.ts";
import { deferred } from "https://deno.land/[email protected]/async/deferred.ts";
Expand All @@ -19,6 +22,7 @@ export class DefaultDriver implements MulticastDriver {

family: "IPv4" | "IPv6";
address: string;
hostname = hostname();

constructor(family: "IPv4" | "IPv6") {
this.family = family;
Expand Down
1 change: 1 addition & 0 deletions src/mdns/default_driver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export class DefaultDriver implements MulticastDriver {

family: "IPv4" | "IPv6";
address: string;
hostname = Deno.hostname();

constructor(family: "IPv4" | "IPv6") {
this.address = family === "IPv4" ? "0.0.0.0" : "::";
Expand Down
46 changes: 46 additions & 0 deletions src/mdns/get_own_address.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { deferred } from "https://deno.land/[email protected]/async/deferred.ts";
import { MulticastInterface } from "./multicast_interface.ts";

export async function getOwnAddress(
multicastInterface: MulticastInterface,
): Promise<string> {
const ownAddressPromise = deferred<string>();

multicastInterface.setLoopback(true);

// Listen to multicast messages
(async () => {
for await (const [_msg, addr] of multicastInterface.messages()) {
if (multicastInterface.isOwnAddress(addr.hostname)) {
ownAddressPromise.resolve(addr.hostname);
}
}
})();

// Send a message
await multicastInterface.send({
header: {
ID: 0,
QR: 0,
OPCODE: 0,
AA: 0,
TC: 0,
RD: 0,
RA: 0,
Z: 0,
AD: 0,
CD: 0,
RCODE: 0,
QDCOUNT: 0,
ANCOUNT: 0,
NSCOUNT: 0,
ARCOUNT: 0,
},
question: [],
answer: [],
authority: [],
additional: [],
});

return ownAddressPromise;
}
26 changes: 15 additions & 11 deletions src/mdns/multicast_interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ import { DefaultDriver } from "./default_driver.ts";

/** A driver which supplies the underlying methods a `MulticastInterface` uses to send and receive multicast messages. */
export interface MulticastDriver {
address: string;

family: "IPv4" | "IPv6";

hostname: string;

send(message: Uint8Array): Promise<void>;

setTTL(ttl: number): Promise<void>;
Expand Down Expand Up @@ -44,13 +44,17 @@ export class MulticastInterface {
while (true) {
const [received, origin] = await driverToUse.receive();

const event = [decodeMessage(received), origin] as [
DnsMessage,
{ hostname: string; port: number },
];

for (const subscriber of subscribers) {
subscriber.push(event);
try {
const event = [decodeMessage(received), origin] as [
DnsMessage,
{ hostname: string; port: number },
];

for (const subscriber of subscribers) {
subscriber.push(event);
}
} catch {
console.warn("Could not decode a message from", origin.hostname);
}
}
})();
Expand Down Expand Up @@ -86,8 +90,8 @@ export class MulticastInterface {
return this.driver.isOwnAddress(address);
}

get address() {
return this.driver.address;
get hostname() {
return this.driver.hostname;
}

get family() {
Expand Down
6 changes: 5 additions & 1 deletion src/mdns/query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@ export class Query {
break;
}

if (multicastInterface.isOwnAddress(host.hostname)) {
continue;
}

if (message.header.QR === 0) {
this.handleQuery(message, host);
} else {
Expand Down Expand Up @@ -142,7 +146,7 @@ export class Query {
// It's a query.

// Is this something we sent ourselves?
if (host.hostname === this.minterface.address) {
if (this.minterface.isOwnAddress(host.hostname)) {
return;
}

Expand Down
Loading

0 comments on commit 91a97b3

Please sign in to comment.