2014年11月27日星期四

亚马逊aws配置多个公网ip的问题

公司的服务器切换到亚马逊aws服务器, 我们的服务需两个公网ip, 在aws上申请到了两个公网ip, 并且配置成功。
aws服务器使用的是内网ip通过NAT转换成公网ip的方式.
映射关系如下:
$public_ip1 ---> $private_ip1 ----> eth0
$public_ip2 ---> $private_ip2 ----> eth1
但是使用过程发现只有一个公网可以通。
当黙认网关设置在eth0上时,$public_ip1可以通, $public_ip2不通;当黙认网关设置在eth1上时$public_ip2可以通,$public_ip1不通。
于是我做了如下操作:
把黙认网关设置在eth0上, 在公网ip为123.123.123.123的机器上ping $public_ip2,然后在服务器上使用ip route show cache查看路由表缓存,发现服务器到123.123.123.123的路由走的是eth0, 也就是说$public_ip2接收到的数据包,返回的时候走的是eth0,源ip会被NAT成$public_ip1, 所以会$public_ip2不通。
问题的原因已经明白了,现在要做的就是怎样让从eth1进入的数据包从eth1返回,eth0接收到的数据包从eth0返回。
这里我使用Linux的iproute2功能,让eth0eth1查找不同的路由表
先执行如下命令,添加两条路由表别名
echo 200 t_eth0 >> /etc/iproute2/rt_tables
echo 201 t_eth1 >> /etc/iproute2/rt_tables
然后在路由表中添加路由规则
ip route add default via $gw_eth0 dev eth0 table t_eth0
ip route add default via $gw_eth1 dev eth1 table t_eth1
再添加路由查找规则
ip rule add from $private_ip1 table t_eth0
ip rule add from $private_ip2 table t_eth1
以上规则的意思是,当源ip为$private_ip1时,查路由表t_eth0,在表t_eth0中,黙认走eth0; 当源ip为$private_ip2时,查路由表t_eth1,表t_eth1中,黙认走eth1
这样设置之后,不管黙认网关设置在哪个网卡上,两个公网ip都可以通了。

2014年9月29日星期一

反向代理twitter.com的nginx配置文件

折腾nginx反向代理,终于配置成功了twitter.com的反向代理,可以登陆成功。
首先,需要安装 HttpSubsModule 模块,参见 http://wiki.nginx.org/HttpSubsModule
在http部分加入如下指令,使HttpSubsModule替换javascript中域名,否则登陆时无法输码
subs_filter_types  application/x-javascript application/javascript;

反代twitter.com的配置

server {
    server_name t.example.org;

    #proxy_cache cache1;

    listen 443 ssl spdy;

    add_header Strict-Transport-Security max-age=3153600;
    #add_header X-Frame-Options DENY;

    # 证书
    ssl_certificate      /home/user/a.example.org.crt;
    ssl_certificate_key  /home/user/a.example.org.key;

    #root t.example.org;

    # 禁止搜索引擎
    if ($http_user_agent ~ (google|bot|baidu) ){
        return 403;
    }

    location / {
        proxy_set_header Accept-Encoding "";
        proxy_set_header Accept-Langauge "zh-CN";
        proxy_set_header Host $proxy_host;

        proxy_pass https://twitter.com/;

        # cookie domain replace
        proxy_cookie_domain twitter.com t.example.org;

        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        # 域名替换
        subs_filter twitter.com t.example.org;
        subs_filter abs.twimg.com abs.example.org;
        #subs_filter t.co co.example.org;
    }

}

反代abs.twimg.com的配置

server {
    server_name abs.example.org;

    #proxy_cache cache1;

    listen 443 ssl spdy;

    add_header Strict-Transport-Security max-age=3153600;
    add_header X-Frame-Options DENY;

    # 证书
    ssl_certificate      /home/user/a.example.org.crt;
    ssl_certificate_key  /home/user/a.example.org.key;

    #root abs.example.org;

    # 禁止搜索引擎
    if ($http_user_agent ~ (google|bot|baidu) ){
        return 403;
    }

    location / {
        proxy_set_header Accept-Encoding "";
        proxy_set_header Accept-Langauge "zh-CN";
        proxy_set_header Host $proxy_host;

        proxy_pass https://abs.twimg.com/;

        # cookie domain replace
        proxy_cookie_domain twimg.com abs.example.org;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        # 域名替换
        subs_filter twitter.com t.example.org;
        subs_filter abs.twimg.com abs.example.org;
        #subs_filter t.co co.example.org;
    }
}
我是使用子域名反代twitter域名的方式, 理论上可以使用子目录反代域名的方式,但是这种配置会比较麻烦,很是考验耐心,我成功配置过用子目录反代google。
abs.twimg.com 我这里可以直接访问,但是有一个js文件控制着登陆框的密码输入,所以反代后替换掉域名,就可以输入密码了。
pbs.twimg.com是图片的域名,我这里可以直接访问,就不用反代了。
2014-09-29 18:24 更新:
删除了t.co配置部分,因为如果替换域名t.co, 会连带替换到脚本中的一些其它东西,脚本会执行出错。

2014年9月10日星期三

利用cx_freeze在没有Python的Windows上运行Python源代码

在没有安装Python运行环境的Windows机器上运行python程序,大家的通常做法是使用cx_freeze/pyinstaller等打包成exe文件,我也是一直这样做。但是有一个问题,程序做很小的改动的时候,都需要重新打包,然后再拷备过去等一系列复杂的操作。
我发现goagent项目就是提供的源码,在windows上是用一个python27.exe的程序解释源程序。研究了一番,发现goagent是使用py2exe把依赖的库打包成一个zip文件,然后再做一个python27.exe的程序, 由python27.exe来执行,并且有一个单独的项目,名为pybuild,项目见这里
我使用pybuild的脚本来处理我的程序,希望做成跟goagent一样的效果,结果发现pybuild/py2exe根本搞不定pygtk。
我只有另想办法了,cx_freeze打包的时候可以生成一个单独的压缩包,里面包含依赖的库。看来cx_freeze可以做成goagent的效果。
我直接使用pybuid里面的python27.py来生成python27.exe, 然后再写一个py文件(collect_libs.py)把程序里用到的库全部import一遍。然后利用cx_freeze把python27.py和collect_libs.py打包,完成后删除生成的collect_libs.exe。包含python27.exe的目录就是程序的运行环境, 可以直接使用python27.exe执行python程序。
使用的setup脚本如下
from cx_Freeze import setup, Executable

# Dependencies are automatically detected, but it might need
# fine tuning.
buildOptions = dict(
        packages = [], excludes = [],
        include_msvcr = True,
        include_in_shared_zip = True,
        )

executables = [
    Executable('python27.py', 'Console'),
    Executable('collect_libs.py', "Console")
]

setup(name='python27',
      version = '1.0',
      description = 'the python shell',
      options = dict(build_exe = buildOptions),
      executables = executables)
测试了一下,效果还不错。与pybuild/py2exe相比, cx_freeze把dll,pyd放在目录里面,zip文件里面是pyc文件,而pybuild是把dll, pyd, py文件全放在压缩包里。
需要注意的是,如果cx_freeze处理使用了gevent的程序,需要对cx_freeze本身做一些修改, 修改freezer.py文件中的EXTENSION_LOADER_SOURCE = 内容中的 import os, imp, sys为如下形式,详情参考这里
os = __import__("os")
imp = __import__("imp")
sys = __import__("sys")
另外,cx_freeze不能处理egg文件,需要手动拷备egg文件到目标目录下,在程序的最开始加入如下内容,才能正确的import egg文件
import sys
import glob
for egg in glob.glob("*.egg"):
    sys.path.append(egg)

2014年8月28日星期四

Linux 下SQLITE数据库无法在NFS/CIFS之上运行的解决办法

我在debain下mount了samba(CIFS)共享, 然后运行mindlna,让minidlna stream samba上的视频和音乐, 无奈minidlan拒绝工作。我启用debug模式,发现在minidlna启动时,sqlite数据库建表失败。于时我修改数据库的存放路径到本地的ext4文件系统上,minidlna工作良好。
由此推断可能是CIFS的问题, 于是我使用 sqlite /mnt/media/test.db测试,/mnt/media是samba的挂载点。我输入如下的SQL语句测试:
create table t1 (a int, b int);
直接报如下错误:
table is locked
我使用google搜索了一圈,发现很多人有此问题, 但都没有解决方案,最终在一个英文论坛上发现有人提到添加nolock参数, 但是提问的人没有回复效果。
我于是添加nolock参数、重新挂载samba来测试一下效果:
umount /mnt/media
mount -t cifs -o user=myuser,password=mypass,nolock //172.16.1.5/share /mnt/media
然后,再次使用sqlite /mnt/media/test.db测试,create tableinsertdeleteupdate 等SQL操作都可以成功,不会有任何错误了。把minidlna的数据库路径修改到samba上也没有问题了。
所以nolock参数可以解决此问题,于是修改/etc/fstab添加nolock让系统启动时自动使用nolock参数挂载:
//172.16.1.6/share  /mnt/media  cifs    defaults,user=myuser,password=mypass,nolock 0 0

2014年8月23日星期六

使用ssh遂道远程访问家中的设备

我家中有一台树莓派(raspberrypi),我用它作下载机,还有一台WiFiDisk用来做NAS。白天上班时我想知道家中的设备运行情况,可是我家是长城宽带,是一个大局域网,ADSL拔号拿到的ip看似是公网ip,实际上还是内网ip,所以DDNS和端口映射就无效了。

要解决这种远程访问局域网的问题,我知道至少有两种方案,一种是使用ngrok,另一种是使用ssh遂道。ngrok使用的是别人提供的服务器,我有自己的vps,所以我选择了使用ssh遂道中转。

知识复习

我们来复习一下ssh遂道的三种方式:
  1. Local->Remote (ssh -L) 本地监听一个端口,此端口的所有请求通过ssh遂道转发到远端的某个端口;
  2. Remote->Local (ssh -R) 远端临听一个端口,此端口的所有请求通过ssh遂道转发到本地网络的某个端口;
  3. Dynamic (ssh -D) 本地监听一个端口,此端口做为sock5代理,所有连接通过远端服务转发出去,ssh翻墙通常使用这种方式。
我使用的第二种方式,在树莓派上运行ssh连接到vps,在vps上申请一个端口,然后转发到本地的22端口。要使用这种方式必须要先配置ssh无密码登陆,具体的配置自行搜索, 如果不配置无密码登陆就无法实现断线后自动重连。

命令

我使用的是如下命令
ssh -R $VPS_IP:2222:127.0.0.1:22 -l $USERNAME -N -T -o ServerAliveInternal=20 $VPS_IP
以上命令,-R $VPS_IP:2222:127.0.0.1:22的意思是在vps上临听2222端口,转发到本机的22端口,-N表示不启动shell,-T表示不分配tty,-o ServerAliveInternal=20表示每20s发送一个消息,用来检测是否断线。我第一次就是忘了-o参数,结果在家中测试可以连接,等我到办公室时,已经无法连接了,因为底层已经断了,便是没有消息发送,上层无法检测到是否断线。

ssh配置

vps上需要修改ssh配置文件/etc/ssh/sshd_config,修改其中的GatewayPortsyesclientspecial, 此参数黙认为no,当为no的时候分配的端口只能bind到127.0.0.1上, 是无法通过远程连接的。修改后需要重启sshd,执行命令:
service sshd restart

完整脚本

VPS_IP=1.1.1.1
USERNAME=myname
REMOTE_PORT=2222
LOCAL_PORT=2222
LOCAL_HOST=127.0.0.1
ID_FILE=~/my_id   # private key file

while true
do
    ssh -i $ID_FILE \
        -N -T \
        -R $VPS_IP:$REMOTE_PORT:$LOCAL_HOST:$LOCAL_PORT \
        -l $USERNAME \
        -o ServerAliveInternal=20 \
        -o ConnectTimeout=20 \
        $VPS_IP
    sleep 10
done
将此脚本加到启动脚本中即可。
此脚本只是转发到本机的ssh端口,当然还可以转发到其它机器。例如,家中的笔忘本电脑打开了远程桌面,假设ip是192.168.1.100,使用-R $VPS_IP:3322:192.168.1.100:3389参数, 就可以通过vps的3322端口访问到家中笔记本电脑的远程桌面了。
当然,在家中访问办公室电脑也可以使用同样的方法,在办公室运行ssh即可。此方法不需要向网络管理员申请端口映射。自己可以随机控制端口,你只需要有自己的vps即可。

2014年7月25日星期五

Linux 下使用backtrace获取程序栈信息

以前调试Linux驱动的时候,知道在kernel里使用dump_stack可以打印出内核栈信息,可以很方便查看函数的调用关系。 现在我才知道glibc也支持获取栈信息,并且有相关的函数:

   #include <execinfo.h>

   int backtrace(void **buffer, int size);

   char **backtrace_symbols(void *const *buffer, int size);

   void backtrace_symbols_fd(void *const *buffer, int size, int fd);

以下是Man里的示例代码

       #include <execinfo.h>
       #include <stdio.h>
       #include <stdlib.h>
       #include <unistd.h>

       void
       myfunc3(void)
       {
           int j, nptrs;
       #define SIZE 100
           void *buffer[100];
           char **strings;

           nptrs = backtrace(buffer, SIZE);
           printf("backtrace() returned %d addresses\n", nptrs);

           /* The call backtrace_symbols_fd(buffer, nptrs, STDOUT_FILENO)
              would produce similar output to the following: */

           strings = backtrace_symbols(buffer, nptrs);
           if (strings == NULL) {
               perror("backtrace_symbols");
               exit(EXIT_FAILURE);
           }

           for (j = 0; j < nptrs; j++)
               printf("%s\n", strings[j]);

           free(strings);
       }

       static void   /* "static" means don't export the symbol... */
       myfunc2(void)
       {
           myfunc3();
       }

       void
       myfunc(int ncalls)
       {
           if (ncalls > 1)
               myfunc(ncalls - 1);
           else
               myfunc2();
       }

       int
       main(int argc, char *argv[])
       {
           if (argc != 2) {
               fprintf(stderr, "%s num-calls\n", argv[0]);
               exit(EXIT_FAILURE);
           }

           myfunc(atoi(argv[1]));
           exit(EXIT_SUCCESS);
       }


    编译时要加 -rdynamic 参数,否则只有函数地址,没有函数名
 
    $ gcc -rdynamic prog.c -o prog
    $ ./prog 3
     backtrace() returned 8 addresses
     ./prog(myfunc3+0x5c) [0x80487f0]
     ./prog [0x8048871]
     ./prog(myfunc+0x21) [0x8048894]
     ./prog(myfunc+0x1a) [0x804888d]
     ./prog(myfunc+0x1a) [0x804888d]
     ./prog(main+0x65) [0x80488fb]
     /lib/libc.so.6(__libc_start_main+0xdc) [0xb7e38f9c]
     ./prog [0x8048711]

2014年7月23日星期三

squid 访问google.com出现503错误的解决方法

  最近通过https连接到squid,访问google不太正常,查看日志发现大量的 CONNECT www.google.com:443 出现503错误,并且503出现的概率为80%,换了几个版本的squid 都是一样的情况,怀疑是squid的问题,因为同一台服务器上shadowsocks就没有问题。

  我尝试修改配置文件, 增加 dns_v4_first, 指定tcp_outgoing_address,指定dns_nameserves, 问题依旧。

  查看squid文档, 发现squid连接失败后不会重试

Option Name:connect_retries
Replaces:
Requires:
Default Value:Do not retry failed connections.

于是增加
  connect_retries 3
重启squid, 客户端访问google,观察了一上午, 503错误再也没有了。

2014年7月15日星期二

上大学网公布的中国虚假大学名单2014



转载自真相网, 原文链接 http://dafahao.com/chinese-fake-universities-list-2014.html

真相网2014.7.15】近日,上大学网发布了第三批中国虚假大学名单警示榜,其中包括了60多所,涉及中国19个省市的大学。之前也公布了二批虚假大学名单,请急于求学的学生和家长警惕受骗上当。
这些虚假大学以假仿真,很多听上去像是十分正规的大学,其实都是骗人的,比如说,中国信息科技大学、上海同济医科大学和广东科技管理大学等等。而这份警示榜中的信息都是由热心网友、受骗考生,过往应届高考生家长提供。这让人不禁思考,监管部门到底是干什么的。
上大学网公布的榜单声明说“警示榜中的各种虚假信息均由热心网友、受骗考生或应往届高考生家长提供,经上大学网认真搜集、对比和核实调研后确认,请广大低学历或急需提升文凭的朋友、2014年及今后的广大高考生和家长在高考志愿填报时仔细甄别、不要轻信。”
榜单中包括北京经济管理学院、中国信息科技大学、首都财经管理学院等60所,涉及中国19个省市的大学。这是上大学网对外公布的第三批虚假大学。前两批分别是2013年6月26日发布的《上大学网百所中国虚假大学警示榜》和2013年7月23日发布的《上大学网第二批中国虚假大学警示榜(共50所)》。
在上大学网第一次公布的名单中,有超过七成的虚假大学都号称校区在北京,并往往以“中国”、“首都”、“北京”等词企图混水摸鱼。
“上大学”网负责人表示,分数特别低、又想上大学的孩子,最可能会上假大学的当。“上大学”网发现,很多假大学广告上的学校简介都是抄袭真大学往年的简介。
有媒体评论说,这类假大学仿冒名称、以假乱真,再盗用正牌高校的照片,对高校不甚了解的考生和家长,极有可能信以为真。
附录:
第三批 《上大学网第三批中国虚假大学警示榜(2014年60所)》,为上大学网专家团队在前二批基础上精心研发而成,属于上大学网在2014年全国高考后最新原创首发的大学榜单。

上大学网第三批中国虚假大学警示榜(2014年60所)

第一批 2013年6月26日首发:上大学网百所中国虚假大学警示榜

第二批 2013年7月23日首发:上大学网第二批中国虚假大学警示榜(共50所)

2014年7月9日星期三

通过ssl安全地使用代理服务器

   通常我们使用代理服务器时,浏览器与代理服务器之间的传输都是明文的,虽然https是加密的,但是https会话开始时依然是明文的,例如,https会话开始时浏览器发送的
    CONNECT www.google.com:443 HTTP/1.1
就是明文的,审查者仍然可以知道你访问了什么网站,如果是他们不喜欢的网站,他们就可以阻止你继续访问。

本文教你如何使用ssl保护你与代理服务器之间的连接。


需要的软件

    服务器端squid 2.6以上,编译时开启了--enable-ssl
    chrome/chromium浏览器 加SwitchySharp插件


服务器端配置

   如果你的系统软件仓库中带的squid编译时没有加 --enable-ssl选项,你需要下载squid的源码,添加--enable-ssl选项重新编译


生成证书

  如果你有现成的证书可以直接使用,如果没有,生成一个自签名的证书,命令如下
  openssl genrsa -out server.key  2048
  openssl req -new -x509 -out server.crt -key server.key -days 365


squid 配置

    在配置文件squid.conf中添加
    https_port 8004 cert=/path/to/server.crt key=/path/to/server.key

防火墙需要允许8004的连接
iptables -A INPUT -p tcp --dport 8004 -j ACCEPT


浏览器设置

    到目前为止(2014-07)只有chrome/chromium支持ssl连接到代理服务器,并且只能通过pac配置

新建一个文本文件命名为proxy.pac,添加如下内容

function FindProxyForURL(url, host){
    return "HTTPS your_proxy_server_name:8004";
}

把your_proxy_server_name 替换成你的代理服务器ip或域名

在SwitchySharp中新建一个情景模式,命名为myproxy_ssl,选择自动配置,然后点击导入pac文件,选择你刚才新建的proxy.pac文件,保存

切换到myproxy_ssl,测试代理服务器能否正常连接


证书问题

    如果使用的是自签名的证书,浏览器会报证书错误,把服务器上的server.crt作为信任的根证书导入浏览器的信任列表即可


参考来源
http://wiki.squid-cache.org/Features/HTTPS
http://dev.chromium.org/developers/design-documents/secure-web-proxy

2014年7月8日星期二

使用混淆之后的ssh连接vps

gfw对ssh的干扰严重到正常的远程管理都受到了影响,把ssh运行在3389,443端口都无济于事。
通过google我发现了两种解决方案:
1.使用obfsproxy
2.使用obfuscated-openssh

obfsproxy是tor项目的,根据google的结果,目前已经阵亡,于是我使用第二种方案。

服务端安装方法
 git clone https://github.com/brl/obfuscated-openssh.git
 cd obfuscated-openssh

  自定义安装位置, 启用md5和pam支持
 ./configure --prefix=/home/dingjun/openssh-obfs --with-md5-passwords --with-pam --with-pid-dir=/home/dingjun/openssh-obfs/var/run --with-privsep-path=/home/dingjun/openssh-obfs/var/empty
 make 
 make install

配置
修改openssh-obfs/etc/sshd_config文件加入如下配置


ObfuscatedPort 8009  # 监听端口
ObfuscateKeyword  wfgkcuf  # 混淆使用的keyword


启动

sudo /home/dingjun/openssh-obfs/sbin/sshd


客户端

windows 下使用potty, potty是打了混淆补丁的putty,下载地址
http://www.mrhinkydink.com/potty.htm

运行potty.exe, 界面和putty一模一样的

在ssh选项里选中 Enable key exchange obfuscation, 然后输入服务器上配置的ObfuscateKeyword

现在就可以使用了
使用cat /var/log/message 测试一下,连接没有被断开