用户态协议栈tapip代码分析-TCP数据流过程与socket API实现

作者

QQ群:852283276
微信:arm80x86
微信公众号:青儿创客基地
B站:主页 https://space.bilibili.com/208826118

TCP传输控制块TCB(Transmission Control Block)

TCP利用TCB保存当前连接的状态,每新建一个连接就需要一个TCB,发送TCP报文相关的变量:

    Send Sequence Variables
	
      SND.UNA - send unacknowledged
      SND.NXT - send next
      SND.WND - send window
      SND.UP  - send urgent pointer
      SND.WL1 - segment sequence number used for last window update
      SND.WL2 - segment acknowledgment number used for last window update
      ISS     - initial send sequence number

接收TCP报文相关的变量:

    Receive Sequence Variables
											  
      RCV.NXT - receive next
      RCV.WND - receive window
      RCV.UP  - receive urgent pointer
      IRS     - initial receive sequence number

tapip的实现在tcp/tcp.h中:

struct tcp_sock {
	struct sock sk;
	struct hlist_node bhash_list;	/* for bind hash table, e/lhash node is in sk */
	unsigned int bhash;		/* bind hash value */
	int accept_backlog;		/* current entries of accept queue */
	int backlog;			/* size of accept queue */
	struct list_head listen_queue;	/* waiting for second SYN+ACK of three-way handshake */
	struct list_head accept_queue;	/* waiting for third ACK of three-way handshake */
	struct list_head list;
	struct tcp_timer timewait;	/* TIME-WAIT TIMEOUT */
	struct tapip_wait *wait_accept;
	struct tapip_wait *wait_connect;
	struct tcp_sock *parent;
	unsigned int flags;
	struct cbuf *rcv_buf;
	struct list_head rcv_reass;	/* list head of unordered reassembled tcp segments */
	/* transmission control block (RFC 793) */
	unsigned int snd_una;	/* send unacknowledged */
	unsigned int snd_nxt;	/* send next */
	unsigned int snd_wnd;	/* send window */
	unsigned int snd_up;	/* send urgent pointer */
	unsigned int snd_wl1;	/* seq for last window update */
	unsigned int snd_wl2;	/* ack for last window update */
	unsigned int iss;	/* initial send sequence number */
	unsigned int rcv_nxt;	/* receive next */
	unsigned int rcv_wnd;	/* receive window */
	unsigned int rcv_up;	/* receive urgent pointer */
	unsigned int irs;	/* initial receive sequence number */
	unsigned int state;	/* connection state */
};

另外还有一些处理当前报文的变量:

    Current Segment Variables
	
      SEG.SEQ - segment sequence number
      SEG.ACK - segment acknowledgment number
      SEG.LEN - segment length
      SEG.WND - segment window
      SEG.UP  - segment urgent pointer
      SEG.PRC - segment precedence value

tapip的实现在tcp/tcp.h中:

/* host-order tcp current segment (RFC 793) */
struct tcp_segment {
	unsigned int seq;	/* segment sequence number */
	unsigned int ack;	/* segment acknowledgment number */
	unsigned int lastseq;	/* segment last sequence number */
	unsigned int len;	/* segment length */
	unsigned int dlen;	/* segment text length */
	unsigned int wnd;	/* segment window */
	unsigned int up;	/* segment urgent point */
	unsigned int prc;	/* segment precedence value(no used) */
	unsigned char *text;		/* segment text */
	struct ip *iphdr;
	struct tcp *tcphdr;
};

TCP通信流程

当一个连接建立,数据流的处理就开始了,TCB中的三个重要变量用于追踪状态:

  • SND.NXT 这是发送将要使用的Sequence Number
  • RCV.NXT 这是接收期望接收的下一个Sequence Number
  • SND.UNA 这是发送者记录最老的没有ACK的Sequence Number

如果经过很长一段时间,没有传输发生,这三个变量最终会相等,例如TCP A发送一个segment然后增加SND.NXT,TCP B接收报文确认Sequence Number然后发送ACK,TCP A接收ACK,增加SND.UNA。三个变量增加的数量取决于报文中的数据长度,linux上用tcpdump命令来监控TCP的数据流程,参考tcpdump参数解析及使用详解
tapip TOP1的TCP/UDP通信会有checksum错误。tapip TOP2,打开tty1,

zc@ubuntu:~/xilinx/app/tapip-master$ sudo ./tapip 
[42979]loop_dev_init lo ip address: 127.0.0.1
[42979]loop_dev_init lo netmask:    255.0.0.0
[42979]getname_tap net device: tap0
[42979]getmtu_tap mtu: 1500
[42979]gethwaddr_tap mac addr: ba:f2:bd:65:51:3a
[42979]setipaddr_tap set IPaddr: 10.0.0.2
[42979]getipaddr_tap get IPaddr: 10.0.0.2
[42979]setnetmask_tap set Netmask: 255.255.255.0
[42979]setup_tap ifup tap0
[42979]veth_dev_init veth ip address: 10.0.0.1
[42979]veth_dev_init veth hw address: 00:34:45:67:89:ab
[42979]arp_cache_init ARP CACHE INIT
[42979]arp_cache_init ARP CACHE SEMAPHORE INIT
[42979]rt_init route table init
[42979]raw_init raw ip init
[42979]net_stack_run thread 0: net_timer
[42979]net_stack_run thread 1: tcp_timer
[42979]net_stack_run thread 2: netdev_interrupt
[42979]net_stack_run thread 3: shell worker
[net shell]: snc -b 10.0.0.1:12345
#### User configure  ###############
CONFIG_DEBUG = n
CONFIG_DEBUG_PKB = n
CONFIG_DEBUG_WAIT = n
CONFIG_DEBUG_SOCK = n
CONFIG_DEBUG_ARP_LOCK = n
CONFIG_DEBUG_ICMPEXCFRAGTIME = n
CONFIG_TOPLOGY = 2
#### End of User configure #########

# Use 'make V=1' to see the full commands
ifeq ("$(origin V)", "command line")
	Q =
else
	Q = @
endif
export Q

MAKEFLAGS += --no-print-directory

LD = ld
CC = gcc
CFLAGS = -Wall -I../include
LFLAGS = -pthread
export LD CC CFLAGS

ifeq ($(CONFIG_DEBUG), y)
	CFLAGS += -g
endif

ifeq ($(CONFIG_DEBUG), y)
	CFLAGS += -DDEBUG_PKB
endif

ifeq ($(CONFIG_DEBUG_SOCK), y)
	CFLAGS += -DSOCK_DEBUG
endif

ifeq ($(CONFIG_DEBUG_ICMPEXCFRAGTIME), y)
	CFLAGS += -DICMP_EXC_FRAGTIME_TEST
endif

ifeq ($(CONFIG_DEBUG_WAIT), y)
	CFLAGS += -DWAIT_DEBUG
endif

ifeq ($(CONFIG_DEBUG_ARP_LOCK), y)
	CFLAGS += -DDEBUG_ARPCACHE_LOCK
endif

ifeq ($(CONFIG_TOPLOGY), 1)
	CFLAGS += -DCONFIG_TOP1
else
	CFLAGS += -DCONFIG_TOP2
endif

NET_STACK_OBJS =	shell/shell_obj.o	\
			net/net_obj.o		\
			arp/arp_obj.o		\
			ip/ip_obj.o		\
			socket/socket_obj.o	\
			udp/udp_obj.o		\
			tcp/tcp_obj.o		\
			app/app_obj.o		\
			lib/lib_obj.o

all:tapip
tapip:$(NET_STACK_OBJS)
	@echo " [BUILD] $@"
	$(Q)$(CC) $(LFLAGS) $^ -o $@

shell/shell_obj.o:shell/*.c
	@make -C shell/
net/net_obj.o:net/*.c
	@make -C net/
arp/arp_obj.o:arp/*.c
	@make -C arp/
ip/ip_obj.o:ip/*.c
	@make -C ip/
udp/udp_obj.o:udp/*.c
	@make -C udp/
tcp/tcp_obj.o:tcp/*.c
	@make -C tcp/
lib/lib_obj.o:lib/*.c
	@make -C lib/
socket/socket_obj.o:socket/*.c
	@make -C socket/
app/app_obj.o:app/*.c
	@make -C app/

test:cbuf
# test program for circul buffer
cbuf:lib/cbuf.c lib/lib.c
	@echo " [CC] $@"
	$(Q)$(CC) -DCBUF_TEST -Iinclude/ $^ -o $@

tag:
	ctags -R *

clean:
	find . -name *.o | xargs rm -f
	rm -f tapip cbuf

lines:
	@echo "code lines:"
	@wc -l `find . -name \*.[ch]` | sort -n

[net shell]: 

打开tty2,

cat Makefile | nc 10.0.0.1 12345

打开tty3,tcpdump抓包,S为SYN,S.为SYN和ACK,前三个包为three way握手过程,其中seq和ack为1,表示的是相对位置,方便理解(Relative sequence numbers are shown by default with tcpdump to ease readability),之后开始数据传输。注意:seq = ack + data_length。

zc@ubuntu:~$ sudo tcpdump -i tap0 tcp -vvv -XX
[sudo] password for zc: 
tcpdump: listening on tap0, link-type EN10MB (Ethernet), capture size 262144 bytes
01:59:30.676806 IP (tos 0x0, ttl 64, id 58146, offset 0, flags [DF], proto TCP (6), length 60)
    bogon.36292 > bogon.12345: Flags [S], cksum 0xbee9 (correct), seq 1403716138, win 29200, options [mss 1460,sackOK,TS val 885176942 ecr 0,nop,wscale 7], length 0
	0x0000:  0034 4567 89ab baf2 bd65 513a 0800 4500  .4Eg.....eQ:..E.
	0x0010:  003c e322 4000 4006 4397 0a00 0002 0a00  .<."@.@.C.......
	0x0020:  0001 8dc4 3039 53ab 022a 0000 0000 a002  ....09S..*......
	0x0030:  7210 bee9 0000 0204 05b4 0402 080a 34c2  r.............4.
	0x0040:  ba6e 0000 0000 0103 0307                 .n........
01:59:30.677062 IP (tos 0x0, ttl 64, id 7, offset 0, flags [none], proto TCP (6), length 40)
    bogon.12345 > bogon.36292: Flags [S.], cksum 0x15ee (correct), seq 12345682, ack 1403716139, win 4096, length 0
	0x0000:  baf2 bd65 513a 0034 4567 89ab 0800 4500  ...eQ:.4Eg....E.
	0x0010:  0028 0007 0000 4006 66c7 0a00 0001 0a00  .(....@.f.......
	0x0020:  0002 3039 8dc4 00bc 6152 53ab 022b 5012  ..09....aRS..+P.
	0x0030:  1000 15ee 0000                           ......
01:59:30.678226 IP (tos 0x0, ttl 64, id 58147, offset 0, flags [DF], proto TCP (6), length 40)
    bogon.36292 > bogon.12345: Flags [.], cksum 0xb3de (correct), seq 1, ack 1, win 29200, length 0
	0x0000:  0034 4567 89ab baf2 bd65 513a 0800 4500  .4Eg.....eQ:..E.
	0x0010:  0028 e323 4000 4006 43aa 0a00 0002 0a00  .(.#@.@.C.......
	0x0020:  0001 8dc4 3039 53ab 022b 00bc 6153 5010  ....09S..+..aSP.
	0x0030:  7210 b3de 0000                           r.....
01:59:30.678426 IP (tos 0x0, ttl 64, id 58148, offset 0, flags [DF], proto TCP (6), length 576)
    bogon.36292 > bogon.12345: Flags [.], cksum 0x8905 (correct), seq 1:537, ack 1, win 29200, length 536
	0x0000:  0034 4567 89ab baf2 bd65 513a 0800 4500  .4Eg.....eQ:..E.
	0x0010:  0240 e324 4000 4006 4191 0a00 0002 0a00  .@.$@.@.A.......
	0x0020:  0001 8dc4 3039 53ab 022b 00bc 6153 5010  ....09S..+..aSP.
	0x0030:  7210 8905 0000 2323 2323 2055 7365 7220  r.....####.User.
	0x0040:  636f 6e66 6967 7572 6520 2023 2323 2323  configure..#####
	0x0050:  2323 2323 2323 2323 2323 0a43 4f4e 4649  ##########.CONFI
	0x0060:  475f 4445 4255 4720 3d20 6e0a 434f 4e46  G_DEBUG.=.n.CONF
	0x0070:  4947 5f44 4542 5547 5f50 4b42 203d 206e  IG_DEBUG_PKB.=.n
	0x0080:  0a43 4f4e 4649 475f 4445 4255 475f 5741  .CONFIG_DEBUG_WA
	0x0090:  4954 203d 206e 0a43 4f4e 4649 475f 4445  IT.=.n.CONFIG_DE
	0x00a0:  4255 475f 534f 434b 203d 206e 0a43 4f4e  BUG_SOCK.=.n.CON
	0x00b0:  4649 475f 4445 4255 475f 4152 505f 4c4f  FIG_DEBUG_ARP_LO
	0x00c0:  434b 203d 206e 0a43 4f4e 4649 475f 4445  CK.=.n.CONFIG_DE
	0x00d0:  4255 475f 4943 4d50 4558 4346 5241 4754  BUG_ICMPEXCFRAGT
	0x00e0:  494d 4520 3d20 6e0a 434f 4e46 4947 5f54  IME.=.n.CONFIG_T
	0x00f0:  4f50 4c4f 4759 203d 2032 0a23 2323 2320  OPLOGY.=.2.####.
	0x0100:  456e 6420 6f66 2055 7365 7220 636f 6e66  End.of.User.conf
	0x0110:  6967 7572 6520 2323 2323 2323 2323 230a  igure.#########.
	0x0120:  0a23 2055 7365 2027 6d61 6b65 2056 3d31  .#.Use.'make.V=1
	0x0130:  2720 746f 2073 6565 2074 6865 2066 756c  '.to.see.the.ful
	0x0140:  6c20 636f 6d6d 616e 6473 0a69 6665 7120  l.commands.ifeq.
	0x0150:  2822 2428 6f72 6967 696e 2056 2922 2c20  ("$(origin.V)",.
	0x0160:  2263 6f6d 6d61 6e64 206c 696e 6522 290a  "command.line").
	0x0170:  0951 203d 0a65 6c73 650a 0951 203d 2040  .Q.=.else..Q.=.@
	0x0180:  0a65 6e64 6966 0a65 7870 6f72 7420 510a  .endif.export.Q.
	0x0190:  0a4d 414b 4546 4c41 4753 202b 3d20 2d2d  .MAKEFLAGS.+=.--
	0x01a0:  6e6f 2d70 7269 6e74 2d64 6972 6563 746f  no-print-directo
	0x01b0:  7279 0a0a 4c44 203d 206c 640a 4343 203d  ry..LD.=.ld.CC.=
	0x01c0:  2067 6363 0a43 464c 4147 5320 3d20 2d57  .gcc.CFLAGS.=.-W
	0x01d0:  616c 6c20 2d49 2e2e 2f69 6e63 6c75 6465  all.-I../include
	0x01e0:  0a4c 464c 4147 5320 3d20 2d70 7468 7265  .LFLAGS.=.-pthre
	0x01f0:  6164 0a65 7870 6f72 7420 4c44 2043 4320  ad.export.LD.CC.
	0x0200:  4346 4c41 4753 0a0a 6966 6571 2028 2428  CFLAGS..ifeq.($(
	0x0210:  434f 4e46 4947 5f44 4542 5547 292c 2079  CONFIG_DEBUG),.y
	0x0220:  290a 0943 464c 4147 5320 2b3d 202d 670a  )..CFLAGS.+=.-g.
	0x0230:  656e 6469 660a 0a69 6665 7120 2824 2843  endif..ifeq.($(C
	0x0240:  4f4e 4649 475f 4445 4255 4729 2c20       ONFIG_DEBUG),.
01:59:30.678432 IP (tos 0x0, ttl 64, id 58149, offset 0, flags [DF], proto TCP (6), length 576)
    bogon.36292 > bogon.12345: Flags [.], cksum 0xa3c4 (correct), seq 537:1073, ack 1, win 29200, length 536
	0x0000:  0034 4567 89ab baf2 bd65 513a 0800 4500  .4Eg.....eQ:..E.
	0x0010:  0240 e325 4000 4006 4190 0a00 0002 0a00  .@.%@.@.A.......
	0x0020:  0001 8dc4 3039 53ab 0443 00bc 6153 5010  ....09S..C..aSP.
	0x0030:  7210 a3c4 0000 7929 0a09 4346 4c41 4753  r.....y)..CFLAGS
	0x0040:  202b 3d20 2d44 4445 4255 475f 504b 420a  .+=.-DDEBUG_PKB.
	0x0050:  656e 6469 660a 0a69 6665 7120 2824 2843  endif..ifeq.($(C
	0x0060:  4f4e 4649 475f 4445 4255 475f 534f 434b  ONFIG_DEBUG_SOCK
	0x0070:  292c 2079 290a 0943 464c 4147 5320 2b3d  ),.y)..CFLAGS.+=
	0x0080:  202d 4453 4f43 4b5f 4445 4255 470a 656e  .-DSOCK_DEBUG.en
	0x0090:  6469 660a 0a69 6665 7120 2824 2843 4f4e  dif..ifeq.($(CON
	0x00a0:  4649 475f 4445 4255 475f 4943 4d50 4558  FIG_DEBUG_ICMPEX
	0x00b0:  4346 5241 4754 494d 4529 2c20 7929 0a09  CFRAGTIME),.y)..
	0x00c0:  4346 4c41 4753 202b 3d20 2d44 4943 4d50  CFLAGS.+=.-DICMP
	0x00d0:  5f45 5843 5f46 5241 4754 494d 455f 5445  _EXC_FRAGTIME_TE
	0x00e0:  5354 0a65 6e64 6966 0a0a 6966 6571 2028  ST.endif..ifeq.(
	0x00f0:  2428 434f 4e46 4947 5f44 4542 5547 5f57  $(CONFIG_DEBUG_W
	0x0100:  4149 5429 2c20 7929 0a09 4346 4c41 4753  AIT),.y)..CFLAGS
	0x0110:  202b 3d20 2d44 5741 4954 5f44 4542 5547  .+=.-DWAIT_DEBUG
	0x0120:  0a65 6e64 6966 0a0a 6966 6571 2028 2428  .endif..ifeq.($(
	0x0130:  434f 4e46 4947 5f44 4542 5547 5f41 5250  CONFIG_DEBUG_ARP
	0x0140:  5f4c 4f43 4b29 2c20 7929 0a09 4346 4c41  _LOCK),.y)..CFLA
	0x0150:  4753 202b 3d20 2d44 4445 4255 475f 4152  GS.+=.-DDEBUG_AR
	0x0160:  5043 4143 4845 5f4c 4f43 4b0a 656e 6469  PCACHE_LOCK.endi
	0x0170:  660a 0a69 6665 7120 2824 2843 4f4e 4649  f..ifeq.($(CONFI
	0x0180:  475f 544f 504c 4f47 5929 2c20 3129 0a09  G_TOPLOGY),.1)..
	0x0190:  4346 4c41 4753 202b 3d20 2d44 434f 4e46  CFLAGS.+=.-DCONF
	0x01a0:  4947 5f54 4f50 310a 656c 7365 0a09 4346  IG_TOP1.else..CF
	0x01b0:  4c41 4753 202b 3d20 2d44 434f 4e46 4947  LAGS.+=.-DCONFIG
	0x01c0:  5f54 4f50 320a 656e 6469 660a 0a4e 4554  _TOP2.endif..NET
	0x01d0:  5f53 5441 434b 5f4f 424a 5320 3d09 7368  _STACK_OBJS.=.sh
	0x01e0:  656c 6c2f 7368 656c 6c5f 6f62 6a2e 6f09  ell/shell_obj.o.
	0x01f0:  5c0a 0909 096e 6574 2f6e 6574 5f6f 626a  \....net/net_obj
	0x0200:  2e6f 0909 5c0a 0909 0961 7270 2f61 7270  .o..\....arp/arp
	0x0210:  5f6f 626a 2e6f 0909 5c0a 0909 0969 702f  _obj.o..\....ip/
	0x0220:  6970 5f6f 626a 2e6f 0909 5c0a 0909 0973  ip_obj.o..\....s
	0x0230:  6f63 6b65 742f 736f 636b 6574 5f6f 626a  ocket/socket_obj
	0x0240:  2e6f 095c 0a09 0909 7564 702f 7564       .o.\....udp/ud
01:59:30.678434 IP (tos 0x0, ttl 64, id 58150, offset 0, flags [DF], proto TCP (6), length 576)
    bogon.36292 > bogon.12345: Flags [.], cksum 0x19a9 (correct), seq 1073:1609, ack 1, win 29200, length 536
	0x0000:  0034 4567 89ab baf2 bd65 513a 0800 4500  .4Eg.....eQ:..E.
	0x0010:  0240 e326 4000 4006 418f 0a00 0002 0a00  .@.&@.@.A.......
	0x0020:  0001 8dc4 3039 53ab 065b 00bc 6153 5010  ....09S..[..aSP.
	0x0030:  7210 19a9 0000 705f 6f62 6a2e 6f09 095c  r.....p_obj.o..\
	0x0040:  0a09 0909 7463 702f 7463 705f 6f62 6a2e  ....tcp/tcp_obj.
	0x0050:  6f09 095c 0a09 0909 6170 702f 6170 705f  o..\....app/app_
	0x0060:  6f62 6a2e 6f09 095c 0a09 0909 6c69 622f  obj.o..\....lib/
	0x0070:  6c69 625f 6f62 6a2e 6f0a 0a61 6c6c 3a74  lib_obj.o..all:t
	0x0080:  6170 6970 0a74 6170 6970 3a24 284e 4554  apip.tapip:$(NET
	0x0090:  5f53 5441 434b 5f4f 424a 5329 0a09 4065  _STACK_OBJS)..@e
	0x00a0:  6368 6f20 2220 5b42 5549 4c44 5d20 2440  cho.".[BUILD].$@
	0x00b0:  220a 0924 2851 2924 2843 4329 2024 284c  "..$(Q)$(CC).$(L
	0x00c0:  464c 4147 5329 2024 5e20 2d6f 2024 400a  FLAGS).$^.-o.$@.
	0x00d0:  0a73 6865 6c6c 2f73 6865 6c6c 5f6f 626a  .shell/shell_obj
	0x00e0:  2e6f 3a73 6865 6c6c 2f2a 2e63 0a09 406d  .o:shell/*.c..@m
	0x00f0:  616b 6520 2d43 2073 6865 6c6c 2f0a 6e65  ake.-C.shell/.ne
	0x0100:  742f 6e65 745f 6f62 6a2e 6f3a 6e65 742f  t/net_obj.o:net/
	0x0110:  2a2e 630a 0940 6d61 6b65 202d 4320 6e65  *.c..@make.-C.ne
	0x0120:  742f 0a61 7270 2f61 7270 5f6f 626a 2e6f  t/.arp/arp_obj.o
	0x0130:  3a61 7270 2f2a 2e63 0a09 406d 616b 6520  :arp/*.c..@make.
	0x0140:  2d43 2061 7270 2f0a 6970 2f69 705f 6f62  -C.arp/.ip/ip_ob
	0x0150:  6a2e 6f3a 6970 2f2a 2e63 0a09 406d 616b  j.o:ip/*.c..@mak
	0x0160:  6520 2d43 2069 702f 0a75 6470 2f75 6470  e.-C.ip/.udp/udp
	0x0170:  5f6f 626a 2e6f 3a75 6470 2f2a 2e63 0a09  _obj.o:udp/*.c..
	0x0180:  406d 616b 6520 2d43 2075 6470 2f0a 7463  @make.-C.udp/.tc
	0x0190:  702f 7463 705f 6f62 6a2e 6f3a 7463 702f  p/tcp_obj.o:tcp/
	0x01a0:  2a2e 630a 0940 6d61 6b65 202d 4320 7463  *.c..@make.-C.tc
	0x01b0:  702f 0a6c 6962 2f6c 6962 5f6f 626a 2e6f  p/.lib/lib_obj.o
	0x01c0:  3a6c 6962 2f2a 2e63 0a09 406d 616b 6520  :lib/*.c..@make.
	0x01d0:  2d43 206c 6962 2f0a 736f 636b 6574 2f73  -C.lib/.socket/s
	0x01e0:  6f63 6b65 745f 6f62 6a2e 6f3a 736f 636b  ocket_obj.o:sock
	0x01f0:  6574 2f2a 2e63 0a09 406d 616b 6520 2d43  et/*.c..@make.-C
	0x0200:  2073 6f63 6b65 742f 0a61 7070 2f61 7070  .socket/.app/app
	0x0210:  5f6f 626a 2e6f 3a61 7070 2f2a 2e63 0a09  _obj.o:app/*.c..
	0x0220:  406d 616b 6520 2d43 2061 7070 2f0a 0a74  @make.-C.app/..t
	0x0230:  6573 743a 6362 7566 0a23 2074 6573 7420  est:cbuf.#.test.
	0x0240:  7072 6f67 7261 6d20 666f 7220 6369       program.for.ci
01:59:30.678463 IP (tos 0x0, ttl 64, id 7, offset 0, flags [none], proto TCP (6), length 40)
    bogon.12345 > bogon.36292: Flags [.], cksum 0x15ef (correct), seq 1, ack 537, win 3560, length 0
	0x0000:  baf2 bd65 513a 0034 4567 89ab 0800 4500  ...eQ:.4Eg....E.
	0x0010:  0028 0007 0000 4006 66c7 0a00 0001 0a00  .(....@.f.......
	0x0020:  0002 3039 8dc4 00bc 6153 53ab 0443 5010  ..09....aSS..CP.
	0x0030:  0de8 15ef 0000                           ......

TCP通信关闭

关闭TCP连接可以通过RST报文强制关闭或FIN报文协商,一般是FIN报文。
主动关闭连接的一方发送FIN报文,另一方回复ACK报文,然后完成自己的关闭操作,即发送FIN报文,等待ACK,这样双方互发FIN报文和收到ACK,连接关闭。显然,关闭一个连接需要4个报文,而建立连接只要3个。
另外,TCP是一个双向协议,如果一方断开连接,而另一方还处于等待接收状态,这时称之为半关闭状态。由于网络通信会经过很多交换节点,如果在FIN报文协商的过程中,报文丢失,这可能会导致TCP连接处被挂起,在linux的实现中,有一个定时器,如果FIN报文协商超时,则强制关闭连接,虽然不符合协议要求,但是可以避免DoS攻击。
用RST报文来断开连接适用于如下场景,连接到一个不存在的端口或接口,一方的TCP状态机崩溃,且不可恢复,导致现在连接无法开始,所以,只要TCP数据传输不出错,就不会用到RST报文。
前面的报文里面没有FIN报文,为什么呢,首先看看TCP连接关闭时不发FIN包的奇怪行为分析,但是会发RST包,来看看调用,

zc@ubuntu:~/xilinx/app/tapip-master$ strace cat Makefile | nc 10.0.0.1 12345
execve("/bin/cat", ["cat", "Makefile"], [/* 63 vars */]) = 0
brk(NULL)                               = 0x137c000
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=108742, ...}) = 0
mmap(NULL, 108742, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fe48afff000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0P\t\2\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=1868984, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fe48affe000
mmap(NULL, 3971488, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fe48aa2b000
mprotect(0x7fe48abeb000, 2097152, PROT_NONE) = 0
mmap(0x7fe48adeb000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1c0000) = 0x7fe48adeb000
mmap(0x7fe48adf1000, 14752, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fe48adf1000
close(3)                                = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fe48affd000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fe48affc000
arch_prctl(ARCH_SET_FS, 0x7fe48affd700) = 0
mprotect(0x7fe48adeb000, 16384, PROT_READ) = 0
mprotect(0x60b000, 4096, PROT_READ)     = 0
mprotect(0x7fe48b01a000, 4096, PROT_READ) = 0
munmap(0x7fe48afff000, 108742)          = 0
brk(NULL)                               = 0x137c000
brk(0x139d000)                          = 0x139d000
open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=2981280, ...}) = 0
mmap(NULL, 2981280, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fe48a753000
close(3)                                = 0
fstat(1, {st_mode=S_IFIFO|0600, st_size=0, ...}) = 0
open("Makefile", O_RDONLY)              = 3
fstat(3, {st_mode=S_IFREG|0666, st_size=1854, ...}) = 0
fadvise64(3, 0, 0, POSIX_FADV_SEQUENTIAL) = 0
mmap(NULL, 139264, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fe48afda000
read(3, "#### User configure  ###########"..., 131072) = 1854
write(1, "#### User configure  ###########"..., 1854) = 1854
read(3, "", 131072)                     = 0
munmap(0x7fe48afda000, 139264)          = 0
close(3)                                = 0
close(1)                                = 0
close(2)                                = 0
exit_group(0)                           = ?
+++ exited with 0 +++

socket API

BSD Socket API是最著名的Socket API,源自于1983年4.2BSD UNIX,Linux Socket API兼容BSD Socket API。
tapip的socket API设计,

Linux socket model
====================================================
socket
   `------> +---------+-+-+
            |  sock   | | |
            +---------+ | |
            | inet_sock | |   --> PF_INET      [family]
            +-----------+ |
            | tcp_sock    |   --> SOCK_STREAM  [type]
            +-------------+       IPPROTO_TCP  [protocol]

 tcp_sock is Transmission Control Block(TCB) of RFC 793

----------------------------------------------------
inet_protosw (inetsw_array[])
+---------+
| type    | (SOCK_[type])                      [type]
+---------+
|protocol | (IPPROTO_[protocol])               [protocol]
+---------+
| ops     | (inet_[type]_ops)                  [type]
+---------+
| prot   ----->  proto         (tcp_prot)      [protocol]
+---------+     +-------------+
                | operations  |
                |  .accept    |
                |  .close     |
                |  .......    |
                +-------------+

Fucntion calling path:
 sys_connect
  .. -> inet_[type]_ops->connect()
   .. -> sock->sk_prot->connect()
 (sock->sk_prot == inet_protosw->prot)


Tapip socket model
====================================================

socket
   `------> +---------+-+
            |  sock   | |   --> PF_INET      [family]
            +---------+ |
            | tcp_sock  |   --> SOCK_STREAM  [type]
            |           |
            | /* tcb */ |       IPPROTO_TCP  [protocol]
            |           |
            +-----------+

 tcp_sock::somefield is Transmission Control Block(TCB) of RFC 793
----------------------------------------------------
socket->ops (inet_ops)
sock->ops   (tcp_ops)

Fucntion calling path:
  _send()
    -> socket->ops->send() [inet_send]
      -> sock->ops->send() [tcp_send]

tapip TOP2,测试udp发送,打开tty,更正一下,原作者的脚本需加上-u指定UDP,否则无法监听。

zc@ubuntu:~/xilinx/app/tapip-master$ sudo iptables -I INPUT -p udp -s 10.0.0.1 -j ACCEPT
[sudo] password for zc: 
zc@ubuntu:~/xilinx/app/tapip-master$ nc -l 12345
^C
zc@ubuntu:~/xilinx/app/tapip-master$ nc -u -l 12345
asdf
asd
asd
asdf

打开tty2,

[net shell]: snc -u -c 10.0.0.2:12345
heloo
hello
^C
[net shell]: snc -u -c 10.0.0.2:12345
hello
^C
[net shell]: snc -u -c 10.0.0.2:12345
hello
asdf
asdf
asdfsadf


#从这儿开始,tty1收到数据
asdf
asdf
asd
asd
asdf
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值