windows-nt/Source/XPSP1/NT/net/tcpip/driver/tcp/secfltr.c
2020-09-26 16:20:57 +08:00

1316 lines
38 KiB
C

/********************************************************************/
/** Microsoft LAN Manager **/
/** Copyright(c) Microsoft Corp., 1990-1993 **/
/********************************************************************/
/* :ts=4 */
//** SECFLTR.C - Security Filter Support
//
//
// Security filters provide a mechanism by which the transport protocol
// traffic accepted on IP interfaces may be controlled. Security filtering
// is globally enabled or disabled for all IP interfaces and transports.
// If filtering is enabled, incoming traffic is filtered based on registered
// {interface, protocol, transport value} tuples. The tuples specify
// permissible traffic. All other values will be rejected. For UDP datagrams
// and TCP connections, the transport value is the port number. For RawIP
// datagrams, the transport value is the IP protocol number. An entry exists
// in the filter database for all active interfaces and protocols in the
// system.
//
// The initial status of security filtering - enabled or disabled, is
// controlled by the registry parameter
//
// Services\Tcpip\Parameters\EnableSecurityFilters
//
// If the parameter is not found, filtering is disabled.
//
// The list of permissible values for each protocol is stored in the registry
// under the <Adaptername>\Parameters\Tcpip key in MULTI_SZ parameters.
// The parameter names are TCPAllowedPorts, UDPAllowedPorts and
// RawIPAllowedProtocols. If no parameter is found for a particular protocol,
// all values are permissible. If a parameter is found, the string identifies
// the permissible values. If the string is empty, no values are permissible.
//
// Filter Operation (Filtering Enabled):
//
// IF ( Match(interface, protocol) AND ( AllValuesPermitted(Protocol) OR
// Match(Value) ))
// THEN operation permitted.
// ELSE operation rejected.
//
// Database Implementation:
//
// The filter database is implemented as a three-level structure. The top
// level is a list of interface entries. Each interface entry points to
// a list of protocol entries. Each protocol entry contains a bucket hash
// table used to store transport value entries.
//
// The following calls may be used to access the security filter database:
//
// InitializeSecurityFilters
// CleanupSecurityFilters
// IsSecurityFilteringEnabled
// ControlSecurityFiltering
// AddProtocolSecurityFilter
// DeleteProtocolSecurityFilter
// AddValueSecurityFilter
// DeleteValueSecurityFilter
// EnumerateSecurityFilters
// IsPermittedSecurityFilter
//
#include "precomp.h"
#include "addr.h"
#include "tlcommon.h"
#include "udp.h"
#include "tcp.h"
#include "raw.h"
#include "tcpcfg.h"
#include "tcpinfo.h"
#include "secfltr.h"
//
// All of the init code can be discarded.
//
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT, InitializeSecurityFilters)
#endif
//
// The following routines must be supplied by each platform which implements
// security filters.
//
extern TDI_STATUS
GetSecurityFilterList(
IN NDIS_HANDLE ConfigHandle,
IN ulong Protocol,
IN OUT PNDIS_STRING FilterList
);
extern uint
EnumSecurityFilterValue(
IN PNDIS_STRING FilterList,
IN ulong Index,
OUT ulong * FilterValue
);
//
// Constants
//
#define DHCP_CLIENT_PORT 68
//
// Modification Opcodes
//
#define ADD_VALUE_SECURITY_FILTER 0
#define DELETE_VALUE_SECURITY_FILTER 1
//
// Types
//
//
// Structure for a transport value entry.
//
struct value_entry {
struct Queue ve_link;
ulong ve_value;
};
typedef struct value_entry VALUE_ENTRY, *PVALUE_ENTRY;
#define VALUE_ENTRY_HASH_SIZE 16
#define VALUE_ENTRY_HASH(value) (value % VALUE_ENTRY_HASH_SIZE)
//
// Structure for a protocol entry.
//
struct protocol_entry {
struct Queue pe_link;
ulong pe_protocol;
ULONG pe_accept_all; // TRUE if all values are accepted.
struct Queue pe_entries[VALUE_ENTRY_HASH_SIZE];
};
typedef struct protocol_entry PROTOCOL_ENTRY, *PPROTOCOL_ENTRY;
//
// Structure for an interface entry.
//
struct interface_entry {
struct Queue ie_link;
IPAddr ie_address;
struct Queue ie_protocol_list; // list of protocols to filter
};
typedef struct interface_entry INTERFACE_ENTRY, *PINTERFACE_ENTRY;
//
// Global Data
//
//
// This list of interface entries is the root of the filter database.
//
struct Queue InterfaceEntryList;
//
// The filter operations are synchronized using the AddrObjTableLock.
//
extern IPInfo LocalNetInfo;
//
// Filter Database Helper Functions
//
//* FindInterfaceEntry - Search for an interface entry.
//
// This utility routine searches the security filter database
// for the specified interface entry.
//
//
// Input: InterfaceAddress - The address of the interface to search for.
//
//
// Returns: A pointer to the database entry for the Interface,
// or NULL if no match was found.
//
//
PINTERFACE_ENTRY
FindInterfaceEntry(ULONG InterfaceAddress)
{
PINTERFACE_ENTRY ientry;
struct Queue *qentry;
for (qentry = InterfaceEntryList.q_next;
qentry != &InterfaceEntryList;
qentry = qentry->q_next
) {
ientry = STRUCT_OF(INTERFACE_ENTRY, qentry, ie_link);
if (ientry->ie_address == InterfaceAddress) {
return (ientry);
}
}
return (NULL);
}
//* FindProtocolEntry - Search for a protocol associated with an interface.
//
// This utility routine searches the security filter database
// for the specified protocol registered under the specified interface.
//
//
// Input: InterfaceEntry - A pointer to an interface entry to search under.
// Protocol - The protocol value to search for.
//
//
// Returns: A pointer to the database entry for the <Address, Protocol>,
// or NULL if no match was found.
//
//
PPROTOCOL_ENTRY
FindProtocolEntry(PINTERFACE_ENTRY InterfaceEntry, ULONG Protocol)
{
PPROTOCOL_ENTRY pentry;
struct Queue *qentry;
for (qentry = InterfaceEntry->ie_protocol_list.q_next;
qentry != &(InterfaceEntry->ie_protocol_list);
qentry = qentry->q_next
) {
pentry = STRUCT_OF(PROTOCOL_ENTRY, qentry, pe_link);
if (pentry->pe_protocol == Protocol) {
return (pentry);
}
}
return (NULL);
}
//* FindValueEntry - Search for a value on a particular protocol.
//
// This utility routine searches the security filter database
// for the specified value registered under the specified protocol.
//
//
// Input: ProtocolEntry - A pointer to the database structure for the
// Protocol to search.
// FilterValue - The value to search for.
//
//
// Returns: A pointer to the database entry for the <Protocol, Value>,
// or NULL if no match was found.
//
//
PVALUE_ENTRY
FindValueEntry(PPROTOCOL_ENTRY ProtocolEntry, ULONG FilterValue)
{
PVALUE_ENTRY ventry;
ulong hash_value = VALUE_ENTRY_HASH(FilterValue);
struct Queue *qentry;
for (qentry = ProtocolEntry->pe_entries[hash_value].q_next;
qentry != &(ProtocolEntry->pe_entries[hash_value]);
qentry = qentry->q_next
) {
ventry = STRUCT_OF(VALUE_ENTRY, qentry, ve_link);
if (ventry->ve_value == FilterValue) {
return (ventry);
}
}
return (NULL);
}
//* DeleteProtocolValueEntries
//
// This utility routine deletes all the value entries associated with
// a protocol filter entry.
//
//
// Input: ProtocolEntry - The protocol filter entry for which to
// delete the value entries.
//
//
// Returns: Nothing
//
void
DeleteProtocolValueEntries(PPROTOCOL_ENTRY ProtocolEntry)
{
ulong i;
PVALUE_ENTRY entry;
for (i = 0; i < VALUE_ENTRY_HASH_SIZE; i++) {
while (!EMPTYQ(&(ProtocolEntry->pe_entries[i]))) {
DEQUEUE(&(ProtocolEntry->pe_entries[i]), entry, VALUE_ENTRY, ve_link);
CTEFreeMem(entry);
}
}
return;
}
//* ModifyProtocolEntry
//
// This utility routine modifies one or more filter values associated
// with a protocol.
//
//
// Input: Operation - The operation to perform (add or delete)
//
// ProtocolEntry - A pointer to the protocol entry structure on
// which to operate.
//
// FilterValue - The value to add or delete.
//
//
// Returns: TDI_STATUS code
//
TDI_STATUS
ModifyProtocolEntry(ulong Operation, PPROTOCOL_ENTRY ProtocolEntry,
ulong FilterValue)
{
TDI_STATUS status = TDI_SUCCESS;
if (FilterValue == 0) {
if (Operation == ADD_VALUE_SECURITY_FILTER) {
//
// Accept all values for the protocol
//
ProtocolEntry->pe_accept_all = TRUE;
} else {
//
// Reject all values for the protocol
//
ProtocolEntry->pe_accept_all = FALSE;
}
DeleteProtocolValueEntries(ProtocolEntry);
} else {
PVALUE_ENTRY ventry;
ulong hash_value;
//
// This request modifies an individual entry.
//
ventry = FindValueEntry(ProtocolEntry, FilterValue);
if (Operation == ADD_VALUE_SECURITY_FILTER) {
if (ventry == NULL) {
ventry = CTEAllocMem(sizeof(VALUE_ENTRY));
if (ventry != NULL) {
ventry->ve_value = FilterValue;
hash_value = VALUE_ENTRY_HASH(FilterValue);
ENQUEUE(&(ProtocolEntry->pe_entries[hash_value]),
&(ventry->ve_link));
ProtocolEntry->pe_accept_all = FALSE;
} else {
status = TDI_NO_RESOURCES;
}
}
} else {
if (ventry != NULL) {
REMOVEQ(&(ventry->ve_link));
CTEFreeMem(ventry);
}
}
}
return (status);
}
//* ModifyInterfaceEntry
//
// This utility routine modifies the value entries of one or more protocol
// entries associated with an interface.
//
//
// Input: Operation - The operation to perform (add or delete)
//
// ProtocolEntry - A pointer to the interface entry structure on
// which to operate.
//
// Protocol - The protocol on which to operate.
//
// FilterValue - The value to add or delete.
//
//
// Returns: TDI_STATUS code
//
TDI_STATUS
ModifyInterfaceEntry(ulong Operation, PINTERFACE_ENTRY InterfaceEntry,
ulong Protocol, ulong FilterValue)
{
PPROTOCOL_ENTRY pentry;
TDI_STATUS status;
TDI_STATUS returnStatus = TDI_SUCCESS;
if (Protocol == 0) {
struct Queue *qentry;
//
// Modify all protocols on the interface
//
for (qentry = InterfaceEntry->ie_protocol_list.q_next;
qentry != &(InterfaceEntry->ie_protocol_list);
qentry = qentry->q_next
) {
pentry = STRUCT_OF(PROTOCOL_ENTRY, qentry, pe_link);
status = ModifyProtocolEntry(Operation, pentry, FilterValue);
if (status != TDI_SUCCESS) {
returnStatus = status;
}
}
} else {
//
// Modify a specific protocol on the interface
//
pentry = FindProtocolEntry(InterfaceEntry, Protocol);
if (pentry != NULL) {
returnStatus = ModifyProtocolEntry(Operation, pentry, FilterValue);
} else {
returnStatus = TDI_INVALID_PARAMETER;
}
}
return (returnStatus);
}
//* ModifySecurityFilter - Add or delete an entry.
//
// This routine adds or deletes an entry to/from the security filter database.
//
//
// Input: Operation - The operation to perform (Add or Delete)
// InterfaceAddress - The interface address to modify.
// Protocol - The protocol to modify.
// FilterValue - The transport value to add/delete.
//
// Returns: A TDI status code:
// TDI_INVALID_PARAMETER if the protocol is not in the database.
// TDI_ADDR_INVALID if the interface is not in the database.
// TDI_NO_RESOURCES if memory could not be allocated.
// TDI_SUCCESS otherwise
//
// NOTES:
//
TDI_STATUS
ModifySecurityFilter(ulong Operation, IPAddr InterfaceAddress, ulong Protocol,
ulong FilterValue)
{
PINTERFACE_ENTRY ientry;
TDI_STATUS status;
TDI_STATUS returnStatus = TDI_SUCCESS;
if (InterfaceAddress == 0) {
struct Queue *qentry;
//
// Modify on all interfaces
//
for (qentry = InterfaceEntryList.q_next;
qentry != &InterfaceEntryList;
qentry = qentry->q_next
) {
ientry = STRUCT_OF(INTERFACE_ENTRY, qentry, ie_link);
status = ModifyInterfaceEntry(Operation, ientry, Protocol,
FilterValue);
if (status != TDI_SUCCESS) {
returnStatus = status;
}
}
} else {
ientry = FindInterfaceEntry(InterfaceAddress);
if (ientry != NULL) {
returnStatus = ModifyInterfaceEntry(Operation, ientry, Protocol,
FilterValue);
} else {
returnStatus = TDI_ADDR_INVALID;
}
}
return (returnStatus);
}
//* FillInEnumerationEntry
//
// This utility routine fills in an enumeration entry for a particular
// filter value entry.
//
//
// Input: InterfaceAddress - The address of the associated interface.
//
// Protocol - The associated protocol number.
//
// Value - The enumerated value.
//
// Buffer - Pointer to the user's enumeration buffer.
//
// BufferSize - Pointer to the size of the enumeration buffer.
//
// EntriesReturned - Pointer to a running count of enumerated
// entries stored in Buffer.
//
// EntriesAvailable - Pointer to a running count of entries available
// for enumeration.
//
// Returns: Nothing.
//
// Note: Values written to enumeration entry are in host byte order.
//
void
FillInEnumerationEntry(IPAddr InterfaceAddress, ulong Protocol, ulong Value,
uchar ** Buffer, ulong * BufferSize,
ulong * EntriesReturned, ulong * EntriesAvailable)
{
TCPSecurityFilterEntry *entry = (TCPSecurityFilterEntry *) * Buffer;
if (*BufferSize >= sizeof(TCPSecurityFilterEntry)) {
entry->tsf_address = net_long(InterfaceAddress);
entry->tsf_protocol = Protocol;
entry->tsf_value = Value;
*Buffer += sizeof(TCPSecurityFilterEntry);
*BufferSize -= sizeof(TCPSecurityFilterEntry);
(*EntriesReturned)++;
}
(*EntriesAvailable)++;
return;
}
//* EnumerateProtocolValues
//
// This utility routine enumerates values associated with a
// protocol on an interface.
//
//
// Input: InterfaceEntry - Pointer to the associated interface entry.
//
// ProtocolEntry - Pointer to the protocol being enumerated.
//
// Value - The value to enumerate.
//
// Buffer - Pointer to the user's enumeration buffer.
//
// BufferSize - Pointer to the size of the enumeration buffer.
//
// EntriesReturned - Pointer to a running count of enumerated
// entries stored in Buffer.
//
// EntriesAvailable - Pointer to a running count of entries available
// for enumeration.
//
// Returns: Nothing.
//
void
EnumerateProtocolValues(PINTERFACE_ENTRY InterfaceEntry,
PPROTOCOL_ENTRY ProtocolEntry, ulong Value,
uchar ** Buffer, ulong * BufferSize,
ulong * EntriesReturned, ulong * EntriesAvailable)
{
struct Queue *qentry;
TDI_STATUS status = TDI_SUCCESS;
PVALUE_ENTRY ventry;
ulong i;
if (Value == 0) {
//
// Enumerate all values
//
if (ProtocolEntry->pe_accept_all == TRUE) {
//
// All values permitted.
//
FillInEnumerationEntry(
InterfaceEntry->ie_address,
ProtocolEntry->pe_protocol,
0,
Buffer,
BufferSize,
EntriesReturned,
EntriesAvailable
);
} else {
for (i = 0; i < VALUE_ENTRY_HASH_SIZE; i++) {
for (qentry = ProtocolEntry->pe_entries[i].q_next;
qentry != &(ProtocolEntry->pe_entries[i]);
qentry = qentry->q_next
) {
ventry = STRUCT_OF(VALUE_ENTRY, qentry, ve_link);
FillInEnumerationEntry(
InterfaceEntry->ie_address,
ProtocolEntry->pe_protocol,
ventry->ve_value,
Buffer,
BufferSize,
EntriesReturned,
EntriesAvailable
);
}
}
}
} else {
//
// Enumerate a specific value, if it is registered.
//
ventry = FindValueEntry(ProtocolEntry, Value);
if (ventry != NULL) {
FillInEnumerationEntry(
InterfaceEntry->ie_address,
ProtocolEntry->pe_protocol,
ventry->ve_value,
Buffer,
BufferSize,
EntriesReturned,
EntriesAvailable
);
}
}
return;
}
//* EnumerateInterfaceProtocols
//
// This utility routine enumerates protocols associated with
// an interface.
//
//
// Input: InterfaceEntry - Pointer to the associated interface entry.
//
// Protocol - Protocol number to enumerate.
//
// Value - The filter value to enumerate.
//
// Buffer - Pointer to the user's enumeration buffer.
//
// BufferSize - Pointer to the size of the enumeration buffer.
//
// EntriesReturned - Pointer to a running count of enumerated
// entries stored in Buffer.
//
// EntriesAvailable - Pointer to a running count of entries available
// for enumeration.
//
// Returns: Nothing.
//
void
EnumerateInterfaceProtocols(PINTERFACE_ENTRY InterfaceEntry, ulong Protocol,
ulong Value, uchar ** Buffer, ulong * BufferSize,
ulong * EntriesReturned, ulong * EntriesAvailable)
{
PPROTOCOL_ENTRY pentry;
if (Protocol == 0) {
struct Queue *qentry;
//
// Enumerate all protocols.
//
for (qentry = InterfaceEntry->ie_protocol_list.q_next;
qentry != &(InterfaceEntry->ie_protocol_list);
qentry = qentry->q_next
) {
pentry = STRUCT_OF(PROTOCOL_ENTRY, qentry, pe_link);
EnumerateProtocolValues(
InterfaceEntry,
pentry,
Value,
Buffer,
BufferSize,
EntriesReturned,
EntriesAvailable
);
}
} else {
//
// Enumerate a specific protocol
//
pentry = FindProtocolEntry(InterfaceEntry, Protocol);
if (pentry != NULL) {
EnumerateProtocolValues(
InterfaceEntry,
pentry,
Value,
Buffer,
BufferSize,
EntriesReturned,
EntriesAvailable
);
}
}
return;
}
//
// Filter Database Public API.
//
//* InitializeSecurityFilters - Initializes the security filter database.
//
// The routine performs the initialization necessary to enable the
// security filter database for operation.
//
// Input: None.
//
// Returns: Nothing.
//
//
void
InitializeSecurityFilters(void)
{
INITQ(&InterfaceEntryList);
return;
}
//* CleanupSecurityFilters - Deletes the entire security filter database.
//
// This routine deletes all entries from the security filter database.
//
//
// Input: None.
//
// Returns: Nothing.
//
// NOTE: This routine acquires the AddrObjTableLock.
//
//
void
CleanupSecurityFilters(void)
{
PPROTOCOL_ENTRY pentry;
PINTERFACE_ENTRY ientry;
CTELockHandle handle;
CTEGetLock(&AddrObjTableLock.Lock, &handle);
while (!EMPTYQ(&InterfaceEntryList)) {
DEQUEUE(&InterfaceEntryList, ientry, INTERFACE_ENTRY, ie_link);
while (!EMPTYQ(&(ientry->ie_protocol_list))) {
DEQUEUE(&(ientry->ie_protocol_list), pentry, PROTOCOL_ENTRY,
pe_link);
DeleteProtocolValueEntries(pentry);
CTEFreeMem(pentry);
}
CTEFreeMem(ientry);
}
SecurityFilteringEnabled = FALSE;
CTEFreeLock(&AddrObjTableLock.Lock, handle);
return;
}
//* IsSecurityFilteringEnabled
//
// This routine returns the current global status of security filtering.
//
// Entry: Nothing
//
// Returns: 0 if filtering is disabled, !0 if filtering is enabled.
//
extern uint
IsSecurityFilteringEnabled(void)
{
uint enabled;
CTELockHandle handle;
CTEGetLock(&AddrObjTableLock.Lock, &handle);
enabled = SecurityFilteringEnabled;
CTEFreeLock(&AddrObjTableLock.Lock, handle);
return (enabled);
}
//* ControlSecurityFiltering
//
// This routine globally enables/disables security filtering.
//
// Entry: IsEnabled - 0 disabled filtering, !0 enables filtering.
//
// Returns: Nothing
//
extern void
ControlSecurityFiltering(uint IsEnabled)
{
CTELockHandle handle;
CTEGetLock(&AddrObjTableLock.Lock, &handle);
if (IsEnabled) {
SecurityFilteringEnabled = TRUE;
} else {
SecurityFilteringEnabled = FALSE;
}
CTEFreeLock(&AddrObjTableLock.Lock, handle);
return;
}
//* AddProtocolSecurityFilter
//
// This routine enables security filtering for a specified protocol
// on a specified IP interface.
//
// Entry: InterfaceAddress - The interface on which to enable the protocol.
// (in network byte order)
// Protocol - The protocol to enable.
// ConfigName - The configuration key from which to read
// the filter value information.
//
// Returns: Nothing
//
void
AddProtocolSecurityFilter(IPAddr InterfaceAddress, ulong Protocol,
NDIS_HANDLE ConfigHandle)
{
NDIS_STRING filterList;
ulong filterValue;
ulong i;
PINTERFACE_ENTRY ientry;
PPROTOCOL_ENTRY pentry;
PVOID temp;
CTELockHandle handle;
TDI_STATUS status;
if (IP_ADDR_EQUAL(InterfaceAddress, NULL_IP_ADDR) ||
IP_LOOPBACK_ADDR(InterfaceAddress)
) {
return;
}
ASSERT((Protocol != 0) && (Protocol <= 0xFF));
//
// Read the protocol-specific filter value list from the registry.
//
filterList.MaximumLength = filterList.Length = 0;
filterList.Buffer = NULL;
if (ConfigHandle != NULL) {
status = GetSecurityFilterList(ConfigHandle, Protocol, &filterList);
}
//
// Preallocate interface & protocol structures. We abort on failure.
// The interface & protocol will be protected by default.
//
ientry = CTEAllocMem(sizeof(INTERFACE_ENTRY));
if (ientry == NULL) {
return;
}
ientry->ie_address = InterfaceAddress;
INITQ(&(ientry->ie_protocol_list));
pentry = CTEAllocMem(sizeof(PROTOCOL_ENTRY));
if (pentry == NULL) {
CTEFreeMem(ientry);
return;
}
pentry->pe_protocol = Protocol;
pentry->pe_accept_all = FALSE;
for (i = 0; i < VALUE_ENTRY_HASH_SIZE; i++) {
INITQ(&(pentry->pe_entries[i]));
}
//
// Now go set everything up. First create the interface and protocol
// structures.
//
CTEGetLock(&AddrObjTableLock.Lock, &handle);
temp = FindInterfaceEntry(InterfaceAddress);
if (temp == NULL) {
//
// New interface & protocol.
//
ENQUEUE(&InterfaceEntryList, &(ientry->ie_link));
ENQUEUE(&(ientry->ie_protocol_list), &(pentry->pe_link));
} else {
//
// Existing interface
//
CTEFreeMem(ientry);
ientry = temp;
temp = FindProtocolEntry(ientry, Protocol);
if (temp == NULL) {
//
// New protocol
//
ENQUEUE(&(ientry->ie_protocol_list), &(pentry->pe_link));
} else {
//
// Existing protocol
//
CTEFreeMem(pentry);
}
}
CTEFreeLock(&AddrObjTableLock.Lock, handle);
//
// At this point, the protocol entry is installed, but no values
// are permitted. This is the safest default.
//
if (ConfigHandle != NULL) {
//
// Process the filter value list.
//
if (status == TDI_SUCCESS) {
for (i = 0;
EnumSecurityFilterValue(&filterList, i, &filterValue);
i++
) {
AddValueSecurityFilter(InterfaceAddress, Protocol,
filterValue);
}
} else if (status == TDI_ITEM_NOT_FOUND) {
//
// No filter registered, permit everything.
//
AddValueSecurityFilter(InterfaceAddress, Protocol, 0);
}
}
if (filterList.Buffer != NULL) {
CTEFreeMem(filterList.Buffer);
}
return;
}
//* DeleteProtocolSecurityFilter
//
// This routine disables security filtering for a specified protocol
// on a specified IP interface.
//
// Entry: InterfaceAddress - The interface on which to disable the protocol.
// (in network byte order)
// Protocol - The protocol to disable.
//
// Returns: Nothing
//
void
DeleteProtocolSecurityFilter(IPAddr InterfaceAddress, ulong Protocol)
{
PINTERFACE_ENTRY ientry;
PPROTOCOL_ENTRY pentry;
CTELockHandle handle;
BOOLEAN deleteInterface = FALSE;
CTEGetLock(&AddrObjTableLock.Lock, &handle);
ientry = FindInterfaceEntry(InterfaceAddress);
if (ientry != NULL) {
ASSERT(!EMPTYQ(&(ientry->ie_protocol_list)));
pentry = FindProtocolEntry(ientry, Protocol);
if (pentry != NULL) {
REMOVEQ(&(pentry->pe_link));
}
if (EMPTYQ(&(ientry->ie_protocol_list))) {
//
// Last protocol, delete interface as well.
//
REMOVEQ(&(ientry->ie_link));
deleteInterface = TRUE;
}
CTEFreeLock(&AddrObjTableLock.Lock, handle);
if (pentry != NULL) {
DeleteProtocolValueEntries(pentry);
CTEFreeMem(pentry);
}
if (deleteInterface) {
ASSERT(EMPTYQ(&(ientry->ie_protocol_list)));
CTEFreeMem(ientry);
}
} else {
CTEFreeLock(&AddrObjTableLock.Lock, handle);
}
return;
}
//* AddValueSecurityFilter - Add an entry.
//
// This routine adds a value entry for a specified protocol on a specified
// interface in the security filter database.
//
//
// Input: InterfaceAddress - The interface address to which to add.
// (in network byte order)
// Protocol - The protocol to which to add.
// FilterValue - The transport value to add.
// (in host byte order)
//
// Returns: A TDI status code:
// TDI_INVALID_PARAMETER if the protocol is not in the database.
// TDI_ADDR_INVALID if the interface is not in the database.
// TDI_NO_RESOURCES if memory could not be allocated.
// TDI_SUCCESS otherwise
//
// NOTES:
//
// This routine acquires AddrObjTableLock.
//
// Zero is a wildcard value. Supplying a zero value for the
// InterfaceAddress and/or Protocol causes the operation to be applied
// to all interfaces and/or protocols, as appropriate. Supplying a
// non-zero value causes the operation to be applied to only the
// specified interface and/or protocol. Supplying a FilterValue parameter
// of zero causes all values to be acceptable. Any previously
// registered values are deleted from the database.
//
TDI_STATUS
AddValueSecurityFilter(IPAddr InterfaceAddress, ulong Protocol, ulong FilterValue)
{
CTELockHandle handle;
TDI_STATUS status;
CTEGetLock(&AddrObjTableLock.Lock, &handle);
status = ModifySecurityFilter(ADD_VALUE_SECURITY_FILTER, InterfaceAddress,
Protocol, FilterValue);
CTEFreeLock(&AddrObjTableLock.Lock, handle);
return (status);
}
//* DeleteValueSecurityFilter - Delete an entry.
//
// This routine deletes a value entry for a specified protocol on a specified
// interface in the security filter database.
//
//
// Input: InterfaceAddress - The interface address from which to delete.
// (in network byte order)
// Protocol - The protocol from which to delete.
// FilterValue - The transport value to delete.
// (in host byte order)
//
// Returns: A TDI status code:
// TDI_INVALID_PARAMETER if the protocol is not in the database.
// TDI_ADDR_INVALID if the interface is not in the database.
// TDI_NO_RESOURCES if memory could not be allocated.
// TDI_SUCCESS otherwise
//
// NOTES:
//
// This routine acquires AddrObjTableLock.
//
// Zero is a wildcard value. Supplying a zero value for the
// InterfaceAddress and/or Protocol causes the operation to be applied
// to all interfaces and/or protocols, as appropriate. Supplying a
// non-zero value causes the operation to be applied to only the
// specified interface and/or protocol. Supplying a FilterValue parameter
// of zero causes all values to be rejected. Any previously
// registered values are deleted from the database.
//
TDI_STATUS
DeleteValueSecurityFilter(IPAddr InterfaceAddress, ulong Protocol,
ulong FilterValue)
{
CTELockHandle handle;
TDI_STATUS status;
CTEGetLock(&AddrObjTableLock.Lock, &handle);
status = ModifySecurityFilter(DELETE_VALUE_SECURITY_FILTER,
InterfaceAddress, Protocol, FilterValue);
CTEFreeLock(&AddrObjTableLock.Lock, handle);
return (status);
}
//* EnumerateSecurityFilters - Enumerate security filter database.
//
// This routine enumerates the contents of the security filter database
// for the specified protocol and IP interface.
//
// Input: InterfaceAddress - The interface address to enumerate. A value
// of zero means enumerate all interfaces.
// (in network byte order)
//
// Protocol - The protocol to enumerate. A value of zero
// means enumerate all protocols.
//
// Value - The Protocol value to enumerate. A value of
// zero means enumerate all protocol values.
// (in host byte order)
//
// Buffer - A pointer to a buffer into which to put
// the returned filter entries.
//
// BufferSize - On input, the size in bytes of Buffer.
// On output, the number of bytes written.
//
// EntriesAvailable - On output, the total number of filter entries
// available in the database.
//
// Returns: A TDI status code:
//
// TDI_ADDR_INVALID if the address is not a valid IP interface.
// TDI_SUCCESS otherwise.
//
// NOTES:
//
// This routine acquires AddrObjTableLock.
//
// Entries written to output buffer are in host byte order.
//
void
EnumerateSecurityFilters(IPAddr InterfaceAddress, ulong Protocol,
ulong Value, uchar * Buffer, ulong BufferSize,
ulong * EntriesReturned, ulong * EntriesAvailable)
{
PINTERFACE_ENTRY ientry;
TDI_STATUS status = TDI_SUCCESS;
CTELockHandle handle;
*EntriesAvailable = *EntriesReturned = 0;
CTEGetLock(&AddrObjTableLock.Lock, &handle);
if (InterfaceAddress == 0) {
struct Queue *qentry;
//
// Enumerate all interfaces.
//
for (qentry = InterfaceEntryList.q_next;
qentry != &InterfaceEntryList;
qentry = qentry->q_next
) {
ientry = STRUCT_OF(INTERFACE_ENTRY, qentry, ie_link);
EnumerateInterfaceProtocols(
ientry,
Protocol,
Value,
&Buffer,
&BufferSize,
EntriesReturned,
EntriesAvailable
);
}
} else {
//
// Enumerate a specific interface.
//
ientry = FindInterfaceEntry(InterfaceAddress);
if (ientry != NULL) {
EnumerateInterfaceProtocols(
ientry,
Protocol,
Value,
&Buffer,
&BufferSize,
EntriesReturned,
EntriesAvailable
);
}
}
CTEFreeLock(&AddrObjTableLock.Lock, handle);
return;
}
//* IsPermittedSecurityFilter
//
// This routine determines if communications addressed to
// {Protocol, InterfaceAddress, Value} are permitted by the security filters.
// It looks up the tuple in the security filter database.
//
// Input: InterfaceAddress - The IP interface address to check
// (in network byte order)
// IPContext - The IPContext value passed to the transport
// Protocol - The protocol to check
// Value - The value to check (in host byte order)
//
// Returns: A boolean indicating whether or not the communication is permitted.
//
// NOTES:
//
// This routine must be called with AddrObjTableLock held.
//
//
BOOLEAN
IsPermittedSecurityFilter(IPAddr InterfaceAddress, void *IPContext,
ulong Protocol, ulong FilterValue)
{
PINTERFACE_ENTRY ientry;
PPROTOCOL_ENTRY pentry;
PVALUE_ENTRY ventry;
ulong hash_value;
struct Queue *qentry;
ASSERT(Protocol <= 0xFF);
for (qentry = InterfaceEntryList.q_next;
qentry != &InterfaceEntryList;
qentry = qentry->q_next
) {
ientry = STRUCT_OF(INTERFACE_ENTRY, qentry, ie_link);
if (ientry->ie_address == InterfaceAddress) {
for (qentry = ientry->ie_protocol_list.q_next;
qentry != &(ientry->ie_protocol_list);
qentry = qentry->q_next
) {
pentry = STRUCT_OF(PROTOCOL_ENTRY, qentry, pe_link);
if (pentry->pe_protocol == Protocol) {
if (pentry->pe_accept_all == TRUE) {
//
// All values accepted. Permit operation.
//
return (TRUE);
}
hash_value = VALUE_ENTRY_HASH(FilterValue);
for (qentry = pentry->pe_entries[hash_value].q_next;
qentry != &(pentry->pe_entries[hash_value]);
qentry = qentry->q_next
) {
ventry = STRUCT_OF(VALUE_ENTRY, qentry, ve_link);
if (ventry->ve_value == FilterValue) {
//
// Found it. Operation is permitted.
//
return (TRUE);
}
}
//
// {Interface, Protocol} protected, but no value found.
// Reject operation.
//
return (FALSE);
}
}
//
// Protocol not registered. Reject operation
//
return (FALSE);
}
}
//
// If this packet is on the loopback interface, let it through.
//
if (IP_LOOPBACK_ADDR(InterfaceAddress)) {
return (TRUE);
}
//
// Special check to allow the DHCP client to receive its packets.
// It is safe to make this check all the time because IP will
// not permit a packet to get through on an NTE with a zero address
// unless DHCP is in the process of configuring that NTE.
//
if ((Protocol == PROTOCOL_UDP) &&
(FilterValue == DHCP_CLIENT_PORT) &&
(*LocalNetInfo.ipi_isdhcpinterface) (IPContext)
) {
return (TRUE);
}
//
// Interface not registered. Deny operation.
//
return (FALSE);
}