Compare commits

..

4 Commits

Author SHA1 Message Date
Owen 515afc14a5 Add handlers 2026-07-16 11:23:53 -04:00
Owen 903e8c0fa1 Send localEndpoints on sites to olm 2026-07-16 10:47:24 -04:00
Owen 7f9c760380 Save the local endpoints 2026-07-16 09:59:11 -04:00
Owen 530a1a5350 Add new column 2026-07-16 09:59:07 -04:00
14 changed files with 210 additions and 32 deletions
+1 -1
View File
@@ -41,7 +41,7 @@ services:
- 80:80 # Port for traefik because of the network_mode
traefik:
image: traefik:v3.7
image: traefik:v3.6
container_name: traefik
restart: unless-stopped
network_mode: service:gerbil # Ports appear on the gerbil service
+1 -1
View File
@@ -50,7 +50,7 @@ services:
- 80:80{{end}}
traefik:
image: docker.io/traefik:v3.7
image: docker.io/traefik:v3.6
container_name: traefik
restart: unless-stopped
{{if .InstallGerbil}}network_mode: service:gerbil # Ports appear on the gerbil service{{end}}{{if not .InstallGerbil}}
+1
View File
@@ -107,6 +107,7 @@ export const sites = pgTable(
lastPing: integer("lastPing"),
address: varchar("address"),
endpoint: varchar("endpoint"),
localEndpoints: varchar("localEndpoints"), // JSON encoded list of string ips on the local machine to try to connect to
publicKey: varchar("publicKey"),
lastHolePunch: bigint("lastHolePunch", { mode: "number" }),
listenPort: integer("listenPort"),
+1
View File
@@ -118,6 +118,7 @@ export const sites = sqliteTable("sites", {
// exit node stuff that is how to connect to the site when it has a wg server
address: text("address"), // this is the address of the wireguard interface in newt
endpoint: text("endpoint"), // this is how to reach gerbil externally - gets put into the wireguard config
localEndpoints: text("localEndpoints"), // JSON encoded list of string ips on the local machine to try to connect to
publicKey: text("publicKey"), // TODO: Fix typo in publicKey
lastHolePunch: integer("lastHolePunch"),
listenPort: integer("listenPort"),
@@ -48,7 +48,8 @@ export const handleNewtRegisterMessage: MessageHandler = async (context) => {
pingResults,
newtVersion,
backwardsCompatible,
chainId
chainId,
localEndpoints
} = message.data;
if (!publicKey) {
logger.warn("Public key not provided");
@@ -131,7 +132,10 @@ export const handleNewtRegisterMessage: MessageHandler = async (context) => {
.set({
pubKey: publicKey,
exitNodeId: exitNodeId,
subnet: newSubnet
subnet: newSubnet,
localEndpoints: localEndpoints
? JSON.stringify(localEndpoints)
: null
})
.where(eq(sites.siteId, siteId))
.returning();
@@ -139,7 +143,10 @@ export const handleNewtRegisterMessage: MessageHandler = async (context) => {
await db
.update(sites)
.set({
pubKey: publicKey
pubKey: publicKey,
localEndpoints: localEndpoints
? JSON.stringify(localEndpoints)
: null
})
.where(eq(sites.siteId, siteId))
.returning();
+4
View File
@@ -30,6 +30,7 @@ export async function buildSiteConfigurationForOlmClient(
siteId: number;
name?: string;
endpoint?: string;
localEndpoints?: string[];
publicKey?: string;
serverIP?: string | null;
serverPort?: number | null;
@@ -206,6 +207,9 @@ export async function buildSiteConfigurationForOlmClient(
name: site.name,
// relayEndpoint: relayEndpoint, // this can be undefined now if not relayed // lets not do this for now because it would conflict with the hole punch testing
endpoint: site.endpoint,
localEndpoints: site.localEndpoints
? JSON.parse(site.localEndpoints)
: undefined,
publicKey: site.publicKey,
serverIP: site.address,
serverPort: site.listenPort,
@@ -0,0 +1,74 @@
import { db, sites } from "@server/db";
import { MessageHandler } from "@server/routers/ws";
import { clients, Olm } from "@server/db";
import { and, eq } from "drizzle-orm";
import { updatePeer as newtUpdatePeer } from "../newt/peers";
import logger from "@server/logger";
export const handleOlmLocalMessage: MessageHandler = async (context) => {
const { message, client: c, sendToClient } = context;
const olm = c as Olm;
logger.info("Handling local olm message!");
if (!olm) {
logger.warn("Olm not found");
return;
}
if (!olm.clientId) {
logger.warn("Olm has no client!");
return;
}
const clientId = olm.clientId;
const [client] = await db
.select()
.from(clients)
.where(eq(clients.clientId, clientId))
.limit(1);
if (!client) {
logger.warn("Client not found");
return;
}
// make sure we hand endpoints for both the site and the client and the lastHolePunch is not too old
if (!client.pubKey) {
logger.warn("Client has no endpoint or listen port");
return;
}
const { siteId, chainId } = message.data;
// Get the site
const [site] = await db
.select()
.from(sites)
.where(eq(sites.siteId, siteId))
.limit(1);
if (!site || !site.exitNodeId) {
logger.warn("Site not found or has no exit node");
return;
}
// update the peer on the newt
await newtUpdatePeer(siteId, client.pubKey, {
endpoint: "" // this removes the endpoint so the newt knows to accept local
});
// Just ack the message, we don't keep sending it
return {
message: {
type: "olm/wg/peer/local",
data: {
siteId: siteId,
chainId
}
},
broadcast: false,
excludeSender: false
};
};
+2 -2
View File
@@ -79,9 +79,9 @@ export const handleOlmRelayMessage: MessageHandler = async (context) => {
)
);
// update the peer on the exit node
// update the peer on the newt
await newtUpdatePeer(siteId, client.pubKey, {
endpoint: "" // this removes the endpoint so the exit node knows to relay
endpoint: "" // this removes the endpoint so the newt knows to relay
});
return {
@@ -3,24 +3,15 @@ import {
db,
networks,
siteNetworks,
siteResources,
siteResources
} from "@server/db";
import { MessageHandler } from "@server/routers/ws";
import {
clients,
clientSitesAssociationsCache,
Olm,
sites
} from "@server/db";
import { clients, clientSitesAssociationsCache, Olm, sites } from "@server/db";
import { and, eq, inArray, isNotNull, isNull } from "drizzle-orm";
import logger from "@server/logger";
import {
generateAliasConfig,
} from "@server/lib/ip";
import { generateAliasConfig } from "@server/lib/ip";
import { generateRemoteSubnets } from "@server/lib/ip";
import {
addPeer as newtAddPeer,
} from "@server/routers/newt/peers";
import { addPeer as newtAddPeer } from "@server/routers/newt/peers";
export const handleOlmServerPeerAddMessage: MessageHandler = async (
context
@@ -135,10 +126,7 @@ export const handleOlmServerPeerAddMessage: MessageHandler = async (
clientSiteResourcesAssociationsCache.siteResourceId
)
)
.innerJoin(
networks,
eq(siteResources.networkId, networks.networkId)
)
.innerJoin(networks, eq(siteResources.networkId, networks.networkId))
.innerJoin(
siteNetworks,
and(
@@ -147,10 +135,7 @@ export const handleOlmServerPeerAddMessage: MessageHandler = async (
)
)
.where(
eq(
clientSiteResourcesAssociationsCache.clientId,
client.clientId
)
eq(clientSiteResourcesAssociationsCache.clientId, client.clientId)
);
// Return connect message with all site configurations
@@ -161,6 +146,9 @@ export const handleOlmServerPeerAddMessage: MessageHandler = async (
siteId: site.siteId,
name: site.name,
endpoint: site.endpoint,
localEndpoints: site.localEndpoints
? JSON.parse(site.localEndpoints)
: undefined,
publicKey: site.publicKey,
serverIP: site.address,
serverPort: site.listenPort,
@@ -170,7 +158,7 @@ export const handleOlmServerPeerAddMessage: MessageHandler = async (
aliases: generateAliasConfig(
allSiteResources.map(({ siteResources }) => siteResources)
),
chainId: chainId,
chainId: chainId
}
},
broadcast: false,
@@ -0,0 +1,95 @@
import { db, exitNodes, sites } from "@server/db";
import { MessageHandler } from "@server/routers/ws";
import { clients, clientSitesAssociationsCache, Olm } from "@server/db";
import { and, eq } from "drizzle-orm";
import { updatePeer as newtUpdatePeer } from "../newt/peers";
import logger from "@server/logger";
export const handleOlmUnLocalMessage: MessageHandler = async (context) => {
const { message, client: c, sendToClient } = context;
const olm = c as Olm;
logger.info("Handling unlocal olm message!");
if (!olm) {
logger.warn("Olm not found");
return;
}
if (!olm.clientId) {
logger.warn("Olm has no client!");
return;
}
const clientId = olm.clientId;
const [client] = await db
.select()
.from(clients)
.where(eq(clients.clientId, clientId))
.limit(1);
if (!client) {
logger.warn("Client not found");
return;
}
// make sure we hand endpoints for both the site and the client and the lastHolePunch is not too old
if (!client.pubKey) {
logger.warn("Client has no endpoint or listen port");
return;
}
const { siteId, chainId } = message.data;
// Get the site
const [site] = await db
.select()
.from(sites)
.where(eq(sites.siteId, siteId))
.limit(1);
if (!site) {
logger.warn("Site not found or has no exit node");
return;
}
const [clientSiteAssociation] = await db
.select()
.from(clientSitesAssociationsCache)
.where(
and(
eq(clientSitesAssociationsCache.clientId, olm.clientId),
eq(clientSitesAssociationsCache.siteId, siteId)
)
);
if (!clientSiteAssociation) {
logger.warn("Client-Site association not found");
return;
}
if (!clientSiteAssociation.endpoint) {
logger.warn("Client-Site association has no endpoint, cannot unrelay");
return;
}
// update the peer on the newt
await newtUpdatePeer(siteId, client.pubKey, {
endpoint: clientSiteAssociation.isRelayed
? ""
: clientSiteAssociation.endpoint // this is the endpoint of the client to connect directly to the newt
});
return {
message: {
type: "olm/wg/peer/unlocal",
data: {
siteId: siteId,
chainId
}
},
broadcast: false,
excludeSender: false
};
};
@@ -77,9 +77,9 @@ export const handleOlmUnRelayMessage: MessageHandler = async (context) => {
return;
}
// update the peer on the exit node
// update the peer on the newt
await newtUpdatePeer(siteId, client.pubKey, {
endpoint: clientSiteAssociation.endpoint // this is the endpoint of the client to connect directly to the exit node
endpoint: clientSiteAssociation.endpoint // this is the endpoint of the client to connect directly to the newt
});
return {
+2
View File
@@ -13,3 +13,5 @@ export * from "./recoverOlmWithFingerprint";
export * from "./handleOlmDisconnectingMessage";
export * from "./handleOlmServerInitAddPeerHandshake";
export * from "./offlineChecker";
export * from "./handleOlmUnLocalMessage";
export * from "./handleOlmLocalMessage";
+2
View File
@@ -18,6 +18,7 @@ export async function addPeer(
serverPort: number | null;
remoteSubnets: string[] | null; // optional, comma-separated list of subnets that this site can access
aliases: Alias[];
localEndpoints?: string[]; // optional, list of local endpoints for the peer
},
olmId?: string,
version?: string | null
@@ -44,6 +45,7 @@ export async function addPeer(
name: peer.name,
publicKey: peer.publicKey,
endpoint: peer.endpoint,
localEndpoints: peer.localEndpoints,
relayEndpoint: peer.relayEndpoint,
serverIP: peer.serverIP,
serverPort: peer.serverPort,
+5 -1
View File
@@ -20,7 +20,9 @@ import {
handleOlmServerPeerAddMessage,
handleOlmUnRelayMessage,
handleOlmDisconnectingMessage,
handleOlmServerInitAddPeerHandshake
handleOlmServerInitAddPeerHandshake,
handleOlmLocalMessage,
handleOlmUnLocalMessage
} from "../olm";
import { handleHealthcheckStatusMessage } from "../target";
import { handleRoundTripMessage } from "./handleRoundTripMessage";
@@ -32,6 +34,8 @@ export const messageHandlers: Record<string, MessageHandler> = {
"olm/wg/register": handleOlmRegisterMessage,
"olm/wg/relay": handleOlmRelayMessage,
"olm/wg/unrelay": handleOlmUnRelayMessage,
"olm/wg/local": handleOlmLocalMessage,
"olm/wg/unlocal": handleOlmUnLocalMessage,
"olm/ping": handleOlmPingMessage,
"olm/disconnecting": handleOlmDisconnectingMessage,
"newt/disconnecting": handleNewtDisconnectingMessage,