Traffic Shaping unter OSX 10.10 mit pfctl und dnctl

Traffic Shaping unter OSX 10.10 mit pfctl und dnctl

Ich versuche, Traffic Shaping (Drosselung) auf Mac OS X 10.10 über pfctlund durchzuführen dnctl.

Ich habe einen einfachen Testserver und -client mit netcat ( nc) und einer synthetischen zufälligen Nutzlastdatei implementiert, um zu überprüfen, ob meine Dummynet-Pipe-Drosselung richtig funktioniert. Bisher hat der Versuch, die Dummynet-Pipe mit demGUI-App für Murus-Firewallscheint den Datenverkehr nicht richtig zu drosseln (64 MB-Übertragung ist in ~200 ms abgeschlossen).

Hier ist ein OSX-Bash-Shell-Skript (erfordert brew install coreutils) gdate, das ein vollständiges Beispiel darstellt. Wenn Sie es in einem Terminal wie folgt ausführen:

./throttle-test.sh server

und noch einer als

./throttle-test.sh client

Sie versuchen, eine Nutzlast von 64 MB über Ihre en0Schnittstelle zu übertragen (wird nicht verwendet lo0, da die enorme MTU nicht mit dem WAN-Verkehr vergleichbar ist).

Ich habe auch die Übertragung der Datei auf einen Remote-Linux-Laptop getestet, um zu sehen, ob die Drosselung umgangen wird, da es sich bei Quell- und Ziel-IP beide um lokale IPs handelt. Aber sogar bei einer Remote-Maschine in meinem LAN/WLAN ist die Geschwindigkeit viel schneller als die gedrosselte Grenze.

Meine Frage ist, welches Skript richtig wäre, um diesen Dateitransfer zu konfigurieren pfctlund dnctlauf eine bestimmte Bandbreitengrenze (z. B. 8 Mbit/s) zu drosseln. Der Umfang der Drosselung kann ein bestimmter TCP-Port sein.

Beachten Sie, dass OS X 10.10 dies nicht mehr enthält, ipfwdaher suche ich nach etwas, das pfctlund verwendet dnctl.

Hier ist meine throttle-test.shDatei:

#!/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 "$@"

Aktualisieren

Hier ist, was ich bisher habe. Dies scheint in der Download-Richtung korrekt zu funktionieren, in der Upload-Richtung gibt es jedoch überhaupt keine Drosselung.

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
}

Antwort1

Dies ist ein Skript, das ich mit einigem Erfolg auf El Capitan 10.11 verwendet habe:

#!/bin/bash

# Reset dummynet to default config
dnctl -f flush

# Compose an addendum to the default config: creates a new anchor
(cat /etc/pf.conf &&
  echo 'dummynet-anchor "my_anchor"' &&
  echo 'anchor "my_anchor"') | pfctl -q -f -

# Configure the new anchor
cat <<EOF | pfctl -q -a my_anchor -f -
no dummynet quick on lo0 all
dummynet out proto tcp from any to any port 1:65535 pipe 1
EOF

# Create the dummynet queue
dnctl pipe 1 config bw 40000byte/s

# Activate PF
pfctl -E

# to check that dnctl is properly configured: sudo dnctl list

Der einzige relevante Unterschied scheint das zu sein no dummynet quick on lo0 all, von dem ich nicht wirklich weiß, was es macht und das hier zu finden ist:https://www.reddit.com/r/osx/comments/3g7dim/limiting_bandwidth_per_application/

verwandte Informationen