198 lines
6.4 KiB
C
198 lines
6.4 KiB
C
|
#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;
|
|||
|
}
|