#!/bin/sh
# DHCP阻断（安全关键）：OpenWrt容器【绝不】提供DHCP服务。
# 一旦容器桥接到iKuai局域网，若它抢答DHCP，会造成流量劫持/回环，后果严重。
#
# 采用【双保险】，且以【防火墙阻断】为主防线——配置层只能挡住dnsmasq，
# 挡不住插件自带/绿色安装的DHCP服务端；内核层丢弃才是可靠保证：
#   1)防火墙层（主）：在容器自身netns内丢弃DHCP服务端报文——
#      收请求INPUT udp dport 67/547；发应答OUTPUT udp sport 67/547。
#      （DHCPv4 client 68→server 67；DHCPv6 client 546→server 547。
#       入向只丢dport 67/547，不影响容器作为客户端收68/546的应答。）
#      仅作用于容器网段，绝不碰宿主。需uclibc iptables兼容层（attach/桥接模式启用，
#      恰是会发生抢答的场景）；纯管理模式无兼容层、容器不被桥接，无风险。
#   2)配置层（辅）：关闭dnsmasq的DHCP、停用odhcpd。
# 本脚本尽力而为，任何一步失败都不影响容器启动，自身始终退出0。

# --- 1)防火墙层：丢弃DHCP服务端报文（收请求 + 发应答）---
drop_dhcp() {
    IPT="$1"
    command -v "$IPT" >/dev/null 2>&1 || return 0
    # 不收DHCP服务端请求
    "$IPT" -C INPUT  -p udp --dport 67  -j DROP >/dev/null 2>&1 || "$IPT" -I INPUT  1 -p udp --dport 67  -j DROP >/dev/null 2>&1
    "$IPT" -C INPUT  -p udp --dport 547 -j DROP >/dev/null 2>&1 || "$IPT" -I INPUT  1 -p udp --dport 547 -j DROP >/dev/null 2>&1
    # 不发DHCP服务端应答
    "$IPT" -C OUTPUT -p udp --sport 67  -j DROP >/dev/null 2>&1 || "$IPT" -I OUTPUT 1 -p udp --sport 67  -j DROP >/dev/null 2>&1
    "$IPT" -C OUTPUT -p udp --sport 547 -j DROP >/dev/null 2>&1 || "$IPT" -I OUTPUT 1 -p udp --sport 547 -j DROP >/dev/null 2>&1
}
drop_dhcp iptables
drop_dhcp ip6tables

# --- 2)配置层：dnsmasq不提供DHCP，停用odhcpd ---
if command -v uci >/dev/null 2>&1; then
    for s in $(uci -q show dhcp 2>/dev/null | sed -n 's/^dhcp\.\([^.=]*\)\.\?[^=]*=.*/\1/p' | sort -u); do
        case "$s" in
            @dnsmasq*|dnsmasq) : ;;
            *) uci -q set "dhcp.$s.ignore=1" 2>/dev/null ;;
        esac
    done
    uci -q set dhcp.@dnsmasq[0].dhcpv4=disabled 2>/dev/null
    # dns_redirect（DNS劫持）会执行 `nft add table inet dnsmasq`，而宿主内核没有
    # nf_tables —— 每次开机都会刷一串 "Could not process rule: Operation not
    # permitted" 日志，而且功能注定不生效。容器不提供DHCP/DNS劫持，恒关闭。
    # 写在这里而不是只写在镜像里：/etc/config/dhcp是conffile，用户/旧镜像的
    # upper层可能带着1，运行时兜底才可靠。
    uci -q set dhcp.@dnsmasq[0].dns_redirect=0 2>/dev/null
    uci -q set dhcp.odhcpd=odhcpd 2>/dev/null
    uci -q set dhcp.odhcpd.maindhcp=0 2>/dev/null
    uci -q commit dhcp 2>/dev/null
fi
# --- 5)系统自带的ttyd服务让位，容器终端由ikuai-compat-terminal独占 ---
# 容器终端监听管理口mgmt的专用端口17681（让开上游ttyd的7681，用户想装
# 自己的ttyd就用7681）。若上游ttyd服务也被启用，它会去抢端口、和我们的实例
# 互相顶掉。用户opkg安装/升级ttyd后postinst可能重新启用它，所以每次开机
# 都收敛一次（disable会删掉 /etc/rc.d/S??ttyd，stop处理已在跑的老进程）。
if [ -x /etc/init.d/ttyd ]; then
    /etc/init.d/ttyd stop >/dev/null 2>&1
    /etc/init.d/ttyd disable >/dev/null 2>&1
fi

# --- 6) LuCI 语言：一次性迁移到 auto（跟随浏览器），之后尊重用户的选择 ---
# 语言策略：只维护【简体中文 + English】两套语言包（英文是 LuCI 的源字符串，无需语言包）。
# luci.main.lang 出厂设为 auto → 浏览器是中文就自动简体中文，是英文就英文。
#
# /etc/config/luci 是 conffile：老容器把它写进了 upper（数据盘），改打包镜像不生效，
# 所以这里做迁移。但**只迁一次**（用标记文件），否则会把用户在 LuCI 里锁定的语言
# 反复改回 auto——用户明确要求「我在那边锁了简体中文，那个 uci 配置应该能保存」。
LANG_MARK=/etc/ikuai-compat-lang-migrated
if [ ! -f "$LANG_MARK" ] && command -v uci >/dev/null 2>&1; then
    # 仅当值仍是旧镜像的硬编码默认 zh_cn 时才改；用户已选过别的语言就不动。
    if [ "$(uci -q get luci.main.lang 2>/dev/null)" = "zh_cn" ]; then
        uci -q set luci.main.lang='auto' && uci -q commit luci
    fi
    # 清掉历史遗留的繁体中文字段（0.2.92 短暂提供过，现已不维护该语言包）
    uci -q delete luci.languages.zh_tw 2>/dev/null && uci -q commit luci
    : > "$LANG_MARK"
fi

# --- 7) opkg 列表目录改到持久位置 ---
# 默认 lists_dir 指向 /var/opkg-lists，而容器里 /var 是指向 /tmp 的符号链接（tmpfs）。
# 结果：软件源列表一重启容器就没了 → 【软件包管理】的「说明」列又变空、搜索还报
# 「软件源索引为空」，用户不得不反复点【更新软件源】。改到 /etc/opkg-lists
# （/etc 在 overlay 的 upper 上，落在数据盘，持久）。/etc/opkg.conf 是 conffile，
# 老容器会把它写进 upper，所以每次启动收敛一次。
if [ -f /etc/opkg.conf ]; then
    if ! grep -q '^lists_dir ext /etc/opkg-lists$' /etc/opkg.conf 2>/dev/null; then
        sed -i 's#^lists_dir .*#lists_dir ext /etc/opkg-lists#' /etc/opkg.conf 2>/dev/null || true
    fi
fi
mkdir -p /etc/opkg-lists 2>/dev/null || true
# 迁移：本次开机已下载到 /var/opkg-lists 的列表直接搬过去，省一次重复下载。
if [ -d /var/opkg-lists ]; then
    for f in /var/opkg-lists/*; do
        [ -e "$f" ] || continue
        b=$(basename "$f")
        [ -e "/etc/opkg-lists/$b" ] || mv "$f" "/etc/opkg-lists/$b" 2>/dev/null
    done
fi

# --- 8) 清理历史辅助目录（已扁平化为 /usr/ikuai/compat*）---
# 辅助目录的演进：/helpers → /usr/ikuai/helper → /usr/ikuai/compat{,-helper}。
# 老容器的 upper 层（数据盘）会留下旧目录空壳——挂载已不指向它们，留着只会让人误以为
# 还有挂载点。只在该目录内容全部是我们认得的名字时才删，避免误删别人的目录。
for _old in /helpers /usr/ikuai/helper; do
    [ -d "$_old" ] || continue
    unknown=$(ls -A "$_old" 2>/dev/null | grep -vxE 'ikuai-compat|ikuai-compat-helper|\.keep|\.sc|x' || true)
    [ -z "$unknown" ] && rm -rf "$_old" 2>/dev/null || true
done

[ -x /etc/init.d/odhcpd ] && /etc/init.d/odhcpd stop >/dev/null 2>&1
[ -x /etc/init.d/dnsmasq ] && /etc/init.d/dnsmasq reload >/dev/null 2>&1
exit 0
