kk Blog —— 通用基础

date [-d @int|str] [+%s|"+%F %T"]

cubic

http://www.pagefault.info/?p=145

这次主要来看一下内核拥塞控制算法cubic的实现,在linux kernel中实现了很多种拥塞控制算法,不过新的内核(2.6.19之后)默认是cubic(想得到当前内核使用的拥塞控制算法可以察看/proc/sys/net/ipv4/tcp_congestion_control这个值).下面是最新的redhat 6的拥塞控制算法(rh5还是bic算法):

1
2
[root@rhel6 ~]# cat /proc/sys/net/ipv4/tcp_congestion_control 
cubic

这个算法的paper在这里:

http://netsrv.csc.ncsu.edu/export/cubic_a_new_tcp_2008.pdf

拥塞控制算法会在tcp_ack中被调用,如果是正常的ack(比如不是重复的,不是sack等等)就会进入拥塞控制算法。

cubic会调用tcp_slow_start这个方法(基本上每种拥塞控制算法都会调用它),这个方法主要是处理slow start,而内核中的slow start是这样子的,接收一个ack,snd_cwnd就会加1,然后当cwnd大于设置的拥塞窗口阀值snd_ssthresh的时候,就会进入拥塞避免状态。而在发送数据包的时候,会判断in_flight(可以认为是发送还没确认的数据包,它等于发送未确认的数据包-sack的数据段-丢失的数据段+重传的数据段,我的前面的blog有详细解释这个数据段)是否大于snd_cwnd,如果大于等于则不会发送数据,如果小于才会继续发送数据。

而进入拥塞避免状态之后,窗口的增长速度将会减缓,

来看一下我用jprobe hook tcp_slow_start(slow start处理函数) 和 tcp_cong_avoid_ai (拥塞避免处理)的数据。

在下面的数据中sk表示当前socket的地址, in_flight packet表示发送还未接收的包, snd_cwnd表示发送拥塞窗口。 然后详细解释下count后面的两个值,其中第一个是snd_cwnd_cnt,表示在当前的拥塞窗口中已经发送的数据段的个数,而第二个是struct bictcp的一个域cnt,它是cubic拥塞算法的核心,主要用来控制在拥塞避免状态的时候,什么时候才能增大拥塞窗口,具体实现是通过比较它和snd_cwnd_cnt,来决定是否增大拥塞窗口,而这个值的计算,我这里不会分析,想了解的,可以去看cubic的paper。

还有一个需要注意的地方就是ssthresh,可以看到这个值在一开始初始化为一个最大的值,然后在进入拥塞避免状态的时候被设置为前一次拥塞窗口的大小.这个处理可以看rfc2581的这段:

The initial value of ssthresh may be arbitrarily high (i.e., the size of the advertised window), but it may be reduced in response to congestion. When cwnd < ssthresh, the slow-start algorithm is used and when cwnd > ssthresh, the congestion avoidance algorithm is used. When cwnd and ssthresh are equal, the sender may use either of them.

我们后面会看到这个值在cubic中是如何被设置的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
//进入slow start,可以看到拥塞窗口默认初始值是3,然后每次接收到ack,都会加1.
enter [slow start state] tcp_sock is 4129562112 in_flight packets is 2, snd_cwnd is 3, ssthresh is 2147483647, count is [0:0]
enter [slow start state] tcp_sock is 4129562112 in_flight packets is 3, snd_cwnd is 4, ssthresh is 2147483647, count is [0:0]
enter [slow start state] tcp_sock is 4129562112 in_flight packets is 4, snd_cwnd is 5, ssthresh is 2147483647, count is [0:0]
enter [slow start state] tcp_sock is 4129562112 in_flight packets is 5, snd_cwnd is 6, ssthresh is 2147483647, count is [0:0]
enter [slow start state] tcp_sock is 4129562112 in_flight packets is 4, snd_cwnd is 7, ssthresh is 2147483647, count is [0:0]
enter [slow start state] tcp_sock is 4129562112 in_flight packets is 7, snd_cwnd is 8, ssthresh is 2147483647, count is [0:0]
enter [slow start state] tcp_sock is 4129562112 in_flight packets is 6, snd_cwnd is 9, ssthresh is 2147483647, count is [0:0]
enter [slow start state] tcp_sock is 4129562112 in_flight packets is 9, snd_cwnd is 10, ssthresh is 2147483647, count is [0:0]
enter [slow start state] tcp_sock is 4129562112 in_flight packets is 10, snd_cwnd is 11, ssthresh is 2147483647, count is [0:0]
enter [slow start state] tcp_sock is 4129562112 in_flight packets is 11, snd_cwnd is 12, ssthresh is 2147483647, count is [0:0]
enter [slow start state] tcp_sock is 4129562112 in_flight packets is 10, snd_cwnd is 13, ssthresh is 2147483647, count is [0:0]
enter [slow start state] tcp_sock is 4129562112 in_flight packets is 9, snd_cwnd is 14, ssthresh is 2147483647, count is [0:0]
enter [slow start state] tcp_sock is 4129562112 in_flight packets is 14, snd_cwnd is 15, ssthresh is 2147483647, count is [0:0]
//ssthresh被更新为当前拥塞窗口的大小,后面会看到为什么是16
enter [slow start state] tcp_sock is 4129562112 in_flight packets is 13, snd_cwnd is 16, ssthresh is 16, count is [0:0]
//进入拥塞避免,可以清楚的看到,此时拥塞窗口大于对应的阀值ssthresh.
enter [cong avoid state] tcp_sock is 4129562112 in_flight packets is 16, snd_cwnd is 17, ssthresh is 16, count is [0:877]
enter [cong avoid state] tcp_sock is 4129562112 in_flight packets is 15, snd_cwnd is 17, ssthresh is 16, count is [1:877]
enter [cong avoid state] tcp_sock is 4129562112 in_flight packets is 16, snd_cwnd is 17, ssthresh is 16, count is [2:877]
enter [cong avoid state] tcp_sock is 4129562112 in_flight packets is 15, snd_cwnd is 17, ssthresh is 16, count is [3:877]
enter [cong avoid state] tcp_sock is 4129562112 in_flight packets is 14, snd_cwnd is 17, ssthresh is 16, count is [4:877]
enter [cong avoid state] tcp_sock is 4129562112 in_flight packets is 13, snd_cwnd is 17, ssthresh is 16, count is [5:877]
//这里注意,其中count的第一个值是一直线性增长的,也就是说下面省略了大概80条log,而在这80几次中拥塞窗口一直维持在17没有变化
....................................................................................................................
//可以看到cnt变为3,也就是说明当执行完拥塞避免就会增加窗口了。
enter [cong avoid state] tcp_sock is 4129562112 in_flight packets is 13, snd_cwnd is 17, ssthresh is 16, count is [91:3]
//增加窗口的大小,然后将snd_cwnd_cnt reset为0.
enter [cong avoid state] tcp_sock is 4129562112 in_flight packets is 11, snd_cwnd is 18, ssthresh is 16, count is [0:6]
enter [cong avoid state] tcp_sock is 4129562112 in_flight packets is 16, snd_cwnd is 18, ssthresh is 16, count is [1:6]
enter [cong avoid state] tcp_sock is 4129562112 in_flight packets is 14, snd_cwnd is 18, ssthresh is 16, count is [2:6]
enter [cong avoid state] tcp_sock is 4129562112 in_flight packets is 12, snd_cwnd is 18, ssthresh is 16, count is [3:6]
enter [cong avoid state] tcp_sock is 4129562112 in_flight packets is 12, snd_cwnd is 18, ssthresh is 16, count is [4:6]

可以看到在slow start的状态,发送拥塞窗口就是很简单的每次加1,而当进入拥塞避免之后,明显的拥塞窗口的增大速度变慢很多。

接下来来看具体的代码是如何实现的.

首先来看bictcp_cong_avoid,也就是cubic拥塞控制算法的handler(一般来说在tcp_ack中被调用),它有3个参数,第一个是对应的sock,第二个是对应的ack序列号,而第三个就是比较重要的一个变量,表示发送还没有被ack的数据包(在linux 内核tcp拥塞处理一中详细介绍过内核中这些变量),这个变量是拥塞控制的核心。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
static void bictcp_cong_avoid(struct sock *sk, u32 ack, u32 in_flight)
{
	struct tcp_sock *tp = tcp_sk(sk);
	struct bictcp *ca = inet_csk_ca(sk);
	//判断发送拥塞窗口是否到达限制,如果到达限制则直接返回。
	if (!tcp_is_cwnd_limited(sk, in_flight))
		return;
	//开始决定进入slow start还是拥塞控制状态
	if (tp->snd_cwnd <= tp->snd_ssthresh) {
		//是否需要reset对应的bictcp的值
		if (hystart && after(ack, ca->end_seq))
			bictcp_hystart_reset(sk);
		//进入slow start状态
		tcp_slow_start(tp);
	} else {
		//进入拥塞避免状态,首先会更新ca->cnt.
		bictcp_update(ca, tp->snd_cwnd);
		//然后进入拥塞避免
		tcp_cong_avoid_ai(tp, ca->cnt);
	}
}

接下来就是看tcp_is_cwnd_limited,这个函数主要是实现RFC2861中对拥塞窗口的检测。它返回1说明拥塞窗口被限制,我们需要增加拥塞窗口,否则的话,就不需要增加拥塞窗口。

然后这里还有两个判断,先来看第一个 gso的概念,gso是Generic Segmentation Offload的简写,他的主要功能就是尽量的延迟数据包的传输,以便与在最恰当的时机传输数据包,这个机制是处于数据包离开协议栈与进入驱动之间。比如如果驱动支持TSO的话,gso就会将多个unsegmented的数据段传递给驱动。而TSO是TCP Segmentation Offload的缩写,它表示驱动支持协议栈发送大的MTU的数据段,然后硬件负责来切包,然后将数据发送出去,这样子的话,就能提高系统的吞吐。这几个东西(还有GRO),以后我会详细分析,现在只需要大概知道他们是干什么的。

而在这里如果支持gso,就有可能是tso defer住了数据包,因此这里会进行几个相关的判断,来看需不需要增加拥塞窗口。。

然后是burst的概念,主要用来控制网络流量的突发性增大,也就是说当left数据(还能发送的数据段数)大于burst值的时候,我们需要暂时停止增加窗口,因为此时有可能我们这边数据发送过快。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int tcp_is_cwnd_limited(const struct sock *sk, u32 in_flight)
{
	const struct tcp_sock *tp = tcp_sk(sk);
	u32 left;
	//比较发送未确认和发送拥塞窗口的大小
	if (in_flight >= tp->snd_cwnd)
		return 1;
	//得到还能发送的数据包的段数
	left = tp->snd_cwnd - in_flight;
	if (sk_can_gso(sk) &&
		left * sysctl_tcp_tso_win_divisor < tp->snd_cwnd &&
		left * tp->mss_cache < sk->sk_gso_max_size)
		return 1;
	//看是否还能发送的数据包是否小于等于burst
	return left <= tcp_max_burst(tp);
}

接下来来看snd_ssthresh是如何被设置的,这个值在加载cubic模块的时候可以传递一个我们制定的值给它,不过,默认是很大的值,我这里是2147483647,然后在接收ack期间(slow start)期间会调整这个值,在cubic中,默认是16(一般来说说当拥塞窗口到达16的时候,snd_ssthresh会被设置为16).

在cubic中有两个可以设置snd_ssthresh的地方一个是hystart_update,一个是bictcp_recalc_ssthresh,后一个我这里就不介绍了,以后介绍拥塞状态机的时候会详细介绍,现在只需要知道,只有遇到拥塞的时候,需要调整snd_ssthres的时候,我们才需要调用bictcp_recalc_ssthresh。

而hystart_update是在bictcp_acked中被调用,而bictcp_acked则是基本每次收到ack都会调用这个函数,我们来看在bictcp_acked中什么情况就会调用hystart_update:

1
2
3
4
/* hystart triggers when cwnd is larger than some threshold */
if (hystart && tp->snd_cwnd <= tp->snd_ssthresh &&
	tp->snd_cwnd >= hystart_low_window)
	hystart_update(sk, delay);

其中hystart是hybrid slow start打开的标志,默认是开启,hystart_low_window是设置snd_ssthresh的最小拥塞窗口值,默认是16。而tp->snd_ssthresh默认是一个很大的值,因此这里就知道了,当拥塞窗口增大到16的时候我们就会进去hystart_update来更新snd_ssthresh.因此hystart_updat换句话来说也就是主要用于是否退出slow start。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
static void hystart_update(struct sock *sk, u32 delay)
{
	struct tcp_sock *tp = tcp_sk(sk);
	struct bictcp *ca = inet_csk_ca(sk);

	if (!(ca->found & hystart_detect)) {
		.................................................................
		/*
		 * Either one of two conditions are met,
		 * we exit from slow start immediately.
		 */
		//found是一个是否退出slow start的标记
		if (ca->found & hystart_detect)
			//设置snd_ssthresh
			tp->snd_ssthresh = tp->snd_cwnd;
	}
}

然后是slow start的处理,这里有关abc的处理,注释都很详细了,这里就不解释了,我们主要看abc关闭的部分。这里使用cnt,也是主要为了打开abc之后的slow start。

这是abc(Appropriate Byte Counting)相关的rfc:

http://www.faqs.org/rfcs/rfc3465.html

Appropriate Byte Countin会导致拥塞控制算法很激进,比如打开它之后就不一定每次ack都会执行slow start,而且窗口也会增加的快很多。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
void tcp_slow_start(struct tcp_sock *tp)
{
	int cnt; /* increase in packets */

	/* RFC3465: ABC Slow start
	 * Increase only after a full MSS of bytes is acked
	 *
	 * TCP sender SHOULD increase cwnd by the number of
	 * previously unacknowledged bytes ACKed by each incoming
	 * acknowledgment, provided the increase is not more than L
	 */
	if (sysctl_tcp_abc && tp->bytes_acked < tp->mss_cache)
		return;
	//限制slow start的cnt
	if (sysctl_tcp_max_ssthresh > 0 && tp->snd_cwnd > sysctl_tcp_max_ssthresh)
		cnt = sysctl_tcp_max_ssthresh >> 1; /* limited slow start */
	else
		cnt = tp->snd_cwnd;            /* exponential increase */

	/* RFC3465: ABC
	 * We MAY increase by 2 if discovered delayed ack
	 */
	if (sysctl_tcp_abc > 1 && tp->bytes_acked >= 2*tp->mss_cache)
		cnt <<= 1;
	tp->bytes_acked = 0;
	//更新cnt,也就是当前拥塞窗口接受的段的个数.
	tp->snd_cwnd_cnt += cnt;
	while (tp->snd_cwnd_cnt >= tp->snd_cwnd) {
		//这里snd_cwnd_cnt是snd_cwnd的几倍,拥塞窗口就增加几。
		tp->snd_cwnd_cnt -= tp->snd_cwnd;
		//如果拥塞窗口没有超过最大值,则加一
		if (tp->snd_cwnd < tp->snd_cwnd_clamp)
			tp->snd_cwnd++;
	}
}

最后是拥塞避免的处理。这里主要的步骤就是通过判断当前的拥塞窗口下已经发送的数据段的个数是否大于算法计算出来的值w,如果大于我们才能增加拥塞窗口值,否则之需要增加snd_cwnd_cnt。

1
2
3
4
5
6
7
8
9
10
11
12
void tcp_cong_avoid_ai(struct tcp_sock *tp, u32 w)
{
	//判断是否大于我们的标记值
	if (tp->snd_cwnd_cnt >= w) {
		if (tp->snd_cwnd < tp->snd_cwnd_clamp)
			tp->snd_cwnd++;
		tp->snd_cwnd_cnt = 0;
	} else {
		//增加计数值
		tp->snd_cwnd_cnt++;
	}
}

iptables

http://my.oschina.net/kisops/blog/150995

解决:nf_conntrack: table full, dropping packet.


“连接跟踪表已满,开始丢包”!相信不少用iptables的同学都会见过这个错误信息吧,这个问题曾经也困扰过我好长一段时间。此问题的解决办法有四种(nf_conntrack 在CentOS 5 / kernel <= 2.6.19中名为 ip_conntrack ):

一、关闭防火墙。 简单粗暴,直接有效

1
2
3
4
chkconfig iptables off
chkconfig ip6tables off
service iptables stop
service ip6tables stop

切记:在防火墙关闭状态下,不要通过iptables指令(比如 iptables -nL)来查看当前状态!因为这样会导致防火墙被启动,而且规则为空。虽然不会有任何拦截效果,但所有连接状态都会被记录,浪费资源且影响性能并可能导致防火墙主动丢包!

二、加大防火墙跟踪表的大小,优化对应的系统参数

1、状态跟踪表的最大行数的设定,理论最大值 CONNTRACK_MAX = RAMSIZE (in bytes) / 16384 / (ARCH / 32)

以64G的64位操作系统为例,CONNTRACK_MAX = 6410241024*1024/16384/2 = 2097152

即时生效请执行:

1
sysctl -w net.netfilter.nf_conntrack_max = 2097152
2、其哈希表大小通常为总表的1/8,最大为1/2。

CONNTRACK_BUCKETS = CONNTRACK_MAX / 8

同样64G的64位操作系统,哈希最佳范围是 262144 ~ 1048576 。

运行状态中通过 sysctl net.netfilter.nf_conntrack_buckets 进行查看,通过文件 /sys/module/nf_conntrack/parameters/hashsize 进行设置

或者新建 /etc/modprobe.d/iptables.conf ,重新加载模块才生效:

1
options nf_conntrack hashsize = 262144
3、还有些相关的系统参数sysctl -a | grep nf_conntrack可以调优(/etc/sysctl.conf ):
1
2
3
4
5
net.netfilter.nf_conntrack_max  =   1048576
net.netfilter.ip_conntrack_tcp_timeout_established  =   3600
net.netfilter.nf_conntrack_tcp_timeout_close_wait  =   60
net.netfilter.nf_conntrack_tcp_timeout_fin_wait  =   120
net.netfilter.nf_conntrack_tcp_timeout_time_wait  =   120

三、使用祼表,添加“不跟踪”标识。如下示例更适合桌面系统或随意性强的服务器。因为它开启了连接的状态机制,方便和外部通信。修改 /etc/sysconfig/iptables 文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
*raw
# 对TCP连接不启用追踪,解决ip_contrack满导致无法连接的问题
-A PREROUTING -p tcp -m tcp --dport 80 -j NOTRACK
-A PREROUTING -p tcp -m tcp --dport 22 -j NOTRACK
-A PREROUTING -p tcp -m tcp --dport 21 -j NOTRACK
-A PREROUTING -p tcp -m tcp --dport 11211 -j NOTRACK
-A PREROUTING -p tcp -m tcp --dport 60000:60100 -j NOTRACK
-A PREROUTING -p tcp -s 192.168.10.1 -j NOTRACK
-A OUTPUT -p tcp -m tcp --sport 80 -j NOTRACK
-A OUTPUT -p tcp -m tcp --sport 22 -j NOTRACK
-A OUTPUT -p tcp -m tcp --sport 21 -j NOTRACK
-A OUTPUT -p tcp -m tcp --sport 11211 -j NOTRACK
-A OUTPUT -p tcp -m tcp --sport 60000:60100 -j NOTRACK
-A OUTPUT -p tcp -s 192.168.10.1 -j NOTRACK
COMMIT
*filter
# 允许ping
-A INPUT -p icmp -j ACCEPT
# 对本地回路、第5张网卡放行
-A INPUT -i lo -j ACCEPT
-A INPUT -i eth4 -j ACCEPT
# 连接状态跟踪,已建立的连接允许传输数据
-A INPUT -m state --state ESTABLISHED,RELATED,INVALID,UNTRACKED -j ACCEPT
# filter表里存在但在raw里不存在的,默认会进行连接状态跟踪
-A INPUT -s 192.168.10.31 -p tcp --dport 2669 -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
COMMIT

或者干脆对所有连接都关闭跟踪,不跟踪任何连接状态。不过规则就限制比较严谨,进出都需要显式申明。示例 /etc/sysconfig/iptables :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
*raw
# 对TCP/UDP连接不启用追踪,解决nf_contrack满导致无法连接的问题
-A PREROUTING -p tcp -j NOTRACK
-A PREROUTING -p udp -j NOTRACK
-A OUTPUT -p tcp -j NOTRACK
-A OUTPUT -p udp -j NOTRACK
COMMIT
*filter
# 允许ping
-A INPUT -p icmp -j ACCEPT
# 对本地回路和eth1放行
-A INPUT -i lo -j ACCEPT
-A INPUT -i eth1 -j ACCEPT
# 只允许符合条件的连接进行传输数据
-A INPUT -p tcp --dport 22 -j ACCEPT
-A INPUT -p tcp --sport 80 -j ACCEPT
-A INPUT -p udp --sport 53 -j ACCEPT
-A INPUT -p udp --sport 123 -j ACCEPT
# 出去的包都不限制
-A OUTPUT -p tcp -j ACCEPT
-A OUTPUT -p udp -j ACCEPT
# 输入和转发的包不符合规则的全拦截
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
COMMIT

效果如下图:

四、删除连接跟踪模块lsmod | grep nf_conntrack,不使用连接状态的跟踪功能。

1、删除nf_conntrack和相关的依赖模块,示例:
1
2
3
4
5
6
7
8
9
rmmod nf_conntrack_ipv4
rmmod nf_conntrack_ipv6
rmmod xt_state
rmmod xt_CT
rmmod xt_conntrack
rmmod iptable_nat
rmmod ipt_REDIRECT
rmmod nf_nat
rmmod nf_conntrack
2、禁用跟踪模块,把它加到黑名单(/etc/modprobe.d/blacklist.conf ):
1
2
3
4
5
6
7
8
9
10
# 禁用 nf_conntrack 模块
blacklist nf_conntrack
blacklist nf_conntrack_ipv6
blacklist xt_conntrack
blacklist nf_conntrack_ftp
blacklist xt_state
blacklist iptable_nat
blacklist ipt_REDIRECT
blacklist nf_nat
blacklist nf_conntrack_ipv4
3、去掉防火墙里所有和状态相关的配置(比如state状态,NAT功能),示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
*filter
# 允许ping
-A INPUT -p icmp -j ACCEPT
# 对本地回路和第2张网卡放行
-A INPUT -i lo -j ACCEPT
-A INPUT -i eth1 -j ACCEPT
# 对端口放行
-A INPUT -p tcp --dport 1331 -j ACCEPT
# 对IP放行
-A INPUT -s 192.168.10.31 -j ACCEPT

#允许本机进行DNS查询

-A INPUT -p udp --sport 53 -j ACCEPT
-A OUTPUT -p udp -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
COMMIT

另外,防火墙的配置文件最好也改下,不要加载任何额外模块(/etc/sysconfig/iptables-config):

1
2
3
4
5
6
7
8
IPTABLES_MODULES="" # 不需要任何附加模块
IPTABLES_MODULES_UNLOAD="no" # 避免iptables重启后sysctl中对应的参数被重置为系统默认值
IPTABLES_SAVE_ON_STOP="no"
IPTABLES_SAVE_ON_RESTART="no"
IPTABLES_SAVE_COUNTER="no"
IPTABLES_STATUS_NUMERIC="yes"
IPTABLES_STATUS_VERBOSE="no"
IPTABLES_STATUS_LINENUMBERS="no"

往往我们对连接的跟踪都是基于操作系统的(netstat / ss ),防火墙的连接状态完全是它自身实现产生的。

总结:防火墙有条件还是交给上层设备完成会更好,使用防火墙一定要做调优;如果不需要防火墙的跟踪功能,规则简单的可以开启NOTRACK选项,条件允许的情况下就删除它吧!

curl命令

http://blog.csdn.net/hqzxsc2006/article/details/50547684

-s 静默输出;没有-s的话就是下面的情况,这是在脚本等情况下不需要的信息。

监控首页各项时间指标:

1
2
3
4
5
6
7
curl -o /dev/null -s -w '%{time_connect} %{time_starttransfer} %{time_total}' http://www.miotour.com
0.244 1.044 2.672

时间指标解释 :
time_connect      建立到服务器的 TCP 连接所用的时间
time_starttransfer    在发出请求之后,Web 服务器返回数据的第一个字节所用的时间
time_total            完成请求所用的时间

在发出请求之后,Web 服务器处理请求并开始发回数据所用的时间是 (time_starttransfer)1.044 - (time_connect)0.244 = 0.8 秒

客户机从服务器下载数据所用的时间是 (time_total)2.672 - (time_starttransfer)1.044 = 1.682 秒

-x 指定访问IP与端口号

1
curl -x 61.135.169.105:80 http://www.baidu.com

-I 仅仅取文件的http头部

1
curl   -I  -x 192.168.1.1:80  http://www.miotour.com

用referer做的防盗链,就可以使用-e来设置

1
curl -e "http://www.qiecuo.org"    http:// www.miotour.com -v  -I

-H去构造你想要的http头部

1
curl -H "X-Forward-For:8.8.8.8" http://www.miotour.com  -v  -I

curl提交用户名和密码

1
2
curl http://name:passwd@www.miotour.com
curl -u name:passwd http://www.miotour.com

-b “cookie” 此参数用来构造一个携带cookie的请求

USER AGENT 关于浏览器发送的http请求信息. Curl允许用命令制定. 发送一些用于欺骗服务器或cgi的信息.

1
curl -A 'Mozilla/3.0 (Win95; I)' http://www.nationsbank.com/

alias命令

功能说明: 设置指令的别名。

语 法: alias[别名]=[指令名称]

参 数: 若不加任何参数,则列出目前所有的别名设置。

举 例:

1
2
3
4
5
6
7
8
alias
alias egrep='egrep --color=auto'
alias fgrep='fgrep --color=auto'
alias grep='grep --color=auto'
alias l='ls -CF'
alias la='ls -A'
alias ll='ls -alF'
alias ls='ls --color=auto'

说 明:用户可利用alias,自定指令的别名。若仅输入alias,则可列出目前所有的别名设置。 alias的效力仅及于该次登入的操作。若要每次登入是即自动设好别名,可在/etc/profile或自己的~/.bashrc中设定指令的别名。

如果你想给每一位用户都生效的别名,请把alias la=‘ls -al’ 一行加在/etc/bashrc最后面,bashrc是环境变量的配置文件 /etc/bashrc和~/.bashrc 区别就在于一个是设置给全系统一个是设置给单用户使用.

tcp连接建立过程

一、server

1. 接收syn
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
tcp_v4_do_rcv {
	nsk = tcp_v4_hnd_req(sk, skb);

	nsk == sk


	tcp_rcv_state_process {
		icsk->icsk_af_ops->conn_request(sk, skb)
		tcp_v4_conn_request {
			__tcp_v4_send_synack {

				2. 发送syn/ack
			}
		}
	}
}
2. 接收ack
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
tcp_v4_do_rcv {
	nsk = tcp_v4_hnd_req(sk, skb) {
		req = inet_csk_search_req
		nsk = tcp_check_req {
			tcp_v4_syn_recv_sock {
				tcp_create_openreq_child {
					inet_csk_clone {

						newsk->sk_state = TCP_SYN_RECV;

					}
				}
			}
		}
	}

	nsk != sk {
		tcp_child_process {
			tcp_rcv_state_process {

				if (!tcp_validate_incoming(sk, skb, th, 0))
					return 0;

				/* step 5: check the ACK field */
				if (th->ack) {
					int acceptable = tcp_ack(sk, skb, FLAG_SLOWPATH) > 0;

					switch (sk->sk_state) {
						case TCP_SYN_RECV:

						tcp_set_state(sk, TCP_ESTABLISHED);

					}

					case TCP_ESTABLISHED:
						tcp_data_queue(sk, skb);
						queued = 1;
						break;
					}
				}

			}
		}
	}
}

二、client

1. 发送syn
1
2
3
4
5
6
7
8
9
10
tcp_v4_connect {

	tcp_set_state(sk, TCP_SYN_SENT);

	tcp_connect {
		__tcp_add_write_queue_tail
		tcp_transmit_skb
		inet_csk_reset_xmit_timer
	}
}
2. 接收syn/ack
1
2
3
4
5
6
7
8
9
10
11
12
tcp_v4_do_rcv {
	sk->sk_state == TCP_SYN_SENT

	tcp_rcv_state_process {
		queued = tcp_rcv_synsent_state_process(sk, skb, th, len) {

			tcp_set_state(sk, TCP_ESTABLISHED);

			tcp_send_ack(sk); // 发送ack
		}
	}
}