Skip to content

Instantly share code, notes, and snippets.

Created May 29, 2017 18:22
Show Gist options
  • Star 10 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save anonymous/0fdec75fa20a7f1ce4806391d6b0429b to your computer and use it in GitHub Desktop.
Save anonymous/0fdec75fa20a7f1ce4806391d6b0429b to your computer and use it in GitHub Desktop.
OpenWrt map-e (JPNE v6plus) において、割当ポート240個をちゃんと使わせるための設定。
## /etc/firewall.user
# This file is interpreted as shell script.
# Put your custom iptables rules here, they will
# be executed with each firewall (re-)start.
# Internal uci firewall chains are flushed and recreated on reload, so
# put custom rules into the root chains e.g. INPUT or FORWARD or into the
# special user chains, e.g. input_wan_rule or postrouting_lan_rule.
iptables -t nat -A PREROUTING -m statistic --mode nth --every 15 --packet 0 -j MARK --set-mark 10
iptables -t nat -A PREROUTING -m statistic --mode nth --every 15 --packet 1 -j MARK --set-mark 11
iptables -t nat -A PREROUTING -m statistic --mode nth --every 15 --packet 2 -j MARK --set-mark 12
iptables -t nat -A PREROUTING -m statistic --mode nth --every 15 --packet 3 -j MARK --set-mark 13
iptables -t nat -A PREROUTING -m statistic --mode nth --every 15 --packet 4 -j MARK --set-mark 14
iptables -t nat -A PREROUTING -m statistic --mode nth --every 15 --packet 5 -j MARK --set-mark 15
iptables -t nat -A PREROUTING -m statistic --mode nth --every 15 --packet 6 -j MARK --set-mark 16
iptables -t nat -A PREROUTING -m statistic --mode nth --every 15 --packet 7 -j MARK --set-mark 17
iptables -t nat -A PREROUTING -m statistic --mode nth --every 15 --packet 8 -j MARK --set-mark 18
iptables -t nat -A PREROUTING -m statistic --mode nth --every 15 --packet 9 -j MARK --set-mark 19
iptables -t nat -A PREROUTING -m statistic --mode nth --every 15 --packet 10 -j MARK --set-mark 20
iptables -t nat -A PREROUTING -m statistic --mode nth --every 15 --packet 11 -j MARK --set-mark 21
iptables -t nat -A PREROUTING -m statistic --mode nth --every 15 --packet 12 -j MARK --set-mark 22
iptables -t nat -A PREROUTING -m statistic --mode nth --every 15 --packet 13 -j MARK --set-mark 23
iptables -t nat -A PREROUTING -m statistic --mode nth --every 15 --packet 14 -j MARK --set-mark 24
iptables -t nat -A OUTPUT -m statistic --mode nth --every 15 --packet 0 -j MARK --set-mark 10
iptables -t nat -A OUTPUT -m statistic --mode nth --every 15 --packet 1 -j MARK --set-mark 11
iptables -t nat -A OUTPUT -m statistic --mode nth --every 15 --packet 2 -j MARK --set-mark 12
iptables -t nat -A OUTPUT -m statistic --mode nth --every 15 --packet 3 -j MARK --set-mark 13
iptables -t nat -A OUTPUT -m statistic --mode nth --every 15 --packet 4 -j MARK --set-mark 14
iptables -t nat -A OUTPUT -m statistic --mode nth --every 15 --packet 5 -j MARK --set-mark 15
iptables -t nat -A OUTPUT -m statistic --mode nth --every 15 --packet 6 -j MARK --set-mark 16
iptables -t nat -A OUTPUT -m statistic --mode nth --every 15 --packet 7 -j MARK --set-mark 17
iptables -t nat -A OUTPUT -m statistic --mode nth --every 15 --packet 8 -j MARK --set-mark 18
iptables -t nat -A OUTPUT -m statistic --mode nth --every 15 --packet 9 -j MARK --set-mark 19
iptables -t nat -A OUTPUT -m statistic --mode nth --every 15 --packet 10 -j MARK --set-mark 20
iptables -t nat -A OUTPUT -m statistic --mode nth --every 15 --packet 11 -j MARK --set-mark 21
iptables -t nat -A OUTPUT -m statistic --mode nth --every 15 --packet 12 -j MARK --set-mark 22
iptables -t nat -A OUTPUT -m statistic --mode nth --every 15 --packet 13 -j MARK --set-mark 23
iptables -t nat -A OUTPUT -m statistic --mode nth --every 15 --packet 14 -j MARK --set-mark 24
#$ diff -c /lib/netifd/proto/map.sh.orig /lib/netifd/proto/map.sh
*** /lib/netifd/proto/map.sh.orig 2017-05-30 02:45:19.000000000 +0900
--- /lib/netifd/proto/map.sh 2017-05-30 02:45:18.000000000 +0900
***************
*** 135,140 ****
--- 135,141 ----
json_add_string snat_ip $(eval "echo \$RULE_${k}_IPV4ADDR")
json_close_object
else
+ local mark=10
for portset in $(eval "echo \$RULE_${k}_PORTSETS"); do
for proto in icmp tcp udp; do
json_add_object ""
***************
*** 142,152 ****
--- 143,155 ----
json_add_string target SNAT
json_add_string family inet
json_add_string proto "$proto"
+ json_add_string mark "$mark"
json_add_boolean connlimit_ports 1
json_add_string snat_ip $(eval "echo \$RULE_${k}_IPV4ADDR")
json_add_string snat_port "$portset"
json_close_object
done
+ mark=`expr $mark + 1`
done
fi
if [ "$type" = "map-t" ]; then
@RemiNV
Copy link

RemiNV commented Aug 20, 2020

回避策として利用されている設定だと思いますが、バグは下記の通り直していますので新しいバージョンを使っていればもう必要ないかと思います。
https://bugs.openwrt.org/index.php?do=details&task_id=3284

あとは、バグがまだ直されていないバージョンを使っていれば、これを使うのではなく、「json_add_boolean connlimit_ports 1」を「json_add_string connlimit_ports "1"」に変えるだけで済むと思います。

@osakanataro
Copy link

うちで使っているGL-MV1000はまだfirewall3部分は修正されてなかったので、map.sh の「json_add_boolean connlimit_ports "1"」修正だけを行ったところ、「iptables -t nat -L -v」で確認できるChain POSTROUTINGが最初の3つぐらいしか使われていない、という事象は継続しました。
ただ、同時接続セッションが増えすぎた時にそれ以上の新規セッションがはれなくなっているような動作は無くなりました。

とりあえず、偏りすぎなのは大丈夫なのかよくわからなかったので、両方の対策を実施しています

@RemiNV
Copy link

RemiNV commented Nov 24, 2020

「json_add_boolean connlimit_ports "1"」ではなく、「json_add_string connlimit_ports "1"」です(booleanの読み取りにバグがあったため、「boolean」を「string」に変えます)。

うまく行けば、
iptables -t nat -S POSTROUTING
で確認すると、「-m connlimit」の入ったルールが出るはずです。そうなったらこの上の30個のルールを使う必要無いと思います。

@osakanataro
Copy link

GL.iNet GL-MV1000 firmware 3.102 ベース:OpenWrt 19.07.0-rc1 r10649-c4fdb377a2 にて、「json_add_string connlimit_ports "1"」だけを適用してみましたが、ちょっとコネクション数が増えるとそれ以上の通信ができなくなる、ということが頻発しましたので、結局こっちの設定に戻しました。

ちゃんと
-A POSTROUTING -o map-wan6_map -p icmp -m connlimit --connlimit-upto 16 --connlimit-mask 32 --connlimit-daddr -m comment --comment "!fw3: ubus:wan6_map[map] nat 0" -j SNAT --to-source 10?.???.???.???:5856-5871
とかのルールが追加されてはいるんですけどね・・・

GL.iNet製品のfirmwareはv3.104(7月リリース)、v3.105(先週リリース)と出ているんですが、どちらもIPv6を無効化して使えなくしているという謎修正をしてるのでベースのOpenWrtが新しくなった場合についてはいまだ果たせずとなります。

@Nadias-jp
Copy link

新しいと治っているかも、ということで試してみました。
21.02.0-RC1です。
osakanataroさんの報告と変わらず、で、詰まってまったくみれなくなることは無くなったのですが、特定のホームページは見られないままでした。

https://www.nichiban.co.jp
http://www.ntt-finance.co.jp/billing/index.html
(ログイン画面以降)

iptables -t nat -S POSTROUTING
-A POSTROUTING -m comment --comment "!fw3: Custom postrouting rule chain" -j postrouting_rule
-A POSTROUTING -o map-wan -p icmp -m connlimit --connlimit-upto 16 --connlimit-mask 32 --connlimit-daddr -m comment --comment "!fw3: ubus:wan[map] nat 0" -j SNAT --to-source XXX.XXX.XXX.XXX:1088-1103
-A POSTROUTING -o map-wan -p tcp -m connlimit --connlimit-upto 16 --connlimit-mask 32 --connlimit-daddr -m comment --comment "!fw3: ubus:wan[map] nat 1" -j SNAT --to-source XXX.XXX.XXX.XXX:1088-1103
-A POSTROUTING -o map-wan -p udp -m connlimit --connlimit-upto 16 --connlimit-mask 32 --connlimit-daddr -m comment --comment "!fw3: ubus:wan[map] nat 2" -j SNAT --to-source XXX.XXX.XXX.XXX:1088-1103

多分、RemiNVさんのパッチ後の動作だと思うのですが

iptables -t nat -L -v
   22  1415 postrouting_rule  all  --  any    any     anywhere             anywhere             /* !fw3: Custom postrouting rule chain */
    0     0 SNAT       icmp --  any    map-wan  anywhere             anywhere             #conn dst/32 <= 16 /* !fw3: ubus:wan[map] nat 0 */ to:XXX.XXX.XXX.XXX:1088-1103
    8   472 SNAT       tcp  --  any    map-wan  anywhere             anywhere             #conn dst/32 <= 16 /* !fw3: ubus:wan[map] nat 1 */ to:XXX.XXX.XXX.XXX:1088-1103
    1    76 SNAT       udp  --  any    map-wan  anywhere             anywhere             #conn dst/32 <= 16 /* !fw3: ubus:wan[map] nat 2 */ to:XXX.XXX.XXX.XXX:1088-1103

使われるのは一番上だけでした。
「json_add_string connlimit_ports "1"」でも上記は変化ありませんでした。

とりあえずご報告でした。
(Marvel MACCHIATObinです)

@Nadias-jp
Copy link

5chにカスタムルールを書いてくれてる方がいらっしゃいました。
https://pastebin.pl/view/raw/06212cd8
カスタムルールに書き込み、
sh /etc/firewall.user
にて動作確認しました。
感謝。

@Nadias-jp
Copy link

コメントアウトしながらニチバンベンチ回してみました。

  • map.shの書き換えは不要。
  • デフォルトで--connlimit-mask 32で設定されるが、上記ルールで--connlimit-mask 0 上書きが必要→どこをいじれば変更できるかわかりませんでした・・・。
  • 上記ルールの'done'以降は、デフォルトで大丈夫なので不要。
  • mark対応は必要(コメントアウトすると回らない)
  • typo→iptables -t nat -F OUTPUT

@osakanataro
Copy link

うちのopenWRT 21.02.0-RC環境で試したところ、範囲外のポートを指定するiptablesを出力していたので、こんな↓感じで設定しました。
https://gist.github.com/osakanataro/a9ba5ded340070b8e6abc28969d7ae4f

@Nadias-jp
Copy link

Luciに大分、変更が入り細かく設定できるようになりました。
合わせて上記を再チェックしました。やはり--connlimit-mask 32ではconnlimitが効かないようで1番目しか使われませんでした。
以下のようにスクリプトを書き換えました。

https://p.teknik.io/YuLFn

ニチバンも今のところ快調です。
connlimit-maskの設定がLuciからできるようになれば良いのですが。

@pantan-cymk
Copy link

map.shからconnlimit-maskをいじる方法です。
fw3のsnat周りのソースコードをみていたらextraオプションが使えることがわかりました。
extraはユーザー指定の文字列をコマンドとしてスルーするようです。

root@OpenWrt:/lib/netifd/proto# diff -c map.sh.org map.sh
*** map.sh.org Thu Jul 15 18:08:22 2021
--- map.sh Thu Jul 15 17:15:45 2021
***************
*** 150,155 ****
--- 150,156 ----
                    json_add_boolean connlimit_ports 1
                    json_add_string snat_ip $(eval "echo \$RULE_${k}_IPV4ADDR")
                    json_add_string snat_port "$portset"
+ json_add_string extra " --connlimit-mask 0 "
                json_close_object
                done
            done

ただ、実際設定してみるとバランスはされるのですが、DNS(UDP)とping(ICMP)は動作するようですが、HTTP/HTTPSまわり(多分TCP)がうまく動作しないです
じゃあ、statisticで分散してみればいいじゃないかと、実行してみると、接続できないことはないのですが、やけに動作が不安定だったりします。
うまく行かないもんですな…というお話だけ。おいておきます

root@OpenWrt:/lib/netifd/proto# diff -c map.sh.org map.sh
*** map.sh.org Thu Jul 15 18:08:22 2021
--- map.sh Thu Jul 15 19:43:45 2021
***************
*** 140,145 ****
--- 140,146 ----
              json_add_string snat_ip $(eval "echo \$RULE_${k}_IPV4ADDR")
            json_close_object
          else
+ local packetnum=0
            for portset in $(eval "echo \$RULE_${k}_PORTSETS"); do
                for proto in icmp tcp udp; do
                json_add_object ""
***************
*** 147,157 ****
                  json_add_string target SNAT
                  json_add_string family inet
                  json_add_string proto "$proto"
! json_add_boolean connlimit_ports 1
                    json_add_string snat_ip $(eval "echo \$RULE_${k}_IPV4ADDR")
                    json_add_string snat_port "$portset"
                json_close_object
                done
            done
          fi
          if [ "$maptype" = "map-t" ]; then
--- 148,160 ----
                  json_add_string target SNAT
                  json_add_string family inet
                  json_add_string proto "$proto"
! # json_add_boolean connlimit_ports 1
                    json_add_string snat_ip $(eval "echo \$RULE_${k}_IPV4ADDR")
                    json_add_string snat_port "$portset"
+ json_add_string extra " -m statistic --mode nth --every 15 --packet ${packetnum} "
                json_close_object
                done
+ packetnum=`expr $packetnum + 1`
            done
          fi
          if [ "$maptype" = "map-t" ]; then

@kurobee-dev
Copy link

@pantan-cymk さんの見つけた json_add_string extra に刺激を受けて標準のmap.sh への改造だけで
icmp,udp の --connlimit-mask 0 化 と tcp の statistic 化ができましたので参考まで。
パラメータがちゃんと指定されていればポートセットの数の違うサービスでも動的に対応できます。
https://gist.github.com/kurobee-dev/4107b18683e01d17a9b8678e770d272c

--connlimit-mask 32 の時に一番上のセットしか使われていないというのは、数分から数時間程度では使われないので当然なのですが、数日単位で放置してたら他のポートセットもカウントアップされてる事が分かるかと思います。いわゆるYAMAHAのポートセービングNATですね。JPNEみたいな240しか使えないサービスでポート使用量節約のためにそういう設定になっているのですから、ポンポン次のセットに移られても困ります。とはいえ、TCPではなぜか調子が悪いのでそれだけ statistic にしたかったのも事実。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment