Homepage
Privacy Policy
iYoRoy DN42 Network
About
More
Friends
Language
简体中文
English
Search
1
Centralized Deployment of EasyTier using Docker
1,705 Views
2
Adding KernelSU Support to Android 4.9 Kernel
1,091 Views
3
Enabling EROFS Support for an Android ROM with Kernel 4.9
309 Views
4
Installing 1Panel Using Docker on TrueNAS
300 Views
5
2025 Yangcheng Cup CTF Preliminary WriteUp
296 Views
Android
Ops
NAS
Develop
Network
Projects
DN42
One Man ISP
CTF
Kubernetes
Cybersecurity
Brain Dumps
IoT
Login
Search
Search Tags
Network Technology
BGP
BIRD
Linux
DN42
Android
OSPF
C&C++
Web
AOSP
CTF
Cybersecurity
Docker
iBGP
Windows
MSVC
Services
Kernel
IGP
TrueNAS
Kagura iYoRoy
A total of
35
articles have been written.
A total of
23
comments have been received.
Index
Column
Android
Ops
NAS
Develop
Network
Projects
DN42
One Man ISP
CTF
Kubernetes
Cybersecurity
Brain Dumps
IoT
Pages
Privacy Policy
iYoRoy DN42 Network
About
Friends
Language
简体中文
English
35
articles related to
were found.
Centralized Deployment of EasyTier using Docker
EasyTier is inherently a decentralized P2P tool where any node can act as a relay server. However, each node's configuration file must be manually edited, which felt somewhat unfamiliar after migrating from Tailscale. Additionally, during the exploration phase, frequent configuration changes are often needed, leading to the decision to deploy EasyTier's Dashboard centrally for unified device management. Project Repository: https://github.com/easytier/easytier The official documentation doesn't explicitly provide a method for deploying the config-server separately, but it's actually quite straightforward, as the server component is already included in the downloaded binary file. This article focuses on installation via Docker Compose. For binary installation, please refer to the reference articles below. Analysis The dashboard deployment consists of two main parts: a backend RESTful API and a frontend web console. The easytier-web-embed binary found in the Releases provides both. Therefore, running this single binary enables the full functionality. Let's Get Started Deploying the API and Web Console Deploying with Docker is straightforward. Two ports need to be exposed: 11211/tcp: API interface, HTTP 22020/udp: For communication between clients (easytier-core) and the server. Volume mapping is required for the container's /app folder to persist data. The Compose file is as follows: services: easytier: restart: always hostname: easytier volumes: - /opt/easytier/api:/app ports: - "127.0.0.1:11211:11211" - "22020:22020/udp" environment: - TZ=Asia/Shanghai image: easytier/easytier:latest entrypoint: easytier-web-embed The image here is the same one used for deploying the client via Docker in the official documentation. The default entrypoint is easytier-core, so running the web API requires specifying the entrypoint as easytier-web-embed. Since the API interface requires HTTPS, the 11211 port is not directly exposed to the public internet here. Instead, it's bound to 127.0.0.1 and then exposed via a reverse proxy with HTTPS. Setting up Reverse Proxy I use 1Panel, so I simply created a new site in the panel and set up a reverse proxy to the configured API port. Registering a Console Account After deployment, open https://your-domain.com (if using the built-in console version, adding /web/ is not necessary). Change the 'Api Host' to https://your-domain.com. Ensure there is no trailing "/" in the Api Host URL, otherwise, strange issues may occur. Click 'Register' below to create an account. Then use this account to log in and access the console. Client Configuration Remove all startup parameters for the client, keeping only --config-server udp://your-ip:22020/your-username. Run the easytier-core binary, and the device should appear in the console. Click the settings button on the right, then click 'Create' to create a network for it. The subsequent steps are the same as in the local GUI mode and won't be detailed here. After saving, select the newly created network from the 'network' dropdown to join it. Because Docker container data is lost on restart, when deploying the client in Docker, a file must be mapped to the container path /usr/local/bin/et_machine_id to save the machine ID. Otherwise, the network will need to be reconfigured after each restart. Additionally, setting the container's hostname can be used as the device name displayed in the web console. Here is my compose file for the client: services: easytier: command: '--config-server udp://<ip>:22020/KaguraiYoRoy' environment: - TZ=Asia/Shanghai hostname: truenas image: easytier/easytier:latest labels: com.centurylinklabs.watchtower.enable: 'true' mem_limit: 0m network_mode: host privileged: True restart: always volumes: - >- /mnt/systemdata/DockerData/easytier/app/et_machine_id:/usr/local/bin/et_machine_id watchtower: command: '--interval 3600 --cleanup --label-enable' environment: - TZ=Asia/Shanghai - WATCHTOWER_NO_STARTUP_MESSAGE image: containrrr/watchtower restart: always volumes: - /var/run/docker.sock:/var/run/docker.sock References: https://blog.mitsea.com/1a57bda595c580088006c17d6ba2a744/ https://github.com/EasyTier/EasyTier/issues/722 https://github.com/EasyTier/EasyTier/issues/577 https://github.com/EasyTier/EasyTier/pull/718
15/04/2025
3,971 Views
0 Comments
7 Stars
Querying DNS Records Using WINAPI in C++
This article has been migrated from an old blog (a kind of cyber reincarnation). Corrections are welcome if any errors are found. Timeline {timeline} {timeline-item color="#50BFFF"} July 5, 2022: Published on the old blog, available on archive.org {/timeline-item} {timeline-item color="#50BFFF"} March 20, 2025: Migrated to the current blog {/timeline-item} {timeline-item color="#4F9E28"} Febuary 21, 2026: Added reminder for header and static library file links {/timeline-item} {/timeline} Background Multiple access endpoints were configured for an API to handle service unavailability in certain regions where access might be blocked. Initially, I considered creating a file within the website to store node information, but this approach proved unfeasible because regions with connectivity issues couldn't retrieve information about other endpoints. Then, the idea emerged to use DNS resolution records - specifically, a TXT record - to store the relevant node data for querying. Implementation Research After searching on Bing, I found that most existing articles use sockets to directly send query packets. However, these methods typically only retrieve A and CNAME records, which wasn't suitable for my needs. Finally, I focused on the DnsQuery function mentioned in MSDN and found a sample article: Use DnsQuery to Resolve Host Names. Function Analysis According to the official documentation, the function requires the header windns.h and needs to link against the libraries Ws2_32.lib and Dnsapi.lib. The function parameters are as follows: DNS_STATUS DnsQuery_A( [in] PCSTR pszName, [in] WORD wType, [in] DWORD Options, [in, out, optional] PVOID pExtra, [out, optional] PDNS_RECORD *ppQueryResults, [out, optional] PVOID *pReserved ); Parameter Explanation: pszName is the hostname to query. wType is the query type, such as A record, CNAME, TXT, etc. Specific constants are documented by MSDN: DNS Constants. Options literally means the query method. I used DNS_QUERY_STANDARD directly. Details can also be found in the documentation: DNS Constants. pExtra and pReserved can simply be set to NULL. ppQueryResultsis a pointer to the query results, of type PDNS_RECORD*. This requires passing a reference to the variable's value. Return value: The DNS_STATUS type. If the query fails, it returns the corresponding error code from Winerror.h. Usage Understanding the usage method made it straightforward. To avoid linker errors, make sure to include the following headers and libraries at the beginning: #include <windns.h> #pragma comment(lib, "Ws2_32.lib") #pragma comment(lib, "Dnsapi.lib") My TXT record domain is test.iyoroy.cn. The query code is as follows: PDNS_RECORD pDnsRecord; DNS_STATUS QueryRet = DnsQuery(L"test.iyoroy.cn", DNS_TYPE_TEXT, DNS_QUERY_STANDARD, NULL, &pDnsRecord, NULL); if (QueryRet) { MessageBox(GhWnd, L"DNS query failed!\r\nWill use the default node.", L"Warning", MB_ICONERROR | MB_OK); } std::wstring strQueryRes = *pDnsRecord->Data.TXT.pStringArray; // This is the query result. Successfully implemented the functionality. Postscript TXT records automatically filter out spaces and line breaks. Therefore, I chose to store Base64 encoded data in the record, decode it when used, and then split it using stringstream. For Base64 decoding, I adapted the code from this article: Base64 Encoding and Decoding in C++. Below is the rewritten decoding function using wide characters: {collapse} {collapse-item label="Expand Code"} //Function: Base64 Decryption static const std::wstring base64_chars = L"ABCDEFGHIJKLMNOPQRSTUVWXYZ" L"abcdefghijklmnopqrstuvwxyz" L"0123456789+/"; static inline bool is_base64(wchar_t c) { return (isalnum(c) || (c == L'+') || (c == L'/')); } std::wstring base64_decode(std::wstring const& encoded_string) { int in_len = encoded_string.size(); int i = 0; int j = 0; int in_ = 0; wchar_t char_array_4[4], char_array_3[3]; std::wstring ret; while (in_len-- && (encoded_string[in_] != L'=') && is_base64(encoded_string[in_])) { char_array_4[i++] = encoded_string[in_]; in_++; if (i == 4) { for (i = 0; i < 4; i++) char_array_4[i] = base64_chars.find(char_array_4[i]); char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; for (i = 0; (i < 3); i++) ret += char_array_3[i]; i = 0; } } if (i) { for (j = i; j < 4; j++) char_array_4[j] = 0; for (j = 0; j < 4; j++) char_array_4[j] = base64_chars.find(char_array_4[j]); char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; for (j = 0; (j < i - 1); j++) ret += char_array_3[j]; } return ret; } Splitting the decoded string: wstringstream wDnsRec(base64_decode(*pDnsRecord->Data.TXT.pStringArray)); wstring wNodes[16]; unsigned int nNodes = 0; while (wDnsRec >> wNodes[nNodes]) nNodes++; {/collapse-item} {/collapse} After that, selecting an available node becomes possible. Reference Articles: https://learn.microsoft.com/en-us/previous-versions/troubleshoot/windows/win32/use-dnsquery-resolve-host-names https://learn.microsoft.com/en-us/windows/win32/dns/dns-constants https://blog.csdn.net/sky04/article/details/6881649
20/03/2025
206 Views
4 Comments
4 Stars
Using Alist to Sync TrueNAS to OneDrive
Background I have an E5 subscription and was originally using a solution involving running the driveone/onedrive:edge Docker container to achieve synchronization. However, this solution had drawbacks: firstly, it lacked a GUI/WebUI, and secondly, each sync operation would consume 25%-50% of CPU resources. Considering that TrueNAS's built-in sync solution can sync to WebDAV, I thought of using Alist to mount OneDrive and convert it into WebDAV for TrueNAS to mount. Process Installing Alist Create a persistent storage folder for Alist and write a Docker Compose file according to the official Alist documentation: services: alist: environment: - PUID=3000 - PGID=950 - UMASK=022 image: xhofe/alist:latest ports: - '8088:5244' restart: always volumes: - /mnt/systemdata/DockerData/alist/etc:/opt/alist/data - /mnt/data/Storage:/mnt/data Here, I exposed the Alist port on 8088. Mapping /mnt/data/Storage allows Alist to manage local storage; mapping /mnt/systemdata/DockerData/alist/etc serves as the folder for storing Alist data. Configuring OneDrive on Alist is not discussed in this article; please refer to the official Alist documentation. Here, I mounted my OneDrive at /OneDrive. After setup, go to the Alist admin panel -> Users, edit your user or create a new user, and check the Webdav Read and Webdav Manage permissions to enable WebDAV access for this user. Configuring TrueNAS Sync Go to TrueNAS Admin-Credentials-Backup Credentials, and add a Cloud Credential with the following parameters: Provider: WebDAV Name: Custom URL: Alist address +/dav, e.g., I used http://127.0.0.1:8088/dav WebDAV Service: OTHER Username和Password: Alist account credentials Verify the credential and save it if successful. Next, go to TrueNAS Admin -> Data Protection, and add a Cloud Sync Task. Under Provider, select the WebDAV credential for Alist created earlier. The parameters are explained in detail below: Direction: Choose PULL (cloud to local) or PUSH (local to cloud) Transfer Mode: COPY: Copy files. Files deleted from the source folder later will not be deleted from the target. MOVE: Copy files and then delete them from the source folder after transfer. SYNC: Keep the source and target folders synchronized. Files deleted from the source will also be deleted from the target. Directory/Files: The local file or folder to sync. Folder: The target folder in the cloud storage. Description: Notes. Schedule: Set a schedule using Cron syntax. You can use predefined intervals or write your own. For example, I selected PUSH, SYNC, syncing from /mnt/data/Storage to /OneDrive/TrueNAS, scheduled to run daily at 00:00. After editing, save the task. It will automatically upload local files to OneDrive at the scheduled time. Old Solution Project Address: https://github.com/abraunegg/onedrive Reference Articles: https://alist.nn.ci/zh/guide/install/docker.html https://alist.nn.ci/zh/guide/drivers/onedrive.html
13/03/2025
397 Views
0 Comments
1 Stars
Using Home Broadband without Public IP + CDNfly to Host a Website
Introduction As is well known, hosting a website with home broadband usually requires a public IP address. However, in certain cases without a public IP, it is possible to expose an HTTP port on the carrier's exit IP for external connections through special methods, i.e., NAT penetration (this is different from FRP, ngrok, or Oray-like intranet penetration, as it does not require a server). Prerequisites Download NatTypeTester to check your NAT type. Please refer to relevant materials for details on NAT types. Ensure your network environment meets the following conditions: Under RFC3489, the NAT type must be Full Cone. Under RFC5780, the TCP mapping behavior must be EndpointIndependent. If UDPBlocked appears, change the server. Methods to Improve NAT Type Reduce the number of router layers. If using modem dial-up, connect the device directly under the modem. For multi-layer routing, connect the device directly under the top router. Enable UPnP on the router. Set the DMZ host to the server IP. Getting Started We use Lucky as the NAT penetration tool, deployed on TrueNAS via Docker Compose. TrueNAS locally has port 9080 open for HTTP. Deploying a web server is not covered in this article. Installing Lucky Follow the official guide and write a Docker Compose file: services: lucky: image: gdy666/lucky network_mode: host restart: always volumes: - /mnt/systemdata/DockerData/lucky/luckyconf:/goodluck Modify the persistent storage path to your own. Note: network_mode must be host. It can be deployed without host, but that is not discussed here. After installation, open http://[YourIP]:16601. The default username is 666 and password is 666. After logging in, modify security settings as required. Configuring Penetration Open STUN Intranet Penetration on the left side of the Lucky page and create a penetration rule. Fill in the local port with any port (ensure it does not conflict with local services), and the target address and port with the IP and port of the web service on the intranet. After completing the above configuration, choose one of the following penetration methods: {tabs} {tabs-pane label="NAT-PMP Method"} Enable the router's UPnP function, turn on the NAT-PMP switch in STUN penetration, and fill in the router address as the NAT-PMP gateway address. {/tabs-pane} {tabs-pane label="DMZ Host Method"} Set the server IP where Lucky is installed as the DMZ host in the router's DMZ settings, then turn off the UPnP and NAT-PMP options in STUN penetration. {/tabs-pane} {tabs-pane label="Non-Docker Installation + UPnP"} Enable the router's UPnP function, turn on the UPnP switch in STUN penetration, fill in the router IP as the UPnP gateway IP, and fill in the Lucky host IP as the UPnP client local IP, leaving others blank. {/tabs-pane} {tabs-pane label="Docker Installation + UPnP"} First, run Lucky in a non-Docker environment to obtain the UPnP interface address. For example, install Lucky on a computer (Windows) and create a test tunnel with the same content as the non-Docker installation. The target address and port can be filled arbitrarily. After enabling penetration, you might see content like this in the log: UPNP===>Control URL: http://192.168.3.1:5351/ctl/IPCon (Here, the URL is my Xiaomi router AX3600's UPnP management address; different routers may vary.) Copy the Control URL, then fill it into the UPnP Control Interface Address in the Docker Lucky and enable penetration. {/tabs-pane} {/tabs} If no issues arise, you should see the address and port assigned by the carrier's public exit IP. If you can access it from outside or if an itdog test shows green, the penetration is successful. Configuring CDNfly WebHook Since the public IP and port obtained this way are dynamic, a service similar to DDNS is needed to fix the access method. You can use CloudFlare Workers for redirection or use a CDN to dynamically modify the origin IP and port. I use the latter. My CDN uses the cdnfly management system. Refer to the cdnfly official documentation for API request methods. When editing the STUN intranet penetration rule, open Webhook below and check Only trigger Webhook when the address is different from the last time. Fill in the API address: https://[your-cdn-domain]/v1/sites, request method PUT; request headers include api-key and api-secret (can be found in the CDNfly backend): api-key: Your API Key api-secret: Your API Secret The request body uses JSON format to construct the payload according to the cdnfly official documentation (change the id field to your website id; if multiple websites, copy and modify accordingly): [ { "id": 114, "backend_http_port": #{port}, "backend": [ { "addr": "#{ip}", "weight": 1, "state": "up" } ] }, { "id": 514, "backend_http_port": #{port}, "backend": [ { "addr": "#{ip}", "weight": 1, "state": "up" } ] } ] Where #{ip} and #{port} are parameters provided by Lucky, representing the obtained public IP and port. Save, and if no issues, the CDN's corresponding website's origin address and port will be automatically changed to the carrier's public IP and port. Security Considerations I recommend using HTTPS penetration because HTTP is plain text and less secure. If using HTTPS, change backend_http_port to backend_https_port in the CDN API call payload and switch to HTTPS origin in the CDN. Reference Articles: https://doc.cdnfly.cn/wangzhanguanli-v1-sites.html https://lucky666.cn/docs/intro https://www.bilibili.com/opus/971100369193009187 https://github.com/gdy666/lucky
09/03/2025
379 Views
0 Comments
1 Stars
Installing 1Panel Using Docker on TrueNAS
Background My TrueNAS has some performance headroom, so I'm thinking of deploying a web service. I want to install a control panel to reduce manual work. Considering the performance overhead of virtual machines, the high memory requirements for ZFS cache, and the fact that the NAS itself isn't very powerful, I decided to use Docker for deployment. Furthermore, since 1Panel itself is distributed as a Docker image, both systems controlling the TrueNAS host's Docker daemon is essentially equivalent to deploying websites directly on the TrueNAS host, making management easier. Analysis {alert type="warning"} This article assumes TrueNAS can access Docker Hub and the Docker daemon is already configured. {/alert} Environment Information Storage Pool There are two storage pools: /mnt/data: 1 x MIRROR | 2 wide | 2.73 TiB | HDD /mnt/systemdata: 1 x DISK | 1 wide | 223.57 GiB | SSD Docker data is stored in storage pool #2. Datasets There are three datasets: Storage: Located in the data storage pool, stores cold data. DockerData: Located in the systemdata storage pool, stores persistent data for containers. KaguraiYoRoy: Located in systemdata, the user's home directory. Installing 1Panel Used the moelin/1panel:latest image for deployment. Many parts of this process can refer to the README written by the image author. Project address: okxlin/docker-1panel Created a folder specifically for storing 1Panel data within the DockerData dataset, which is used as /opt/1panel inside the container, located at /mnt/systemdata/DockerData/1panel. Persistent Volumes To allow 1Panel to manage the host's Docker, map /var/run/docker.sock and the host's Docker directory. Map the data folder created for it earlier. The Docker directory in TrueNAS is different from typical Linux systems. Typically, it's at /var/lib/docker, but in TrueNAS, it's at /mnt/.ix-apps/docker. Environment Variables and Port Mapping The environment variables are the same as those set by the image author, passing TZ=Asia/Shanghai. Port mapping can be set as needed; the container's port is 10086. Docker Compose With the above information, writing the Docker Compose file becomes straightforward. The complete Docker Compose file is as follows: services: 1panel: dns: - 223.5.5.5 environment: - TZ=Asia/Shanghai image: moelin/1panel:latest labels: createdBy: Apps ports: - '8085:10086' restart: always volumes: - /var/run/docker.sock:/var/run/docker.sock - /mnt/.ix-apps/docker:/var/lib/docker - /mnt/systemdata/DockerData/1panel/opt:/opt/1panel - /mnt/systemdata/DockerData/1panel/root:/root - /etc/docker:/etc/docker Mapping /root is because I need to run Git inside the container, and Git config is stored under /root. Setting DNS is because 1Panel needs to download data online when building environment images, and errors occur without specifying DNS. After installation, access the port you set. 1Panel Basic Information: Default Username: 1panel Default Password: 1panel_password Default Entrance: entrance Troubleshooting Docker Mirror During testing, it was found that without setting a mirror source, even with a Proxy configured, installing the PHP environment would fail. Furthermore, configuring both a mirror source and a Proxy also led to installation failure; the reason is unclear. Open /etc/docker/daemon.json on TrueNAS and add registry-mirrors: { "data-root": "/mnt/.ix-apps/docker", "default-address-pools": [ { "base": "172.17.0.0/12", "size": 24 } ], "exec-opts": [ "native.cgroupdriver=cgroupfs" ], "iptables": true, "registry-mirrors": [ "https://docker.1panel.live" ], "storage-driver": "overlay2" } Save the file, restart the host's Docker service, then try installing the environment in 1Panel again. {alert type="warning"} This configuration might be lost after a reboot. Try to install all necessary environments and apps in one go if possible. {/alert} Containers Created by 1Panel Fail to Start This is because in 1Panel, the default folder for storing data is the mapped /opt/1panel. However, the containers actually run on the TrueNAS host and try to access /opt/1panel, which doesn't exist on TrueNAS by default, and its /opt is read-only by default. This causes a "Read-only filesystem" error when starting containers. My solution is straightforward: On the TrueNAS host, first remount /opt as read-write, then create a symbolic link pointing to 1Panel's data folder. cd /opt mount -o remount,rw /opt ln -s /mnt/systemdata/DockerData/1panel/opt 1panel After this, it should work normally. One thing to note: When installing OpenResty in 1Panel, remember to avoid using ports 80 and 443, as these are the default ports for the TrueNAS web UI.
07/03/2025
822 Views
0 Comments
1 Stars
1
...
5
6
7