SOCKS5代理TCP CONNECT实验

背景知识

RFC1928
WiKi

实验目的

了解使用Socks代理进行TCP连接的过程。

实验环境

ubuntu

实验步骤
  1. 安装sSocks(Socks5 Sevrer)
    wget http://pilotfiber.dl.sourceforge.net/project/ssocks/ssocks-0.0.14.tar.gz
    tar zxvf ssocks-0.0.14.tar.gz
    cd ssocks-0.0.14
    ./configure
    make

  2. 安装nmap(我们用该软件包中的ncat创建一个TCP的echo server,作为要用代理连接的目标服务)
    sudo apt-get install nmap
    安装完成后使用命令:
    ncat -l 8082 —keep-open —exec “/bin/cat”
    测试echo server是否OK

  3. 启动sSocks server(无认证模式)和echo server
    客户机连接到服务器,先发送一个版本标识/方法选择报文:

    VER: X’05’ SOCKS协议版本号
    NMETHODS: METHODS的个数,我们使用X’01’
    METHOD:
    当前被定义的的值有:
      >> X’00’ 无验证需求
      >> X’01’ 通用安全服务应用程序接口(GSSAPI)
      >> X’02’ 用户名/密码(USERNAME/PASSWORD)
      >> X’03’ 至 X’7F’ IANA 分配(IANA ASSIGNED)
      >> X’80’ 至 X’FE’ 私人方法保留(RESERVED FOR PRIVATE METHODS)
      >> X’FF’ 无可接受方法(NO ACCEPTABLE METHODS)
    这里我们使用X’00’
    我们发送十六进制数据: 05 01 00
    Socks5服务器应答报文:

    因为我们使用了无认证模式,因此正确情况下服务器应答:05 00

  4. 客户机发送代理需求报文
    报文格式:

    其中:
    VER protocol version:X’05’
    CMD
     CONNECT X’01’
     BIND X’02’
     UDP ASSOCIATE X’03’
    RSV RESERVED
    ATYP address type of following address
     IP V4 address: X’01’
     DOMAINNAME: X’03’
     IP V6 address: X’04’
    DST.ADDR desired destination address
    DST.PORT desired destination port in network octet order

本次实验,我们测试TCP CONNECT命令,请求代理服务器连接到我们使用ncat启动的TCO echo server。
发送十六进制数据:05 01 00 01 73 9f 9d 7e 1f 92
正常情况下,我们会收到服务器的应答报文,格式如下:

其中:
VER protocol version: X’05’
REP Reply field:
  X’00’ succeeded
  X’01’ general SOCKS server failure
  X’02’ connection not allowed by ruleset
  X’03’ Network unreachable
  X’04’ Host unreachable
  X’05’ Connection refused
  X’06’ TTL expired
  X’07’ Command not supported
  X’08’ Address type not supported
  X’09’ to X’FF’ unassigned
RSV RESERVED
ATYP address type of following address
  IP V4 address: X’01’
  DOMAINNAME: X’03’
  IP V6 address: X’04’
BND.ADDR server bound address
BND.PORT server bound port in network octet order
标志RESERVED(RSV)的地方必须设置为X’00’。

代理完成后,就可以发送一些数据测试下,是否能收到echo server的响应了:

微代码

记录一些平时缩写或网上偶遇的代码段,以备不时之需。

Java

  1. 单例模式的最佳写法
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    public class Singleton {

    private volatile static Singleton instance;
    private Singleton () {}
    public static Singleton getInstance() {
    if(instance == null) {
    synchronized(Singleton.class) {
    if(instance == null) {
    instance = new Singleton();
    }
    }
    }
    return instance;
    }
    }

PyQt4中的右键弹出菜单

笔者在用PyQt4写GUI程序时,有时为了获得更好的交互体验,会给一些控件加右键弹出菜单。这里以一段代码为例,记录下给控件添加右键菜单的步骤。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#-*- coding: utf-8 -*-
import sys
from PyQt4 import QtGui
from PyQt4 import QtCore

class TestWidget(QtGui.QWidget):

def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)

self.setGeometry (100, 100, 200, 120)

# STEP 0 create a widget
self.button = QtGui.QPushButton("Test button", self)
# STEP 1 setContextMenuPolicy
self.button.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
# STEP 2 connect signal
self.connect(self.button,
QtCore.SIGNAL("customContextMenuRequested(const QPoint&)"),
self.onButtonPopMenu)
# STEP 3 make a menu and add actions
self.buttonMenu = QtGui.QMenu(self)
action1 = QtGui.QAction("Test Action", self,
priority=QtGui.QAction.LowPriority,
triggered=self.onAction1)
# Add icon for menu action if you have icon resource(not necessary)
#action1.setIcon(QtGui.QIcon(":/app/icons/app/copy.png"))
self.buttonMenu.addAction(action1)
# you can create more actions and add them to self.buttonMenu

def onButtonPopMenu(self, point):
self.buttonMenu.exec_(self.button.mapToGlobal(point))

def onAction1(self):
print "Hello uname"

if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
widget = TestWidget()
widget.show()
app.exec_()

以上代码运行效果如图:

在Intel Edison开发板上安装ubilinux系统


Intel的Edison开发板使用一颗双核双线程500MHz的Intel凌动CPU和一个32位100MHz的Quark MCU。有板载的WiFi和BLE资源。官方的给出的Linux版本为Yocto Linux。
官方资源链接
个人用惯了Ubuntu,感觉Yocto Linux没有那么给力。于是找到了一个非官方推荐的基于Debian “Wheezy”的ubilinux的系统
以下是在Edison上安装ubilinux的步骤。

  1. 下载ubilinux, http://www.emutexlabs.com/files/ubilinux/ubilinux-edison-150309.tar.gz
  2. 将压缩包中的toFlash文件夹解压到本地磁盘
  3. 因为ubilinux安装过程需要用到dfu-util工具,因此需要下载dfu for windows
    笔者开始没有下载该工具直接执行toFlash目录下的flashall.bat脚本时就遇到了如下错误。
  4. 下载好dfu for windows后将,下载压缩包中的dfu-util.exe和libusb-1.0.dll拷贝到步骤1得到toFlash目录中。
  5. 给Edison上电并使用串口登录Yocto Linux环境。
  6. 执行toFlash目录下的flashall.bat脚本,然后已登录Edison的串口终端中执行reboot重启设备。此时安装过程就会开始,如图:

    安装过程中Edison会重启一次,该过程中不要断电,也不要断开PC与Edison的通信线路。
    需要特别注意的是,最后一步的Flashing rootfs会等待比较久,耐心等待就好,不要做任何Ctrl+C的打断操作!
  7. 安装完成后,Edison会在重启一次。重启完成后在串口终端中使用账户edison/edison登录即可。

后记:没有找到比较快的软件源,apt-get update会比较慢:(
更多的安装细节可以在这里找到
https://learn.sparkfun.com/tutorials/loading-debian-ubilinux-on-the-edison

一种嵌入式设备数据的实时无线观察方法

  笔者有一块STM32的开发板,需要读取MPU6050的姿态数据。这些数据在经过均值和卡尔曼滤波等处理后,得到一些角度数据。这些角度数据对笔者进行的开发调试非常重要,因此需要一种可以实时观察这些数据的手段。
最简单的方式是通过一根串口线连接到PC,打开PC端的串口数据处理软件即可。但这样会有一根数据线,数据线的存在造成的物理抖动会干扰到这些数据,并且会阻碍开发板在更大的空间内自由移动。因此需要寻找无线的解决方案。

  笔者使用如下方式,通过WiFi获取开发板数据并在PC端的RealtimePlotter软件上显示数据波形。

  1. Serial<->Tcp Bridge用来将开发板的串口数据通过桥接的方式提供给通过TCP连接的COM2TCP。这里的Serial<->Tcp Bridge笔者使用一个运行在安装了OpenWRT系统开发板上的Linux进程(sock2serial)。
  2. COM2TCP是一个可以Windows系统上桥接网络和串口通信的工具,下载地址。下载完成后打开,可看到如下的设置界面:

    将IP和TCP Port配置为Serial<->Tcp Bridge监听的地址和端口。COM Port选择一个未使用的COM口,单击连接即可。
  3. 笔者用来观察波形的软件RealtimePlotter是github上的一个开源工具,使用Processing语言编写。该软件从串口读取数据并绘制波形,支持最大六个通过的数据绘制。
    数据格式为: “value1 value2 value3 value4 value5 value6\r”。有时间可以把这个工具修改为从TCP服务器读取数据,这样就可以省去COM2TCP了。
    RealtimePlotter有三个目录,分别为BasicRealtimePlotter、RealtimePlotterArduinoCode和RealtimePlotterWithControlPanel。笔者使用BasicRealtimePlotter,这里需要编辑BasicRealtimePlotter.pde代码,修改在COM2TCP中使用的串口号,如图:

一切准备就绪后,运行BasicRealtimePlotter.pde就可以看到数据了。
有几点需要注意:

  1. 原始数据仍通过串口输出,波特率设置高点可以更快传输数据。
  2. BasicRealtimePlotter软件的数据绘制能力有限,数据太快太多有可能绘制不过来。

NodeMCU上手笔记

笔者最近想把开发板的高速传感器数据通过无线的方式传输到PC端进行波形分析,需要一个串口到WiFi的透传模块。之前笔者一直使用路由器刷入OpenWRT的方式来做串口和WiFi的透传,这样摆脱了调试线,又有不错的通信速度,效果还是不错的。

之前了解过NodeMCU,看介绍它也有WiFi和串口,应该可以满足需求,于是在淘宝买了一块做了实验。关于NodeMCU,笔者这里简单说下:
NodeMCU是一个基于esp8266的开发板,官方的说法它是一个超简单的物联网开发平台。确实,它有WiFi和串口,上可以连接云主机,下可以通过串口或I2C与其他传感器通信。不过笔者的试用感受,这东西玩玩就行了,很难想象它将来会在物联网上有什么大的成就。
不过笔者比较欣赏的是它提供了一套Lua的API,这对之前没有搞过硬件开发的纯软程序员来说是个比较好的切入点。
它的官网:http://www.nodemcu.com/
它在Github的开源地址:https://github.com/nodemcu/nodemcu-firmware
(笔者之前也一度想给STM32开发一套Lua的API,一直没有时间精力去搞 - - !)

一般从淘宝买回来的时候,卖家已经帮忙刷好了固件。不过自己还是要熟悉下过程,再刷一遍:

1. 安装串口驱动

如果购买的是esp8266模块,则需要一个TTL转串口的模块,按照官方文档接好Rx,Tx,并安装好串口驱动。
如果购买的是已经做好的NodeMCU开发板,那USB连接到电脑,并安装好串口驱动就好了。

2. 刷固件

去NodeMCU的Github项目地址去下载它的固件nodemcu_xxx.bin和烧写工具ESP8266Flasher.exe
https://github.com/nodemcu/nodemcu-firmware/releases
https://github.com/nodemcu/nodemcu-flasher

打开ESP8266Flasher,选择NodeMCU使用的串口(一般ESP8266Flasher会自动选择该串口,如果你只连接了这个一个串口设备)。
在Config页中的第一个选择框处选择已下载的固件bin文件。

然后切换到Operation页中单击Flash按钮开始烧写。大概3分钟烧写完成,如下图所示:

3. 测试

打开串口工具,选择NodeMCU的串口号,波特率默认9600(暂时没有找到修改方法,可能需要重新编译固件)。
打开后,NodeMCU会输出几个乱码(没有的话,可以reset下板子)然后版本号、一行错误提示,和输入提示符。如图:

我们输入一行Lua代码:
print(“Hello NodeMCU, This is uname”)
可以看到NodeMCU正常执行了该打印语句。

4. 如何做串口到WiFi的串口

至少有两种方式,一是修改固件代码,从esp8266提供的C API层搞起编译一个自己的专有透传固件。前端时间在一个STM32的论坛看到,已经有人这么做了(不过是Socket通信是UDP,不推荐)。
另一种方式就是使用Lua的API写自己的穿透脚本,然后通过串口写入NodeMCU。这样的方式相对简单易行,但有一个问题,如何让自己的脚本在板子启动时自动执行。
我们仔细看下上图中的那行错误提示:
lua: cannot open init.lua
实际上NodeMCU上电后默认会执行init.lua中的代码,因为刷入的固件中并没有init.lua这个文件,所以才会出错。
我们先尝试写一行打印语句到init.lua中看看是不是会在上电后默认执行:

可以看到,我们写入init.lua中的代码在上电时自动执行了!
于是,我们可以参考官方给出的Lua API:https://github.com/nodemcu/nodemcu-firmware/wiki/nodemcu_api_cn
写自己的透传脚本了。

5. 怎么上传脚本到NodeMCU开发板

刚刚没有交代。这里补上,如上图,通过Lua API提供的file模块即可将代码一行一行的写入init.lua。
你需要了解一些Lua的语法。

6. 透传脚本

笔者已经写好了用于透传的init.lua脚本,并写好了用于上传init.lua的flash.py脚本和用于删除已上传init.lua的clean.py脚本(若要使用该上传和删除脚本,需按照Python环境和pyserial模块)。

  • init.lua:

不要按照上图重新敲代码,所有代码和工具我都已上传到我的github:https://github.com/uname/nodemcu-sernet-proxy

使用flash.py上传init.lua:

上传完成后重新在串口工具中打开串口:

此时你从串口敲入的Lua语句不再被执行,而是直接转发到通过TCP连接到NodeMCU服务器的客户端!
以后该脚本一上电,init.lua脚本执行,进入透传模式。再也无法像刚开始那样愉快的输入Lua语句执行了,如果要回到之前那样,执行执行clean.py脚本。

记住一下几点:

  • 透传模式下NodeMCU的WiFI工作在AP模式,网络SSID一般为ESP_XXXXXX,密码为空
  • 串口波特率貌似只能为9600
  • 串口发送的数据必须以\r或\n结尾开会被转发(转发出去的数据中会去除\r\n)

玩Arduino的同学可以用这个转发脚本搞一个WiFi控制的小车哦:)

2015++

此刻,办公室下午三点半起来活动的广播响起。
记得这个活动在12年发起,不知不觉的光阴流转,忽然已是2015的最后一天!
深圳的冬天,没有一丝冷意。办公室的暖气甚至一度让我觉得闷热,但在此刻,我却感到了阵阵冷意,那是一种失落时由内而外的刺痛。
窗外,依旧是记忆中的模样——常年绿色的行道树、匆忙的车流、还有深圳楼市野蛮生长的喧闹……
从未在新年来临时如此不舍,愿2016工作顺心,身体健康,家人平安,更祝愿亲爱的一切都好……

Long Beach. LA. USA(拍摄于15年911纪念日)

树莓派2通过I2C访问MPU6050

笔者最近做了一个平衡车,主要用到了STM32F10x + MPU9250 + FreeRTOS。
手边正好还有一块MPU6050的模块和树莓派2,就趁热打铁先把树莓派访问MPU6050的路走通,以便后面需要时查阅。

1. 首先要启动树莓派的I2C功能

sudo mount /dev/mmcblk0p1 /mnt/
cd /mnt
sudo vim config.txt

找到下面两行

将注释符号#删掉,如果没有上面两行则自己编辑保存。然后reboot系统。

2. 安装i2c-tools

sudo apt-get install i2c-tools

顺便推荐个国内的树莓派软件源:
deb http://mirrors.ustc.edu.cn/raspbian/raspbian/ wheezy main contrib non-free rpi
编辑/etc/apt/sources.list,注释掉官方源,添加上面那个。重新sudo apt-get update下。

3. 连接MPU6050设备,并测试I2C驱动是否已经OK

接线只需要四根:电源正3.3V,Ground,SCL,SDA。
MPU6050模块上会有标志,与树莓派对齐用杜邦线接好即可。
树莓派2的IO定义如图:

连接好设备后,通过命令:
i2cdetect -l
查看设备是否已正常工作。如果你的树莓派只接了MPU6050一个I2C设备,对应设备文件为:
/dev/i2c-1

至此I2C驱动已开启,设备工作正常,可以继续写代码访问数据了。


4. 代码

Github上有个MotionSensorExample用于树莓派对MPU6050/MPU6500/MPU9150/MPU9250的I2C访问。
不过笔者clone了代码,在树莓派2上编译失败了。
有人也遇到了相同的问题并发了issue#
inv_mpu_lib/inv_mpu.c:392:2: error: expected primary-expression before ‘.’ token
截至到笔者发此文章时,作者似乎也并未修改该问题(其实就是树莓派2上安装版本的g++编译器不支持C99标准的C struct复合字面量初始化问题)。
于是笔者fock了源码,并修复了这个错误。所以这里就用我修改后的MotionSensorExample来测试吧。

5. 编译&&测试

ssh或者serial登陆到树莓派2,clone笔者修改后的MotionSensorExample:

git clone https://github.com/uname/MotionSensorExample
cd MotionSensorExample
make

如果一切OK的,会在MotionSensorExample生成一个测试程序mstest,执行mstest观察数据读数。

6. 其他

MotionSensorExample通过条件编译的方式来支持不同的MPU(6050/6500/9150/9250),只要修改位于MotionSensorExample/MotionSenso下的Makefile即可:
CXX_OPTS=-c -DMPU6050 -DMPU_DEBUGOFF -I../libs/

实际上笔者这次测试用的是MPU9250,但是如果编译时使用-DMPU9250,则编译出的程序并不能正确工作,
不过既然-DMPU6050可以拿到yaw, pitch, roll数据,暂时也就够用了。错误定位等到有时间再慢慢看吧。