通过 iptables 在同一个端口根据源地址解复用(demux)

现在遇到一个场景,原来的一个服务只给一个客户端用,但现在增加了一个客户端,由于客户端配置相同,但是服务端需要区别对待两个客户端的服务端配置,所以利用 iptables 根据源地址做了一个端口转发,实现了 demux 。 假设:服务器在 192.168.0.1 ,客户端分别在 192.168.0.2 和 192.168.0.3 。客户端配置的服务端地址是 192.168.0.1:8000 。之前,在服务器上只跑了一个服务,监听着 8000 端口。 现在,在服务器上再跑一个服务,监听 8001 端口,同时根据需求进行相应的配置。然后,加上如下 iptables 规则: $ sudo iptables -t nat -A PREROUTING -s 192.168.0.3 -d 192.168.0.1 -p tcp -m tcp --dport 8000 -j REDIRECT --to-ports 8001 这样,在不需要更改客户端的情况下,完成了需要的效果。

Read More

升级 MongoDB 到 4.0

MongoDB 4.0 刚刚发布,加入了我很想要的 Transaction 功能。不过,我一更新就发现 MongoDB 起不来了。研究了一下日志,发现由于我创建数据库时,MongoDB版本是 3.4 ,虽然后来升级到了 3.6 ,但还是用着 3.4的兼容模式。这个可以这样来检测: $ mongo > db.adminCommand( { getParameter: 1, featureCompatibilityVersion: 1 } ) 如果不是 3.6, 升级到 4.0 之前,需要先执行如下操作: $ # MongoDB version 3.6 $ mongo > db.adminCommand( { setFeatureCompatibilityVersion: "3.6" } ) 然后再升级到 MongoDB 4.0 ,才能正常地启动 MongoDB 4.0 。之后可以考虑尝试使用 MongoDB 4.0 的 Transaction 了。不知道什么时候进入 Debian 的 stretch-backports 源中。 为了使用 MongoDB 4.0 的新特性,输入以下命令: $ mongo > db.adminCommand( { setFeatureCompatibilityVersion: "4.0" } ) 之后会尝试一下 MongoDB 4.

Read More

Wireguard 隧道搭建

随着 Wireguard Go 版本的开发,在 macOS 上起 WireGuard Tunnel 成为现实。于是,搭建了一个 macOS 和 Linux 之间的 WireGuard Tunnel。假设 Linux 端为服务端, macOS 端为客户端。 macOS端: $ brew install wireguard-tools $ cd /usr/local/etc/wireguard $ wg genkey > privatekey $ wg pubkey < privatekey > publickey $ vim tunnel.conf [Interface] PrivateKey = MACOS_PRIVATE_KEY [Peer] PublicKey = LINUX_PUBLIC_KEY # Generated below AllowedIPs = 192.168.0.0/24 Endpoint = LINUX_PUBLIC_IP:12345 $ vim up.sh #!/bin/bash # change interface name when necessary sudo wireguard-go utun0 sudo wg setconf utun0 tunnel.

Read More

Verilog 初体验

自己以前一直对硬件方面没有接触,但是大二大三很快就要接触相关知识,所以自己就先预习一下 Verilog HDL,以便以后造计算机。听学长们推荐了一本书叫《自己动手写CPU》,由于自己手中只有很老的 Spartan-3 板子,手上没有可以用来试验的 FPGA ,所以选择用 Verilog + Verilator 进行模拟。既然是模拟,自然是会有一定的问题,不过这个以后再说。 然后就是模仿着这本书的例子,写了指令的获取和指令的解码两部分很少很少的代码,只能解码 ori (or with immidiate) 这一个指令。然后,通过 verilator 跑模拟,输出 vcd 文件,再用 gtkwave 显示波形,终于能够看到我想要的结果了。能够看到,前一个时钟周期获取指令,下一个时钟周期进行解码,出现了流水线的结果。这让我十分开心。 接下来就是实现一些基本的算术指令,然后讲计算的结果写入到相应的寄存器中。这样做完之后,就可以做一个基于 verilator 的简易 A+B 程序了。 我的代码发布在jiegec/learn_verilog中。最近马上到考试周,可能到暑假会更频繁地更新吧。

Read More

在 ArchLinux 上编译 LineageOS for Huawei Angler

实践了一下如何在 ArchLinux 上编译自己的 LineageOS 。本文主要根据官方文档 进行编写。 $ # for py2 virtualenv and running x86 prebuilt binaries(e.g. bison) $ sudo pacman -Sy python2-virtualenv lib32-gcc-libs $ mkdir -p ~/bin $ mkdir -p ~/virtualenv $ # build script is written in python 2 $ cd ~/virtualenv $ virtualenv2 -p /usr/bin/python2 py2 $ mkdir -p ~/android/lineage $ curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo $ chmod a+x ~/bin/repo $ vim ~/.config/fish/config.fish set -x PATH ~/bin $PATH set -x USE_CCACHE=1 $ exec fish -l $ cd ~/android/lineage $ repo init -u https://github.

Read More

编写 eBPF 程序和利用 HyperLogLog 统计包的信息

前段时间在写概率论与数理统计的期末论文,讨论的主题是如何对一个十分巨大的多重集合(或者是流)中相异元素个数进行估计,写的是 HyperLogLog 等算法。联想到前段时间 LWN 上多次提到的 eBPF 和 BCC 的文章,我准备自己用 eBPF 实现一个高效的估计 inbound packet 中来相异源地址的个数和 outbound packet 中相异目的地址的个数。经过了许多的尝试和努力,最终是写成了 jiegec/hll_ebpf ,大致原理如下: 由于 eBPF 是一个采用专用的 bytecode 并且跑在内核中的语言,虽然我们可以用 clang 写 C 语言然后交给 LLVM 生成相应地 eBPF bytecode ,但仍然收到许多的限制。而且,我很少接触 Linux 内核开发,于是在找内核头文件时费了一番功夫。首先是核心代码: struct bpf_map_def SEC("maps") hll_ebpf_out_daddr = { .type = BPF_MAP_TYPE_PERCPU_ARRAY, .key_size = sizeof(u32), .value_size = sizeof(u32), .max_entries = 256, .pinning = 2 // PIN_GLOBAL_NS }; SEC("out_daddr") int bpf_out_daddr(struct __sk_buff *skb) { u32 daddr = get_daddr(skb); u32 hash = Murmur3(daddr, 0); update_hll(&hll_ebpf_out_daddr, hash); return 0; } 首先是声名一个类型为 PERCPU_ARRAY 的 eBPF MAP 类型。这里的 MAP 不是字典,Array 才是真是的数据结构,只不过提供的 API 是类似于字典的。 SEC 宏则是指定这个东西要放在哪一个段,这个在后面会提到。这个函数的作用就是,获取 IP 包的目的地址(其实应该判断一下是否是 IPv4的),然后根据 HyperLogLog 的要求,进行哈希(这里采用的是 Murmur3),然后对得到的哈希值分段,前一部分用于索引,后一部分的 nlz (clz, whatever)用于估计。具体算法详情可以参考 HyperLogLog 的论文。

Read More

调整 Nginx 和 PHP 的上传文件大小限制

之前迁移的 MediaWiki ,有人提出说无法上传一个 1.4M 的文件。我去看了一下网站,上面写的是限制在 2M ,但是一上传就说 Entity Too Large,无法上传。后来经过研究,是 Nginx 对 POST 的大小进行了限制,同时 PHP 也有限制。 Nginx 的话,可以在 nginx.conf 的 http 中添加,也可以在 server 或者 location 中加入这么一行: client_max_body_size 100m; 我的建议是,尽量缩小范围到需要的地方,即 location > server > http 。 在 PHP 中,则修改 /etc/php/7.0/fpm/php.ini : post_max_size = 100M 回到 MediaWiki 的上传页面,可以看到显示的大小限制自动变成了 100M ,这个是从 PHP 的配置中直接获得的。

Read More

最近写 Node.js 遇到的若干坑

最近在做前后端分离,前端在用 Vue.js 逐步重写,后端则变为 api 的形式。同时,我尝试了用 autocannon 和 clinic 工具测试自己的 api endpoint 的性能,一开始发现有几个延迟会特别高,即使是一个很简单的 api 也有不正常的高延迟。 于是,我用 clinic 生成了 flamegraph ,发现了一些问题: 我在 session 里保存了一些缓存的信息,这部分内容比较大, express-session 在保存到数据库前会先 JSON.stringify 再 crc 判断是否有改变,如果有改变则保存下来。但是由于我的这个对象嵌套层数多,所以时间花得很多。我调整了这个对象的结构,缩小了很多以后,果然这部分快了很多 有一个 API 需要大量的数据库查询,原本是 O(结点总数)次查询,我考虑到我们数据的结构,改成了O(深度),果然快了许多 之前遇到一个小问题,就是即使我没有登录,服务器也会记录 session 并且返回一个 cookie 。检查以后发现,是 connect-flash 即使在没有使用的时候,也会往 cookie 中写入一个空的对象,这就导致 express-session 认为需要保存,所以出现了问题。解决方案就是,换成了它的一个 fork : connect-flash-plus ,它解决了这个问题

Read More

在 Nginx 将某个子路径反代

现在遇到这么一个需求,访问根下面是提供一个服务,访问某个子路径(/abc),则需要提供另一个服务。这两个服务处于不同的机器上,我们现在通过反代把他们合在一起。在配置这个的时候,遇到了一些问题,最后得以解决。 upstream root { server 1.2.3.4:1234; } upstream subpath { server 4.3.2.1:4321; } server { listen 443 ssl; server_name test.example.com; # the last slash is useful, see below location /abc/ { proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; # the last slash is useful too, see below proxy_pass http://subpath/; } location / { proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_pass http://root; } } 由于并不想 subpath 他看到路径中 /abc/ 这一层,导致路径和原来在根下不同,通过这样配置以后,特别是两个末尾的斜杠,可以让 nginx 把 GET /abc/index.

Read More

向 Nexus 6P 中刷入 LineageOS 实践

Nexus 6P 自带的系统没有允许 Root ,所以需要自己解锁 bootloader 并且刷上别的系统。我选择了 LineageOS 。Nexus 6P 的代号为 angler, 首先可以找到官方的安装教程。 我们需要下载的东西: $ wget https://mirrorbits.lineageos.org/full/angler/20180521/lineage-15.1-20180521-nightly-angler-signed.zip $ wget https://mirrorbits.lineageos.org/full/angler/20180521/lineage-15.1-20180521-nightly-angler-signed.zip?sha256 -O lineage-15.1-20180521-nightly-angler-signed.zip.sha256 $ wget https://mirrorbits.lineageos.org/su/addonsu-15.1-arm64-signed.zip $ wget https://mirrorbits.lineageos.org/su/addonsu-15.1-arm64-signed.zip?sha256 -O addonsu-15.1-arm64-signed.zip $ wget https://github.com/opengapps/arm64/releases/download/20180527/open_gapps-arm64-8.1-full-20180527.zip $ wget https://github.com/opengapps/arm64/releases/download/20180527/open_gapps-arm64-8.1-full-20180527.zip.md5 $ wget https://dl.twrp.me/angler/twrp-3.2.1-0-angler.img $ wget https://dl.twrp.me/angler/twrp-3.2.1-0-angler.img.asc $ wget https://dl.twrp.me/angler/twrp-3.2.1-0-angler.img.md5 $ gpg --verify *.asc $ md5sum -c *.md5 $ sha256sum -c *.sha256 其中 Open GApps 可以自己考虑选择 full 还是其它的选择。 接下来,按照教程,先解锁 bootloader 。连接手机,进入 USB Debugging Mode ,重启进入 bootloader 并且解锁:

Read More