├── .github
└── workflows
│ └── NanoPi-R2S RK3328 OpenWrt 19.07 Build.yml
├── CHANGELOG.md
├── README.md
├── patches
├── 001-add-full_cone_nat.patch
└── 011-fix-zerotier-aes.patch
├── r2s-rk3328-config
└── rk3328.xml
/.github/workflows/NanoPi-R2S RK3328 OpenWrt 19.07 Build.yml:
--------------------------------------------------------------------------------
1 | name: NanoPi-R2S RK3328 OpenWrt 19.07 Build
2 |
3 | on:
4 | push:
5 | paths:
6 | - 'CHANGELOG.md'
7 |
8 | jobs:
9 |
10 | build:
11 |
12 | runs-on: self-hosted
13 |
14 | steps:
15 |
16 | - name: Checkout
17 | uses: actions/checkout@master
18 | with:
19 | ref: master
20 |
21 | - name: Initialize Environment
22 | env:
23 | DEBIAN_FRONTEND: noninteractive
24 | run: |
25 | sudo apt-get update
26 | sudo rm -rf /usr/share/dotnet /usr/local/lib/android/sdk
27 | sudo docker image prune -a -f
28 | sudo apt-get -y install unzip subversion
29 | sudo apt-get -y purge dotnet* ghc* google* llvm* mysql* php* zulu* firefox hhvm
30 | sudo apt-get -y autoremove --purge
31 | wget -O - https://raw.githubusercontent.com/friendlyarm/build-env-on-ubuntu-bionic/master/install.sh | bash
32 |
33 | #- name: Setup Debug Session
34 | # uses: P3TERX/debugger-action@master
35 |
36 | - name: Install Repo
37 | run: |
38 | git clone https://github.com/friendlyarm/repo
39 | sudo cp repo/repo /usr/bin/
40 |
41 | - name: Download Source
42 | run: |
43 | rm -rf code
44 | mkdir code
45 | cd code
46 | repo init -u https://github.com/friendlyarm/friendlywrt_manifests -b master-v19.07.5 -m rk3328.xml --repo-url=https://github.com/friendlyarm/repo --no-clone-bundle
47 | cp ../rk3328.xml ../code/.repo/manifests/rk3328.xml
48 | repo sync -c --no-clone-bundle -j8
49 |
50 | - name: Merge LEDE
51 | run: |
52 | cd code
53 | git clone https://github.com/coolsnowwolf/lede
54 | cd friendlywrt
55 | cp -r ../lede/package/lean package/
56 | cp -r ../lede/package/libs/pcre package/libs/
57 | sed -i 's/^src-git luci.*/src-git luci https:\/\/github.com\/coolsnowwolf\/luci/' feeds.conf.default
58 | sed -i 's/^src-git packages.*/src-git packages https:\/\/github.com\/coolsnowwolf\/packages;openwrt-19.07/' feeds.conf.default
59 | echo 'src-git node https://github.com/nxhack/openwrt-node-packages.git' >> feeds.conf.default
60 |
61 | - name: Install Extra Packages
62 | run: |
63 | cd code/friendlywrt/package
64 |
65 | git clone https://github.com/rufengsuixing/luci-app-adguardhome
66 |
67 | git clone https://github.com/jerrykuku/lua-maxminddb.git
68 | git clone https://github.com/jerrykuku/luci-app-vssr.git
69 |
70 | rm -rf lean/luci-theme-argon
71 | git clone -b 18.06 https://github.com/jerrykuku/luci-theme-argon.git
72 |
73 | svn co https://github.com/vernesong/OpenClash/trunk/luci-app-openclash
74 |
75 | svn co https://github.com/xiaorouji/openwrt-passwall/trunk/luci-app-passwall
76 | svn co https://github.com/xiaorouji/openwrt-passwall/trunk/tcping
77 | svn co https://github.com/xiaorouji/openwrt-passwall/trunk/ssocks
78 | svn co https://github.com/xiaorouji/openwrt-passwall/trunk/trojan-plus
79 | svn co https://github.com/xiaorouji/openwrt-passwall/trunk/trojan-go
80 | svn co https://github.com/xiaorouji/openwrt-passwall/trunk/naiveproxy
81 | svn co https://github.com/xiaorouji/openwrt-passwall/trunk/brook
82 | svn co https://github.com/xiaorouji/openwrt-passwall/trunk/chinadns-ng
83 | svn co https://github.com/xiaorouji/openwrt-passwall/trunk/xray-core
84 | svn co https://github.com/xiaorouji/openwrt-passwall/trunk/xray-plugin
85 |
86 | svn co https://github.com/songchenwen/nanopi-r2s/trunk/luci-app-r2sflasher
87 |
88 | svn co https://github.com/pymumu/smartdns/trunk/package/openwrt smartdns
89 | svn co https://github.com/pymumu/luci-app-smartdns/branches/lede luci-app-smartdns
90 |
91 | svn co https://github.com/lisaac/luci-app-dockerman/trunk/applications/luci-app-dockerman
92 |
93 | git clone https://github.com/jerrykuku/luci-app-jd-dailybonus.git
94 | git clone https://github.com/NateLol/luci-app-oled
95 |
96 | - name: Install Clash Binaries
97 | run: |
98 | cd code/friendlywrt/package/base-files/files
99 | mkdir -p etc/openclash/core
100 | # for updates, go to: https://github.com/Dreamacro/clash/releases
101 | wget -qO- https://github.com/Dreamacro/clash/releases/download/v1.4.2/clash-linux-armv8-v1.4.2.gz | gunzip -c > etc/openclash/core/clash
102 | # for updates, go to: https://github.com/vernesong/OpenClash/releases/tag/TUN-Premium
103 | wget -qO- https://github.com/vernesong/OpenClash/releases/download/TUN-Premium/clash-linux-armv8-2021.03.10.gz | gunzip -c > etc/openclash/core/clash_tun
104 | # for updates, go to: https://github.com/vernesong/OpenClash/releases/tag/TUN
105 | wget -qO- https://github.com/vernesong/OpenClash/releases/download/TUN/clash-linux-armv8.tar.gz | tar xOvz > etc/openclash/core/clash_game
106 | chmod +x etc/openclash/core/clash*
107 |
108 | - name: Update Target.mk
109 | run: |
110 | cd code/friendlywrt/include
111 | sed -i 's/dnsmasq /dnsmasq-full default-settings luci /' target.mk
112 |
113 | - name: Update Feeds
114 | run: |
115 | cd code/friendlywrt
116 | ./scripts/feeds update -a
117 | ./scripts/feeds install -a
118 |
119 | - name: Install Mods
120 | run: |
121 | cd code/friendlywrt
122 |
123 | rm -rf feeds/packages/libs/libcap
124 | svn co https://github.com/openwrt/packages/trunk/libs/libcap feeds/packages/libs/libcap
125 |
126 | rm -rf package/feeds/packages/netdata
127 | svn co https://github.com/openwrt/packages/trunk/admin/netdata package/feeds/packages/netdata
128 |
129 | rm -rf feeds/packages/libs/libnatpmp
130 | svn co https://github.com/coolsnowwolf/packages/trunk/libs/libnatpmp feeds/packages/libs/libnatpmp
131 |
132 | rm -rf feeds/packages/lang/luasec
133 | svn co https://github.com/coolsnowwolf/packages/trunk/lang/luasec feeds/packages/lang/luasec
134 |
135 | sed -i '/STAMP_BUILT/d' feeds/packages/utils/runc/Makefile
136 | sed -i '/STAMP_BUILT/d' feeds/packages/utils/containerd/Makefile
137 |
138 | sed -i '/upx/d' package/lean/frp/Makefile
139 | sed -i '/upx/d' package/lean/UnblockNeteaseMusicGo/Makefile
140 | sed -i '/upx/d' package/trojan-go/Makefile
141 |
142 | wget -O package/kernel/kmod-sched-cake/Makefile https://raw.githubusercontent.com/coolsnowwolf/lede/master/package/kernel/kmod-sched-cake-oot/Makefile
143 | wget -O feeds/packages/libs/libxml2/Makefile https://raw.githubusercontent.com/coolsnowwolf/packages/master/libs/libxml2/Makefile
144 |
145 | sed -i "/redirect_https/d" package/network/services/uhttpd/files/uhttpd.config
146 | sed -i '/Load Average/i\\t\t
<%:CPU Temperature%> | <%=luci.sys.exec("cut -c1-2 /sys/class/thermal/thermal_zone0/temp")%>℃ |
' feeds/luci/modules/luci-mod-admin-full/luasrc/view/admin_status/index.htm
147 | sed -i 's/pcdata(boardinfo.system or "?")/"ARMv8"/' feeds/luci/modules/luci-mod-admin-full/luasrc/view/admin_status/index.htm
148 | sed -i 's/services/vpn/g' package/feeds/luci/luci-app-openvpn/luasrc/controller/openvpn.lua
149 | sed -i 's/resolv.conf.d\/resolv.conf.auto/resolv.conf.auto/g' package/lean/luci-app-flowoffload/root/etc/init.d/flowoffload
150 |
151 | sed -i '/done/imkfs.ext4 /dev/mmcblk0p2 && mkdir /mnt/mmcblk0p2 && mount /dev/mmcblk0p2 /mnt/mmcblk0p2 && mkdir /mnt/mmcblk0p2/docker\n' package/base-files/files/root/setup.sh
152 | sed -i "/done/iblock detect | sed \"s/enabled\\\t'0'/enabled\\\t'1'/\" > /etc/config/fstab\n" package/base-files/files/root/setup.sh
153 | sed -i '/done/i[ -f /etc/init.d/dockerman ] && /etc/init.d/dockerman restart\n' package/base-files/files/root/setup.sh
154 |
155 | sed -i 's/\/opt\/docker/\/mnt\/mmcblk0p2\/docker/g' package/luci-app-dockerman/root/etc/config/dockerman
156 | sed -i 's/\/root/\/mnt\/mmcblk0p2/g' package/luci-app-r2sflasher/root/usr/bin/rom_flash
157 |
158 | - name: Patch Kernel
159 | run: |
160 | cd code/kernel/
161 | #git apply ../../patches/001-add-full_cone_nat.patch
162 |
163 | - name: Custom Configure Files
164 | run: |
165 | rm -f code/friendlywrt/.config*
166 | cp r2s-rk3328-config code/configs/config_rk3328
167 |
168 | - name: Set Default Values
169 | run: |
170 | cd code/friendlywrt
171 | sed -i '/uci commit luci/i\uci set luci.main.mediaurlbase=/luci-static/argon' package/lean/default-settings/files/zzz-default-settings
172 |
173 | - name: Install UPX
174 | run: |
175 | ln -s /usr/bin/upx-ucl code/friendlywrt/staging_dir/host/bin/upx
176 |
177 | - name: Build OpenWrt
178 | run: |
179 | cd code
180 | sed -i 's/set -eu/set -u/' scripts/mk-friendlywrt.sh
181 | ./build.sh nanopi_r2s.mk
182 |
183 | - name: Fix Rootfs Owner and Group
184 | run: |
185 | sudo df -lh
186 | lodev=$(sudo losetup -f)
187 | echo "found unused loop dev $lodev"
188 | sudo losetup -o 100663296 $lodev code/out/*.img
189 | #sudo mkfs -t ext4 $lodev
190 | sudo rm -rf /mnt/friendlywrt-tmp
191 | sudo mkdir -p /mnt/friendlywrt-tmp
192 | sudo mount $lodev /mnt/friendlywrt-tmp
193 | sudo chown -R root:root /mnt/friendlywrt-tmp
194 | sudo umount /mnt/friendlywrt-tmp
195 | sudo losetup -d $lodev
196 |
197 | - name: Assemble Artifact
198 | run: |
199 | rm -rf ./artifact/
200 | mkdir -p ./artifact/
201 |
202 | cp code/out/*.img.zip ./artifact/
203 | cp code/friendlywrt/.config ./artifact/
204 |
205 | - name: Upload Artifact
206 | uses: actions/upload-artifact@master
207 | with:
208 | name: FriendlyWrt_NanoPi-R2S RK3328 v19.07
209 | path: ./artifact/
210 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## 20210303
2 | * 日常更新
3 | * 修复 trogan-go 无法运行的问题
4 |
5 | ## 20210210
6 | * Docker
7 |
8 | ## 20210208
9 | * 集成 luci-app-dockerman
10 | * 修复 UnblockNeteaseMusicGo 无法启动的问题
11 |
12 | ## 20210206
13 | * 开机挂载 Docker 资料分区
14 |
15 | ## 20210202
16 | * Make OTA Work Again
17 |
18 | ## 20210130
19 | * 更新 netdata
20 | * 修复 OpenClash 依赖问题
21 |
22 | ## 20210124
23 | * 修复 frp 无法启动的问题
24 |
25 | ## 20210121
26 | * 更新到 19.07.5
27 | * Kernel 5.10.2
28 | * 新增 jerrykuku/luci-app-vssr
29 | * 新增 xiaorouji/openwrt-passwall
30 |
31 | ## 20201102
32 | * 常规更新
33 |
34 | ## 20200909
35 | * 更新 SmartDNS
36 |
37 | ## 20200819
38 | * 移除 luci-app-clash
39 | * OpenClash 内置 TUN/Game 二进制文件
40 |
41 | ## 20200817
42 | * Clash 更新到 v1.1.0
43 |
44 | ## 20200815
45 | * 开启 luci-app-adguardhome
46 | * 开启 luci-app-jd-dailybonus
47 | * 替换 node 为 https://github.com/nxhack/openwrt-node-packages/
48 |
49 | ## 20200809
50 | * 新增 luci-app-oled
51 |
52 | ## 20200723
53 | * Docker
54 |
55 | ## 20200718
56 | * Kernel 5.4.50
57 | * Clash 更新到 1.0.0
58 |
59 | ## 20200515
60 | * Kernel 5.4.40
61 | * 支持 RTL8812AU
62 |
63 | ## 20200509
64 | * 修正 Clash 二进制文件权限
65 | * 修正 luci-app-clash 在 menuconfig 的分类
66 | * 将 luci-app-openvpn 菜单项移至 vpn
67 |
68 | ## 20200508
69 | * 集成 smartdns
70 | * 集成 luci-app-smartdns
71 | * Clash 更新到 0.20.0
72 |
73 | ## 20200418
74 | * 集成 luci-app-r2sflasher
75 |
76 | ## 20200417
77 | * 重新整理 yml
78 | * 因应上游调整
79 |
80 | ## 20200403
81 | * Kernel 5.4.29
82 |
83 | ## 20200329
84 | * 移除 Flow Offloading 补丁
85 |
86 | ## 20200326
87 | * 默认不开启 Full Cone NAT 与 Flow Offloading
88 |
89 | ## 20200311
90 | * 添加 xt_FLOWOFFLOAD
91 | * 添加 RTL8821CU 源代码
92 |
93 | ## 20200308
94 | * 只允许从 LAN 访问 SSH
95 | * 更换 luci-app-unblockmusic
96 |
97 | ## 20200229
98 | * 官方修复每次重启 Mac 地址变化问题
99 |
100 | ## 20200227
101 | * 支持 RTL8821CU 芯片的 USB WiFi 设备,已知支持列表:
102 | - [COMFAST 726B](https://u.jd.com/DOkkhX)
103 | - [COMFAST CF-759BF](https://u.jd.com/C2ivH7)
104 | * 官方 Kernel 更新到 5.4.22
105 | * 更新 argon 主题
106 | * 官方修复 LED 问题
107 |
108 | ## 20200226
109 | * 添加 frpc 和 npc
110 | * 支持 Full Cone NAT
111 |
112 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 使用 Github Actions 在线编译 NanoPi-R2S 固件
2 |
3 | * NanoPi R2S CNC 官方金属壳版 购买链接: [https://s.click.taobao.com/ZPSFRyu](https://s.click.taobao.com/ZPSFRyu)
4 | * 推荐朗科 32G TF 卡 ¥17.90 购买链接: [https://u.jd.com/wDywo8y](https://u.jd.com/wDywo8y)
5 |
6 | ## 说明
7 | * 管理 IP: 192.168.2.1
8 | * 默认管理密码: password
9 |
10 | ## 特色
11 | * 支持 RTL8821CU/RTL8822BU/RTL8812AU 芯片的 USB WiFi 设备,已知支持列表:
12 | - [COMFAST 726B](https://u.jd.com/ISyZWQh)
13 | - [COMFAST CF-759BF](https://u.jd.com/IRyZhYG)
14 | - [COMFAST CF-927BF](https://u.jd.com/I2yv0kA)
15 | * 集成 [OpenClash](https://github.com/vernesong/OpenClash) 及其 core/tun/game binaries
16 | * 集成 [HelloWorld](https://github.com/jerrykuku/luci-app-vssr)
17 | * 集成 [Passwall](https://github.com/xiaorouji/openwrt-passwall)
18 | * 集成 [luci-app-adguardhome](https://github.com/rufengsuixing/luci-app-adguardhome)
19 | * 集成 [coolsnowwolf/packages](https://github.com/coolsnowwolf/packages), [coolsnowwolf/luci](https://github.com/coolsnowwolf/luci) 与 [coolsnowwolf/lede/package/lean](https://github.com/coolsnowwolf/lede/tree/master/package/lean)
20 | * 集成 [luci-theme-argon](https://github.com/jerrykuku/luci-theme-argon)
21 | * 集成 [luci-app-r2sflasher](https://github.com/songchenwen/nanopi-r2s/tree/master/luci-app-r2sflasher)
22 | * 集成 [Smartdns](https://github.com/pymumu/smartdns) 与 luci-app-smartdns
23 | * 集成 [luci-app-oled](https://github.com/NateLol/luci-app-oled)
24 | * 集成 [luci-app-jd-dailybonus](https://github.com/jerrykuku/luci-app-jd-dailybonus)
25 | * 集成 [luci-app-dockerman](https://github.com/lisaac/luci-app-dockerman)
26 |
27 | ## 用法
28 | Fork 到自己的账号下,将 `.github/workflows` 下 `.yml` 文件中的 `runs-on: self-hosted` 改成 `runs-on: ubuntu-latest`(因为我是自己的服务器上编译,更快),编辑文件 `CHANGELOG.md` 触发编译动作。
29 |
30 | ## 注意
31 | 产品发布初期,官方代码每天都在变,遇到无法编译时,请过来查看 `.yml` 与 `config` 最新异动。
32 |
33 | ## 参考
34 | * [使用Github的Actions功能在线编译NanoPi-R1S固件(包含H5和H3)](https://totoro.site/index.php/archives/70/)
35 | * [skytotwo/NanoPi-R1S-Build-By-Actions](https://github.com/skytotwo/NanoPi-R1S-Build-By-Actions)
36 | * [klever1988/nanopi-openwrt](https://github.com/klever1988/nanopi-openwrt)
37 | * [yangliu/NanoPi-R2S](https://github.com/yangliu/NanoPi-R2S)
38 | * [maxming2333/NanoPi-R2S](https://github.com/maxming2333/NanoPi-R2S)
39 | * [songchenwen/nanopi-r2s](https://github.com/songchenwen/nanopi-r2s)
40 | * [fanck0605/nanopi_r2s](https://github.com/fanck0605/nanopi_r2s)
41 |
--------------------------------------------------------------------------------
/patches/001-add-full_cone_nat.patch:
--------------------------------------------------------------------------------
1 | diff --git a/arch/arm64/configs/nanopi-r2_linux_defconfig b/arch/arm64/configs/nanopi-r2_linux_defconfig
2 | index 240a9bf57..9f8f37ca7 100644
3 | --- a/arch/arm64/configs/nanopi-r2_linux_defconfig
4 | +++ b/arch/arm64/configs/nanopi-r2_linux_defconfig
5 | @@ -1665,3 +1665,4 @@ CONFIG_SCHEDSTATS=y
6 | CONFIG_DEBUG_SPINLOCK=y
7 | CONFIG_FUNCTION_TRACER=y
8 | CONFIG_BLK_DEV_IO_TRACE=y
9 | +CONFIG_NETFILTER_XT_TARGET_FULLCONENAT=y
10 | diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig
11 | index f17b40211..99f691a67 100644
12 | --- a/net/ipv4/netfilter/Kconfig
13 | +++ b/net/ipv4/netfilter/Kconfig
14 | @@ -239,6 +239,15 @@ config IP_NF_TARGET_NETMAP
15 | (e.g. when running oldconfig). It selects
16 | CONFIG_NETFILTER_XT_TARGET_NETMAP.
17 |
18 | +config IP_NF_TARGET_FULLCONENAT
19 | + tristate "FULLCONENAT target support"
20 | + depends on NETFILTER_ADVANCED
21 | + select NETFILTER_XT_TARGET_FULLCONENAT
22 | + ---help---
23 | + This is a backwards-compat option for the user's convenience
24 | + (e.g. when running oldconfig). It selects
25 | + CONFIG_NETFILTER_XT_TARGET_FULLCONENAT.
26 | +
27 | config IP_NF_TARGET_REDIRECT
28 | tristate "REDIRECT target support"
29 | depends on NETFILTER_ADVANCED
30 | diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
31 | index 91efae88e..17f5c748a 100644
32 | --- a/net/netfilter/Kconfig
33 | +++ b/net/netfilter/Kconfig
34 | @@ -956,6 +956,14 @@ config NETFILTER_XT_TARGET_NETMAP
35 |
36 | To compile it as a module, choose M here. If unsure, say N.
37 |
38 | +config NETFILTER_XT_TARGET_FULLCONENAT
39 | + tristate '"FULLCONENAT" target support'
40 | + depends on NF_NAT
41 | + ---help---
42 | + Full Cone NAT
43 | +
44 | + To compile it as a module, choose M here. If unsure, say N.
45 | +
46 | config NETFILTER_XT_TARGET_NFLOG
47 | tristate '"NFLOG" target support'
48 | default m if NETFILTER_ADVANCED=n
49 | diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
50 | index 4fc075b61..2b588d5a5 100644
51 | --- a/net/netfilter/Makefile
52 | +++ b/net/netfilter/Makefile
53 | @@ -209,3 +209,6 @@ obj-$(CONFIG_IP_SET) += ipset/
54 |
55 | # IPVS
56 | obj-$(CONFIG_IP_VS) += ipvs/
57 | +
58 | +# Full cone NAT
59 | +obj-$(CONFIG_NETFILTER_XT_TARGET_FULLCONENAT) += xt_FULLCONENAT.o
60 | diff --git a/net/netfilter/xt_FULLCONENAT.c b/net/netfilter/xt_FULLCONENAT.c
61 | new file mode 100644
62 | index 000000000..8555b54e2
63 | --- /dev/null
64 | +++ b/net/netfilter/xt_FULLCONENAT.c
65 | @@ -0,0 +1,733 @@
66 | +/*
67 | + * Copyright (c) 2018 Chion Tang
68 | + *
69 | + * This program is free software; you can redistribute it and/or modify
70 | + * it under the terms of the GNU General Public License version 2 as
71 | + * published by the Free Software Foundation.
72 | + */
73 | +
74 | +#include
75 | +#include
76 | +#include
77 | +#include
78 | +#include
79 | +#include
80 | +#include
81 | +#include
82 | +#include
83 | +#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
84 | +#include
85 | +#endif
86 | +#include
87 | +#include
88 | +#include
89 | +#include
90 | +#include
91 | +#include
92 | +#include
93 | +#include
94 | +#include
95 | +
96 | +#define HASH_2(x, y) ((x + y) / 2 * (x + y + 1) + y)
97 | +
98 | +#define HASHTABLE_BUCKET_BITS 10
99 | +
100 | +#ifndef NF_NAT_RANGE_PROTO_RANDOM_FULLY
101 | +#define NF_NAT_RANGE_PROTO_RANDOM_FULLY (1 << 4)
102 | +#endif
103 | +
104 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)
105 | +
106 | +static inline int nf_ct_netns_get(struct net *net, u8 nfproto) { return 0; }
107 | +
108 | +static inline void nf_ct_netns_put(struct net *net, u8 nfproto) {}
109 | +
110 | +static inline struct net_device *xt_in(const struct xt_action_param *par) {
111 | + return par->in;
112 | +}
113 | +
114 | +static inline struct net_device *xt_out(const struct xt_action_param *par) {
115 | + return par->out;
116 | +}
117 | +
118 | +static inline unsigned int xt_hooknum(const struct xt_action_param *par) {
119 | + return par->hooknum;
120 | +}
121 | +
122 | +#endif
123 | +
124 | +struct nat_mapping_original_tuple {
125 | + struct nf_conntrack_tuple tuple;
126 | +
127 | + struct list_head node;
128 | +};
129 | +
130 | +struct nat_mapping {
131 | + uint16_t port; /* external UDP port */
132 | + int ifindex; /* external interface index*/
133 | +
134 | + __be32 int_addr; /* internal source ip address */
135 | + uint16_t int_port; /* internal source port */
136 | +
137 | + int refer_count; /* how many references linked to this mapping
138 | + * aka. length of original_tuple_list */
139 | +
140 | + struct list_head original_tuple_list;
141 | +
142 | + struct hlist_node node_by_ext_port;
143 | + struct hlist_node node_by_int_src;
144 | +
145 | +};
146 | +
147 | +struct tuple_list {
148 | + struct nf_conntrack_tuple tuple_original;
149 | + struct nf_conntrack_tuple tuple_reply;
150 | + struct list_head list;
151 | +};
152 | +
153 | +#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
154 | +struct notifier_block ct_event_notifier;
155 | +#else
156 | +struct nf_ct_event_notifier ct_event_notifier;
157 | +#endif
158 | +int tg_refer_count = 0;
159 | +int ct_event_notifier_registered = 0;
160 | +
161 | +static DEFINE_MUTEX(nf_ct_net_event_lock);
162 | +
163 | +static DEFINE_HASHTABLE(mapping_table_by_ext_port, HASHTABLE_BUCKET_BITS);
164 | +static DEFINE_HASHTABLE(mapping_table_by_int_src, HASHTABLE_BUCKET_BITS);
165 | +
166 | +static DEFINE_SPINLOCK(fullconenat_lock);
167 | +
168 | +static LIST_HEAD(dying_tuple_list);
169 | +static DEFINE_SPINLOCK(dying_tuple_list_lock);
170 | +static void gc_worker(struct work_struct *work);
171 | +static struct workqueue_struct *wq __read_mostly = NULL;
172 | +static DECLARE_DELAYED_WORK(gc_worker_wk, gc_worker);
173 | +
174 | +static char tuple_tmp_string[512];
175 | +/* non-atomic: can only be called serially within lock zones. */
176 | +static char* nf_ct_stringify_tuple(const struct nf_conntrack_tuple *t) {
177 | + snprintf(tuple_tmp_string, sizeof(tuple_tmp_string), "%pI4:%hu -> %pI4:%hu",
178 | + &t->src.u3.ip, be16_to_cpu(t->src.u.all),
179 | + &t->dst.u3.ip, be16_to_cpu(t->dst.u.all));
180 | + return tuple_tmp_string;
181 | +}
182 | +
183 | +static struct nat_mapping* allocate_mapping(const __be32 int_addr, const uint16_t int_port, const uint16_t port, const int ifindex) {
184 | + struct nat_mapping *p_new;
185 | + u32 hash_src;
186 | +
187 | + p_new = kmalloc(sizeof(struct nat_mapping), GFP_ATOMIC);
188 | + if (p_new == NULL) {
189 | + pr_debug("xt_FULLCONENAT: ERROR: kmalloc() for new nat_mapping failed.\n");
190 | + return NULL;
191 | + }
192 | + p_new->port = port;
193 | + p_new->int_addr = int_addr;
194 | + p_new->int_port = int_port;
195 | + p_new->ifindex = ifindex;
196 | + p_new->refer_count = 0;
197 | + (p_new->original_tuple_list).next = &(p_new->original_tuple_list);
198 | + (p_new->original_tuple_list).prev = &(p_new->original_tuple_list);
199 | +
200 | + hash_src = HASH_2(int_addr, (u32)int_port);
201 | +
202 | + hash_add(mapping_table_by_ext_port, &p_new->node_by_ext_port, port);
203 | + hash_add(mapping_table_by_int_src, &p_new->node_by_int_src, hash_src);
204 | +
205 | + pr_debug("xt_FULLCONENAT: new mapping allocated for %pI4:%d ==> %d\n",
206 | + &p_new->int_addr, p_new->int_port, p_new->port);
207 | +
208 | + return p_new;
209 | +}
210 | +
211 | +static void add_original_tuple_to_mapping(struct nat_mapping *mapping, const struct nf_conntrack_tuple* original_tuple) {
212 | + struct nat_mapping_original_tuple *item = kmalloc(sizeof(struct nat_mapping_original_tuple), GFP_ATOMIC);
213 | + if (item == NULL) {
214 | + pr_debug("xt_FULLCONENAT: ERROR: kmalloc() for nat_mapping_original_tuple failed.\n");
215 | + return;
216 | + }
217 | + memcpy(&item->tuple, original_tuple, sizeof(struct nf_conntrack_tuple));
218 | + list_add(&item->node, &mapping->original_tuple_list);
219 | + (mapping->refer_count)++;
220 | +}
221 | +
222 | +static struct nat_mapping* get_mapping_by_ext_port(const uint16_t port, const int ifindex) {
223 | + struct nat_mapping *p_current;
224 | +
225 | + hash_for_each_possible(mapping_table_by_ext_port, p_current, node_by_ext_port, port) {
226 | + if (p_current->port == port && p_current->ifindex == ifindex) {
227 | + return p_current;
228 | + }
229 | + }
230 | +
231 | + return NULL;
232 | +}
233 | +
234 | +static struct nat_mapping* get_mapping_by_int_src(const __be32 src_ip, const uint16_t src_port) {
235 | + struct nat_mapping *p_current;
236 | + u32 hash_src = HASH_2(src_ip, (u32)src_port);
237 | +
238 | + hash_for_each_possible(mapping_table_by_int_src, p_current, node_by_int_src, hash_src) {
239 | + if (p_current->int_addr == src_ip && p_current->int_port == src_port) {
240 | + return p_current;
241 | + }
242 | + }
243 | +
244 | + return NULL;
245 | +}
246 | +
247 | +static void kill_mapping(struct nat_mapping *mapping) {
248 | + struct list_head *iter, *tmp;
249 | + struct nat_mapping_original_tuple *original_tuple_item;
250 | +
251 | + if (mapping == NULL) {
252 | + return;
253 | + }
254 | +
255 | + list_for_each_safe(iter, tmp, &mapping->original_tuple_list) {
256 | + original_tuple_item = list_entry(iter, struct nat_mapping_original_tuple, node);
257 | + list_del(&original_tuple_item->node);
258 | + kfree(original_tuple_item);
259 | + }
260 | +
261 | + hash_del(&mapping->node_by_ext_port);
262 | + hash_del(&mapping->node_by_int_src);
263 | + kfree(mapping);
264 | +}
265 | +
266 | +static void destroy_mappings(void) {
267 | + struct nat_mapping *p_current;
268 | + struct hlist_node *tmp;
269 | + int i;
270 | +
271 | + spin_lock_bh(&fullconenat_lock);
272 | +
273 | + hash_for_each_safe(mapping_table_by_ext_port, i, tmp, p_current, node_by_ext_port) {
274 | + kill_mapping(p_current);
275 | + }
276 | +
277 | + spin_unlock_bh(&fullconenat_lock);
278 | +}
279 | +
280 | +/* check if a mapping is valid.
281 | + * possibly delete and free an invalid mapping.
282 | + * the mapping should not be used anymore after check_mapping() returns 0. */
283 | +static int check_mapping(struct nat_mapping* mapping, struct net *net, const struct nf_conntrack_zone *zone) {
284 | + struct list_head *iter, *tmp;
285 | + struct nat_mapping_original_tuple *original_tuple_item;
286 | + struct nf_conntrack_tuple_hash *tuple_hash;
287 | + struct nf_conn *ct;
288 | +
289 | + if (mapping == NULL) {
290 | + return 0;
291 | + }
292 | +
293 | + if (mapping->port == 0 || mapping->int_addr == 0 || mapping->int_port == 0 || mapping->ifindex == -1) {
294 | + return 0;
295 | + }
296 | +
297 | + /* for dying/unconfirmed conntrack tuples, an IPCT_DESTROY event may NOT be fired.
298 | + * so we manually kill one of those tuples once we acquire one. */
299 | +
300 | + list_for_each_safe(iter, tmp, &mapping->original_tuple_list) {
301 | + original_tuple_item = list_entry(iter, struct nat_mapping_original_tuple, node);
302 | +
303 | + tuple_hash = nf_conntrack_find_get(net, zone, &original_tuple_item->tuple);
304 | +
305 | + if (tuple_hash == NULL) {
306 | + pr_debug("xt_FULLCONENAT: check_mapping(): tuple %s dying/unconfirmed. free this tuple.\n", nf_ct_stringify_tuple(&original_tuple_item->tuple));
307 | +
308 | + list_del(&original_tuple_item->node);
309 | + kfree(original_tuple_item);
310 | + (mapping->refer_count)--;
311 | + } else {
312 | + ct = nf_ct_tuplehash_to_ctrack(tuple_hash);
313 | + if (ct != NULL)
314 | + nf_ct_put(ct);
315 | + }
316 | +
317 | + }
318 | +
319 | + /* kill the mapping if need */
320 | + pr_debug("xt_FULLCONENAT: check_mapping() refer_count for mapping at ext_port %d is now %d\n", mapping->port, mapping->refer_count);
321 | + if (mapping->refer_count <= 0) {
322 | + pr_debug("xt_FULLCONENAT: check_mapping(): kill dying/unconfirmed mapping at ext port %d\n", mapping->port);
323 | + kill_mapping(mapping);
324 | + return 0;
325 | + } else {
326 | + return 1;
327 | + }
328 | +}
329 | +
330 | +static void handle_dying_tuples(void) {
331 | + struct list_head *iter, *tmp, *iter_2, *tmp_2;
332 | + struct tuple_list *item;
333 | + struct nf_conntrack_tuple *ct_tuple;
334 | + struct nat_mapping *mapping;
335 | + __be32 ip;
336 | + uint16_t port;
337 | + struct nat_mapping_original_tuple *original_tuple_item;
338 | +
339 | + spin_lock_bh(&fullconenat_lock);
340 | + spin_lock_bh(&dying_tuple_list_lock);
341 | +
342 | + list_for_each_safe(iter, tmp, &dying_tuple_list) {
343 | + item = list_entry(iter, struct tuple_list, list);
344 | +
345 | + /* we dont know the conntrack direction for now so we try in both ways. */
346 | + ct_tuple = &(item->tuple_original);
347 | + ip = (ct_tuple->src).u3.ip;
348 | + port = be16_to_cpu((ct_tuple->src).u.udp.port);
349 | + mapping = get_mapping_by_int_src(ip, port);
350 | + if (mapping == NULL) {
351 | + ct_tuple = &(item->tuple_reply);
352 | + ip = (ct_tuple->src).u3.ip;
353 | + port = be16_to_cpu((ct_tuple->src).u.udp.port);
354 | + mapping = get_mapping_by_int_src(ip, port);
355 | + if (mapping != NULL) {
356 | + pr_debug("xt_FULLCONENAT: handle_dying_tuples(): INBOUND dying conntrack at ext port %d\n", mapping->port);
357 | + }
358 | + } else {
359 | + pr_debug("xt_FULLCONENAT: handle_dying_tuples(): OUTBOUND dying conntrack at ext port %d\n", mapping->port);
360 | + }
361 | +
362 | + if (mapping == NULL) {
363 | + goto next;
364 | + }
365 | +
366 | + /* look for the corresponding out-dated tuple and free it */
367 | + list_for_each_safe(iter_2, tmp_2, &mapping->original_tuple_list) {
368 | + original_tuple_item = list_entry(iter_2, struct nat_mapping_original_tuple, node);
369 | +
370 | + if (nf_ct_tuple_equal(&original_tuple_item->tuple, &(item->tuple_original))) {
371 | + pr_debug("xt_FULLCONENAT: handle_dying_tuples(): tuple %s expired. free this tuple.\n",
372 | + nf_ct_stringify_tuple(&original_tuple_item->tuple));
373 | + list_del(&original_tuple_item->node);
374 | + kfree(original_tuple_item);
375 | + (mapping->refer_count)--;
376 | + }
377 | + }
378 | +
379 | + /* then kill the mapping if needed*/
380 | + pr_debug("xt_FULLCONENAT: handle_dying_tuples(): refer_count for mapping at ext_port %d is now %d\n", mapping->port, mapping->refer_count);
381 | + if (mapping->refer_count <= 0) {
382 | + pr_debug("xt_FULLCONENAT: handle_dying_tuples(): kill expired mapping at ext port %d\n", mapping->port);
383 | + kill_mapping(mapping);
384 | + }
385 | +
386 | +next:
387 | + list_del(&item->list);
388 | + kfree(item);
389 | + }
390 | +
391 | + spin_unlock_bh(&dying_tuple_list_lock);
392 | + spin_unlock_bh(&fullconenat_lock);
393 | +}
394 | +
395 | +static void gc_worker(struct work_struct *work) {
396 | + handle_dying_tuples();
397 | +}
398 | +
399 | +/* conntrack destroy event callback function */
400 | +#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
401 | +static int ct_event_cb(struct notifier_block *this, unsigned long events, void *ptr) {
402 | + struct nf_ct_event *item = ptr;
403 | +#else
404 | +static int ct_event_cb(unsigned int events, struct nf_ct_event *item) {
405 | +#endif
406 | + struct nf_conn *ct;
407 | + struct nf_conntrack_tuple *ct_tuple_reply, *ct_tuple_original;
408 | + uint8_t protonum;
409 | + struct tuple_list *dying_tuple_item;
410 | +
411 | + ct = item->ct;
412 | + /* we handle only conntrack destroy events */
413 | + if (ct == NULL || !(events & (1 << IPCT_DESTROY))) {
414 | + return 0;
415 | + }
416 | +
417 | + ct_tuple_original = &(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
418 | +
419 | + ct_tuple_reply = &(ct->tuplehash[IP_CT_DIR_REPLY].tuple);
420 | +
421 | + protonum = (ct_tuple_original->dst).protonum;
422 | + if (protonum != IPPROTO_UDP) {
423 | + return 0;
424 | + }
425 | +
426 | + dying_tuple_item = kmalloc(sizeof(struct tuple_list), GFP_ATOMIC);
427 | +
428 | + if (dying_tuple_item == NULL) {
429 | + pr_debug("xt_FULLCONENAT: warning: ct_event_cb(): kmalloc failed.\n");
430 | + return 0;
431 | + }
432 | +
433 | + memcpy(&(dying_tuple_item->tuple_original), ct_tuple_original, sizeof(struct nf_conntrack_tuple));
434 | + memcpy(&(dying_tuple_item->tuple_reply), ct_tuple_reply, sizeof(struct nf_conntrack_tuple));
435 | +
436 | + spin_lock_bh(&dying_tuple_list_lock);
437 | +
438 | + list_add(&(dying_tuple_item->list), &dying_tuple_list);
439 | +
440 | + spin_unlock_bh(&dying_tuple_list_lock);
441 | +
442 | + if (wq != NULL)
443 | + queue_delayed_work(wq, &gc_worker_wk, msecs_to_jiffies(100));
444 | +
445 | + return 0;
446 | +}
447 | +
448 | +static __be32 get_device_ip(const struct net_device* dev) {
449 | + struct in_device* in_dev;
450 | + struct in_ifaddr* if_info;
451 | + __be32 result;
452 | +
453 | + if (dev == NULL) {
454 | + return 0;
455 | + }
456 | +
457 | + rcu_read_lock();
458 | + in_dev = dev->ip_ptr;
459 | + if (in_dev == NULL) {
460 | + rcu_read_unlock();
461 | + return 0;
462 | + }
463 | + if_info = in_dev->ifa_list;
464 | + if (if_info) {
465 | + result = if_info->ifa_local;
466 | + rcu_read_unlock();
467 | + return result;
468 | + } else {
469 | + rcu_read_unlock();
470 | + return 0;
471 | + }
472 | +}
473 | +
474 | +static uint16_t find_appropriate_port(struct net *net, const struct nf_conntrack_zone *zone, const uint16_t original_port, const int ifindex, const struct nf_nat_ipv4_range *range) {
475 | + uint16_t min, start, selected, range_size, i;
476 | + struct nat_mapping* mapping = NULL;
477 | +
478 | + if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) {
479 | + min = be16_to_cpu((range->min).udp.port);
480 | + range_size = be16_to_cpu((range->max).udp.port) - min + 1;
481 | + } else {
482 | + /* minimum port is 1024. same behavior as default linux NAT. */
483 | + min = 1024;
484 | + range_size = 65535 - min + 1;
485 | + }
486 | +
487 | + if ((range->flags & NF_NAT_RANGE_PROTO_RANDOM)
488 | + || (range->flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY)) {
489 | + /* for now we do the same thing for both --random and --random-fully */
490 | +
491 | + /* select a random starting point */
492 | + start = (uint16_t)(prandom_u32() % (u32)range_size);
493 | + } else {
494 | +
495 | + if ((original_port >= min && original_port <= min + range_size - 1)
496 | + || !(range->flags & NF_NAT_RANGE_PROTO_SPECIFIED)) {
497 | + /* 1. try to preserve the port if it's available */
498 | + mapping = get_mapping_by_ext_port(original_port, ifindex);
499 | + if (mapping == NULL || !(check_mapping(mapping, net, zone))) {
500 | + return original_port;
501 | + }
502 | + }
503 | +
504 | + /* otherwise, we start from zero */
505 | + start = 0;
506 | + }
507 | +
508 | + for (i = 0; i < range_size; i++) {
509 | + /* 2. try to find an available port */
510 | + selected = min + ((start + i) % range_size);
511 | + mapping = get_mapping_by_ext_port(selected, ifindex);
512 | + if (mapping == NULL || !(check_mapping(mapping, net, zone))) {
513 | + return selected;
514 | + }
515 | + }
516 | +
517 | + /* 3. at least we tried. override a previous mapping. */
518 | + selected = min + start;
519 | + mapping = get_mapping_by_ext_port(selected, ifindex);
520 | + kill_mapping(mapping);
521 | +
522 | + return selected;
523 | +}
524 | +
525 | +static unsigned int fullconenat_tg(struct sk_buff *skb, const struct xt_action_param *par)
526 | +{
527 | + const struct nf_nat_ipv4_multi_range_compat *mr;
528 | + const struct nf_nat_ipv4_range *range;
529 | +
530 | + const struct nf_conntrack_zone *zone;
531 | + struct net *net;
532 | + struct nf_conn *ct;
533 | + enum ip_conntrack_info ctinfo;
534 | + struct nf_conntrack_tuple *ct_tuple, *ct_tuple_origin;
535 | +
536 | + struct net_device *net_dev;
537 | +
538 | + struct nat_mapping *mapping, *src_mapping;
539 | + unsigned int ret;
540 | +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 18, 0)
541 | + struct nf_nat_range2 newrange;
542 | +#else
543 | + struct nf_nat_range newrange;
544 | +#endif
545 | +
546 | + __be32 new_ip, ip;
547 | + uint16_t port, original_port, want_port;
548 | + uint8_t protonum;
549 | + int ifindex;
550 | +
551 | + ip = 0;
552 | + original_port = 0;
553 | + src_mapping = NULL;
554 | +
555 | + mr = par->targinfo;
556 | + range = &mr->range[0];
557 | +
558 | + mapping = NULL;
559 | + ret = XT_CONTINUE;
560 | +
561 | + ct = nf_ct_get(skb, &ctinfo);
562 | + net = nf_ct_net(ct);
563 | + zone = nf_ct_zone(ct);
564 | +
565 | + memset(&newrange.min_addr, 0, sizeof(newrange.min_addr));
566 | + memset(&newrange.max_addr, 0, sizeof(newrange.max_addr));
567 | + newrange.flags = mr->range[0].flags | NF_NAT_RANGE_MAP_IPS;
568 | + newrange.min_proto = mr->range[0].min;
569 | + newrange.max_proto = mr->range[0].max;
570 | +
571 | + if (xt_hooknum(par) == NF_INET_PRE_ROUTING) {
572 | + /* inbound packets */
573 | + ifindex = xt_in(par)->ifindex;
574 | +
575 | + ct_tuple_origin = &(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
576 | +
577 | + protonum = (ct_tuple_origin->dst).protonum;
578 | + if (protonum != IPPROTO_UDP) {
579 | + return ret;
580 | + }
581 | + ip = (ct_tuple_origin->dst).u3.ip;
582 | + port = be16_to_cpu((ct_tuple_origin->dst).u.udp.port);
583 | +
584 | + /* get the corresponding ifindex by the dst_ip (aka. external ip of this host),
585 | + * in case the packet needs to be forwarded from another inbound interface. */
586 | + net_dev = ip_dev_find(net, ip);
587 | + if (net_dev != NULL) {
588 | + ifindex = net_dev->ifindex;
589 | + dev_put(net_dev);
590 | + }
591 | +
592 | + spin_lock_bh(&fullconenat_lock);
593 | +
594 | + /* find an active mapping based on the inbound port */
595 | + mapping = get_mapping_by_ext_port(port, ifindex);
596 | + if (mapping == NULL) {
597 | + spin_unlock_bh(&fullconenat_lock);
598 | + return ret;
599 | + }
600 | + if (check_mapping(mapping, net, zone)) {
601 | + newrange.flags = NF_NAT_RANGE_MAP_IPS | NF_NAT_RANGE_PROTO_SPECIFIED;
602 | + newrange.min_addr.ip = mapping->int_addr;
603 | + newrange.max_addr.ip = mapping->int_addr;
604 | + newrange.min_proto.udp.port = cpu_to_be16(mapping->int_port);
605 | + newrange.max_proto = newrange.min_proto;
606 | +
607 | + pr_debug("xt_FULLCONENAT: %s ==> %pI4:%d\n", nf_ct_stringify_tuple(ct_tuple_origin), &mapping->int_addr, mapping->int_port);
608 | +
609 | + ret = nf_nat_setup_info(ct, &newrange, HOOK2MANIP(xt_hooknum(par)));
610 | +
611 | + if (ret == NF_ACCEPT) {
612 | + add_original_tuple_to_mapping(mapping, ct_tuple_origin);
613 | + pr_debug("xt_FULLCONENAT: fullconenat_tg(): INBOUND: refer_count for mapping at ext_port %d is now %d\n", mapping->port, mapping->refer_count);
614 | + }
615 | + }
616 | + spin_unlock_bh(&fullconenat_lock);
617 | + return ret;
618 | +
619 | +
620 | + } else if (xt_hooknum(par) == NF_INET_POST_ROUTING) {
621 | + /* outbound packets */
622 | + ifindex = xt_out(par)->ifindex;
623 | +
624 | + ct_tuple_origin = &(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
625 | + protonum = (ct_tuple_origin->dst).protonum;
626 | +
627 | + spin_lock_bh(&fullconenat_lock);
628 | +
629 | + if (protonum == IPPROTO_UDP) {
630 | + ip = (ct_tuple_origin->src).u3.ip;
631 | + original_port = be16_to_cpu((ct_tuple_origin->src).u.udp.port);
632 | +
633 | + src_mapping = get_mapping_by_int_src(ip, original_port);
634 | + if (src_mapping != NULL && check_mapping(src_mapping, net, zone)) {
635 | +
636 | + /* outbound nat: if a previously established mapping is active,
637 | + * we will reuse that mapping. */
638 | +
639 | + newrange.flags = NF_NAT_RANGE_MAP_IPS | NF_NAT_RANGE_PROTO_SPECIFIED;
640 | + newrange.min_proto.udp.port = cpu_to_be16(src_mapping->port);
641 | + newrange.max_proto = newrange.min_proto;
642 | +
643 | + } else {
644 | +
645 | + /* if not, we find a new external port to map to.
646 | + * the SNAT may fail so we should re-check the mapped port later. */
647 | + want_port = find_appropriate_port(net, zone, original_port, ifindex, range);
648 | +
649 | + newrange.flags = NF_NAT_RANGE_MAP_IPS | NF_NAT_RANGE_PROTO_SPECIFIED;
650 | + newrange.min_proto.udp.port = cpu_to_be16(want_port);
651 | + newrange.max_proto = newrange.min_proto;
652 | +
653 | + src_mapping = NULL;
654 | +
655 | + }
656 | + }
657 | +
658 | + if(mr->range[0].flags & NF_NAT_RANGE_MAP_IPS) {
659 | + newrange.min_addr.ip = mr->range[0].min_ip;
660 | + newrange.max_addr.ip = mr->range[0].max_ip;
661 | + } else {
662 | + new_ip = get_device_ip(skb->dev);
663 | + newrange.min_addr.ip = new_ip;
664 | + newrange.max_addr.ip = new_ip;
665 | + }
666 | +
667 | + /* do SNAT now */
668 | + ret = nf_nat_setup_info(ct, &newrange, HOOK2MANIP(xt_hooknum(par)));
669 | +
670 | + if (protonum != IPPROTO_UDP || ret != NF_ACCEPT) {
671 | + /* for non-UDP packets and failed SNAT, bailout */
672 | + spin_unlock_bh(&fullconenat_lock);
673 | + return ret;
674 | + }
675 | +
676 | + /* the reply tuple contains the mapped port. */
677 | + ct_tuple = &(ct->tuplehash[IP_CT_DIR_REPLY].tuple);
678 | + /* this is the resulted mapped port. */
679 | + port = be16_to_cpu((ct_tuple->dst).u.udp.port);
680 | +
681 | + pr_debug("xt_FULLCONENAT: %s ==> %d\n", nf_ct_stringify_tuple(ct_tuple_origin), port);
682 | +
683 | + /* save the mapping information into our mapping table */
684 | + mapping = src_mapping;
685 | + if (mapping == NULL || !check_mapping(mapping, net, zone)) {
686 | + mapping = allocate_mapping(ip, original_port, port, ifindex);
687 | + }
688 | + if (mapping != NULL) {
689 | + add_original_tuple_to_mapping(mapping, ct_tuple_origin);
690 | + pr_debug("xt_FULLCONENAT: fullconenat_tg(): OUTBOUND: refer_count for mapping at ext_port %d is now %d\n", mapping->port, mapping->refer_count);
691 | + }
692 | +
693 | + spin_unlock_bh(&fullconenat_lock);
694 | + return ret;
695 | + }
696 | +
697 | + return ret;
698 | +}
699 | +
700 | +static int fullconenat_tg_check(const struct xt_tgchk_param *par)
701 | +{
702 | + mutex_lock(&nf_ct_net_event_lock);
703 | +
704 | + tg_refer_count++;
705 | +
706 | + pr_debug("xt_FULLCONENAT: fullconenat_tg_check(): tg_refer_count is now %d\n", tg_refer_count);
707 | +
708 | + if (tg_refer_count == 1) {
709 | + nf_ct_netns_get(par->net, par->family);
710 | +#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
711 | + ct_event_notifier.notifier_call = ct_event_cb;
712 | +#else
713 | + ct_event_notifier.fcn = ct_event_cb;
714 | +#endif
715 | +
716 | + if (nf_conntrack_register_notifier(par->net, &ct_event_notifier) == 0) {
717 | + ct_event_notifier_registered = 1;
718 | + pr_debug("xt_FULLCONENAT: fullconenat_tg_check(): ct_event_notifier registered\n");
719 | + } else {
720 | + printk("xt_FULLCONENAT: warning: failed to register a conntrack notifier. Disable active GC for mappings.\n");
721 | + }
722 | +
723 | + }
724 | +
725 | + mutex_unlock(&nf_ct_net_event_lock);
726 | +
727 | + return 0;
728 | +}
729 | +
730 | +static void fullconenat_tg_destroy(const struct xt_tgdtor_param *par)
731 | +{
732 | + mutex_lock(&nf_ct_net_event_lock);
733 | +
734 | + tg_refer_count--;
735 | +
736 | + pr_debug("xt_FULLCONENAT: fullconenat_tg_destroy(): tg_refer_count is now %d\n", tg_refer_count);
737 | +
738 | + if (tg_refer_count == 0) {
739 | + if (ct_event_notifier_registered) {
740 | + nf_conntrack_unregister_notifier(par->net, &ct_event_notifier);
741 | + ct_event_notifier_registered = 0;
742 | +
743 | + pr_debug("xt_FULLCONENAT: fullconenat_tg_destroy(): ct_event_notifier unregistered\n");
744 | +
745 | + }
746 | + nf_ct_netns_put(par->net, par->family);
747 | + }
748 | +
749 | + mutex_unlock(&nf_ct_net_event_lock);
750 | +}
751 | +
752 | +static struct xt_target tg_reg[] __read_mostly = {
753 | + {
754 | + .name = "FULLCONENAT",
755 | + .family = NFPROTO_IPV4,
756 | + .revision = 0,
757 | + .target = fullconenat_tg,
758 | + .targetsize = sizeof(struct nf_nat_ipv4_multi_range_compat),
759 | + .table = "nat",
760 | + .hooks = (1 << NF_INET_PRE_ROUTING) |
761 | + (1 << NF_INET_POST_ROUTING),
762 | + .checkentry = fullconenat_tg_check,
763 | + .destroy = fullconenat_tg_destroy,
764 | + .me = THIS_MODULE,
765 | + },
766 | +};
767 | +
768 | +static int __init fullconenat_tg_init(void)
769 | +{
770 | + wq = create_singlethread_workqueue("xt_FULLCONENAT");
771 | + if (wq == NULL) {
772 | + printk("xt_FULLCONENAT: warning: failed to create workqueue\n");
773 | + }
774 | +
775 | + return xt_register_targets(tg_reg, ARRAY_SIZE(tg_reg));
776 | +}
777 | +
778 | +static void fullconenat_tg_exit(void)
779 | +{
780 | + xt_unregister_targets(tg_reg, ARRAY_SIZE(tg_reg));
781 | +
782 | + if (wq) {
783 | + cancel_delayed_work_sync(&gc_worker_wk);
784 | + flush_workqueue(wq);
785 | + destroy_workqueue(wq);
786 | + }
787 | +
788 | + handle_dying_tuples();
789 | + destroy_mappings();
790 | +}
791 | +
792 | +module_init(fullconenat_tg_init);
793 | +module_exit(fullconenat_tg_exit);
794 | +
795 | +MODULE_LICENSE("GPL");
796 | +MODULE_DESCRIPTION("Xtables: implementation of RFC3489 full cone NAT");
797 | +MODULE_AUTHOR("Chion Tang ");
798 | +MODULE_ALIAS("ipt_FULLCONENAT");
799 |
--------------------------------------------------------------------------------
/patches/011-fix-zerotier-aes.patch:
--------------------------------------------------------------------------------
1 | --- a/make-linux.mk
2 | +++ b/make-linux.mk
3 | @@ -216,11 +216,11 @@ ifeq ($(CC_MACH),armv7ve)
4 | endif
5 | ifeq ($(CC_MACH),arm64)
6 | ZT_ARCHITECTURE=4
7 | - override DEFS+=-DZT_NO_TYPE_PUNNING -DZT_ARCH_ARM_HAS_NEON -march=armv8-a+aes+crypto -mtune=generic -mstrict-align
8 | + override DEFS+=-DZT_NO_TYPE_PUNNING -DZT_ARCH_ARM_HAS_NEON -march=armv8-a+crypto -mtune=generic -mstrict-align
9 | endif
10 | ifeq ($(CC_MACH),aarch64)
11 | ZT_ARCHITECTURE=4
12 | - override DEFS+=-DZT_NO_TYPE_PUNNING -DZT_ARCH_ARM_HAS_NEON -march=armv8-a+aes+crypto -mtune=generic -mstrict-align
13 | + override DEFS+=-DZT_NO_TYPE_PUNNING -DZT_ARCH_ARM_HAS_NEON -march=armv8-a+crypto -mtune=generic -mstrict-align
14 | endif
15 | ifeq ($(CC_MACH),mipsel)
16 | ZT_ARCHITECTURE=5
17 |
--------------------------------------------------------------------------------
/rk3328.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------