Этот ответ основан на принятом ответе наhttps://stackoverflow.com/questions/10683349/forcing-bash-to-expand-variables-in-a-string-loaded-from-a-file
и адаптирован из него.
#!/bin/bash
export FOOBAR="SUCCESS"
file="testfile.txt"
var_name="TEST"
name="$file"
content="$(envsubst < "$file")"
echo "$content"
В отличие от eval
, envsubst
заменяет только переменные, нет риска выполнения других программ посредством подстановки команд или чего-то подобного. Это очень простой инструмент для создания шаблонов для оболочки.
envsubst
является частью утилиты интернационализации GNU gettext (в Debian, она находится в пакете gettext-base
).
Обратите внимание, что envsubst
(, являясь внешней командой, а не оболочкой, созданной -в ), может видеть только те переменные, которые были экспортированы (, но см. стандартную allexport
опцию sh
, чтобы сделать оболочку экспортировать впоследствии определенные переменные в среду ).
Трафик можно ограничить, используя только Управление трафиком в Linux .
Просто для уточнения, shadowsocks создает туннель с одной стороны в качестве прокси-сервера SOCKS5 (sslocal
, я предполагаю, что это то, что работает на сервере OP с учетом заданных портов ), связываясь с удаленная конечная точка (ssserver
), которая сама будет связываться с реальными целевыми серверами. shadowsocks обрабатывает SOCKS5 UDP ASSOCIATE и затем использует (SOCKS5 )UDP на том же порту, что и (SOCKS5 )TCP-порт.
Это решение работает как есть(см. примечание 1)как для TCP, так и для UDP, за исключением того, что UDP может создавать дополнительные проблемы :, если источник создает пакеты UDP размера «больше, чем MTU» (, что, вероятно, не должны выполняться хорошо работающим клиентом или сервером ), они фрагментируются. tc , который работает раньше, чем netfilter в входеи позже, чем netfilter в выходе , будет увидеть фрагменты. Порт UDP недоступен фрагментарно, поэтому никакие фильтры их не поймают и ограничения почти не будет. TCP естественным образом использует MTU для ограничения размера пакета (и в любом случае выполняет обнаружение MTU пути ), в большинстве настроек эта проблема не возникает.
Вот ASCII-изображение потока пакетов (полное изображение обычно представляет одно действие клиента, приводящее к двум потокам, один слева и один справа от прокси-сервера):
traffic controlled TCP self-adjusting / no UDP control
-------------> <-------------
/ \ / \
clients | | proxy | | remote ====== real servers
\ / (sslocal) \ / (ssserver)
<------------- ------------->
traffic controlled already rate limited
Нет нужды и смысла беспокоиться о трафике с удаленным сервером:
В любом случае будет намного сложнее, вероятно, с изменениями внутри shadowsocks, связать боковой трафик удаленного сервера/сервера с клиентским для tc использования.
Для клиентов SOCKS5 требуется только отправка данных, ограничение входящего от них требуется для ограничения пропускной способности, а для клиентов SOCKS5 требуется только получение данных, ограничение исходящего им требуется для ограничения пропускной способности :, если используемое приложение не известно, трафик должен контролироваться в обоих направлениях.
Управление дорожным движением — сложная тема, которую я едва могу коснуться. Я дам два вида ответов :простой и грубый, выполняющий контроль (только отбрасывание излишков ), и более сложный, выполняющий формирование (вкл. задержка перед сбросом )с интерфейсом IFB для обхода ограничений входа .
Приведенную ниже документацию следует прочитать, чтобы понять концепции и реализацию Linux.:
http://www.tldp.org/HOWTO/Traffic-Control-HOWTO/
Кроме того, эта команда, реализованная в сценарии оболочки (и использующая аналогичные механизмы, как в этом ответе ), действительно может творить чудеса:
https://github.com/magnific0/wondershaper
Полицейское действие используется для отбрасывания любых избыточных портов сопоставления пакетов (, что является грубым методом ). Обычно он используется для входа , но работает и для выхода . Трафик ограничен по скорости, но могут быть колебания и несправедливое распределение между различными клиентами с ограниченной скоростью (, особенно если речь идет о UDP и TCP ).
исходящие(исходящие пакеты)
Самым простым qdisc , позволяющим прикреплять фильтры, являетсяprioqdisc , особенности которого практически не используются.
tc qdisc add dev eth0 root handle 1: prio
Простое добавление следующего фильтра (с 8 Мбит/с <=> 1 МБ/с )по одному на порт(u16 at 0 layer transport
означает «исходный порт» ), это будет сделано для TCP и UDP(см. также примечание 2):
tc filter add dev eth0 parent 1: protocol ip basic match 'cmp(u16 at 0 layer transport eq 1081)' action police rate 8mibit burst 256k
tc filter add dev eth0 parent 1: protocol ip basic match 'cmp(u16 at 0 layer transport eq 1082)' action police rate 8mibit burst 256k
В случае, если я неправильно понял и должен быть только один общий предел для 1081 и 1082, используйте его вместо двух вышеперечисленных, сгруппировав их в одно и то же действие (, что легко с основным / ematch фильтр ), который затем будет обрабатывать их в одном сегменте токенов:
tc filter add dev eth0 parent 1: protocol ip basic match 'cmp(u16 at 0 layer transport eq 1081) or cmp(u16 at 0 layer transport eq 1082)' action police rate 8mibit burst 256k
входящие (входящие пакеты)
Вход более ограничен, чем выход(не может выполнять формирование ), но в любом случае это не было сделано в простом случае. Для его использования требуется просто добавить ingress
qdisc(см. примечание 3):
tc qdisc add dev eth0 ingress
Эквивалентные фильтры(u16 at 2 layer transport
означают «порт назначения»):
tc filter add dev eth0 ingress protocol ip basic match 'cmp(u16 at 2 layer transport eq 1081)' action police rate 8mibit burst 256k
tc filter add dev eth0 ingress protocol ip basic match 'cmp(u16 at 2 layer transport eq 1082)' action police rate 8mibit burst 256k
или для одного лимита вместо двух вышеперечисленных:
tc filter add dev eth0 ingress protocol ip basic match 'cmp(u16 at 2 layer transport eq 1081) or cmp(u16 at 2 layer transport eq 1082)' action police rate 8mibit burst 256k
выход , вход или обе настройки можно заменить их улучшенной версией ниже. предыдущие настройки должны быть очищены в первую очередь.
Чтобы удалить ранее примененные настройки tc, просто удалите root и ingressqdiscs . Все, что ниже их, включая фильтры, также будет удалено. Корневой интерфейс интерфейса по умолчанию qdisc с зарезервированным дескриптором 0 :будет возвращен.
tc qdisc del dev eth0 root
tc qdisc del dev eth0 ingress
Использование формирования , которое может задерживать пакеты перед их отбрасыванием, должно улучшить общие результаты. Ведро маркеров иерархии(HTB ),классовый qdisc будет управлять пропускной способностью, в то время как стохастическая равноправная организация очереди(SFQ)улучшит справедливость между клиентами, когда они конкурируют в пределах ограниченной пропускной способности.
выход
Вот картинка ascii, описывающая следующие настройки:
root 1: HTB classful qdisc
|
/ | \
/ | \
/ | \
/ | \
/ 1:20 1:30 HTB classes
/ 8mibit 8mibit
/ | \
/ | \
/ 20: 30:
/ SFQ SFQ
still 1:
default port port
incl. port 1080 1081 1082
Ограниченная пропускная способность не будет занимать дополнительный доступный трафик (OP не задавала этот вопрос ):, поэтому они не являются подклассом класса по умолчанию «всей доступной пропускной способности». Остальной трафик по умолчанию, включая порт 1080, просто остается на 1 :без специальной обработки. В других условиях, когда классам разрешено заимствовать доступную пропускную способность, эти классы должны быть помещены ниже родительского класса, скорость которого установлена с точным значением максимально доступной пропускной способности, чтобы знать, что заимствовать. Таким образом, конфигурация потребует тонкой -настройки для каждого случая. Я сделал это просто.
Классовый qdisc htb:
tc qdisc add dev eth0 root handle 1: htb
Классы htb, прикрепленные sfq и направляющие к ним фильтры:
tc class add dev eth0 parent 1: classid 1:20 htb rate 8mibit
tc class add dev eth0 parent 1: classid 1:30 htb rate 8mibit
tc qdisc add dev eth0 parent 1:20 handle 20: sfq perturb 10
tc qdisc add dev eth0 parent 1:30 handle 30: sfq perturb 10
tc filter add dev eth0 parent 1: protocol ip prio 1 basic match 'cmp(u16 at 0 layer transport eq 1081)' flowid 1:20
tc filter add dev eth0 parent 1: protocol ip prio 1 basic match 'cmp(u16 at 0 layer transport eq 1082)' flowid 1:30
или для одного лимита вместо 6 команд выше:
tc class add dev eth0 parent 1: classid 1:20 htb rate 8mibit
tc qdisc add dev eth0 parent 1:20 handle 20: sfq perturb 10
tc filter add dev eth0 parent 1: protocol ip prio 1 basic match 'cmp(u16 at 0 layer transport eq 1081)' flowid 1:20
tc filter add dev eth0 parent 1: protocol ip prio 1 basic match 'cmp(u16 at 0 layer transport eq 1082)' flowid 1:20
вход
Ingress qdisc нельзя использовать для формирования (, например задержки пакетов ), а только для их отбрасывания фильтрами, как в простом случае. Для лучшего контроля доступен трюк :Промежуточный функциональный блок , который выглядит как искусственный исходящий интерфейс, где входящий трафик может быть перенаправляется с фильтрами, но мало взаимодействует с остальной частью сетевого стека. После установки к нему можно применить исходящие функции, даже если некоторые из них не всегда могут быть полезны, учитывая, что реальный контроль над входящим трафиком не находится в руках принимающей системы. Итак, здесь я настраиваю интерфейс ifb0
, а затем продублирую вышеприведенные настройки(выхода)на нем,иметь вид -формирования входа, который ведет себя лучше, чем просто контроль.
Создание ifb0(см. примечание 4)и применение тех же настроек, что и для предыдущего выхода:
ip link add name ifb0 type ifb 2>/dev/null || :
ip link set dev ifb0 up
tc qdisc add dev ifb0 root handle 1: htb
Классы и направляющие к ним фильтры:
tc class add dev ifb0 parent 1: classid 1:20 htb rate 8mibit
tc class add dev ifb0 parent 1: classid 1:30 htb rate 8mibit
tc qdisc add dev ifb0 parent 1:20 handle 20: sfq perturb 10
tc qdisc add dev ifb0 parent 1:30 handle 30: sfq perturb 10
tc filter add dev ifb0 parent 1: protocol ip prio 1 basic match 'cmp(u16 at 2 layer transport eq 1081)' flowid 1:20
tc filter add dev ifb0 parent 1: protocol ip prio 1 basic match 'cmp(u16 at 2 layer transport eq 1082)' flowid 1:30
или для одного предела, вместо этого, если 6 команд выше:
tc class add dev ifb0 parent 1: classid 1:20 htb rate 8mibit
tc qdisc add dev ifb0 parent 1:20 handle 20: sfq perturb 10
tc filter add dev ifb0 parent 1: protocol ip prio 1 basic match 'cmp(u16 at 2 layer transport eq 1081)' flowid 1:20
tc filter add dev ifb0 parent 1: protocol ip prio 1 basic match 'cmp(u16 at 2 layer transport eq 1082)' flowid 1:20
Перенаправление с eth0 входящего на ifb0исходящего выполняется ниже. Для оптимизации перенаправляйте только нужные порты, а не весь трафик. Фактическая фильтрация и формирование в любом случае выполняются выше в ifb0 .
tc qdisc add dev eth0 ingress
tc filter add dev eth0 ingress protocol ip basic match 'cmp(u16 at 2 layer transport eq 1081)' action mirred egress redirect dev ifb0
tc filter add dev eth0 ingress protocol ip basic match 'cmp(u16 at 2 layer transport eq 1081)' action mirred egress redirect dev ifb0
Примечания:
1. Протестировано с использованием нескольких сетевых пространств имен в Debian 10/ядре 5.3. Синтаксис команд также протестирован на контейнере CentOS 7.6/ядре 5.3 (, а не 3.10 ).
2. Вместо этого можно было бы использовать u32 match ip sport 1081 0xffff
для сопоставления исходного порта 1081. Но это не обрабатывало бы наличие параметра IP. u32 match tcp src 1081 0xffff
может с этим справиться, но на самом деле требует комплексного использования трехфильтров u32 , как описано в справочной странице . Так что в конце концов я выбрал basic match
.
3. ingress
имеет зарезервированный дескриптор ffff:
независимо от того, указан он или нет (указанное значение дескриптора игнорируется ), поэтому я бы не стал его указывать. Ссылка на вход по parent ffff:
может быть заменена просто ingress
, так что я выбрал именно это.
4. При первом создании интерфейса IFB загружается модуль ifb, который по умолчанию автоматически создает интерфейсы ifb0 и ifb1 в исходном пространстве имен, что приводит к ошибка, если запрашивается имя интерфейса ifb0, хотя на самом деле он был создан в результате выполнения команды. В то же время этот интерфейс не отображается в сетевом пространстве имен (, например :контейнер ), если просто загружается модуль, поэтому он все еще нужен там.Таким образом, добавление 2>/dev/null || :
решает проблему в обоих случаях. Конечно, я предполагаю, что поддержка IFB действительно доступна.