Hello,
I'm having a problem when using a kernel extension that should filter network traffic.
- The kext (through the sftl_filter) starts to filter all packets, and sends them to a process in userspace
- The client performs some operations (in this case, it simply sends the packet data back to the driver unmodified)
- The driver re-injects the modified packet back into the network stream
Incoming data works great. However, uploading data larger than 500kb results in an abruptly closed connection. Smaller files can be uploaded without issue. This is via any protocol, tested on ftp, http, https, etc.
Simplified driver code:
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 and tl_data_out_fn functions are used in sftl_filter. ctl_send is used in kern_ctl_reg as ctl_send_func.
Simplified userspace process code:
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);
}Any help / advice would be appreciated. Kext and userspace process repository.
Thank you