TRIVIAL: Add xray-core-subnet-mimicry article (#4)
This commit is contained in:
1 parent
49b545f1b4
commit
ea35a3d9f5
21 files changed
+785
-79
No files matched your search
@@ -0,0 +1,182 @@
|
||||
---
|
||||
title: 'Xray Subnet Mimicry'
|
||||
description: 'Building a distributed 10.0.0.0/8 private network with Xray-core'
|
||||
createdDate: 2026-03-08
|
||||
tags: ['networking', 'guide']
|
||||
---
|
||||
|
||||
> This guide is for **educational purposes** only. It is designed as a technical demonstration of Xray-core's routing capabilities and private subnet mimicry. It is NOT intended for restriction evasion or illegal activities. Use this knowledge responsibly and in compliance with your local laws.
|
||||
|
||||
## Why Subnet Mimicry?
|
||||
|
||||
By constructing a "Flat Network" (Layer 3) over the public internet, you achieve a unified private address space (`10.0.0.0/8`) distributed across distinct servers.
|
||||
|
||||
- **Distributed Topology**: Each node is an authoritative gateway for its own `/16` segment (e.g., Hub on `10.1.0.0/16`, Spokes on `10.2.0.0/16` and `10.3.0.0/16`).
|
||||
- **NAT Traversal**: Spokes (Bridges) actively initiate connections to the Hub (Portal), allowing nodes behind NAT to be reachable.
|
||||
- **Centralized Resolution**: Enforce network-wide DNS policies through a central Hub resolver.
|
||||
|
||||
---
|
||||
|
||||
## Technical Stack Overview
|
||||
|
||||
1. **Xray-core**: The routing engine handling VLESS connections, reverse tunneling, and TPROXY interception.
|
||||
2. **TPROXY**: Transparent proxying in the Linux Mangle table that intercepts TCP/UDP traffic while preserving original destination IPs.
|
||||
3. **Policy Routing**: Using `ip rule` and routing Table 100 to force intercepted packets into the local loopback for Xray to process.
|
||||
4. **Mux.cool**: A multiplexing protocol that packs hundreds of virtual connections (TCP/UDP streams) into a single physical TLS connection.
|
||||
5. **AdGuard Home**: The centralized DNS resolver for the entire subnet.
|
||||
6. **Nginx**: Used as camouflage on the main public inbound port to hide the Xray instance.
|
||||
|
||||
---
|
||||
|
||||
## 1. The Deployment Stack
|
||||
|
||||
This configuration represents the Central Hub (Server A) which acts as the Portal for Spoke connections. The Hub hosts the centralized DNS and the fallback Nginx camouflage.
|
||||
|
||||
```yaml
|
||||
name: 'a'
|
||||
|
||||
services:
|
||||
xray:
|
||||
image: ghcr.io/xtls/xray-core:26.1.23
|
||||
container_name: a-xray
|
||||
network_mode: host
|
||||
volumes:
|
||||
- ./xray.jsonc:/etc/xray/config.jsonc:ro
|
||||
- /etc/letsencrypt/live:/etc/letsencrypt/live:ro
|
||||
command: -c '/etc/xray/config.jsonc'
|
||||
restart: unless-stopped
|
||||
cap_add:
|
||||
- NET_ADMIN
|
||||
- NET_RAW
|
||||
|
||||
nginx:
|
||||
image: nginxinc/nginx-unprivileged:1.29-alpine
|
||||
container_name: a-nginx
|
||||
networks:
|
||||
direct:
|
||||
ipv4_address: 10.1.1.4
|
||||
restart: unless-stopped
|
||||
security_opt:
|
||||
- no-new-privileges:true
|
||||
|
||||
adguard:
|
||||
image: adguard/adguardhome:v0.107.72
|
||||
container_name: root-adguard
|
||||
volumes:
|
||||
- adguard-work:/opt/adguardhome/work
|
||||
- adguard-conf:/opt/adguardhome/conf
|
||||
networks:
|
||||
direct:
|
||||
ipv4_address: 10.1.1.3
|
||||
restart: unless-stopped
|
||||
cap_add:
|
||||
- NET_BIND_SERVICE
|
||||
- SYS_NICE
|
||||
- CAP_CHOWN
|
||||
security_opt:
|
||||
- no-new-privileges:true
|
||||
|
||||
networks:
|
||||
direct:
|
||||
name: a-direct
|
||||
driver: bridge
|
||||
ipam:
|
||||
config:
|
||||
- subnet: 10.1.0.0/16 # Using the full /16 as defined for Server A
|
||||
gateway: 10.1.0.1
|
||||
|
||||
volumes:
|
||||
adguard-work:
|
||||
name: a-adguard-work
|
||||
adguard-conf:
|
||||
name: a-adguard-conf
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. Configuration & Routing
|
||||
|
||||
### Generating Identity UUIDs
|
||||
|
||||
Each connection needs its own cryptographic "Key". You need 4 UUIDs mapped to your config files.
|
||||
|
||||
```bash
|
||||
# Generate UUIDs for the Server B and Server C mappings
|
||||
docker run --rm ghcr.io/xtls/xray-core uuid
|
||||
```
|
||||
|
||||
The mapping is as follows:
|
||||
|
||||
- `UUID_B_REVERSE`: Tunnel control for Server B.
|
||||
- `UUID_B_DIRECT`: Data traffic for Server B.
|
||||
- `UUID_C_REVERSE`: Tunnel control for Server C.
|
||||
- `UUID_C_DIRECT`: Data traffic for Server C.
|
||||
|
||||
### Policy Routing (Table 100)
|
||||
|
||||
Apply the routing configuration script on **EVERY** server node to set up the kernel parameters and routing Table 100. This tricks the kernel into handing the packet to our TPROXY inbound listening on `127.0.0.1:12345`.
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# 1. Enable IP Forwarding
|
||||
sudo sysctl -w net.ipv4.ip_forward=1
|
||||
|
||||
# 2. IP Rule for mark 0x1 -> table 100
|
||||
sudo ip rule add fwmark 0x1 lookup 100 priority 100
|
||||
|
||||
# 3. Local route in table 100
|
||||
sudo ip route add local 0.0.0.0/0 dev lo table 100
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Firewall Interception
|
||||
|
||||
Open `/etc/ufw/before.rules` and insert the specific node rules immediately after the `*filter` header requirements. Below is the configuration for Server A (Hub, `10.1.0.0/16`):
|
||||
|
||||
```text
|
||||
*mangle
|
||||
:XRAY - [0:0]
|
||||
:XRAY_MASK - [0:0]
|
||||
:DIVERT - [0:0]
|
||||
|
||||
# --- PREROUTING CHAIN (Traffic from other containers/nodes) ---
|
||||
-A XRAY -d 10.1.0.0/16 -j RETURN
|
||||
-A XRAY ! -d 10.0.0.0/8 -j RETURN
|
||||
-A XRAY -m mark --mark 0xff -j RETURN
|
||||
-A XRAY -p udp -j TPROXY --on-ip 127.0.0.1 --on-port 12345 --tproxy-mark 1
|
||||
-A XRAY -p tcp -j TPROXY --on-ip 127.0.0.1 --on-port 12345 --tproxy-mark 1
|
||||
-A PREROUTING -j XRAY
|
||||
|
||||
# --- OUTPUT CHAIN (Traffic originating from the server itself) ---
|
||||
-A XRAY_MASK -d 10.1.0.0/16 -j RETURN
|
||||
-A XRAY_MASK ! -d 10.0.0.0/8 -j RETURN
|
||||
-A XRAY_MASK -m mark --mark 0xff -j RETURN
|
||||
-A XRAY_MASK -p udp -j MARK --set-mark 1
|
||||
-A XRAY_MASK -p tcp -j MARK --set-mark 1
|
||||
-A OUTPUT -j XRAY_MASK
|
||||
|
||||
# --- DIVERT Optimization ---
|
||||
-A DIVERT -j MARK --set-mark 1
|
||||
-A DIVERT -j ACCEPT
|
||||
-I PREROUTING -p tcp -m socket -j DIVERT
|
||||
|
||||
COMMIT
|
||||
```
|
||||
|
||||
Reload UFW once applied:
|
||||
|
||||
```bash
|
||||
sudo ufw reload
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Resources
|
||||
|
||||
- [Xray-core Official Documentation](https://xtls.github.io/)
|
||||
- [Xray Reverse Proxy Documentation](https://xtls.github.io/en/config/reverse.html)
|
||||
- [Project X (Xray) GitHub](https://github.com/XTLS/Xray-core)
|
||||
- [Linux Kernel TPROXY Documentation](https://www.kernel.org/doc/Documentation/networking/tproxy.txt)
|
||||
- [Cloudflare Blog: TPROXY](https://blog.cloudflare.com/how-we-built-spectrum/)
|
||||
@@ -1,6 +1,7 @@
|
||||
import React from 'react';
|
||||
import * as TestArticle from './articles/2026/test-article.mdx';
|
||||
import * as MatrixServerDeploymentGuide from './articles/2026/matrix-server-deployment-guide.mdx';
|
||||
import * as XrayCoreSubnetMimicry from './articles/2026/xray-core-subnet-mimicry.mdx';
|
||||
|
||||
export interface Article {
|
||||
slug: string;
|
||||
@@ -45,6 +46,7 @@ export const articles: Record<string, Article> = {
|
||||
MatrixServerDeploymentGuide,
|
||||
'2026/matrix-server-deployment-guide'
|
||||
),
|
||||
'xray-core-subnet-mimicry': register(XrayCoreSubnetMimicry, '2026/xray-core-subnet-mimicry'),
|
||||
};
|
||||
|
||||
export const sortedArticles = Object.values(articles).sort(
|
||||
|
||||
@@ -7,11 +7,6 @@ import { createPage } from '../../../lib/core/createPage';
|
||||
|
||||
const article = articles['test-article'];
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||
if (!article) {
|
||||
throw new Error('Article not found');
|
||||
}
|
||||
|
||||
createPage(
|
||||
function TestArticlePage(): React.JSX.Element {
|
||||
return (
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
import { MARKDOWN_COMPONENTS } from '@ermnvldmr/ui';
|
||||
import React from 'react';
|
||||
|
||||
import { articles } from '../../../../content/registry';
|
||||
import { ArticleLayout } from '../../../components/Layout/ArticleLayout';
|
||||
import { createPage } from '../../../lib/core/createPage';
|
||||
|
||||
const article = articles['xray-core-subnet-mimicry'];
|
||||
|
||||
createPage(
|
||||
function XrayCoreSubnetMimicryPage(): React.JSX.Element {
|
||||
return (
|
||||
<ArticleLayout
|
||||
createdDate={article.createdDate}
|
||||
description={article.description}
|
||||
tags={article.tags}
|
||||
title={article.title}
|
||||
updatedDate={article.updatedDate}
|
||||
>
|
||||
<article.Component components={MARKDOWN_COMPONENTS} />
|
||||
</ArticleLayout>
|
||||
);
|
||||
},
|
||||
{
|
||||
title: `${article.title} - Vladimir Eremin`,
|
||||
description: article.description,
|
||||
}
|
||||
);
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Separator, Article, VStack, Breadcrumbs } from '@ermnvldmr/ui';
|
||||
import { Article, Breadcrumbs } from '@ermnvldmr/ui';
|
||||
import React from 'react';
|
||||
|
||||
import { sortedArticles } from '../../../content/registry';
|
||||
@@ -10,11 +10,9 @@ createPage(
|
||||
function ArticlesList(): React.JSX.Element {
|
||||
const breadcrumbs = (
|
||||
<Breadcrumbs>
|
||||
<Breadcrumbs.Item>
|
||||
<a href="/">Home</a>
|
||||
</Breadcrumbs.Item>
|
||||
<Breadcrumbs.Item href="/">Home</Breadcrumbs.Item>
|
||||
<Breadcrumbs.Separator />
|
||||
<Breadcrumbs.Item>Articles</Breadcrumbs.Item>
|
||||
<Breadcrumbs.Item isCurrent>Articles</Breadcrumbs.Item>
|
||||
</Breadcrumbs>
|
||||
);
|
||||
|
||||
@@ -25,32 +23,25 @@ createPage(
|
||||
paddingY="medium"
|
||||
title="Articles"
|
||||
>
|
||||
<VStack className="w-full" gap={8}>
|
||||
<div className="grid grid-cols-1 gap-8 md:grid-cols-2">
|
||||
{sortedArticles.map((article, index) => (
|
||||
<React.Fragment key={article.slug}>
|
||||
{index > 0 && index % 2 === 0 && (
|
||||
<div className="col-span-1 py-8 md:col-span-2">
|
||||
<Separator className="w-full" type="double" />
|
||||
</div>
|
||||
)}
|
||||
<Article
|
||||
additionalText={article.tags?.join(' • ')}
|
||||
className="h-full"
|
||||
headline={article.title}
|
||||
href={`/articles/${article.slug}`}
|
||||
subHeadline={article.createdDate.toLocaleDateString(undefined, {
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric',
|
||||
})}
|
||||
>
|
||||
{article.description}
|
||||
</Article>
|
||||
</React.Fragment>
|
||||
))}
|
||||
</div>
|
||||
</VStack>
|
||||
<div className="grid grid-cols-1 gap-8 md:grid-cols-2">
|
||||
{sortedArticles.map((article) => (
|
||||
<React.Fragment key={article.slug}>
|
||||
<Article
|
||||
additionalText={article.tags?.join(' • ')}
|
||||
className="h-full"
|
||||
headline={article.title}
|
||||
href={`/articles/${article.slug}`}
|
||||
subHeadline={article.createdDate.toLocaleDateString(undefined, {
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric',
|
||||
})}
|
||||
>
|
||||
{article.description}
|
||||
</Article>
|
||||
</React.Fragment>
|
||||
))}
|
||||
</div>
|
||||
</DefaultLayout>
|
||||
);
|
||||
},
|
||||
|
||||
@@ -9,24 +9,56 @@ createPage(
|
||||
function HomePage(): React.JSX.Element {
|
||||
return (
|
||||
<DefaultLayout centerVertically headerAddonLeft={<Header level={3}>{SITE_TITLE}</Header>}>
|
||||
<VStack gap={4}>
|
||||
<Header level={2}>Welcome to my page!</Header>
|
||||
<Paragraph>
|
||||
If you see this page, my website is successfuly installed and working.
|
||||
<br />
|
||||
It will be further configured.
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
For the source code and support please refer to{' '}
|
||||
<Link href="https://github.com/deytenit/ermnvldmr.com/">ermnvldmr.com monorepo</Link>.
|
||||
<br />
|
||||
Pictures of mine are available at{' '}
|
||||
<Link href="https://ermnvldmr.com/instagram">@deytenit</Link>.
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
Check out my <Link href="/articles">thoughts and articles on various matters</Link>.
|
||||
</Paragraph>
|
||||
<Paragraph italic>Thank you for visiting!</Paragraph>
|
||||
<VStack gap={24}>
|
||||
<Header delay={0} level={1}>
|
||||
Welcome to my corner of the internet.
|
||||
</Header>
|
||||
<VStack gap={12}>
|
||||
<Paragraph delay={300} size="l" type="title">
|
||||
You are arrived right as the lights turned on. The core foundation is solid and the
|
||||
site is officially live,
|
||||
<br />
|
||||
but the metaphorical boxes are still being unpacked. Expect this space to evolve
|
||||
continuously as everything finds its proper place.
|
||||
</Paragraph>
|
||||
<Paragraph delay={350} size="l" type="title">
|
||||
Sharing the underlying architecture is a core philosophy here. If you are curious
|
||||
about the specifics of how it is all built,
|
||||
<br />
|
||||
you can inspect the{' '}
|
||||
<Link href="https://github.com/deytenit/ermnvldmr.com/" size="l" type="title">
|
||||
ermnvldmr.com repository
|
||||
</Link>{' '}
|
||||
to see the complete blueprints.
|
||||
</Paragraph>
|
||||
<Paragraph delay={400} size="l" type="title">
|
||||
For a look at the world away from terminal screens and code editors, the{' '}
|
||||
<Link href="https://ermnvldmr.com/instagram" size="l" type="title">
|
||||
@deytenit
|
||||
</Link>{' '}
|
||||
visual diary captures those moments.
|
||||
</Paragraph>
|
||||
<Paragraph delay={450} size="l" type="title">
|
||||
Whenever you are ready to look around, feel free to dive into{' '}
|
||||
<Link href="/articles" size="l" type="title">
|
||||
the growing collection of articles
|
||||
</Link>
|
||||
.
|
||||
<br />
|
||||
It is a dedicated space covering everything from technical deep-dives to everyday
|
||||
reflections.
|
||||
</Paragraph>
|
||||
<Paragraph delay={500} size="l" type="title">
|
||||
Even though the rest of the environment is still a work in progress, the communication
|
||||
lines are fully operational.
|
||||
<br />
|
||||
Whether you want to discuss tech, share a perspective on a recent read, or simply make
|
||||
a connection, the mailbox is open at...
|
||||
</Paragraph>
|
||||
</VStack>
|
||||
<Link delay={1000} href="mailto:personal@ermnvldmr.com" size="l" type="title">
|
||||
personal@ermnvldmr.com
|
||||
</Link>
|
||||
</VStack>
|
||||
</DefaultLayout>
|
||||
);
|
||||
|
||||
@@ -69,15 +69,11 @@ export const ArticleLayout: React.FC<ArticleLayoutProps> = ({
|
||||
|
||||
const breadcrumbs = (
|
||||
<Breadcrumbs>
|
||||
<Breadcrumbs.Item>
|
||||
<a href="/">Home</a>
|
||||
</Breadcrumbs.Item>
|
||||
<Breadcrumbs.Item href="/">Home</Breadcrumbs.Item>
|
||||
<Breadcrumbs.Separator />
|
||||
<Breadcrumbs.Item>
|
||||
<a href="/articles">Articles</a>
|
||||
</Breadcrumbs.Item>
|
||||
<Breadcrumbs.Item href="/articles">Articles</Breadcrumbs.Item>
|
||||
<Breadcrumbs.Separator />
|
||||
<Breadcrumbs.Item>{title}</Breadcrumbs.Item>
|
||||
<Breadcrumbs.Item isCurrent>{title}</Breadcrumbs.Item>
|
||||
</Breadcrumbs>
|
||||
);
|
||||
|
||||
|
||||
Reference in new issue
Block a user