-
Notifications
You must be signed in to change notification settings - Fork 106
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[shares] usage and demos #13
Comments
今天刚写的 qBittorrent 打洞脚本,可能不太完善,欢迎大家反馈: |
尝试实现了 NAT-PMP 协议给 Transmission 用 |
对于wireguard方式,写了一个PowerShell脚本,能够自动修改配置文件的 使用方法:
在Windows 11, Powershell 5.1.22621.963测试通过,也可以配合Windows下的sudo使用。 另外,在Android下,也可以用termux运行nm-echo.sh来获得IP地址,可以不必更换客户端。 |
TCP 打洞部署 Vmess TCP 代理服务 让流量回家,通过脚本生成 vmess 分享链接保持更新。 对比 wireguard 优点:
SIng-box 服务端 Vmess 配置示例:
配合 natmap 的 linux 脚本(需要 base64 命令,openwrt 通过 opkg install coreutils-base64 安装):
生成的 分享链接 文件可以通过 内网穿透 或者 增加 curl 命令上传至 web 服务暴露出来。 注意:
|
Resolve IP4P and generate config with cloudflare worker. worker.js: /**
* Purpose: Resolve IP4P and generate a configuration using a Cloudflare worker.
*
* Usage:
* 1. Create an online configuration file with placeholders: ${ip4p.ip}, ${ip4p.port}, ${query.xxx}.
* 2. Set your online configuration URL as the CONFIG_URL variable and publish this script as a Cloudflare worker.
* 3. Retrieve your generated configuration by accessing https://YOUR-WORKER.workers.dev/YOUR-random-PATH-12435/clash?IP4P_DOMAIN=YOUR_IP4P_DOMAIN&cipher=YOUR_CIPHER&password=YOUR_PASSWORD.
* 4. Additional keyword checks to the user-agent header can be applied, by setting ALLOW_UA_KEYWORDS.
*
* Notes:
* 1. Only IP4P_DOMAIN is mandatory; the rest of the query parameters are optional.
* 2. The configuration itself can be in any format you like (yaml, json, etc.).
* 3. Add ?_= to the CONFIG_URL to prevent caching.
* 4. Choose a random PATH to prevent URL leakage.
* 5. If the worker's domain is blocked in your region, consider binding the worker to your custom domain.
*/
// Set your online configuration URL here
const CONFIG_URL = 'https://gist.githubusercontent.com/YOUR_ONLINE_CONFIG/config-ss.yaml?_=';
// Choose a random path to prevent URL leakage
const PATH = '/YOUR-random-PATH-12435/clash';
// Keywords to allow in user-agent header
// const ALLOW_UA_KEYWORDS = 'clash,Clash,v2ray'
const ALLOW_UA_KEYWORDS = ''
// Cloudflare DNS-over-HTTPS URL
const DOH_URL = 'https://cloudflare-dns.com/dns-query?ct=application/dns-json';
const ALLOW_UA_KEYWORDS_ARR = ALLOW_UA_KEYWORDS.split(',')
.filter(keyword => keyword)
/**
* Performs an HTTP GET request.
*
* @param {string | URL} url - The URL to fetch.
* @returns {Promise<Response>} A promise that resolves to the fetch response.
*/
const get = async (url) => {
const res = await fetch(url)
if (!res.ok) {
throw new Error(`Request error: ${res.status}`)
}
return res
}
/**
* Resolves DNS records using DNS-over-HTTPS.
*
* @param {string} domain - The domain to resolve.
* @param {string} [type='AAAA'] - The DNS record type (default: 'AAAA').
* @returns {Promise<Object>} A promise that resolves to the DNS response JSON object.
*/
const resolveDNSRecord = async (domain, type = 'AAAA') => {
const url = new URL(DOH_URL)
url.searchParams.append('name', domain)
url.searchParams.append('type', type)
const res = await get(url)
return res.json()
}
/**
* @typedef {Object} IP4PInfo
* @property {string} ip - The IP address.
* @property {number} port - The port number.
*/
/**
* Resolves IP4P information from DNS records.
*
* @param {string} domain - The domain to resolve IP4P for.
* @returns {Promise<IP4PInfo>} A promise that resolves to an object containing IP and port.
* @throws {Error} If the IP4P information is invalid.
*/
const resolveIP4P = async (domain) => {
const json = await resolveDNSRecord(domain)
const answer = json?.Answer
if (!answer || !Array.isArray(answer)) {
throw new Error('Invalid dns record')
}
const data = answer.find(t => t.data)?.data || ''
const parts = data.split(':')
if (parts.length !== 5) {
throw new Error(`Invalid IP4P: ${data}`)
}
// See: https://github.com/heiher/natmap/wiki/ssh#proxycommand
const port = parseInt(parts[2], 16)
const ipab = parseInt(parts[3], 16)
const ipcd = parseInt(parts[4], 16)
if (Number.isNaN(port) || Number.isNaN(ipab) || Number.isNaN(ipcd)) {
throw new Error(`Invalid IP4P values: ${data}`)
}
const ipa = ipab >> 8
const ipb = ipab & 0xff
const ipc = ipcd >> 8
const ipd = ipcd & 0xff
const ip = `${ipa}.${ipb}.${ipc}.${ipd}`
return {
ip,
port,
}
}
/**
* Gets the configuration from the online source with placeholders replaced.
*
* @param {string} url - The URL of the configuration source.
* @param {(type: string, key: string) => string | undefined} replacer - A function that replaces placeholders based on their type and key.
* @returns {Promise<string>} A promise that resolves to the configuration with placeholders replaced.
*/
const getConfig = async (url, replacer) => {
const urlObject = new URL(url)
const {
searchParams,
} = urlObject
if (searchParams.has('_')) {
searchParams.set('_', `${Math.random()}`)
}
const res = await get(urlObject)
const configText = await res.text()
return configText.replace(/\$\{([^}]+)\}/g, (g0, g1) => {
const index = g1.indexOf('.')
if (index === -1) {
return g0
}
const type = g1.slice(0, index)
const key = g1.slice(index + 1)
const value = replacer(type, key)
if (typeof value === 'string') {
return value
}
return g0
})
}
/**
* Checks if the user-agent header is allowed.
*
* @param {string} ua - The user-agent header.
* @returns {boolean} True if user-agent is allowed, false otherwise.
*/
const allowUA = (ua) => {
if (ALLOW_UA_KEYWORDS_ARR.length === 0) {
return true
}
return ALLOW_UA_KEYWORDS_ARR.some(keyword => ua.includes(keyword))
}
/**
* Main function to handle requests.
*
* @param {Request} request - The request object.
* @returns {Promise<string>} A promise that resolves to the response.
* @throws {Error}
*/
const main = async (request) => {
const {
url,
headers,
} = request
const ua = headers.get('user-agent')
if (!allowUA(ua)) {
throw new Error('Invalid user-agent, failed to pass keyword checking')
}
const {
pathname,
searchParams,
} = new URL(url)
if (pathname !== PATH) {
throw new Error(`Unknown request: ${pathname}`)
}
const domain = searchParams.get('IP4P_DOMAIN')
if (!domain) {
throw new Error('Domain name not provided')
}
const ip4p = await resolveIP4P(domain)
const config = await getConfig(CONFIG_URL, (type, key) => {
if (type === 'ip4p' && (key === 'ip' || key === 'port')) {
return `${ip4p[key]}`
} else if (type === 'query') {
return searchParams.get(key) || ''
}
return undefined;
})
return config
}
// Cloudflare worker export
export default {
/**
* Cloudflare Worker Fetch Function.
*
* @param {Request} request - The incoming request object.
* @param {Object} env - The environment object.
* @param {Object} ctx - The context object.
* @returns {Promise<Response>} A promise that resolves to the response.
*/
async fetch(request, env, ctx) {
try {
const content = await main(request)
return new Response(content, {
status: 200,
headers: {
'cache-control': 'no-cache, no-store'
}
})
} catch (e) {
console.error(e)
return new Response('', {
status: 404,
headers: {
'cache-control': 'no-cache, no-store'
}
})
}
},
} Config file (can be yaml, json, whatever format you like): mixed-port: 7890
mode: rule
ipv6: true
dns:
ipv6: true
proxies:
-
name: proxy-server
type: ss
server: ${ip4p.ip}
port: ${ip4p.port}
cipher: "${query.cipher}"
password: "${query.password}"
udp: true
proxy-groups:
-
name: PROXY
type: select
proxies:
- proxy-server
- DIRECT
rule-providers:
reject:
type: http
behavior: domain
url: "https://ghproxy.com/https://raw.githubusercontent.com/Loyalsoldier/clash-rules/release/reject.txt"
path: ./ruleset/reject.yaml
interval: 86400
private:
type: http
behavior: domain
url: "https://ghproxy.com/https://raw.githubusercontent.com/Loyalsoldier/clash-rules/release/private.txt"
path: ./ruleset/private.yaml
interval: 86400
gfw:
type: http
behavior: domain
url: "https://ghproxy.com/https://raw.githubusercontent.com/Loyalsoldier/clash-rules/release/gfw.txt"
path: ./ruleset/gfw.yaml
interval: 86400
tld-not-cn:
type: http
behavior: domain
url: "https://ghproxy.com/https://raw.githubusercontent.com/Loyalsoldier/clash-rules/release/tld-not-cn.txt"
path: ./ruleset/tld-not-cn.yaml
interval: 86400
telegramcidr:
type: http
behavior: ipcidr
url: "https://ghproxy.com/https://raw.githubusercontent.com/Loyalsoldier/clash-rules/release/telegramcidr.txt"
path: ./ruleset/telegramcidr.yaml
interval: 86400
applications:
type: http
behavior: classical
url: "https://ghproxy.com/https://raw.githubusercontent.com/Loyalsoldier/clash-rules/release/applications.txt"
path: ./ruleset/applications.yaml
interval: 86400
rules:
- RULE-SET,applications,DIRECT
- RULE-SET,private,DIRECT
- RULE-SET,reject,REJECT
- RULE-SET,tld-not-cn,PROXY
- RULE-SET,gfw,PROXY
- RULE-SET,telegramcidr,PROXY
- MATCH,DIRECT |
https://github.com/sub-store-org/Sub-Store 的节点域名解析支持了 IP4P |
clash.meta(mihomo) 已支持 IP4P 出站 感谢 亚托莉佬以及 mihomo 开发组接受我的建议( 用法: 开启 IPv6, 在需要使用的地方配置 IP4P 域名. IP4P 节点和 ip4p.web.com 这个服务可以正常使用
|
IP4P 请求自动重定向(以 Surge 为例) 效果为 访问 使用场景 使用固定的 URL 访问 STUN 打洞的内网服务 模块和脚本见 https://t.me/zhetengsha/1198 |
可以利用自部署的pastebin服务,例如SharzyL/pastebin-worker,来提供分享链接,不必暴露自己的web服务。 配合 natmap 的 linux 脚本(也需要 base64 命令): #!/bin/bash
ip_address="${1}"
port="${2}"
pastebin_url="https://shz.al/"
pastebin_name="<随机字符串a>"
pb_pass="<随机字符串b>"
raw_ss_url="ss://2022-blake3-aes-128-gcm:<密码>@${ip_address}:${port}#ss-home4
ss://2022-blake3-aes-128-gcm:<密码>@<其他地址>#ss-home6
"
# Apply base64 encoding
base64_encoded=$(echo -n "${raw_ss_url}" | base64 -w 0)
# Upload the result using curl
curl -Fc="${base64_encoded}" -Fe="24M" -Fs="${pb_pass}" -Fn="${pastebin_name}" "${pastebin_url}"
curl -X PUT -Fc="${base64_encoded}" -Fe="24M" "${pastebin_url}~${pastebin_name}:${pb_pass}"
然后就可以用 |
我尝试着给 WireGuard iOS 官方客户端添加了 IP4P 支持,自己用下来没有问题,这里分享出来。 用法也很简单,和 Android 基本一样,不过会判断 peer 端口填写为 0 才会开启 IP4P 解析。 https://github.com/yv-code/wireguard-apple 感谢各位开源作者。 |
截至 2024.06.03 , 使用NATMap在NAT-1私网IP宽带上部署Web服务 一文中的 wdns 脚本已不能正常运作,应该是 Cloudflare 改了 API,故更新脚本。脚本中的子域名,Origin 规则(名称默认 natmap) 都需要在面板中预先创建。脚本需要 jq 支持。
|
cf 重定向 脚本
|
wireguard windows便携版客户端,支持IP4P解析,端口随意写,域名解析到IP4P地址时会自动解析IP和端口。 |
可否增加一个TXT解析功能呢?有些环境无法解析IPV6/IP4P |
我之前的实现(使用系统DNS解析器)确实在某些系统上存在无法解析AAAA记录的情况,看这版实现可能是可以的,建议实测看看。 |
这个默认使用223.5.5.5的DNS解析,没有使用系统DNS解析,理论上不存在无法解析AAAA记录的情况,我实测只要能联网的环境都可以使用(PS:如果局域网劫持所有53端口的DNS解析请求到不支持解析AAAA记录的内网DNS另说。。。)。
|
感谢,heiher 的版本一直会触发更新,显示"正在获取更新元数据",你的是否可以取消它的更新检测? |
没做处理,目前是基于最新版改的,没弹更新,后面有更新了我再跟进,升级逻辑在这里 ui/src/main/java/com/wireguard/android/updater/Updater.kt,可以问问chatgpt自己改改 |
Welcome to share the usage and demos.
欢迎分享用法、示例。
The text was updated successfully, but these errors were encountered: