systemctl简易教程

systemctl是目前几个主流linux都推荐的服务管理工具,这里记录一下systemctl的实用教程。本教程基于 Ubuntu 20 系统。 什么是systemctrl systemctl是目前几个主流linux都推荐的服务管理工具,它提供了统一的管理linux守护进程的接口。 在systemctl之前,我们习惯于使用service来管理服务,目前,Ubuntu中已经将大部分的service重定向到systemctl了,这意味着,如果你在Ubuntu上修改/etc/init.d/中的服务脚本(也就是service加载的那些服务),会发现没有什么作用。查看脚本一般可以看到这样一条语句:. /lib/lsb/init-functions,在这个子程序中,命令被重定向为使用systemctl了。 如何使用 很简单: systemctl <command> <service> 其中,service为具体的服务名称,command为要对此服务进行的操作,常见的有: start:启动 stop:停止 restart:重新启动 enable:设置开机自启 disable:取消开机自启 如何自定义一个服务 自定义的服务,都位于/usr/lib/systemd/system下,一般以.service为后缀。 我们可以自建一个xxx.service文件,这就对应了一个自建的服务,文件名就是服务名。 service文件实际上是对此服务的一个配置文件,我们可以参考一下其他的配置。这里我们参考一下nginx的配置: [Unit] Description=A high performance web server and a reverse proxy server Documentation=man:nginx(8) After=network.target [Service] Type=forking PIDFile=/run/nginx.pid ExecStartPre=/usr/local/nginx/sbin/nginx -t -q -g 'daemon on; master_process on;' ExecStart=/usr/local/nginx/sbin/nginx -g 'daemon on; master_process on;' ExecReload=/usr/local/nginx/sbin/nginx -g 'daemon on; master_process on;' -s reload ExecStop=-/sbin/start-stop-daemon --quiet --stop --retry QUIT/5 --pidfile /run/nginx.pid TimeoutStopSec=5 KillMode=mixed [Install] WantedBy=multi-user.target 可以看到,配置文件分了几个部分。 Unit部分,定义了服务的基本信息,其中After比较重要,定义了服务的依赖顺序,也就是当前服务应该依赖哪个服务。 Service就是服务的具体定义了,我们说明几个关键项: Type:进程类型,常用的选择有: simple:认为ExecStart命令的主进程就是服务进程,ExecStart命令会在服务进程结束后才退出。也就是说,如果你的ExecStart命令在服务进程结束之前退出的话(参见forking的情形),你会发现systemctl会在ExecStart命令退出后主动杀死服务进程。 forking:认为ExecStart命令只是一个单纯的启动命令,服务进程是由ExecStart命令fork出去的,且ExecStart命令的主进程会在服务进程启动后退出。 PIDFile:存储进程号的文件 ExecStart:启动命令,对此命令会有一些要求,参见Type配置项 Install部分,在WantedBy中定义了服务应该在哪个启动级别下加载。 完整的配置文件的说明,可以参见这篇文档。 注意,如果你修改了一个服务配置文件,你需要调用systemctl daemon-reload来重新加载所有的服务。 如何令服务开机启动 systemctl enable <service> 此命令实际上是在/etc/systemd/system/下对应服务启动级别的目录里,创建一个软链,指向/lib/systemd/system/<service>。系统启动时,会从/etc/systemd/system/下对应当前启动级别的目录里,加载所有的服务配置并按照依赖顺序拉起它们。 注意:网上某些文章说,自定义开机自启服务只要在/etc/systemd/system/下创建对应的服务配置文件就可以了。这种方法其实是不正确的!应该按照上述方法,在/lib/systemd/system/下创建服务文件,在通过systemctl enable来把它加载进/etc/systemd/system/中。

轨道动力学学习笔记

最近在玩kOS,为了鼓捣出自动化的任务代码,开始学习一些浅显的轨道动力学。 Textbook Rocket and Space Technology 基本的数学约定 坐标系和坐标系变换 我们使用右手笛卡尔坐标系,即右手大拇指指向$X+$、食指指向$Y+$、掌心朝向$Z+$。 我们约定如下的旋转矩阵:$\mathbb{R}_x(\theta)$、$\mathbb{R}_y(\theta)$、$\mathbb{R}_z(\theta)$分别表示向$X$、$Y$、$Z$负方向看去时绕该轴逆时针旋转$\theta$角度的旋转矩阵,于是有: \[\mathbb{R}_x(\theta) = \left( \begin{array}{} 1 & 0 & 0 \\ 0 & \cos{\theta} & -\sin{\theta} \\ 0 & \sin{\theta} & \cos{\theta} \\ \end{array} \right)\] \[\mathbb{R}_y(\theta) = \left( \begin{array}{} \cos{\theta} & 0 & \sin{\theta} \\ 0 & 1 & 0 \\ -\sin{\theta} & 0 & \cos{\theta} \end{array} \right)\] \[\mathbb{R}_z(\theta) = \left( \begin{array}{} \cos{\theta} & -\sin{\theta} & 0 \\ \sin{\theta} & \cos{\theta} & 0 \\ 0 & 0 & 1 \end{array} \right)\] 对于地心赤道坐标系,我们一般定义为:原点$O$在地心处,$xOy$平面为赤道平面,$X$方向朝春分点,$Z$方向朝北极。 一般,在天球坐标系上,我们假设天球半径为$1$,在地球坐标系上,则假设地球半径为$1$。 公式4.33-4.37推导 为了记述方便,我们暂且记$\alpha = \Delta{\lambda}$,$\gamma = \frac{\pi}{2} - \beta$。在这个问题中,我们只关心天球坐标和在天球面上的方向,因此接下来我们所讨论的轨道、赤道等,都是指它们在天球上的投影,也就是说我们所讨论的轨道实际上是天球上的一个大圆。 首先,不妨假设这条轨道的升、降交点分别与秋、春分点重合,这样,轨道平面与赤道平面的交线即升、降交点的连线,就与秋、春分点的连线重合,也就是$X$轴。 接下来,我们将轨道看做轨道由这样一个“初始轨道”变换而来:一条与赤道重合且燃尽点与秋分点$(1,0,0)$重合的大圆轨道。那么有两种变换途径均可达到目的: 第一种途径:先转向$l$,使得升交点到达秋分点,再绕轨道平面与赤道平面的交线即$X$轴旋转$i$,得到轨道倾角。即先绕$Z$轴旋转$l$,再绕$X$轴旋转$i$。变换矩阵为: \[\mathbb{R}_x(i) \cdot \mathbb{R}_z(l) = \left(\begin{array}{lll} \cos{l} & -\sin{l} & 0 \\ \cos{i} \cdot \sin{l} & \cos{i} \cdot \cos{l} & -\sin{i} \\ \sin{i} \cdot \sin{l} & \sin{i} \cdot \cos{l} & \cos{i} \end{array}\right)\] 第二,先绕燃尽点的法线方向旋转出燃尽点的方位角东偏北$\gamma$,注意由于此时燃尽点位于秋分点,因此燃尽点的法线方向即为$(1,0,0)$,然后仰角$\delta$,使燃尽点到达指定纬度,最后再转向$\alpha$,使得升交点到达指定位置,也使燃尽点到达指定经度。即先绕$X$轴旋转$\gamma$,然后绕$Y$轴旋转$-\delta$,最后绕$Z$轴旋转$\alpha$。变换矩阵为: \[\mathbb{R}_z(\alpha) \cdot \mathbb{R}_y(-\delta) \cdot \mathbb{R}_x(\gamma) = \left(\begin{array}{lll} \cos{\alpha} \cdot \cos{\delta} & -\cos{\alpha} \cdot \sin{\delta} \cdot \sin{\gamma} - \sin{\alpha} \cdot \cos{\gamma} & -\cos{\alpha} \cdot \sin{\delta} \cdot \cos{\gamma} + \sin{\alpha} \cdot \sin{\gamma} \\ \sin{\alpha} \cdot \cos{\delta} & -\sin{\alpha} \cdot \sin{\delta} \cdot \sin{\gamma} + \cos{\alpha} \cdot \cos{\gamma} & -\sin{\alpha} \cdot \sin{\delta} \cdot \sin{\gamma} - \cos{\alpha} \cdot \sin{\gamma} \\ \sin{\delta} & \cos{\delta} \cdot \sin{\gamma} & \cos{\delta} \cdot \cos{\gamma} \end{array}\right)\] 上面两个变换矩阵是相等的,因此9个元素两两相等,于是: 根据元素$(3,3)$相等,我们可以得到$\cos{i} = \cos{\delta} \cdot \sin{\beta}$,即公式4.33; 根据元素$(3,1)$相等,我们可以得到$\sin{l} = \frac {\sin{\delta}} {\sin{i}}$;根据元素$(3,2)$相等,我们可以得到$\cos{l} = \frac {\cos{\delta} \cdot \cos{\beta}} {\sin{i}}$;两式相除得到$\tan{l} = \frac {\tan{\delta}} {\cos{\beta}}$,即公式4.34; 根据元素$(2,1)$相等,我们可以得到$\sin{\alpha} = \frac {\cos{i} \cdot \sin{l}} {\cos{\delta}}$;根据元素$(1,1)$相等,我们可以得到$\cos{\alpha} = \frac {\cos{l}} {\cos{\delta}}$;两式相除得到$\tan{\alpha} = \frac {\cos{i}} {\tan{l}}$,即公式4.35。

在Ubuntu上配置OpenConnect

OpenConnect是一个开源的VPN软件,目前为止似乎只有它的原生版没有被河蟹,本文介绍一下如何在Ubuntu上搭建OpenConnect服务器,以及如何使用AnyConnect连接这个VPN。 书接上文,自从上次配了个服务器之后,没多久就发现服务器down了,查看日志发现VPN一连上就reset了,后来上论坛上看了一下,觉得应该是OpenVPN的特征包已经被GFW识别出了。#到了后来直接服务器都登不上了,GFW真狠……#。话说现在GFW已经不是曾经的那个GFW了,模式识别、机器学习行为分析……无所不用其极啊…… 但是,总要有人能翻墙吧,BAT和各大独角兽都给自己公司的内网搭设了专线VPN,上个Google、SO啥的完全不是问题,zf不可能封禁他们吧,不然这些公司怎么活?所以BAT用的翻墙软件咱们肯定能用,那BAT用啥呢,反正百度用的是Cisco的VPN————哦~原来BAT用的是Cisco的收费解决方案啊,这不是我们平民老百姓玩得起的啊…… 但是这时OpenConnect横空出世了,打倒Cisco大地主,帮我们翻身农奴得解放~OpenConnect最牛逼的一点就是它破解了Cisco的VPN协议,所以,我们可以用OpenConnect服务假冒Cisco的VPN服务,愉快地假装BAT翻墙。 说起来其实是一套服务,其实我们只需要搭建一个OpenConnect服务端就好了,毕竟人家Cisco卖的是服务端解决方案,客户端都是一摸一样的AnyConnect软件,不收钱的,我们只需要用Cisco官方的AnyConnect软件连接假冒成Cisco服务端的OpenConnect服务端,就算大功告成。 那么开始动手吧~ 搭建OpenConnect服务端ocserv 首先OpenConnect(以下简称OC)的服务端软件是叫做ocserv(官方repo在此),我们接下来其实都是在跟这个ocserv过不去。 本次实验所用的环境是DigitalOcean的5美元服务器,搭载 Ubuntu 16.04 系统。 准备SSL证书 OC用的是标准的TLS协议搭建隧道(现在Cisco还有专门的IPSec隧道协议,这一点OC还没能做到),因此我们的服务器需要一套SSL证书(密钥+证书),鉴于我们是穷人,自然是不可能花钱去申请这么一套证书的,所以我们还需要自己假扮证书颁发机构,这个机构又需要一套证书。 一套证书包括一个密钥和一个证书,其实就是一对非对称公私钥,私钥就是密钥,公钥就是证书。 我们使用certtool这个工具来生成SSL证书,这个工具发布在gnutls-bin这个包里,可以直接apt-get install -y gnutls-bin安装,安装完成后就可以直接使用certtool了。 证书颁发机构 首先生成证书颁发机构的密钥ca-key.pem: certtool --generate-privkey --outfile ca-key.pem 然后生成证书,证书需要一些签名信息,所以我们先创建一个模板文件ca.tmpl,其内容为: cn = "example-ca.com" organization = "example-ca.com" serial = 1 expiration_days = 3650 ca signing_key cert_signing_key crl_signing_key 然后就可以用上面的密钥结合这个模板文件中的信息,生成证书ca-cert.pem: certtool --generate-self-signed --load-privkey ca-key.pem --template ca.tmpl --outfile ca-cert.pem 至此我们就造出了一个证书颁发机构,它具有公开的证书ca-cert.pem,以及自己保密持有的密钥ca-key.pem。当然,由于我们这个颁发机构不在各大厂商(如微软、苹果等)的受信任机构列表中,所以实际使用的时候,客户端会提示我们说证书来自不受信任的颁发机构,这个时候当然是选择原谅他啦~ 服务端证书 然后生成服务器的证书,和上面一样的套路,同样是先生成私钥: certtool --generate-privkey --outfile server-key.pem 然后准备证书模板,这次的模板内容为: cn = "example-server.cm" organization = "example-server.com" expiration_days = 3650 signing_key encryption_key tls_www_server 然后创建证书,这次创建的证书是由上面的证书颁发机构颁发的,因此需要颁发机构的签名,创建的命令如下: certtool --generate-certificate --load-privkey server-key.pem --load-ca-certificate ca-cert.pem --load-ca-privkey ca-key.pem --template server.tmpl --outfile server-cert.pem 服务端证书就这么创建完啦~ 用户证书 有些情况下,每个用户也需要一个自己的证书(下面会具体说明),所以我们现在来创建一个用户证书,首先同样是生成私钥: certtool --generate-privkey --outfile zhangsan-key.pem 用户证书的创建模板如下: cn = "Zhang San" unit = "Google Inc." expiration_days = 365 signing_key tls_www_client 同服务器一样,用户证书也是由颁发机构颁发的,生成它的命令如下: certtool --generate-certificate --load-privkey zhangsan-key.pem --load-ca-certificate ca-cert.pem --load-ca-privkey ca-key.pem --template zhangsan.tmpl --outfile zhangsan-cert.pem 此外,AnyConnect支持导入的证书格式为PKCS12的格式,因此需要将密钥和证书一起打包成PKCS12格式的证书,命令如下: certtool --to-p12 --load-privkey zhangsan-key.pem --pkcs-cipher 3des-pkcs12 --load-certificate zhangsan-cert.pem --outfile zhangsan.p12 --outder 那么用户 Zhang San 的证书就创建好啦。 为了比较方便地为用户生成证书,我写了一个脚本gen_user_certs: #!/bin/bash echo "" > $1.tmpl echo "cn = $1" >> $1.tmpl echo "unit = $1" >> $1.tmpl echo "expiration_days = 3650" >> $1.tmpl echo "signing_key" >> $1.tmpl echo "tls_www_client" >> $1.tmpl certtool --generate-privkey --outfile $1-key.pem certtool --generate-certificate --load-privkey $1-key.pem --load-ca-certificate /etc/ocserv/certs/ca-cert.pem --load-ca-privkey /etc/ocserv/certs/ca-key.pem --template $1.tmpl --outfile $1-cert.pem certtool --to-p12 --load-privkey $1-key.pem --pkcs-cipher 3des-pkcs12 --load-certificate $1-cert.pem --outfile $1.p12 --outder chmod +x gen_user_certs赋予它可执行权限,然后运行gen_user_certs <username>即可,譬如: gen_user_certs wangwu 安装和配置ocserv Ubuntu的源里默认就有ocserv,因此直接用apt安装即可: apt-get install -y ocserv 安装完成后,应该会生成/etc/ocserv目录,其中有一个ocserv.conf配置文件,我们打开它,来配置ocserv,几条比较关键的配置如下: # 登陆方式,这里配置为使用证书登录 auth = "certificate" # 允许同时连接的客户端数量 max-clients = 4 # 限制同一客户端的并行登陆数量 max-same-clients = 2 # 服务监听的IP(也就是服务器的IP,可不设置,默认就是监听所有IP) listen-host = 1.2.3.4 # 服务监听的TCP/UDP端口 # 如果你不设置,默认端口都是443 # 但经过我的测试,似乎443端口登不上去,不知是不是墙的原因 tcp-port = 1234 udp-port = 1234 # 自动优化VPN的网络性能 try-mtu-discovery = true # 确保服务器正确读取用户证书(后面会用到用户证书) # 示例配置文件的注释中说可以填 2.5.4.3 或 0.9.2342.19200300.100.1.1 # 原配置文件默认已经填写了 0.9.2342.19200300.100.1.1 # 但经我测试这个是没法用的,必须要填 2.5.4.3 cert-user-oid = 2.5.4.3 # 服务器证书与密钥 server-cert = /path/to/server-cert.pem server-key = /path/to/server-key.pem # 证书颁发机构证书,用于验证用户证书是否受信 ca-cert = /path/to/ca-cert.pem # 客户端连上vpn后使用的dns dns = 8.8.8.8 dns = 8.8.4.4 # 注释掉所有的route,这样服务器就会转发所有的包; # 否则服务器只会转发目的网段在route之中的包。 #route = 192.168.1.0/255.255.255.0 # 启用cisco客户端兼容性支持 cisco-client-compat = true route可以配置多条,你可以把常用的banned网站的IP都通过route加进来,从而实现智能分流(不在route列表里的不走VPN),比如这位大神的配置:https://github.com/don-johnny/anyconnect-routes/blob/master/routes,但是很不幸,由于OpenConnect的原理所限,你不可能像socks那样直接配置域名甚至使用PAC。 不管因为什么原因,如果你不幸没有/etc/ocserv/ocserv.conf这个文件,可以去ocserv的repo上去下载sample.conf,然后在此基础上进行改动。 配置NAT转发 和OpenVPN相似,OpenConnect同样是基于网关转发的VPN模型,所以我们一样要配置VPN转发。在网上学习的时候我发现了一个神器ufw,它是Ubuntu上的防火墙管理工具,有了它就可以做iptables的大部分工作,同时它使用起来又比iptables简单。ufw是基于配置文件的,它的配置文件都在/etc/ufw目录下,配置好之后通过ufw reload命令重新加载。如果你是第一次使用,在reload前还需要通过ufw enable来开启ufw。 首先设置ufw的默认策略,修改/etc/default/ufw,把默认转发策略改成ACCEPT: DEFAULT_FORWARD_POLICY="ACCEPT" 然后开启IP转发,编辑/etc/ufw/sysctl.conf,根据你的需要,开启IPv4或IPv6: # 如果你不需要IPv4转发,注释掉下面这一行 net/ipv4/ip_forward=1 # 如果你不需要IPv6转发,注释掉下面这两行 net/ipv6/conf/default/forwarding=1 net/ipv6/conf/all/forwarding=1 我不确定是否还要编辑/etc/sysctl.conf,如果不行你可以试试编辑它,修改net.ipv4.ip_forward = 1,编辑好之后运行sysctl -p使设置生效。 然后添加转发条目,编辑/etc/ufw/before.rules,在末尾的COMMIT后加入如下配置: *nat :POSTROUTING ACCEPT [0:0] -A POSTROUTING -s 0.0.0.0/0 -o eth0 -j MASQUERADE COMMIT 关于这段配置,做几个小说明: 这个文件实际上就是在编辑iptables的规则 第一行*nat表示下面的规则属于nat这个表(还记得iptables的路由表概念吗) 第三行就是配置NAT转发,表示将来源于任何地址、发到eth0接口的包的源地址都修改为eth0的地址,-j MASQUERADE是一个神奇的语句,相当于-j SNAT --to 接口当前地址,可以自动查询接口的当前地址并NAT到这个地址上。所以如果你的服务器IP是固定的,也可以直接写成-j SNAT --to 123.123.123.123 关于iptables配置NAT,可以具体参见网上的文章,比如这篇 这些配置都做完之后,用ufw reload命令使其生效(如果你的ufw处于禁用状态,需要先ufw enable启用之)。 配置完之后可以查看一下iptables的规则,看是不是符合意愿,使用命令iptables -t nat -L查看nat表的规则,我的结果如下: Chain PREROUTING (policy ACCEPT) target prot opt source destination Chain INPUT (policy ACCEPT) target prot opt source destination Chain OUTPUT (policy ACCEPT) target prot opt source destination Chain POSTROUTING (policy ACCEPT) target prot opt source destination SNAT all -- anywhere anywhere to:123.123.123.123 注意,我没有使用MASQUERADE而是直接用了SNAT --to指到我的服务器地址,所以最后一条规则是那样的。 最后还需要放行你的VPN端口: ufw allow 1234 ufw allow 1234/udp 开启ocserv 现在我们可以启动ocserv啦,按道理来说应该可以通过service ocserv start来启动,但我发现这种方式启动的ocserv会监听默认端口443,而不是你在配置文件里自定义的端口(进一步测试发现ocserv实际上是加载了配置文件的,因为我在配置文件中的auth的确字段生效了),所以我放弃了这种方式,改用命令启动: ocserv -c /etc/ocserv/ocserv.conf -f -d 1 其中,-c xxx是指定配置文件,-f表示前台运行(如果不加这个选项ocserv会自动转到后台运行,不阻塞控制台),-d 1表示verbose的等级,会打印出来调试信息。 配置客户端 下面我以iOS版的AnyConnect为例来说明,首先需要去AppStore下载AnyConnect,打开后界面如下: 添加用户证书 首先我们需要添加用户证书,你需要先把你的用户证书上传到一个http服务器上,让它可以用http协议下载,如:http://123.123.123.123/zhangsan.p12,然后点“诊断”-“导入用户证书”,输入上面的URL,会提示你输密码,这里输入你生成p12证书时的密码即可。 配置服务器信息 回到首页,点击“连接”-“添加VPN”连接,输入服务器地址和端口,如123.123.123.123:1234,然后点击“高级”-“证书”,选择你刚刚导入的证书。 连接 回到首页,点击右上角的开关,就可以愉快连接啦~ 首次连接的时候会出现弹框,告诉你这个证书不可信任,前面说过了,原谅他,我们点击弹框右上角的“导入”,就可以将我们的服务器证书加入信任列表,以后就不会再提示了~ 另一种认证方式 我们还可以让ocserv采用 用户名+密码 的认证方式,这种情况下客户端不需要添加用户证书了(当然你也就没必要生成一个用户证书给用户了),而是需要通过一个用户名密码去登录,不过每次登录都需要输入用户名密码,还是挺麻烦的。 首先配置ocserv.conf,作以下修改: # 登陆方式,这里改为使用密码登录,并配置密码库文件 auth = "plain[/path/to/ocpasswd]" # 证书颁发机构证书,用于验证用户证书是否受信 # 这里不需要验证用户证书了,可以注释掉这一句 #ca-cert = /path/to/ca-cert.pem 然后添加一个用户,比如zhangsan: ocpasswd -c /etc/ocserv/ocpasswd zhangsan 然后会提示输入密码,完成后用户就创建成功了。 重启ocserv,在客户端删掉用户证书,重新连接,就会被要求输入用户名密码了。 其他客户端配置 Windows和Mac的AnyConnect客户端似乎不太方便从官网下载(似乎官网下载要求你有一个思科账户并且这个账户上有相关的合同签署),所以可以从这个地方下载:http://frodo.sca.com/downloads/VPN-Clients/AnyConnect/。 Windows中导入用户证书 Windows版的AnyConnect客户端本身没有提供导入用户证书的功能,但它会使用Windows系统中的个人证书作为用户证书尝试连接,可以用Windows的MMC工具管理证书。 Ctrl+R运行mmc,点击“文件”-“添加/删除管理单元”,然后添加“证书”管理单元,这时会提示“该管理单元将始终为下列账户管理证书”,这里一定要选择“计算机账户”,后面的一律默认选项即可。 添加完成后,左侧导航栏中的“控制台根节点”下会出现“证书(本地计算机)”节点,点进去,依次进入“个人”-“证书”,可以看到这里列出了系统中所有的用户证书。然后在右边的“操作”窗口中点击“更多操作”-“所有任务”-“导入”,选择你的p12证书文件,导入即可。 然后再打开AnyConnect连接服务器就能连上了~ 其实MMC也可以用来管理Windows的受信证书blabla…,可以随便玩玩。 参考文献 Console log for ocserv configuration 使用ocserv搭建 Cisco Anyconnect 服务器 TLS/SSL工作原理

搭建OpenVPN并通过IPv6访问IPv4

本文介绍如何在 Ubuntu 14.04 上搭建 OpenVPN,并通过 IPv6 访问之,如果服务器有 IPv4 的出口,那么就可以在不登录学校网关的情况下愉(mian)快(fei)上网啦。 今天在某小美女的办公室干活,因为没有网络账号,全程断网码代码,非常难受,突然想到之前上大学的时候,因为校园网欠费,想出来的在DO的IPv6主机上搭建VPN的招数,又想到我在实验室的电脑上长期跑着Ubuntu,灵机一动,既然这里和实验室都是CERNET,能不能用IPv6互通,从而用实验室能上网的那台机器当跳板,实现免费上网呢? 基本的网络结构就是如上,左边是我的小本本,它现在被限制只能上CERNET,中间是我在实验室的服务器,它具有双接口(严格来说是单接口双IP,一个v4,一个v6),能够访问外网,我的本本通过VPN走服务器,就可以蹭服务器的v4访问外网啦。 之前配置的是PPTP协议的VPN,但PPTP问题颇多,而且新版的 Mac OS 已经默认移除了PPTP的VPN支持,所以这次准备转投OpenVPN。 实际上据说 Linux 上的 pptpd 根本就是不支持IPv6的,因为其所依赖的 ppp 包不支持IPv6,但我当年确实跑通了。其实原理上来说PPP协议应该可以支持v6,只是流行的ppp包不支持罢了。可能当年用了什么黑科技吧,不记得了 :P 配置 OpenVPN 安装 首先安装openvpn,对于Ubuntu,apt已经提供了openvpn的安装包,而CentOS据说是需要源码安装的,本文以Ubutnu为例: sudo apt-get install openvpn 配置证书和密钥 在开始使用OpenVPN之前,我们还需要生成一系列的RSA证书和密钥以供使用,OpenVPN开发了一套叫做easy_rsa的软件,已经提供了一系列的小工具来生成这些东西。 下载easy_rsa,并解压,进入easy_rsa工具集目录: wget https://github.com/OpenVPN/easy-rsa/archive/release/2.x.zip unzip 2.x.zip cd easy-rsa-release-2.x/easy_rsa/2.0 可以ls -l一下看看,这里提供了一大堆的工具给你用,下面我们看看怎么用这些工具生成我们需要的东西。 首先编辑vars这个文件,这个文件会告诉后续的步骤你想要生成的rsa证书和密钥的配置,你也可以留作默认,编辑好之后,需要source一下,来使得更改生效。 source ./vars 这时他会提示你:NOTE: If you run ./clean-all, I will be doing a rm -rf on /path/to/easy-rsa/easy-rsa/2.0/keys 既然他让你run一遍那就run一遍吧: ./clean-all 然后我们来生成证书颁发机构: ./build-ca 这个命令会要求你输入一堆信息,你可以都直接Enter掉让他使用默认值,如果你之前配置过vars文件的话,你会观察到这些默认值都是你刚刚在那里配置过的,实际上,包括后面我们要运行的很多命令都是使用vars里面的配置当默认值。 然后生成服务端证书: ./build-key-server server 这里server是生成的服务端证书的文件名(不带后缀),可以任意取。 同时也需要生成一份客户端证书: ./build-key client 这里client是生成的客户端证书的文件名(也不带后缀),可以任意取,如果你愿意,也可以生成多份不同的证书,分发给不同的用户。 最后生成 Diffie Hellman 参数: ./build-dh 这里最后还需要再生成一个ta.key,不太清楚是干什么用的,但是没它不行: openvpn --genkey --secret ta.key 现在可以ls keys,看一下keys目录下都有哪些文件: ca.crt, ca.key:生成的颁发机构证书 server.crt, server.csr, server.key:生成的服务端证书和密钥 client.crt, client.csr, client.key:生成的客户端证书和密钥 dh2048.pem:生成的 Diffie Hellman 参数文件 配置服务端OpenVPN 新建一个OpenVPN配置文件/etc/openvpn/server.conf,编辑如下: # OpenVPN支持2种设备模式(TUN和TAP) # TUN运行在二层,TCP运行在3层 # 为了较好地支持IPv4,我么使用TUN dev tun # OpenVPN的默认协议配置是udp # 使用TUN模式的IPv6模式,我们使用udp proto udp6 # OpenVPN的默认端口是1194 # 但是由于某些我们都知道的原因 # 1194端口经常针对性的被干(he)扰(xie) # 所以最好换个端口 port 11194 # 下面配置上我们刚刚生成的服务端证书信息 ca /path/to/easy-rsa/easy-rsa/2.0/keys/ca.crt cert /path/to/easy-rsa/easy-rsa/2.0/keys/server.crt key /path/to/easy-rsa/easy-rsa/2.0/keys/server.key dh /path/to/easy-rsa/easy-rsa/2.0/keys/dh2048.pem user nobody group nogroup # OpenVPN中,VPN实际上相当于一层路由 # 这里配置的就是路由的入口网段 # 是一个虚拟的网段,可以任意配置 server 172.16.18.0 255.255.255.0 # 以下继承OpenVPN的默认配置 persist-key persist-tun status /var/log/openvpn-status.log verb 3 client-to-client push "redirect-gateway def1" push "dhcp-option DNS 4.2.2.1" # 这里使用一个可用的DNS即可 log-append /var/log/openvpn comp-lzo 注意server 172.16.18.0 255.255.255.0这条,OpenVPN中,将一个VPN连接视为一层转发路由,这一配置就是配置了路由的入口网段,这是一个虚拟出的网段,所有连接到VPN的客户端都会被分配一个该网段内的虚拟地址,到达的数据包会被这条虚拟路由转发到服务器的实际接口上去。即使OpenVPN在IPv6上运行,这里仍然配置的是一个v4地址,因为OpenVPN的这个虚拟网段是只允许配置为v4的协议的。 下面启用IPv4转发:编辑/etc/sysctl.conf,修改net.ipv4.ip_forward = 1,编辑好之后运行sysctl -p使设置生效。 启用NAT转发: iptables -t nat -A POSTROUTING -s 172.16.18.0/24 -o eth0 -j SNAT --to-source 123.123.123.123 这条配置里,172.16.18.0/24为源网段,就是你刚刚配置的那个虚拟网段,而123.123.123.123则是你服务器出口的实际IPv4地址,这样就完成了这个转发操作。 启动OpenVPN服务端 激动人心的时刻到了,运行: sudo service openvpn start 此时OpenVPN应该可以正常启动了,启动后运行netstat -anp | grep 11194,看一下是否正常占用了11194端口,以确认OpenVPN确实正常启动了。 也可以配置为开机自动启动: chkconfig openvpn on 近日在 Ubuntu 16.04 上测试发现 service 和 chkconfig 命令不太好使了,应该使用如下两条命令: systemctl start openvpn@server update-rc.d openvpn start 20 2 3 4 5 配置OpenVPN客户端 首先需要下载服务端上生成的客户端证书及密钥,还有证书颁发机构的证书,即ca.crt, client.crt, client.key这三个文件。 客户端的配置文件的位置依你所使用的OpenVPN客户端而决定,配置文件的基本配置如下: # 设置为客户端配置文件 client # 设备和协议,与服务端配置保持一致 dev tun proto udp6 # 服务端地址及端口 # 这里我们愉快地配置为一个IPv6地址 # 端口要与服务端配置一致 remote 2001:1111:1111:1111:1111:1111:1111:1111 11194 # 保持默认配置 resolv-retry infinite nobind persist-key persist-tun # 配置为你存放机构证书和客户端证书、密钥的路径 ca /path/to/ca.crt cert /path/to/client.crt key /path/to/client.key comp-lzo verb 3 注意remote 2001:1111:1111:1111:1111:1111:1111:1111 11194这一句,IPv6的地址是如此地富裕,以至于一个接口往往能配置很多条IPv6地址,当你实际使用的时候,可能会遇到你发送的VPN请求的目的地址与服务端响应的源地址不一致的情况,这个时候你需要换一个合适的地址。我用的Tunnelblick客户端比较友好,报错信息里面已经显示了实际收到的源地址和期望的源地址,直接配置即可。 愉快地上网吧! 参考文献 【教程】使用IPv6 Openvpn加速访问外国网站 透过OpenVPN建立IPv4/IPv6隧道

关于泊松过程的理解

泊松过程(Poisson Process)在上大学学排队论的时候就学过,但是当时感觉就没搞太清楚,最近又看了一遍,感觉似乎理解了一些东西,这篇博文会不定期更新,以添加我最新的理解。 先说说泊松分布 讲之前首先强调一下,泊松分布(Poisson Distribution)和泊松过程是两个概念。泊松分布是一种概率分布,一种概率分布说白了就是一类具有相同形式的概率密度函数。而泊松过程是指一个随机过程,随机过程可以看做是在一个连续或者离散的时间线上,连续发生的一系列随机事件的组合。所以泊松分布和泊松过程并不是一码事。 另外,泊松过程也不是说这个过程中的每一个随机事件符合泊松分布。泊松过程是一个比较抽象的过程,这也是为什么我学了这么长时间一直没理解清楚的原因(我觉得是这样/捂脸/)。至于它到底是个什么样的过程,等会我再说。 泊松分布 咳咳,好吧,现在开始真的说泊松分布啦~ 为了引出泊松分布,我们先说伯努利分布(Bernoulli distribution),又叫0-1分布,如果一个离散变量只能取0、1两个值,那么就说这个变量服从伯努利分布: \eqc P(x=k) = \left\{\begin{aligned} & 1 - p, & k = 0 \\ & p , & k = 1 \end{aligned} 举个例子,你抛一枚硬币(这个硬币不一定两面是一样重的,跑出两面的概率不一样),会得到正面(1)或者反面(0)两个结果,这个时候你的结果的分布就服从伯努利分布。其实这个很好理解对吧…… 然后说二项分布,如果你做n次互相独立同分布的伯努利实验,那么各次实验结果的和(也就是结果为1的次数)将会服从二项分布。二项分布的概率函数为: \eqc P_n(x) = C_n^x \cdot p^x \cdot (1-p)^{(n-x)} 诚然,当\eq n=1时二项分布即为伯努利分布。 真的真的要说泊松分布了 泊松分布是二项分布的另一个极限情况,当二项分布中的阳性概率\eq p \rightarrow 0很小而试验次数\eq n \rightarrow +\infty时,满足\eq np = \lambda时,得到的即为参数为\eq \lambda的泊松分布,所以泊松分布的概率函数为: \eqc P(x) = \mathop{lim}\limits_{n \rightarrow +\infty} P_n(x) = \lambda^{-x} \cdot \frac{e^\lambda}{k!} 可以证明,泊松分布的期望和方差都是\eq \lambda。 从上面的推导来看,泊松分布所表达的其实是这么一件事,就是说当你做有限次的伯努利实验时,发生阳性结果(至少发生一次)的概率近乎于0,但是当你做无穷多次的时候,阳性结果发生的概率就不是0了,而是一个随机的有限的值(期望是有限的)。这样说似乎很奇怪,因为现实世界中似乎并没有这样奇怪的实验去做。 如果你觉得上面这段话不好理解,那我给你举个反面的例子,你可以从相反的方向理解一下(当然这段话并不重要,所以你可以不看),但是请注意,以下并不是泊松分布的真正意义。工程界有一个著名的定律叫做墨菲定理,它的说法大概是说:“如果一件事情有变坏的可能性,那么它就一定会变坏”。这句话似乎非常匪夷所思,它是一个叫墨菲的工程师提出的,我觉得他说这句话的本意只是提醒其他的工程师要注意细节,再小的bug都不要忽视。 不过,它之所以被称为“定理”,的确是有它的科学依据的,让我们来假设“变坏”是一个阳性结果(1),那“正常”就是阴性结果(1),“一件事情有变坏的可能性”也就是说存在一个\eq p \not= 0,那么你对\eq P_n(x)求\eq n \rightarrow \infty的极限会发现,当\eq x = 0时\eq P_n(x) \rightarrow 0,也就是说这件事情不变坏的可能性为0,也就是说它一定会变坏咯,所以墨菲定理其实是有数学依据的。当然根据这个推导你也可以看出,\eq P_n(n)其实还是0,实际上应该说在长期的生产中一定不会一直正常,但也一定不会一直出故障。墨菲想说的是,虽然不会一直出故障,但一定会出故障,但有些故障是绝不允许发生的,所以你得让\eq p = 0。 实际中你不可能让\eq p = 0,但你可以做到让\eq p \rightarrow 0,也就是说,你可以让事件发生的次数服从一个泊松分布,这个时候事件不发生的概率就不再趋近于0了,而是有一个确定的概率值,实际上事件发生\eq x次的概率值都是确切的,而当\eq x \rightarrow +\infty时,概率将会趋近于0. 泊松过程 这篇文章重点在于讲泊松过程,这一段我着重给出泊松过程的一些数学上的定义和推导,后面会慢慢讨论的。 首先讨论增量过程,如果随机变量随着时间的变化其值会增加,则这个过程就是一个增量过程,增量\eq X(t_2) - X(t_1)是一个随机变量。数学表示就是\eq X(t_2) - X(t_1) > 0, \ \forall\ 0<t_1<t_2. 在一个增量过程中,如果对于任意的\eq 0<t_1<t_2<t_3<t_4,增量\eq X(t_2) - X(t_1)和\eq X(t_4) - X(t_3)是独立的,那么这就是一个独立增量过程。也就是说,独立增量过程中,任意两个不重叠的时间段之内的增量是独立的。 在一个独立增量过程中,如果对于任意的\eq t_1,t_2,h > 0,增量\eq X(t_2) - X(t_1)和\eq X(t_4 + h) - X(t_1 + h)服从相同的分布,那么这个过程就是一个平稳增量过程。 在平稳增量过程,对于一个给定的时间间隔\eq \tau,如果增量\eq X(t+\tau) - X(t)服从泊松分布,那么这个过程就叫做泊松过程。 下面给出泊松过程的定义:如果单位时间内事件发生的次数\eq X符合泊松分布\eq P(X=k) = \frac{e^{-\lambda} \lambda^k}{k!},则这个随机过程是一个参数为\eq \lambda的泊松过程。 理解泊松过程的含义 上面啰嗦了那么多,主要是为了讲清泊松过程的来历,从上面的推论看出,泊松过程实际上就是描述这么一个过程,在每一刻,某个事件发生的概率是确定的,而在固定的时间段之内,发生这个事件的次数服从一个特定的概率分布。但是,这样的一个过程不一定是泊松过程,它实际上是一个平稳增量的过程,而泊松过程的实际上是一类特定的平稳增量过程,增量的分布服从泊松分布的平稳增量过程才是泊松过程。 关于泊松过程的参数\eq \lambda的含义 \eq \lambda的正式定义是到达率,它指的是单位时间内发生事件次数的期望值,对于任意的时间间隔\eq \tau,在这段时间内发生事件次数实际上也符合泊松分布,这个泊松分布的参数是\eq \lambda\tau。