维护一个 WordPress 网站确实比较麻烦,需要配置 PHP 和 MySQL 等一系列环境。 虽然我一直“裸奔”多年,但始终担心安全漏洞问题。最近尝试了 Docker 和 docker-compose,虽然简化了部署过程,但 PHP 和 WordPress 的升级仍然让人头疼。 于是,我开始寻找替代方案。考虑到我的博客更新频率较低,静态网页似乎是一 个不错的选择。在了解了各种静态网站生成器后,我最终选择了 Hugo. Hugo 能够将 Markdown 文件转换为静态网页,然后可以部署在任何服务器上,例如 GitHub Pages。这对于我来说非常方便。 然而这个东西也有一些缺点,从Wordpress导出不是很方便,另外文档、主题 都不是很完善,我还去问了一下Gemini有什么其他的替代方案,它选的其他两个 一个是基于ruby的Jekyll,一个是基于nodejs的Hexo,都不是很喜欢,所以还是选了基于golang的Hugo。 Gemini总结的还是比较到位的: 优点: 速度极快,使用 Go 语言编写,性能优秀。 功能强大,支持各种高级特性。 拥有丰富的文档和社区。 缺点: 学习曲线可能稍陡峭,需要一定的技术基础。 主题数量可能不如 Jekyll 丰富。
翻墙回国:Linux单臂路由和透明代理-细节
上篇讲了讲原理,这个文章记录一下细节。 一、远程服务器 腾讯Cloud现在有活动,99一年,500G月流量。装shadowsocks-libev和dnsmasq. shadowsocks是代理服务器,dnsmasq提供中国境内的DNS解析。 # dnsmasq.conf port=7753 bind-interfaces Config.json for shadowsocks { "server": "0.0.0.0", "server_port": 7788, "password": "ABCDefghijklmnopq", "method": "chacha20-ietf-poly1305", "timeout": 600, "no_delay": true, "mode": "tcp_only" } 二、本地Linux 首先Enable routing:然后sysctl -p使之生效 # /etc/sysctl.conf net.ipv4.ip_forward=1 创建一个所有中国IP的ipset: curl 'http://ftp.apnic.net/apnic/stats/apnic/delegated-apnic-latest' | grep ipv4 | grep CN | awk -F\| '{ printf("%s/%d\n", $4, 32-log($5)/log(2)) }' > chnroute.txt sudo ipset create chnroute hash:net cat chnroute.txt | sudo xargs -I ip ipset add chnroute ip 设置所有的中国IP都转发到本机的7892端口,clash的redir端口。 # 在 nat 表中创建新链 iptables -t nat -N SHADOWSOCKS # X.X.X.X 是远程shadowsocks的地址,不用转发它,否则该死循环了 iptables -t nat -A SHADOWSOCKS -d X.X.X.X -j RETURN # 局域网地址 iptables -t nat -A SHADOWSOCKS -d 0.0.0.0/8 -j RETURN iptables -t nat -A SHADOWSOCKS -d 10.0.0.0/8 -j RETURN iptables -t nat -A SHADOWSOCKS -d 127.0.0.0/8 -j RETURN iptables -t nat -A SHADOWSOCKS -d 169.254.0.0/16 -j RETURN iptables -t nat -A SHADOWSOCKS -d 172.16.0.0/12 -j RETURN iptables -t nat -A SHADOWSOCKS -d 192.168.0.0/16 -j RETURN iptables -t nat -A SHADOWSOCKS -d 224.0.0.0/4 -j RETURN iptables -t nat -A SHADOWSOCKS -d 240.0.0.0/4 -j RETURN # 所有的中国IP去本机7892端口 iptables -t nat -A SHADOWSOCKS -p tcp -m set --match-set chnroute dst -j REDIRECT --to-ports 7892 # 把这个Chain放在PREROUTING里 iptables -t nat -I PREROUTING -p tcp -j SHADOWSOCKS 设置clash代理 ...
翻墙回国:Linux单臂路由和透明代理-概述
最近折腾家里的网络,主要解决的问题是国内各大视频音乐网站都有IP限制,无法观看。这个其实unblock youku插件在桌面可以解决,但是在手机上就不行了。于是进阶的方案是在国内买个VM,然后弄个http/socks proxy。这个方案的缺点是得给每个设备手动指定代理,而且国外的网站又不想走代理(会被墙!),自动选择代理的pac脚本也不是所有的设备都支持。所以就只剩最复杂的方案,透明代理。原则上来说,就是在家里的某个路由器上折腾一下,把所有的国内流量通过代理送过去,其他的流量走原来的路线。 透明代理 透明代理的原理是Linux Kernel提供的一个功能。它可以把符合某个条件的报文直接转发到一个端口,由软件来处理。这样的话,我们就可以把所有的中国IP都直接转发给本机的一个本地代理,然后本地代理转发给一个国内的远程代理,这样这个请求就看起来像国内的IP了。如果流量不是问题,这个其实实现起来非常简单,通过IPSET可以把所有的中国IP都包含在内,然后直接全部转发。只是很多网站是视频网站,我的国内虚拟机每月只有500G,可能不是很够,所以最好能像unblock youku一样,只是认证过程走国内流量,播放部分继续直接走默认路由。 代理选择 一开始我研究了squid。这个是上个世纪就存在的代理了。它可以缓存网页来达到加速效果,但是在https横行的世界,缓存并没有什么用。当然,有的代理(mitmproxy,Man In The Middle Proxy)可以自动生成中间人证书,就可以查看每个SSL/TLS的流量是什么内容了(这个将来也许可以用来做家长控制)。我折腾了很久的squid,就是不能让它集联起来,本地代理死活不去找远程代理。另外一种是著名的翻墙软件shadowsocks(ss),我这个其实应该不用那么复杂,因为并不需要隐藏内容,但是相关的软件实在多,所以我最后还是用了ss。普通的https proxy应该也是可以的。最后我的Client Proxy是clash,Server Proxy是shadowsocks-libev。Clash是一个中国小伙用go写的,可定制性高一些。 方案一 说到路由器,第一反应是搞open source的定制的ROM,比如OpenWRT。BTW DD-WRT已死,RIP。有人给OpenWRT做了一个shadowsocks的plugin,理论上就可以在路由器上配置哪些网站通过shadowsocks出去。这个显然是给国内翻墙出来用的。这个方案有这些问题: 路由器得可以烧OpenWRT。我家的不行。 还必须得搞某个国内大神自己编译的版本,才能有那个plugin,不是很靠谱。 直接在x86上装openwrt当纯路由——OpenWRT不太支持UEFI,然而新的电脑都是UEFI,所以根本无法启动。 OpenWRT是嵌入式软件,改动起来很麻烦,懒得搞cross compile那些。 Tomato之类的也都类似,放弃了。 方案二 既然OpenWRT不靠谱,那么找些专门的路由软件吧。这个比较著名的有pfSense,OPNSense之类的防火墙兼路由系统。这个也有问题: 都是基于FreeBSD的,缺少一个Linux Kernel提供的功能:iptables REDIRECT。 既然主业是防火墙,那应该站在modem和wifi中间,需要一个双网卡的机器,然而我不想去买个新机器。用某些VLAN的方案也许可以,但是setup也很麻烦。 方案三 最后的方案还是fallback到vallina Linux,并且手动设置它为路由器,还用iptables做了转发。一开始不想用这个的方法其实是不想手动设置这些,不过最后看来也不是很复杂。具体内容包括 设置Linux可以转发报文——这个只用改动一个内核配置就好了 用ipset和iptables设置所有的中国IP都REDIRECT到本机的代理端口 这个端口不是普通的proxy端口,必须是要能理解REDIRECT的端口。该服务要查询kernel询问原来的目的地才能做到转发,否则,这就是一个从device到本地代理的普通TCP链接请求,没有任何意义。这也是为什么必须用clash或者ss-redir(shadowsocks的一个组件),redsocks的原因。 本地代理根据某些规则,进一步决定是否要转发去上级代理(国内),还是自己直接链接服务器。比如我们想要youku.com的域名全部去国内的代理,但是其他的一些CDN就直连。这个只有clash做的比较好,可以定义规则。golang想加点东西也很容易。 本地代理从TCP上只能看到IP地址,如何知道其域名从而运行规则呢?当然我们可以做反向域名解析,但是这个太慢,而且不可靠。Clash做了两个黑科技。总体来说,它自带一个DNS,要求客户端链接它的DNS。这样客户端做了DNS解析后,它存一份在内存里,这样请求来了之后它就可以直接做内存里的反向查询。它还有一个叫fakeip的技术,就是每个DNS请求都返回一个不可路由的192.18.0.0/16的IP段地址,这样收到请求后它就可以一一对应IP和域名。当然,这个对于我这个只转发部分IP的情况不适用。 DNS还有另外一个问题,如果DNS解析发生在国外,如果该网站在国外有分舵(bilibili在LA就有),那么问题根本没有解决。所以要求中国的域名要发到中国的解析。还好Clash也有支持,虽然它是设计来给国内用的,但是也可以解决我们的问题:在fallback-filter.domains里面列出要去backup nameserver的,就可以了。支持域名后缀。 接下来应该设置DHCP服务器,让所有的设备的网关和DNS都指向这个Linux,它就成了一个软件路由器。它的下级是原先的真·网关。可以在原有路由器的DHCP上改,或者直接关闭,在Linux上配置一个DHCP服务器。我们家的路由器即不能改DHCP,也不能将其关闭,只能手动一个一个设置静态IP了?。打算扔了重新买个。 其他的一些问题 IPV6 这个目前并没有好好支持,但是好在中国的网站支持ipv6的也不多。加上应该也不是很困难,原理是一样的。等IPv6再普及一些吧。 IPTables/ipset vs nftables 新的nftables应该可以替代iptables/ipset,但是现在这个规则也比较简单,以后再说了。。 这个是概述,下一篇写写具体的设置,命令。 参考 http://ivo-wang.github.io/2018/02/24/ss-redir/ https://0x01.io/2017/04/01/x86-软路由透明代理构建方案/
Keygen for an android wireframe app
hack过几个Java的程序,发现他们的生产license key的方法几乎都一样,难道是用了什么library。大家的通用方法就是把用户信息用key=value的形式弄成一个文本,然后用privatekey签名。程序里面就是一个public key,验证这个签名。有趣的是,大家都会用GZIP之类的方式压缩,然后再Base64。可以反思一下怎么样更好的防止hack。。 keygen很简单,覆盖掉public key: keytool -genkeypair -keyalg DSA -alias mykey -keystore k.jks keytool -exportcert -keystore k.jks -alias mykey -file ccc.cer 然后,Keygen using groovy: import java.util.zip.* import java.security.* import java.security.cert.* str="""email=who@know.com issueDate=19/09/2013 maintenanceYears=99 quantity=99 registeredTo=Joe Doe """ KeyStore ks = KeyStore.getInstance("JKS"); ks.load(new FileInputStream("k.jks"), "hahaha".toCharArray()) KeyStore.ProtectionParameter protParam = new KeyStore.PasswordProtection("hahaha".toCharArray()); def pk = pkEntry = ks.getEntry("mykey", protParam).getPrivateKey(); Signature s = Signature.getInstance("SHA1withDSA") s.initSign(pk) s.update(str.getBytes()) sig = s.sign().encodeBase64() o=new ByteArrayOutputStream() m=new GZIPOutputStream(o) full = str + "__signature__=" + sig + "\n" println full m.write(full.getBytes()) m.close() b=o.toByteArray().encodeBase64() println b
Random password
对市面上的random password管理器不是很放心,还是自己写一个来的安心。 生成器: #!/usr/bin/python import random,sys SPECIAL='~_+`-=!@#$%^&*(){}|\][:;<>,.?/' PRINT='asdfghjklqwertyuiopzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890' def get_next(s): return s[random.randrange(0, len(s))] length=15 if (len(sys.argv) ==2): length=int(sys.argv[1]) p='' for i in range(length): if random.random() > 0.8: p += get_next(SPECIAL) else: p += get_next(PRINT) print '' print p print '' 管理器 #!/usr/bin/python import os, sys, keyring, getpass, subprocess, shlex cmd_dir = os.path.dirname(sys.argv[0]) tmp_file = '%s/pwtmp' % (cmd_dir) option = '' if len(sys.argv) > 1: option = sys.argv[1] passwd = keyring.get_keyring().get_password("masterpw","sma").encode('ascii') enc_cmd='openssl aes-256-cbc -a -salt -in %s -out %s/pw.enc -pass pass:%s' % (tmp_file, cmd_dir, passwd) dec_cmd='openssl aes-256-cbc -d -a -salt -in %s/pw.enc -pass pass:%s' % (cmd_dir, passwd) dec_cmd_file='openssl aes-256-cbc -d -a -salt -in %s/pw.enc -out %s -pass pass:%s' % (cmd_dir, tmp_file, passwd) def my_exec(cmd): args = shlex.split(cmd) p = subprocess.Popen(args) ret = p.wait() if ret != 0: raise "Failed to exec %s" % cmd if option != 'edit': p = subprocess.Popen(shlex.split(dec_cmd), stdout=subprocess.PIPE) for l in p.stdout.readlines(): l = l.strip() if option: if l.lower().find(option) >= 0: print l else: print l elif option == 'edit': my_exec(dec_cmd_file) my_exec('vi ' + tmp_file) my_exec(enc_cmd) my_exec('rm ' + tmp_file) my_exec('scp %s/pw.enc shawnma.com:' % cmd_dir)
Re-engineering a java plugin
最近有一个软件,一切都挺好用的,就是不支持我们公司的版本控制系统。只有商业版才支持——但是只为了这么一个plugin就去买个商业版太亏了。所以就搞了一点手脚,扒了一个plugin出来,记录一下。 简单的安装那个plugin,失败:需要商业版本 unzip plugin.jar:很显然的有一个Verifier.class看起来很扎眼,反编译一下,里面在做一些类似RSA之类的计算。果断改编之,使其成为一个空方法。 plugin.xml是一个描述文件,里面写了depends on商业版,去掉。 再启动,有一个Verifier相关class找不到。这个软件使用pico作为container,作为constructor来说,有个很奇怪的class需要resolve dependency。还好这个class的接口很小,写一个空的class(反正verifier也是空的),然后在原有class上派生一个新的plugin class,直接new这个class给父类的constructor,这样,pico就只需要resolve剩余的三个dependency。。 一切看起来就ok了。最后的问题是,这个plugin引用了商业版某个实现类的一个XXXImpl.DEBUG的字段(真糟糕)。没办法,只好用javassist搞免费版本的class,给他强行加一个DEBUG字段: import javassist.*; cp = ClassPool.getDefault() cp.appendClassPath('/Applications/my.app/lib/pro.jar') c = cp.get("com.i.o.v.ChangeListManagerImpl") debug = new CtField(CtClass.booleanType, "DEBUG", c) debug.setModifiers(Modifier.PUBLIC|Modifier.STATIC) c.addField(debug) b = c.toBytecode() new FileOutputStream("A.class").write(b) 在重新package这个jar,搞定。so far so good..
priceline 竞标失败
实在是太可恶了,本来想同感priceline bid一个酒店,但是结果感觉是被骗了,记录一下。 有一个垃圾3.5星的酒店,趴在69这个价格上,我一路从60升到69,就中了,结果仔细一看,丫每天收15块的停车费,你妹美国哪有酒店收停车费的,69+15=84块一晚老子可以定4星了。不过,LA的酒店相比还是比较贵一点点的…… 总结一下: bid前要仔细研究某个区域里的所有酒店,如果有明显不好的,宁可放弃整个区域,或者去hotwire直接定。 太早定也可能没有很好的价格,据说需要自己定一个价格然后每天去bid几次。69相比其他人定的还是偏高。 betterbidding是个不错的网站。
烧一下Moto Defy (MB525)
很久没写东西,来这里除草。 搞过几个android手机,一只HTC Desire,一只Sumsung Galaxy S2 Skyrocket,今天终于把老婆的联通版MB525给烧成了CM9(的某个RC版本)。记录一下,以免以后忘了,也给有意理解如何hack MB525的同学做个参考。 首先,所有的信息的最权威版本来自xda,这个xda的beginner guide很有效。另外有一个中文版的yeeyan网的翻译,在这里。 综述如下: 第一步是下载moto的驱动。很容易找到,不多废话。小心32和64位的区别。 第二步就是获取手机的root权限。下载super oneclick root就可以解决这个问题。搞完之后,用adb shell(adb是android sdk的一个程序,不过super one click里有一个最小的版本)就可以进入手机的shell,并且经过su就可以是root了。 Moto手机的bootloader是锁死的,无法更新,有好处也有坏处——好处是几乎永远不会把手机变成砖(HTC就有这个可能性)。坏处是,它对签名什么的检查比较严格,搞一个custom的ROM有点困难,不像HTC/Samsung那么简单。 第三步:不过还是有聪明人的。有人发明了2nd init,这个东西具体怎么工作我还没仔细搞明白,不过它可以在bootloader启动原装的kernel之后,装载这个2nd init,这样就可以启动custom的recovery,或者启动一个custom ROM. 2nd init是一个apk文件,在root之后装上,运行,就好了。 moto还有一个诡异的东西,叫efuse,让系统一旦升级后无法降级。这个麻烦的地方是有时候如果你还想返回原厂rom去保修的话,可能有点困难,所以要小心。不过对于我这样完全放弃保修的人,也无所谓——而且我根本没用moto的刷机包。 第四步:搞到需要装的ROM。网上很多人说要刷底包什么的,其实不是必须的。底包就是为一个新的baseband的,其他的东西没什么用处。我搞了最新的CM9的RC0版本,外加一个CM9需要的kernel,外加一个google app的包(版权问题)。把他们放在SD卡上 第五步:重启,自动进入2nd init,引导进入一个叫bootmenu的小程序,然后可以进入recovery,刷那些zip file,就好了。它刷system区的方法只是格式化,并且把文件拷过去,所以不会触发efuse。 wipe data, wipe cache, reboot,yeah~~~android ICS for defy。。不过似乎稍微有点不稳定,死机一次,自动重启一次。也许要downgrade到CM7.1去。不过,我总是不太信任国内的同志们做的东西,怕里面有什么malware。 重申:刷底包的那些SBF似乎不是必须的,我的baseband还是联通自带的那个版本。 PS,我的手机是红镜头,刷完之后变成了MB526 defy+。
Reloaded
把机器弄到新的VPS server——没办法,搬家过程中,没有网络,只能租一个地方来放点东西。便宜倒是挺便宜,只是OpenVZ做的VPS不够稳定,有一次稀里糊涂的硬盘空间就没了,还有长达半个月的时间里,php fastcgi的进程总是莫名其妙的被kill -9。今天灵光一闪,搞来php-fpm,才算稳定下来。另外有时候还一顿一顿的,就像java VM里面的GC一样。内存只有512M,没有swap(也不能有,OpenVZ的限制),Sun的java虚拟机根本启动不了,没有足够的内存。好在我们还有JRockit。加上jetty(还试过winstone,不过也没啥太好的效果),内存70M左右。。。总之,所谓便宜没好货,还是Xen的好一点。 又回到美国,跟10年前的感觉还是不一样的。有空跟大家八卦八卦……
Smooth gallery patch for NextGen
NextGen gallery号称是wordpress最好的相册管理插件,不过它的显示实在不敢让人恭维,真的是很难看。找了一圈,发现原来还要在plugin上再加plugin来显示。基于javascript之类的显示plugin倒是挺多的,比如有个nextgen scroll gallery, jj nextgen-jquery-slider,不过都有一些问题,最大的问题,对于我来说,就是不能处理不同大小的图片,要么被crop了,要么就比例不对,scale错了。最后找到一个人,对现有的nextgen smooth gallery plugin做了一个patch,可以自动适应图片的大小!这很不错,于是把他的那个patch合并到smooth gallery viewer里面去,还顺便把smooth gallery的版本升级到2.1beta,附带fix一个在当前页打开图片的bug,结果就是这么一个新的plugin,放在这里,万一有人需要… 注意这个东西和jquery冲突(它使用一个叫mootools的library),所以在配置里一定要选上使用iframe,否则根本没法显示。来观赏一下我家小妞最新的成长吧..