树莓派的内网穿透

家里的宽带没有公网IP,从外面没有办法SSH到树莓派上。如果有公网IP的话,现在一般的路由器都支持端口转发功能,在路由器的管理界面添加一条转发规则即可。

不过有一天,我突然想到了SSH的端口转发功能,其实很简单的一条命令:

ssh -N -f -R 8022:localhost:22 xxx@remote-host.com

简单解释一下,-N表示了不要执行任何命令,-f表示在后台执行,-R 8022:localhost:22表示remote-host.com上将会监听8022端口,并将所有的流量转发到localhost:22端口上来。就是这么简单。

当然了,前提是你要有一台有公网IP的主机,这个就自己想办法搞定吧,比如阿里云什么的。

但是,这个办法有个缺点,树莓派重启了就失效了,可以参考[这个][autosshd],在树莓派上略加修改就能用了,把autosshd脚本放到/etc/init.d下,再执行

update-rd.d autosshd defaults

autosshd加到自启动项里去。其实这个脚本就是利用了autossh这个工具。

不过我对上面的那个脚本做了些修改,供大家参考:

#!/bin/bash

### BEGIN INIT INFO
# Provides:          autossh
# Required-Start:    $network $local_fs
# Required-Stop:     $network $local_fs
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: This script starts and stops the autossh daemon
### END INIT INFO

# Source function library.
#. /etc/rc.d/init.d/functions

# Source networking configuration.
#. /etc/sysconfig/network

# Check that networking is up.
#[ ${NETWORKING} = "no" ] && exit 0

TUNNEL_SSHCONFIG="/home/pi/.ssh/config"
TUNNEL_IDENTITY="/home/pi/.ssh/id_rsa"
TUNNEL_HOST="xxx@remote-host.com"
TUNNEL_REDIRECT="8022:localhost:22"

export AUTOSSH_PIDFILE="/var/run/autossh.pid"

# By default it's all good.
RETVAL=0

# Start function.
start() {
    local name=$1
    echo -n $"Starting ${name}: "
    if [ -e "/var/lock/subsys/${name}" ]; then
        if [ -e "/var/run/${name}.pid" ] && [ -e /proc/`cat /var/run/${name}.pid` ]; then
            echo -n $"already exists.";
            failure $"already exists.";
            echo
            return 1
        fi
    fi
    #daemon /usr/bin/autossh -M 0 -f -nNT -F ${TUNNEL_SSHCONFIG} -i ${TUNNEL_IDENTITY} ${TUNNEL_HOST}
    /usr/bin/autossh -f -M 0 -CNnqT -F ${TUNNEL_SSHCONFIG} -i ${TUNNEL_IDENTITY} -R ${TUNNEL_REDIRECT} ${TUNNEL_HOST} -o ServerAliveInterval=30 -o ServerAliveCountMax=5
    RETVAL=$?
    [ $RETVAL -eq 0 ] && touch "/var/lock/subsys/${name}"
    echo
    return $RETVAL
}

# Stop function.
stop() {
    local name=$1
    echo -n $"Stopping ${name}: "
    #killproc -p "/var/run/${name}.pid" ${name}
    kill `cat /var/run/${name}.pid`
    RETVAL=$?
    echo
    [ $RETVAL -eq 0 ] && rm -f "/var/lock/subsys/${name}"
    return $RETVAL
}

# See how we were called.
case "$1" in
    start)
        start "autossh"
        ;;
    stop)
        stop "autossh"
        ;;
    restart)
        $0 stop
        sleep 3
        $0 start
        ;;
    status)
        status "autossh"
        RETVAL=$?
        ;;
    *)
        echo $"Usage: $0 {start|stop|restart|status}"
        exit 1
        ;;
esac

exit $RETVAL

做了几点改进:

  1. 修改了一下在树莓派上可以跑,但是很多地方还有待改进
  2. 修改了ssh的启动参数,添加了-Cq,可以man ssh自己看
  3. 添加了-o ServerAliveInterval=30 -o ServerAliveCountMax=5,可以自动检测SSH连接可用性

至此

100 次查看 | 没有评论
2014年12月15日 | 归档于 Raspberry Pi

树莓派上配置无线网络

上一篇里抱怨了没有键盘,没有显示器,没有有线网络的情况下,配置无线网络很不方便。后来通过安装XBMC暂时解决了这个问题。现在已经从XBMC转投了Raspbian,周六在家里研究了一下树莓派的无线网络配置方法。

首先要确认树莓派正确识别和支持了你的无线网卡,我买的是这一款 腾达 W311MI,在shell里运行lsusb,在我的树莓派上执行结果如下:

Bus 001 Device 004: ID 148f:5370 Ralink Technology, Corp. RT5370 Wireless Adapter

我们可以看到,使用的是Ralink芯片,对于USB网卡不支持的情况,我觉得通过搜索,应该是能够找到相关的驱动的。或者您在购买之前先查询一下,是否被树莓派支持。至于还有文章里说lsmod用来查询内核里是否加载了网卡的驱动,这个我就没有深究了。

方法1

基本上通过以上确认以后,下面就是扫描一下家里的无线网络了,取得一些必要的参数。使用iwlist wlan0 scanning,结果输出会很长,注意其中这部分:

IEEE 802.11i/WPA2 Version 1
Group Cipher : TKIP
Pairwise Ciphers (2) : CCMP TKIP
Authentication Suites (1) : PSK

确保/etc/network/interfaces的内容如下:
auto lo

iface lo inet loopback
iface eth0 inet dhcp

allow-hotplug wlan0
iface wlan0 inet manual
wpa-roam /etc/wpa_supplicant/wpa_supplicant.conf
iface default inet dhcp

这是树莓派安装完成后原版的文件内容,不要iface wlan0 inet manual改为iface wlan0 inet dhcp,我就是被这个坑了很久。

然后修改/etc/wpa_supplicant/wpa_supplicant.conf,修改后:

ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1

network={
    ssid="WIFI_SSID"
    scan_ssid=1
    proto=RSN
    key_mgmt=WPA-PSK
    pairwise=CCMP TKIP
    group=CCMP TKIP
    psk="WIFI_PASSWORD"
    auth_alg=OPEN
    #id_str="home"
}

除了ssid和psk外,{}内的其它内容似乎都可以不配置。当然了,也可以用wpa_supplicant命令来配置,具体的可以参考这里

这种方法的好处是:1、可以实现有线网络与无线网络共存;2、可以配置多个接入点。其中奥妙之后就在于/etc/network/interfaces里的wpa-roam,前面也指出来了,这里IP获取的方式是mannual,那如果我在wpa_supplicant里配置了多个不同的网络,每个网络获取IP地址的方式不同,应该怎么处理呢,其实我们可以为每个网络指定一个名称,如上面在/etc/wpa_supplicant/wpa_supplicant.conf中指定的id_str,然后在/etc/network/interfaces中添加iface $id_str inet dhcp即可。

方法2
auto lo

iface lo inet loopback
iface eth0 inet dhcp

allow-hotplug wlan0
iface wlan0 inet dhcp
wpa-ssid "WIFI_SSID"
wpa-psk "WIFI_PASSWORD"
iface default inet dhcp

这种方法是,配置比较简单,但是不支持在多个网络间漫游。

157 次查看 | 没有评论
2014年12月7日 | 归档于 Raspberry Pi

我的树莓派

在北京的时候就买了个 树莓派 ,还是千辛万苦从大不列颠海淘过来了,交了50块钱的关税。搞来之后其实挺郁闷的,因为啥?因为没法玩。在公司连不上网(有认证),在家里没有显示器(其实不用显示器也能用),反正各种不折腾就不能玩。后来也就没管。再后来,到了魔都,每周回苏城,终于有机会开撸树莓派了。家里的电视有HDMI输入,直接拿了小米盒子的HDMI线接到树莓派上,开机,点亮,一切正常。但是因为没有网线,无法SSH上去,就没有办法配置无线网卡(家里没有USB键盘)。没办法配置无线网卡基本上就等于废了。后来我就装了个XBMC,这货有虚拟键盘,有可视化界面,可以直接配置无线网卡,于是我就很Happy的RUN起来了。

然后就挺入移动硬盘,装上aria2,用迅雷离线下载电影,XBMC中连的盘直接可以在小米盒子上看。

这样一直用得挺爽,直到有一天,XBMC傻逼的更新,把SSH远程登录给搞坏了,我怀疑是启动的时候SSHD没有启起来,anyway,不能远程登录啊!那作为一个Linux不就废了么!老婆实在是看不惯我周末老在家折腾这破玩意儿,批准我买个家用NAS。但是在京东上看来看去,觉得花个几千块钱买个东西就下下电影、录录家里的视频监控,还是略贵。于是转念一想,我可以买个小米路由啊,于是我就买了个小米路由,这货先不表,可玩性远不如树莓派。

买完小米路由,我才脑洞大开,尼玛啊,小米盒子之所以能支持直接访问XBMC里的文件,无非就是XBMC提供了DLNA和SAMBA的访问方式,DLNA没搞过,SAMBA搞过无数次啊!尼煤!小米路由那废柴现在已经被我降成二级路由了。(我还是得吐糟几句货,作为一个路由器,它的功能真的是太弱了,连几十块钱的路由器都支持的桥接、静态路由表啥的功能,它都不支持)

后来,我又折腾了一个上午,现在基本上都搞定了。把我装的东西,和我实现的功能,在这里罗列一下。具体的每一项,有可能的话,我再分篇展开。

aria2

Linux里的下载利器,它并不是一个简单的下载工具,你可以认为它是一个下载服务器,外部工具可以通过RPC的方式向它请求开始某个下载任务,查看下载任务的状态等等,在RPI上安装很简单sudo apt-get install aria2 -y,基本也不用什么配置吧,以Deamon的形式启动,打开远程访问即可。(TODO:补充配置文件和启动脚本

我在/etc/init.d下放了个脚本,加入到了自启动项,即可机器重启了,也能正常服务。

nginx && aria2-webui

装这货并不是为了Run一个WebServer,只是想用它来跑 aria2-webui,装上git(sudo apt-get install git -y),然后把aria2-webui的代码克隆到本地,在nginx的文件里配一个alias,指像这个文件夹即可。(TODO:补充配置文件)。然后在Chrome里装一个ThunderLixianAssistant,配置好aria2的远程RPC的URL,选择下载到本地『YAWW』,就能通过aria2来下载,然后下载的进度可以在网页上访问aria2-webui来查看。很方便。aria2下载的速度不比小米路由器下载的速度慢。

BitTorrent Sync

这货绝对是个好东西啊,可以无中心节点的在节点之同步数据。于是我在我自己外网的服务器上装了一个,在Raspberry Pi上也装了一个。即可以同步大文件,又可以同步小文件。这样我在外面的时候,如果有一些事情想让树莓派做,就把脚本写好传到公网的服务器上,通过btsync同步到家里,家里树莓派上定期扫描固定的目录下有无新的脚本,有则执行,并把结果输出到目录下。我通过公网的服务器同步下来的文件,就知道执行的结果了。

samba

安装sudo apt-get install samba samba-common-bin -y,装好以后记得用smbpasswd pi来设置一下密码。在小米盒子的高清播放器里就能连接了。当然,在任何的PC和MAC上也能连。

motion

此乃居家利器啊,安装同样很简单sudo apt-get install motion,启动也很简单sudo motion -c ./motion.conf,具体的conf文件可以在官网上看文档。这个东西有什么用呢,它可以监控USB摄像头(你随便几十块钱买的报像头基本上都能用)的画面变化,当有比较大幅度的变化的时候,会拍下一张照片或者保存一段录像。懂了吧,是不是跟某些智能摄像机宣传的功能有些像? 你如果仅仅是想通过USB摄像头拍照的话,可以装一个fswebcam,这货一个命令就能拍一张照片,也挺方便。然后用脚本把照片上传到Dropbox或者百度云之类的网盘上,在远程就能查看了。

Xware

这是迅雷出的远程下载的应用,哭晕在厕所,在这里下载,据说要选 Xware1.0.31_armel_v5te_glibc.zip

170 次查看 | 没有评论
2014年12月2日 | 归档于 Raspberry Pi

tmux支持gbk编码

其实背景是这样的,我用Mac,字符编码是UTF-8,我们的开发环境是Linux,字符编码是GBK,当然我可以把终端的编码改成GBK,就能轻松使用了。但是谁叫咱总觉得把本地终端的编码改得跟Host环境不一致别扭的呢,于是只能想其他办法。我在screen里是找到了完美的解决方案的。但是tmux之前实在是玩不转。后来Google到一个工具,luit,给你举个例子,聪明的你可能就明白这东西怎么用了:

luit -encoding gbk freaky_gbk_app

是的,就是这么简单,就可以把任何命令的输出按照你指定的格式转换为UTF-8,于是在我的.zshrc里加上一条

alias ssh-gbk='/usr/local/luit/bin/luit -encoding gbk ssh'

当我用ssh-gbk登录开发机的时候,luit会自动将输出从gbk转换到utf-8。

当然,也可以在开发机上装上luit后,加个如下的命令:

alias tmux-gbk='/usr/local/luit/bin/luit -encoding gbk tmux'

世界变得美好了,就是这样。

话说我已经从bash+screen的拥趸渐渐转移到zsh+tmux了,这个世界有多种选择,也是件美好的事情。

542 次查看 | 没有评论
2014年7月22日 | 归档于 Linux
标签: , ,

如何hook一个系统调用

背景 是这样的:某高人写的library里判断了新sock出来的socket的文件句柄要>0,且不谈这个assertion是否,我们的系统在运行到某个时间后,会不满足这个断言,说明有人把stdin给关了。

仔细想了一下,没有什么地方是需要把stdin关闭掉的,只能说明程序里有bug,比如某个fd被错误的赋予了0这个初始值,在没有初始化的情况下被关闭了。这是个bug。首先想到的办法是在所有调用close的地方都加上日志,这个工作量巨大,而且很容易出现遗露。其实在Linux里可以通过插入so的方式,hook某些动态连接库里的函数。只要用户没有选择静态编译,就会调用我们替换的版本。经过一翻Google,主要参考了 这篇 文章。最后成品的代码如下:

my_close.c

#define _GNU_SOURCE
#include <dlfcn.h>
#include <assert.h>

typedef int (*orig_close_f_type)(int fd);

int close(int fd)
{
    /* Some evil injected code goes here. */
    assert(fd > 0);
    orig_close_f_type orig_close;
    orig_close = (orig_close_f_type)dlsym(RTLD_NEXT, "close");
    return orig_close(fd);
}

使用这个方法编译:

gcc -g -shared -fPIC my_close.c -o my_close.so -ldl

然后在运行程序前定义LD_PRELOAD,方法为

export LD_PRELOAD=$PWD/my_close.so
./run_your_app

或者

LD_PRELOAD=$PWD/my_close.so ./run_your_app

如上代码在调用close时,如果fd等于0,会coredump。

510 次查看 | 3 条评论
2014年7月21日 | 归档于 Linux, 工作
标签: , , , ,

把git repository导入到svn

我这个需求确实比较奇葩。一般人都是先有了svn了,然后用git svn在本地管理一下,或者与某个git remote绑定一下。但是我的需求是先有了gitlab上的某个git repository,然后第一版写完之后,才申请了svn repository,我想把git中的内容全部导入到svn里,并且以后还是基于git svn来管理。( 因为狼厂现在统一的SCM还是SVN

然后大体思路是这样的

git svn clone https://svn.baidu.com/xxx/trunk/yyy
git remote add -f -tags -m master gitlab g@gitlab.baidu.com:xxx/yyy.git
git merge gitlab/master
git svn dcommit

之后再怎么搞就比较灵活了,比如直接绑定到gitlab/master上,或者在本地开发,再merge到gitlab/master上,或者在gitlab上再建一个svn的分支。

哎,git这种先进的生产工具怎么就被一帮人调研过之后给否定了呢。

443 次查看 | 没有评论
2014年7月21日 | 归档于 Linux, 技术

gdb中dump一段内存

我们会有这种需求,在 gdb 中将某段内存 dump 保存到文件中,比如一段无法在 gdb 中直接访问的二进制数据(一段私有格式的网络包什么的)。其实在 gdb 里这个命令就叫dump,这里仅给出一种简单的用法,其他的可以在gdbhelp

dump binary memory file start_addr end_addr

前面就写dump binary memory,后面接文件名,接着是起始地址,然后是尾地址。dump出来的数据怎么用就随君了。

话说都一年没写博客了,再过两天入职就三年了。

448 次查看 | 没有评论
2014年7月3日 | 归档于 C++, Linux, Unix, 工作
标签: , ,

入职两年了

上个月7月13日是我入职百度满两周年的日子。一直以为我曾经在入职一周年的时候写过一篇日志,可以翻来翻去,只找到一篇入职半月小记。本还想比较一下现在与一年前的心态,此已无从考据。唯有一篇27岁了的日志,还能回想起当时所说的那些烦心事情。好在也像当时所写,现在能嘴角一扬,没有想像中的那么坏,咬咬牙,没有过不去的坎。

前段时间,跟一位老程序员聊天,说到工作,我问他你觉得怎么衡量一个工作的好坏。他告诉我,看两点,一是成长;二是收获。回想自己在百度这两年,成长,学到了、巩固了许多知识;收获,职称和薪水都有不错的涨幅。我曾经在找工作回顾(7+1):微软中写过:

去百度是做基础相关的东西,我更偏向于这个方向,而且可以继续接触Linux相关的技术,对于一个对开源有着极大热情的我来说,更偏向于选择去这里,而且百度整个就是一个互联网企业,也是符合我的初衷。

这段话大体是没有错的,但其中有一点不正确,如果对于开源有着狂热的热情的话,还是不要来百度。在百度,很多东西都是自己做的。开源的东西也用,但绝对不是主流;核心的技术一般也不会开源出去。不过好在,不用开源一般也是因为开源产品在性能、稳定性、功能等方面满足不了我们的需求,而不是非得搞个新的出来。你如果非得问我,为啥不去修改开源的实现,我只能说,有些系统在提需求的时候,业界还没有相应的开源实现。

两年了,人越来越老,老了就不想过生日;老了就更加知道有些话,只能憋肚子里,不能说出来。我想每个事物都有他好的一面与坏的一面。曾经觉得应该在五年后评价自己当初找工作的选择,那就等再过段时间,等到自己离开了这家公司,亦或是干满了五年再说。

1,856 次查看 | 1 条评论
2013年8月12日 | 归档于 未分类
标签:

换到rMBP了

我为什么要换Mac?

其实我挺喜欢Linux的,上学的时候用来作实验、编程环境;工作以后作为日常的桌面。各种软件使用起来得心应手,多桌面切换随心所欲,各种开源软件自己编译、使用的各种开心。工作效率绝对不输Windows。

但是,很多『为什么』的问题总会有一个『但是』做转折,我这里也不例外。Ubuntu是我用了两年的发行版,Unity是我很喜欢的桌面环境,说到这里很多人可能就会因为世界观、人生观、价值观跟我不同关掉这个页面了。我们应该允许人们有着不同的追求。我为啥喜欢Ubuntu/Unity,因为用这俩不用折腾,一点都不折腾,开箱即用,配合各种快捷键,其实很爽啊。我基本上没怎么遇到过很多人说的经常崩溃、系统不稳定的问题。嗯,又瞎扯了半天,还没但出来。但是,很多软件没有Linux的版本,却有Mac的版本,而且很漂亮。即使有Linux上的版本的,也没有Mac上的漂亮。比如Chrome这货。在Linux上丑的我基本上不愿意使用。还有QQ,官方有Mac的版本,而且做得还挺好。Linux上呢,以前发行过32位的版本,后来好像也不维护了。

是的,因为Linux虽然好用,但是不够漂亮,一些锦上添花的软件在Linux下的使用体验不如Mac。有人说Mac是 命令行与桌面环境的完美结合 。我很认同。再加之MBP那帅气的外型,去香港玩的时候就顺了一台。

所以,简单的总结一下,就是Mac比Linux更漂亮,哈哈

为什么选Retina屏幕

我觉得,任何使用过视网膜屏幕的人,都不会再会喜欢用传统屏幕的笔记本,简直是渣,颗粒感太强。视网膜屏真的很舒服。如果你有购买MBP的冲动,强烈推荐。

Mac目前改变了我的什么习惯?

  1. 不再使用Firefox,转向Chrome
  2. 不再使用Thunderbird,转向Mail.app(我也试过其他一些好用的App,但是都不支持Exchange Server)
  3. 买了一套iWorks,不再使用LibreOffice
  4. 常用的Terminal换成了iTerm2
  5. 又开始用QQ、QQ五笔、迅雷
  6. 学会了用brew安装一些常用的软件包,这东西不错,适合有洁癖的人

我现在使用不习惯的地方

  1. 外接显示器时,某个应用全屏后,另一显示器则不能显示。这个要有多傻逼就有多傻逼,等着10.9升级可以解决这个,工作效率又能上一个台阶了
  2. 目录结构不是标准的Unix/Linux,所以能看到Applications/System啥的目录,有洁癖的人略觉不爽
1,693 次查看 | 2 条评论
2013年8月2日 | 归档于 未分类
标签:

一处死锁分析

最近在进行回归测试的时候,QA同学反映有一处死锁,导致大量线程Hang死。通过pstack查看后,发现如下可疑的两个线程:

Thread 1: 1. Hold A.ReadLock, 2. Request B.ReadLock
Thread 2: 1. Hold B.ReadLock, 2. Request A.WriteLock

看到此处就觉得比较奇怪,Thread2被Hang住很正常,因为A的读锁被Thread1占有了,此时无法加上A的写锁,但是为什么Thread 1会被锁死呢?因为此时B的读锁最少被Thread 2加上了,说明没有写线程占有写锁。且其他大量线程都被锁死在请求B的读锁的时候。

排除掉所有那些请求B的读锁被Hang死的线程后,发现了一个可疑的线程,这个线程Hang在如下位置

Thread 3: Request B.WriteLock

即存在一个线程在请求B的写锁,且处于等待的过程中。疑点比较明显,于是gdb之后,打印了一下这个pthread_rwlock_t的属性,发现其__rw_kind的属性值是1,顺藤摸瓜,发现这个读写锁在初始化的时候使用了如下过程:

pthread_rwlockattr_t attr;
pthread_rwlockattr_init(&attr)
pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP);
pthread_rwlock_init(&_rwlock, &attr);

其中PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP表明写锁优先的模式,即有写者等待时,所有读者被阻塞,所以因为Thread 3在获取B的写锁,则Thread 1无法获取B的读锁,从而导致A的读锁不会被释放,此种情况Thread 2无法获取A的写锁,也不会释放B的读锁,导致死锁。

解完Bug后,大呼原来多线程情况下,两个以前线程也有可能在某些情况下造成死锁。即只要有加锁顺序不一致的情况,且有读写锁混合的情况下,如果有写锁优先的情况,也有可能导致死锁。

1,977 次查看 | 1 条评论
2013年5月14日 | 归档于 C++, Linux, 工作, 技术

无觅相关文章插件,快速提升流量