2011年7月23日星期六

Using gogoc's IPv6 DNS Server

在/etc/NetworkManager/dispatchter.d/下新添加一个文件,命名为99dnsgogoc。当NetworkManager探知新的网络事件时,就会按文件名的字典序依次执行目录里的那些脚本,见man NetworkManager。往99dnsgogoc里添加如下内容:

#!/bin/sh -e

GOGOC_DNSSERVER="nameserver 2001:5c0:1000:11::2"
# Insert disco.gogo6.com's AAAA record to /etc/resolv.conf's first line
sed -i "1i$GOGOC_DNSSERVER" /etc/resolv.conf
这样就会优先使用gogoc具有IPv6解析功能的DNS服务器,比如BlogSpot和Youtube就可以很方便的访问了。

参考链接
http://gogonet.gogo6.com/forum/topics/installing-gogoc-in-ubuntu?commentId=3731159%3AComment%3A118744

2011年5月27日星期五

备忘:手机摄像头的再利用[Nokia 7260]

我有一个Nokia 7260手机,黑红的,进大学时带来了北京。2008年换了新手机,一直放寝室柜子里,企图某天知识到位了练练手。拆卸之,至少把那个摄像头用上。

7260的摄像头是30万像素的,有夜间模式,感光其实还满好的。想起来,这个手机给我留下了不少好资料。如今,正要毕业了,大学余额不足30天,虽然知识储备还远远不足,想要对这个项目的情况有所了解,所以开始收集资料了。

首先找到了一份7260-schematic.pdf的文档,包含有7260较详细的线路图。Camera模块的编号是X1470,上面标注的型号是CLE9014-01E。文档里边还包含有它的时钟信号在示波器里的参数。

还没有拆机,囧。先记在这里,这事够复杂。现在的思路是:拿到它的datasheet,分析工作机制。非电子工程专业,猜测后边会需要用到一些控制器,把最小元器件集合从手机里剥离出来,跟控制器对接,根据datasheet写驱动,当然,这是很后很后的话了。


更新:
1. CLE9014-01E,虽然搜索没有找到完全对应的数据。不过,它应该指的是摄像头的插座,叫做Camera Module Sockets,貌似由一家日本公司(www.smk.co.jp)设计制造。2011-05-27
2. STV0900BE,图上写着HW accelerator,应该是硬编解码之类的东西。它跟Camera连着。还是不知道他们之间的关系。2011-05-27

2011年4月29日星期五

Toggle Proxy Settings in Windows Through Python

不是说ctypes很牛逼吗,不是说扩展功能很强吗,怎么做到的?不想使用pywin32这样的第3方库。找着找着,发现Python自备了一个叫做_winreg的模块,还好在解释器里import了,吃惊不小。

好吧,代码显示不太正常的样子,pastbin吧。
import ctypes
import _winreg

# See http://msdn.microsoft.com/en-us/library/aa385328(v=vs.85).aspx
#: Causes the proxy data to be reread from the registry for a handle. No buffer is required. This option can be used on the HINTERNET handle returned by InternetOpen. It is used by InternetSetOption.
INTERNET_OPTION_REFRESH = 37
#: Notifies the system that the registry settings have been changed so that it verifies the settings on the next call to InternetConnect. This is used by InternetSetOption.
INTERNET_OPTION_SETTINGS_CHANGED = 39
# setup function
Wininet = ctypes.windll.Wininet
InternetSetOption = Wininet.InternetSetOptionW

HKEY_CURRENT_USER = _winreg.HKEY_CURRENT_USER
SUB_KEY_PATH = r'Software\Microsoft\Windows\CurrentVersion\Internet Settings'

def main():
    hkey = _winreg.OpenKey(HKEY_CURRENT_USER, SUB_KEY_PATH, 0, _winreg.KEY_READ | _winreg.KEY_WRITE)
    (ProxyEnabled, _) = _winreg.QueryValueEx(hkey, 'ProxyEnable')
    _winreg.SetValueEx(hkey, 'ProxyEnable', 0, _winreg.REG_DWORD, not ProxyEnabled)
    print 'enabled' if not ProxyEnabled else 'disabled'


    InternetSetOption(0, INTERNET_OPTION_REFRESH, 0, 0)
    InternetSetOption(0, INTERNET_OPTION_SETTINGS_CHANGED, 0, 0)

if __name__ == '__main__':
    main()

程序首先检查HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ProxyEnable的值,然后Toggle一下,0则设为1,1则设为0。然后通过InternetSetOption函数告知系统设置已变。

Chrome不自备代理控制功能,感觉Swichy的体验不好。之前尝试用显示的注册表操作命令完成,可是Chrome硬是不随之变化,非得再开一次那个Internet Options窗口才生效。特别是更新.pac文件的时候,真苦逼,居然假死。

想要接触Win32和Python的C扩展,希望对系统和编译器了解得多一些,但是Visual C++和Win32的那些宏真的很繁琐,即使用Python也不容易放开手脚。

更新:
[1]. 用ctypes调用RegOpenKeyEx和RegQueryKeyEx,http://pastebin.com/35zv649Q
[2]. 第一次写Windows API程序。真复杂。http://pastebin.com/kGWGJMmL

有用的链接:
[1]. InternetSetOption Function,http://msdn.microsoft.com/en-us/library/aa385114(v=vs.85).aspx
[2]. Option Flags,http://msdn.microsoft.com/en-us/library/aa385328(v=vs.85).aspx
[3]. The ctypes package,http://starship.python.net/crew/theller/ctypes/

2011年4月28日星期四

Variables With Underscores In Python

Python's magical underscored identifiers always surprised me!

__repr__, __unicode__, __str__, __len__, __gt__, __lt__, __eq__, __hash__, __get__, __set__, __getattr__, __setattr__, __del__, __iter__, __next__, __getitem__, __dict__, __blah__

所以……有木有!有木有!!下面讨论的场景主要是在类的定义中。可参见链接[1]。

1. 一个下划线
这是一个约定。使用单个下划线的标识符表示该符号是对象私有的,使用者不应直接操作之。

2. 两个下划线
在类的定义中,如果出现__identifier这样的符号,则不论其所处的语法上下文,都会被符号_classname__identifier代替,其中,classname是去掉下划线的类名。如下例:

>>> def __print_hello():
...     print 'hello'
...
>>> class Class(object):
...     def pack(self):
...             __print_hello()
...
>>> inst = Class()
>>> inst.pack()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in pack
NameError: global name '_Class__print_hello' is not defined
>>>
嗯,我就在第2种情况里挂了一次。。

链接:
[1]. Private Variables,http://docs.python.org/tutorial/classes.html#private-variables
[2]. The meaning of a single- and a double-underscore before an object name in Python,http://stackoverflow.com/questions/1301346/the-meaning-of-a-single-and-a-double-underscore-before-an-object-name-in-python

Streams in NTFS

使用Windows 7后发现,从浏览器下载的文件的属性多了些东西,例如:
"This file came from another computer and might be blocked to help protect this computer"
IE,Google Chrome,Firefox都支持这个功能。这个属性不会随着位置的移动和拷贝而丢失。"Unblock"之后的文件与原文件的各种哈希校验也一致。How Windows managed to track such kind of identity?

这个特性来自于NTFS的Streams概念。存放着数据之外的数据。打开一个命令行,执行以下命令:

echo Hello, Streams >test:stream
more <test:stream
第1条命令会创建一个test文件,文件的大小为0. 第2条命令会显示结果“Hello, Streams”。重定向符冒号后边的即是流的名称了,每个文件可以有多个。上边提到的识别功能即是利用NTFS Stream这种“数据之外的数据”做到的。

使用链接[1]里提供的工具,可以查看到一个文件包含的流信息。用那个工具检查从浏览器里下载的文件,有这样的结果:

F:\>streams breathe-life.jpg

Streams v1.56 - Enumerate alternate NTFS data streams
Copyright (C) 1999-2007 Mark Russinovich
Sysinternals - www.sysinternals.com

F:\breathe-life.jpg:
   :Zone.Identifier:$DATA       24

F:\>more <breathe-life.jpg:Zone.Identifier
[ZoneTransfer]
ZoneId=3
从链接[2]我们可以知道流的命名规范为:filename:stream name:stream type,所以呢,Zone.Identifier就是流的名字了,$DATA即流的类型。那么,如果清空掉这个流的信息会怎么样呢?其实就相当于“Unblock”操作了。

F:\>set /pvar=<nul >breathe-life.jpg:Zone.Identifier
在链接[3]里边有一个写流的例子,用C也可以的,就写了一个。
#include <stdio.h>

int main()
{
    FILE *fout;

    fout = fopen("test:stream", "wb");
    fprintf(fout, "Hello Stream Through Pure C.\n");
    fclose(fout);
    return 0;
}

链接[5]是比较全的一篇介绍,Data Streams是NTFS的特性,所以,当文件从NTFS向FAT转移时,流的信息会丢失。链接[6]来自维基,对Streams的背景进行介绍,在文件系统里边,除我们看到的常规文件属性信息外,还有一种叫做fork的信息,fork信息最大的不同是它没有大小限制,甚至可以比正常数据更大,Streams即是NTFS里的fork。


链接:
[1]. Streams v1.56,http://technet.microsoft.com/en-us/sysinternals/bb897440.aspx
[2]. File Streams,http://msdn.microsoft.com/en-us/library/aa364404(VS.85).aspx
[3]. Using Streams,http://msdn.microsoft.com/en-us/library/bb540537(v=VS.85).aspx
[4]. http://superuser.com/questions/38476/this-file-came-from-another-computer-how-can-i-unblock-all-the-files-in-a
[5]. Practical Guide to Alternative Data Streams in NTFS,http://www.irongeek.com/i.php?page=security/altds
[6]. Fork (file system),http://en.wikipedia.org/wiki/Fork_(filesystem)

2011年4月25日星期一

使用gogo6创建IPv6网络

1. 点击此链接,进去创建一个账号Freenet6账号,(注:Freenet6和gogoNET账号用处是不同的)。

2. 使用的操作系统Ubuntu 10.10,需要安装的包名为“gogoc”。

3. 配置/etc/gogoc/gogoc.conf。下面的配置是用于路由器方式的,eth1属于VMnet0网络,gogoc服务启动后,会使用radvd给VMnet0上的机器提供地址自动配置服务。原始文件配置文件的注释中有详细的说明,配置时只需要相应的uncomment就好了,赞!
userid=username
passwd=password
server=authenticated.freenet6.net
auth_method=any
host_type=router
prefix_len=64
if_prefix=eth1
log_stderr=0
log_file=3
4. "Not starting gogoc - no server key",或者plain方式可以成功,passdss-3des-1却不可以。参见文档/usr/share/doc/gogoc/README.debian,解决办法有两种:
    1. 使用/usr/sbin/gogoc -n启动gogoc,根据提示手动添加公钥
    2. 编辑/etc/default/gogoc,修改选项:CHECK_KEYFILE="no"
公钥文件位置:/var/lib/gogoc/gogockeys.pub,可以打开看一看。

5. 服务控制
    1. 打开,停止,重启服务:sudo service gogoc start|stop|restart
    2. 强制关闭:sudo killall gogoc radvd
    3. 打开和关闭开机自启动:sudo update-rc.d gogoc enable|disable

6. 修改gogoc启动radvd时的配置参数。相关的文件在/usr/share/gogoc/template/linux.sh,有这样的内容:
cat > "$rtadvdconfigfile" <<EOF
##### rtadvd.conf made by gogoCLIENT ####
interface $TSP_HOME_INTERFACE
{
  AdvSendAdvert on;
  AdvLinkMTU 1280;
  prefix $TSP_PREFIX::/64
  {
    AdvOnLink on;
    AdvAutonomous on;
  };
};
EOF
修改cat行和EOF行之间的内容就好了,比如把AdvLinkMTU调大。

移位和尾端

遭遇多次了,还是记下来好。曾经看到一些对尾端的描述,用的是“前前后后”、“左左右右”这些个相对参照,描述的内容一样,每各人每次的理解常常不一致。所以先定义一些“绝对参照”:

对于内存中数据的表示,屏幕上,纸上,从左到右,从上到下,地址从小到大。
对于逻辑上数据的表示,屏幕上,纸上,从左到右,从上到下,先是高位(MSB),再是低位(LSB)。

1. 移位操作是有独立意义逻辑意义的,不依赖尾端。以0x0102为例:
    <<. 左移4位,就增大16倍,变成0x1020
    >>. 右移4位,就用整数除法减小了16倍,变成0x0010

2. 尾端影响的是数据在内存、CPU、线路上存储,传输和处理时的排布。以0x0102为例,在大尾端机器内存中的顺序是01 02,在小尾端机器内存中的顺序是02 01。识记方法,我们用的x86电脑是小尾端的,小尾端,低地址对应低位,高地址对应高位。

3. 字节为单位,8比特
以IPv4和IPv6中的头部字段中的片偏移和标志位为例,演练一下移位操作和尾端。frag_off保存的是一个16位的大尾端数据,其中有13位是片偏移,3位是标志位,排布如下:
IPv4中:(0(1),DF(1),MF(1),Fragment-Offset(13))
IPv6中:(Fragment-Offset(13),Res(2),M(1))
其中,Res是保留位,全部置0,MF与M是等价的两个标志

从IPv4的格式转换为IPv6的格式
#define IP_OFFSET 0x1fff
#define IP_MF     0x2000

frag_off_6 = (ntohs(frag_off_4) & IP_OFFSET) << 3;
frag_off_6 &= 0xfff8;
frag_off_6 |= (ntohs(frag_off_4) & IP_MF) ? 0x0001 : 0x0000;
frag_off_6 = htons(frag_off_6);
总结:不纠结于那8+5=13的比特边界,先把数据转成宿主机的格式(ntohs),然后换照“绝对参照”中的逻辑,该怎么操作就怎么操作,操作完成后,再转成目标尾端(htons)。

4. Bit Field,下面这个结构定义是怎么回事?
struct iphdr {
#if defined(__LITTLE_ENDIAN_BITFIELD)
    __u8    ihl:4,
        version:4;
#elif defined (__BIG_ENDIAN_BITFIELD)
    __u8    version:4,
          ihl:4;
#else
#error    "Please fix <asm/byteorder.h>"
#endif
计算机在读写内存的时候,逻辑上最小的单位是1个字节,也就是8比特。IPv4头部中version和ihl各占4比特,编译器要把它们组装成1个字节。一般来说,传输时,version在前,ihl在后。因此,这2个4比特的组装顺序不是儿戏。

文章最开始规定的“绝对坐标”也是编译器和代码编写者之间的逻辑约定,地址前低后高。以小尾端为例,按第2条描述的识记方法,低(ihl)对应LSB,高(version)对应MSB,因此组装后的字节就是(version,ihl),Bingo!

如果代码就按defined(__LITTLE_ENDIAN_BITFIELD)来写,在大尾端机器中会怎么样呢?低(ihl)对应MSB,高(veresion)对应LSB,因此组装后的字节就是(ihl,version),反啦!

5. 有用的链接
[1]. Low Level Operators and Bit Fields, http://www.cs.cf.ac.uk/Dave/C/node13.html