From b8adf51e1d8b18d68e64a9488c7c3fa8b562c121 Mon Sep 17 00:00:00 2001 From: Ycarus Date: Mon, 15 Apr 2019 22:18:01 +0200 Subject: [PATCH] Add DSCP support --- luci-app-omr-dscp/Makefile | 15 ++ .../luasrc/controller/omr-dscp.lua | 8 + .../luasrc/model/cbi/dscp-domains.lua | 31 ++++ luci-app-omr-dscp/luasrc/model/cbi/dscp.lua | 84 +++++++++ luci-app-omr-dscp/root/etc/init.d/omr-dscp | 164 ++++++++++++++++++ luci-app-omr-dscp/root/etc/uci-defaults/dscp | 24 +++ openmptcprouter-full/Makefile | 2 +- 7 files changed, 327 insertions(+), 1 deletion(-) create mode 100644 luci-app-omr-dscp/Makefile create mode 100644 luci-app-omr-dscp/luasrc/controller/omr-dscp.lua create mode 100644 luci-app-omr-dscp/luasrc/model/cbi/dscp-domains.lua create mode 100644 luci-app-omr-dscp/luasrc/model/cbi/dscp.lua create mode 100755 luci-app-omr-dscp/root/etc/init.d/omr-dscp create mode 100755 luci-app-omr-dscp/root/etc/uci-defaults/dscp diff --git a/luci-app-omr-dscp/Makefile b/luci-app-omr-dscp/Makefile new file mode 100644 index 000000000..253ddac12 --- /dev/null +++ b/luci-app-omr-dscp/Makefile @@ -0,0 +1,15 @@ +# +# Copyright (C) 2018-2019 Ycarus (Yannick Chabanois) +# +# + +include $(TOPDIR)/rules.mk + +LUCI_TITLE:=LuCI Interface to DSCP +#LUCI_DEPENDS:= + +PKG_LICENSE:=GPLv3 + +include ../luci/luci.mk + +# call BuildPackage - OpenWrt buildroot signature diff --git a/luci-app-omr-dscp/luasrc/controller/omr-dscp.lua b/luci-app-omr-dscp/luasrc/controller/omr-dscp.lua new file mode 100644 index 000000000..860fadbf8 --- /dev/null +++ b/luci-app-omr-dscp/luasrc/controller/omr-dscp.lua @@ -0,0 +1,8 @@ +module("luci.controller.omr-dscp", package.seeall) + +function index() + entry({"admin", "network", "omr-dscp"}, alias("admin", "network", "omr-dscp", "dscp"), _("OMR-DSCP")) + --entry({"admin", "network", "omr-dscp", "index"}, template("omr-dscp/dscp")) + entry({"admin", "network", "omr-dscp", "dscp"}, cbi("dscp"), _("DSCP"),1) + entry({"admin", "network", "omr-dscp", "domains"}, cbi("dscp-domains"), _("DSCP Domains"),2).leaf = true +end diff --git a/luci-app-omr-dscp/luasrc/model/cbi/dscp-domains.lua b/luci-app-omr-dscp/luasrc/model/cbi/dscp-domains.lua new file mode 100644 index 000000000..2b6e2523a --- /dev/null +++ b/luci-app-omr-dscp/luasrc/model/cbi/dscp-domains.lua @@ -0,0 +1,31 @@ +-- Copyright 2018-2019 Ycarus (Yannick Chabanois) +-- Licensed to the public under the Apache License 2.0. + +local ipc = require "luci.ip" +local sys = require "luci.sys" +local net = require "luci.model.network".init() + +m = Map("dscp", translate("DSCP by domain"), translate("Set DSCP by domains.")) + +s = m:section(TypedSection, "domains", translate("Domains")) +s.addremove = true +s.anonymous = true +s.template = "cbi/tblsection" + +hn = s:option(Value, "name", translate("Domain")) +hn.datatype = "hostname" +hn.optional = false +--hn.rmempty = true + +t = s:option(ListValue, "class", translate("Class")) +t:value("cs0", translate("CS0 - Normal/Best Effort")) +t:value("cs1", translate("CS1 - Low priority")) +t:value("cs2", translate("CS2 - High priority")) +t:value("cs3", translate("CS3 - SIP")) +t:value("cs4", translate("CS4 - Streaming video")) +t:value("cs5", translate("CS5")) +t:value("cs6", translate("CS6 - Network routing")) +t:value("cs7", translate("CS7")) +t:value("ef", translate("EF Voice")) + +return m diff --git a/luci-app-omr-dscp/luasrc/model/cbi/dscp.lua b/luci-app-omr-dscp/luasrc/model/cbi/dscp.lua new file mode 100644 index 000000000..c298306d0 --- /dev/null +++ b/luci-app-omr-dscp/luasrc/model/cbi/dscp.lua @@ -0,0 +1,84 @@ +-- Copyright 2008 Steven Barth +-- Licensed to the public under the Apache License 2.0. + +local uci = luci.model.uci.cursor() + +local wa = require "luci.tools.webadmin" +local ut = require "luci.util" +local sys = require "luci.sys" + +m = Map("dscp", translate("Differentiated services"), + translate("Traffic may be classified by many different parameters, such as source address, destination address or traffic type and assigned to a specific traffic class.")) + +--s = m:section(SimpleSection, "DSCP Values", "") + +s = m:section(TypedSection, "classify", translate("Classification Rules")) +s.template = "cbi/tblsection" +s.anonymous = true +s.addremove = true +--s.sortable = true + +function cbiAddProtocol(field) + local protocols = ut.trim(sys.exec("cat /etc/protocols | grep '\\s# ' | awk '{print $1}' | grep -v '^#' | grep -vw -e 'ip' -e 'tcp' -e 'udp' -e 'icmp' -e 'esp' | grep -v 'ipv6' | sort | tr '\n' ' '")) + for p in string.gmatch(protocols, "%S+") do + field:value(p) + end +end + +direction = s:option(ListValue, "direction", translate("Direction")) + direction.default = "upload" + direction.rmempty = false + direction:value("upload", translate("upload")) + direction:value("download", translate("download")) + direction:value("both", translate("both")) + +proto = s:option(Value, "proto", translate("Protocol")) + proto.default = "all" + proto.rmempty = false + proto:value("tcp") + proto:value("udp") + proto:value("all") + proto:value("ip") + proto:value("icmp") + proto:value("esp") + cbiAddProtocol(proto) + +srch = s:option(Value, "src_ip", translate("Source host")) + srch.rmempty = true + srch:value("", translate("all")) + wa.cbi_add_knownips(srch) + +sports = s:option(Value, "src_port", translate("Source ports")) + sports.rmempty = true + sports:value("", translate("all")) + sports:depends("proto","tcp") + sports:depends("proto","udp") + +dsth = s:option(Value, "dest_ip", translate("Destination host")) + dsth.rmempty = true + dsth:value("", translate("all")) + dsth:depends("direction", "upload") + wa.cbi_add_knownips(dsth) + +dports = s:option(Value, "dest_port", translate("Destination ports")) + dports.rmempty = true + dports:value("", translate("all")) + dports:depends(proto="tcp") + dports:depends(proto="udp") +-- dports:depends({proto="tcp", direction="upload"}) +-- dports:depends({proto="udp", direction="upload"}) + +t = s:option(ListValue, "class", translate("Class")) + t:value("cs0", translate("CS0 - Normal/Best Effort")) + t:value("cs1", translate("CS1 - Low priority")) + t:value("cs2", translate("CS2 - High priority")) + t:value("cs3", translate("CS3 - SIP")) + t:value("cs4", translate("CS4 - Streaming video")) + t:value("cs5", translate("CS5")) + t:value("cs6", translate("CS6 - Network routing")) + t:value("cs7", translate("CS7")) + t:value("ef", translate("EF Voice")) + +comment = s:option(Value, "comment", translate("Comment")) + +return m diff --git a/luci-app-omr-dscp/root/etc/init.d/omr-dscp b/luci-app-omr-dscp/root/etc/init.d/omr-dscp new file mode 100755 index 000000000..d5ddfd836 --- /dev/null +++ b/luci-app-omr-dscp/root/etc/init.d/omr-dscp @@ -0,0 +1,164 @@ +#!/bin/sh /etc/rc.common +# vim: set noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 : + +# shellcheck disable=SC2034 +START=90 +# shellcheck disable=SC2034 +STOP=10 +# shellcheck disable=SC2034 +USE_PROCD=1 + +# shellcheck disable=SC1091 +. /lib/functions.sh + +# Get the lan interface name +lan_device= +config_load network +config_get lan_device lan ifname + +config_load dscp + +_ipt() { + iptables -w -t mangle "$@" +} + +_add_dscp_rule() { + _ipt -A dscp_prerouting -p "$proto" -s "$src_ip" -d "$dest_ip" "$@" -m comment --comment "$comment" -j DSCP --set-dscp-class "$class" + _ipt -A dscp_prerouting -p "$proto" -s "$src_ip" -d "$dest_ip" "$@" -m comment --comment "$comment" -j RETURN + _ipt -A dscp_postrouting -p "$proto" -s "$src_ip" -d "$dest_ip" "$@" -m comment --comment "$comment" -j DSCP --set-dscp-class "$class" + _ipt -A dscp_postrouting -p "$proto" -s "$src_ip" -d "$dest_ip" "$@" -m comment --comment "$comment" -j RETURN +} + +_add_dscp_domain() { + domain=""; config_get domain "$1" name "" + class=""; config_get class "$1" class "" + [ -n "$domain" ] && uci -q add_list dhcp.@dnsmasq[0].ipset="/$domain/omr-$class" +} + +_add_dscp_domains_rules() { + for $class in cs0 cs1 cs2 cs3 cs4 cs5 cs6 cs7 ef; do + _ipt -A dscp_prerouting -m set --match-set omr-$class src,dst -m comment --comment "$class" -j DSCP --set-dscp-class "$class" + _ipt -A dscp_prerouting -m set --match-set omr-$class src,dst -m comment --comment "$class" -j RETURN + _ipt -A dscp_postrouting -m set --match-set omr-$class src,dst -m comment --comment "$class" -j DSCP --set-dscp-class "$class" + _ipt -A dscp_postrouting -m set --match-set omr-$class src,dst -m comment --comment "$class" -j RETURN + done +} + +_add_dscp_rules() { + proto="" ; config_get proto "$1" proto all + src_ip="" ; config_get src_ip "$1" src_ip 0.0.0.0/0 + src_port="" ; config_get src_port "$1" src_port 0:65535 + dest_ip="" ; config_get dest_ip "$1" dest_ip 0.0.0.0/0 + dest_port="" ; config_get dest_port "$1" dest_port 0:65535 + class="" ; config_get class "$1" class + direction="" ; config_get direction "$1" direction "upload" + comment="" ; config_get comment "$1" comment "-" + + case "$direction" in + upload|both) + # Apply the rule locally + case "$proto" in + tcp|udp) + _add_dscp_rule -m multiport --sports "$src_port" -m multiport --dports "$dest_port" + ;; + *) + _add_dscp_rule + ;; + esac + ;; + download|both) + ;; + esac +} + +_add_prerouting_chain() { + _ipt -N "$1" + _ipt -I PREROUTING -i "$lan_device" -j "$1" +} + +_add_postrouting_chain() { + _ipt -N "$1" + _ipt -I POSTROUTING -i "$lan_device" -j "$1" +} + +_add_fwmark_chain() { + _ipt -N dscp_mark + _ipt -A PREROUTING -i "$lan_device" -j dscp_mark + _ipt -A POSTROUTING -i "$lan_device" -j dscp_mark + for class in cs4 cs5 cs6 cs7; do + # xtun (hex) -> 0x7874756e + _ipt -A dscp_mark \ + -m comment --comment "$class" \ + -m dscp --dscp-class "$class" \ + -j MARK --set-mark 0x7874756e + done +} + +_add_dscp_output_chain() { + _ipt -N dscp_output + _ipt -I OUTPUT -j dscp_output +} + +_remove_prerouting_chain() { + _ipt -F "$1" 2>/dev/null || return + _ipt -D PREROUTING -i "$lan_device" -j "$1" + _ipt -X "$1" +} + +_remove_postrouting_chain() { + _ipt -F "$1" 2>/dev/null || return + _ipt -D POSTROUTING -i "$lan_device" -j "$1" + _ipt -X "$1" +} + +_remove_output_chain() { + _ipt -F "$1" 2>/dev/null || return + _ipt -D OUTPUT -j "$1" + _ipt -X "$1" +} + +_setup_tunnel() { + # Mark the packets to route through xtun0 + _add_fwmark_chain + # tun0: cs0 (default) + # xtun0: cs6 + _ipt -A dscp_output -o "tun0" -j DSCP --set-dscp-class cs6 +} + +_cleanup() { + _remove_prerouting_chain dscp_prerouting + _remove_prerouting_chain dscp_mark + _remove_postouting_chain dscp_postrouting + _remove_postrouting_chain dscp_mark + _remove_output_chain dscp_output +} + +start_service() { + # Cleanup + _cleanup + + # Add chains + _add_prerouting_chain dscp_prerouting + _add_postrouting_chain dscp_postrouting + _add_dscp_output_chain + _add_dscp_domains_rules + + # Setup the tunnels dscp / marks + _setup_tunnel + + # Add rules base on the user configuration + config_foreach _add_dscp_rules classify + config_foreach _add_dscp_domain domains +} + +stop_service() { + _cleanup +} + +reload_service() { + start +} + +service_triggers() { + procd_add_reload_trigger dscp glorytun +} diff --git a/luci-app-omr-dscp/root/etc/uci-defaults/dscp b/luci-app-omr-dscp/root/etc/uci-defaults/dscp new file mode 100755 index 000000000..b0295c7f8 --- /dev/null +++ b/luci-app-omr-dscp/root/etc/uci-defaults/dscp @@ -0,0 +1,24 @@ +#!/bin/sh + +if [ "$(uci -q get dscp)" = "" ]; then + uci -q batch <<-EOF + add dscp classify + set dscp.@classify[0].direction='both' + set dscp.@classify[0].proto='icmp' + set dscp.@classify[0].class='cs5' + set dscp.@classify[0].comment='ICMP' + set dscp.@classify[1].direction='both' + set dscp.@classify[1].proto='udp' + set dscp.@classify[1].class='cs5' + set dscp.@classify[1].src_port='53,123,5353' + set dscp.@classify[1].comment='DNS udp and NTP' + set dscp.@classify[2].direction='both' + set dscp.@classify[2].proto='tcp' + set dscp.@classify[2].class='cs5' + set dscp.@classify[2].src_port='53,5353' + set dscp.@classify[2].comment='DNS tcp' + commit dscp + EOF +fi + +exit 0 \ No newline at end of file diff --git a/openmptcprouter-full/Makefile b/openmptcprouter-full/Makefile index 2503a395d..25aefe62e 100644 --- a/openmptcprouter-full/Makefile +++ b/openmptcprouter-full/Makefile @@ -33,7 +33,7 @@ MY_DEPENDS := \ libiwinfo-lua \ ca-bundle ca-certificates libustream-openssl \ luci-mod-admin-full luci-app-firewall luci-app-glorytun luci-app-shadowsocks-libev luci-app-unbound luci-theme-openmptcprouter luci-base \ - luci-app-nginx-ha luci-app-omr-tracker \ + luci-app-nginx-ha luci-app-omr-tracker luci-app-omr-dscp \ luci-app-sqm sqm-scripts-extra \ luci-app-vnstat omr-quota luci-app-omr-quota \ luci-app-mptcp luci-app-openmptcprouter luci-app-omr-bypass luci-app-mail luci-app-snmpd luci-app-upnp \