Tc: kiểm soát xâm nhập và phản chiếu ifb


20

Tôi đang cố gắng thiết lập lưu lượng truy cập định hình trên một cổng Linux như được viết ở đây . Kịch bản cần được tùy chỉnh vì tôi có nhiều giao diện LAN. Vì vậy, để định hình phía LAN, tôi dự định tạo một thiết bị giả ifb như vậy:

     modprobe ifb
     ip link set dev ifb0 up
    /sbin/tc qdisc add dev $WAN_INTERFACE ingress
    /sbin/tc filter add dev $WAN_INTERFACE parent ffff: protocol ip u32 match u32 0 0 action mirred egress redirect dev ifb0

Kịch bản từ repo ý chính được đề cập ở trên có những dòng này:

 /sbin/tc qdisc add dev $WAN_INTERFACE handle ffff: ingress
    /sbin/tc filter add dev $WAN_INTERFACE parent ffff: protocol ip prio 1 u32 match ip sport $INTERACTIVE_PORT 0xffff flowid :1
    /sbin/tc filter add dev $WAN_INTERFACE parent ffff: protocol ip prio 1 u32 match ip dport $INTERACTIVE_PORT 0xffff flowid :1
    /sbin/tc filter add dev $WAN_INTERFACE parent ffff: protocol ip prio 5 0 u32 match ip src 0.0.0.0/0 police rate $MAX_DOWNRATE_INGRESS burst 20k drop flowid :2

Mã này và mã tạo giao diện ifb không hợp nhau. Tập lệnh tùy chỉnh được thực thi, nhưng thiết bị ifb0 không hiển thị bất kỳ số liệu thống kê lưu lượng truy cập nào. Nếu tôi nhận xét mã repo chính xâm nhập (trích dẫn ở trên), thì thiết bị ifb0 hiển thị số lượng gói được truyền. Ngoài ra, các dòng này không thể được thực thi cùng nhau:

/sbin/tc qdisc add dev $WAN_INTERFACE ingress
/sbin/tc qdisc add dev $WAN_INTERFACE handle ffff: ingress

Tôi nhận được tập tin tồn tại lỗi. Vì vậy, làm cách nào tôi có thể định hình xâm nhập trên mạng WAN_INTERFACE và đồng thời cũng định hình lưu lượng truy cập vào mạng LAN thông qua thiết bị ifb0?

Câu trả lời:


41

IFB là một giải pháp thay thế cho các bộ lọc tc để xử lý lưu lượng truy cập, bằng cách chuyển hướng nó sang giao diện ảo và coi đó là lưu lượng truy cập ở đó. Bạn cần một giao diện ifb trên mỗi giao diện vật lý, để chuyển hướng lưu lượng truy cập từ eth0 sang ifb0, eth1 sang ifb1 và như vậy trên.

Khi chèn mô-đun ifb, hãy cho nó biết số lượng giao diện ảo bạn cần. Mặc định là 2:

modprobe ifb numifbs=1

Bây giờ, kích hoạt tất cả các giao diện ifb:

ip link set dev ifb0 up # repeat for ifb1, ifb2, ...

Và chuyển hướng lưu lượng truy cập từ các giao diện vật lý sang giao diện ifb tương ứng. Đối với eth0 -> ifb0:

tc qdisc add dev eth0 handle ffff: ingress
tc filter add dev eth0 parent ffff: protocol ip u32 match u32 0 0 action mirred egress redirect dev ifb0

Một lần nữa, lặp lại cho eth1 -> ifb1, eth2 -> ifb2, v.v., cho đến khi tất cả các giao diện bạn muốn định hình được bao phủ.

Bây giờ, bạn có thể áp dụng tất cả các quy tắc bạn muốn. Quy tắc đi ra cho eth0 đi như bình thường trong eth0. Hãy giới hạn băng thông, ví dụ:

tc qdisc add dev eth0 root handle 1: htb default 10
tc class add dev eth0 parent 1: classid 1:1 htb rate 1mbit
tc class add dev eth0 parent 1:1 classid 1:10 htb rate 1mbit

Không cần phải nói, lặp lại cho eth1, eth2, ...

Nhập quy tắc cho eth0, bây giờ đi theo quy tắc đi ra trên ifb0 (bất cứ điều gì đi vào ifb0 phải xuất hiện và chỉ lưu lượng truy cập eth0 đi vào ifb0). Một lần nữa, một ví dụ giới hạn băng thông:

tc qdisc add dev ifb0 root handle 1: htb default 10
tc class add dev ifb0 parent 1: classid 1:1 htb rate 1mbit
tc class add dev ifb0 parent 1:1 classid 1:10 htb rate 1mbit

Ưu điểm của phương pháp này là các quy tắc đi ra linh hoạt hơn nhiều so với các bộ lọc xâm nhập. Bộ lọc chỉ cho phép bạn bỏ các gói, không giới thiệu thời gian chờ, ví dụ. Bằng cách xử lý lưu lượng truy cập khi đi ra, bạn có thể thiết lập các quy tắc hàng đợi, với các lớp lưu lượng và, nếu cần, các bộ lọc. Bạn có quyền truy cập vào toàn bộ cây tc, không chỉ các bộ lọc đơn giản.


Hoàn thành tốt Luôn luôn tốt để thấy một chuyên gia bật lên với câu trả lời đầu tiên của ngôi sao nhạc rock.
Magellan

Đây có thể là một câu hỏi ngây thơ, nhưng tôi không tìm thấy thông tin cụ thể. Dựa trên câu trả lời này (đó là btw tuyệt vời), có thể lấy ifb0số liệu thống kê cụ thể cho một cgroup classid không? Đó là, tôi có thể lấy thành công số liệu thống kê đầu ra cho một nhóm với bộ lọc classid. Nhưng lưu lượng đến cũng có thể được tính trên cơ sở cho mỗi nhóm?
JDI

lưu ý rằng nếu bạn sử dụng iptable để đánh dấu gói tin của mình và sau đó lọc chúng, bạn không thể sử dụng ifb vì tất cả các tiêu đề xâm nhập sẽ được chuyển tiếp TRƯỚC bất kỳ đánh dấu nào. vì vậy bạn sẽ giữ lớp của mình ở mức 0 và tất cả được chuyển tiếp đến mặc định. IMQ dường như là giải pháp cứng nhắc cho người dùng iptables.
ornoone

@ SérgioCarvalho Tôi dường như không thể làm điều này hoạt động song song với bộ điều khiển net_cls của các nhóm. Tôi hơi bối rối, vì tôi có thể hạn chế lưu lượng truy cập mạng đi ra bình thường (đi ra) bằng cách sử dụng net_cls song song với tc? Dự đoán tốt nhất của tôi là vì lý do nào đó sử dụng ifb theo cách này mà các gói đi ra từ ifb không được gắn thẻ đúng cách kể từ khi chúng bắt đầu xâm nhập? Bất cứ ai có thể xác nhận điều này hoặc đề nghị một cách mà tôi có thể?
Dậu

3

Dựa trên câu trả lời của Sérgio Carvalho, tôi đã tạo một tập lệnh bash nhỏ để giới hạn băng thông:

Tên tệp: Netspeed

#!/bin/bash 

#USAGE: sudo ./netspeed -l limit_in_kbit -s
usage="sudo $(basename "$0") -l speed_limit -s
  -l speed_limit - speed limit with units (eg. 1mbit, 100kbit, more on \`man tc\`)
  -s - remove all limits
"

# default values
LIMIT=0
STOP=0

# hardcoded constats
IFACE=ifb0 # fake interface name which will be used for shaping the traffic
NETFACE=wlan0 # interface which in connected to the internet

# shift all required and leave only optional

while getopts ':hl:s' option; do
  case "$option" in
   l) LIMIT=$OPTARG
      ;;
   s) STOP=1
      ;;
   h) echo "$usage"
      exit
      ;;
  esac
done

#
# functions used in script
#
function limitExists { # detected by ingress on $NETFACE qdisc
   # -n equals true if non-zero string length
  if [[ -n `tc qdisc show | grep "ingress .* $NETFACE"` ]]
  then
    return 0 # true
  else
    return 1 # false
  fi

}
function ifaceExists {
  # -n equals true if non-zero string length
  if [[ -n `ifconfig -a | sed 's/[ \t].*//;/^\(lo\|\)$/d' | grep $IFACE` ]]
  then
    return 0 # true
  else
    return 1 # false
  fi
}
function ifaceIsUp {
  # -n equals true if non-zero string length
  if [[ -n `ifconfig | sed 's/[ \t].*//;/^\(lo\|\)$/d' | grep $IFACE` ]]
  then
    return 0 # true
  else
    return 1 # false
  fi
}
function createLimit {
  #3. redirect ingress
  tc qdisc add dev $NETFACE handle ffff: ingress
  tc filter add dev $NETFACE parent ffff: protocol ip u32 match u32 0 0 action mirred egress redirect dev $IFACE

  #4. apply egress rules to local inteface (like wlan0)
  tc qdisc add dev $NETFACE root handle 1: htb default 10
  tc class add dev $NETFACE parent 1: classid 1:1 htb rate $LIMIT
  tc class add dev $NETFACE parent 1:1 classid 1:10 htb rate $LIMIT

  #5. and same for our relaying virtual interfaces (to simulate ingress)
  tc qdisc add dev $IFACE root handle 1: htb default 10
  tc class add dev $IFACE parent 1: classid 1:1 htb rate $LIMIT
  tc class add dev $IFACE parent 1:1 classid 1:10 htb rate $LIMIT
}
function updateLimit {
  #3. redirect ingress
  tc filter replace dev $NETFACE parent ffff: protocol ip u32 match u32 0 0 action mirred egress redirect dev $IFACE

  #4. apply egress rules to local inteface (like wlan0)
  tc class replace dev $NETFACE parent 1: classid 1:1 htb rate $LIMIT
  tc class replace dev $NETFACE parent 1:1 classid 1:10 htb rate $LIMIT

  #5. and same for our relaying virtual interfaces (to simulate ingress)
  tc class replace dev $IFACE parent 1: classid 1:1 htb rate $LIMIT
  tc class replace dev $IFACE parent 1:1 classid 1:10 htb rate $LIMIT
}
function removeLimit {
  if limitExists ; then
    tc qdisc del dev $NETFACE ingress
    tc qdisc del dev $NETFACE root
    tc qdisc del dev $IFACE root
  fi
  if ifaceIsUp ; then
    ip link set dev $IFACE down
  fi
}

#
# main script
#
if [[ `whoami` != "root" ]]; then
  echo "WARNING: script must be executed with root privileges!"
  echo $usage
  exit 1
fi
if [ $STOP -eq 1 ]; then
  echo "REMOVING limit"
  removeLimit
  echo "limit REMOVED"
elif [ "$LIMIT" != "0" ]; then
  # prepare interface
  if ! ifaceExists ; then
    echo "CREATING $IFACE by modprobe"
    modprobe ifb numifbs=1
    if ! ifaceExists ; then
      echo "creating $IFACE by modprobe FAILED"
      echo "exit with ERROR code 2"
      exit 2
    fi
  fi
  # set interface up
  if ifaceIsUp ; then
    echo "$IFACE is already up"
  else
    echo "set $IFACE up"
    ip link set dev $IFACE up # ( use ifconfig to see results)
    if ifaceIsUp ; then
      echo "$IFACE is up"
    else
      echo "enabling $IFACE by ip link FAILED"
      echo "exit with ERROR code 3"
      exit 3
    fi
  fi

  # create/update limits
  if limitExists ; then
    echo "update limit"
    updateLimit
  else
    echo "create limit"
    createLimit
  fi

  echo "limit CREATED"
  exit 0
else
  echo $usage
fi

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.