web-dev-qa-db-ja.com

TCを使用したユーザーごとのOpenVPN帯域幅の制限/スロットル

OpenVPN TCPおよびUDP(2サービス)を介してサーバーに接続するユーザーのグループがあります。2つのサービスは_tun0_および_tun1_

TCコマンドを使用して、各ユーザーの帯域幅を5mb/sアップおよび5mb/sダウンに制限できるようにしたいと思います。

これは、PPTP)を使用して実装するのがかなり簡単でした。各ユーザーが独自のインターフェースを持っているため、このインターフェース用の新しいクラス/フィルターを作成して、次のようなものを使用して、希望する速度制限に制限できます。

_IF=<taken from up script, i.e. ppp1>
tc qdisc del dev $IF root
tc qdisc add dev $IF root handle 1: cbq avpkt 1000 bandwidth 100mbit
tc class add dev $IF parent 1: classid 1:1 cbq rate 10mbit allot 1500 prio 5 bounded isolated
tc filter add dev $IF parent 1: protocol ip prio 16 u32 match ip src 0.0.0.0/0 flowid 1:1
tc qdisc add dev $IF parent 1:1 sfq perturb 10
_

OpenVPNのユーザーが自分のインターフェースを取得していないことがわかる限り、すべてのトラフィックはメインの_tun0_および_tun1_インターフェースを通過します。

ここで2つの問題があります。

1)上記のスクリプトは、何らかの理由でOpenVPNで動作しないようです(インターフェイス名を_tun0_または_tun1_に設定)。テストユーザーは引き続きインターネットの最大速度でダウンロードできます。

2)ソースIPごとにこれをフィルタリングし、OpenVPNのupスクリプトに追加するときに、他のフィルター/クラスを維持しながら接続し、downスクリプトでそのフィルター/クラスを削除する必要があります。 、再度、接続されている他のユーザーの制限に影響を与えません(つまり、ユーザーが接続するたびにtun0のqdiscを削除することはできません)。

検索時に見つけることができる唯一の助けは

「そのためにTCを使用できます」

しかし、方法の説明はありません...

ありがとう!

7
user1167223

私はかつて、各ユーザーの接続を個別にファイアウォールで保護するためにこのようなことをしました。ユーザーが接続または切断したときに呼び出されるOpenVPNのlearn-addressスクリプトを使用して実装しました。私はそれをあなたのユースケースに適合させました。

スクリプトは次のようになります。

#!/bin/bash

statedir=/tmp/

function bwlimit-enable() {
    ip=$1
    user=$2

    # Disable if already enabled.
    bwlimit-disable $ip

    # Find unique classid.
    if [ -f $statedir/$ip.classid ]; then
        # Reuse this IP's classid
        classid=`cat $statedir/$ip.classid`
    else
        if [ -f $statedir/last_classid ]; then
            classid=`cat $statedir/last_classid`
            classid=$((classid+1))
        else
            classid=1
        fi
        echo $classid > $statedir/last_classid
    fi

    # Find this user's bandwidth limit
    # downrate: from VPN server to the client
    # uprate: from client to the VPN server
    if [ "$user" == "myuser" ]; then
        downrate=10mbit
        uprate=10mbit
    Elif [ "$user" == "anotheruser"]; then
        downrate=2mbit
        uprate=2mbit
    else
        downrate=5mbit
        uprate=5mbit
    fi

    # Limit traffic from VPN server to client
    tc class add dev $dev parent 1: classid 1:$classid htb rate $downrate
    tc filter add dev $dev protocol all parent 1:0 prio 1 u32 match ip dst $ip/32 flowid 1:$classid

    # Limit traffic from client to VPN server
    tc filter add dev $dev parent ffff: protocol all prio 1 u32 match ip src $ip/32 police rate $uprate burst 80k drop flowid :$classid

    # Store classid and dev for further use.
    echo $classid > $statedir/$ip.classid
    echo $dev > $statedir/$ip.dev
}

function bwlimit-disable() {
    ip=$1

    if [ ! -f $statedir/$ip.classid ]; then
        return
    fi
    if [ ! -f $statedir/$ip.dev ]; then
        return
    fi

    classid=`cat $statedir/$ip.classid`
    dev=`cat $statedir/$ip.dev`

    tc filter del dev $dev protocol all parent 1:0 prio 1 u32 match ip dst $ip/32
    tc class del dev $dev classid 1:$classid

    tc filter del dev $dev parent ffff: protocol all prio 1 u32 match ip src $ip/32

    # Remove .dev but keep .classid so it can be reused.
    rm $statedir/$ip.dev
}

# Make sure queueing discipline is enabled.
tc qdisc add dev $dev root handle 1: htb 2>/dev/null || /bin/true
tc qdisc add dev $dev handle ffff: ingress 2>/dev/null || /bin/true

case "$1" in
    add|update)
        bwlimit-enable $2 $3
        ;;
    delete)
        bwlimit-disable $2
        ;;
    *)
        echo "$0: unknown operation [$1]" >&2
        exit 1
        ;;
esac

exit 0

スクリプトは、次のようにOpenVPNのserver.confにインストールする必要があります。

learn-address <path-to-script>
script-security 3

OpenVPNが実際にスクリプトを呼び出すため、script-security 3が必要です。

ユーザーが接続すると、スクリプトは<path-to-script> add <ip> <username>として呼び出されます。さらに、ネットワークインターフェイスは環境変数$devに配置されます(例:tun0)。

スクリプトは、キューイング規則のネットワークインターフェイスを構成し、それに必要なフィルターとクラスをアタッチします。フィルターとクラスをインストールしたIPを追跡するので、ユーザーが切断した場合にそれらを後で削除できます。その状態は/tmpディレクトリに保持されます。これはおそらく変更する必要があります。

交通管制に関するものを100%正しく取得したかどうかはわかりません。 (OpenVPNからユーザーへの)ダウンロードトラフィックシェーピングは正常に機能しますが、アップロードを制限することはあまり正確ではありません。多分あなたはより良い方法を見つけてそれをスクリプトに統合することができます。

10
Oliver