mirror of
https://github.com/fosrl/pangolin.git
synced 2026-07-17 11:06:30 +02:00
Compare commits
7 Commits
1.19.2
...
ea1badf4e0
| Author | SHA1 | Date | |
|---|---|---|---|
| ea1badf4e0 | |||
| 4435a669a6 | |||
| 90eceb457a | |||
| f39cbc9bf4 | |||
| 50da863bb7 | |||
| c6ddd5c402 | |||
| 0fb5ace9c7 |
@@ -511,6 +511,12 @@ export class TraefikConfigManager {
|
||||
let traefikConfig;
|
||||
try {
|
||||
const currentExitNode = await getCurrentExitNodeId();
|
||||
|
||||
const maintenancePort = config.getRawConfig().server.next_port;
|
||||
const maintenanceHost =
|
||||
config.getRawConfig().server.internal_hostname;
|
||||
const pangolinUIUrl = `http://${maintenanceHost}:${maintenancePort}`;
|
||||
|
||||
// logger.debug(`Fetching traefik config for exit node: ${currentExitNode}`);
|
||||
traefikConfig = await getTraefikConfig(
|
||||
// this is called by the local exit node to get its own config
|
||||
@@ -521,7 +527,8 @@ export class TraefikConfigManager {
|
||||
build == "saas"
|
||||
? false
|
||||
: config.getRawConfig().traefik.allow_raw_resources, // dont allow raw resources on saas otherwise use config
|
||||
build != "oss" // generate browser gateway targets on cloud and enterprise
|
||||
pangolinUIUrl, // generate maintenance pages on cloud and hybrid
|
||||
pangolinUIUrl // generate browser gateway targets on cloud and hybrid
|
||||
);
|
||||
|
||||
const domains = new Set<string>();
|
||||
|
||||
@@ -44,8 +44,8 @@ export async function getTraefikConfig(
|
||||
filterOutNamespaceDomains = false, // UNUSED BUT USED IN PRIVATE
|
||||
generateLoginPageRouters = false, // UNUSED BUT USED IN PRIVATE
|
||||
allowRawResources = true,
|
||||
allowMaintenancePage = true, // UNUSED BUT USED IN PRIVATE
|
||||
allowBrowserGatewayResources = true
|
||||
maintenancePageUiUrl: string | null = null, // UNUSED BUT USED IN PRIVATE
|
||||
browserGatewayUiUrl: string | null = null // UNUSED BUT USED IN PRIVATE
|
||||
): Promise<any> {
|
||||
// Get resources with their targets and sites in a single optimized query
|
||||
// Start from sites on this exit node, then join to targets and resources
|
||||
|
||||
@@ -84,8 +84,8 @@ export async function getTraefikConfig(
|
||||
filterOutNamespaceDomains = false,
|
||||
generateLoginPageRouters = false,
|
||||
allowRawResources = true,
|
||||
allowMaintenancePage = true,
|
||||
allowBrowserGatewayResources = true
|
||||
maintenancePageUiUrl: string | null = null,
|
||||
browserGatewayUiUrl: string | null = null
|
||||
): Promise<any> {
|
||||
// Get resources with their targets and sites in a single optimized query
|
||||
// Start from sites on this exit node, then join to targets and resources
|
||||
@@ -317,7 +317,7 @@ export async function getTraefikConfig(
|
||||
BrowserGatewayResourceEntry
|
||||
>();
|
||||
|
||||
if (allowBrowserGatewayResources) {
|
||||
if (browserGatewayUiUrl) {
|
||||
for (const row of resourcesWithTargetsAndSites) {
|
||||
if (!["ssh", "vnc", "rdp"].includes(row.mode)) {
|
||||
continue;
|
||||
@@ -630,10 +630,11 @@ export async function getTraefikConfig(
|
||||
}
|
||||
}
|
||||
|
||||
if (showMaintenancePage && allowMaintenancePage) {
|
||||
if (showMaintenancePage && maintenancePageUiUrl) {
|
||||
const maintenanceServiceName = `${key}-maintenance-service`;
|
||||
const maintenanceRouterName = `${key}-maintenance-router`;
|
||||
const rewriteMiddlewareName = `${key}-maintenance-rewrite`;
|
||||
const maintenanceHeadersMiddlewareName = `${key}-maintenance-headers`;
|
||||
|
||||
const entrypointHttp =
|
||||
config.getRawConfig().traefik.http_entrypoint;
|
||||
@@ -646,15 +647,11 @@ export async function getTraefikConfig(
|
||||
? `*.${domainParts.slice(1).join(".")}`
|
||||
: fullDomain;
|
||||
|
||||
const maintenancePort = config.getRawConfig().server.next_port;
|
||||
const maintenanceHost =
|
||||
config.getRawConfig().server.internal_hostname;
|
||||
|
||||
config_output.http.services[maintenanceServiceName] = {
|
||||
loadBalancer: {
|
||||
servers: [
|
||||
{
|
||||
url: `http://${maintenanceHost}:${maintenancePort}`
|
||||
url: maintenancePageUiUrl
|
||||
}
|
||||
],
|
||||
passHostHeader: true
|
||||
@@ -673,12 +670,26 @@ export async function getTraefikConfig(
|
||||
}
|
||||
};
|
||||
|
||||
config_output.http.middlewares[
|
||||
maintenanceHeadersMiddlewareName
|
||||
] = {
|
||||
headers: {
|
||||
customRequestHeaders: {
|
||||
Host: "app.pangolin.net", // if we are sending to the cloud the host needs to be this but we will pull the p-host to find the resource
|
||||
"p-host": fullDomain
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
config_output.http.routers[maintenanceRouterName] = {
|
||||
entryPoints: [
|
||||
resource.ssl ? entrypointHttps : entrypointHttp
|
||||
],
|
||||
service: maintenanceServiceName,
|
||||
middlewares: [rewriteMiddlewareName],
|
||||
middlewares: [
|
||||
rewriteMiddlewareName,
|
||||
maintenanceHeadersMiddlewareName
|
||||
],
|
||||
rule: rule,
|
||||
priority: 2000,
|
||||
...(resource.ssl ? { tls } : {})
|
||||
@@ -691,6 +702,7 @@ export async function getTraefikConfig(
|
||||
resource.ssl ? entrypointHttps : entrypointHttp
|
||||
],
|
||||
service: maintenanceServiceName,
|
||||
middlewares: [maintenanceHeadersMiddlewareName],
|
||||
rule: `${rule} && (PathPrefix(\`/_next\`) || PathRegexp(\`^/__nextjs*\`) || Path(\`/favicon.ico\`)) `,
|
||||
priority: 2001,
|
||||
...(resource.ssl ? { tls } : {})
|
||||
@@ -1027,7 +1039,7 @@ export async function getTraefikConfig(
|
||||
}
|
||||
}
|
||||
|
||||
if (allowBrowserGatewayResources) {
|
||||
if (browserGatewayUiUrl) {
|
||||
// Generate Traefik config for browser gateway resources
|
||||
const browserGatewayPort = 39999;
|
||||
for (const [, bgResource] of browserGatewayResourcesMap.entries()) {
|
||||
@@ -1119,20 +1131,17 @@ export async function getTraefikConfig(
|
||||
}
|
||||
}
|
||||
|
||||
if (showBgMaintenancePage && allowMaintenancePage) {
|
||||
if (showBgMaintenancePage && maintenancePageUiUrl) {
|
||||
const bgMaintenanceServiceName = `bg-r${bgResource.resourceId}-maintenance-service`;
|
||||
const bgMaintenanceRouterName = `bg-r${bgResource.resourceId}-maintenance-router`;
|
||||
const bgRewriteMiddlewareName = `bg-r${bgResource.resourceId}-maintenance-rewrite`;
|
||||
const bgMaintenanceHeadersMiddlewareName = `bg-r${bgResource.resourceId}-maintenance-headers`;
|
||||
|
||||
const entrypointHttp =
|
||||
config.getRawConfig().traefik.http_entrypoint;
|
||||
const entrypointHttps =
|
||||
config.getRawConfig().traefik.https_entrypoint;
|
||||
|
||||
const maintenancePort = config.getRawConfig().server.next_port;
|
||||
const maintenanceHost =
|
||||
config.getRawConfig().server.internal_hostname;
|
||||
|
||||
if (!config_output.http.services)
|
||||
config_output.http.services = {};
|
||||
if (!config_output.http.middlewares)
|
||||
@@ -1144,7 +1153,7 @@ export async function getTraefikConfig(
|
||||
loadBalancer: {
|
||||
servers: [
|
||||
{
|
||||
url: `http://${maintenanceHost}:${maintenancePort}`
|
||||
url: maintenancePageUiUrl
|
||||
}
|
||||
],
|
||||
passHostHeader: true
|
||||
@@ -1158,12 +1167,26 @@ export async function getTraefikConfig(
|
||||
}
|
||||
};
|
||||
|
||||
config_output.http.middlewares![
|
||||
bgMaintenanceHeadersMiddlewareName
|
||||
] = {
|
||||
headers: {
|
||||
customRequestHeaders: {
|
||||
Host: "app.pangolin.net", // if we are sending to the cloud the host needs to be this but we will pull the p-host to find the resource
|
||||
"p-host": fullDomain
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
config_output.http.routers![bgMaintenanceRouterName] = {
|
||||
entryPoints: [
|
||||
bgResource.ssl ? entrypointHttps : entrypointHttp
|
||||
],
|
||||
service: bgMaintenanceServiceName,
|
||||
middlewares: [bgRewriteMiddlewareName],
|
||||
middlewares: [
|
||||
bgRewriteMiddlewareName,
|
||||
bgMaintenanceHeadersMiddlewareName
|
||||
],
|
||||
rule: hostRule,
|
||||
priority: 2000,
|
||||
...(bgResource.ssl ? { tls } : {})
|
||||
@@ -1176,6 +1199,7 @@ export async function getTraefikConfig(
|
||||
bgResource.ssl ? entrypointHttps : entrypointHttp
|
||||
],
|
||||
service: bgMaintenanceServiceName,
|
||||
middlewares: [bgMaintenanceHeadersMiddlewareName],
|
||||
rule: `${hostRule} && (PathPrefix(\`/_next\`) || PathRegexp(\`^/__nextjs*\`) || Path(\`/favicon.ico\`))`,
|
||||
priority: 2001,
|
||||
...(bgResource.ssl ? { tls } : {})
|
||||
@@ -1234,9 +1258,8 @@ export async function getTraefikConfig(
|
||||
// The primary type is used for the path rewrite (e.g. /rdp), mirroring
|
||||
// how the maintenance page rewrites everything to /maintenance-screen.
|
||||
const primaryType = typeMap.keys().next().value as string;
|
||||
const internalHost = config.getRawConfig().server.internal_hostname;
|
||||
const internalPort = config.getRawConfig().server.next_port;
|
||||
const uiRewriteMiddlewareName = `bg-r${bgResource.resourceId}-ui-rewrite`;
|
||||
const uiHeadersMiddlewareName = `bg-r${bgResource.resourceId}-ui-headers`;
|
||||
const entrypoint = bgResource.ssl
|
||||
? config.getRawConfig().traefik.https_entrypoint
|
||||
: config.getRawConfig().traefik.http_entrypoint;
|
||||
@@ -1252,11 +1275,20 @@ export async function getTraefikConfig(
|
||||
}
|
||||
};
|
||||
|
||||
config_output.http.middlewares![uiHeadersMiddlewareName] = {
|
||||
headers: {
|
||||
customRequestHeaders: {
|
||||
Host: "app.pangolin.net", // if we are sending to the cloud the host needs to be this but we will pull the p-host to find the resource
|
||||
"p-host": fullDomain
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
config_output.http.services![bgUiServiceName] = {
|
||||
loadBalancer: {
|
||||
servers: [
|
||||
{
|
||||
url: `http://${internalHost}:${internalPort}`
|
||||
url: browserGatewayUiUrl
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1267,7 +1299,11 @@ export async function getTraefikConfig(
|
||||
`bg-r${bgResource.resourceId}-assets-router`
|
||||
] = {
|
||||
entryPoints: [entrypoint],
|
||||
middlewares: routerMiddlewares,
|
||||
middlewares: [
|
||||
...routerMiddlewares,
|
||||
uiRewriteMiddlewareName,
|
||||
uiHeadersMiddlewareName
|
||||
],
|
||||
service: bgUiServiceName,
|
||||
rule: `${hostRule} && (PathPrefix(\`/_next\`) || PathRegexp(\`^/__nextjs*\`) || Path(\`/favicon.ico\`))`,
|
||||
priority: 101,
|
||||
@@ -1279,7 +1315,11 @@ export async function getTraefikConfig(
|
||||
`bg-r${bgResource.resourceId}-ui-router`
|
||||
] = {
|
||||
entryPoints: [entrypoint],
|
||||
middlewares: [...routerMiddlewares, uiRewriteMiddlewareName],
|
||||
middlewares: [
|
||||
...routerMiddlewares,
|
||||
uiRewriteMiddlewareName,
|
||||
uiHeadersMiddlewareName
|
||||
],
|
||||
service: bgUiServiceName,
|
||||
rule: hostRule,
|
||||
priority: 100,
|
||||
@@ -1312,10 +1352,6 @@ export async function getTraefikConfig(
|
||||
const siteResourceRouterName = `${srKey}-router`;
|
||||
const siteResourceRewriteMiddlewareName = `${srKey}-rewrite`;
|
||||
|
||||
const maintenancePort = config.getRawConfig().server.next_port;
|
||||
const maintenanceHost =
|
||||
config.getRawConfig().server.internal_hostname;
|
||||
|
||||
if (!config_output.http.routers) {
|
||||
config_output.http.routers = {};
|
||||
}
|
||||
@@ -1331,7 +1367,7 @@ export async function getTraefikConfig(
|
||||
loadBalancer: {
|
||||
servers: [
|
||||
{
|
||||
url: `http://${maintenanceHost}:${maintenancePort}`
|
||||
url: maintenancePageUiUrl
|
||||
}
|
||||
],
|
||||
passHostHeader: true
|
||||
|
||||
@@ -277,6 +277,8 @@ hybridRouter.get(
|
||||
);
|
||||
}
|
||||
|
||||
const pangolinUIUrl = config.getRawConfig().app.dashboard_url; // points to the dashboard to serve from there
|
||||
|
||||
try {
|
||||
const traefikConfig = await getTraefikConfig(
|
||||
remoteExitNode.exitNodeId,
|
||||
@@ -284,8 +286,8 @@ hybridRouter.get(
|
||||
true, // But don't allow domain namespace resources
|
||||
false, // Dont include login pages,
|
||||
true, // allow raw resources
|
||||
false, // dont generate maintenance page
|
||||
false // dont generate browser gateway targets
|
||||
pangolinUIUrl, // dont generate maintenance page
|
||||
pangolinUIUrl // generate browser gateway targets
|
||||
);
|
||||
|
||||
return response(res, {
|
||||
|
||||
@@ -54,7 +54,7 @@ export const handleNewtGetConfigMessage: MessageHandler = async (context) => {
|
||||
// TODO: somehow we should make sure a recent hole punch has happened if this occurs (hole punch could be from the last restart if done quickly)
|
||||
}
|
||||
|
||||
if (existingSite.lastHolePunch && now - existingSite.lastHolePunch > 5) {
|
||||
if (existingSite.lastHolePunch && now - existingSite.lastHolePunch > 12) {
|
||||
logger.warn(
|
||||
`Site last hole punch is too old; skipping this register. The site is failing to hole punch and identify its network address with the server. Can the site reach the server on UDP port ${config.getRawConfig().gerbil.clients_start_port}?`
|
||||
);
|
||||
|
||||
@@ -348,7 +348,7 @@ export const handleOlmRegisterMessage: MessageHandler = async (context) => {
|
||||
// this prevents us from accepting a register from an olm that has not hole punched yet.
|
||||
// the olm will pump the register so we can keep checking
|
||||
// TODO: I still think there is a better way to do this rather than locking it out here but ???
|
||||
if (now - (client.lastHolePunch || 0) > 5 && sitesCount > 0) {
|
||||
if (now - (client.lastHolePunch || 0) > 12 && sitesCount > 0) {
|
||||
logger.warn(
|
||||
`[handleOlmRegisterMessage] Client last hole punch is too old and we have sites to send; skipping this register. The client is failing to hole punch and identify its network address with the server. Can the client reach the server on UDP port ${config.getRawConfig().gerbil.clients_start_port}?`,
|
||||
{ orgId: client.orgId, clientId: client.clientId }
|
||||
|
||||
@@ -17,13 +17,18 @@ export async function traefikConfigProvider(
|
||||
// Get the current exit node name from config
|
||||
const currentExitNodeId = await getCurrentExitNodeId();
|
||||
|
||||
const maintenancePort = config.getRawConfig().server.next_port;
|
||||
const maintenanceHost = config.getRawConfig().server.internal_hostname;
|
||||
const pangolinUIUrl = `http://${maintenanceHost}:${maintenancePort}`;
|
||||
|
||||
const traefikConfig = await getTraefikConfig(
|
||||
currentExitNodeId,
|
||||
config.getRawConfig().traefik.site_types,
|
||||
build == "oss", // filter out the namespace domains in open source
|
||||
build != "oss", // generate the login pages on the cloud and and enterprise,
|
||||
config.getRawConfig().traefik.allow_raw_resources,
|
||||
build != "oss" // generate browser gateway resources on cloud and enterprise
|
||||
pangolinUIUrl,
|
||||
pangolinUIUrl
|
||||
);
|
||||
|
||||
if (traefikConfig?.http?.middlewares) {
|
||||
|
||||
@@ -28,7 +28,7 @@ export default async function MaintenanceScreen() {
|
||||
|
||||
try {
|
||||
const headersList = await headers();
|
||||
const host = headersList.get("host") || "";
|
||||
const host = headersList.get("p-host") || headersList.get("host") || "";
|
||||
const hostname = host.split(":")[0];
|
||||
|
||||
const res = await priv.get<AxiosResponse<GetMaintenanceInfoResponse>>(
|
||||
|
||||
@@ -6,7 +6,7 @@ import { cache } from "react";
|
||||
|
||||
export const getBrowserTargetForRequest = cache(async () => {
|
||||
const headersList = await headers();
|
||||
const host = headersList.get("host") || "";
|
||||
const host = headersList.get("p-host") || headersList.get("host") || "";
|
||||
const hostname = host.split(":")[0];
|
||||
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user