c++ - NKE 套接字过滤器 (MacOS):无法正确重新注入输出数据包
问题描述
使用应过滤网络流量的内核扩展时,我在 MacOS 中遇到问题。
- kext(通过 sftl_filter)开始过滤所有数据包,并将它们发送到用户空间中的进程
- 客户端执行一些操作(在这种情况下,它只是将数据包数据原封不动地发送回驱动程序)
- 驱动程序将修改后的数据包重新注入网络流
传入的数据效果很好。但是,上传大于 500kb 的数据会导致连接突然关闭。可以毫无问题地上传较小的文件。这是通过任何协议,在 ftp、http、https 等上测试的。
简化的驱动程序代码:
errno_t tl_data_fn(void *cookie, socket_t so, const struct sockaddr *addr, mbuf_t *data, mbuf_t *control, sflt_data_flag_t flags, FilterSocketDataDirection direction) {
if (check_tag(data, gidtag, FILTER_TAG_TYPE, direction == FilterSocketDataDirectionIn ? IN_DONE : OUT_DONE)) {
return 0;
}
if (!cookie) return result;
filter_cookie *f_cookie = get_filter_cookie(cookie);
FilterNotification notification;
if (direction == FilterSocketDataDirectionIn) {
notification.event = FilterEventDataIn;
} else {
notification.event = FilterEventDataOut;
}
notification.socketId = (uint64_t)so;
notification.inputoutput.dataSize = (uint32_t)mbuf_pkthdr_len(*data);
mbuf_copydata(*data, offset, notification.inputoutput.dataSize, notification.inputoutput.data);
ctl_enqueuedata(f_cookie->ctl_ref, f_cookie->ctl_unit, ¬ification, sizeof(FilterNotification), CTL_DATA_EOR);
mbuf_freem(*data);
if (control != NULL && *control != NULL)
mbuf_freem(*control);
return EJUSTRETURN;
}
errno_t tl_data_in_fn(void *cookie, socket_t so, const struct sockaddr *from, mbuf_t *data, mbuf_t *control, sflt_data_flag_t flags) {
return tl_data_fn(cookie, so, from, data, control, flags, FilterSocketDataDirectionIn);
}
errno_t tl_data_out_fn(void *cookie, socket_t so, const struct sockaddr *to, mbuf_t *data, mbuf_t *control, sflt_data_flag_t flags) {
return tl_data_fn(cookie, so, to, data, control, flags, FilterSocketDataDirectionOut);
}
errno_t ctl_send(kern_ctl_ref ctl_ref, u_int32_t unit, void *unitinfo, mbuf_t m, int flags) {
FilterClientResponse response;
mbuf_copydata(m, 0, sizeof(response), &response);
mbuf_t data;
mbuf_allocpacket(MBUF_WAITOK, response.dataSize, NULL, &data);
mbuf_copyback(data, 0, response.dataSize, response.data, MBUF_WAITOK);
set_tag(&data, gidtag, FILTER_TAG_TYPE, response.direction == FilterSocketDataDirectionIn ? IN_DONE : OUT_DONE);
if (response.direction == FilterSocketDataDirectionIn) {
sock_inject_data_in((socket_t)response.socketId, NULL, data, NULL, 0);
} else {
sock_inject_data_out((socket_t)response.socketId, NULL, data, NULL, 0);
}
mbuf_freem(m);
return 0;
}
tl_data_in_fn
和tl_data_out_fn
函数用于sftl_filter
. ctl_send
用于kern_ctl_reg
as ctl_send_func
。
简化的用户空间进程代码:
int s = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL);
//connect to driver
FilterNotification notification;
while (recv(s, ¬ification, sizeof(FilterNotification), 0) == sizeof(FilterNotification)) {
FilterClientResponse response;
response.socketId = notification.socketId;
response.direction = (notification.event == FilterEventDataIn) ? FilterSocketDataDirectionIn : FilterSocketDataDirectionOut;
response.dataSize = notification.inputoutput.dataSize;
memcpy(response.data, notification.inputoutput.data, notification.inputoutput.dataSize);
send(s, &response, sizeof(response), 0);
}
任何帮助/建议将不胜感激。Kext 和用户空间进程存储库。
谢谢
解决方案
推荐阅读
- java - Java 8 遍历列表并存储在 Map 中
- java - 归档列表中的未知列 sql 插入错误
- mongodb - 架构验证所需的 Mongoose 数组不起作用
- fonts - 在 mPDF 7 中注册自定义字体时遇到问题
- ssl - haproxy 反向 ssl 终止
- app-store - Xcode 下载失败。使用已购买页面重试
- laravel - querybuilder get() 上的 reverse() 更改收集结果
- javascript - Angular 5 iframe 设置宽度和高度与其内容相同
- reactjs - react-native-navigation 1.1.45 和 RN 0.43 兼容性
- database - DB2 中具有一个可为空列的复合唯一键