From c118da628da7a9e08eb43ac3357f6c15cba0af5e Mon Sep 17 00:00:00 2001 From: Suvendhu Hansa Date: Fri, 14 Feb 2025 17:31:15 +0530 Subject: [PATCH] icwmp: fix gateway info race condition --- icwmp/Makefile | 1 + .../uci-defaults/86-set-gateway-device-info | 292 ++++++++++++++++++ .../{netmode.l2mode => 06_netmode.l2mode} | 0 obuspa/Makefile | 2 +- ...-dhcp-option => 91-obuspa-set-dhcp-option} | 0 5 files changed, 294 insertions(+), 1 deletion(-) create mode 100644 icwmp/files/etc/uci-defaults/86-set-gateway-device-info rename netmode/files/etc/uci-defaults/{netmode.l2mode => 06_netmode.l2mode} (100%) rename obuspa/files/etc/uci-defaults/{obuspa-set-dhcp-option => 91-obuspa-set-dhcp-option} (100%) diff --git a/icwmp/Makefile b/icwmp/Makefile index fd655092d..1b838c2a4 100755 --- a/icwmp/Makefile +++ b/icwmp/Makefile @@ -70,6 +70,7 @@ define Package/icwmp/install $(INSTALL_DATA) ./files/etc/config/cwmp $(1)/etc/config/cwmp $(INSTALL_BIN) ./files/etc/init.d/icwmpd $(1)/etc/init.d/icwmpd $(INSTALL_BIN) ./files/etc/uci-defaults/85-cwmp-set-userid $(1)/etc/uci-defaults/ + $(INSTALL_BIN) ./files/etc/uci-defaults/86-set-gateway-device-info $(1)/etc/uci-defaults/ $(INSTALL_BIN) ./files/etc/uci-defaults/90-cwmpfirewall $(1)/etc/uci-defaults/ $(INSTALL_BIN) ./files/etc/uci-defaults/95-set-random-inform-time $(1)/etc/uci-defaults/ $(INSTALL_BIN) ./files/etc/icwmpd/vendor_log.sh $(1)/etc/icwmpd/vendor_log.sh diff --git a/icwmp/files/etc/uci-defaults/86-set-gateway-device-info b/icwmp/files/etc/uci-defaults/86-set-gateway-device-info new file mode 100644 index 000000000..8e99b57c4 --- /dev/null +++ b/icwmp/files/etc/uci-defaults/86-set-gateway-device-info @@ -0,0 +1,292 @@ +#!/bin/sh + +. /lib/functions.sh + +convert_to_hex() { + local val="" + local optval="${1}" + OPTIND=1 + while getopts ":" opt "-$optval" + do + temp=$(printf "%02X" "'${OPTARG:-:}") + val="${val}:${temp}" + done + + echo "${val}" +} + +configure_send_op125() { + local sendopt="${1}" + local intf="${2}" + local uci="${3}" + local hex_oui="" + local hex_serial="" + local hex_class="" + local oui_len=0 + local serial_len=0 + local class_len=0 + + if [ "${uci}" = "network" ]; then + local opt125="125:00:00:0D:E9" + else + if [ -z "${sendopt}" ]; then + local opt125="125,00:00:0D:E9" + else + local opt125=":00:00:0D:E9" + fi + fi + + config_get oui cpe manufacturer_oui "" + if [ -z "${oui}" ]; then + oui=$(db -q get device.deviceinfo.ManufacturerOUI) + fi + + oui=$(echo "${oui}" | tr 'a-f' 'A-F') + + config_get serial cpe serial_number "" + if [ -z "${serial}" ]; then + serial=$(db -q get device.deviceinfo.SerialNumber) + fi + + config_get class cpe product_class "" + if [ -z "${class}" ]; then + class=$(db -q get device.deviceinfo.ProductClass) + fi + + oui_len=$(echo -n "${oui}" | wc -m) + serial_len=$(echo -n "${serial}" | wc -m) + class_len=$(echo -n "${class}" | wc -m) + + if [ "${oui_len}" -eq 0 ] || [ "${serial_len}" -eq 0 ]; then + return 0 + fi + + opt125_len=$((oui_len + serial_len + class_len)) + if [ "${class_len}" -gt 0 ]; then + opt125_len=$((opt125_len + 6)) + else + opt125_len=$((opt125_len + 4)) + fi + + hex_opt125_len=$(printf "%02X" "${opt125_len}") + opt125="${opt125}:${hex_opt125_len}" + hex_oui=$(convert_to_hex "${oui}") + if [ -z "${hex_oui}" ]; then + return 0 + fi + + hex_oui_len=$(printf "%02X" "${oui_len}") + if [ "${uci}" = "network" ]; then + opt125="${opt125}:01:${hex_oui_len}${hex_oui}" + else + opt125="${opt125}:04:${hex_oui_len}${hex_oui}" + fi + + hex_serial=$(convert_to_hex "${serial}") + if [ -z "${hex_serial}" ]; then + return 0 + fi + + hex_serial_len=$(printf "%02X" "${serial_len}") + if [ "${uci}" = "network" ]; then + opt125="${opt125}:02:${hex_serial_len}${hex_serial}" + else + opt125="${opt125}:05:${hex_serial_len}${hex_serial}" + fi + + if [ "${class_len}" -gt 0 ]; then + hex_class=$(convert_to_hex "${class}") + if [ -z "${hex_class}" ]; then + return 0 + fi + + hex_class_len=$(printf "%02X" "${class_len}") + if [ "${uci}" = "network" ]; then + opt125="${opt125}:03:${hex_class_len}${hex_class}" + else + opt125="${opt125}:06:${hex_class_len}${hex_class}" + fi + fi + + + if [ "${uci}" = "network" ]; then + new_send_opt="$sendopt $opt125" + uci -q set network."${intf}".sendopts="$new_send_opt" + else + new_send_opt="$sendopt$opt125" + uci -q add_list dhcp."${intf}".dhcp_option="$new_send_opt" + fi +} + +check_for_suboptions() { + # Check if option 4 and 5 present inside enterprise id 3561 + data=$(echo "${1}" | sed 's/://g') + len=$(printf "${data}"|wc -c) + + rem_len="${len}" + while [ $rem_len -gt 8 ]; do + subopt_present=0 + + ent_id="${data:0:8}" + ent_id=$(printf "%d\n" "0x$ent_id") + if [ $ent_id -ne 3561 ]; then + len_val=${data:8:2} + data_len=$(printf "%d\n" "0x$len_val") + # add 4 byte for ent_id and 1 byte for len + data_len=$(( data_len * 2 + 10 )) + # move ahead data to next enterprise id + data=${data:"${data_len}":"${rem_len}"} + rem_len=$(( rem_len - data_len )) + continue + fi + + # read the length of enterprise data + len_val=${data:8:2} + data_len=$(printf "%d\n" "0x$len_val") + # add 4 byte for ent_id and 1 byte for len + data_len=$(( data_len * 2 + 10 )) + + len_val=${data:8:2} + opt_len=$(printf "%d\n" "0x$len_val") + if [ $opt_len -eq 0 ]; then + echo ${subopt_present} + return 0 + fi + + # populate the option data of enterprise id + sub_data_len=$(( opt_len * 2)) + # starting 10 means ahead of length field + sub_data=${data:10:"${sub_data_len}"} + + # parsing of suboption of option 125 + while [ $sub_data_len -gt 0 ]; do + # get the suboption id + sub_opt_id=${sub_data:0:2} + sub_opt_id=$(printf "%d\n" "0x$sub_opt_id") + case "${sub_opt_id}" in + "4") subopt_present=1 + ;; + "5") subopt_present=1 + ;; + esac + + if [ ${subopt_present} -eq 1 ]; then + break; + fi + + # get the length of suboption + sub_opt_len=${sub_data:2:2} + sub_opt_len=$(printf "%d\n" "0x$sub_opt_len") + sub_opt_len=$(( sub_opt_len * 2 )) + + # add 2 bytes for sub_opt id and sub_opt len field + sub_opt_end=$(( sub_opt_len + 4 )) + + # update the remaining sub option hex string length + sub_data_len=$((sub_data_len - sub_opt_end)) + + # fetch next sub option hex string + sub_data=${sub_data:${sub_opt_end}:${sub_data_len}} + done + + if [ ${subopt_present} -eq 1 ]; then + break; + else + # move ahead data to next enterprise id + rem_len=$(( rem_len - $data_len )) + data=${data:"${data_len}":"${rem_len}"} + fi + done + + echo ${subopt_present} +} + +enable_dhcp_option125() { + local wan="${1}" + local reqopts="$(uci -q get network."${wan}".reqopts)" + local sendopts="$(uci -q get network."${wan}".sendopts)" + local proto="$(uci -q get network."${wan}".proto)" + local newreqopts="" + local newsendopts="" + local req125_present=0 + local send125_present=0 + local network_uci_update=0 + local opt125="125:" + + for ropt in $reqopts; do + case $ropt in + 125) req125_present=1 ;; + *) ;; + esac + done + + for sopt in $sendopts; do + if [[ "$sopt" == "$opt125"* ]]; then + send125_present=1 + break + fi + done + + if [ "${proto}" = "dhcp" ]; then + if [ ${req125_present} -eq 0 ]; then + newreqopts="$reqopts 125" + uci -q set network."${wan}".reqopts="$newreqopts" + network_uci_update=1 + fi + + if [ ${send125_present} -eq 0 ]; then + configure_send_op125 "${sendopts}" "${wan}" "network" + network_uci_update=1 + fi + fi + + if [ ${network_uci_update} -eq 1 ]; then + uci commit network + ubus call network reload + fi +} + +enable_dnsmasq_option125() { + local lan="${1}" + local send125_present=0 + local opt125="125," + + local proto="$(uci -q get dhcp."${lan}".dhcpv4)" + if [ "${proto}" = "server" ]; then + opt_list="$(uci -q get dhcp."${lan}".dhcp_option)" + base_opt="" + + for sopt in $opt_list; do + if [[ "$sopt" == "$opt125"* ]]; then + send125_present=$(check_for_suboptions "${sopt:4}") + base_opt="${sopt}" + break + fi + done + + if [ ${send125_present} -eq 0 ]; then + uci -q del_list dhcp."${lan}".dhcp_option="${base_opt}" + configure_send_op125 "${base_opt}" "${lan}" "dhcp" + ubus call uci commit '{"config":"dhcp"}' + fi + fi +} + +configure_gateway_device_info() { + local dhcp_discovery wan_interface skip_dhcp_boot_options disable_gatewayinfo + + config_load cwmp + config_get wan_interface cpe default_wan_interface "wan" + config_get lan_interface cpe default_lan_interface "" + config_get disable_gatewayinfo cpe disable_gatewayinfo "0" + + if [ -n "${lan_interface}" ]; then + if [ "${disable_gatewayinfo}" -ne 1 ]; then + # Set dhcp_option 125 if not already configured + enable_dhcp_option125 "${wan_interface}" + enable_dnsmasq_option125 "${lan_interface}" + fi + fi +} + +configure_gateway_device_info diff --git a/netmode/files/etc/uci-defaults/netmode.l2mode b/netmode/files/etc/uci-defaults/06_netmode.l2mode similarity index 100% rename from netmode/files/etc/uci-defaults/netmode.l2mode rename to netmode/files/etc/uci-defaults/06_netmode.l2mode diff --git a/obuspa/Makefile b/obuspa/Makefile index 8ba388135..a834f9a88 100644 --- a/obuspa/Makefile +++ b/obuspa/Makefile @@ -130,7 +130,7 @@ define Package/obuspa/install echo "$(VENDOR_PREFIX)" > $(1)/etc/obuspa/vendor_prefix $(INSTALL_BIN) ./files/etc/uci-defaults/01-fix-upgrade-uci $(1)/etc/uci-defaults/ $(INSTALL_BIN) ./files/etc/uci-defaults/60-generate-ctrust-defaults $(1)/etc/uci-defaults/ - $(INSTALL_BIN) ./files/etc/uci-defaults/obuspa-set-dhcp-option $(1)/etc/uci-defaults/ + $(INSTALL_BIN) ./files/etc/uci-defaults/91-obuspa-set-dhcp-option $(1)/etc/uci-defaults/ $(INSTALL_BIN) ./files/etc/uci-defaults/92-obuspa_firewall $(1)/etc/uci-defaults/ $(INSTALL_BIN) ./files/etc/firewall.usp $(1)/etc/ $(INSTALL_BIN) ./files/etc/udhcpc.user.d/udhcpc_obuspa_opt125.user $(1)/etc/udhcpc.user.d/udhcpc_obuspa_opt125.user diff --git a/obuspa/files/etc/uci-defaults/obuspa-set-dhcp-option b/obuspa/files/etc/uci-defaults/91-obuspa-set-dhcp-option similarity index 100% rename from obuspa/files/etc/uci-defaults/obuspa-set-dhcp-option rename to obuspa/files/etc/uci-defaults/91-obuspa-set-dhcp-option