kk Blog —— 通用基础


date [-d @int|str] [+%s|"+%F %T"]
netstat -ltunp
sar -n DEV 1

git-svn

常用

1
2
3
4
1、git-svn clone your_svn_repository
2、git add/commit
3、git-svn rebase    获取中心svn repository的更新;
4、git-svn dcommit   将本地git库的修改同步到中心svn库。

git-svn默认包含在Git的安装包中,不过在Ubuntu中,git-svn是作为一个独立的Package需要额外安装的(sudo apt-get install git-svn)。安装后你就可以使用git svn xxx命令来操作中心SVN代码库了。当然如果你要使用与git svn等价的git-svn命令的话,你还需要将/usr/lib/git-core配置到你的PATH环境变量中,否则Shell会提示你无法找到 git-svn这个命令。

  • 检出一个已存在svn repository(类似于svn checkout)
    我们可以通过git-svn clone命令完成这个操作: git-svn clone your_svn_repository_url

  • 从中心服务器的svn repository获取最新更新
    这个操作可以通过"git-svn rebase"完成。注意这里用的是rebase,而不是update。update命令对于通过git-svn检出的svn repostory的git版本库是不可用的。

  • 查看提交历史日志
    这个简单,使用"git-svn log",加上-v选项,还可以提供每次commit操作涉及的相关文件的详细信息。

  • 将本地代码同步到Svn服务器
    完成这一操作需要通过"git-svn dcommit"命令。这个命令会将你在本地使用git commit提交到本地代码库的所有更改逐一提交到svn库中。加上-n选项,则该命令不会真正执行commit到svn的操作,而是会显示会有哪些本地 变动将被commit到svn服务器。git-svn dcommit似乎不能单独提交某个本地版本的修改,而是一次批量提交所有与svn中心版本库的差异。

下面是一个git-svn的一般使用流程:

1、git-svn clone your_svn_repository;
2、修改本地代码,使用git add/commit将修改提交到本地git库;
3、定期使用git-svn rebase获取中心svn repository的更新;
4、使用git-svn dcommit命令将本地git库的修改同步到中心svn库。

冲突

使用git-svn处理代码冲突的步骤有些繁琐,不过瑕不掩瑜吧。这里用一个小例子来说明一下。

假设某svn中心库上的某个项目foo中只有一个源码文件foo.c:
* 我在使用git-svn clone检出版本时,foo.c当时只有一个commit版本信息:"svn v1";
* clone出来后,我在本地git库中修改foo.c,并通过git commit提交到本地git库中,版本为"git v1";
* 不过与此同时另外一个同事也在修改foo.c这个文件,并已经将他的修改提交到了svn库中,版本为"svn v2";
* 此时我使用git-svn dcommit尝试提交我的改动,git-svn提示我:
Committing to svn://10.10.1.1:80/foo …
M foo.c
事务过时: 过期: ”foo/foo.c“在事务“260-1” at /usr/lib/git-core/git-svn line 570
* 使用git-svn rebase获取svn服务器上的最新foo.c,导致与foo.c冲突,不过此时svn版本信息已经添加到本地git库中(通过git log可以查看),git-svn rebase提示你在解决foo.c的冲突后,运行git rebase –continue完成rebase操作;
* 打开foo.c,修改代码,解决冲突;
* 执行git rebase –continue,git提示我:
You must edit all merge conflicts and then
mark them as resolved using git add
* 执行git add foo.c,告知git已完成冲突解决;
* 再次执行git rebase –continue,提示"Applying: git v1",此时"git v1"版本又一次成功加入本地版本库,你可通过git log查看;
* 执行git-svn dcommit将foo.c的改动同步到svn中心库,到此算是完成一次冲突解决。

  • 设置忽略文件
    要忽略某些文件, 需要首先执行如下命令:
    git config –global core.excludesfile ~/.gitignore
    然后编辑 vi ~/.gitignore.
    例如: 需要忽略vim的临时文件,就写:
    .*.swp

解析pcap数据包格式(code)

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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
#include <stdio.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <linux/types.h>

typedef unsigned int  bpf_u_int32;
typedef unsigned short  u_short;
typedef int bpf_int32;
typedef struct pcap_file_header {
	bpf_u_int32 magic;
	u_short version_major;
	u_short version_minor;
	bpf_int32 thiszone;
	bpf_u_int32 sigfigs;   
	bpf_u_int32 snaplen;   
	bpf_u_int32 linktype;  
}pcap_file_header;
 
typedef struct  timestamp{
	bpf_u_int32 timestamp_s;
	bpf_u_int32 timestamp_ms;
}timestamp;
 
typedef struct pcap_header{
	timestamp ts;
	bpf_u_int32 capture_len;
	bpf_u_int32 len;
 
}pcap_header;


#define ETH_ALEN 6
#define __LITTLE_ENDIAN_BITFIELD 1
#define NIPQUAD(addr) \
		((unsigned char *)&addr)[0], \
		((unsigned char *)&addr)[1], \
		((unsigned char *)&addr)[2], \
		((unsigned char *)&addr)[3]


struct ethhdr {
	unsigned char h_dest[ETH_ALEN];       /* destination eth addr */
	unsigned char h_source[ETH_ALEN];     /* source ether addr    */
	unsigned short    h_proto;                /* packet type ID field */
};

struct iphdr {
#if defined(__LITTLE_ENDIAN_BITFIELD)
	__u8  ihl:4,
			version:4;
#elif defined (__BIG_ENDIAN_BITFIELD)
	__u8  version:4,
			ihl:4;
#endif
	__u8    tos;
	__be16  tot_len;
	__be16  id;
	__be16  frag_off;
	__u8    ttl;
	__u8    protocol;
	__u16   check;
	__be32  saddr;
	__be32  daddr;
	/*The options start here. */
};

struct tcphdr {
	__u16   source;
	__u16   dest;
	__u32   seq;
	__u32   ack_seq;
#if defined(__LITTLE_ENDIAN_BITFIELD)
	__u16   res1:4,
			doff:4,
			fin:1,
			syn:1,
			rst:1,
			psh:1,
			ack:1,
			urg:1,
			ece:1,
			cwr:1;
#elif defined(__BIG_ENDIAN_BITFIELD)
	__u16   doff:4,
			res1:4,
			cwr:1,
			ece:1,
			urg:1,
			ack:1,
			psh:1,
			rst:1,
			syn:1,
			fin:1;
#endif  
	__u16   window;
	__u16   check;
	__u16   urg_ptr;
};

struct udphdr {
	__u16   source;
	__u16   dest;
	__u16   len;
	__u16   check;
};

struct icmphdr {
	__u8  type;
	__u8  code;
	__u16 checksum;
	union {
		struct {
			__u16   id;
			__u16   sequence;
		} echo;
		__u32   gateway;
		struct {
			__u16   __unused;
			__u16   mtu;
		} frag;
	} un;
};

FILE *fp1, *fp2;
__u32 flag1, flag2, seq1, seq2, ip1, ip2;
long long stime;

void printPcap(int count, void * data, struct pcap_header *ph)
{
	size_t size = ph->capture_len;
	unsigned  short iPos = 0;
	struct ethhdr *eth;
	struct iphdr *iph;
	struct tcphdr *tcph;
	struct udphdr *udph;
	struct icmphdr *icmph;
	__u8 op1, op2, type, len;
	void * data1;
	int i;
	long long dt;

	if (data==NULL) {
		return;
	}
	eth = (struct ethhdr*)(data);
	eth->h_proto = ntohs(eth->h_proto);
	//printf("Ether:\tproto = 0x%x\n", eth->h_proto);
	if (eth->h_proto == 0x0800) { // IP
		iph = (struct iphdr*)(data+sizeof(struct ethhdr));
		if (iph->protocol == IPPROTO_TCP) { // tcp
			tcph = (struct tcphdr*)(data+sizeof(struct ethhdr)+sizeof(struct iphdr));
			if (tcph->ack == 0 && tcph->syn == 1) {
				seq1 = ntohl(tcph->seq);
				ip1 = iph->saddr;
				flag1 = 1;
				stime = 1000000LL*ph->ts.timestamp_s + ph->ts.timestamp_ms;
			} else if (tcph->ack == 1 && tcph->syn == 1) {
				seq2 = ntohl(tcph->seq);
				ip2 = iph->saddr;
				flag2 = 1;
			}

			if (flag1 == 0) {
				flag1 = 1;
				seq1 = ntohl(tcph->seq)-1;
				ip1 = iph->saddr;
				stime = 1000000LL*ph->ts.timestamp_s + ph->ts.timestamp_ms;
			}
			if (flag2 == 0 && iph->saddr != ip1) {
				flag2 = 1;
				seq2 = ntohl(tcph->seq)-1;
				ip2 = iph->saddr;
			}

			dt = (1000000LL*ph->ts.timestamp_s+ph->ts.timestamp_ms) - stime;
			fprintf(fp1, "%d\t%llu\t", count, dt/1000);
			fprintf(fp1, "%d.%d.%d.%d\t%d.%d.%d.%d\t%u\t%u\t%d\t",
						NIPQUAD(iph->saddr), NIPQUAD(iph->daddr),
						(iph->saddr==ip1?ntohl(tcph->seq)-seq1:ntohl(tcph->seq)-seq2),
						(iph->saddr==ip1?ntohl(tcph->ack_seq)-seq2:ntohl(tcph->ack_seq)-seq1),
						ntohs(iph->tot_len)-iph->ihl*4-tcph->doff*4 + tcph->syn + tcph->fin);
			fprintf(fp1, "%d\t%d\t%d\t%d\t", ntohs(iph->tot_len), iph->ihl*4, tcph->doff*4, iph->ttl);
			fprintf(fp1, "%u\t%u\t%d\t%d\t%d\t",
						ntohl(tcph->seq), ntohl(tcph->ack_seq),
						tcph->ack, tcph->syn, ntohs(tcph->window));

			if (tcph->doff > 5) {
				data1 = data + sizeof(struct ethhdr)+sizeof(struct iphdr)+sizeof(struct tcphdr);
				op1 = *(__u8*)(data1);
				op2 = *(__u8*)(data1+1);
				type = *(__u8*)(data1+2);
				len = *(__u8*)(data1+3);
				//fprintf(fp1, "%u\t%u\t%u\t%u\n", op1, op2, type, len);
				if (op1 == 1 && op2 == 1 && type == 5) { // sack
					i = 4;
					while (i < len+2) {
						if (i > 4) fprintf(fp1, " ");
						fprintf(fp1, "%u-%u", ntohl(*(__u32*)(data1+i))-seq2, ntohl(*(__u32*)(data1+i+4))-seq2);
						i += 8;
					}
				}
			}
			fprintf(fp1, "\n");

		} else if (iph->protocol == IPPROTO_UDP) { // udp
			udph = (struct udphdr*)(data+sizeof(struct ethhdr)+sizeof(struct iphdr));
			//printf("UDP:\tsource=%u\tdest=%u\tlen=%d\n", ntohs(udph->source), ntohs(udph->dest), ntohs(udph->len));
		} else if (iph->protocol == IPPROTO_ICMP) { // ICMP
			icmph = (struct icmphdr*)(data+sizeof(struct ethhdr)+sizeof(struct iphdr));
			//printf("ICMP:\ttype=%u\tcode=%u\n", icmph->type, icmph->code);
		}
	}
}

#define MAX_ETH_FRAME 1514000
int main (int argc, const char * argv[])
{
	pcap_file_header  pfh;
	pcap_header  ph;
	int count=0;
	void * buff = NULL;
	int readSize=0;
	int ret = 0;
 
	 if (argc != 2) {
		 printf("uage: ./a.out pcap_filename\n");
		 return -1;
	 }
	FILE *fp = fopen(argv[1], "r");
	if (fp==NULL) {
		fprintf(stderr, "Open file %s error.", argv[1]);
		return -1;
	}
	fread(&pfh, sizeof(pcap_file_header), 1, fp);
 
	fp1 = fopen("out", "w");
	fprintf(fp1, "#ID\tTIME\tsaddr\tdaddr\tseq\tack_seq\tpayload\ttot_len\tihl\tdoff\tttl\tseq\tack_seq\tack\tsyn\twin\tSACK\n");
	buff = (void *)malloc(MAX_ETH_FRAME);
	flag1 = flag2 = 0;

	for (count=1; ; count++) {
		memset(buff,0,MAX_ETH_FRAME);
		readSize=fread(&ph, sizeof(pcap_header), 1, fp);
		if (readSize<=0) {
			break;
		}
		if (buff==NULL) {
			fprintf(stderr, "malloc memory failed.\n");
			return -1;
		}
 
		readSize=fread(buff,1,ph.capture_len, fp);
		if (readSize != ph.capture_len) {
			free(buff);
			fprintf(stderr, "pcap file parse error.\n");
			return -1;
		}
		printPcap(count, buff, &ph);

		if (feof(fp) || readSize <=0 ) {
			break;
		}
	}
	fclose(fp);
	fclose(fp1);
	return ret;
}

解析pcap数据包格式

协议是一个比较复杂的协议集,有很多专业书籍介绍。在此,我仅介绍其与编程密切相关的部分:以太网上TCP/IP协议的分层结构及其报文格式。
我们知道TCP/IP协议采用分层结构,其分层模型及协议如下表:
应 用 层 (Application) HTTP、Telnet、FTP、SMTP、SNMP
传 输 层 (Transport) TCP、UDP
网 间 网层 (Internet) IP【ARP、RARP、ICMP】
网络接口层 (Network) Ethernet、X.25、SLIP、PPP

协议采用分层结构,因此,数据报文也采用分层封装的方法。下面以应用最广泛的以太网为例说明其数据报文分层封装,如下图所示:

任何通讯协议都有独特的报文格式,TCP/IP协议也不例外。对于通讯协议编程,我们首先要清楚其报文格式。由于TCP/IP协议采用分层模型,各层都有专用的报头,以下就简单介绍以太网下TCP/IP各层报文格式。

8字节的前导用于帧同步,CRC域用于帧校验。这些用户不必关心其由网卡芯片自动添加。目的地址和源地址是指网卡的物理地址,即MAC地址,具有唯一性。帧类型或协议类型是指数据包的高级协议,如 0x0806表示ARP协议,0x0800表示IP协议等。

  ARP/RARP(地址解析/反向地址解析)报文格式如下图:

“硬件类型”域指发送者本机网络接口类型(值“1”代表以太网)。“协议类型”域指发送者所提供/请求的高级协议地址类型(“0x0800”代表 IP协议)。“操作”域指出本报文的类型(“1”为ARP请求,“2”为ARP响应,“3”为RARP请求,“4”为RARP响应)。

  IP数据报头格式如下图:

  我们用单片机实现TCP/IP协议要作一些简化,不考虑数据分片和优先权。因此,在此我们不讨论服务类型和标志偏移域,只需填“0” 即可。协议“版本”为4,“头长度”单位为32Bit,“总长度”以字节为单位,表示整个IP数据报长度。“标识”是数据包的ID号,用于识别不同的IP 数据包。“生存时间” TTL是个数量及的概念,防止无用数据包一直存在网络中。一般每经过路由器时减一,因此通过TTL 可以算出数据包到达目的地所经过的路由器个数。“协议”域表示创建该数据包的高级协议类型。如 1表示ICMP协议,6表示TCP协议,17表示 UDP协议等。IP数据包为简化数据转发时间,仅采用头校验的方法,数据正确性由高层协议保证。

  ICMP(网间网控制报文协议)协议 应用广泛。在此仅给出最常见的回应请求与应答报文格式,用户命令ping便是利用此报文来测试信宿机的可到达性。报文格式如下图所示:

  类型0 为回应应答报文,8 为回应请求报文。整个数据包均参与检验。注意ICMP封装在IP数据包里传送。

  UDP报文格式如下图:

  TCP报文格式如下图:


WireShark捕获的数据

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
46
47
48
		以下为物理层的数据帧概况

Frame 1 (62 bytes on wire, 62 bytes captured)           1号帧,线路62字节,实际捕获62字节
Arrival Time: Jan 21, 2008 15:17:33.910261000           捕获日期和时间
[Time delta from previous packet:0.00000 seconds]       此包与前一包的时间间隔
[Time since reference or first frame: 0.00 seconds]     此包与第1帧的间隔时间
Frame Number: 1                                         帧序号
Packet Length: 62 bytes                                 帧长度
Capture Length: 62 bytes                                捕获长度
[Frame is marked: False]                                此帧是否做了标记:否
[Protocols in frame: eth:ip:tcp]                        帧内封装的协议层次结构
[Coloring Rule Name: HTTP]                              用不同颜色染色标记的协议名称:HTTP
[Coloring Rule String: http || tcp.port == 80]          染色显示规则的字符串:


		以下为数据链路层以太网帧头部信息
Ethernet II, Src: AcerTech_5b:d4:61 (00:00:e2:5b:d4:61), Dst: Jetcell_e5:1d:0a (00:d0:2b:e5:1d:0a)
以太网协议版本II,源地址:厂名_序号(网卡地址),目的:厂名_序号(网卡地址)
 Destination: Jetcell_e5:1d:0a (00:d0:2b:e5:1d:0a)       目的:厂名_序号(网卡地址)
 Source: AcerTech_5b:d4:61 (00:00:e2:5b:d4:61)           源:厂名_序号(网卡地址)
 Type: IP (0x0800)                                       帧内封装的上层协议类型为IP(十六进制码0800)看教材70页图3.2

		以下为互联网层IP包头部信息
Internet Protocol, Src: 202.203.44.225 (202.203.44.225), Dst: 202.203.208.32 (202.203.208.32)
互联网协议,源IP地址,目的IP地址
Version: 4                                                       互联网协议IPv4
Header length: 20 bytes                                          IP包头部长度
Differentiated Services Field:0x00(DSCP 0x00:Default;ECN:0x00)   差分服务字段
Total Length: 48                                                 IP包的总长度
Identification:0x8360 (33632)                                    标志字段
Flags:                                                           标记字段(在路由传输时,是否允许将此IP包分段)
Fragment offset: 0                                               分段偏移量(将一个IP包分段后传输时,本段的标识)
Time to live: 128                                                生存期TTL
Protocol: TCP (0x06)                                             此包内封装的上层协议为TCP
Header checksum: 0xe4ce [correct]                                头部数据的校验和
Source: 202.203.44.225 (202.203.44.225)                          源IP地址
Destination: 202.203.208.32 (202.203.208.32)                     目的IP地址

		以下为传输层TCP数据段头部信息
Transmission Control Protocol, Src Port: 2764 (2764), Dst Port: http (80), Seq: 0, Len: 0   传输控制协议TCP的内容
Source port: 2764 (2764)                              源端口名称(端口号)
Destination port: http (80)                            目的端口名http(端口号80)
Sequence number: 0    (relative sequence number)       序列号(相对序列号)
Header length: 28 bytes                                头部长度
Flags: 0x02 (SYN)                                      TCP标记字段(本字段是SYN,是请求建立TCP连接)
Window size: 65535                                     流量控制的窗口大小
Checksum: 0xf73b [correct]                             TCP数据段的校验和
Options: (8 bytes)                                     可选项