Skip to content

Commit

Permalink
Add support for fast-tracking packets to the Portmaster
Browse files Browse the repository at this point in the history
  • Loading branch information
dhaavi committed Apr 19, 2021
1 parent ba77a6a commit 503dac6
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 42 deletions.
9 changes: 8 additions & 1 deletion include/pm_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ typedef struct {
UINT8 direction;
UINT8 ipV6; //True: IPv6, False: IPv4
UINT8 protocol; //Protocol (UDP, TCP, ...)
UINT8 dummy; //Dummy for alignment
UINT8 flags; //Flags
UINT32 localIP[4]; //Source Address, only srcIP[0] if IPv4
UINT32 remoteIP[4]; //Destination Address
UINT16 localPort; //Source Port
Expand All @@ -40,6 +40,13 @@ typedef struct {
UINT32 packetSize;
} portmaster_packet_info, *pportmaster_packet_info;


/*
* Packet Info Flags
*/
#define PM_STATUS_FAST_TRACK_PERMITTED 0x01
#define PM_STATUS_SOCKET_AUTH 0x02

/*
* IPv4 Header.
*/
Expand Down
119 changes: 78 additions & 41 deletions sys/pm_callouts.c
Original file line number Diff line number Diff line change
Expand Up @@ -868,44 +868,38 @@ FWP_ACTION_TYPE classifySingle(
return FWP_ACTION_BLOCK;
}

// Request verdict from user land.
// Handle packet of unknown connection.
{
PDATA_ENTRY dentry;
pportmaster_packet_info copied_packet_info;
BOOL fast_tracked = FALSE;
UINT32 id;
//char buf[256];
int rc;

// get process ID
// Get the process ID.
if (FWPS_IS_METADATA_FIELD_PRESENT(inMetaValues, FWPS_METADATA_FIELD_PROCESS_ID)) {
packetInfo->processID = inMetaValues->processId;
} else {
packetInfo->processID = 0;
}

// DEBUG: print its TCP 4-tuple
INFO("Getting verdict for %s", print_packet_info(packetInfo));

//Inbound traffic requires special treatment - this bitshifterei is a special source of error ;-)
if (packetInfo->direction == 1) { //Inbound
status = NdisRetreatNetBufferDataStart(nb, ipHeaderSize, 0, NULL);
if (!NT_SUCCESS(status)) {
ERR("failed to retreat net buffer data start");
return FWP_ACTION_NONE;
}
}

status = copy_packet_data_from_nb(nb, 0, &data, &data_len);
if (!NT_SUCCESS(status)) {
ERR("copy_packet_data_from_nb 2: %d", status);
return FWP_ACTION_NONE;
}

INFO("copy_packet_data_from_nb rc=%d, data_len=%d", status, data_len);

// In order to be as clean as possible, we shift back nb, even though it may not be necessary.
if (packetInfo->direction == 1) { //Inbound
NdisAdvanceNetBufferDataStart(nb, ipHeaderSize, 0, NULL);
// Check if the packet is redirected to the Portmaster and can be fast-tracked.
if (
packetInfo->direction == 1 &&
(packetInfo->localPort == PORT_DNS ||
packetInfo->localPort == PORT_PM_API ||
packetInfo->localPort == PORT_PM_SPN_ENTRY) &&
packetInfo->localIP[0] == packetInfo->localIP[0] &&
packetInfo->localIP[1] == packetInfo->localIP[1] &&
packetInfo->localIP[2] == packetInfo->localIP[2] &&
packetInfo->localIP[3] == packetInfo->localIP[3]
) {
fast_tracked = TRUE;
packetInfo->flags |= PM_STATUS_FAST_TRACK_PERMITTED;

INFO("Fast-tracking %s", print_packet_info(packetInfo));
} else {
INFO("Getting verdict for %s", print_packet_info(packetInfo));
}

// allocate queue entry and copy packetInfo
Expand All @@ -917,24 +911,63 @@ FWP_ACTION_TYPE classifySingle(
copied_packet_info = portmaster_malloc(sizeof(portmaster_packet_info), FALSE);
if (!copied_packet_info) {
ERR("Insufficient Resources for mallocating copied_packet_info");
// TODO: free other allocated memory.
return FWP_ACTION_NONE;
}


RtlCopyMemory(copied_packet_info, packetInfo, sizeof(portmaster_packet_info));
copied_packet_info->packetSize = data_len;
dentry->ppacket = copied_packet_info;

//Register Packet
//INFO("packetInfo->compartmentId= %d, ->interfaceIndex= %d, ->subInterfaceIndex= %d", packetInfo->compartmentId, packetInfo->interfaceIndex, packetInfo->subInterfaceIndex);
DEBUG("trying to register packet");
KeAcquireInStackQueuedSpinLock(&packetCacheLock, &lock_handle_pc);
//Lock packet cache because "register_packet" and "clean_packet_cache" must never run simultaniously
//Explicit lock is required, because two or more callouts can run simultaniously
//btw: Never use static variables in callouts ...
copied_packet_info->id = register_packet(packetCache, copied_packet_info, data, data_len);
KeReleaseInStackQueuedSpinLock(&lock_handle_pc);
INFO("registered packet with ID %u: %s", copied_packet_info->id, print_ipv4_packet(data));
// If fast-tracked, add verdict to cache immediately.
if (fast_tracked) {
// Add to verdict cache
KeAcquireInStackQueuedSpinLock(&verdictCacheV4Lock, &lock_handle_vc);
rc = add_verdict(verdictCache, copied_packet_info, PORTMASTER_VERDICT_ACCEPT);
KeReleaseInStackQueuedSpinLock(&lock_handle_vc);

// In case of failure, abort and free copied data.
if (rc != 0) {
ERR("failed to add verdict: %d", rc);
portmaster_free(copied_packet_info);
// TODO: free other allocated memory.
return FWP_ACTION_NONE;
}

} else {
// If not fast-tracked, copy the packet and register it.

//Inbound traffic requires special treatment - this bitshifterei is a special source of error ;-)
if (packetInfo->direction == 1) { //Inbound
status = NdisRetreatNetBufferDataStart(nb, ipHeaderSize, 0, NULL);
if (!NT_SUCCESS(status)) {
ERR("failed to retreat net buffer data start");
// TODO: free other allocated memory.
return FWP_ACTION_NONE;
}
}

// Copy the packet data.
status = copy_packet_data_from_nb(nb, 0, &data, &data_len);
if (!NT_SUCCESS(status)) {
ERR("copy_packet_data_from_nb 2: %d", status);
// TODO: free other allocated memory.
return FWP_ACTION_NONE;
}
copied_packet_info->packetSize = data_len;
INFO("copy_packet_data_from_nb rc=%d, data_len=%d", status, data_len);

// In order to be as clean as possible, we shift back nb, even though it may not be necessary.
if (packetInfo->direction == 1) { //Inbound
NdisAdvanceNetBufferDataStart(nb, ipHeaderSize, 0, NULL);
}

// Register packet.
DEBUG("trying to register packet");
KeAcquireInStackQueuedSpinLock(&packetCacheLock, &lock_handle_pc);
// Explicit lock is required, because two or more callouts can run simultaneously.
copied_packet_info->id = register_packet(packetCache, copied_packet_info, data, data_len);
KeReleaseInStackQueuedSpinLock(&lock_handle_pc);
INFO("registered packet with ID %u: %s", copied_packet_info->id, print_ipv4_packet(data));
}

// send to queue
/* queuedEntries = */ KeInsertQueue(global_io_queue, &(dentry->entry));
Expand All @@ -952,8 +985,11 @@ FWP_ACTION_TYPE classifySingle(
}
}

if (fast_tracked) {
return FWP_ACTION_PERMIT;
}
return FWP_ACTION_NONE;
}
return FWP_ACTION_NONE;
}

void classifyMultiple(
Expand Down Expand Up @@ -1152,7 +1188,8 @@ void classifyMultiple(

default:
// Unexpected value, drop the packet.
break;
classifyOut->actionType = FWP_ACTION_BLOCK;
return;

}
}
Expand Down

0 comments on commit 503dac6

Please sign in to comment.