From 3ec0955facf328bc9b4908014c1b884634306b56 Mon Sep 17 00:00:00 2001 From: okxlin Date: Wed, 29 Nov 2023 11:51:21 +0800 Subject: [PATCH] =?UTF-8?q?feat:=E6=B7=BB=E5=8A=A0smartdns=E5=88=B0?= =?UTF-8?q?=E5=88=97=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/smartdns/README.md | 149 ++++++++++ apps/smartdns/data.yml | 20 ++ apps/smartdns/latest/.env.sample | 2 + apps/smartdns/latest/data.yml | 10 + apps/smartdns/latest/data/smartdns.conf | 368 ++++++++++++++++++++++++ apps/smartdns/latest/docker-compose.yml | 18 ++ apps/smartdns/logo.png | Bin 0 -> 15953 bytes 7 files changed, 567 insertions(+) create mode 100644 apps/smartdns/README.md create mode 100644 apps/smartdns/data.yml create mode 100644 apps/smartdns/latest/.env.sample create mode 100644 apps/smartdns/latest/data.yml create mode 100644 apps/smartdns/latest/data/smartdns.conf create mode 100644 apps/smartdns/latest/docker-compose.yml create mode 100644 apps/smartdns/logo.png diff --git a/apps/smartdns/README.md b/apps/smartdns/README.md new file mode 100644 index 00000000..eeeb851f --- /dev/null +++ b/apps/smartdns/README.md @@ -0,0 +1,149 @@ +# SmartDNS + +**[English](https://github.com/pymumu/smartdns/blob/master/ReadMe_en.md)** + +![SmartDNS](doc/smartdns-banner.png) +SmartDNS 是一个运行在本地的 DNS 服务器,它接受来自本地客户端的 DNS 查询请求,然后从多个上游 DNS 服务器获取 DNS 查询结果,并将访问速度最快的结果返回给客户端,以此提高网络访问速度。 +SmartDNS 同时支持指定特定域名 IP 地址,并高性匹配,可达到过滤广告的效果; 支持DOT(DNS over TLS)和DOH(DNS over HTTPS),更好的保护隐私。 + +与 DNSmasq 的 all-servers 不同,SmartDNS 返回的是访问速度最快的解析结果。 + +支持树莓派、OpenWrt、华硕路由器原生固件和 Windows 系统等。 + +## 使用指导 + +SmartDNS官网:[https://pymumu.github.io/smartdns](https://pymumu.github.io/smartdns) + +## 软件效果展示 + +**阿里 DNS** +使用阿里 DNS 查询百度IP,并检测结果。 + +```shell +$ nslookup www.baidu.com 223.5.5.5 +Server: 223.5.5.5 +Address: 223.5.5.5#53 + +Non-authoritative answer: +www.baidu.com canonical name = www.a.shifen.com. +Name: www.a.shifen.com +Address: 180.97.33.108 +Name: www.a.shifen.com +Address: 180.97.33.107 + +$ ping 180.97.33.107 -c 2 +PING 180.97.33.107 (180.97.33.107) 56(84) bytes of data. +64 bytes from 180.97.33.107: icmp_seq=1 ttl=55 time=24.3 ms +64 bytes from 180.97.33.107: icmp_seq=2 ttl=55 time=24.2 ms + +--- 180.97.33.107 ping statistics --- +2 packets transmitted, 2 received, 0% packet loss, time 1001ms +rtt min/avg/max/mdev = 24.275/24.327/24.380/0.164 ms +pi@raspberrypi:~/code/smartdns_build $ ping 180.97.33.108 -c 2 +PING 180.97.33.108 (180.97.33.108) 56(84) bytes of data. +64 bytes from 180.97.33.108: icmp_seq=1 ttl=55 time=31.1 ms +64 bytes from 180.97.33.108: icmp_seq=2 ttl=55 time=31.0 ms + +--- 180.97.33.108 ping statistics --- +2 packets transmitted, 2 received, 0% packet loss, time 1001ms +rtt min/avg/max/mdev = 31.014/31.094/31.175/0.193 ms +``` + +**SmartDNS** +使用 SmartDNS 查询百度 IP,并检测结果。 + +```shell +$ nslookup www.baidu.com +Server: 192.168.1.1 +Address: 192.168.1.1#53 + +Non-authoritative answer: +www.baidu.com canonical name = www.a.shifen.com. +Name: www.a.shifen.com +Address: 14.215.177.39 + +$ ping 14.215.177.39 -c 2 +PING 14.215.177.39 (14.215.177.39) 56(84) bytes of data. +64 bytes from 14.215.177.39: icmp_seq=1 ttl=56 time=6.31 ms +64 bytes from 14.215.177.39: icmp_seq=2 ttl=56 time=5.95 ms + +--- 14.215.177.39 ping statistics --- +2 packets transmitted, 2 received, 0% packet loss, time 1001ms +rtt min/avg/max/mdev = 5.954/6.133/6.313/0.195 ms +``` + +从对比看出,SmartDNS 找到了访问 www.baidu.com 最快的 IP 地址,比阿里 DNS 速度快了 5 倍。 + +## 特性 + +1. **多 DNS 上游服务器** + 支持配置多个上游 DNS 服务器,并同时进行查询,即使其中有 DNS 服务器异常,也不会影响查询。 + +1. **返回最快 IP 地址** + 支持从域名所属 IP 地址列表中查找到访问速度最快的 IP 地址,并返回给客户端,提高网络访问速度。 + +1. **支持多种查询协议** + 支持 UDP、TCP、DOT 和 DOH 查询及服务,以及非 53 端口查询;支持通过socks5,HTTP代理查询; + +1. **特定域名 IP 地址指定** + 支持指定域名的 IP 地址,达到广告过滤效果、避免恶意网站的效果。 + +1. **域名高性能后缀匹配** + 支持域名后缀匹配模式,简化过滤配置,过滤 20 万条记录时间 < 1ms。 + +1. **域名分流** + 支持域名分流,不同类型的域名向不同的 DNS 服务器查询,支持iptable和nftable更好的分流;支持测速失败的情况下设置域名结果到对应ipset和nftset集合。 + +1. **Windows / Linux 多平台支持** + 支持标准 Linux 系统(树莓派)、OpenWrt 系统各种固件和华硕路由器原生固件。同时还支持 WSL(Windows Subsystem for Linux,适用于 Linux 的 Windows 子系统)。 + +1. **支持 IPv4、IPv6 双栈** + 支持 IPv4 和 IPV 6网络,支持查询 A 和 AAAA 记录,支持双栈 IP 速度优化,并支持完全禁用 IPv6 AAAA 解析。 + +1. **支持DNS64** + 支持DNS64转换。 + +1. **高性能、占用资源少** + 多线程异步 IO 模式,cache 缓存查询结果。 + +1. **主流系统官方支持** + 主流路由系统官方软件源安装smartdns。 + +## 架构 + +![Architecture](https://github.com/pymumu/test/releases/download/blob/architecture.png) + +1. SmartDNS 接收本地网络设备的DNS 查询请求,如 PC、手机的查询请求; +1. 然后将查询请求发送到多个上游 DNS 服务器,可支持 UDP 标准端口或非标准端口查询,以及 TCP 查询; +1. 上游 DNS 服务器返回域名对应的服务器 IP 地址列表,SmartDNS 则会检测从本地网络访问速度最快的服务器 IP; +1. 最后将访问速度最快的服务器 IP 返回给本地客户端。 + +## 编译 + +- 代码编译: + + SmartDNS 提供了编译软件包的脚本(`package/build-pkg.sh`),支持编译 LuCI、Debian、OpenWrt 和 Optware 安装包。 + +- 文档编译: + + 文档分支为`doc`,安装`mkdocs`工具后,执行`mkdocs build`编译。 + +## 捐赠 + +如果你觉得此项目对你有帮助,请捐助我们,使项目能持续发展和更加完善。 + +### PayPal 贝宝 + +[![Support via PayPal](https://cdn.rawgit.com/twolfson/paypal-github-button/1.0.0/dist/button.svg)](https://paypal.me/PengNick/) + +### AliPay 支付宝 + +![alipay](doc/alipay_donate.jpg) + +### WeChat Pay 微信支付 + +![wechat](doc/wechat_donate.jpg) + +## 开源声明 + +SmartDNS 基于 GPL V3 协议开源。 \ No newline at end of file diff --git a/apps/smartdns/data.yml b/apps/smartdns/data.yml new file mode 100644 index 00000000..6c70ef04 --- /dev/null +++ b/apps/smartdns/data.yml @@ -0,0 +1,20 @@ +name: SmartDNS +tags: + - 工具 +title: 一个运行在本地的 DNS 服务器 +type: 工具 +description: 一个运行在本地的 DNS 服务器 +additionalProperties: + key: smartdns + name: SmartDNS + tags: + - Tool + shortDescZh: 一个运行在本地的 DNS 服务器 + shortDescEn: A local DNS server + type: tool + crossVersionUpdate: true + limit: 0 + recommend: 0 + website: https://pymumu.github.io/smartdns + github: https://github.com/pymumu/smartdns + document: https://pymumu.github.io/smartdns diff --git a/apps/smartdns/latest/.env.sample b/apps/smartdns/latest/.env.sample new file mode 100644 index 00000000..ce53b96c --- /dev/null +++ b/apps/smartdns/latest/.env.sample @@ -0,0 +1,2 @@ +CONTAINER_NAME="smartdns" +PANEL_APP_PORT_HTTP="40175" diff --git a/apps/smartdns/latest/data.yml b/apps/smartdns/latest/data.yml new file mode 100644 index 00000000..1838a00a --- /dev/null +++ b/apps/smartdns/latest/data.yml @@ -0,0 +1,10 @@ +additionalProperties: + formFields: + - default: 40175 + edit: true + envKey: PANEL_APP_PORT_HTTP + labelEn: Port + labelZh: 端口 + required: true + rule: paramPort + type: number diff --git a/apps/smartdns/latest/data/smartdns.conf b/apps/smartdns/latest/data/smartdns.conf new file mode 100644 index 00000000..5aa5f6d5 --- /dev/null +++ b/apps/smartdns/latest/data/smartdns.conf @@ -0,0 +1,368 @@ +# 监听53端口 +bind [::]:53 +# 配置上游服务器 +#server 119.29.29.29 +#server 223.5.5.5 +#server 180.184.1.1 +server-tls 1.1.1.1 +server-https https://doh.pub/dns-query +server-https https://dns.alidns.com/dns-query +server-https https://cloudflare-dns.com/dns-query + +force-qtype-SOA 65 +log-level info + +########################################### +# dns server name, default is host name +# server-name, +# example: +# server-name smartdns +# + +# whether resolv local hostname to ip address +# resolv-hostname yes + +# dns server run user +# user [username] +# example: run as nobody +# user nobody +# + +# Include another configuration options +# conf-file [file] +# conf-file blacklist-ip.conf + +# dns server bind ip and port, default dns server port is 53, support binding multi ip and port +# bind udp server +# bind [IP]:[port][@device] [-group [group]] [-no-rule-addr] [-no-rule-nameserver] [-no-rule-ipset] [-no-speed-check] [-no-cache] [-no-rule-soa] [-no-dualstack-selection] +# bind tcp server +# bind-tcp [IP]:[port][@device] [-group [group]] [-no-rule-addr] [-no-rule-nameserver] [-no-rule-ipset] [-no-speed-check] [-no-cache] [-no-rule-soa] [-no-dualstack-selection] +# bind tls server +# bind-tls [IP]:[port][@device] [-group [group]] [-no-rule-addr] [-no-rule-nameserver] [-no-rule-ipset] [-no-speed-check] [-no-cache] [-no-rule-soa] [-no-dualstack-selection] +# bind-cert-key-file [path to file] +# tls private key file +# bind-cert-file [path to file] +# tls cert file +# bind-cert-key-pass [password] +# tls private key password +# bind-https server +# bind-https [IP]:[port][@device] [-group [group]] [-no-rule-addr] [-no-rule-nameserver] [-no-rule-ipset] [-no-speed-check] [-no-cache] [-no-rule-soa] [-no-dualstack-selection] +# option: +# -group: set domain request to use the appropriate server group. +# -no-rule-addr: skip address rule. +# -no-rule-nameserver: skip nameserver rule. +# -no-rule-ipset: skip ipset rule or nftset rule. +# -no-speed-check: do not check speed. +# -no-cache: skip cache. +# -no-rule-soa: Skip address SOA(#) rules. +# -no-dualstack-selection: Disable dualstack ip selection. +# -no-ip-alias: ignore ip alias. +# -force-aaaa-soa: force AAAA query return SOA. +# -ipset ipsetname: use ipset rule. +# -nftset nftsetname: use nftset rule. +# example: +# IPV4: +# bind :53 +# bind :53@eth0 +# bind :6053 -group office -no-speed-check +# IPV6: +# bind [::]:53 +# bind [::]:53@eth0 +# bind-tcp [::]:53 +#bind [::]:53 + +# tcp connection idle timeout +# tcp-idle-time [second] + +# dns cache size +# cache-size [number] +# 0: for no cache +# -1: auto set cache size +# cache-size 32768 + +# enable persist cache when restart +# cache-persist no + +# cache persist file +# cache-file /tmp/smartdns.cache + +# cache persist time +# cache-checkpoint-time [second] +# cache-checkpoint-time 86400 + +# prefetch domain +# prefetch-domain [yes|no] +# prefetch-domain yes + +# cache serve expired +# serve-expired [yes|no] +# serve-expired yes + +# cache serve expired TTL +# serve-expired-ttl [num] +# serve-expired-ttl 0 + +# reply TTL value to use when replying with expired data +# serve-expired-reply-ttl [num] +# serve-expired-reply-ttl 30 + +# List of hosts that supply bogus NX domain results +# bogus-nxdomain [ip/subnet] + +# List of IPs that will be filtered when nameserver is configured -blacklist-ip parameter +# blacklist-ip [ip/subnet] + +# List of IPs that will be accepted when nameserver is configured -whitelist-ip parameter +# whitelist-ip [ip/subnet] + +# List of IPs that will be ignored +# ignore-ip [ip/subnet] + +# alias of IPs +# ip-alias [ip/subnet] [ip1[,ip2]...] +# ip-alias 192.168.0.1/24 10.9.0.1,10.9.0.2 + +# speed check mode +# speed-check-mode [ping|tcp:port|none|,] +# example: +# speed-check-mode ping,tcp:80,tcp:443 +# speed-check-mode tcp:443,ping +# speed-check-mode none + +# force AAAA query return SOA +# force-AAAA-SOA [yes|no] + +# force specific qtype return soa +# force-qtype-SOA [qtypeid |...] +# force-qtype-SOA [qtypeid|start_id-end_id|,...] +# force-qtype-SOA 65 28 +# force-qtype-SOA 65,28 +#force-qtype-SOA 65 + +# Enable IPV4, IPV6 dual stack IP optimization selection strategy +# dualstack-ip-selection-threshold [num] (0~1000) +# dualstack-ip-allow-force-AAAA [yes|no] +# dualstack-ip-selection [yes|no] +# dualstack-ip-selection no + +# edns client subnet +# edns-client-subnet [ip/subnet] +# edns-client-subnet 192.168.1.1/24 +# edns-client-subnet 8::8/56 + +# ttl for all resource record +# rr-ttl: ttl for all record +# rr-ttl-min: minimum ttl for resource record +# rr-ttl-max: maximum ttl for resource record +# rr-ttl-reply-max: maximum reply ttl for resource record +# example: +# rr-ttl 300 +# rr-ttl-min 60 +# rr-ttl-max 86400 +# rr-ttl-reply-max 60 + +# Maximum number of IPs returned to the client|8|number of IPs, 1~16 +# example: +# max-reply-ip-num 1 + +# response mode +# Experimental feature +# response-mode [first-ping|fastest-ip|fastest-response] + +# set log level +# log-level: [level], level=off, fatal, error, warn, notice, info, debug +# log-file: file path of log file. +# log-console [yes|no]: output log to console. +# log-size: size of each log file, support k,m,g +# log-num: number of logs, 0 means disable log +#log-level info + +# log-file /var/log/smartdns/smartdns.log +# log-size 128k +# log-num 2 +# log-file-mode [mode]: file mode of log file. + +# dns audit +# audit-enable [yes|no]: enable or disable audit. +# audit-enable yes +# audit-SOA [yes|no]: enable or disable log soa result. +# audit-size size of each audit file, support k,m,g +# audit-file /var/log/smartdns-audit.log +# audit-console [yes|no]: output audit log to console. +# audit-file-mode [mode]: file mode of audit file. +# audit-size 128k +# audit-num 2 + +# Support reading dnsmasq dhcp file to resolve local hostname +# dnsmasq-lease-file /var/lib/misc/dnsmasq.leases + +# certificate file +# ca-file [file] +# ca-file /etc/ssl/certs/ca-certificates.crt + +# certificate path +# ca-path [path] +# ca-path /etc/ss/certs + +# remote udp dns server list +# server [IP]:[PORT]|URL [-blacklist-ip] [-whitelist-ip] [-check-edns] [-group [group] ...] [-exclude-default-group] +# default port is 53 +# -blacklist-ip: filter result with blacklist ip +# -whitelist-ip: filter result with whitelist ip, result in whitelist-ip will be accepted. +# -check-edns: result must exist edns RR, or discard result. +# g|-group [group]: set server to group, use with nameserver /domain/group. +# e|-exclude-default-group: exclude this server from default group. +# p|-proxy [proxy-name]: use proxy to connect to server. +# -bootstrap-dns: set as bootstrap dns server. +# -set-mark: set mark on packets. +# -subnet [ip/subnet]: set edns client subnet. +# -host-ip [ip]: set dns server host ip. +# server 8.8.8.8 -blacklist-ip -check-edns -group g1 -group g2 +# server tls://dns.google:853 +# server https://dns.google/dns-query + +# remote tcp dns server list +# server-tcp [IP]:[PORT] [-blacklist-ip] [-whitelist-ip] [-group [group] ...] [-exclude-default-group] +# default port is 53 +# server-tcp 8.8.8.8 + +# remote tls dns server list +# server-tls [IP]:[PORT] [-blacklist-ip] [-whitelist-ip] [-spki-pin [sha256-pin]] [-group [group] ...] [-exclude-default-group] +# -spki-pin: TLS spki pin to verify. +# -tls-host-verify: cert hostname to verify. +# -host-name: TLS sni hostname. +# k|-no-check-certificate: no check certificate. +# p|-proxy [proxy-name]: use proxy to connect to server. +# -bootstrap-dns: set as bootstrap dns server. +# Get SPKI with this command: +# echo | openssl s_client -connect '[ip]:853' | openssl x509 -pubkey -noout | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64 +# default port is 853 +# server-tls 8.8.8.8 +# server-tls 1.0.0.1 + +# remote https dns server list +# server-https https://[host]:[port]/path [-blacklist-ip] [-whitelist-ip] [-spki-pin [sha256-pin]] [-group [group] ...] [-exclude-default-group] +# -spki-pin: TLS spki pin to verify. +# -tls-host-verify: cert hostname to verify. +# -host-name: TLS sni hostname. +# -http-host: http host. +# k|-no-check-certificate: no check certificate. +# p|-proxy [proxy-name]: use proxy to connect to server. +# -bootstrap-dns: set as bootstrap dns server. +# default port is 443 +# server-https https://cloudflare-dns.com/dns-query + +# socks5 and http proxy list +# proxy-server URL -name [proxy name] +# URL: socks5://[username:password@]host:port +# http://[username:password@]host:port +# -name: proxy name, use with server -proxy [proxy-name] +# example: +# proxy-server socks5://user:pass@1.2.3.4:1080 -name proxy +# proxy-server http://user:pass@1.2.3.4:3128 -name proxy + +# specific nameserver to domain +# nameserver /domain/[group|-] +# nameserver /www.example.com/office, Set the domain name to use the appropriate server group. +# nameserver /www.example.com/-, ignore this domain + +# expand ptr record from address record +# expand-ptr-from-address yes + +# specific address to domain +# address /domain/[ip1,ip2|-|-4|-6|#|#4|#6] +# address /www.example.com/1.2.3.4, return ip 1.2.3.4 to client +# address /www.example.com/1.2.3.4,5.6.7.8, return multiple ip addresses +# address /www.example.com/-, ignore address, query from upstream, suffix 4, for ipv4, 6 for ipv6, none for all +# address /www.example.com/#, return SOA to client, suffix 4, for ipv4, 6 for ipv6, none for all + +# specific cname to domain +# cname /domain/target + +# enalbe DNS64 feature +# dns64 [ip/subnet] +# dns64 64:ff9b::/96 + +# enable ipset timeout by ttl feature +# ipset-timeout [yes] + +# specific ipset to domain +# ipset /domain/[ipset|-] +# ipset /www.example.com/block, set ipset with ipset name of block +# ipset /www.example.com/-, ignore this domain + +# add to ipset when ping is unreachable +# ipset-no-speed ipsetname +# ipset-no-speed pass + +# enable nftset timeout by ttl feature +# nftset-timeout [yes|no] +# nftset-timeout yes + +# add to nftset when ping is unreachable +# nftset-no-speed [#4:ip#table#set,#6:ipv6#table#setv6] +# nftset-no-speed #4:ip#table#set + +# enable nftset debug, check nftset setting result, output log when error. +# nftset-debug [yes|no] +# nftset-debug yes + +# specific nftset to domain +# nftset /domain/[#4:ip#table#set,#6:ipv6#table#setv6] +# nftset /www.example.com/ip#table#set, equivalent to 'nft add element ip table set { ... }' +# nftset /www.example.com/-, ignore this domain +# nftset /www.example.com/#6:-, ignore ipv6 + +# set ddns domain +# ddns-domain domain + +# set domain rules +# domain-rules /domain/ [-speed-check-mode [...]] +# rules: +# [-c] -speed-check-mode [mode]: speed check mode +# speed-check-mode [ping|tcp:port|none|,] +# [-a] -address [address|-]: same as address option +# [-n] -nameserver [group|-]: same as nameserver option +# [-p] -ipset [ipset|-]: same as ipset option +# [-t] -nftset [nftset|-]: same as nftset option +# [-d] -dualstack-ip-selection [yes|no]: same as dualstack-ip-selection option +# -no-serve-expired: ignore expired domain +# -delete: delete domain rule +# -no-ip-alias: ignore ip alias +# -no-cache: ignore cache + +# collection of domains +# the domain-set can be used with /domain/ for address, nameserver, ipset, etc. +# domain-set -name [set-name] -type list -file [/path/to/file] +# [-n] -name [set name]: domain set name +# [-t] -type [list]: domain set type, list only now +# [-f] -file [path/to/set]: file path of domain set +# +# example: +# domain-set -name domain-list -type list -file /etc/smartdns/domain-list.conf +# address /domain-set:domain-list/1.2.3.4 +# nameserver /domain-set:domain-list/server-group +# ipset /domain-set:domain-list/ipset +# domain-rules /domain-set:domain-list/ -speed-check-mode ping + +# set ip rules +# ip-rules ip-cidrs [-ip-alias [...]] +# rules: +# [-c] -ip-alias [ip1,ip2]: same as ip-alias option +# [-a] -whitelist-ip: same as whitelist-ip option +# [-n] -blacklist-ip: same as blacklist-ip option +# [-p] -bogus-nxdomain: same as bogus-nxdomain option +# [-t] -ignore-ip: same as ignore-ip option + +# collection of IPs +# the ip-set can be used with /ip-cidr/ for ip-alias, ignore-ip, etc. +# ip-set -name [set-name] -type list -file [/path/to/file] +# [-n] -name [set name]: ip set name +# [-t] -type [list]: ip set type, list only now +# [-f] -file [path/to/set]: file path of ip set +# +# example: +# ip-set -name ip-list -file /etc/smartdns/ip-list.conf +# bogus-nxdomain ip-set:ip-list +# ip-alias ip-set:ip-list 1.2.3.4 +# ip-alias ip-set:ip-list ip-set:ip-map-list \ No newline at end of file diff --git a/apps/smartdns/latest/docker-compose.yml b/apps/smartdns/latest/docker-compose.yml new file mode 100644 index 00000000..02f6e569 --- /dev/null +++ b/apps/smartdns/latest/docker-compose.yml @@ -0,0 +1,18 @@ +version: '3' +services: + smartdns: + container_name: ${CONTAINER_NAME} + restart: always + networks: + - 1panel-network + ports: + - "${PANEL_APP_PORT_HTTP}:53/udp" + volumes: + - "./data:/etc/smartdns" + image: pymumu/smartdns:latest + labels: + createdBy: "Apps" + +networks: + 1panel-network: + external: true diff --git a/apps/smartdns/logo.png b/apps/smartdns/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..896eb4f567705cdfe55ecb1f20c3b839ba79a12a GIT binary patch literal 15953 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 literal 0 HcmV?d00001