ddwrt 笔记
本笔记里内容基于如下环境:
路由器: Asus RT-N16 (mipsel 32位架构)
网络
获取 wan 网关 ip
nvram get wan_gateway
获取 wan interface ip
nvram get wan_ipaddr
这几个 IP 是 ddwrt 在 ppp 拨号连接 /断开 时维护设置的, 不受 VPN 连接 /路由表更改等操作影响.
指定一个直连 (不走 VPN)的策略路由表 table 1
ip route add 0/0 via $(nvram get wan_gateway) table 1
对路由器本机向外发出的 ping (icmp) 打标记. 注意在 OUTPUT 阶段无法使用 -o (路由还没确定), 必须根据数据包dst地址是外部来判断
iptables -t mangle -A OUTPUT ! -d 192.168.0.0/16 -p icmp -j MARK --set-mark 0xa
对含有 0xa (10) 标记数据包 走 table 1 路由
ip rule add prio 1 fwmark 0xa table 1
关于标记 mark: mark比较特殊,它不是包本身 的一部分,而是在包穿越计算机的过程中由内核分配的和它相关联的一个字段。它可能被用来改变包的传输 路径或过滤。 mark 字段的值是一个无符号的整数, 在32位系统上最大可以是4294967296(就是2的32次方)(默认mark是0, 表示没有)
mark 值格式可以是10进制数字或 0xFF 这种格式的二进制. 推荐16进制, 因为 ip rule list / iptables -t mangle -vxnL 显示时候均输出16进制
ping 命令可以用 -m mark 设置icmp包标记值 (不是所有 build 都支持)
用户
增加一个用户, 需要修改启动脚本, 开机时写入
/etc/passwd (实际上映射了 /tmp/etc/passwd )
grep -q direct /tmp/etc/passwd || echo "direct:*:1024:1024:direct connecting users:/var:/bin/false" >> /tmp/etc/passwd
iptables 对属于这个用户进程的外出流量打标记 (需要先自己编译安装 iptables 和 owner extension 扩展)
iptables -t mangle -A OUTPUT -m owner --uid-owner 1024 -j MARK --set-mark 0xa
-----------------------------------------------------------------------------------------------------------
This module attempts to match various characteristics of the packet creator, for locally generated packets. This match is only valid in the OUTPUT and POSTROUTING chains. Forwarded packets do not have any socket associated with them. Packets from kernel threads do have a socket, but usually no owner.
[!] --uid-owner username
[!] --uid-owner userid[-userid]
Matches if the packet socket's file structure (if it has one) is owned by the given user. You may also specify a numerical UID, or an UID range.
[!] --gid-owner groupname
[!] --gid-owner groupid[-groupid]
Matches if the packet socket's file structure is owned by the given group. You may also specify a numerical GID, or a GID range.
[!] --socket-exists
Matches if the packet is associated with a socket.
-----------------------------------------------------------------------------------------------------------
--uid-owner 无法应用于 ping 之类的 RAW_SOCKET 发出的数据包 ?
貌似我现在 (2014.10)的 ddwrt 固件 (svn24461, 3.10.44 kernel) 存在 bug, iptables owner match module (kernel xt_owner) 工作不正常, 从测试上看, iptables -m owner 的 --uid-owner 总是返回 False, 即使是对应用户所属进程发出的数据包.
ipkg repository setup
/etc/ipkg.conf 不可编辑 (根分区只读), 所以要修改 ipkg repository 设置只能用 mount 形式
创建 /jffs/etc/ipkg.conf, 使用 OpenWrt 的 repository 源, 建议使用对应内核的 OpenWrt build 的源, 3.10.44 内核的 OpenWrt 版本是
barrier_breaker 14.07-rc1, 或者使用最新版的 OpenWrt snapshot repository (但里面部分 kmod-* 内核模块 package 无法安装)
src base http://downloads.openwrt.org/snapshots/trunk/brcm47xx/packages/base
src main http://downloads.openwrt.org/snapshots/trunk/brcm47xx/packages/packages
#src attitude http://downloads.openwrt.org/attitude_adjustment/12.09/brcm47xx/generic/packages
dest root /jffs
dest mmc /mmc
dest opt /opt
dest smbfs /tmp/mnt/smbshare
dest ram /tmp
startup 脚本里增加:
mount --bind /jffs/etc/ipkg.conf /etc/ipkg.conf
OpenWrt 的源里很多软件 ddwrt 安装都会报兼容性问题, 但实际上可以正常运行. 建议关闭 ipkg 的 dependency 错误报告, 在 profile 脚本里增加:
alias ipkg="ipkg -force-depends"
Dnsmqsq
ddwrt 里面自带的 dnsmasq 不知道是什么破版本的, 有旧又烂, 什么高级特性都不支持. 建议换掉.
安装 OpenWrt 里的 dnsmasq-full: (推荐安装到默认位置 /jffs, /opt usb 设备可能启动时并未立即挂载完全 )
ipkg -force-depends install dnsmasq-full
在 ddwrt startup 脚本里设置用安装的 dnsmasq-full 里的 dnsmasq 代替系统内置的 dnsmasq: (我不确定改 PATH 优先级有没有作用, 因为 ddwrt一些系统服务的 PATH 貌似是固定的, 所以还是 mount 可靠)
mount --bind /jffs/usr/sbin/dnsmasq /usr/sbin/dnsmasq
ipset
需要内核模块支持:
* kmod-nfnetlink
** kmod-ipt-ipset
ip_set.ko
ip_set_bitmap_ip.ko
ip_set_bitmap_ipmac.ko
ip_set_bitmap_port.ko
ip_set_hash_ip.ko
ip_set_hash_ipport.ko
ip_set_hash_ipportip.ko
ip_set_hash_ipportnet.ko
ip_set_hash_net.ko
ip_set_hash_netiface.ko
ip_set_hash_netport.ko
ip_set_list_set.ko
**
* xt_set.ko (alias: ipt_set, iptables set 模块)
测试内核模块是否支持:
ipset list
// 如果nfnetlink模块未加载 (并且没有编译在内核里), 会提示 "can't connect to kernel." 错误.
测试内核是否支持 xt_set.ko: 执行一条 iptables -m set 命令:
ipset create direct hash:ip
iptables -t mangle -A OUTPUT -m set --match-set direct dst -j MARK --set-mark 0xa
// 如果 xt_set.ko 未加载, iptables 会报错 (iptables: No chain/target/match by that name.)
// 如果 iptables 没有 -m set 动态库, 会提示 match not found 之类错误
cat /proc/net/ip_tables_matches
// see there is a "set"
这个版本 ddwrt 版本内核里已经编译进去了 nfnetlink, 但不包括 xt_set.ko (并且固件自带的内核模块目录里也没有), 所以需要自己编译 xt_set.ko 内核模块. 然后在路由器上加载:
insmod /path/to/xt_set.ko
安装 ipset 用户空间工具: ipkg install ipset
使用:
---------------------------
Usage: ipset [options] COMMAND
Commands:
create SETNAME TYPENAME [type-specific-options] ( create == -N)
Create a new set
add SETNAME ENTRY
Add entry to the named set
del SETNAME ENTRY
Delete entry from the named set
test SETNAME ENTRY
Test entry in the named set
destroy [SETNAME]
Destroy a named set or all sets
list [SETNAME] (list == -L)
List the entries of a named set or all sets
save [SETNAME]
Save the named set or all sets to stdout
restore
Restore a saved state
flush [SETNAME]
Flush a named set or all sets
rename FROM-SETNAME TO-SETNAME
Rename two sets
swap FROM-SETNAME TO-SETNAME
Swap the contect of two existing sets
-------------------------
* bitmap:ip: can store up to 65535 (B-class network) entries. You can store same size network addresses in this kind of sets as well and an IP address will be in the set if the network address it belongs to can be found in the set.
* hash:ip (iphash): 可以存储任意个 ip 地址. Same size network addresses can be stored in an hash:ip type of set as well.
* hash:net: 存储任意个不同子网长度的网络
创建一个 "direct" ipset:
ipset create direct hash:ip
操作 ipset 里面记录:
ipset add direct 8.8.8.8/32
使用 iptables 的 set match 匹配 ipset 里地址:
iptables -t mangle -A PREROUTING -m set --match-set direct dst -j MARK --set-mark 0xa
iptables -t mangle -A OUTPUT -m set --match-set direct dst -j MARK --set-mark 0xa
对 0xa 标记 设置查询路由表:
ip rule add fwmark 0xa table 1
设置 dnsmasq 将查询到的域名 ip 加入 ipset: (域名同时匹配子域名, 与 address=// 和 server=// 行为相同)
ipset=//[domain/][,]