Estou tentando fazer o traffic shaping (estrangulamento) no Mac OS X 10.10 via pfctl
e dnctl
.
Implementei um servidor e cliente de teste simples com o netcat ( nc
) e um arquivo de carga útil sintético para verificar se a otimização do meu tubo dummynet está funcionando corretamente. Até agora, tentar configurar o pipe dummynet usando o aplicativo GUI do firewall murus não parece regular o tráfego corretamente (a transferência de 64MB é concluída em ~ 200ms).
Aqui está um script de shell bash do OSX (requer brew install coreutils
para gdate
) que é um exemplo completo. Se você executá-lo em um terminal como:
./throttle-test.sh server
e outro como
./throttle-test.sh client
Eles tentarão transferir uma carga útil de 64 MB sobre sua interface en0
(não usando lo0
porque sua enorme MTU não é análoga ao tráfego da WAN).
Eu também testei a transferência do arquivo para um laptop linux remoto para ver se o IP de origem e destino era IP local, ignorando o afogamento, mas mesmo para uma máquina remota na minha LAN / wifi a velocidade é muito mais rápida que limite limitado.
Minha pergunta é o que seria um script correto para configurar pfctl
e dnctl
para acelerar essa transferência de arquivos para um determinado limite de largura de banda (digamos 8mbps, por exemplo). O escopo do afogamento pode ser uma porta TCP específica.
Observação O OS X 10.10 não inclui mais ipfw
, então estou procurando algo usando pfctl
e dnctl
.
Este é o meu arquivo throttle-test.sh
:
#!/bin/bash
set -o errexit # always exit on error
set -o errtrace # trap errors in functions as well
set -o pipefail # don't ignore exit codes when piping output
set -o posix # more strict failures in subshells
# set -x # enable debugging
IFS="$(printf "\n\t")"
setup_payload() {
local payload_path="$1"
local size_kbytes="$2"
mkdir -p $(basename "${payload_path}")
if [[ -f "${payload_path}" ]]; then
local on_disk=$(wc -c < "${payload_path}")
fi
if [[ ${on_disk} -ne $((${size_kbytes} * 1024)) ]]; then
echo "creating payload file ${payload_path}"
dd if=/dev/urandom of="${payload_path}" \
bs=1024 count="${size_kbytes}" &> /dev/null
fi
}
start_server() {
local payload_path="$1"
local ip="$2"
local port="$3"
while true; do
echo "Starting netcat server for ${payload_path} on ${ip}:${port}"
nc -l "${ip}" "${port}" < "${payload_path}"
sleep 1
done
}
hash() {
shasum -a 256 "$1" | cut -d " " -f 1
}
verify_hashes() {
# Sanity check no funny business
from_hash=$(hash "$1")
to_hash=$(hash "$2")
if [[ "${from_hash}" != "${to_hash}" ]]; then
echo "checksums did not match ${from_hash} ${to_hash}" 1>&2
exit 10
fi
}
client() {
local payload_path="$1"
local ip="$2"
local port="$3"
# time how long it takes to transfer the payload file
start=$(gdate +%s%3N)
nc -d "${ip}" "${port}" > "${payload_path}.client"
stop=$(gdate +%s%3N)
verify_hashes "${payload_path}" "${payload_path}.client"
local duration=$((${stop} - ${start}))
echo "${duration}"
}
main() {
local size_kbytes=$((64 * 1024)) # 64 MB
local payload_path="/tmp/throttle-test/data-${size_kbytes}.bin"
local port="${PORT-9112}"
# You may need to change this if you are on linux
local interface="${INTERFACE-en0}"
local ip=$(ipconfig getifaddr "${interface}")
setup_payload "${payload_path}" "${size_kbytes}"
case "$1" in
server)
start_server "${payload_path}" "${ip}" "${port}"
;;
client)
local duration=$(client "${payload_path}" "${ip}" "${port}")
echo "Transfered ${size_kbytes} kbytes in ${duration} ms"
;;
*)
echo "Usage: $0 <server|client>"
;;
esac
}
main "$@"
Atualizar
Aqui está o que eu tenho até agora. Isso parece funcionar corretamente para a direção de download, mas não para acelerar na direção do upload.
throttle_start() {
local down_mbps="$1"
local up_mbps="$2"
local delay=$(($3 / 2))
sudo dnctl pipe 1 config bw "${down_mbps}Mbit/s" delay "${delay}"
sudo dnctl pipe 2 config bw "${up_mbps}Mbit/s" delay "${delay}"
(cat /etc/pf.conf && \
echo 'dummynet-anchor "throttle"' && \
echo 'anchor "throttle"') | sudo pfctl -f -
cat << EOF | sudo pfctl -a throttle -f -
dummynet in quick proto tcp from any port = 9112 to any pipe 1
dummynet out quick proto tcp from any to any port = 9112 pipe 2
EOF
sudo pfctl -q -e
}