2007年12月20日 星期四

SIP Transaction and Dialog parameters

Transaction:
Via - Must contain a branch parameter to identify the transaction created by that request. The branch ID must always begin with the characters “z9hG4bK” as a magic cookie.
Branch parameter “branch=z9hG4bK776asdhds” to identify the transaction


Dialog:
The combination of the “To tag”, “From tag”, and “Call-ID” completely defines a peer-to-peer SIP relationship between Alice and Bob and is referred to as a dialog.

2007年12月19日 星期三

bash, tcsh shell variable experience

Default file permission is 666 (user, group, other can read/write file)
Default directory permission is 777 (user, group, other can none/add, delete/list the files of the directory)

#tcsh .tcshrc file

alias h history 25
alias j jobs -l
alias la ls -a
alias lf ls -FA
alias ll ls -lA
alias su su -m

setenv EDITOR vi
setenv VISUAL ${EDITOR}
setenv EXINIT 'set autoindent'
setenv PAGER more

set path = (~/bin /bin /sbin /usr/local/{,s}bin /usr/{bin,sbin,X11R6/bin,pkg/{,s}bin,games} )

if ($?prompt) then
# An interactive shell -- set some stuff up
set filec
set history = 1000
# set ignoreeof
set mail = (/var/mail/$USER)
set mch = `hostname -s`
set prompt = "${mch:q}: {\!} "
umask 22
endif
alias vi env TERM=xterm vim
setenv CVSROOT :ext:username@IP-Address:/home/cvsroot
setenv CVS_RSH /usr/local/bin/ssh
set prompt="[%{^[[1;32m%}%n%{^[[31m%}@%{^[[33m%}%m%{^[[36m%}(%{^[[34m%}%p%{^[[36m%}):%{^[[35m%}~%C2%{^[[0m%}]"
setenv LD_LIBRARY_PATH /usr/pkg/lib:/usr/lib/compat/aout:/usr/X11R6/lib:/usr/local/lib:/usr/X11R6/lib/aout:/usr/lib/aout:/usr/lib
#setenv ENABLE_STARTUP_LOCALE zh_TW.Big5
#setenv LC_CTYPE en_US.ISO_8859-1
#setenv LANG zh_TW.Big5
# 若要支援中文顯示, 請設定成下面的 LC settings
setenv LANG zh_TW.UTF-8
setenv LC_CTYPE zh_TW.UTF-8
setenv LC_ALL zh_TW.UTF-8
setenv LC_MESSAGES zh_TW.UTF-8
unset autologout

tcshell 的cvs environment variable設定方法
setenv CVSROOT ":ext:username@1.2.3.4:/home/cvsroot"
setenv CVS_RSH "/usr/bin/ssh"

bashrc 的cvs environment variable設定方法
export CVSROOT=:ext:username@1.2.3.4:/home/cvsroot
export CVS_RSH=/usr/bin/ssh

The following are reference from http://www.horde.org/source/using.php
sh, ksh, bash, zsh:
export CVSROOT=:pserver:cvsread@anoncvs.horde.org:/repository

csh, tcsh:
setenv CVSROOT :pserver:cvsread@anoncvs.horde.org:/repository


# 另外要設定環境變數, 一般可以使用 export (設定單個) or source (讀入一個config file)

在/root/.bashrc or /root/.bash_profile檔案中,
加入下列的參數
export PS1='[fish]# '
則shell 的prompt ]就會變成
[fish]#

sh, bash:
set environment variable:
# export Variable_Name=Variable_Value
show all the environment variable values
# set
reload config file
# source /to/path/.bashrc

csh, tcsh:
set environment variable:
# setenv Variable_Name Variable_Value
show all the environment variable values
# setenv

2007年10月9日 星期二

Fast path vs Slow path in linux kernel routing

Fast path vs Slow path in Linux kernel routing

執行順序
先做Fast Path Routing, 如果找不到, 才會做 Slow Path Routing
ip_input.c: ip_rcv_finish: PREROUTING CHAIN traversal 之後的function, 做ip packet receive 後的最後處理
ip_input.c: ip_rcv_finish: function 定義於此
ip_input.c: ip_route_input: 做fast path routing, 作法為利用rcu_dereference 循序去撈出rt_hash_table[hash] 裡面的 chain 為rth (struct rtable), 然後和 source, destination, iif, mark, tos 等作比較, 若符合, 則update lastuse 為jiffies, 另外設定 skb->dst = (struct dst_entry*)rth, 讓之後可以使用
route.c: ip_route_input: function 定義於此
route.c: ip_route_input_slow: 如果fast path routing 找不到之前的routing cache, 我們就做slow path routeing
route.c: ip_route_input_slow: function 定義於此
route.c fib_lookup: 執行fib search
net/ipv4/fib_rules.c: fib_lookup: function 定義於此
net/ipv4/fib_rules.c: fib_rules_lookup: 帶了定義在fib_rules.c 裡面特有的參數, 利用fib4_rules_ops 這個變數
net/core/fib_rules.c: fib_rules_lookup: function 定義於此
net/core/fib_rules.c: fib_rules_lookup: 利用 list_for_each_entry_rcu 去逐步檢查每個
ops->rules_list 的rule 和 fl (struct flowi) 是否符合
net/core/fib_rules.c: ops->action: 執行match rule->action
net/ipv4/fib_rules.c: fib4_rule_action: function 定義於此
net/ipv4/fib_rules.c: fib4_rule_action: 當rule->action 為 FR_ACT_TO_TBL時, 執行 include/net/ip_fib.h: fib_get_table: 如果是non-Local, 則為ip_fib_main_table, 如果是Local, 則為ip_fib_local_table
net/ipv4/fib_rules.c: tbl->tb_lookup




Fast path
* using routing cache
* accomplish by ip_route_input function
compare the data of routing cache (rth->fl, rtable->flow)



Slow path
* using FIB(Forwarding Information Base)
* accomplish by ip_route_input_slow, fib_lookup

2007年9月21日 星期五

share/static library experience sharing

一般gcc compile 預設都是使用share library (libXXX.so.X), 除非compile時, gcc 加上 -static 或是直接將.a (libXXX.a) 和.o (object files)放在一起來link成execution file

如何看static library 的成員API 有哪些
# strings libpcap.a | grep pcap_findalldevs
pcap_findalldevs
pcap_findalldevs
pcap_findalldevs

Show the member symbols/variables/functions of shared library
# nm /usr/local/src/library/libpcap/libpcap-0.9.7/libpcap.so.0.9.7 | grep pcap_findalldevs
000052c0 T pcap_findalldevs

nm can show the shared library (libXXX.so.a.b.c) and static library (libYYY.a)

More verbose command with options
with -l, it will show the symbols/variables/functions appearing place(file name and line number) originally
with -o, it will print out the symbols/variables/functions belong to which library

show the symbols of the static library
# nm -o -l /usr/lib/libeXosip2.a 2> /dev/null | grep eXosip_init
/usr/lib/libeXosip2.a:eXconf.o:00001800 T eXosip_init /usr/local/src/sip/libeXosip2-3.0.3-3/src/eXconf.c:616

show the symbols of the shared library
# nm -o -l /usr/lib/libeXosip2.so.4.2.0 2> /dev/null | grep eXosip_init
/usr/lib/libeXosip2.so.4.2.0:0000c4ce T eXosip_init /usr/local/src/sip/libeXosip2-3.0.3-3/src/eXconf.c:616

If you have ever used to strip the static/shared library, all the symbols (functions/variables) inside the file will be deleted.
# strip /usr/lib/libeXosip2.a
# strip /usr/lib/libeXosip2.so.4.2.0

The type is displayed as a letter;
lowercase means that the symbol is local,
uppercase means that the symbol is global (external).

Typical symbol types include
T (a normal definition in the code section),
D (initialized data section),
B (uninitialized data section),
U (undefined; the symbol is used by the library but not defined by the library),
W (weak; if another library also defines this symbol, that definition overrides this one)



如何看某一個程式使用哪些shared library
# ldd zip
libc.so.6 => /lib/i686/libc.so.6 (0x42000000)
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0xb7fee000)


Question: 下面這樣的程式編譯, 不是只要用到 static library 就可以了嗎? 為什麼還要用到 dynamic library?

# cat aaa.c
#include
#include

void main()
{
char errbuf[1024];
pcap_if_t *devices = NULL;
pcap_findalldevs(&devices, errbuf);
printf("ok\n");


# gcc -o aaa -lpcap aaa.c
aaa.c: In function `main':
aaa.c:5: warning: return type of `main' is not `int'
aaa.c:10:2: warning: no newline at end of file
/tmp/cc6CFwvH.o: In function `main':
/tmp/cc6CFwvH.o(.text+0x2f): undefined reference to `pcap_findalldevs' ==> 未定義 pcap_findalldevs, 因為libpcap.so.0 沒有包含這個API
collect2: ld returned 1 exit status

>>> libpcap static/shared library compiling procedures
# ./configure --prefix=/home/userName/usr --exec-prefix=/home/userName/usr --enable-yydebug

( DON'T set this parameter, --enable-optimizer-dbg, cause it will result the "dflag" variable in the optimize.c nondefined. And later if we compile other program will due to linking error...

my examples:
compile NSAT program...
g++ -Wall -O6 -funroll-loops -ansi -fPIC -DLINUX functions.o pidalloc.o nsat.o progress.o AuditSet.o SockSet.o Distributed.o Logging.o mod/binfo.o mod/bo.o mod/ftp.o mod/rpc.o mod/snmp.o mod/www.o mod/xp_icmp_addrmask.o mod/xp_icmp_timestamp.o mod/xp_pcap_iface.o mod/xp_utils.o mod/xp_icmp_echo.o mod/xp_logic_tree.o mod/xp_pkt_exams.o mod/xp_icmp_infr.o mod/xp_udp_probe.o libmix++/net/net.o libmix++/misc/misc.o libmix++/misc/exclude.o -o ../nsat -L/usr/X11R6/lib -L/home/userName/usr/lib -lX11 -lrpcsvc -lpcap
/home/userName/usr/lib/libpcap.so: undefined reference to `dflag'
)


make all
# make install
會編譯出來 libpcap.a static library
# make shared
# make install-shared
會編譯出來 libpcap.so.0.9.7 shared library

要真正編譯之前, 需要先到/usr/local/lib or /usr/lib 下面建立soft link 如下
ln -sf ./libpcap.so.0.9.7 ./libpcap.so

之後再去編譯程式就ok了

Or
{
# tar xvfz libpcap-1.0.0.tar.gz cd libpcap-1.0.0
# ./configure --prefix=/usr
# make shared all
# make install-shared install
# ln -sf /usr/lib/libpcap.so.1.0.0 /usr/lib/libpcap.so
# ln -sf /usr/lib/libpcap.so.1.0.0 /usr/lib/libpcap.so.1
}

[root@localhost src]# cat aaa.c
#include
#include

int main()
{
char errbuf[1024];
pcap_if_t *devices = NULL;
pcap_findalldevs(&devices, errbuf);
printf("ok\n");
return 0;
}
[root@localhost src]# gcc -o aaa -lpcap -L/usr/local/lib aaa.c
# ls aaa -la
-rwxr-x--- 1 root root 11769 Sep 21 17:45 aaa

成功編譯出 aaa 程式

How to use ldconfig to add the /usr/lib to the system permanently?
Use the following command to add the library path
PATH="$PATH:/sbin" ldconfig -n /usr/lib


openssl 編完 make install 之後秀出來的message, 告知我們如何做share library linking
* you link with static (archive) libraries. If you are truly
paranoid about security, you should use static libraries.
* you use the GNU libtool code during linking
(http://www.gnu.org/software/libtool/libtool.html)
* you use pkg-config during linking (this requires that
PKG_CONFIG_PATH includes the path to the OpenSSL shared
library directory), and make use of -R or -rpath.
(http://www.freedesktop.org/software/pkgconfig/)
* you specify the system-wide link path via a command such
as crle(1) on Solaris systems.
* you add the OpenSSL shared library directory to /etc/ld.so.conf
and run ldconfig(8) on Linux systems.

We can show all the searched directories that
# ldconfig -Nv | grep ":" | sed 's/:.*//'


* you define the LD_LIBRARY_PATH, LIBPATH, SHLIB_PATH (HP),
DYLD_LIBRARY_PATH (MacOS X) or PATH (Cygwin and DJGPP)
environment variable and add the OpenSSL shared library
directory to it.

One common tool to check the dynamic dependencies of an executable
or dynamic library is ldd(1) on most UNIX systems.

See any operating system documentation and manpages about shared
libraries for your version of UNIX. The following manpages may be
helpful: ld(1), ld.so(1), ld.so.1(1) [Solaris], dld.sl(1) [HP],
ldd(1), crle(1) [Solaris], pldd(1) [Solaris], ldconfig(8) [Linux],
chatr(1) [HP].
cp libcrypto.pc /tmp/newopenssl/lib/pkgconfig
chmod 644 /tmp/newopenssl/lib/pkgconfig/libcrypto.pc
cp libssl.pc /tmp/newopenssl/lib/pkgconfig
chmod 644 /tmp/newopenssl/lib/pkgconfig/libssl.pc
cp openssl.pc /tmp/newopenssl/lib/pkgconfig
chmod 644 /tmp/newopenssl/lib/pkgconfig/openssl.pc

2007年9月19日 星期三

Find the answer -- Asking "Google"

search specific operating system
http://www.google.com/linux
http://www.google.com/bsd

search specific patents
http://www.google.com/patents

search data within a specific site (url)
site:openmoko.org text
site:openmoko.org accelerometer

search data within a specific site (url) from desired mail-user address
site:openmoko.org text "at fic.com.tw"
site:openmoko.org text "at openmoko.org"
site:openmoko.org "release date" "at fic.com.tw"

search a keyword inside a specified site:
retransmission site:http://www.wireshark.org/docs/wsug_html_chunked/

利用 Google Co-op. 可以量身訂作打造企業自己的search engine

Find the answer of coding/programming
Google C Groups
http://groups.google.com/group/comp.lang.c/topics?lnk=gschg&hl=en&pli=1
And of course Google...
http://www.google.com

2007年9月17日 星期一

如何啟動windows 的休眠設定

1. 在電源裝置中啟動休眠
2. 選擇關機時, 會出現三個選項, 這時按下shift 鍵, 待機會變成休眠, 按下即可休眠

2007年8月29日 星期三

Gmail 設定方式

(1) 瀏覽 Gmail 的 Mail Setting, 選擇 enable POP download。

開啟知識總理的郵件模組,至郵件帳戶新增Gmail帳戶,並依下述(2)-(6)步驟填寫資料。

(2)收件伺服器 (POP3) –
pop.gmail.com
使用 SSL: Yes
通信埠 : 995

(3) 寄件伺服器 (SMTP) –
smtp.gmail.com
使用 SSL: Yes
通信埠: 465 or 587 (請自己嘗試選擇讓寄件速度較快的通信埠,我建議選用 587)
使用認證: Yes(勾選我的伺服器需要認證)

(4) 帳戶名稱: 您的 Gmail 帳戶名稱(包括 '@gmail.com')

(5) 電子郵件地址: 您的 Gmail 電子郵件地址 ( '您的 Gmail 帳戶名稱@gmail.com')

(6) 密碼: 您的 Gmail 密碼

注意:

(a) 不要在寄件與收件伺服器上勾選 "使用安全密碼驗證登入"。
(b) 如果您使用垃圾郵件過濾模式預覽Gmail並自Gmail讀取郵件的訊息內容,則當您再次按下預覽或欲將郵件收至本地端資料夾,您將無法再度看到或收取那些已經被"讀取"的郵件。別擔心! 那些郵件不會消失或被刪除,這是因為Gmail會將被讀取過的郵件自動轉至Gmail上的Inbox資料夾,稍後您可以登入網頁 Gmail再度讀取之。您可以直接使用本地端資料夾模式來下載或接收Gmail的郵件訊息,這樣的操作模式下就跟其他的客戶端電 子郵件軟體完全一樣。
(c) 目前Gmail的繁體中文介面、信件內容之繁體中文解碼似乎還在測試階段,所以有時候可能會在收信轉碼時產生亂碼。

2007年8月20日 星期一

Big/Little endian

在ethereal 所錄的封包中看到下面的字串, 由於一般RFC protocol所使用的byte order 都是big endian,
37ea ==> big endian 所以真正的value為 37ea

如果在程式當中利用 ntohs (network to host short) 會存成ea37 (little endian format), 存在x86的記憶體當中

當我們print 這個data時, 會嗅出其真正的涵義, 也就是real value, not storing value

2007年8月14日 星期二

很棒, 資料很豐富的network wiki sites

http://linux-net.osdl.org/index.php/Main_Page

wiki Computer Network Group
http://en.wikipedia.org/wiki/Computer_Network

2007年8月8日 星期三

pscp howto

將 192.168.XX.YY server 的檔案 dump1 抓下來, 存成檔名 dump1.cap
C:\pscp.exe UserName@192.168.XX.YY:/dump1 dump1.cap

Another userful tool for the scp is WinSCP (GUI application) :)

2007年8月6日 星期一

stun/turn message types/attributes

Message Types:
From STUN RFC -
0x0001 : Binding Request
0x0101 : Binding Response
0x0111 : Binding Error Response
0x0002 : Shared Secret Request
0x0102 : Shared Secret Response
0x0112 : Shared Secret Error Response

From TURN draft -
0x0003 : Allocate Request
0x0103 : Allocate Response
0x0113 : Allocate Error Response
0x0004 : Send Request
0x0104 : Send Response
0x0114 : Send Error Response
0x0115 : Data Indication
0x0006 : Set Active Destination Request
0x0106 : Set Active Destination Response
0x0116 : Set Active Destination Error Response

Attributes:
From STUN RFC -
0x0001: MAPPED-ADDRESS
0x0002: RESPONSE-ADDRESS
0x0003: CHANGE-REQUEST
0x0004: SOURCE-ADDRESS
0x0005: CHANGED-ADDRESS
0x0006: USERNAME
0x0007: PASSWORD
0x0008: MESSAGE-INTEGRITY
0x0009: ERROR-CODE
0x000a: UNKNOWN-ATTRIBUTES
0x000b: REFLECTED-FROM

From TURN draft -
0x000d: LIFETIME
0x000e: ALTERNATE-SERVER
0x000f: MAGIC-COOKIE
0x0010: BANDWIDTH
0x0011: DESTINATION-ADDRESS
0x0012: REMOTE-ADDRESS
0x0013: DATA
0x0014: NONCE
0x0015: REALM

user-attribute format: dest:src

+ Added all the message format (2008/07/11)

Stun header format
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type | Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Value ....
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Address Related format
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|x x x x x x x x| Family | Port |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

CHANGE-REQUEST
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 A B 0|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+


ERROR-CODE
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 0 |Class| Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Reason Phrase (variable) ..
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+


UNKNOWN-ATTRIBUTES
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Attribute 1 Type | Attribute 2 Type |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Attribute 3 Type | Attribute 4 Type ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Reference:
http://www.ietf.org/rfc/rfc3489.txt
http://www1.tools.ietf.org/wg/behave/
http://www1.tools.ietf.org/wg/mmusic/

2007年8月5日 星期日

如何讓vi 有顏色

if has("terminfo")
set t_Co=8
set t_Sf=^[[3%p1%dm
set t_Sb=^[[4%p1%dm
else
set t_Co=8
set t_Sf=^[[3%dm
set t_Sb=^[[4%dm
endif

syntax on
set tabstop=4
set shiftwidth=4
set autoindent

2007年8月1日 星期三

執行程式時, 找不到shared library 時, 該如何處理

# ./aaad
./aaad: error while loading shared libraries: libosip2.so.4: cannot open shared object file: No such file or directory

遇到執行程式時, 找不到shared library 時, ㄧ般都是路徑沒有設定正確
可以透過修改 /etc/ld.so.conf,
include /etc/ld.so.conf.d/*.conf
/usr/X11R6/lib
/usr/local/lib <--- 增加這一行 然後執行 # ldconfig 就會做出動態連結所需的cache檔 或是直接執行下面這一行也可以 export LD_LIBRARY_PATH=/usr/local/lib 另外也可以直接在程式run time 來設定環境變數, 直接執行程式 # ./aaa ./aaa: relocation error: ./aaa: undefined symbol: pcap_findalldevs ===> 因為預設的shared library 只有找/usr/lib, 沒有/usr/local/lib, 所以若沒有設定環境變數, 就無法載入 shared library, 無法成功執行
# LD_LIBRARY_PATH=/usr/local/lib ./aaa
ok
==> 有另外設定shared library path, 就可以找到 shared library, 就可以成功執行

標準做法如下
Libraries have been installed in:
/usr/lib

If you ever happen to want to link against installed libraries
in a given directory, LIBDIR, you must either use libtool, and
specify the full pathname of the library, or use the `-LLIBDIR'
flag during linking and do at least one of the following:
- add LIBDIR to the `LD_LIBRARY_PATH' environment variable
during execution
- add LIBDIR to the `LD_RUN_PATH' environment variable
during linking
- use the `-Wl,--rpath=LIBDIR' linker flag
e.g.
# gcc -c pq.c
# gcc -lpq -L/usr/local/lib -Wl,rpath=/usr/local/lib -o pq pq.o

- have your system administrator add LIBDIR to `/etc/ld.so.conf'

See any operating system documentation about shared libraries for
more information, such as the ld(1) and ld.so(8) manual pages.

實際範例
test -z "/usr/lib" || mkdir -p -- "/usr/lib"
/bin/sh ../libtool --mode=install /usr/bin/install -c 'libeXosip2.la' '/usr/lib/libeXosip2.la'
/usr/bin/install -c .libs/libeXosip2.so.6.0.0 /usr/lib/libeXosip2.so.6.0.0
(cd /usr/lib && { ln -s -f libeXosip2.so.6.0.0 libeXosip2.so.6 || { rm -f libeXosip2.so.6 && ln -s libeXosip2.so.6.0.0 libeXosip2.so.6; }; })
(cd /usr/lib && { ln -s -f libeXosip2.so.6.0.0 libeXosip2.so || { rm -f libeXosip2.so && ln -s libeXosip2.so.6.0.0 libeXosip2.so; }; })
/usr/bin/install -c .libs/libeXosip2.lai /usr/lib/libeXosip2.la
/usr/bin/install -c .libs/libeXosip2.a /usr/lib/libeXosip2.a
chmod 644 /usr/lib/libeXosip2.a
ranlib /usr/lib/libeXosip2.a
PATH="$PATH:/sbin" ldconfig -n /usr/lib

結果如下
# ls -l /usr/lib/libe*
-rw-r--r-- 1 root root 632866 Dec 24 12:35 /usr/lib/libeXosip2.a
-rwxr-xr-x 1 root root 902 Dec 24 12:35 /usr/lib/libeXosip2.la
lrwxrwxrwx 1 root root 19 Dec 24 12:35 /usr/lib/libeXosip2.so -> libeXosip2.so.6.0.0
lrwxrwxrwx 1 root root 19 Dec 24 12:35 /usr/lib/libeXosip2.so.6 -> libeXosip2.so.6.0.0
-rwxr-xr-x 1 root root 544903 Dec 24 12:35 /usr/lib/libeXosip2.so.6.0.0

ortp 的make install範例
test -z "/usr/lib" || mkdir -p -- "/usr/lib"
/bin/sh ../libtool --mode=install /usr/bin/install -c 'libortp.la' '/usr/lib/libortp.la'
/usr/bin/install -c .libs/libortp.so.5.0.0 /usr/lib/libortp.so.5.0.0
(cd /usr/lib && { ln -s -f libortp.so.5.0.0 libortp.so.5 || { rm -f libortp.so.5 && ln -s libortp.so.5.0.0 libortp.so.5; }; })
(cd /usr/lib && { ln -s -f libortp.so.5.0.0 libortp.so || { rm -f libortp.so && ln -s libortp.so.5.0.0 libortp.so; }; })
/usr/bin/install -c .libs/libortp.lai /usr/lib/libortp.la
/usr/bin/install -c .libs/libortp.a /usr/lib/libortp.a
chmod 644 /usr/lib/libortp.a
ranlib /usr/lib/libortp.a
PATH="$PATH:/sbin" ldconfig -n /usr/lib
----------------------------------------------------------------------
Libraries have been installed in:
/usr/lib

2007年7月19日 星期四

這段code 的意思看不懂

int
stunRand()
{
// return 32 bits of random stuff
assert( sizeof(int) == 4 );
static bool init=false;
if ( !init )
{
init = true;

UInt64 tick;

#if defined(WIN32)
volatile unsigned int lowtick=0,hightick=0;
__asm
{
rdtsc
mov lowtick, eax
mov hightick, edx
}
tick = hightick;
tick <<= 32;
tick |= lowtick;
#else
asm("rdtsc" : "=A" (tick));
#endif
int seed = int(tick);
#ifdef WIN32
srand(seed);
#else
srandom(seed);
#endif
}

#ifdef WIN32
assert( RAND_MAX == 0x7fff );
int r1 = rand();
int r2 = rand();

int ret = (r1<<16) + r2;

return ret;
#else
return random();
#endif
}

尤其是

asm("rdtsc" : "=A" (tick));
int seed = int(tick);

不太懂

2007年7月18日 星期三

想要在 bash 裡面把ㄧ個 group 的資料註解掉該怎麼做

想要在 bash 裡面把ㄧ個 group 的資料註解掉該怎麼做

範例
true << bt_encry
This is comments, Hello, Hello....
bt_encry

another format as following example.
: << COMMENTBLOCK
echo "This line will not echo."
This is a comment line missing the "#" prefix.
This is another comment line missing the "#" prefix.
&*@!!++=
The above line will cause no error message,
because the Bash interpreter will ignore it.
COMMENTBLOCK

Reference the following technique which was called "Here Document".
Example 17-10. Commenting out a block of code

1 #!/bin/bash
2 # commentblock.sh
3
4 : << COMMENTBLOCK
5 echo "This line will not echo."
6 This is a comment line missing the "#" prefix.
7 This is another comment line missing the "#" prefix.
8
9 &*@!!++=
10 The above line will cause no error message,
11 because the Bash interpreter will ignore it.
12 COMMENTBLOCK
13
14 echo "Exit value of above \"COMMENTBLOCK\" is $?." # 0
15 # No error shown.
16
17
18 # The above technique also comes in useful for commenting out
19 #+ a block of working code for debugging purposes.
20 # This saves having to put a "#" at the beginning of each line,
21 #+ then having to go back and delete each "#" later.
22
23 : << DEBUGXXX
24 for file in *
25 do
26 cat "$file"
27 done
28 DEBUGXXX
29
30 exit 0

英文簡寫意義

i.e. == id est 那就是;即
e.g. == exempli gratia 例如

2007年7月17日 星期二

買房子要注意的四大準則

1. 慎選地段良好
2. 景觀優美
3. 產品規劃在水準以上
4. 具備口碑的建商所蓋的房子

選屋四大原則︰地段、景觀、規劃、口碑 缺一不可

位於良好地段與景觀的房子,除了住起來便利、舒適外,房屋價值更有隨時間而歷久彌堅的特色,可說在先天上便立於不敗之地

這也是美國地產大亨唐納‧川普與香港地產鉅子李嘉誠念茲在茲的「地段決定論」。

http://www.housenews.com.tw/subjectDetail.do?operation=subjectDetail&values.subjectNo=23B13B188B62EA75BD15

2007年7月15日 星期日

Linux/BSD terminal 突然不聽使喚的時候(按Enter, 不會出現new line)

Question: Unknown terminal type ?

> name a few) complain that Terminal type eterm is an unknown terminal.

in bash:

export TERM=vt100

or in csh:

setenv TERM vt100

若在pytty下,vi 無法秀出完整的全物頁面,修改
Configuration > Terminal > Keyboard > The Function keys and keypads ==> VT100+

當在 Linux 機器的系統當中,忘記打export TERM=vt100時,
導致系統發生segmentation fault時,可以打下列指令救回來

# export TERM=vt100


當螢幕不聽使喚的時候
[root@localhost AAA]# [root@localhost AAA]# [root@localhost AAA]
# stty echo

ubuntu 利用 putty 執行 vi 會看到一堆亂碼

ubuntu 利用 putty 執行 vi 會看到一堆亂碼, 原因是因為ubuntu 預設支援顯示中文訊息,
採用 UTF-8 編碼, 所以 putty 預設的編碼會導致顯示的訊息為亂碼,
Change Settings -> Window -> Translation -> Receive data assumed to be in which character set 改成 UTF-8 (預設是use font encoding) 即可

另外也可以在 shell 裡執行
export LANG=C

How to disable the bell ring of putty?
Set the following option
Putty Configuration->Terminal->Bell->Set the style of bell->Action to happen when a bell occurs->None(Bell Disabled) (Originally was Make default system alert sound)

2007年7月12日 星期四

Turn 使用上的注意事項

sendRequest Method 不能不間斷連續執行兩次, 容易會有卡住的情形發生

2007年7月10日 星期二

mount windows directory In the Linux shell

mount windows directory In the Linux shell

mount -t smbfs -o username=sophia,password=,debug=4 //192.168.17.178/Upload /mnt/sophia

2007年7月3日 星期二

socket programming 關於 binary file 的 debug 技巧

編輯 binary file
# heme dataindi
(heme 是一套在Linux 上面的binary 編輯程式)

如下
00000000: 01 15 00 58 00 00 00 00 00 00 00 00 74 8A 8D 6F 00 00 00 00 00 0F 00 04 ...X........t..o........
00000018: 72 C6 4B C6 00 13 00 40 00 01 00 2C 55 9A EC 54 44 34 16 08 B4 45 4F 10 r.K....@...,U..TD4...EO.
00000030: 12 00 00 00 00 01 15 00 58 00 00 00 00 00 00 00 00 74 8A 8D 6F 00 00 00 ........X........t..o...
00000048: 00 00 0F 00 04 00 00 00 18 72 C6 4B C6 00 13 00 40 00 01 00 2C 55 9A EC .........r.K....@...,U..
00000060: 54 44 34 16 08 B4 45 4F D4 E0 00 04 TD4...EO....


傳送指定的 binary 檔案
# cat dataindi | ./netcat -u 127.0.0.1 1111 -v -v -x

port scanning for specified target
# ./netcat -x -v -w 2 -z -t target-host 1-1024 ==> scan port 1 to 1024 for the target-host

netcat as server to response huge data
$ cat backup.iso | pv -b | nc -l 3333


Netcat examples
http://www.g-loaded.eu/2006/11/06/netcat-a-couple-of-useful-examples/

Netcat – a couple of useful examples

November 6th, 2006 by George Notaras

One of the Linux command line tools I had initially under-estimated is netcat or just nc. By default, netcat creates a TCP socket either in listening mode (server socket) or a socket that is used in order to connect to a server (client mode). Actually, netcat does not care whether the socket is meant to be a server or a client. All it does is to take the data from stdin and transfer it to the other end across the network.

The simplest example of its usage is to create a server-client chat system. Although this is a very primitive way to chat, it shows how netcat works. In the following examples it is assumed that the machine that creates the listening socket (server) has the 192.168.0.1 IP address. So, create the chat server on this machine and set it to listen to 3333 TCP port:

$ nc -l 3333

On the other end, connect to the server with the following:

$ nc 192.168.0.1 3333

In this case, the keyboard acts as the stdin. Anything you type in the server machine’s terminal is transfered to the client machine and vice-versa.

Transfering Files

In the very same way it can be used to transfer files between two computers. You can create a server that serves the file with the following:

$ cat backup.iso | nc -l 3333

Receive backup.iso on the client machine with the following:

$ nc 192.168.0.1 3333 > backup.iso

As you may have noticed, netcat does not show any info about the progress of the data transfer. This is inconvenient when dealing with large files. In such cases, a pipe-monitoring utility like pv can be used to show a progress indicator. For example, the following shows the total amount of data that has been transfered in real-time on the server side:

$ cat backup.iso | pv -b | nc -l 3333

Of course, the same can be implemented on the client side by piping netcat’s output through pv:

$ nc 192.168.0.1 3333 | pv -b > backup.iso
Other Examples

Netcat is extremely useful for creating a partition image and sending it to a remote machine on-the-fly:

$ dd if=/dev/hdb5 | gzip -9 | nc -l 3333

On the remote machine, connect to the server and receive the partition image with the following command:

$ nc 192.168.0.1 3333 | pv -b > myhdb5partition.img.gz

This might not be as classy as the partition backups using partimage, but it is efficient.

Another useful thing is to compress the critical files on the server machine with tar and have them pulled by a remote machine:

$ tar -czf - /etc/ | nc -l 3333

As you can see, there is a dash in the tar options instead of a filename. This is because tar’s output needs to be passed to netcat.

On the remote machine, the backup is pulled in the same way as before:

$ nc 192.168.0.1 3333 | pv -b > mybackup.tar.gz

Security

It is obvious that using netcat in the way described above, the data travels in the clear across the network. This is acceptable in case of a local network, but, in case of transfers across the internet, then it would be a wise choice to do it through an SSH tunnel.

Using an SSH tunnel has two advantages:

  1. The data is transfered inside an encrypted tunnel, so it is well-protected.
  2. You do not need to keep any open ports in the firewall configuration of the machine that will act as the server, as the connections will take place through SSH.

You pipe the file to a listening socket on the server machine in the same way as before. It is assumed that an SSH server runs on this machine too.

$ cat backup.iso | nc -l 3333

On the client machine connect to the listening socket through an SSH tunnel:

$ ssh -f -L 23333:127.0.0.1:3333 me@192.168.0.1 sleep 10; \
nc 127.0.0.1 23333 | pv -b > backup.iso

This way of creating and using the SSH tunnel has the advantage that the tunnel is automagically closed after file transfer finishes. For more information and explanation about it please read my article about auto-closing SSH tunnels.

Telnet-like Usage

Netcat can be used in order to talk to servers like telnet does. For example, in order to get the definition of the word “server” from the “WordNet” database at the dict.org dictionary server, I’d do:

$ nc dict.org 2628
220 ..............some WELCOME.....
DEFINE wn server
150 1 definitions retrieved
151 "server" wn "WordNet (r) 2.0"
server
n 1: a person whose occupation is to serve at table (as in a
restaurant) [syn: {waiter}]
2: (court games) the player who serves to start a point
3: (computer science) a computer that provides client stations
with access to files and printers as shared resources to a
computer network [syn: {host}]
4: utensil used in serving food or drink
.
250 ok [d/m/c = 1/0/18; 0.000r 0.000u 0.000s]
QUIT
221 bye [d/m/c = 0/0/0; 16.000r 0.000u 0.000s]

Works as a Port Scanner too

A useful command line flag is -z. When it is used, netcat does not initiate a connection to the server, but just informs about the open port it has found. Also, instead of a single port, it can accept a port-range to scan. For example:

$ nc -z 192.168.0.1 80-90
Connection to 192.168.0.1 80 port [tcp/http] succeeded!

In this example, netcat scanned the 80-90 range of ports and reported that port 80 is open on the remote machine.

The man page contains some more interesting examples, so take the time to read it.

Notes

All the above examples have been performed on Fedora 5/6. Netcat syntax may vary slightly among Linux distributions, so read the man page carefully.

Netcat provides a primitive way to transfer data between two networked computers. I wouldn’t say it’s an absolutely necessary tool in the everyday use, but there are times that this primitive functionality is very useful.

2007年6月14日 星期四

share memory allocate size 上限?

最近在寫ㄧ個程式, 發現share memory 似乎有aloocate length 上限, 但是似乎沒有return error, 上限似乎是3000 bytes 左右, 超過這個值之後, share memory attach (shmat function call 會失敗?), 目前還要再花一點時間來確認這個問題....

Linux 上面實測不同data type length

Linux 上面實測不同data type length, 利用 stun program 測試的結果
size (bytes)
int: 4
struct sockaddr: 16
struct timeval: 8
UInt128: 16
char: 1
unsigned char: 1
double: 8

typedef unsigned char UInt8: 1
typedef unsigned short UInt16: 2
typedef unsigned int UInt32: 4
typedef unsigned long ULong32: 4
typedef double Double: 8
typedef unsigned long long UInt64: 8

2007年5月20日 星期日

C++ string type relation

istream 下面有
iostream
ifstream (end point)
istringstream (end point)

ostream 下面有
iostream
ofstream (end point)
ostringstream (end point)

iostream 下面有
fstream (end point)
stringstream (end point)

iostream library 圖示
http://www.cplusplus.com/reference/iostream/

Some C++ experience

1. type stringstream 的 member function
rdbuf Get/set the associated stringbuf object (public member function)

當呼叫過這一個rdbuf api 後, 原先stringstream 內的data 就會被刪除

str Get/set the associated string object (public member function)
如果只是想要顯示資料, 可以利用 str 這一個api 即可

至於其他的type, 如
ifstream
isstringstream
stream


ifstream public member functions
(constructor) Construct object and optionally open file (constructor member)
rdbuf Get the associated filebuf object (public member function)
is_open Check if a file is open (public member function)
open Open file (public member function)
close Close file (public member function)


istringstream public member functions
(constructor) Construct an object and optionally initialize its content (constructor member)
rdbuf Get/set the associated stringbuf object (public member function)
str Get/set the string content (public member function)

string

bridge packet traversal

bridge path ==> [ebtables|iptables]/table-name HOOK-name

## BROUTE Chain
net/core/dev.c
netif_receive_skb

net/core/dev.c
handle_bridge

net/core/dev.c
br_handle_frame_hook

/* Here br_handle_frame_hook is a callback function pointer
net/bridge/br.c
br_init
br_handle_frame_hook = br_handle_frame;
include/linux/if_bridge.h:extern int (*br_handle_frame_hook)(struct net_bridge_port *p, struct sk_buff **pskb);
*/

net/bridge/br_input.c:
br_handle_frame

# br_handle_frame will return 1 and terminate terminate the packet traversal travel

net/bridge/netfilter/ebtable_broute.c
ebt_broute
ret = ebt_do_table(NF_BR_BROUTING, pskb, (*pskb)->dev, NULL, &broute_table); ==> ebtables/BROUTE BROUTING

## PREROUTING Chain
net/bridge/br_input.c:
br_handle_frame
NF_HOOK(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL, br_handle_frame_finish); ==> ebtables/NAT PREROUTING
ebt_nat_dst
br_nf_pre_routing

ebtables will traversal Netfilter/Prerouting in the ebtables/PREROUTING after traversal (ebtables/NAT PREROUTING) as follows

// Due to ebtables (PF_BRIDGE) prerouting hook function : br_nf_pre_routing
net/bridge/br_netfilter.c:
br_nf_pre_routing
NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, skb->dev, NULL, br_nf_pre_routing_finish); ==> iptables/CONNTRACK-DEFRAG PREROUTING
NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, skb->dev, NULL, br_nf_pre_routing_finish); ==> iptables/RAW PREROUTING
NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, skb->dev, NULL, br_nf_pre_routing_finish); ==> iptables/CONNTRACK PREROUTING
NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, skb->dev, NULL, br_nf_pre_routing_finish); ==> iptables/MANGLE PREROUTING
NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, skb->dev, NULL, br_nf_pre_routing_finish); ==> iptables/TPROXY PREROUTING
NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, skb->dev, NULL, br_nf_pre_routing_finish); ==> iptables/NAT PREROUTING

# (br_nf_pre_routing will always return NF_STOLEN, so the br_handle_frame_finish function doesn;t need to run again!)

net/bridge/br_netfilter.c:
br_nf_pre_routing_finish
NF_HOOK_THRESH(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL, br_nf_pre_routing_finish_bridge, 1);
or
NF_HOOK_THRESH(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL, br_handle_frame_finish, 1);
// No hook currently less than thresh 1

So either run
net/bridge/br_netfilter.c:
br_nf_pre_routing_finish_bridge
or
net/bridge/br_input.c:
br_handle_frame_finish

# This is the final(finished) function of the ebtables / PREROUTING chain
# Because the br_nf_pre_routing return the NF_STOLEN verdict, so we will not run the br_handle_frame_finish function again
net/bridge/br_input.c:
br_handle_frame_finish

//FORWARD path


net/bridge/br_forward.c:
br_flood_forward
net/bridge/br_forward.c:
br_flood
br_flood will call callback function (__packet_hook)
net/bridge/br_forward.c:
__br_forward
NF_HOOK(PF_BRIDGE, NF_BR_FORWARD, skb, indev, skb->dev, br_forward_finish); ==> ebtables/FILTER FORWARD
ebt_hook
br_nf_forward_ip
br_nf_forward_arp


net/bridge/br_netfilter.c:
br_nf_forward_ip
NF_HOOK(pf, NF_IP_FORWARD, skb, bridge_parent(in), bridge_parent(out), br_nf_forward_finish);
## it will return NF_STOLEN verdict

net/bridge/br_netfilter.c:
br_nf_forward_arp
NF_HOOK(NF_ARP, NF_ARP_FORWARD, skb, (struct net_device *)in, (struct net_device *)out, br_nf_forward_finish);
## it will return NF_STOLEN verdict


net/bridge/br_netfilter.c:
br_nf_forward_ip
ip_sabotage_out
NF_HOOK(pf, NF_IP_FORWARD, skb, bridge_parent(in), bridge_parent(out), br_nf_forward_finish); ==> iptables/MANGLE FORWARD
NF_HOOK(pf, NF_IP_FORWARD, skb, bridge_parent(in), bridge_parent(out), br_nf_forward_finish); ==> iptables/FILTER FORWARD

# br_nf_forward_ip will return NF_STOLEN verdict

net/bridge/br_netfilter.c:
br_nf_forward_finish
NF_HOOK_THRESH(PF_BRIDGE, NF_BR_FORWARD, skb, in, skb->dev, br_forward_finish, 1);
// No hook currently less than thresh 1

net/bridge/br_forward.c:
br_forward_finish
NF_HOOK(PF_BRIDGE, NF_BR_POST_ROUTING, skb, NULL, skb->dev, br_dev_queue_push_xmit);

ebt_nat_src
br_nf_post_routing

net/bridge/br_netfilter.c:
br_nf_post_routing
NF_HOOK(pf, NF_IP_POST_ROUTING, skb, NULL, realoutdev, br_dev_queue_push_xmit);
## it will return NF_STOLEN verdict

net/bridge/br_netfilter.c:
br_nf_post_routing
ip_sabotage_out
NF_HOOK(pf, NF_IP_POST_ROUTING, skb, NULL, realoutdev, br_dev_queue_push_xmit); ==> iptables/TPROXY POSTROUTING
NF_HOOK(pf, NF_IP_POST_ROUTING, skb, NULL, realoutdev, br_dev_queue_push_xmit); ==> iptables/MANGLE POSTROUTING
NF_HOOK(pf, NF_IP_POST_ROUTING, skb, NULL, realoutdev, br_dev_queue_push_xmit); ==> iptables/NAT POSTROUTING
NF_HOOK(pf, NF_IP_POST_ROUTING, skb, NULL, realoutdev, br_dev_queue_push_xmit); ==> iptables/CONNTRACK POSTROUTING

net/bridge/br_forward.c:
br_dev_queue_push_xmit
## return 0

2007年5月18日 星期五

socket receive api call 的運作流程

socket receive api call

Receiving packets
case SYS_RECV:
err = sys_recv(a0, (void __user *)a1, a[2], a[3]);

case SYS_RECVFROM:
err = sys_recvfrom(a0, (void __user *)a1, a[2], a[3], (struct sockaddr __user *)a[4], (int __user *)a[5]);

case SYS_RECVMSG:
/* BSD recvmsg interface */
err = sys_recvmsg(a0, (struct msghdr __user *) a1, a[2]);



Sending packets
case SYS_SEND:
err = sys_send(a0, (void __user *)a1, a[2], a[3]);

case SYS_SENDTO:
err = sys_sendto(a0,(void __user *)a1, a[2], a[3], (struct sockaddr __user *)a[4], a[5]);

case SYS_SENDMSG:
err = sys_sendmsg(a0, (struct msghdr __user *) a1, a[2]);


sys_recv

asmlinkage long sys_recv(int fd, void __user * ubuf, size_t size, unsigned flags)
{
return sys_recvfrom(fd, ubuf, size, flags, NULL, NULL);
}


asmlinkage long sys_recvfrom(int fd, void __user * ubuf, size_t size, unsigned flags,
struct sockaddr __user *addr, int __user *addr_len)
{
[略]
// main function
err=sock_recvmsg(sock, &msg, size, flags);
[略]
}


asmlinkage long sys_recvmsg(int fd, struct msghdr __user *msg, unsigned int flags)
{
[略]
err = sock_recvmsg(sock, &msg_sys, total_len, flags);
[略]
}

/*
all the received api will call sock_recvmsg function finally
*/
int sock_recvmsg(struct socket *sock, struct msghdr *msg,
size_t size, int flags)
{
[略]
ret = __sock_recvmsg(&iocb, sock, msg, size, flags);
[略]
}


static inline int __sock_recvmsg(struct kiocb *iocb, struct socket *sock,
struct msghdr *msg, size_t size, int flags)
{
[略]
err = security_socket_recvmsg(sock, msg, size, flags);
if (err)
return err;

return sock->ops->recvmsg(iocb, sock, msg, size, flags);
}

The Received API was followed the below line sequence
sock_recvmsg
__sock_recvmsg
sock->ops->recvmsg(iocb, sock, msg, size, flags);
/* This will issue sock_common_recvmsg function
* and then issue sk->sk_prot->recvmsg function
* For tcp it is the tcp_recvmsg
* then it is the tcp_prequeue_process
* teen if there is any packets exist in the prequeue buffer, run the sk->sk_backlog_rcv
* the sk->sk_backlog_rcv is a called back function (for tcp it is tcp_v4_do_rcv), which was
registered while the socket is created (inet_create function)
*/



sock->ops->recvmsg(iocb, sock, msg, size, flags);
will call
sock_common_recvmsg(struct kiocb *iocb, struct socket *sock,
struct msghdr *msg, size_t size, int flags)

and then will call

sock->sk->sk_prot->recvmsg(iocb, sk, msg, size, flags & MSG_DONTWAIT,
flags & ~MSG_DONTWAIT, &addr_len);


In SOCK_STREAM will call the follwoing function

int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
size_t len, int nonblock, int flags, int *addr_len)


In SOCK_DGRAM will call the follwoing function

int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
size_t len, int noblock, int flags, int *addr_len)

In SOCK_RAW will call the follwoing function

int raw_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
size_t len, int noblock, int flags, int *addr_len)

tproxy 的運作

About tproxy

SIP A: MAC a ---> (Bridged port): MAC m ---- Device ----- (Bridged port):MAC n -----> DIP W:MAC:w

the pair physical port of device was bridged, call br0, and have a IP (P)

Features
* Remember the original sourc ip (A), remember the original MAC (a)
* Send the packet from device to destination (Second segment), original ip:mac P:n
* Replace the P:n with A:a (this is the main task of tproxy

ㄧ般情況packet 走routing 的順序(不含bridge)

net/ipv4/ip_input.c
ip_rcv_finish

/* ip_route_input function will find the destination cache in the routing cache or forwarding information base. And pointer

the destination cache in the skb->dst */
net/ipv4/route.c
ip_route_input

normally the packet will in this way
net/ipv4/route.c
ip_route_input_slow

/* If the packet is bound to received by the host itself. The input function of routing table will be set as ip_local_deliver

*/
rth->u.dst.input= ip_local_deliver

net/ipv4/ip_input.c
ip_local_deliver

NF_HOOK(PF_INET, NF_IP_LOCAL_IN, skb, skb->dev, NULL, ip_local_deliver_finish); ==> iptables/MANGLE INPUT
NF_HOOK(PF_INET, NF_IP_LOCAL_IN, skb, skb->dev, NULL, ip_local_deliver_finish); ==> iptables/FILTER INPUT
NF_HOOK(PF_INET, NF_IP_LOCAL_IN, skb, skb->dev, NULL, ip_local_deliver_finish); ==> iptables/NAT INPUT
NF_HOOK(PF_INET, NF_IP_LOCAL_IN, skb, skb->dev, NULL, ip_local_deliver_finish); ==> iptables/CONNTRACK_LAST INPUT


net/ipv4/ip_input.c
ip_local_deliver_finish

net/ipv4/ip_input.c
ipprot->handler(skb);

net/ipv4/tcp_ipv4.c
int tcp_v4_rcv(struct sk_buff *skb)

net/ipv4/tcp_ipv4.c
sk_add_backlog(sk, skb);

net/ipv4/tcp_ipv4.c
tcp_v4_do_rcv


/*
if (!sock_owned_by_user(sk)) {
if (!tcp_prequeue(sk, skb))
ret = tcp_v4_do_rcv(sk, skb);
} else
sk_add_backlog(sk, skb);
*/

application source code

一堆好用的 network applications

整理的很詳細, 包括各種適用平台, 以及該軟體的介紹(包含一些常用的 network library)

http://www.stearns.org/doc/pcap-apps.html


packetfactory 所出產的也很豐富
http://www.packetfactory.net/projects/index.html


netfilter source
http://freshmeat.net/~laf0rge/

There are many funny application projects with source code available in the "Linux@DUKE Projects"
http://linux.duke.edu/projects/

source code reference examples:

perl:
mrtg: http://oss.oetiker.ch/mrtg/
ibmonitor: http://ibmonitor.sourceforge.net/index.html
cvs2cl.pl: http://www.red-bean.com/cvs2cl/


python:
denyhosts: http://denyhosts.sourceforge.net/
yum: http://yum.baseurl.org/

php:
http://www.cacti.net/

2007年5月12日 星期六

http reply message 要如何才能自動讓client browser 自動載入

當http reply message 回覆的 http payload 當中, 具有下面的meta tag, 則client browser 再看到這樣的訊息, 就會自動重新載入 http page, 載入的時間點定義在content 當中, 這裡的範例為3秒
//meta http-equiv="refresh" content="3; URL=http://midcom-p2p.sourceforge.net/"

2007年5月11日 星期五

C 的特殊字元

- '\n' closes a line
- '\f' closes a page
- '\t' prints a tab wide spaces (whereas the definition of the tab
depends on the driver attached to the stream.)
- '\b' lets the logical cursor go a char backwards
whereas this cursor may be a the cursor on screen, the printhead,
a pinter inside the print buffer on the device or the driver....
- '\a' may ring a bell, a siren, or another device that
does require the attention of the operator or even does nothing when
no device that can be activated on that signal gets activated.
On a PC it will give traditionally a signal to the speaker or
play a wave file through the soudcard - or even do nothing or
something else.

Linux Command - mount

nroff -ms orig-file
orig-file 是ㄧ個尚未格式化過的檔案, 內容類似這樣
.in 0
.ne 4
Copyright Notice
.sp
.in 3
Copyright (C) The Internet Society (2003). All Rights Reserved.
in 0
.ne 4
Abstract
.sp
.in 3
This document describes methods
by which peer-to-peer (P2P) applications

經過nroff 轉檔後的結果,
.sp ==> 表示ㄧ行空白行
.in N ==> 表示下面的文字 right shift N 個字元
.ne N ==> 應該是厎下面文字的 font size (我猜的), 不過因為 nroff 不支援, 其他版本的roff (e.g. groff) 才有支援
Copyright Notice

Copyright (C) The Internet Society (2003). All Rights Reserved.

Abstract

This document describes methods by which peer-to-peer (P2P) applications

// mount command 的用法
// mount windows directory In the Linux shell

mount -t smbfs -o username=sophia,password=,debug=4 //192.168.17.178/Upload /mnt/sophia/

// mount usb drive as linux directory, default will use fat/vfat file system
# mount /dev/sdb1 /mnt/usbflash

# mount
[omit]
/dev/sdb1 on /mnt/usbflash type vfat (rw)

==>Show the mounted devices
# cat /proc/partitions
major minor #blocks name

8 16 488386560 sdb
8 17 512000 sdb1
8 18 487873536 sdb2
253 0 1540096 dm-0
253 1 52428800 dm-1
253 2 433881088 dm-2
8 32 15687680 sdc ==> Our usb device
8 33 15683584 sdc1

[root@vincentlin /]# mount -t ntfs-3g /dev/sdc1 /mnt/usb/

How to checkout some files of sourceforge CVS

Here we use the modcom-p2p project as the example
http://sourceforge.net/projects/midcom-p2p

Step1.
# cvs -d:pserver:anonymous@midcom-p2p.cvs.sourceforge.net:/cvsroot/midcom-p2p login
Logging in to :pserver:anonymous@midcom-p2p.cvs.sourceforge.net:2401/cvsroot/midcom-p2p
CVS password:

Simply press "Enter"

Step2.
checkout "doc" and "web" project
# cvs -z3 -d:pserver:anonymous@midcom-p2p.cvs.sourceforge.net:/cvsroot/midcom-p2p co -P doc
# cvs -z3 -d:pserver:anonymous@midcom-p2p.cvs.sourceforge.net:/cvsroot/midcom-p2p co -P web

2007年5月9日 星期三

Netfilter P2P issues

Netfilter P2P issues
Patch:
http://lists.netfilter.org/pipermail/netfilter-devel/2006-January/023084.html
Coding hint:
http://lists.netfilter.org/pipermail/netfilter-devel/2005-December/022584.html
Theory:
http://lists.netfilter.org/pipermail/netfilter-devel/2004-November/017479.html

-------------first part--------------
diff -Nur linux-2.6.13.3/include/linux/netfilter_i
pv4/ip_conntrack.h linux-b/include/linux/netfilter_ipv4/ip_conntrack.h
--- linux-2.6.13.3/include/linux/netfilter_ipv4/ip_conntrack.h 2005-10-04
07:27
:34.000000000 +0800
+++ linux-b/include/linux/netfilter_ipv4/ip_conntrack.h 2005-11-02
18:11:00.0000
00000 +0800
@@ -65,6 +65,27 @@

/* Both together */
IPS_NAT_DONE_MASK = (IPS_DST_NAT_DONE | IPS_SRC_NAT_DONE),
+
+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+ IPS_SNATP2P_SRC_BIT = 9,
+ IPS_SNATP2P_SRC = (1 << IPS_SNATP2P_SRC_BIT),
+
+ IPS_SNATP2P_DST_BIT = 10,
+ IPS_SNATP2P_DST = (1 << IPS_SNATP2P_DST_BIT),
+
+ /* Both together. */
+ IPS_SNATP2P_MASK = (IPS_SNATP2P_DST | IPS_SNATP2P_SRC),
+
+ IPS_SNATP2P_SRC_DONE_BIT = 11,
+ IPS_SNATP2P_SRC_DONE = (1 << IPS_SNATP2P_SRC_DONE_BIT),
+
+ IPS_SNATP2P_DST_DONE_BIT = 12,
+ IPS_SNATP2P_DST_DONE = (1 << IPS_SNATP2P_DST_DONE_BIT),
+
+ /* Both together. */
+ IPS_SNATP2P_DONE_MASK = (IPS_SNATP2P_DST_DONE |
IPS_SNATP2P_SRC_DONE),
+#endif
+
};

#ifdef __KERNEL__
diff -Nur linux-2.6.13.3/include/linux/netfilter_i
pv4/ip_nat.h linux-b/include/linux/netfilter_ipv4/ip_nat.h
--- linux-2.6.13.3/include/linux/netfilter_ipv4/ip_nat.h 2005-10-04
07:27
:34.000000000 +0800
+++ linux-b/include/linux/netfilter_ipv4/ip_nat.h 2005-11-07
21:28:32.0000
00000 +0800
@@ -59,6 +59,10 @@
{
struct list_head bysource;

+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+ struct list_head by_modified_source;
+#endif
+
/* Helper (NULL if none). */
struct ip_nat_helper *helper;

@@ -76,6 +80,11 @@
extern int ip_nat_used_tuple(const struct ip_conntrack_tuple *tuple,
const struct ip_conntrack *ignored_conntrack);

+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+extern int find_appropriate_p2p_dst(const struct ip_conntrack_tuple *tuple,
+ struct ip_conntrack_tuple *result);
+#endif
+
/* Calculate relative checksum. */
extern u_int16_t ip_nat_cheat_check(u_int32_t oldvalinv,
u_int32_t newval,
diff -Nur linux-2.6.13.3/net/ipv4/netfilter/Kconf
g linux-b/net/ipv4/netfilter/Kconfig
--- linux-2.6.13.3/net/ipv4/netfilter/Kconfig 2005-10-04
07:27:34.000000000 +
800
+++ linux-b/net/ipv4/netfilter/Kconfig 2005-11-09 17:11:10.000000000 +0800
@@ -484,6 +484,14 @@

To compile it as a module, choose M here. If unsure, say N.

+config IP_NF_TARGET_SNATP2P
+ tristate "SNATP2P target support"
+ depends on IP_NF_NAT
+ help
+ SNATP2P is an implementation for P2P need.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
config IP_NF_TARGET_NETMAP
tristate "NETMAP target support"
depends on IP_NF_NAT
diff -Nur linux-2.6.13.3/net/ipv4/netfilter/Makef
le linux-b/net/ipv4/netfilter/Makefile
--- linux-2.6.13.3/net/ipv4/netfilter/Makefile 2005-10-04
07:27:34.000000000 +
800
+++ linux-b/net/ipv4/netfilter/Makefile 2005-11-09 17:13:00.000000000 +0800
@@ -68,6 +68,7 @@
obj-$(CONFIG_IP_NF_TARGET_MARK) += ipt_MARK.o
obj-$(CONFIG_IP_NF_TARGET_MASQUERADE) += ipt_MASQUERADE.o
obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o
+obj-$(CONFIG_IP_NF_TARGET_SNATP2P) += ipt_SNATP2P.o
obj-$(CONFIG_IP_NF_TARGET_NETMAP) += ipt_NETMAP.o
obj-$(CONFIG_IP_NF_TARGET_SAME) += ipt_SAME.o
obj-$(CONFIG_IP_NF_TARGET_CLASSIFY) += ipt_CLASSIFY.o
diff -Nur linux-2.6.13.3/net/ipv4/netfilter/ip_co
ntrack_proto_tcp.c linux-b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
--- linux-2.6.13.3/net/ipv4/netfilter/ip_conntrack_proto_tcp.c 2005-10-04
07:2
:34.000000000 +0800
+++ linux-b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c 2005-11-11
21:21:34.000
00000 +0800
@@ -979,10 +979,19 @@
problem case, so we can delete the conntrack
immediately. --RR */
if (th->rst) {
+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+ /*maybe we don't need to care this condition
anymore,Rusty?since we take care of holepunch and hairpin!*/
+ if(conntrack->status & IPS_SNATP2P_SRC_DONE){
+ timeout = 2 MINS;
+ ip_ct_refresh_acct(conntrack, ctinfo, skb, timeout);
+ return NF_DROP;
+ }
+#else
if (del_timer(&conntrack->timeout))
conntrack->timeout.function((unsigned long)
conntrack);
return NF_ACCEPT;
+#endif
}
} else if (!test_bit(IPS_ASSURED_BIT, &conntrack->status)
&& (old_state == TCP_CONNTRACK_SYN_RECV
diff -Nur linux-2.6.13.3/net/ipv4/netfilter/ip_nat
_core.c linux-b/net/ipv4/netfilter/ip_nat_core.c
--- linux-2.6.13.3/net/ipv4/netfilter/ip_nat_core.c 2005-10-04
07:27:34.0000
00000 +0800
+++ linux-b/net/ipv4/netfilter/ip_nat_core.c 2005-11-09
17:29:24.000000000 +0
800
@@ -1,4 +1,4 @@

/* (C) 1999-2001 Paul `Rusty' Russell
* (C) 2002-2004 Netfilter Core Team <coreteam at netfilter.org>
@@ -47,6 +47,11 @@
static unsigned int ip_nat_htable_size;

static struct list_head *bysource;
+
+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+static struct list_head *by_modified_source;
+#endif
+
struct ip_nat_protocol *ip_nat_protos[MAX_IP_NAT_PROTO];


@@ -59,6 +64,16 @@
tuple->dst.protonum, 0) % ip_nat_htable_size;
}

+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+static inline unsigned int
+hash_by_dst(const struct ip_conntrack_tuple *tuple)
+{
+ /* Original src, to ensure we map it consistently if poss. */
+ return jhash_3words(tuple->dst.ip, tuple->dst.u.all,
+ tuple->dst.protonum, 0) % ip_nat_htable_size;
+}
+#endif
+
/* Noone using conntrack by the time this called. */
static void ip_nat_cleanup_conntrack(struct ip_conntrack *conn)
{
@@ -67,6 +82,10 @@

write_lock_bh(&ip_nat_lock);
list_del(&conn->nat.info.bysource);
+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+ if ((conn->status & IPS_SNATP2P_MASK) && (conn->status &
IPS_SNATP2P_DONE_MASK))
+ list_del(&conn->nat.info.by_modified_source);
+#endif
write_unlock_bh(&ip_nat_lock);
}

@@ -93,6 +112,14 @@
We could keep a separate hash if this proves too slow. */
struct ip_conntrack_tuple reply;

+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+ if((ignored_conntrack->status & IPS_SNATP2P_SRC)
+ && !(ignored_conntrack->status &
IPS_SNATP2P_SRC_DONE))
+ if (modified_src_occupied(tuple,ignored_conntrack))
+ return 1;
+#endif
+
+
invert_tuplepr(&reply, tuple);
return ip_conntrack_tuple_taken(&reply, ignored_conntrack);
}
@@ -160,6 +187,77 @@
return 0;
}

+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+static inline int
+same_modified_src(const struct ip_conntrack *ct,
+ const struct ip_conntrack_tuple *tuple)
+{
+ if (ct->status & IPS_SNATP2P_DST)
+ return (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum
+ == tuple->dst.protonum
+ && ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip
+ == tuple->src.ip
+ && ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.all
+ == tuple->src.u.all);
+ else
+ /*must be ct->status & IPS_SNATP2P_SRC*/
+ return (ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.protonum
+ == tuple->dst.protonum
+ && ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip
+ == tuple->src.ip
+ && ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.all
+ == tuple->src.u.all);
+}
+
+static int
+modified_src_occupied(const struct ip_conntrack_tuple *tuple,
+ const struct ip_conntrack *conntrack)
+{
+ unsigned int h = hash_by_src(tuple);
+ struct ip_conntrack *ct;
+
+ read_lock_bh(&ip_nat_lock);
+ list_for_each_entry(ct, &by_modified_source[h],
nat.info.by_modified_source) {
+ if (same_modified_src(ct, tuple)) {
+ if (same_src(ct,
&conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple))
+ /*that's an appropriate source*/
+ next;
+ read_unlock_bh(&ip_nat_lock);
+ return 1;
+ }
+ }
+ read_unlock_bh(&ip_nat_lock);
+ return 0;
+}
+
+int
+find_appropriate_p2p_dst(const struct ip_conntrack_tuple *tuple,
+ struct ip_conntrack_tuple *result)
+{
+ unsigned int h = hash_by_src(tuple);
+ struct ip_conntrack *ct;
+
+ read_lock_bh(&ip_nat_lock);
+ list_for_each_entry(ct, &by_modified_source[h],
nat.info.by_modified_source) {
+ if (same_modified_src(ct, tuple)) {
+ if (ct->status & IPS_SNATP2P_DST)
+ invert_tuplepr(result,
+
&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
+ else
+ invert_tuplepr(result,
+
&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
+ result->src = tuple->src;
+ read_unlock_bh(&ip_nat_lock);
+ return 1;
+
+ }
+ }
+ read_unlock_bh(&ip_nat_lock);
+ return 0;
+}
+
+#endif
+
/* For [FUTURE] fragmentation handling, we want the least-used
src-ip/dst-ip/proto triple. Fairness doesn't come into it. Thus
if the range specifies 1.2.3.4 ports 10000-10005 and 1.2.3.5 ports
@@ -260,6 +358,11 @@
struct ip_conntrack_tuple curr_tuple, new_tuple;
struct ip_nat_info *info = &conntrack->nat.info;
int have_to_hash = !(conntrack->status & IPS_NAT_DONE_MASK);
+
+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+ int have_to_hash_modified_src = ((conntrack->status &
IPS_SNATP2P_MASK)
+ && !(conntrack->status & IPS_SNATP2P_DONE_MASK));
+#endif
enum ip_nat_manip_type maniptype = HOOK2MANIP(hooknum);

IP_NF_ASSERT(hooknum == NF_IP_PRE_ROUTING
@@ -301,11 +404,31 @@
list_add(&info->bysource, &bysource[srchash]);
write_unlock_bh(&ip_nat_lock);
}
+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+ if (have_to_hash_modified_src){
+ unsigned int srchash
+ = (conntrack->status & IPS_SNATP2P_SRC) ?
+ hash_by_dst(&conntrack->tuplehash[IP_CT_DIR_REPLY]
+ .tuple) :
hash_by_dst(&conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
+ .tuple);
+ write_lock_bh(&ip_nat_lock);
+ list_add(&info->by_modified_source,
&by_modified_source[srchash]);
+ write_unlock_bh(&ip_nat_lock);
+ }
+#endif
/* It's done. */
if (maniptype == IP_NAT_MANIP_DST)
+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+ if (conntrack->status & IPS_SNATP2P_DST)
+ set_bit(IPS_SNATP2P_DST_DONE_BIT,
&conntrack->status);
+#endif
set_bit(IPS_DST_NAT_DONE_BIT, &conntrack->status);
else
+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+ if (conntrack->status & IPS_SNATP2P_SRC)
+ set_bit(IPS_SNATP2P_SRC_DONE_BIT,
&conntrack->status);
+#endif
set_bit(IPS_SRC_NAT_DONE_BIT, &conntrack->status);

return NF_ACCEPT;
@@ -507,7 +630,13 @@
bysource = vmalloc(sizeof(struct list_head) * ip_nat_htable_size);
if (!bysource)
return -ENOMEM;
+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+ by_modified_source = vmalloc(sizeof(struct list_head) *
ip_nat_htable_size);
+ if (!by_modified_source )
+ return -ENOMEM;
+#endif
+
/* Sew in builtin protocols. */
write_lock_bh(&ip_nat_lock);
for (i = 0; i < MAX_IP_NAT_PROTO; i++)
@@ -521,6 +650,11 @@
INIT_LIST_HEAD(&bysource[i]);
}

+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+ for (i = 0; i < ip_nat_htable_size; i++) {
+ INIT_LIST_HEAD(&by_modified_source[i]);
+ }
+#endif
/* FIXME: Man, this is a hack. */
IP_NF_ASSERT(ip_conntrack_destroyed == NULL);
ip_conntrack_destroyed = &ip_nat_cleanup_conntrack;
@@ -534,7 +668,11 @@
static int clean_nat(struct ip_conntrack *i, void *data)
{
memset(&i->nat, 0, sizeof(i->nat));
- i->status &= ~(IPS_NAT_MASK | IPS_NAT_DONE_MASK | IPS_SEQ_ADJUST);
+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+ i->status &= ~(IPS_NAT_MASK | IPS_NAT_DONE_MASK | IPS_SEQ_ADJUST |
IPS_SNATP2P_MASK | IPS_SNATP2P_DONE_MASK);
+#else
+ i->status &= ~(IPS_NAT_MASK | IPS_NAT_DONE_MASK | IPS_SEQ_ADJUST);
+#endif
return 0;
}

@@ -544,4 +682,7 @@
ip_ct_iterate_cleanup(&clean_nat, NULL);
ip_conntrack_destroyed = NULL;
vfree(bysource);
+#if defined( CONFIG_IP_NF_TARGET_SNATP2P)
+ vfree(by_modified_source);
+#endif
}

diff -Nur linux-2.6.13.3/net/ipv4/netfilter/ip_nat
_rule.c linux-b/net/ipv4/netfilter/ip_nat_rule.c
--- linux-2.6.13.3/net/ipv4/netfilter/ip_nat_rule.c 2005-10-04
07:27:34.0000
00000 +0800
+++ linux-b/net/ipv4/netfilter/ip_nat_rule.c 2005-11-07
21:26:44.000000000 +0
800
@@ -267,9 +267,30 @@
ret = ipt_do_table(pskb, hooknum, in, out, &nat_table, NULL);

if (ret == NF_ACCEPT) {
- if (!ip_nat_initialized(ct, HOOK2MANIP(hooknum)))
- /* NUL mapping */
- ret = alloc_null_binding(ct, info, hooknum);
+ if (!ip_nat_initialized(ct, HOOK2MANIP(hooknum))){
+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+ if ((HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST)){
+ struct ip_conntrack_tuple reply_tuple, new_tuple;
+ invert_tuplepr(&reply_tuple,
+ &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
+ if (find_appropriate_p2p_dst(&reply_tuple, &new_tuple){
+ struct ip_nat_range range;
+ /* This must be a fresh one. */
+ BUG_ON(ct->status & IPS_NAT_DONE_MASK);
+ ct->status |= IPS_SNATP2P_DST;
+ range.flags = (IP_NAT_RANGE_MAP_IPS |
IP_NAT_RANGE_PROTO_SPECIFIED);
+ range.min = range.max = new_tuple.dst.u;
+ range.min_ip = range.max_ip
+ = new_tuple.dst.ip;
+ ret = ip_nat_setup_info(ct, &range,
NF_IP_PRE_ROUTING);
+ }
+ }
+ if (!ip_nat_initialized(ct, HOOK2MANIP(hooknum)))
+
+#endif
+ /* NUL mapping */
+ ret = alloc_null_binding(ct, info, hooknum);
+ }
}
return ret;
}
diff -Nur linux-2.6.13.3/net/ipv4/netfilter/ip_na
_standalone.c linux-b/net/ipv4/netfilter/ip_nat_standalone.c
--- linux-2.6.13.3/net/ipv4/netfilter/ip_nat_standalone.c 2005-10-04
07:2
:34.000000000 +0800
+++ linux-b/net/ipv4/netfilter/ip_nat_standalone.c 2005-11-07
21:28:10.000
00000 +0800
@@ -393,6 +393,9 @@
module_init(init);
module_exit(fini);

+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+EXPORT_SYMBOL(find_appropriate_p2p_dst);
+#endif
EXPORT_SYMBOL(ip_nat_setup_info);
EXPORT_SYMBOL(ip_nat_protocol_register);
EXPORT_SYMBOL(ip_nat_protocol_unregister);
diff -Nur linux-2.6.13.3/net/ipv4/netfilter/ipt_S
ATP2P.c linux-b/net/ipv4/netfilter/ipt_SNATP2P.c
--- linux-2.6.13.3/net/ipv4/netfilter/ipt_SNATP2P.c 1970-01-01
08:00:00.000
00000 +0800
+++ linux-b/net/ipv4/netfilter/ipt_SNATP2P.c 2005-11-11
20:12:02.000000000 +
800
@@ -0,0 +1,95 @@
+/* This is a module which is used for source-NAT-P2P.
+ * with concept helped by Rusty Russel <rusty at rustcorp.com.au>
+ * and with code by Jesse Peng <tzuhsi.peng at msa.hinet.net>
+ */
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+
+static unsigned int ipt_snatp2p_target(struct sk_buff **pskb,
+ const struct net_device *in,
+ const struct net_device *out,
+ unsigned int hooknum,
+ const void *targinfo,
+ void *userinfo)
+{
+ struct ip_conntrack *ct;
+ enum ip_conntrack_info ctinfo;
+ const struct ip_nat_multi_range_compat *mr = targinfo;
+
+ IP_NF_ASSERT(hooknum == NF_IP_POST_ROUTING);
+
+ ct = ip_conntrack_get(*pskb, &ctinfo);
+
+ /* Connection must be valid and new. */
+ IP_NF_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED
+ || ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY));
+ IP_NF_ASSERT(out);
+ ct->status |= IPS_SNATP2P_SRC;
+ return ip_nat_setup_info(ct, &mr->range[0], hooknum);
+}
+
+static int ipt_snatp2p_checkentry(const char *tablename,
+ const struct ipt_entry *e,
+ void *targinfo,
+ unsigned int targinfosize,
+ unsigned int hook_mask)
+{
+ struct ip_nat_multi_range_compat *mr = targinfo;
+
+ /* Must be a valid range */
+ if (mr->rangesize != 1) {
+ printk("SNATP2P: multiple ranges no longer supported\n");
+ return 0;
+ }
+
+ if (targinfosize != IPT_ALIGN(sizeof(struct
ip_nat_multi_range_compat))
{
+ DEBUGP("SNATP2P: Target size %u wrong for %u ranges\n",
+ targinfosize, mr->rangesize);
+ return 0;
+ }
+
+ /* Only allow these for NAT. */
+ if (strcmp(tablename, "nat") != 0) {
+ DEBUGP("SNATP2P: wrong table %s\n", tablename);
+ return 0;
+ }
+
+ if (hook_mask & ~(1 << NF_IP_POST_ROUTING)) {
+ DEBUGP("SNATP2P: hook mask 0x%x bad\n", hook_mask);
+ return 0;
+ }
+ return 1;
+}
+
+static struct ipt_target ipt_snatp2p_reg = {
+ .name = "SNATP2P",
+ .target = ipt_snatp2p_target,
+ .checkentry = ipt_snatp2p_checkentry,
+};
+
+static int __init init(void)
+{
+ if (ipt_register_target(&ipt_snatp2p_reg))
+ return -EINVAL;
+
+ return 0;
+}
+
+static void __exit fini(void)
+{
+ ipt_unregister_target(&ipt_snatp2p_reg);
+}
+
+module_init(init);
+module_exit(fini);

-------------Second Part------------
diff -Nur iptables-1.3.4/extensions/libi
t_SNATP2P.c iptables-b/extensions/libipt_SNATP2P.c
--- iptables-1.3.4/extensions/libipt_SNATP2P.c 1970-01-01
08:00:00.000000000 +
800
+++ iptables-b/extensions/libipt_SNATP2P.c 2005-11-09
17:32:58.000000000 +
800
@@ -0,0 +1,249 @@
+/* Shared library add-on to iptables to add source-NAT-P2P support. */
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+/* Source NAT data consists of a multi-range, indicating where to map
+ to. */
+struct ipt_natinfo
+{
+ struct ipt_entry_target t;
+ struct ip_nat_multi_range mr;
+};
+
+/* Function which prints out usage message. */
+static void
+help(void)
+{
+ printf(
+"SNATP2P v%s options:\n"
+" --to-source [-][:port-port]\n"
+" Address to map source to.\n"
+" (You can use this more than once)\n\n",
+IPTABLES_VERSION);
+}
+
+static struct option opts[] = {
+ { "to-source", 1, 0, '1' },
+ { 0 }
+};
+
+static struct ipt_natinfo *
+append_range(struct ipt_natinfo *info, const struct ip_nat_range *range)
+{
+ unsigned int size;
+
+ /* One rangesize already in struct ipt_natinfo */
+ size = IPT_ALIGN(sizeof(*info) + info->mr.rangesize *
sizeof(*range));
+
+ info = realloc(info, size);
+ if (!info)
+ exit_error(OTHER_PROBLEM, "Out of memory\n");
+
+ info->t.u.target_size = size;
+ info->mr.range[info->mr.rangesize] = *range;
+ info->mr.rangesize++;
+
+ return info;
+}
+
+/* Ranges expected in network order. */
+static struct ipt_entry_target *
+parse_to(char *arg, int portok, struct ipt_natinfo *info)
+{
+ struct ip_nat_range range;
+ char *colon, *dash, *error;
+ struct in_addr *ip;
+
+ memset(&range, 0, sizeof(range));
+ colon = strchr(arg, ':');
+
+ if (colon) {
+ int port;
+
+ if (!portok)
+ exit_error(PARAMETER_PROBLEM,
+ "Need TCP or UDP with port
specification");
+
+ range.flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
+
+ port = atoi(colon+1);
+ if (port <= 0 || port > 65535)
+ exit_error(PARAMETER_PROBLEM,
+ "Port `%s' not valid\n", colon+1);
+
+ error = strchr(colon+1, ':');
+ if (error)
+ exit_error(PARAMETER_PROBLEM,
+ "Invalid port:port syntax - use dash\n");
+
+ dash = strchr(colon, '-');
+ if (!dash) {
+ range.min.tcp.port
+ = range.max.tcp.port
+ = htons(port);
+ } else {
+ int maxport;
+
+ maxport = atoi(dash + 1);
+ if (maxport <= 0 || maxport > 65535)
+ exit_error(PARAMETER_PROBLEM,
+ "Port `%s' not valid\n", dash+1);
+ if (maxport < port)
+ /* People are stupid. */
+ exit_error(PARAMETER_PROBLEM,
+ "Port range `%s' funky\n",
colon+1);
+ range.min.tcp.port = htons(port);
+ range.max.tcp.port = htons(maxport);
+ }
+ /* Starts with a colon? No IP info...*/
+ if (colon == arg)
+ return &(append_range(info, &range)->t);
+ *colon = '\0';
+ }
+
+ range.flags |= IP_NAT_RANGE_MAP_IPS;
+ dash = strchr(arg, '-');
+ if (colon && dash && dash > colon)
+ dash = NULL;
+
+ if (dash)
+ *dash = '\0';
+
+ ip = dotted_to_addr(arg);
+ if (!ip)
+ exit_error(PARAMETER_PROBLEM, "Bad IP address `%s'\n",
+ arg);
+ range.min_ip = ip->s_addr;
+ if (dash) {
+ ip = dotted_to_addr(dash+1);
+ if (!ip)
+ exit_error(PARAMETER_PROBLEM, "Bad IP address
`%s'\n",
+ dash+1);
+ range.max_ip = ip->s_addr;
+ } else
+ range.max_ip = range.min_ip;
+
+ return &(append_range(info, &range)->t);
+}
+
+/* Function which parses command options; returns true if it
+ ate an option */
+static int
+parse(int c, char **argv, int invert, unsigned int *flags,
+ const struct ipt_entry *entry,
+ struct ipt_entry_target **target)
+{
+ struct ipt_natinfo *info = (void *)*target;
+ int portok;
+
+ if (entry->ip.proto == IPPROTO_TCP
+ || entry->ip.proto == IPPROTO_UDP
+ || entry->ip.proto == IPPROTO_ICMP)
+ portok = 1;
+ else
+ portok = 0;
+
+ switch (c) {
+ case '1':
+ if (check_inverse(optarg, &invert, NULL, 0))
+ exit_error(PARAMETER_PROBLEM,
+ "Unexpected `!' after --to-source");
+
+ if (*flags) {
+ if (!kernel_version)
+ get_kernel_version();
+ if (kernel_version > LINUX_VERSION(2, 6, 10))
+ exit_error(PARAMETER_PROBLEM,
+ "Multiple --to-source not
supported"
;
+ }
+ *target = parse_to(optarg, portok, info);
+ *flags = 1;
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
+/* Final check; must have specfied --to-source. */
+static void final_check(unsigned int flags)
+{
+ if (!flags)
+ exit_error(PARAMETER_PROBLEM,
+ "You must specify --to-source");
+}
+
+static void print_range(const struct ip_nat_range *r)
+{
+ if (r->flags & IP_NAT_RANGE_MAP_IPS) {
+ struct in_addr a;
+
+ a.s_addr = r->min_ip;
+ printf("%s", addr_to_dotted(&a));
+ if (r->max_ip != r->min_ip) {
+ a.s_addr = r->max_ip;
+ printf("-%s", addr_to_dotted(&a));
+ }
+ }
+ if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) {
+ printf(":");
+ printf("%hu", ntohs(r->min.tcp.port));
+ if (r->max.tcp.port != r->min.tcp.port)
+ printf("-%hu", ntohs(r->max.tcp.port));
+ }
+}
+
+/* Prints out the targinfo. */
+static void
+print(const struct ipt_ip *ip,
+ const struct ipt_entry_target *target,
+ int numeric)
+{
+ struct ipt_natinfo *info = (void *)target;
+ unsigned int i = 0;
+
+ printf("to:");
+ for (i = 0; i <>mr.rangesize; i++) {
+ print_range(&info->mr.range[i]);
+ printf(" ");
+ }
+}
+
+/* Saves the union ipt_targinfo in parsable form to stdout. */
+static void
+save(const struct ipt_ip *ip, const struct ipt_entry_target *target)
+{
+ struct ipt_natinfo *info = (void *)target;
+ unsigned int i = 0;
+
+ for (i = 0; i <>mr.rangesize; i++) {
+ printf("--to-source ");
+ print_range(&info->mr.range[i]);
+ printf(" ");
+ }
+}
+
+static struct iptables_target snatp2p = {
+ .next = NULL,
+ .name = "SNATP2P",
+ .version = IPTABLES_VERSION,
+ .size = IPT_ALIGN(sizeof(struct ip_nat_multi_range)),
+ .userspacesize = IPT_ALIGN(sizeof(struct ip_nat_multi_range)),
+ .help = &help,
+ .parse = &parse,
+ .final_check = &final_check,
+ .print = &print,
+ .save = &save,
+ .extra_opts = opts
+};file:///C:/Documents%20and%20Settings/Vincent/Application%20Data/Microsoft/Internet%20Explorer/Quick%20Launch/CuteFTP%208%20Professional.lnk
+
+void _init(void)
+{
+ register_target(&snatp2p);
+}





NAT implementation in the linux
http://lists.netfilter.org/pipermail/netfilter-devel/2004-November/017457.html

For connection/packet PROTO-SRCIP:SPT=>DSTIP:DPT:

1) Look up user-defined rules to decide what range to NAT this to
(default is if no rule). We support ranges.

2) Look up a a "bysource" hash table of (PROTO, SRCIP, SPT). If another
connection from the same endpoint is found, and the same mapping gives a
connection within the range, try that. If that mapping creates a unique
reply (ie. there's no PROTO-DSTIP:DPT=>mapped SRCIP:mapped SPT in our
"conntrack" hash table), we're done.

3) Try a mapping which doesn't change SPT, ie. just changing the SRCIP
to each IP address in the range. If that mapping creates a unique
reply, we're done.

4) Try altering the SPT as well (we attempt to keep high ports high,
etc). If this fails, we drop the connection.

Consider two machines A and B being NATed through N to servers Sa, Sb
and Sc respectively (rule says NAT source to N):

A:45000 -> Sa:80 <=> N:45000 -> Sa:80 (rule 3)
B:45000 -> Sb:80 <=> N:45000 -> Sb:80 (rule 3)
A:45000 -> Sc:80 <=> N:45000 -> Sc:80 (rule 2)
B:45000 -> Sc:80 <=> N:45001 -> Sc:80 (rule 2 clash, rule 4)

2007年5月6日 星期日

如何在child process 中利用gdb debug

問題描述:
跑一個process, 中間 fork ㄧ個 child process, 之後parent process 繼續執行, 發現child process 好像卡住, 不會繼續動作

Step1.
ulimit -c unlimited
設定 core dump file size 為unlimited, 預設值為0 size

ulimit 程式的主要目的是用來設定程式執行的許多參數, 包括 core file size, data segment size 還有許多其他的參數, 請利用 ulimit -a 來秀所有support 的參數
# ulimit -a
core file size (blocks, -c) unlimited
data seg size (kbytes, -d) unlimited
file size (blocks, -f) unlimited
pending signals (-i) 1024
max locked memory (kbytes, -l) 32
max memory size (kbytes, -m) unlimited
open files (-n) 1024t
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
stack size (kbytes, -s) 10240
cpu time (seconds, -t) unlimited
max user processes (-u) 3072
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited


Step2.
執行主程式, 可以看到parent process fork 出child process 的process id 為 31887 (利用 getpid()得知), 另外在 ps 也可以看到

# ps aux | grep prog
root 31886 0.1 0.4 2932 904 pts/1 S+ 00:42 0:00 ./prog
root 31887 0.0 0.4 2912 872 pts/1 S+ 00:42 0:00 ./prog
root 31888 0.0 0.4 2928 928 pts/1 S+ 00:42 0:00 ./prog


Step3.
kill -11 31887
送出 SIGSEGV signal 給 child process, child process 收到 segmentation fault 的signal, 就會 core dump 並且在同一個目錄下, 產生core.XXX (XXX為process id) 的檔案, 以這裡的例子而言就是
core.31887

/usr/include/asm/signal.h 下的定義
#define SIGSEGV 11


Step4.
利用 gdb 來debug
# gdb prog core.31887

[略]
Core was generated by `./prog'.
Program terminated with signal 11, Segmentation fault.
Reading symbols from /usr/lib/libstdc++.so.6...done.
Loaded symbols for /usr/lib/libstdc++.so.6
Reading symbols from /lib/tls/libm.so.6...done.
Loaded symbols for /lib/tls/libm.so.6
Reading symbols from /lib/libgcc_s.so.1...done.
Loaded symbols for /lib/libgcc_s.so.1
Reading symbols from /lib/tls/libc.so.6...done.
Loaded symbols for /lib/tls/libc.so.6
Reading symbols from /lib/ld-linux.so.2...done.
Loaded symbols for /lib/ld-linux.so.2
#0 0x0092e7a2 in _dl_sysinfo_int80 () from /lib/ld-linux.so.2
(gdb) bt << 下bt (backtrace) 去 trace 所有的 function
#0 0x0092e7a2 in _dl_sysinfo_int80 () from /lib/ld-linux.so.2
#1 0x00a0cfc1 in recvfrom () from /lib/tls/libc.so.6
#2 0x0804f0b7 in getMessage (fd=2048, buf=0xfef6d4a0 "\001\001", len=0xfef6cfc4, srcIp=0x800, srcPort=0x800,
verbose=false) at udp.cxx:127
#3 0x0804daf6 in MyTest (myFd=3, dest=@0x800, testNum=1, verbose=false, reply=0xfef6df18) at stun.cxx:2188
#4 0x0804a460 in get_mess (req=0xfef6df50, reqtype=QT_Reflexive, reply=0x0, type=0xfffffe00)
at myclient.cxx:632
#5 0x0804a8c6 in refresh (reqfd=3, svr=0xfef6ea60) at myclient.cxx:572
#6 0x08049299 in main (argc=1, argv=0xfef6eb24) at sip8test.c:71

因為 frame 0, 1 都是system call
frame 2, 3, 4, 5, 6 都是我們程式自己寫的 function
所以可以懷疑程式是卡在 fram 2 getMessage function 當中, 也就是 udp.cxx 的第127 行

Step5.
frame 就是有許多不同層 stack 的意思, 在gdb 中可以利用frame 去jump 到某ㄧ個特定的stack (frame), 來print variable value

(gdb) frame 2 << 我們這裡執行 frame 2 來看stack2 的variable value, 可以用 p XXX 來看
#2 0x0804f0b7 in getMessage (fd=2048, buf=0xfef6d4a0 "\001\001", len=0xfef6cfc4, srcIp=0x800, srcPort=0x800,
verbose=false) at udp.cxx:127
127 *len = recvfrom(fd,


Step6.
這時可以list 來看 code 的內容, 找出錯誤的原因

(gdb) list
122 assert( originalSize > 0 );
123
124 struct sockaddr_in from;
125 int fromLen = sizeof(from);
126
127 *len = recvfrom(fd,
128 buf,
129 originalSize,
130 0,
131 (struct sockaddr *)&from,


Embedded system debug
# toolChain_gdb daemon coreFile
For example
# /opt/v6_be_uclibc/bin/arm_v6_be_uclibc-gdb daemon coreFile

2007年5月3日 星期四

p2p working group and research

Internet2 Peer to Peer Working Group - P2P WG

- [ 翻譯此頁 ]
The Internet2 End-to-End Performance Initiative (E2Epi) is aimed at improving end-to-end performance in the network infrastructure by focusing resources and efforts on improving performance problem detection and resolution throughout ...
p2p.internet2.edu/ - 17k - 頁庫存檔 - 類似網頁

OpenP2P.com -- How the Peer-to-Peer Working Group Ought to Be ...

- [ 翻譯此頁 ]
Tim O'Reilly says that Intel squandered the opportunity to kick off a real working group process at its first meeting of the Peer-to-Peer working group.
www.openp2p.com/pub/a/p2p/2000/10/13/working_grp.html - 29k - 頁庫存檔 - 類似網頁

P2P Networks

- [ 翻譯此頁 ]OpenP2P.com -- p2p development, open source development The O'Reilly Network's P2P DevCenter offers comprehensive P2P developer information. Peer-to-Peer Working Group - Home · Thoughts on Peer-to-Peer.
ntrg.cs.tcd.ie/undergrad/4ba2.02-03/Intro.html - 6k -頁庫存檔 - 類似網頁



pureftp 操作經驗

How to add a user to the pureftp

1. vi /etc/pureftpd.passwd,
新增ㄧ筆user data 在pureftpd 密碼檔當中, ㄧ般標準程序是利用
pure-pw useradd 來新增user, 這裡直接去修改 pureftpd 密碼檔比較快,
直接複製既有其他的user password, 修改username, 以及login 的directory,
david:$2a$07$zSvK1qKH4q3hWAz.E3CAEussQp29Qt/tm2vnEy:10003:100:David Lee:/home/david/./::::::::::::

/home/david/. ==> login directory 之後有一點(.)表示, login 後被 change 為只能看到login directory 以下的檔案, 不能看到整個系統的檔案

2. 新增user 之後, 再去更改該 user 的 password
pure-pw passwd david

3. 最後跑 pure-pw mkdb 即可

2007年5月2日 星期三

shared memory 心得

1. 每個process 都擁有自己的4G virtual memory, 而實際對應到真正的 physically memory, 則是靠kernel 的 Memory management unit 來做處理, 所以在不同的process 之間所看到的同樣位址(virtual address), 實際對應到memory 的 physical address (linear address) 並不相同

2. 如果是 shared memory 則在不同的 process 所看到的 shared memory virtual address 則會對應到同一個physical address

destroy_conntrack 的call 法

destroy_conntrack 的call 法如下
net/ipv4/netfilter/ip_conntrack_core.c
inline void
ip_conntrack_put(struct ip_conntrack *ct)
{
IP_NF_ASSERT(ct);
nf_conntrack_put(&ct->ct_general);
}
include/linux/skbuff.h
static inline void nf_conntrack_put(struct nf_conntrack *nfct)
{
if (nfct && atomic_dec_and_test(&nfct->use))
nfct->destroy(nfct);
}
因為在 init_conntrack 時, 有做 use 的atomic set 動作, 所以必須call ip_conntrack_put 來
作 decrease use 的動作
net/ipv4/netfilter/ip_conntrack_core.c
init_conntrack(const struct ip_conntrack_tuple *tuple,
struct ip_conntrack_protocol *protocol,
struct sk_buff *skb) {
..
[略]
atomic_set(&conntrack->ct_general.use, 1);
conntrack->ct_general.destroy = destroy_conntrack;

2007年5月1日 星期二

shared memory

顯示系統目前的 shared memory
# ipcs -m

------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
0x0000162e 65536 root 666 27 0
0x00000000 98305 root 666 192 0
0x00001234 163843 root 666 192 0

刪除某ㄧ個特定的 shared memory key

# ipcrm -M 0x0000162e

原先的 shared memory 0x0000162e 已經被刪除了
# ipcs -m

------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
0x00000000 98305 root 666 192 0
0x00001234 163843 root 666 192 0

如何傳遞陣列指標(function variable) 在函數中

#include
#include
#include

struct abc {
int val;
char str[10];
};

void allocatemem(void*** a1) {
int amount;

printf("s1 - &a1: %10p, a1: %10p, *a1: %10p\n", a1, *a1, **a1);
amount = sizeof(struct abc)*16;
if ((*a1=(void**)malloc(amount))==NULL) {
printf("errno: %s, desc: %s\n", errno, strerror(errno));
}
printf("s2 - &a1: %10p, a1: %10p, *a1: %10p\n", a1, *a1, **a1);

memset(*a1, 0, amount);
//printf("memset ok\n");
printf("s4 - &a1: %10p, a1: %10p, *a1: %10p\n", a1, *a1, **a1);
}


void filldata(struct abc (*aa)[16]) {
printf("s6 - &aa: %10p, aa: %10p, *aa: %10p, &(*aa)[0]: %10p, &(*aa)[1]: %10p\n", &aa, aa, *aa, &(*aa)[0], &(*aa)[1]);
(*aa)[0].val = 0;
strcpy((*aa)[0].str, "hello0");
printf("aa[0] ok\n");

(*aa[1]).val = 1;
strcpy((*aa[1]).str, "hello1");
printf("aa[1] ok\n");
}

int main(int argc, char** argv) {
struct abc (*a1)[16];
printf("s0 - &a1: %10p, a1: %10p, *a1: %10p, &(*a1)[0]: %10p, &(*a1)[1]: %10p\n", &a1, a1, *a1, &(*a1)[0], &(*a1)[1]);
allocatemem((void***)&a1);
printf("s5 - &a1: %10p, a1: %10p, *a1: %10p, &(*a1)[0]: %10p, &(*a1)[1]: %10p\n", &a1, a1, *a1, &(*a1)[0], &(*a1)[1]);
filldata(a1);

return 0;
}

# gcc -o a5 ./array5.c

# ./a5
s0 - &a1: 0xfeee4444, a1: 0x943c80, *a1: 0x943c80, &(*a1)[0]: 0x943c80, &(*a1)[1]: 0x943c90
s1 - &a1: 0xfeee4444, a1: 0x943c80, *a1: (nil)
s2 - &a1: 0xfeee4444, a1: 0x8820008, *a1: (nil)
s4 - &a1: 0xfeee4444, a1: 0x8820008, *a1: (nil)
s5 - &a1: 0xfeee4444, a1: 0x8820008, *a1: 0x8820008, &(*a1)[0]: 0x8820008, &(*a1)[1]: 0x8820018
s6 - &aa: 0xfeee4420, aa: 0x8820008, *aa: 0x8820008, &(*aa)[0]: 0x8820008, &(*aa)[1]: 0x8820018
aa[0] ok
aa[1] ok