1
/*
****************************************
2
* Name : Vtun 源碼詳細(xì)分析
3
* Version : 3.0.3
4
* Date : Jan. 22, 2014
5
* Author : lucas
6
* Email : lucasysfeng@gmail.com
7
* Blog :
http://www.cnblogs.com/lucasysfeng/
8
* Description : 1.Vtun是一個(gè)短小精悍的開源VPN項(xiàng)目,
9
* 這里分析了其客戶端和服務(wù)器的源碼。
10
* 2.vtun源碼可以從下面網(wǎng)址下載
11
*
http://vtun.sourceforge.net/
12
****************************************
*/
13
14
15
/*
********************************************** client端代碼執(zhí)行基本流程分析 ***********************************************
*/
16
/*
***************************************************************
17
*原型:int main(int argc, char* argv[], char* env[]);
18
*功能:初始化操作,確定是client端還是server端。
19
*下一步:根據(jù)命令行參數(shù)選擇執(zhí)行client或者server分支,先分析client。
20
****************************************************************
*/
21
int
main(
int
argc,
char
*argv[],
char
*
env[])
22
{
23
......
24
......
//
初始化vtun結(jié)構(gòu)體。
25
while
((opt = getopt(argc, argv,
"
misf:P:L:t:npq
"
)) != EOF)
//
獲取命令行參數(shù)并進(jìn)行相應(yīng)操作。
26
{
27
......
28
}
29
reread_config(
0
);
//
讀配置文件。
30
......
31
clear_nat_hack_flags(svr);
//
清除另一方的nat_hack標(biāo)志。
32
if
(!svr)
//
根據(jù)命令行參數(shù)進(jìn)行客戶端配置。
33
{
34
......
35
hst = argv[optind++];
//
vtund server [ip]的第二個(gè)參數(shù)給hst,這個(gè)參數(shù)是服務(wù)器給客戶端定義的名字。
36
host = find_host(hst);
//
hst是命令行參數(shù),host是配置文件中的對應(yīng)該參數(shù)的會話信息。
37
......
38
}
39
vtun.svr_name = strdup(argv[optind]);
//
vtund server [ip]的ip給vtun.srv_name
40
......
//
如果vtun結(jié)構(gòu)體的一些成員沒有被初試話,則賦予默認(rèn)值。
41
switch
(vtun.svr_type)
//
判斷vtun的類型,VTUN_STAND_ALONE VTUN_INETD.
42
{
43
......
44
}
45
if
(daemon)
//
是否要創(chuàng)建守護(hù)進(jìn)程
46
{
47
if
(dofork && fork())
//
當(dāng)命令行設(shè)置為超級守護(hù)進(jìn)程時(shí)不執(zhí)行該操作。
48
...
49
}
50
if
(svr)
51
{
52
memset(&sa,
0
,
sizeof
(sa));
//
掛起時(shí)讀取配置文件。
53
sa.sa_handler =
reread_config;
54
sigaction(SIGHUP, &
sa, NULL);
55
init_title(argc, argv, env,
"
vtund[s]:
"
);
56
57
if
(vtun.svr_type ==
VTUN_STAND_ALONE)
58
write_pid();
//
將當(dāng)前pid寫入文件中
59
60
server(sock);
//
執(zhí)行服務(wù)器操作
61
}
62
else
63
{
64
init_title(argc, argv, env,
"
vtund[c]:
"
);
65
client(host);
//
執(zhí)行客戶端操作,host就是從配置文件讀取出的對應(yīng)命令行參數(shù)會話名的信息。
66
}
67
......
68
}
69
70
71
/*
***********************************************************
72
*原型:void client(struct vtun_host *host);
73
*參數(shù):host是從配置文件中讀出某個(gè)會話名所包含的信息。
74
*功能:建立socket以及bind、connect、select等,認(rèn)證暨建立隧道。
75
*下一步:認(rèn)證auth_client(s, host)后再執(zhí)行tunnel(host)即開啟隧道。
76
************************************************************
*/
77
void
client(
struct
vtun_host *host)
//
host參數(shù)是main函數(shù)中傳遞的配置文件中的會話信息。
78
{
79
......
80
......
//
結(jié)束,掛起等信號處理函數(shù)。
81
while
((!client_term) || (client_term ==
VTUN_SIG_HUP))
82
{
83
if
(reconnect && (client_term != VTUN_SIG_HUP)) { ...... }
//
重連
84
......
85
if
(server_addr(&svr_addr, host) <
0
)
continue
;
//
Set server address
86
if
(local_addr(&my_addr, host,
0
) <
0
)
continue
;
//
Set local address
87
if
((s = socket(AF_INET, SOCK_STREAM,
0
)) == -
1
) { ...... }
//
建立socket套接字
88
opt =
1
;
89
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt,
sizeof
(opt));
//
Required when client is forced to bind to specific port
90
if
(bind(s, (
struct
sockaddr *)&my_addr,
sizeof
(my_addr))){.....}
//
bind
91
host->spd_in = host->spd_out =
0
;
92
host->flags &= VTUN_CLNT_MASK;
//
Clear speed and flags which will be supplied by server.
93
io_init();
94
......
95
96
if
(connect_t(s,(
struct
sockaddr *) &svr_addr, host->
timeout))
97
{
98
.....
99
}
100
else
101
{
102
if
(auth_client(s, host))
//
認(rèn)證,也就是隧道建立過程
103
{
104
...
105
client_term = tunnel(host);
//
開啟隧道,host是配置文件相應(yīng)會話信息。
106
...
107
}
108
else
109
{
110
......
//
認(rèn)證失敗
111
}
112
}
113
close(s);
114
free_sopt(&host->
sopt);
115
}
//
end while
116
......
117
}
118
119
/*
***************************************************************************
120
*補(bǔ)充:在執(zhí)行tunnel(host)前先來看看上面client函數(shù)中的connect_t函數(shù)。
121
*原型:int connect_t(int s, struct sockaddr *svr, time_t timeout);
122
*參數(shù):s是client中建立的套接字描述符。
123
*功能:與服務(wù)器建立連接。
124
****************************************************************************
*/
125
int
connect_t(
int
s,
struct
sockaddr *
svr, time_t timeout)
126
{
127
#if
defined(VTUN_SOCKS) && VTUN_SOCKS == 2
128
/*
Some SOCKS implementations don't support
129
* non blocking connect
*/
130
return
connect(s, svr,
sizeof
(
struct
sockaddr));
131
#else
132
sock_flags =
fcntl(s, F_GETFL);
133
if
(fcntl(s, F_SETFL, O_NONBLOCK) <
0
)...
//
設(shè)置s為非阻塞?
134
if
(connect(s, svr,
sizeof
(
struct
sockaddr)) <
0
&& errno !=
EINPROGRESS)...
135
......
136
if
(
select
(s+
1
, NULL, &fdset, NULL, timeout?&tv:NULL) >
0
)
137
{
138
...
139
getsockopt(s, SOL_SOCKET, SO_ERROR, &errno, &l);
//
?
140
}
141
else
142
{
143
errno =
ETIMEDOUT;
144
fcntl(s, F_SETFL, sock_flags);
145
...
146
}
147
#endif
148
}
//
end connect_t
149
150
/*
************************************************************************
151
*補(bǔ)充:在執(zhí)行tunnel(host)前再來看看上面client函數(shù)中的auth_client.
152
*原型:int auth_client(int fd, struct vtun_host *host);
153
*參數(shù):fd是client端創(chuàng)建的套接字描述符,host是配置文件中某個(gè)會話所包含的信息
154
*功能:認(rèn)證過程,也是隧道建立過程。
155
*************************************************************************
*/
156
int
auth_client(
int
fd,
struct
vtun_host *
host)
157
{
158
......
159
stage = ST_INIT;
//
#define ST_INIT 0
160
while
(readn_t(fd, buf, VTUN_MESG_SIZE, vtun.timeout) >
0
)
//
讀取服務(wù)器發(fā)來認(rèn)證信息。
161
{
162
buf[
sizeof
(buf)-
1
]=
'
\0
'
;
163
switch
(stage)
164
{
165
case
ST_INIT:
166
if
(!strncmp(buf,
"
VTUN
"
,
4
))
167
{
168
stage =
ST_HOST;
169
print_p(fd,
"
HOST: %s\n
"
,host->host);
//
print_p向server發(fā)送HOST:[host]。
170
continue
;
171
}
172
break
;
173
case
ST_HOST:
174
if
(!strncmp(buf,
"
OK
"
,
2
) && cs2cl(buf, chal))
//
接收到請求發(fā)送密碼信息 OK CHAL:[chal]
175
{
176
stage =
ST_CHAL;
177
encrypt_chal(chal, host->
passwd);
178
print_p(fd,
"
CHAL: %s\n
"
, cl2cs(chal));
//
發(fā)送配置文件中本次會話密碼CHAL:[chal]
179
continue
;
180
}
181
break
;
182
case
ST_CHAL:
183
if
(!strncmp(buf,
"
OK
"
,
2
) && cf2bf(buf, host))
//
接收到OK FLAGS:[host]認(rèn)證成功信息
184
success =
1
;
185
break
;
186
}
187
break
;
188
}
//
end while
189
return
success;
190
}
191
192
/*
************************************************************************
193
*原型:int tunnel(strucnt vtun_host* host);
194
*參數(shù):host是配置文件中某個(gè)會話所包含的信息
195
*功能:開啟隧道即初試話設(shè)備讀寫函數(shù),初始化封裝后發(fā)送接收所用協(xié)議。
196
*下一步:linkfd(host);
197
*************************************************************************
*/
198
int
tunnel(
struct
vtun_host *
host)
199
{
200
......
201
if
((host->persist == VTUN_PERSIST_KEEPIF) && (host->loc_fd >=
0
))
//
接口是否已經(jīng)打開
202
interface_already_open =
1
;
203
if
(host->dev){...}
//
判斷虛擬設(shè)備類型
204
if
(!interface_already_open)
//
虛擬網(wǎng)卡沒有打開,則打開之
205
206
...
207
switch
(host->flags &
VTUN_TYPE_MASK)
208
{
209
...
210
case
VTUN_TUN:
211
if
((fd[
0
]=tun_open(dev)) <
0
)
//
打開虛擬網(wǎng)卡,獲取描述符
212
{
213
vtun_syslog(LOG_ERR,
"
Can't allocate tun device %s. %s(%d)
"
, dev, strerror(errno), errno);
214
return
-
1
;
215
}
216
break
;
217
}
218
host->loc_fd = fd[
0
];
//
虛擬設(shè)備文件描述符存在host->loc_fd中
219
}
220
switch
(host->flags & VTUN_PROT_MASK)
//
初始化協(xié)議,tcp還是udp
221
{
222
......
223
case
VTUN_UDP:
224
if
((opt = udp_session(host)) == -
1
){.....}
//
進(jìn)行udp的socket創(chuàng)建等操作
225
proto_write =
udp_write;
226
proto_read =
udp_read;
227
}
228
switch
((pid = fork())){...}
//
建立子進(jìn)程
229
switch
(host->flags & VTUN_TYPE_MASK)
//
根據(jù)虛擬設(shè)備類型,選擇相應(yīng)虛擬設(shè)備讀寫方式
230
{
231
.....
232
case
VTUN_TUN:
233
set_title(
"
%s tun %s
"
, host->
host, dev);
234
dev_read =
tun_read;
235
dev_write =
tun_write;
236
break
;
237
}
238
opt =
linkfd(host);
239
.......
240
}
241
242
/*
************************************************************************
243
*補(bǔ)充:在linkfd之前,我們先來看看tunnel函數(shù)中udp_session.
244
*原型:int udp_session(struct vtun_host *host);
245
*參數(shù):host是配置文件中某個(gè)會話所包含的信息。
246
*功能:udp socket的創(chuàng)建、bind、connect等。
247
*************************************************************************
*/
248
int
udp_session(
struct
vtun_host *
host)
249
{
250
struct
sockaddr_in saddr;
251
short
port;
252
int
s, opt;
253
extern
int
is_rmt_fd_connected;
254
255
if
((s = socket(AF_INET, SOCK_DGRAM,
0
)) == -
1
)
256
{
257
vtun_syslog(LOG_ERR,
"
Can't create socket
"
);
258
return
-
1
;
259
}
260
261
opt =
1
;
262
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt,
sizeof
(opt));
263
264
/*
Set local address and port
*/
265
local_addr(&saddr, host,
1
);
266
if
(bind(s, (
struct
sockaddr *) &saddr,
sizeof
(saddr)))
267
{
268
vtun_syslog(LOG_ERR,
"
Can't bind to the socket
"
);
269
return
-
1
;
270
}
271
272
opt =
sizeof
(saddr);
273
if
(getsockname(s, (
struct
sockaddr *) &saddr, &
opt))
274
{
275
vtun_syslog(LOG_ERR,
"
Can't get socket name
"
);
276
return
-
1
;
277
}
278
279
/*
Write port of the new UDP socket
*/
280
port =
saddr.sin_port;
281
if
(write_n(host->rmt_fd, (
char
*) &port,
sizeof
(
short
)) <
0
)
282
{
283
vtun_syslog(LOG_ERR,
"
Can't write port number
"
);
284
return
-
1
;
285
}
286
host->sopt.lport =
htons(port);
287
288
/*
Read port of the other's end UDP socket
*/
289
if
(readn_t(host->rmt_fd, &port,
sizeof
(
short
), host->timeout) <
0
)
290
{
291
vtun_syslog(LOG_ERR,
"
Can't read port number %s
"
, strerror(errno));
292
return
-
1
;
293
}
294
295
opt =
sizeof
(saddr);
296
if
(getpeername(host->rmt_fd, (
struct
sockaddr *) &saddr, &
opt))
297
{
298
vtun_syslog(LOG_ERR,
"
Can't get peer name
"
);
299
return
-
1
;
300
}
301
302
saddr.sin_port =
port;
303
304
/*
if the config says to delay the UDP connection, we wait for an
305
incoming packet and then force a connection back. We need to
306
put this here because we need to keep that incoming triggering
307
packet and pass it back up the chain.
*/
308
309
if
(VTUN_USE_NAT_HACK(host))
310
is_rmt_fd_connected =
0
;
311
else
312
{
313
if
(connect(s, (
struct
sockaddr *)&saddr,
sizeof
(saddr)))
314
{
315
vtun_syslog(LOG_ERR,
"
Can't connect socket
"
);
316
return
-
1
;
317
}
318
is_rmt_fd_connected =
1
;
319
}
320
321
host->sopt.rport =
htons(port);
322
323
/*
Close TCP socket and replace with UDP socket
*/
324
close(host->
rmt_fd);
325
host->rmt_fd = s;
//
將TCP套接字替換為UDP套接字。
326
327
vtun_syslog(LOG_INFO,
"
UDP connection initialized
"
);
328
return
s;
329
}
330
331
/*
************************************************************************
332
*原型:int linkfd(struct vtun_host *host);
333
*參數(shù):host是配置文件中某個(gè)會話所包含的信息。
334
*功能:初始化加密解密壓縮解壓模塊。
335
*下一步:虛擬網(wǎng)卡讀寫以及數(shù)據(jù)的接收發(fā)送lfd_linker();
336
*************************************************************************
*/
337
int
linkfd(
struct
vtun_host *
host)
338
{
339
......
340
lfd_host =
host;
341
old_prio = getpriority(PRIO_PROCESS,
0
);
//
取得進(jìn)程優(yōu)先級
342
setpriority(PRIO_PROCESS,
0
, LINKFD_PRIO);
343
......
//
Build modules stack加密壓縮等。
344
......
//
結(jié)束進(jìn)程等信號處理函數(shù)。
345
io_init();
346
lfd_linker();
//
虛擬網(wǎng)卡讀寫,封裝解封以及發(fā)送。
347
......
//
鬧鐘信號等。
348
}
349
350
/*
************************************************************************
351
*原型:int lfd_linker(void)
352
*功能:虛擬網(wǎng)卡讀寫以及數(shù)據(jù)的接收發(fā)送lfd_linker();
353
*下一步:結(jié)束。
354
*************************************************************************
*/
355
int
lfd_linker(
void
)
356
{
357
int
fd1 = lfd_host->rmt_fd;
//
fd1是網(wǎng)絡(luò)套接字描述符,也就是最后封裝發(fā)送的那個(gè)套接字描述符。
358
int
fd2 = lfd_host->loc_fd;
//
fd2是虛擬網(wǎng)卡設(shè)備文件描述符。
359
......
360
/*
Delay sending of first UDP packet over broken NAT routers
361
because we will probably be disconnected. Wait for the remote
362
end to send us something first, and use that connection.
*/
363
if
(!VTUN_USE_NAT_HACK(lfd_host))
//
?
364
proto_write(fd1, buf, VTUN_ECHO_REQ);
365
......
366
while
(!linker_term)
//
while循環(huán)體從虛擬網(wǎng)卡讀數(shù)據(jù)后發(fā)送;將接收的數(shù)據(jù)寫入虛擬網(wǎng)卡。
367
{
368
......
369
FD_ZERO(&fdset);
//
等待數(shù)據(jù)
370
FD_SET(fd1, &
fdset);
371
FD_SET(fd2, &
fdset);
372
tv.tv_sec = lfd_host->ka_interval;
//
非阻塞超時(shí)時(shí)間
373
tv.tv_usec =
0
;
374
if
((len =
select
(maxfd, &fdset, NULL, NULL, &tv)) <
0
)
375
{
376
....,.
377
}
//
select非阻塞監(jiān)控
378
if
(ka_need_verify)
//
ka_need_verify和信號處理函數(shù)有關(guān)
379
{
380
...
//
No input frames, check connection with ECHO,沒輸入信息,發(fā)送請求信息。
381
}
382
if
(send_a_packet)
//
默認(rèn)為0不加密
383
{
384
...
//
加密發(fā)送
385
}
386
if
(FD_ISSET(fd1,&fdset) && lfd_check_up())
//
網(wǎng)絡(luò)套接字fd1是否有數(shù)據(jù)到達(dá),加解密模塊是否準(zhǔn)備就緒。
387
{
388
....
389
if
((len = proto_read(fd1, buf)) <=
0
)...
//
接收網(wǎng)絡(luò)中數(shù)據(jù)存到buf
390
fl = len & ~VTUN_FSIZE_MASK;
//
獲取幀標(biāo)志
391
len = len &
VTUN_FSIZE_MASK;
392
if
(fl)
//
fl即frame flags幀標(biāo)志
393
{
394
...
//
判斷是何種幀,即判斷接收到數(shù)據(jù)的類型請求、應(yīng)答、壞幀、關(guān)閉 。
395
}
396
if
((len = lfd_run_up(len, buf, &
out
)) == -
1
)...
//
解密
397
if
(len && dev_write(fd2,
out
, len) <
0
)
398
{
399
...
//
將網(wǎng)絡(luò)套接字fd1的數(shù)據(jù)寫入虛擬網(wǎng)卡fd2。
400
}
401
}
402
if
(FD_ISSET(fd2, &fdset) && lfd_check_down())
//
虛擬網(wǎng)卡中是否有數(shù)據(jù),加解密模塊是否就緒。
403
{
404
if
((len = dev_read(fd2, buf, VTUN_FRAME_SIZE)) <
0
)
405
{
406
...
//
讀取虛擬網(wǎng)卡中數(shù)據(jù)
407
}
408
if
((len = lfd_run_down(len, buf, &
out
)) == -
1
)...
//
加密
409
if
(len && proto_write(fd1,
out
, len) <
0
)
410
{
411
...
//
將虛擬網(wǎng)卡fd2中數(shù)據(jù)通過網(wǎng)絡(luò)套接字fd1發(fā)送。
412
}
413
...
414
}
415
...
416
}
//
end while
417
...
418
proto_write(fd1, buf, VTUN_CONN_CLOSE);
//
通知其他終端本終端連接關(guān)閉
419
...
420
return
0
;
421
}
422
423
424
425
426
/*
********************************************** server端代碼執(zhí)行基本流程分析 ***********************************************
*/
427
/*
***************************************************************
428
*原型:int main(int argc, char* argv[], char* env[]);
429
*功能:初始化操作,確定是client端還是server端。
430
*下一步:根據(jù)命令行參數(shù)選擇執(zhí)行client或者server分支,分析server。
431
****************************************************************
*/
432
int
main(
int
argc,
char
*argv[],
char
*
env[])
433
{
434
......
435
......
//
初始化vtun結(jié)構(gòu)體。
436
while
((opt = getopt(argc, argv,
"
misf:P:L:t:npq
"
)) != EOF)
//
獲取命令行參數(shù)并進(jìn)行相應(yīng)操作。
437
{
438
......
439
}
440
reread_config(
0
);
//
讀配置文件。
441
......
442
clear_nat_hack_flags(svr);
443
if
(!svr)
//
如果不是服務(wù)器,再根據(jù)命令行參數(shù)進(jìn)行配置。
444
{
445
......
446
hst = argv[optind++];
//
vtund server [ip]的第二個(gè)參數(shù)給hst,這個(gè)參數(shù)是服務(wù)器給客戶端定義的名字。
447
host = find_host(hst);
//
hst是命令行參數(shù),host是配置文件中的對應(yīng)該參數(shù)的會話信息。
448
......
449
}
450
vtun.svr_name = strdup(argv[optind]);
//
vtund server [ip]的ip給vtun.srv_name
451
......
//
如果vtun結(jié)構(gòu)體的一些成員沒有被初試話,則賦予默認(rèn)值。
452
switch
(vtun.svr_type)
//
判斷vtun的類型,VTUN_STAND_ALONE VTUN_INETD.
453
{
454
......
455
}
456
if
(daemon)
//
是否要創(chuàng)建守護(hù)進(jìn)程
457
{
458
if
(dofork &&
fork())
459
...
460
}
461
if
(svr)
462
{
463
memset(&sa,
0
,
sizeof
(sa));
//
掛起時(shí)讀取配置文件。
464
sa.sa_handler =
reread_config;
465
sigaction(SIGHUP, &
sa, NULL);
466
467
init_title(argc, argv, env,
"
vtund[s]:
"
);
468
469
if
(vtun.svr_type ==
VTUN_STAND_ALONE)
470
write_pid();
471
472
server(sock);
//
執(zhí)行服務(wù)器操作
473
}
474
else
475
{
476
init_title(argc, argv, env,
"
vtund[c]:
"
);
477
client(host);
//
執(zhí)行客戶端操作,host就是從配置文件讀取出的對應(yīng)命令行參數(shù)會話名的信息。
478
}
479
......
480
}
481
482
/*
***********************************************************
483
*原型:void server(int sock);
484
*參數(shù):sock = 0.
485
*功能:建立socket以及bind、connect、select等,認(rèn)證暨建立隧道。
486
*下一步:根據(jù)守護(hù)進(jìn)程類型選擇執(zhí)行l(wèi)istener還是connection。
487
************************************************************
*/
488
void
server(
int
sock)
489
{
490
struct
sigaction sa;
//
忽略接收進(jìn)程信號。
491
sa.sa_handler =
SIG_IGN;
492
sa.sa_flags =
SA_NOCLDWAIT;
493
;
494
sigaction(SIGINT, &
sa, NULL);
495
sigaction(SIGQUIT, &
sa, NULL);
496
sigaction(SIGCHLD, &
sa, NULL);
497
sigaction(SIGPIPE, &
sa, NULL);
498
sigaction(SIGUSR1, &
sa, NULL);
499
vtun_syslog(LOG_INFO,
"
VTUN server ver %s (%s)
"
, VTUN_VER,
500
vtun.svr_type == VTUN_INETD ?
"
inetd
"
:
"
stand
"
);
501
switch
(vtun.svr_type)
502
//
判斷sever端的類型獨(dú)立啟動守護(hù)進(jìn)程or超級守護(hù)進(jìn)程。
503
{
504
case
VTUN_STAND_ALONE:
//
獨(dú)立啟動守護(hù)進(jìn)程
505
listener();
//
開始監(jiān)聽
506
break
;
507
//
超級守護(hù)進(jìn)程沒有socket、bind、listen、accept過程(inetd實(shí)現(xiàn)該過程),而是直接讀寫開始。
508
case
VTUN_INETD:
//
守護(hù)進(jìn)程
509
connection(sock);
510
break
;
511
}
512
}
513
514
/*
***********************************************************
515
*這里分析獨(dú)立守護(hù)進(jìn)程時(shí)的操作。
516
*原型:void listener(void);
517
*功能:建立socket、bind、listen、accept、connection等。
518
*下一步:connection。
519
************************************************************
*/
520
void
listener(
void
)
521
{
522
...
523
if
(generic_addr(&my_addr, &vtun.bind_addr) <
0
) ...
//
設(shè)置監(jiān)聽地址
524
if
((s = socket(AF_INET, SOCK_STREAM,
0
)) == -
1
)...
//
創(chuàng)建socket
525
opt =
1
;
526
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt,
sizeof
(opt));
527
if
(bind(s, (
struct
sockaddr *)&my_addr,
sizeof
(my_addr)))...
//
bind
528
if
(listen(s,
10
))...
529
...
//
信號處理,防止僵尸進(jìn)程
530
while
((!server_term) || (server_term ==
VTUN_SIG_HUP))
531
{
532
//
注意這個(gè)循環(huán)條件要和linkfd里的循環(huán)條件結(jié)合起來,這里的循環(huán)條件實(shí)際是掛起狀態(tài)才執(zhí)行該循環(huán),
533
//
而不是沒有結(jié)束循環(huán)或者掛起狀態(tài)二者滿足其一執(zhí)行循環(huán)!
534
if
((s1 = accept(s,(
struct
sockaddr *)&cl_addr,&opt)) <
0
)..
//
accept
535
switch
(fork())
//
創(chuàng)建子進(jìn)程
536
{
537
case
0
:
538
close(s);
539
connection(s1);
//
和client建立連接,s1是accept返回的已連接套接字描述符(表示此次TCP三次握手連接成功)。
540
break
;
541
case
-
1
:
542
vtun_syslog(LOG_ERR,
"
Couldn't fork()
"
);
543
default
:
544
close(s1);
545
break
;
546
}
547
}
548
}
549
550
/*
***********************************************************
551
*原型:void connection(int sock);
552
*參數(shù):注意這里的sock是已連接套接字描述符。
553
*功能:建立socket、bind、listen、accept、connection等。
554
*下一步:認(rèn)證成功后開啟隧道即執(zhí)行tunnel。
555
************************************************************
*/
556
void
connection(
int
sock)
//
sock是已連接套接字描述符,和server端監(jiān)聽套接字描述符不同。
557
{
558
if
(getpeername(sock, (
struct
sockaddr *) &cl_addr, &opt))...
//
獲取client端地址
559
...
560
if
(getsockname(sock, (
struct
sockaddr *) &my_addr, &opt) <
0
)...
561
...
562
io_init();
563
if
((host = auth_server(sock)))
//
認(rèn)證
564
{
565
...
//
忽略掛起信號
566
...
//
設(shè)置host的一些成員
567
}
568
tunnel(host);
//
開啟隧道。
569
......
570
}
571
572
/*
***********************************************************************
573
*補(bǔ)充:在開啟隧道之前先來看看上面函數(shù)涉及的server端認(rèn)證auth_server(sock);
574
*原型:void connection(int sock);
575
*參數(shù):注意這里的sock是已連接套接字描述符。
576
*功能:建立socket、bind、listen、accept、connection等。
577
************************************************************************
*/
578
struct
vtun_host * auth_server(
int
fd)
579
{
580
......
581
while
(readn_t(fd, buf, VTUN_MESG_SIZE, vtun.timeout) >
0
)
//
接收來自客戶端的認(rèn)證信息。
582
{
583
...
584
switch
(stage)
585
{
586
case
ST_HOST:
587
if
(!strcmp(str1,
"
HOST
"
))
//
接收來自client的HOST:[host]
588
589
{
590
host =
strdup(str2);
591
gen_chal(chal_req);
592
print_p(fd,
"
OK CHAL: %s\n
"
, cl2cs(chal_req));
//
發(fā)送請求發(fā)送秘密信息OK CHAL:[chal]
593
stage =
ST_CHAL;
594
continue
;
595
}
596
break
;
597
case
ST_CHAL:
598
if
(!strcmp(str1,
"
CHAL
"
))
//
接收密碼
599
600
{
601
if
(!
cs2cl(str2, chal_res))
602
break
;
603
if
(!(h =
find_host(host)))
604
break
;
605
decrypt_chal(chal_res, h->
passwd);
606
if
(!memcmp(chal_req, chal_res, VTUN_CHAL_SIZE))
//
與配置文件中密碼比較
607
608
{
609
/*
Auth successeful.
*/
610
/*
Lock host
*/
611
if
(lock_host(h) <
0
)
612
{
613
/*
Multiple connections are denied
*/
614
h =
NULL;
615
break
;
616
}
617
print_p(fd,
"
OK FLAGS: %s\n
"
, bf2cf(h));
//
發(fā)送成功信息OK FLAGS:[host]
618
}
619
else
620
h =
NULL;
621
}
622
break
;
623
}
//
end switch
624
break
;
625
}
//
end while
626
......
627
}
628
629
/*
************************************************************************
630
*原型:int tunnel(strucnt vtun_host* host);
631
*參數(shù):host是配置文件中某個(gè)會話所包含的信息
632
*功能:開啟隧道即初試話設(shè)備讀寫函數(shù),初始化封裝后發(fā)送接收所用協(xié)議。
633
*下一步:linkfd(host);
634
*************************************************************************
*/
635
int
tunnel(
struct
vtun_host *
host)
636
{
637
......
638
......
//
接口是否打開
639
if
(host->
dev)
640
{ ...}
//
判斷虛擬設(shè)備類型
641
if
(!interface_already_open)
//
獲取虛擬設(shè)備文件描述符
642
{
643
... host->loc_fd = fd[
0
];
//
虛擬設(shè)備文件描述符存在host->loc_fd中
644
}
645
switch
(host->flags & VTUN_PROT_MASK)
//
初始化協(xié)議,tcp還是udp
646
647
{
648
......
649
case
VTUN_UDP:
650
if
((opt = udp_session(host)) == -
1
)
651
{ .....}
//
進(jìn)行udp的socket創(chuàng)建等操作
652
proto_write =
udp_write;
653
proto_read =
udp_read;
654
}
655
switch
((pid =
fork()))
656
{
657
...
658
}
659
switch
(host->flags & VTUN_TYPE_MASK)
//
根據(jù)虛擬設(shè)備類型,選擇相應(yīng)虛擬設(shè)備讀寫方式,
660
{
661
.....
662
case
VTUN_TUN:
663
set_title(
"
%s tun %s
"
, host->
host, dev);
664
dev_read =
tun_read;
665
dev_write =
tun_write;
666
break
;
667
}
668
opt =
linkfd(host);
669
.......
670
}
671
672
/*
************************************************************************
673
*原型:int linkfd(struct vtun_host *host);
674
*參數(shù):host是配置文件中某個(gè)會話所包含的信息
675
*功能:初始化加密解密壓縮解壓模塊。
676
*下一步:虛擬網(wǎng)卡讀寫以及數(shù)據(jù)的接收發(fā)送lfd_linker();
677
*************************************************************************
*/
678
int
linkfd(
struct
vtun_host *host)
//
鏈接虛擬網(wǎng)卡文件描述符和封裝后用于發(fā)送接收的套接字描述符。
679
{
680
......
681
lfd_host =
host;
682
old_prio = getpriority(PRIO_PROCESS,
0
);
683
setpriority(PRIO_PROCESS,
0
, LINKFD_PRIO);
684
......
//
Build modules stack加密壓縮等。
685
......
//
結(jié)束進(jìn)程等信號處理函數(shù)。
686
io_init();
687
lfd_linker();
//
虛擬網(wǎng)卡讀寫,封裝解封以及發(fā)送。
688
......
//
鬧鐘信號等。
689
}
690
691
/*
************************************************************************
692
*原型:int lfd_linker(void)
693
*功能:虛擬網(wǎng)卡讀寫以及數(shù)據(jù)的接收發(fā)送lfd_linker();
694
*下一步:結(jié)束。
695
*************************************************************************
*/
696
int
lfd_linker(
void
)
697
{
698
int
fd1 = lfd_host->rmt_fd;
//
fd1是網(wǎng)絡(luò)套接字描述符,也就是最后封裝發(fā)送的那個(gè)套接字描述符。
699
int
fd2 = lfd_host->loc_fd;
//
fd2是虛擬網(wǎng)卡設(shè)備文件描述符。
700
......
701
/*
Delay sending of first UDP packet over broken NAT routers
702
because we will probably be disconnected. Wait for the remote
703
end to send us something first, and use that connection.
*/
704
if
(!VTUN_USE_NAT_HACK(lfd_host))
//
?
705
proto_write(fd1, buf, VTUN_ECHO_REQ);
706
......
707
while
(!linker_term)
//
while循環(huán)體從虛擬網(wǎng)卡讀數(shù)據(jù)后發(fā)送;將接收的數(shù)據(jù)寫入虛擬網(wǎng)卡。
708
{
709
......
710
FD_ZERO(&fdset);
//
等待數(shù)據(jù)
711
FD_SET(fd1, &
fdset);
712
FD_SET(fd2, &
fdset);
713
tv.tv_sec = lfd_host->ka_interval;
//
非阻塞超時(shí)時(shí)間
714
tv.tv_usec =
0
;
715
if
((len =
select
(maxfd, &fdset, NULL, NULL, &tv)) <
0
)
716
{ ...}
//
select非阻塞監(jiān)控
717
if
(ka_need_verify)
//
ka_need_verify和信號處理函數(shù)有關(guān)
718
{
719
...
//
No input frames, check connection with ECHO,沒輸入信息,發(fā)送請求信息。
720
}
721
if
(send_a_packet)
//
默認(rèn)為0不加密
722
{
723
...
//
加密發(fā)送
724
}
725
if
(FD_ISSET(fd1,&fdset) && lfd_check_up())
//
網(wǎng)絡(luò)套接字fd1是否有數(shù)據(jù)到達(dá),加解密模塊是否準(zhǔn)備就緒。
726
{
727
....
728
if
((len = proto_read(fd1, buf)) < =
0
)...
//
接收網(wǎng)絡(luò)中數(shù)據(jù)存到buf
729
fl = len & ~VTUN_FSIZE_MASK;
//
獲取幀標(biāo)志
730
len = len &
VTUN_FSIZE_MASK;
731
if
(fl)
//
fl即frame flags幀標(biāo)志
732
{
733
...
//
判斷是何種幀,即判斷接收到數(shù)據(jù)的類型請求、應(yīng)答、壞幀、關(guān)閉 。
734
}
735
if
((len = lfd_run_up(len, buf, &
out
)) == -
1
)...
//
解密
736
if
(len && dev_write(fd2,
out
, len) <
0
)
737
{
738
...
//
將網(wǎng)絡(luò)套接字fd1的數(shù)據(jù)寫入虛擬網(wǎng)卡fd2。
739
}
740
}
741
if
(FD_ISSET(fd2, &fdset) && lfd_check_down())
//
虛擬網(wǎng)卡中是否有數(shù)據(jù),加解密模塊是否就緒。
742
{
743
if
((len = dev_read(fd2, buf, VTUN_FRAME_SIZE)) <
0
)
744
{
745
...
//
讀取虛擬網(wǎng)卡中數(shù)據(jù)
746
}
747
if
((len = lfd_run_down(len, buf, &
out
)) == -
1
)...
//
加密
748
if
(len && proto_write(fd1,
out
, len) <
0
)
749
{
750
...
//
將虛擬網(wǎng)卡fd2中數(shù)據(jù)通過網(wǎng)絡(luò)套接字fd1發(fā)送。
751
}
752
...
753
}
754
...
755
}
//
end while
756
...
757
proto_write(fd1, buf, VTUN_CONN_CLOSE);
//
通知其他終端本終端連接關(guān)閉
758
...
759
return
0
;
760
}
?
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061
微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元

