吹着前奏望着天空,我想起 Task 试着完成,为它爆肝的那一天,断电的那一天,709 的那一间,我怎么看不见,消失的 DDL,我好像再来一年~

安装准备

Problem1.apt 源配置问题

在开始之前,我才发现自己的 apt 源配错了。我使用的是 Ubuntu19.10(eoan),但是 apt 源里居然全写的是 Ubuntu 18.04 LTS(Bionic)的源……
因此出现了花式安装报错的问题。
Solution:
自己手动把所有的 Bionic 都换成 eoan……

Problem2.没有合适的 IDE

由于这次任务需要在 Linux 上完成,自己的能力又没有强到能够用眼调试的水平。因此需要安装一个 IDE。(能用 GCC 调试我也服气)
Solution:
用 HUST 邮箱整一个 CLion。网址:CLion
白嫖就完事了~

Echo Server

代码

话不多说,直接上代码:

Linux Server 端

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
#include <netdb.h>
#include <sys/socket.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#define EHCO_PORT 28345//监听端口
#define MAX_CLIENT_NUM 10//最大客户端连接数量
#define MAX_BUFF 101//最大缓冲区长度

void charConversion(char array[]);//大小写转换
int isLowerCase(char ch);//判断小写

int main(){
int socketfd;
socketfd = socket(AF_INET, SOCK_STREAM, 0);//创建套接字
if(socketfd == -1){
printf("errno=%d \n", errno);
exit(1);
}
else{
printf("socket create successfully \n");
}
struct sockaddr_in sa;
bzero(&sa,sizeof(sa));//重置结构体
sa.sin_family = AF_INET;
sa.sin_port = htons(EHCO_PORT);//设定监听端口
sa.sin_addr.s_addr = htons(INADDR_ANY);//设定本地IP
bzero(&(sa.sin_zero), 8);
if(bind(socketfd, (struct sockaddr *)&sa, sizeof(sa))!= 0){
printf("bind failed \n");
printf("errno=%d \n", errno);
exit(1);
}
else{
printf("bind successfully \n");
}
if(listen(socketfd ,MAX_CLIENT_NUM) != 0){
printf("listen error ");
exit(1);
}
else{
printf("listen successfully \n");
}
int clientfd;
struct sockaddr_in clientAdd;
char buff[MAX_BUFF];
socklen_t len = sizeof(clientAdd);
int closing =0;
clientfd = accept(socketfd, (struct sockaddr *)&clientAdd, &len);
printf("Client ip is %s,port is %d\n",inet_ntoa(clientAdd.sin_addr),ntohs(clientAdd.sin_port));
while(closing == 0) {
int n;
while ((n = recv(clientfd, buff, 100, 0)) > 0) {//循环接收数据
buff[n]='\0';
write(STDOUT_FILENO, buff, n);
printf("successfully recv %d bytes\n", n);
printf("client says :%s\n", buff);
if (strcmp(buff, "quit") == 0) {//根据不同情形判断操作
send(clientfd, "See you~", strlen("See you~"), 0);
printf("server says: See you~\n");
closing = 1;
break;
}
charConversion(buff);//将小写全部变为大写
send(clientfd, buff, n, 0);
printf("server replys:%s\n", buff);
}
}
close(clientfd);
close(socketfd);
printf("socket close successfully!\n");
return 0;
}

void charConversion(char array[]){
int i=0; // 定义数组循环下标
while(array[i]){// 数组访问循环控制
//判断是否遇到了字符串的结束标志
if( isLowerCase(array[i]) ){
array[i] = array[i] - ('a'-'A'); // 小写转大写
}
i++;
}
}

// 检测字符是否为小写字母, [a, z]
int isLowerCase(char ch){
return (ch>='a'&&ch<='z');
}

Windows client 端

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
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <winsock.h>
#include <string.h>

#pragma comment( lib, "ws2_32.lib" )

#define PORT 28345
#define MAXDATASIZE 100
#define Address 192.168.188.128
void main(void){

int iClientSock;
int addr_len;
struct sockaddr_in ServerAddr;

int numbytes;
char buf[MAXDATASIZE+1] = "hello world!";

WSADATA WSAData;
//连接准备部分以及初始化
if (WSAStartup(0x0202, &WSAData)){
printf("initializationing error!\n");
WSACleanup();
exit(0);
}

if ((iClientSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1){
printf("创建套接字失败!\n");
WSACleanup();
exit(0);
}
ServerAddr.sin_family = PF_INET;
ServerAddr.sin_port = htons(PORT);
ServerAddr.sin_addr.s_addr = inet_addr("192.168.188.128");//换localhost
if (connect(iClientSock, (struct sockaddr*) & ServerAddr, sizeof(SOCKADDR_IN)) != -1) {
printf("Connection success!\n");
}
else {
printf("Connection failed!\n");
exit(0);
}
memset(&(ServerAddr.sin_zero), 0, sizeof(ServerAddr.sin_zero));
addr_len = sizeof(struct sockaddr);
printf("Server ip is %s,port is %d\n", inet_ntoa(ServerAddr.sin_addr), PORT);
//发送数据部分
while (1) {
printf("client says:");
gets(buf);
numbytes = send(iClientSock, buf, strlen(buf), 0);
if (numbytes == -1){
printf("send调用失败!\n");
WSACleanup();
exit(0);
}
printf("successfully send %d bytes\n", numbytes);
numbytes = -1;
numbytes = recv(iClientSock, buf, MAXDATASIZE, 0);
if (numbytes == -1){
printf("recv调用失败!\n");
WSACleanup();
exit(0);
}
buf[numbytes] = '\0';
printf("recv %d bytes\n", numbytes);
printf("server replys:%s\n", buf);
if (strcmp(buf, "See you~") == 0) {
return;
}
}
closesocket(iClientSock);
WSACleanup();
}

效果

Echo Server Demo

Problem

Socket 一直不能建立连接

这是由于 Linux 和 Windows 的防火墙策略设置
Solution:
在 Linux 中安装白名单 IP 地址:

1
sudo iptables -N whitelist-A whitelist -s 10.10.68.58 -j ACCEPT #将10.10.68.58换成你的主机真实网卡的IP地址

网卡设置有误

在 Task1 中,我错误地将主机中 VMnet8 的 IP 地址设置成了 VM1 的 IP 地址 192.168.188.128,导致出现了我一直都不能用 ssh 连接上我的虚拟机,但是 ping 又能 ping 通的诡异现象。
Solution:
在 Windows 系统中,更改 VMnet8 这张网卡的 IP 地址在虚拟机的相同网段下的其它 IP,例如说 192.168.188.1。

客户端协议设置出错

由于之前在熬测的时候写过了类似的程序,于是乎我想都没想就在 Windows 系统上的 client 用了之前的的源码,然而这份源码是 UDP 协议的,但是在 Linux 上跑的是 TCP 协议的 Server,导致 Server 一直不能发包到 Client。
Solution:
重写 Windows 系统下的源码,改用 TCP 协议。
虽然这次错误实在是有点蠢,但是我因此更加明确了我这次 Task 使用的一些 socket 函数在 UDP 协议与 TCP 协议的不同情况下使用的一些区别,也算是因祸得福(确信。

拓展

client

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
#define Windows
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifdef Windows
#include <windows.h>
#include <winsock.h>
#pragma comment( lib, "ws2_32.lib" )
#define Address "192.168.188.128"
#endif

#ifdef Linux
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#define Address "192.168.188.1"
#endif

#define PORT 28345
#define MAXDATASIZE 100

void main(void)
{

int iClientSock;
struct sockaddr_in ServerAddr;

int numbytes;
char buf[MAXDATASIZE+1] = "hello world!";
#ifdef Windows
WSADATA WSAData;
if (WSAStartup(0x0202, &WSAData))
{
printf("initializationing error!\n");
WSACleanup();
exit(0);
}
#endif

if ((iClientSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1)
{
printf("创建套接字失败!\n");
#ifdef Windows
WSACleanup();
#endif
exit(0);
}
ServerAddr.sin_family = PF_INET;
ServerAddr.sin_port = htons(PORT);
ServerAddr.sin_addr.s_addr = inet_addr(Address);//换localhost
if (connect(iClientSock, (struct sockaddr*) & ServerAddr, sizeof(ServerAddr)) != -1) {
printf("Connection success!\n");
}
else {
printf("Connection failed!\n");
exit(0);
}
memset(&(ServerAddr.sin_zero), 0, sizeof(ServerAddr.sin_zero));
printf("Server ip is %s,port is %d\n", inet_ntoa(ServerAddr.sin_addr), PORT);
while (1) {
printf("client says:");
gets(buf);
numbytes = send(iClientSock, buf, strlen(buf), 0);
if (numbytes == -1)
{
printf("send调用失败!\n");
#ifdef Windows
WSACleanup();
#endif
exit(0);
}
printf("successfully send %d bytes\n", numbytes);
numbytes = -1;
numbytes = recv(iClientSock, buf, MAXDATASIZE, 0);
if (numbytes == -1)
{
printf("recv调用失败!\n");
#ifdef Windows
WSACleanup();
#endif
exit(0);
}
buf[numbytes] = '\0';
printf("recv %d bytes\n", numbytes);
printf("server replys:%s\n", buf);
if (strcmp(buf, "See you~") == 0) {
return;
}
}
#ifdef Windows
closesocket(iClientSock);
WSACleanup();
#endif
#ifdef Linux
close(iClientSock);
#endif
}

Server

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
#define Windows
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifdef Linux
#include <netdb.h>
#include <sys/socket.h>
#include <errno.h>
#include <unistd.h>
#include <arpa/inet.h>
#endif

#ifdef Windows
#include<winsock2.h>
#include<windows.h>
#include<ws2tcpip.h>
#pragma comment( lib, "ws2_32.lib" )
#endif

#define EHCO_PORT 28345//监听端口
#define MAX_CLIENT_NUM 10//最大客户端连接数量
#define MAX_BUFF 101//最大缓冲区长度

void charConversion(char array[]);//大小写转换
int isLowerCase(char ch);//判断小写

int main() {
#ifdef Windows
WSADATA WSAData;
if (WSAStartup(0x0202, &WSAData))
{
printf("initializationing error!\n");
WSACleanup();
exit(0);
}
#endif
int socketfd;
socketfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);//创建套接字
if (socketfd == -1) {
#ifdef Linux
printf("errno=%d \n", errno);
#endif
printf("socket create failed \n");
#ifdef Windows
WSACleanup();
#endif
exit(1);
}
else {
printf("socket create successfully \n");
}
struct sockaddr_in sa;
memset(&sa,0,sizeof(sa));//重置结构体
sa.sin_family = AF_INET;
sa.sin_port = htons(EHCO_PORT);//设定监听端口
sa.sin_addr.s_addr = htons(INADDR_ANY);//设定本地IP
memset(&(sa.sin_zero),0, 8);
if (bind(socketfd, (struct sockaddr*) & sa, sizeof(sa)) != 0) {
printf("bind failed \n");
#ifdef Linux
printf("errno=%d \n", errno);
#endif
#ifdef Windows
WSACleanup();
#endif
exit(1);
}
else {
printf("bind successfully \n");
}
if (listen(socketfd, MAX_CLIENT_NUM) != 0) {
printf("listen error ");
#ifdef Windows
WSACleanup();
#endif
exit(1);
}
else {
printf("listen successfully \n");
}
int clientfd;
struct sockaddr_in clientAdd;
char buff[MAX_BUFF];
socklen_t len = sizeof(clientAdd);
int closing = 0;
clientfd = accept(socketfd, (struct sockaddr*) & clientAdd, &len);
printf("Client ip is %s,port is %d\n", inet_ntoa(clientAdd.sin_addr), ntohs(clientAdd.sin_port));
while (closing == 0) {
int n;
while ((n = recv(clientfd, buff, 100, 0)) > 0) {//循环接收数据
buff[n] = '\0';
#ifdef Linux
write(STDOUT_FILENO, buff, n);
#endif
printf("successfully recv %d bytes\n", n);
printf("client says :%s\n", buff);
if (strcmp(buff, "quit") == 0) {//根据不同情形判断操作
send(clientfd, "See you~", strlen("See you~"), 0);
printf("server says: See you~\n");
closing = 1;
break;
}
charConversion(buff);//将小写全部变为大写
send(clientfd, buff, n, 0);
printf("server replys:%s\n", buff);
}
}
#ifdef Windows
closesocket(clientfd);
closesocket(socketfd);
WSACleanup();
#endif
#ifdef Linux
close(clientfd);
close(socketfd);
#endif
printf("socket close successfully!\n");
return 0;
}

void charConversion(char array[]) {
int i = 0; // 定义数组循环下标
while (array[i]) {// 数组访问循环控制
//判断是否遇到了字符串的结束标志
if (isLowerCase(array[i])) {
array[i] = array[i] - ('a' - 'A'); // 小写转大写
}
i++;
}
}

// 检测字符是否为小写字母, [a, z]
int isLowerCase(char ch) {
return (ch >= 'a' && ch <= 'z');
}

File Server

话不多说,直接上代码

代码

Linux receiver

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
#include "head.h"
#define BUFF_SIZE 1024
#define PORT 28345
#define FILE_NAME_SIZE 512
int main(int argc,char *argv[]){
struct sockaddr_in s_addr,c_addr;
int s_sockfd,c_sockfd;
char buf[BUFF_SIZE];
int c_addr_len=sizeof(struct sockaddr_in);
int s_addr_len=sizeof(struct sockaddr_in);
s_sockfd=socket(AF_INET,SOCK_STREAM,0);
if(s_sockfd==-1)
strerr("socket error");
memset(&s_addr,0,s_addr_len);
s_addr.sin_family=AF_INET;
s_addr.sin_port=htons(PORT);
s_addr.sin_addr.s_addr=htonl(INADDR_ANY);

int opt=1;
setsockopt(s_sockfd,SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
if(bind(s_sockfd,(struct sockaddr*)&s_addr,s_addr_len)==-1)
strerr("bind error");
if(listen(s_sockfd,5)==-1)
strerr("listen error");

while(1){
printf("listening to connect........\n");
c_sockfd=accept(s_sockfd,(struct sockaddr*)&c_addr,&c_addr_len);
if(c_sockfd==-1)
strerr("accept error");

memset(buf,0,BUFF_SIZE);
if(recv(c_sockfd,buf,BUFF_SIZE,0)==-1)
strerr("recv error");
char filename[FILE_NAME_SIZE+1];
memset(filename,0,FILE_NAME_SIZE+1);
strncpy(filename,buf,strlen(buf)>FILE_NAME_SIZE? FILE_NAME_SIZE:strlen(buf));
filename[strlen(buf)]='\0';
if(strcmp(filename,"quit")==0){
printf("Exit.\n");
break;
}
printf("file name is %s\n",filename);

FILE * fp=fopen(filename,"wb+");
if(NULL==fp)
strerr("fopen error");
else{
int length=0;
memset(buf,0,BUFF_SIZE);
while((length=recv(c_sockfd,buf,BUFF_SIZE,0))>0){
if(fwrite(buf,sizeof(char),length,fp)<length)
strerr("fwrite error");
memset(buf,0,BUFF_SIZE);
}
printf("receive file : %s from server successful\n",filename);
fclose(fp);
}
close(c_sockfd);
}//end while(1)
close(s_sockfd);
return 0;
}

Windows Sender

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
#define _CRT_SECURE_NO_WARNINGS
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <WinSock2.h>

#define PORT 28345
#define SERVER_IP "192.168.188.128"
#define BUFFER_SIZE 1024
#define FILE_NAME_MAX_SIZE 512
#pragma comment(lib, "WS2_32")

int main(int argc, char* argv[])
{
if (argc != 2){
printf("usage : %s filename and format\n", argv[0]);
exit(1);
}
// 初始化socket dll
WSADATA wsaData;
WORD socketVersion = MAKEWORD(2, 0);
if (WSAStartup(socketVersion, &wsaData) != 0){
printf("Init socket dll error!");
exit(1);
}

//创建socket
SOCKET c_Socket = socket(AF_INET, SOCK_STREAM, 0);
if (SOCKET_ERROR == c_Socket){
printf("Create Socket Error!");
system("pause");
exit(1);
}//指定服务端的地址
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_addr.S_un.S_addr = inet_addr(SERVER_IP);
server_addr.sin_port = htons(PORT);
int opt = 1;
setsockopt(c_Socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
if (SOCKET_ERROR == connect(c_Socket, (LPSOCKADDR)&server_addr, sizeof(server_addr))){
printf("Can Not Connect To Server IP!\n");
system("pause");
exit(1);
}

char buffer[BUFFER_SIZE];//初始化缓冲区
memset(buffer, 0, BUFFER_SIZE);
strncpy(buffer, argv[1], strlen(argv[1]) > BUFFER_SIZE ? BUFFER_SIZE : strlen(argv[1]));//将文件名传入缓冲区

//向服务器发送文件名
if (send(c_Socket, buffer, BUFFER_SIZE, 0) < 0){
printf("Send File Name Failed\n");
system("pause");
exit(1);
}

//打开文件,准备发送
FILE* fp = fopen(argv[1], "rb");//windows下是"rb",表示打开一个只读的二进制文件
if (NULL == fp){
printf("File: %s Not Found\n", argv[1]);
}
else{
memset(buffer, 0, BUFFER_SIZE);
int length = 0;
//获取文件长度
fseek(fp, 0, SEEK_END); //定位到文件末
long long nFileLen = ftell(fp); //文件总长度
fseek(fp, 0, SEEK_SET); //恢复到文件头
long long sendLength = 0;
while ((length = fread(buffer, sizeof(char), BUFFER_SIZE, fp)) > 0) {
if (send(c_Socket, buffer, length, 0) < 0) {
printf("Send File: %s Failed\n", argv[1]);
break;
}
sendLength += length;
printf("The File have sended %lld percent\n", sendLength * 100 / nFileLen);
memset(buffer, 0, BUFFER_SIZE);
}
fclose(fp);
printf("File: %s Transfer Successful!\n", argv[1]);
}
closesocket(c_Socket);
//释放winsock库
WSACleanup();

system("pause");
return 0;
}

效果

File Server Demo

Problem

Problem1:

遇到了服务端创建文件成功,但是写入文件失败的情况
Solution:
经过检查发现,是 Linux 接收端的代码出现了问题。我写了一个死循环来实现持续接收文件。但是忘记了在每次接收完文件后使用 fclose()语句来释放文件指针,导致文件写入失败。

iptables 过滤报文

通过使用 iptables 丰富的拓展模块,我们可以实现以下 Task 所要求的内容:

根据字符串过滤

这个实现简单快捷,只需要一条 shell 语句:

1
sudo iptables -t filter -I INPUT -m string --algo bm --string "CyberSecurity" -j REJECT

‘-I INPUT’表示对 INPUT 链进行操作
‘-m string’ 表示使用 string 模块。
‘–algo bm’表示使用 bm 算法去匹配指定的字符串。
‘–string “CyberSecurity”‘则表示我们想要匹配的字符串。
实现效果:
过滤指定字符串

根据时间过滤

这个实现也只需要一条 shell 语句:

1
sudo iptables -t filter -I INPUT -p tcp --dport 28345 -m time --timestart 13:00:00 --timestop 16:00:00 -j REJECT

注意,这里的时间默认使用的是 UTC 标准时间,我们需要将我们想要设定的时间-8(因为我们在东八区)才可以使设置正常生效。
‘-I INPUT’表示对 INPUT 链进行操作
‘-m time’表示使用 time 模块。
‘–timestart’选项用于指定起始时间
‘–timestop’选项用于指定结束时间
实现效果:
过滤指定时间

其余部分

能力有限
时间不足
告辞,有空会回来补的
咕咕咕


评论




博客内容遵循 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 协议

本站使用 Zam's Blog 作为主题,总访问量为
字数统计:47k 载入天数...载入时分秒...