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