2 | -- Licensed to the public under the GNU General Public License v3.
3 |
4 | local m, s, o
5 | local shadowsocksr = "shadowsocksr"
6 |
7 | m = Map(shadowsocksr, "%s - %s" %{translate("ShadowSocksR"), translate("Servers Manage")})
8 |
9 | -- [[ Servers Manage ]]--
10 | s = m:section(TypedSection, "servers")
11 | s.anonymous = true
12 | s.addremove = true
13 | s.sortable = true
14 | s.template = "cbi/tblsection"
15 | s.extedit = luci.dispatcher.build_url("admin/services/shadowsocksr/servers/%s")
16 | function s.create(...)
17 | local sid = TypedSection.create(...)
18 | if sid then
19 | luci.http.redirect(s.extedit % sid)
20 | return
21 | end
22 | end
23 |
24 | o = s:option(DummyValue, "alias", translate("Alias"))
25 | function o.cfgvalue(...)
26 | return Value.cfgvalue(...) or translate("None")
27 | end
28 |
29 | o = s:option(DummyValue, "server", translate("Server Address"))
30 | function o.cfgvalue(...)
31 | return Value.cfgvalue(...) or "?"
32 | end
33 |
34 | o = s:option(DummyValue, "server_port", translate("Server Port"))
35 | function o.cfgvalue(...)
36 | return Value.cfgvalue(...) or "?"
37 | end
38 |
39 | o = s:option(DummyValue, "encrypt_method", translate("Encrypt Method"))
40 | function o.cfgvalue(...)
41 | local v = Value.cfgvalue(...)
42 | return v and v:upper() or "?"
43 | end
44 |
45 | o = s:option(DummyValue, "plugin_protocol", translate("PROTOCOL"))
46 | function o.cfgvalue(...)
47 | local v = Value.cfgvalue(...)
48 | return v and v:upper() or "?"
49 | end
50 |
51 | o = s:option(DummyValue, "plugin_obfs", translate("OBFS"))
52 | function o.cfgvalue(...)
53 | local v = Value.cfgvalue(...)
54 | return v and v:upper() or "?"
55 | end
56 |
57 | return m
58 |
--------------------------------------------------------------------------------
/files/luci/view/shadowsocksr/gfwlist.htm:
--------------------------------------------------------------------------------
1 | <%+header%>
2 |
3 |
4 |
5 | <%+footer%>
6 |
--------------------------------------------------------------------------------
/files/root/etc/config/shadowsocksr:
--------------------------------------------------------------------------------
1 |
2 | config general
3 | option start_delay '0'
4 |
5 | config transparent_proxy
6 | option main_server 'nil'
7 | option udp_relay_server 'nil'
8 | option local_port '1234'
9 |
10 | config socks5_proxy
11 | option server 'nil'
12 | option local_port '1080'
13 |
14 | config port_forward
15 | option server 'nil'
16 | option local_port '5300'
17 | option destination '8.8.4.4:53'
18 |
19 | config servers
20 | option fast_open '0'
21 | option server '127.0.0.1'
22 | option server_port '8388'
23 | option timeout '60'
24 | option password 'barfoo!'
25 | option encrypt_method 'rc4-md5'
26 | option plugin_protocol 'origin'
27 | option plugin_obfs 'plain'
28 |
29 | config access_control
30 | option self_proxy '1'
31 |
--------------------------------------------------------------------------------
/files/root/etc/init.d/shadowsocksr:
--------------------------------------------------------------------------------
1 | #!/bin/sh /etc/rc.common
2 | #
3 | # Copyright (C) 2016 Jian Chang
4 | #
5 | # This is free software, licensed under the GNU General Public License v3.
6 | # See /LICENSE for more information.
7 | #
8 |
9 | START=90
10 | STOP=15
11 |
12 | NAME=shadowsocksr
13 | EXTRA_COMMANDS="rules watchdog"
14 | CONFIG_FILE=/var/etc/$NAME.json
15 | CRON_FILE=/etc/crontabs/root
16 |
17 | uci_get_by_name() {
18 | local ret=$(uci get $NAME.$1.$2 2>/dev/null)
19 | echo ${ret:=$3}
20 | }
21 |
22 | uci_get_by_type() {
23 | local ret=$(uci get $NAME.@$1[0].$2 2>/dev/null)
24 | echo ${ret:=$3}
25 | }
26 |
27 | uci_bool_by_name() {
28 | case "$(uci_get_by_name $1 $2)" in
29 | 1|on|true|yes|enabled) return 0;;
30 | esac
31 | return 1
32 | }
33 |
34 | valid_server() {
35 | [ "$(uci get $NAME.$1 2>/dev/null)" = "servers" ]
36 | }
37 |
38 | get_arg_udp() {
39 | local server=$(uci_get_by_type transparent_proxy udp_relay_server)
40 | [ "$server" = "same" ] || valid_server $server && echo "-u"
41 | }
42 |
43 | get_arg_out() {
44 | case "$(uci_get_by_type access_control self_proxy 1)" in
45 | 1) echo "-o";;
46 | 2) echo "-O";;
47 | esac
48 | }
49 |
50 | get_arg_ota() {
51 | uci_bool_by_name $1 auth && echo "-A"
52 | }
53 |
54 | get_arg_tfo() {
55 | if [ "3" = "$(cat /proc/sys/net/ipv4/tcp_fastopen 2>/dev/null)" ]; then
56 | uci_bool_by_name $1 fast_open && echo "--fast-open"
57 | fi
58 | }
59 |
60 | get_arg_obfs() {
61 | local obfs=$(uci_get_by_name $1 obfs)
62 | [ -n "$obfs" ] && echo "--obfs $obfs"
63 | }
64 |
65 | get_arg_obfs_host() {
66 | [ -n "$(uci_get_by_name $1 obfs)" ] && \
67 | echo "--obfs-host $(uci_get_by_name $1 obfs_host cloudfront.net)"
68 | }
69 |
70 | get_server_ips() {
71 | echo $(uci_get_by_name $1 server)
72 | }
73 |
74 | get_lan_hosts() {
75 | uci_bool_by_name $1 enable && \
76 | echo "$(uci_get_by_name $1 type),$(uci_get_by_name $1 host)"
77 | }
78 |
79 | gen_config_file() {
80 | cat <<-EOF >$CONFIG_FILE
81 | {
82 | "server": "$(uci_get_by_name $1 server)",
83 | "server_port": $(uci_get_by_name $1 server_port),
84 | "local_address": "0.0.0.0",
85 | "password": "$(uci_get_by_name $1 password)",
86 | "timeout": $(uci_get_by_name $1 timeout 60),
87 | "method": "$(uci_get_by_name $1 encrypt_method)",
88 | "protocol": "$(uci_get_by_name $1 plugin_protocol)",
89 | "protocol_param": "$(uci_get_by_name $1 plugin_protocol_param)",
90 | "obfs": "$(uci_get_by_name $1 plugin_obfs)",
91 | "obfs_param": "$(uci_get_by_name $1 plugin_obfs_param)"
92 | }
93 | EOF
94 | }
95 |
96 | start_rules() {
97 | config_load $NAME
98 | /usr/bin/ssr-rules \
99 | -s "$(config_foreach get_server_ips servers)" \
100 | -l "$(uci_get_by_type transparent_proxy local_port 1234)" \
101 | -i "$(uci_get_by_type access_control wan_bp_list)" \
102 | -b "$(uci_get_by_type access_control wan_bp_ips)" \
103 | -w "$(uci_get_by_type access_control wan_fw_ips)" \
104 | -I "$(uci_get_by_type access_control lan_ifaces)" \
105 | -d "$(uci_get_by_type access_control lan_target)" \
106 | -a "$(config_foreach get_lan_hosts lan_hosts)" \
107 | -e "$(uci_get_by_type access_control ipt_ext)" \
108 | $(get_arg_out) $(get_arg_udp)
109 | }
110 |
111 | fw_reinit() {
112 | if [ "Z$?" = "Z0" -a "Z$(uci_get_by_type access_control wan_bp_list)" = "Z/dev/flag_gfwlist" ]; then
113 | [ $(ipset list gfwlist | wc -l) -lt 1 ] && /etc/init.d/dnsmasq-extra restart
114 | idx=$(($(iptables -t nat -L SSR_SPEC_WAN_AC | grep all | sed -n -e '/ssr_spec_dst_bp/=') +1))
115 | iptables -t nat -I SSR_SPEC_WAN_AC $idx -m set ! --match-set gfwlist dst -j RETURN 2>/dev/null \
116 | || echo "# Transparent Proxy: TCP NOT ENABLED"
117 | iptables -t mangle -I SSR_SPEC_WAN_AC $idx -m set ! --match-set gfwlist dst -j RETURN 2>/dev/null \
118 | || echo "# Transparent Proxy: UDP NOT ENABLED"
119 | fi
120 |
121 | uci -q show firewall | sed -n 's/.*path=//p' | sed -n '/adbyby\|koolproxy\|dnsmasq/p' | tr -d \' | while read init; do
122 | sh $init restart >/dev/null 2>&1
123 | done
124 | }
125 |
126 | rules() {
127 | if !(pidof ssr-redir >/dev/null); then
128 | logger -st $NAME -p3 "ssr-redir not running."
129 | return 1
130 | fi
131 | start_rules && fw_reinit || /usr/bin/ssr-rules -f
132 | }
133 |
134 | start_redir() {
135 | gen_config_file $1
136 | ssr-redir -c $CONFIG_FILE $2 \
137 | -l $(uci_get_by_type transparent_proxy local_port 1234) \
138 | -f /var/run/ssr-redir$3.pid
139 | }
140 |
141 | ssr_redir() {
142 | command -v ssr-redir >/dev/null 2>&1 || return 1
143 | local main_server=$(uci_get_by_type transparent_proxy main_server)
144 | valid_server $main_server || return 1
145 | local udp_relay_server=$(uci_get_by_type transparent_proxy udp_relay_server)
146 | [ "$udp_relay_server" = "same" ] && udp_relay_server=$main_server
147 |
148 | uci_get_by_name $main_server server | sed "s/^/server=\//;s/$/\/114.114.115.115/" > /var/dnsmasq.d/ssr.conf
149 | uci_get_by_name $main_server server | sed "s/^/server=\//;s/$/\/208.67.222.222#443/" >> /var/dnsmasq.d/ssr.conf
150 | uci_get_by_name $udp_relay_server server | sed "s/^/server=\//;s/$/\/114.114.115.115/" >> /var/dnsmasq.d/ssr.conf
151 | uci_get_by_name $udp_relay_server server | sed "s/^/server=\//;s/$/\/208.67.222.222#443/" >> /var/dnsmasq.d/ssr.conf
152 | ( sort -u /var/dnsmasq.d/ssr.conf | sed '/\/\//d' > /var/dnsmasq.d/ssr-servers.conf ) && rm -f /var/dnsmasq.d/ssr.conf
153 | /etc/init.d/dnsmasq restart
154 |
155 | if [ "$udp_relay_server" = "$main_server" ]; then
156 | start_redir $main_server -u
157 | elif valid_server $udp_relay_server; then
158 | start_redir $main_server
159 | start_redir $udp_relay_server -U -udp
160 | else
161 | start_redir $main_server
162 | fi
163 |
164 | sleep 2
165 | }
166 |
167 | start_local() {
168 | gen_config_file $1
169 | ssr-local -c $CONFIG_FILE -u $(get_arg_tfo $1) \
170 | -l $(uci_get_by_type socks5_proxy local_port 1080) \
171 | -f /var/run/ssr-local.pid
172 | }
173 |
174 | ssr_local() {
175 | command -v ssr-local >/dev/null 2>&1 || return 0
176 | local server=$(uci_get_by_type socks5_proxy server)
177 | valid_server $server && start_local $server
178 | }
179 |
180 | start_tunnel() {
181 | gen_config_file $1
182 | ssr-tunnel -c $CONFIG_FILE -u \
183 | -l $(uci_get_by_type port_forward local_port 5300) \
184 | -L $(uci_get_by_type port_forward destination 8.8.4.4:53) \
185 | -f /var/run/ssr-tunnel.pid
186 | }
187 |
188 | ssr_tunnel() {
189 | command -v ssr-tunnel >/dev/null 2>&1 || return 0
190 | local server=$(uci_get_by_type port_forward server)
191 | valid_server $server && start_tunnel $server
192 | }
193 |
194 | start() {
195 | mkdir -p /var/run /var/etc
196 | ssr_redir && rules
197 | ssr_local
198 | ssr_tunnel
199 | rm -f $CONFIG_FILE
200 | valid_server $(uci_get_by_type transparent_proxy main_server) && add_cron
201 | }
202 |
203 | delay_start() {
204 | (sleep $1 && start >/dev/null 2>&1) &
205 | }
206 |
207 | boot() {
208 | local delay=$(uci_get_by_type general start_delay 0)
209 | if [ "$delay" -gt 0 ]; then
210 | delay_start $delay
211 | else
212 | start
213 | fi
214 | return 0
215 | }
216 |
217 | kill_all() {
218 | kill -9 $(pidof $@) >/dev/null 2>&1
219 | }
220 |
221 | stop() {
222 | /usr/bin/ssr-rules -f
223 | kill_all ssr-redir ssr-local ssr-tunnel
224 | rm -f /var/dnsmasq.d/ssr.conf /var/dnsmasq.d/ssr-servers.conf 2>/dev/null
225 | del_cron
226 | }
227 |
228 | add_cron() {
229 | sed -i '/shadowsocksr_watchdog/d' $CRON_FILE
230 | echo '0 */3 * * * rm -f /var/log/shadowsocksr_watchdog.log 2>&1' >> $CRON_FILE
231 | echo '* * * * * /etc/init.d/shadowsocksr watchdog >> /var/log/shadowsocksr_watchdog.log 2>&1' >> $CRON_FILE
232 | /etc/init.d/cron restart
233 | }
234 |
235 | del_cron() {
236 | sed -i '/shadowsocksr_watchdog/d' $CRON_FILE
237 | /etc/init.d/cron restart
238 | }
239 |
240 | watchdog(){
241 | command -v ssr-redir >/dev/null 2>&1 || return 1
242 | local main_server=$(uci_get_by_type transparent_proxy main_server)
243 | valid_server $main_server || return 1
244 |
245 | LOGTIME=$(date "+%Y-%m-%d %H:%M:%S")
246 | TRPORT=$(uci_get_by_type transparent_proxy local_port 1234)
247 | GOOGLE=$(ping -4 accounts.gstatic.com -c 1 -w 5 2>/dev/null | sed '1{s/[^(]*(//;s/).*//;q}')
248 | IPINCN=119.29.29.29 #DNSPOD HTTPDNS
249 |
250 | if [ "Z$GOOGLE" = "Z" ]; then
251 | echo "[${LOGTIME}] Problem-DNS decteted, restarting ${NAME}..."
252 | [ -x /etc/init.d/dnsmasq-extra ] && /etc/init.d/dnsmasq-extra restart || /etc/init.d/dnsmasq restart
253 | stop >/dev/null 2>&1
254 | start >/dev/null 2>&1
255 | return 0
256 | fi
257 |
258 | cat_connect(){
259 | url=$1
260 | # wget -> busybox wget
261 | ( wget -qO- --tries=3 --timeout=4 $url >/dev/null 2>&1 ) ||
262 | ( busybox wget -qO- -T10 $url >/dev/null 2>&1 )
263 | }
264 |
265 | iptables -t nat -I OUTPUT -p tcp -d $GOOGLE -j REDIRECT --to-port $TRPORT
266 | iptables -t nat -I OUTPUT -p tcp -d $IPINCN -j RETURN
267 | cat_connect $GOOGLE/generate_204
268 | if [ "Z$?" = "Z0" ]; then
269 | echo "[${LOGTIME}] ${NAME} No Problem."
270 | else
271 | cat_connect '119.29.29.29/d?dn=jd.com'
272 | if [ "Z$?" = "Z0" ]; then
273 | echo "[${LOGTIME}] Problem decteted, restarting ${NAME}..."
274 | [ -x /etc/init.d/haproxy-tcp ] && /etc/init.d/haproxy-tcp restart
275 | stop >/dev/null 2>&1
276 | start >/dev/null 2>&1
277 | else
278 | echo '['$LOGTIME'] Network Problem. Do nothing.'
279 | fi
280 | fi
281 |
282 | iptables -t nat -D OUTPUT -p tcp -d $GOOGLE -j REDIRECT --to-port $TRPORT
283 | iptables -t nat -D OUTPUT -p tcp -d $IPINCN -j RETURN
284 | return 0
285 | }
286 |
--------------------------------------------------------------------------------
/files/root/etc/uci-defaults/luci-shadowsocksr:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | uci get shadowsocksr.@general[-1] >/dev/null 2>&1 || \
3 | uci add shadowsocksr general >/dev/null 2>&1
4 | uci get shadowsocksr.@transparent_proxy[-1] >/dev/null 2>&1 || \
5 | uci add shadowsocksr transparent_proxy >/dev/null 2>&1
6 | uci get shadowsocksr.@socks5_proxy[-1] >/dev/null 2>&1 || \
7 | uci add shadowsocksr socks5_proxy >/dev/null 2>&1
8 | uci get shadowsocksr.@port_forward[-1] >/dev/null 2>&1 || \
9 | uci add shadowsocksr port_forward >/dev/null 2>&1
10 | uci get shadowsocksr.@access_control[-1] >/dev/null 2>&1 || \
11 | uci add shadowsocksr access_control >/dev/null 2>&1
12 | uci commit shadowsocksr
13 | uci -q batch <<-EOF >/dev/null
14 | delete ucitrack.@shadowsocksr[-1]
15 | add ucitrack shadowsocksr
16 | set ucitrack.@shadowsocksr[-1].init=shadowsocksr
17 | commit ucitrack
18 | delete firewall.shadowsocksr
19 | set firewall.shadowsocksr=include
20 | set firewall.shadowsocksr.type=script
21 | set firewall.shadowsocksr.path=/var/etc/shadowsocksr.include
22 | set firewall.shadowsocksr.reload=1
23 | commit firewall
24 | EOF
25 | exit 0
26 |
--------------------------------------------------------------------------------
/files/root/usr/bin/ssr-rules:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # Copyright (C) 2016 Jian Chang
4 | #
5 | # This is free software, licensed under the GNU General Public License v3.
6 | # See /LICENSE for more information.
7 | #
8 |
9 | usage() {
10 | cat <<-EOF
11 | Usage: ssr-rules [options]
12 |
13 | Valid options are:
14 |
15 | -s ip address of shadowsocks remote server
16 | -l port number of shadowsocks local server
17 | -S ip address of shadowsocks remote UDP server
18 | -L port number of shadowsocks local UDP server
19 | -i a file whose content is bypassed ip list
20 | -b wan ip of will be bypassed
21 | -w wan ip of will be forwarded
22 | -I proxy only for the given interface
23 | -d the default target of lan access control
24 | -a lan ip of access control, need a prefix to
25 | define proxy type
26 | -e extra options for iptables
27 | -o apply the rules to the OUTPUT chain
28 | -O apply the global rules to the OUTPUT chain
29 | -u enable udprelay mode, TPROXY is required
30 | -U enable udprelay mode, using different IP
31 | and ports for TCP and UDP
32 | -f flush the rules
33 | -h show this help message and exit
34 | EOF
35 | exit $1
36 | }
37 |
38 | loger() {
39 | # 1.alert 2.crit 3.err 4.warn 5.notice 6.info 7.debug
40 | logger -st ssr-rules[$$] -p$1 $2
41 | }
42 |
43 | flush_rules() {
44 | iptables-save -c | grep -v "SSR_SPEC" | sed '/[^ ]--/d' | uniq | iptables-restore -c
45 | uci -q show firewall | sed -n 's/.*path=//p' | sed -n '/gargoyle/p' | tr -d \' | while read init; do
46 | sh $init restart >/dev/null 2>&1
47 | done
48 |
49 | if command -v ip >/dev/null 2>&1; then
50 | ip rule del fwmark 1 lookup 100 2>/dev/null
51 | ip route del local default dev lo table 100 2>/dev/null
52 | fi
53 | for setname in $(ipset -n list | grep "ssr_spec"); do
54 | ipset destroy $setname 2>/dev/null
55 | done
56 | FWI=$(uci get firewall.shadowsocksr.path 2>/dev/null)
57 | [ -n "$FWI" ] && echo '# firewall include file' >$FWI
58 | return 0
59 | }
60 |
61 | ipset_init() {
62 | ipset -! restore <<-EOF || return 1
63 | create ssr_spec_src_ac hash:ip hashsize 64
64 | create ssr_spec_src_bp hash:ip hashsize 64
65 | create ssr_spec_src_fw hash:ip hashsize 64
66 | create ssr_spec_dst_sp hash:net hashsize 64
67 | create ssr_spec_dst_bp hash:net hashsize 64
68 | create ssr_spec_dst_fw hash:net hashsize 64
69 | $(gen_lan_host_ipset_entry)
70 | $(gen_special_purpose_ip | sed -e "s/^/add ssr_spec_dst_sp /")
71 | $(sed -e "s/^/add ssr_spec_dst_bp /" ${IGNORED:=/dev/null} 2>/dev/null)
72 | $(for ip in $WAN_BP_IP; do echo "add ssr_spec_dst_bp $ip"; done)
73 | $(for ip in $WAN_FW_IP; do echo "add ssr_spec_dst_fw $ip"; done)
74 | EOF
75 | return 0
76 | }
77 |
78 | ipt_nat() {
79 | include_ac_rules nat
80 | ipt="iptables -t nat"
81 | $ipt -A SSR_SPEC_WAN_FW -p tcp \
82 | -j REDIRECT --to-ports $local_port || return 1
83 | if [ -n "$OUTPUT" ]; then
84 | $ipt -N SSR_SPEC_WAN_DG
85 | $ipt -A SSR_SPEC_WAN_DG -m set --match-set ssr_spec_dst_sp dst -j RETURN
86 | $ipt -A SSR_SPEC_WAN_DG -p tcp $EXT_ARGS -j $OUTPUT
87 | $ipt -I OUTPUT 1 -p tcp -j SSR_SPEC_WAN_DG
88 | fi
89 | return $?
90 | }
91 |
92 | ipt_mangle() {
93 | [ -n "$TPROXY" ] || return 0
94 | if !(lsmod | grep -q TPROXY && command -v ip >/dev/null); then
95 | loger 4 "TPROXY or ip not found."
96 | return 0
97 | fi
98 | ip rule add fwmark 1 lookup 100
99 | ip route add local default dev lo table 100
100 | include_ac_rules mangle
101 | iptables -t mangle -A SSR_SPEC_WAN_FW -p udp \
102 | -j TPROXY --on-port $LOCAL_PORT --tproxy-mark 0x01/0x01
103 | return $?
104 | }
105 |
106 | export_ipt_rules() {
107 | [ -n "$FWI" ] || return 0
108 | cat <<-CAT >>$FWI
109 | iptables-save -c | grep -v "SSR_SPEC" | sed '/[^ ]--/d' | uniq | iptables-restore -c
110 | uci -q show firewall | sed -n 's/.*path=//p' | sed -n '/gargoyle/p' | tr -d \' | while read init; do
111 | sh $init restart >/dev/null 2>&1
112 | done
113 |
114 | iptables-restore -n <<-EOF
115 | $(iptables-save | grep -E "SSR_SPEC|^\*|^COMMIT" |\
116 | sed -e "s/^-A \(OUTPUT\|PREROUTING\)/-I \1 1/")
117 | EOF
118 | CAT
119 | return $?
120 | }
121 |
122 | gen_lan_host_ipset_entry() {
123 | for host in $LAN_HOSTS; do
124 | case "${host:0:1}" in
125 | n|N)
126 | echo add ssr_spec_src_ac ${host:2}
127 | ;;
128 | b|B)
129 | echo add ssr_spec_src_bp ${host:2}
130 | ;;
131 | g|G)
132 | echo add ssr_spec_src_fw ${host:2}
133 | ;;
134 | esac
135 | done
136 | }
137 |
138 | gen_special_purpose_ip() {
139 | cat <<-EOF | grep -E "^([0-9]{1,3}\.){3}[0-9]{1,3}"
140 | 0.0.0.0/8
141 | 10.0.0.0/8
142 | 100.64.0.0/10
143 | 127.0.0.0/8
144 | 169.254.0.0/16
145 | 172.16.0.0/12
146 | 192.0.0.0/24
147 | 192.0.2.0/24
148 | 192.31.196.0/24
149 | 192.52.193.0/24
150 | 192.88.99.0/24
151 | 192.168.0.0/16
152 | 192.175.48.0/24
153 | 198.18.0.0/15
154 | 198.51.100.0/24
155 | 203.0.113.0/24
156 | 224.0.0.0/4
157 | 240.0.0.0/4
158 | 255.255.255.255
159 | $server
160 | $SERVER
161 | EOF
162 | }
163 |
164 | include_ac_rules() {
165 | local protocol=$([ "$1" = "mangle" ] && echo udp || echo tcp)
166 | iptables-restore -n <<-EOF
167 | *$1
168 | :SSR_SPEC_LAN_DG - [0:0]
169 | :SSR_SPEC_LAN_AC - [0:0]
170 | :SSR_SPEC_WAN_AC - [0:0]
171 | :SSR_SPEC_WAN_FW - [0:0]
172 | -A SSR_SPEC_LAN_DG -m set --match-set ssr_spec_dst_sp dst -j RETURN
173 | -A SSR_SPEC_LAN_DG -p $protocol $EXT_ARGS -j SSR_SPEC_LAN_AC
174 | -A SSR_SPEC_LAN_AC -m set --match-set ssr_spec_src_bp src -j RETURN
175 | -A SSR_SPEC_LAN_AC -m set --match-set ssr_spec_src_fw src -j SSR_SPEC_WAN_FW
176 | -A SSR_SPEC_LAN_AC -m set --match-set ssr_spec_src_ac src -j SSR_SPEC_WAN_AC
177 | -A SSR_SPEC_LAN_AC -j ${LAN_TARGET:=SSR_SPEC_WAN_AC}
178 | -A SSR_SPEC_WAN_AC -m set --match-set ssr_spec_dst_fw dst -j SSR_SPEC_WAN_FW
179 | -A SSR_SPEC_WAN_AC -m set --match-set ssr_spec_dst_bp dst -j RETURN
180 | -A SSR_SPEC_WAN_AC -j SSR_SPEC_WAN_FW
181 | $(gen_prerouting_rules $protocol)
182 | COMMIT
183 | EOF
184 | }
185 |
186 | gen_prerouting_rules() {
187 | [ -z "$IFNAMES" ] && echo -I PREROUTING 1 -p $1 -j SSR_SPEC_LAN_DG
188 | for ifname in $IFNAMES; do
189 | echo -I PREROUTING 1 -i $ifname -p $1 -j SSR_SPEC_LAN_DG
190 | done
191 | }
192 |
193 | while getopts ":s:l:S:L:i:b:w:I:d:a:e:oOuUfh" arg; do
194 | case "$arg" in
195 | s)
196 | # wait-for-dns, timeout 10s
197 | for _ in `seq 10`; do if ping -4 t.cn -c 1 -w 5 >/dev/null 2>&1; then break; else sleep 1; fi; done
198 | server=$(for host in $OPTARG; do ping -4 $host -c 1 -w 5 | sed '1{s/[^(]*(//;s/).*//;q}' ; done)
199 | ;;
200 | l)
201 | local_port=$OPTARG
202 | ;;
203 | S)
204 | # wait-for-dns, timeout 10s
205 | for _ in `seq 10`; do if ping -4 t.cn -c 1 -w 5 >/dev/null 2>&1; then break; else sleep 1; fi; done
206 | SERVER=$(for host in $OPTARG; do ping -4 $host -c 1 -w 5 | sed '1{s/[^(]*(//;s/).*//;q}' ; done)
207 | ;;
208 | L)
209 | LOCAL_PORT=$OPTARG
210 | ;;
211 | i)
212 | IGNORED=$OPTARG
213 | ;;
214 | b)
215 | WAN_BP_IP=$OPTARG
216 | ;;
217 | w)
218 | WAN_FW_IP=$OPTARG
219 | ;;
220 | I)
221 | IFNAMES=$OPTARG
222 | ;;
223 | d)
224 | LAN_TARGET=$OPTARG
225 | ;;
226 | a)
227 | LAN_HOSTS=$OPTARG
228 | ;;
229 | e)
230 | EXT_ARGS=$OPTARG
231 | ;;
232 | o)
233 | OUTPUT=SSR_SPEC_WAN_AC
234 | ;;
235 | O)
236 | OUTPUT=SSR_SPEC_WAN_FW
237 | ;;
238 | u)
239 | TPROXY=1
240 | ;;
241 | U)
242 | TPROXY=2
243 | ;;
244 | f)
245 | flush_rules
246 | exit 0
247 | ;;
248 | h)
249 | usage 0
250 | ;;
251 | esac
252 | done
253 |
254 | [ -z "$server" -o -z "$local_port" ] && usage 2
255 |
256 | if [ "$TPROXY" = 1 ]; then
257 | unset SERVER
258 | LOCAL_PORT=$local_port
259 | elif [ "$TPROXY" = 2 ]; then
260 | : ${SERVER:?"You must assign an ip for the udp relay server."}
261 | : ${LOCAL_PORT:?"You must assign a port for the udp relay server."}
262 | fi
263 |
264 | flush_rules && ipset_init && ipt_nat && ipt_mangle && export_ipt_rules
265 | RET=$?
266 | [ "$RET" = 0 ] || loger 3 "Start failed!"
267 | exit $RET
268 |
--------------------------------------------------------------------------------
/preview/00_status.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shadowsocksr-rm/luci-app-shadowsocksr/8fad1fcfddac5e8d61af5a780e1d48d220c621df/preview/00_status.png
--------------------------------------------------------------------------------
/preview/01_servers.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shadowsocksr-rm/luci-app-shadowsocksr/8fad1fcfddac5e8d61af5a780e1d48d220c621df/preview/01_servers.png
--------------------------------------------------------------------------------
/preview/02_acl.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shadowsocksr-rm/luci-app-shadowsocksr/8fad1fcfddac5e8d61af5a780e1d48d220c621df/preview/02_acl.png
--------------------------------------------------------------------------------
/preview/03_log.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shadowsocksr-rm/luci-app-shadowsocksr/8fad1fcfddac5e8d61af5a780e1d48d220c621df/preview/03_log.png
--------------------------------------------------------------------------------
/preview/04_custom.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shadowsocksr-rm/luci-app-shadowsocksr/8fad1fcfddac5e8d61af5a780e1d48d220c621df/preview/04_custom.png
--------------------------------------------------------------------------------
/preview/05_gfwlist.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shadowsocksr-rm/luci-app-shadowsocksr/8fad1fcfddac5e8d61af5a780e1d48d220c621df/preview/05_gfwlist.png
--------------------------------------------------------------------------------
/tools/po2lmo/Makefile:
--------------------------------------------------------------------------------
1 |
2 | INSTALL = install
3 | PREFIX = /usr/bin
4 |
5 | po2lmo: src/po2lmo.o src/template_lmo.o
6 | $(CC) $(LDFLAGS) -o src/po2lmo src/po2lmo.o src/template_lmo.o
7 |
8 | install:
9 | $(INSTALL) -m 755 src/po2lmo $(PREFIX)
10 |
11 | clean:
12 | $(RM) src/po2lmo src/*.o
13 |
--------------------------------------------------------------------------------
/tools/po2lmo/src/po2lmo.c:
--------------------------------------------------------------------------------
1 | /*
2 | * lmo - Lua Machine Objects - PO to LMO conversion tool
3 | *
4 | * Copyright (C) 2009-2012 Jo-Philipp Wich
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | #include "template_lmo.h"
20 |
21 | static void die(const char *msg)
22 | {
23 | fprintf(stderr, "Error: %s\n", msg);
24 | exit(1);
25 | }
26 |
27 | static void usage(const char *name)
28 | {
29 | fprintf(stderr, "Usage: %s input.po output.lmo\n", name);
30 | exit(1);
31 | }
32 |
33 | static void print(const void *ptr, size_t size, size_t nmemb, FILE *stream)
34 | {
35 | if( fwrite(ptr, size, nmemb, stream) == 0 )
36 | die("Failed to write stdout");
37 | }
38 |
39 | static int extract_string(const char *src, char *dest, int len)
40 | {
41 | int pos = 0;
42 | int esc = 0;
43 | int off = -1;
44 |
45 | for( pos = 0; (pos < strlen(src)) && (pos < len); pos++ )
46 | {
47 | if( (off == -1) && (src[pos] == '"') )
48 | {
49 | off = pos + 1;
50 | }
51 | else if( off >= 0 )
52 | {
53 | if( esc == 1 )
54 | {
55 | switch (src[pos])
56 | {
57 | case '"':
58 | case '\\':
59 | off++;
60 | break;
61 | }
62 | dest[pos-off] = src[pos];
63 | esc = 0;
64 | }
65 | else if( src[pos] == '\\' )
66 | {
67 | dest[pos-off] = src[pos];
68 | esc = 1;
69 | }
70 | else if( src[pos] != '"' )
71 | {
72 | dest[pos-off] = src[pos];
73 | }
74 | else
75 | {
76 | dest[pos-off] = '\0';
77 | break;
78 | }
79 | }
80 | }
81 |
82 | return (off > -1) ? strlen(dest) : -1;
83 | }
84 |
85 | static int cmp_index(const void *a, const void *b)
86 | {
87 | uint32_t x = ((const lmo_entry_t *)a)->key_id;
88 | uint32_t y = ((const lmo_entry_t *)b)->key_id;
89 |
90 | if (x < y)
91 | return -1;
92 | else if (x > y)
93 | return 1;
94 |
95 | return 0;
96 | }
97 |
98 | static void print_uint32(uint32_t x, FILE *out)
99 | {
100 | uint32_t y = htonl(x);
101 | print(&y, sizeof(uint32_t), 1, out);
102 | }
103 |
104 | static void print_index(void *array, int n, FILE *out)
105 | {
106 | lmo_entry_t *e;
107 |
108 | qsort(array, n, sizeof(*e), cmp_index);
109 |
110 | for (e = array; n > 0; n--, e++)
111 | {
112 | print_uint32(e->key_id, out);
113 | print_uint32(e->val_id, out);
114 | print_uint32(e->offset, out);
115 | print_uint32(e->length, out);
116 | }
117 | }
118 |
119 | int main(int argc, char *argv[])
120 | {
121 | char line[4096];
122 | char key[4096];
123 | char val[4096];
124 | char tmp[4096];
125 | int state = 0;
126 | int offset = 0;
127 | int length = 0;
128 | int n_entries = 0;
129 | void *array = NULL;
130 | lmo_entry_t *entry = NULL;
131 | uint32_t key_id, val_id;
132 |
133 | FILE *in;
134 | FILE *out;
135 |
136 | if( (argc != 3) || ((in = fopen(argv[1], "r")) == NULL) || ((out = fopen(argv[2], "w")) == NULL) )
137 | usage(argv[0]);
138 |
139 | memset(line, 0, sizeof(key));
140 | memset(key, 0, sizeof(val));
141 | memset(val, 0, sizeof(val));
142 |
143 | while( (NULL != fgets(line, sizeof(line), in)) || (state >= 2 && feof(in)) )
144 | {
145 | if( state == 0 && strstr(line, "msgid \"") == line )
146 | {
147 | switch(extract_string(line, key, sizeof(key)))
148 | {
149 | case -1:
150 | die("Syntax error in msgid");
151 | case 0:
152 | state = 1;
153 | break;
154 | default:
155 | state = 2;
156 | }
157 | }
158 | else if( state == 1 || state == 2 )
159 | {
160 | if( strstr(line, "msgstr \"") == line || state == 2 )
161 | {
162 | switch(extract_string(line, val, sizeof(val)))
163 | {
164 | case -1:
165 | state = 4;
166 | break;
167 | default:
168 | state = 3;
169 | }
170 | }
171 | else
172 | {
173 | switch(extract_string(line, tmp, sizeof(tmp)))
174 | {
175 | case -1:
176 | state = 2;
177 | break;
178 | default:
179 | strcat(key, tmp);
180 | }
181 | }
182 | }
183 | else if( state == 3 )
184 | {
185 | switch(extract_string(line, tmp, sizeof(tmp)))
186 | {
187 | case -1:
188 | state = 4;
189 | break;
190 | default:
191 | strcat(val, tmp);
192 | }
193 | }
194 |
195 | if( state == 4 )
196 | {
197 | if( strlen(key) > 0 && strlen(val) > 0 )
198 | {
199 | key_id = sfh_hash(key, strlen(key));
200 | val_id = sfh_hash(val, strlen(val));
201 |
202 | if( key_id != val_id )
203 | {
204 | n_entries++;
205 | array = realloc(array, n_entries * sizeof(lmo_entry_t));
206 | entry = (lmo_entry_t *)array + n_entries - 1;
207 |
208 | if (!array)
209 | die("Out of memory");
210 |
211 | entry->key_id = key_id;
212 | entry->val_id = val_id;
213 | entry->offset = offset;
214 | entry->length = strlen(val);
215 |
216 | length = strlen(val) + ((4 - (strlen(val) % 4)) % 4);
217 |
218 | print(val, length, 1, out);
219 | offset += length;
220 | }
221 | }
222 |
223 | state = 0;
224 | memset(key, 0, sizeof(key));
225 | memset(val, 0, sizeof(val));
226 | }
227 |
228 | memset(line, 0, sizeof(line));
229 | }
230 |
231 | print_index(array, n_entries, out);
232 |
233 | if( offset > 0 )
234 | {
235 | print_uint32(offset, out);
236 | fsync(fileno(out));
237 | fclose(out);
238 | }
239 | else
240 | {
241 | fclose(out);
242 | unlink(argv[2]);
243 | }
244 |
245 | fclose(in);
246 | return(0);
247 | }
248 |
--------------------------------------------------------------------------------
/tools/po2lmo/src/template_lmo.c:
--------------------------------------------------------------------------------
1 | /*
2 | * lmo - Lua Machine Objects - Base functions
3 | *
4 | * Copyright (C) 2009-2010 Jo-Philipp Wich
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | #include "template_lmo.h"
20 |
21 | /*
22 | * Hash function from http://www.azillionmonkeys.com/qed/hash.html
23 | * Copyright (C) 2004-2008 by Paul Hsieh
24 | */
25 |
26 | uint32_t sfh_hash(const char *data, int len)
27 | {
28 | uint32_t hash = len, tmp;
29 | int rem;
30 |
31 | if (len <= 0 || data == NULL) return 0;
32 |
33 | rem = len & 3;
34 | len >>= 2;
35 |
36 | /* Main loop */
37 | for (;len > 0; len--) {
38 | hash += sfh_get16(data);
39 | tmp = (sfh_get16(data+2) << 11) ^ hash;
40 | hash = (hash << 16) ^ tmp;
41 | data += 2*sizeof(uint16_t);
42 | hash += hash >> 11;
43 | }
44 |
45 | /* Handle end cases */
46 | switch (rem) {
47 | case 3: hash += sfh_get16(data);
48 | hash ^= hash << 16;
49 | hash ^= data[sizeof(uint16_t)] << 18;
50 | hash += hash >> 11;
51 | break;
52 | case 2: hash += sfh_get16(data);
53 | hash ^= hash << 11;
54 | hash += hash >> 17;
55 | break;
56 | case 1: hash += *data;
57 | hash ^= hash << 10;
58 | hash += hash >> 1;
59 | }
60 |
61 | /* Force "avalanching" of final 127 bits */
62 | hash ^= hash << 3;
63 | hash += hash >> 5;
64 | hash ^= hash << 4;
65 | hash += hash >> 17;
66 | hash ^= hash << 25;
67 | hash += hash >> 6;
68 |
69 | return hash;
70 | }
71 |
72 | uint32_t lmo_canon_hash(const char *str, int len)
73 | {
74 | char res[4096];
75 | char *ptr, prev;
76 | int off;
77 |
78 | if (!str || len >= sizeof(res))
79 | return 0;
80 |
81 | for (prev = ' ', ptr = res, off = 0; off < len; prev = *str, off++, str++)
82 | {
83 | if (isspace(*str))
84 | {
85 | if (!isspace(prev))
86 | *ptr++ = ' ';
87 | }
88 | else
89 | {
90 | *ptr++ = *str;
91 | }
92 | }
93 |
94 | if ((ptr > res) && isspace(*(ptr-1)))
95 | ptr--;
96 |
97 | return sfh_hash(res, ptr - res);
98 | }
99 |
100 | lmo_archive_t * lmo_open(const char *file)
101 | {
102 | int in = -1;
103 | uint32_t idx_offset = 0;
104 | struct stat s;
105 |
106 | lmo_archive_t *ar = NULL;
107 |
108 | if (stat(file, &s) == -1)
109 | goto err;
110 |
111 | if ((in = open(file, O_RDONLY)) == -1)
112 | goto err;
113 |
114 | if ((ar = (lmo_archive_t *)malloc(sizeof(*ar))) != NULL)
115 | {
116 | memset(ar, 0, sizeof(*ar));
117 |
118 | ar->fd = in;
119 | ar->size = s.st_size;
120 |
121 | fcntl(ar->fd, F_SETFD, fcntl(ar->fd, F_GETFD) | FD_CLOEXEC);
122 |
123 | if ((ar->mmap = mmap(NULL, ar->size, PROT_READ, MAP_SHARED, ar->fd, 0)) == MAP_FAILED)
124 | goto err;
125 |
126 | idx_offset = ntohl(*((const uint32_t *)
127 | (ar->mmap + ar->size - sizeof(uint32_t))));
128 |
129 | if (idx_offset >= ar->size)
130 | goto err;
131 |
132 | ar->index = (lmo_entry_t *)(ar->mmap + idx_offset);
133 | ar->length = (ar->size - idx_offset - sizeof(uint32_t)) / sizeof(lmo_entry_t);
134 | ar->end = ar->mmap + ar->size;
135 |
136 | return ar;
137 | }
138 |
139 | err:
140 | if (in > -1)
141 | close(in);
142 |
143 | if (ar != NULL)
144 | {
145 | if ((ar->mmap != NULL) && (ar->mmap != MAP_FAILED))
146 | munmap(ar->mmap, ar->size);
147 |
148 | free(ar);
149 | }
150 |
151 | return NULL;
152 | }
153 |
154 | void lmo_close(lmo_archive_t *ar)
155 | {
156 | if (ar != NULL)
157 | {
158 | if ((ar->mmap != NULL) && (ar->mmap != MAP_FAILED))
159 | munmap(ar->mmap, ar->size);
160 |
161 | close(ar->fd);
162 | free(ar);
163 |
164 | ar = NULL;
165 | }
166 | }
167 |
168 |
169 | lmo_catalog_t *_lmo_catalogs = NULL;
170 | lmo_catalog_t *_lmo_active_catalog = NULL;
171 |
172 | int lmo_load_catalog(const char *lang, const char *dir)
173 | {
174 | DIR *dh = NULL;
175 | char pattern[16];
176 | char path[PATH_MAX];
177 | struct dirent *de = NULL;
178 |
179 | lmo_archive_t *ar = NULL;
180 | lmo_catalog_t *cat = NULL;
181 |
182 | if (!lmo_change_catalog(lang))
183 | return 0;
184 |
185 | if (!dir || !(dh = opendir(dir)))
186 | goto err;
187 |
188 | if (!(cat = malloc(sizeof(*cat))))
189 | goto err;
190 |
191 | memset(cat, 0, sizeof(*cat));
192 |
193 | snprintf(cat->lang, sizeof(cat->lang), "%s", lang);
194 | snprintf(pattern, sizeof(pattern), "*.%s.lmo", lang);
195 |
196 | while ((de = readdir(dh)) != NULL)
197 | {
198 | if (!fnmatch(pattern, de->d_name, 0))
199 | {
200 | snprintf(path, sizeof(path), "%s/%s", dir, de->d_name);
201 | ar = lmo_open(path);
202 |
203 | if (ar)
204 | {
205 | ar->next = cat->archives;
206 | cat->archives = ar;
207 | }
208 | }
209 | }
210 |
211 | closedir(dh);
212 |
213 | cat->next = _lmo_catalogs;
214 | _lmo_catalogs = cat;
215 |
216 | if (!_lmo_active_catalog)
217 | _lmo_active_catalog = cat;
218 |
219 | return 0;
220 |
221 | err:
222 | if (dh) closedir(dh);
223 | if (cat) free(cat);
224 |
225 | return -1;
226 | }
227 |
228 | int lmo_change_catalog(const char *lang)
229 | {
230 | lmo_catalog_t *cat;
231 |
232 | for (cat = _lmo_catalogs; cat; cat = cat->next)
233 | {
234 | if (!strncmp(cat->lang, lang, sizeof(cat->lang)))
235 | {
236 | _lmo_active_catalog = cat;
237 | return 0;
238 | }
239 | }
240 |
241 | return -1;
242 | }
243 |
244 | static lmo_entry_t * lmo_find_entry(lmo_archive_t *ar, uint32_t hash)
245 | {
246 | unsigned int m, l, r;
247 | uint32_t k;
248 |
249 | l = 0;
250 | r = ar->length - 1;
251 |
252 | while (1)
253 | {
254 | m = l + ((r - l) / 2);
255 |
256 | if (r < l)
257 | break;
258 |
259 | k = ntohl(ar->index[m].key_id);
260 |
261 | if (k == hash)
262 | return &ar->index[m];
263 |
264 | if (k > hash)
265 | {
266 | if (!m)
267 | break;
268 |
269 | r = m - 1;
270 | }
271 | else
272 | {
273 | l = m + 1;
274 | }
275 | }
276 |
277 | return NULL;
278 | }
279 |
280 | int lmo_translate(const char *key, int keylen, char **out, int *outlen)
281 | {
282 | uint32_t hash;
283 | lmo_entry_t *e;
284 | lmo_archive_t *ar;
285 |
286 | if (!key || !_lmo_active_catalog)
287 | return -2;
288 |
289 | hash = lmo_canon_hash(key, keylen);
290 |
291 | for (ar = _lmo_active_catalog->archives; ar; ar = ar->next)
292 | {
293 | if ((e = lmo_find_entry(ar, hash)) != NULL)
294 | {
295 | *out = ar->mmap + ntohl(e->offset);
296 | *outlen = ntohl(e->length);
297 | return 0;
298 | }
299 | }
300 |
301 | return -1;
302 | }
303 |
304 | void lmo_close_catalog(const char *lang)
305 | {
306 | lmo_archive_t *ar, *next;
307 | lmo_catalog_t *cat, *prev;
308 |
309 | for (prev = NULL, cat = _lmo_catalogs; cat; prev = cat, cat = cat->next)
310 | {
311 | if (!strncmp(cat->lang, lang, sizeof(cat->lang)))
312 | {
313 | if (prev)
314 | prev->next = cat->next;
315 | else
316 | _lmo_catalogs = cat->next;
317 |
318 | for (ar = cat->archives; ar; ar = next)
319 | {
320 | next = ar->next;
321 | lmo_close(ar);
322 | }
323 |
324 | free(cat);
325 | break;
326 | }
327 | }
328 | }
329 |
--------------------------------------------------------------------------------
/tools/po2lmo/src/template_lmo.h:
--------------------------------------------------------------------------------
1 | /*
2 | * lmo - Lua Machine Objects - General header
3 | *
4 | * Copyright (C) 2009-2012 Jo-Philipp Wich
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | #ifndef _TEMPLATE_LMO_H_
20 | #define _TEMPLATE_LMO_H_
21 |
22 | #include
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include
29 | #include
30 | #include
31 | #include
32 | #include
33 | #include
34 | #include
35 | #include
36 |
37 | #if (defined(__GNUC__) && defined(__i386__))
38 | #define sfh_get16(d) (*((const uint16_t *) (d)))
39 | #else
40 | #define sfh_get16(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)\
41 | +(uint32_t)(((const uint8_t *)(d))[0]) )
42 | #endif
43 |
44 |
45 | struct lmo_entry {
46 | uint32_t key_id;
47 | uint32_t val_id;
48 | uint32_t offset;
49 | uint32_t length;
50 | } __attribute__((packed));
51 |
52 | typedef struct lmo_entry lmo_entry_t;
53 |
54 |
55 | struct lmo_archive {
56 | int fd;
57 | int length;
58 | uint32_t size;
59 | lmo_entry_t *index;
60 | char *mmap;
61 | char *end;
62 | struct lmo_archive *next;
63 | };
64 |
65 | typedef struct lmo_archive lmo_archive_t;
66 |
67 |
68 | struct lmo_catalog {
69 | char lang[6];
70 | struct lmo_archive *archives;
71 | struct lmo_catalog *next;
72 | };
73 |
74 | typedef struct lmo_catalog lmo_catalog_t;
75 |
76 |
77 | uint32_t sfh_hash(const char *data, int len);
78 | uint32_t lmo_canon_hash(const char *data, int len);
79 |
80 | lmo_archive_t * lmo_open(const char *file);
81 | void lmo_close(lmo_archive_t *ar);
82 |
83 |
84 | extern lmo_catalog_t *_lmo_catalogs;
85 | extern lmo_catalog_t *_lmo_active_catalog;
86 |
87 | int lmo_load_catalog(const char *lang, const char *dir);
88 | int lmo_change_catalog(const char *lang);
89 | int lmo_translate(const char *key, int keylen, char **out, int *outlen);
90 | void lmo_close_catalog(const char *lang);
91 |
92 | #endif
93 |
--------------------------------------------------------------------------------