a simple p2p message with xor cipher
// p2p.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <limits.h>
#include <ifaddrs.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <netdb.h>
#include <net/if.h>
#define BUFFER_SIZE 1024
#define PORT 36963
#define DEFAULT_KEY "Qk2E@$ilHu#uWUIfrbz#rbID1z"
void open_port(int port);
void check_permissions();
void get_program_directory(char *buffer, size_t buffer_size);
void xor_encrypt_decrypt(const char *input, const char *key, char *output);
void read_key_from_file(const char *filename, char *key, size_t key_size);
void *receive_messages(void *sock_desc);
void *input_thread_func(void *sock_desc_ptr);
void close_sockets(int sock1, int sock2);
void swapFirstLast(char str[]);
void get_ip_address();
// 获取程序目录
void get_program_directory(char *buffer, size_t buffer_size) {
ssize_t size = readlink("/proc/self/exe", buffer, buffer_size);
if (size >= 0) {
buffer[size] = '\0'; // 确保以 null 结尾
char *lastSlash = strrchr(buffer, '/');
if (lastSlash) {
*lastSlash = '\0'; // 保留目录部分
}
}
}
// XOR 加密/解密函数
void xor_encrypt_decrypt(const char *input, const char *key, char *output) {
size_t input_len = strlen(input);
size_t key_len = strlen(key);
for (size_t i = 0; i < input_len; i++) {
output[i] = input[i] ^ key[i % key_len];
}
output[input_len] = '\0';
}
// 读取密钥文件的函数
void read_key_from_file(const char *filename, char *key, size_t key_size) {
char program_dir[PATH_MAX];
get_program_directory(program_dir, sizeof(program_dir));
char filepath[PATH_MAX];
snprintf(filepath, sizeof(filepath), "%s/%s", program_dir, filename);
FILE *file = fopen(filepath, "r");
if (file) {
if (fgets(key, key_size, file) != NULL) {
size_t len = strlen(key);
if (len > 0 && key[len - 1] == '\n') {
key[len - 1] = '\0';
}
} else {
strncpy(key, DEFAULT_KEY, key_size);
}
fclose(file);
} else {
file = fopen(filepath, "w");
if (file) {
fprintf(file, "%s\n", DEFAULT_KEY);
fclose(file);
strncpy(key, DEFAULT_KEY, key_size);
key[key_size - 1] = '\0'; // 确保以 null 结尾
printf("创建新密钥文件 '%s' 并使用默认密钥。\n", filename);
} else {
perror("无法创建密钥文件");
strncpy(key, DEFAULT_KEY, key_size - 1);
key[key_size - 1] = '\0'; // 确保以 null 结尾
}
}
}
// 接收消息的线程函数
void *receive_messages(void *sock_desc) {
int sock = *(int *)sock_desc;
char buffer[BUFFER_SIZE];
char decrypted[BUFFER_SIZE];
char key[BUFFER_SIZE];
read_key_from_file("p2p.key", key, sizeof(key));
while (1) {
int read_size = recv(sock, buffer, sizeof(buffer) - 1, 0);
if (read_size > 0) {
buffer[read_size] = '\0';
xor_encrypt_decrypt(buffer, key, decrypted);
swapFirstLast(key);
printf("\033[2K\033[1G对方发送的消息: %s\n", decrypted);
printf("请输入消息: ");
fflush(stdout);
} else {
if (read_size == 0) {
printf("对方已断开连接\n");
} else {
perror("接收消息失败");
}
break; // 退出循环
}
}
close(sock); // 关闭现有套接字
return NULL;
}
// 用户输入处理线程函数
void *input_thread_func(void *sock_desc_ptr) {
int *sock_desc = (int *)sock_desc_ptr;
char message[BUFFER_SIZE];
char key[BUFFER_SIZE];
read_key_from_file("p2p.key", key, sizeof(key));
while (1) {
printf("请输入消息: ");
fflush(stdout);
if (fgets(message, sizeof(message), stdin) == NULL) {
perror("读取输入失败");
break;
}
message[strcspn(message, "\n")] = 0; // 移除换行符
if (strlen(message) == 0) {
continue; // 继续下一轮循环
}
char encrypted[BUFFER_SIZE];
xor_encrypt_decrypt(message, key, encrypted);
ssize_t sent_bytes = send(*sock_desc, encrypted, strlen(encrypted), 0);
if (sent_bytes == strlen(encrypted)) {
swapFirstLast(key);
}
}
return NULL;
}
int main(int argc, char *argv[]) {
check_permissions();
open_port(PORT);
printf("端口已成功打开。\n");
char key[BUFFER_SIZE];
read_key_from_file("p2p.key", key, sizeof(key)); // 读取密钥
struct sockaddr_in server_addr, client_addr;
if (argc > 1) {
const char *server_ip = argv[1];
int sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
perror("创建 socket 失败");
return 1;
}
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(PORT);
inet_pton(AF_INET, server_ip, &server_addr.sin_addr);
if (connect(sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
perror("连接失败");
close(sock);
return 1;
} else {
printf("连接成功\n");
pthread_t recv_thread, input_thread;
pthread_create(&recv_thread, NULL, receive_messages, (void *)&sock);
pthread_create(&input_thread, NULL, input_thread_func, (void *)&sock);
pthread_join(recv_thread, NULL);
pthread_cancel(input_thread); // 取消输入线程,确保退出
pthread_join(input_thread, NULL);
close(sock);
return 0;
}
}
// 进入服务器模式
while (1) {
int listen_sock = socket(AF_INET, SOCK_STREAM, 0);
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(PORT);
int opt = 1;
if (setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
perror("setsockopt failed");
close(listen_sock);
exit(EXIT_FAILURE);
}
if (bind(listen_sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
perror("绑定失败");
close(listen_sock);
continue; // 返回循环以重新绑定
}
listen(listen_sock, 3);
printf("本机为服务端\n");
get_ip_address();
printf("等待连接...\n");
int addr_len = sizeof(client_addr);
int new_socket = accept(listen_sock, (struct sockaddr *)&client_addr, (socklen_t*)&addr_len);
if (new_socket < 0) {
perror("接收连接失败");
close(listen_sock);
continue; // 返回循环以等待下一个连接
}
printf("连接成功\n");
pthread_t recv_thread, input_thread;
pthread_create(&recv_thread, NULL, receive_messages, (void *)&new_socket);
pthread_create(&input_thread, NULL, input_thread_func, (void *)&new_socket);
pthread_join(recv_thread, NULL);
pthread_cancel(input_thread); // 取消输入线程,确保退出
pthread_join(input_thread, NULL);
close_sockets(new_socket, listen_sock); // 关闭套接字
}
return 0;
}
// 打开端口
void open_port(int port) {
char command[100];
snprintf(command, sizeof(command), "iptables -A INPUT -p tcp --dport %d -j ACCEPT", port);
int result = system(command);
if (result == -1 || WEXITSTATUS(result) != 0) {
fprintf(stderr, "执行打开 TCP 端口命令失败. 退出.\n");
exit(EXIT_FAILURE);
}
}
// 权限检查函数
void check_permissions() {
if (getuid() != 0) {
fprintf(stderr, "您必须以管理员身份运行此程序.\n");
exit(EXIT_FAILURE);
}
}
// 关闭套接字的函数
void close_sockets(int sock1, int sock2) {
close(sock1);
close(sock2);
}
void swapFirstLast(char str[]) {
int length = strlen(str);
if (length > 1) {
char temp = str[0];
str[0] = str[length - 1];
str[length - 1] = temp;
}
}
void get_ip_address() {
struct ifaddrs *addrs;
char ip[INET_ADDRSTRLEN];
// 获取所有网络接口的地址信息
if (getifaddrs(&addrs) == -1) {
perror("getifaddrs");
exit(EXIT_FAILURE);
}
// 遍历每个接口
for (struct ifaddrs *tmp = addrs; tmp != NULL; tmp = tmp->ifa_next) {
// 只处理IPv4地址,并且接口是活动的
if (tmp->ifa_addr && tmp->ifa_addr->sa_family == AF_INET) {
if (getnameinfo(tmp->ifa_addr, sizeof(struct sockaddr_in), ip, sizeof(ip), NULL, 0, NI_NUMERICHOST) == 0) {
// 检查接口是否是活动的
if (tmp->ifa_flags & IFF_UP) {
printf("Interface: %s, IP Address: %s\n", tmp->ifa_name, ip);
}
}
}
}
// 释放内存
freeifaddrs(addrs);
}