X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=Modules%2FIPStack%2Ffirewall.c;h=b0390816fa15e5c94cb885b19f3df41d3abef2d8;hb=f42e912b8bc615c2009b795ce12d4c54cef4ee8b;hp=c250dd0870e5d537f4fa5b979c0985261ca68f50;hpb=3af08228012b1e79b7f47457f606911f3064dcbd;p=tpg%2Facess2.git diff --git a/Modules/IPStack/firewall.c b/Modules/IPStack/firewall.c index c250dd08..b0390816 100644 --- a/Modules/IPStack/firewall.c +++ b/Modules/IPStack/firewall.c @@ -3,36 +3,171 @@ * - Firewall Rules */ #include "ipstack.h" +#include "firewall.h" + +#define MAX_ADDRTYPE 9 // === IMPORTS === +// === TYPES === +typedef struct sKeyValue tKeyValue; +typedef struct sFirewallMod tFirewallMod; +typedef struct sModuleRule tModuleRule; +typedef struct sRule tRule; +typedef struct sChain tChain; + +// === STRUCTURES === +struct sKeyValue +{ + const char *Key; + const char *Value; +}; + +struct sFirewallMod +{ + const char *Name; + + int (*Match)(tModuleRule *Rule, int AddrType, + const void *Src, const void *Dest, + Uint8 Type, Uint32 Flags, + size_t Length, const void *Data); + + tModuleRule *(*Create)(tKeyValue *Params); +}; + +struct sModuleRule +{ + tModuleRule *Next; + + tFirewallMod *Mod; + + char Data[]; +}; + +struct sRule +{ + tRule *Next; + + int PacketCount; // Number of packets seen + int ByteCount; // Number of bytes seen (IP Payload bytes) + + int bInvertSource; // Boolean NOT flag on source + void *Source; // Source address bytes + int SourceMask; // Source address mask bits + + int bInvertDest; // Boolean NOT flag on destination + void *Dest; // Destination address bytes + int DestMask; // Destination address mask bits + + tModuleRule *Modules; // Modules loaded for this rule + + char Target[]; // Target rule name +}; + +struct sChain +{ + tChain *Next; + + tRule *FirstRule; + tRule *LastRule; + + char Name[]; +}; + // === PROTOTYPES === - int IPTablesV4_TestChain( - const char *RuleName, - const tIPv4 *Src, const tIPv4 *Dest, - Uint8 Type, Uint32 Flags, - size_t Length, const void *Data - ); - int IPTablesV6_TestChain( + int IPTables_TestChain( const char *RuleName, - const tIPv6 *Src, const tIPv6 *Dest, + const int AddressType, + const void *Src, const void *Dest, Uint8 Type, Uint32 Flags, size_t Length, const void *Data ); // === GLOBALS === +tChain *gapFirewall_Chains[MAX_ADDRTYPE+1]; +tChain gFirewall_DROP = {.Name="DROP"}; +tChain gFirewall_ACCEPT = {.Name="ACCEPT"}; +tChain gFirewall_RETURN = {.Name="RETURN"}; // === CODE === +/** + * \brief Apply a rule to a packet + * \return -1 for no match, -2 for RETURN, eFirewallAction otherwise + */ +int IPTables_DoRule( + tRule *Rule, int AddrType, + const void *Src, const void *Dest, + Uint8 Type, Uint32 Flags, + size_t Length, const void *Data) +{ + int rv; + // Check if source doesn't match + if( !IPStack_CompareAddress(AddrType, Src, Rule->Source, Rule->SourceMask) == !Rule->bInvertSource ) + return -1; + // Check if destination doesn't match + if( !IPStack_CompareAddress(AddrType, Dest, Rule->Dest, Rule->DestMask) == !Rule->bInvertDest ) + return -1; + + // TODO: Handle modules (UDP/TCP/etc) + tModuleRule *modrule; + for( modrule = Rule->Modules; modrule; modrule = modrule->Next ) + { + if( !modrule->Mod->Match ) continue; + rv = modrule->Mod->Match(modrule, AddrType, Src, Dest, Type, Flags, Length, Data); + if(rv != 0) return rv; // No match / action + } + + // Update statistics + Rule->PacketCount ++; + Rule->ByteCount += Length; + + return IPTables_TestChain(Rule->Target, AddrType, Src, Dest, Type, Flags, Length, Data); +} + /** * \brief Tests an IPv4 chain on a packet - * \return Boolean Disallow (0: Packet Allowed, 1: Drop, 2: Reject) + * \return Boolean Disallow (0: Packet Allowed, 1: Drop, 2: Reject, 3: Continue, -1 no match) */ - int IPTablesV4_TestChain( +int IPTables_TestChain( const char *RuleName, - const tIPv4 *Src, const tIPv4 *Dest, + const int AddressType, + const void *Src, const void *Dest, Uint8 Type, Uint32 Flags, size_t Length, const void *Data ) { + int rv; + tChain *chain; + tRule *rule; + + if( AddressType >= MAX_ADDRTYPE ) return -1; // Bad address type + + // Catch builtin targets + if(strcmp(RuleName, "") == 0) return -1; // No action + if(strcmp(RuleName, "ACCEPT") == 0) return 0; // Accept packet + if(strcmp(RuleName, "DROP") == 0) return 1; // Drop packet + if(strcmp(RuleName, "RETURN") == 0) return -2; // Return from rule + + // Find the rule + for( chain = gapFirewall_Chains[AddressType]; chain; chain = chain->Next ) + { + if( strcmp(chain->Name, RuleName) == 0 ) + break; + } + if( !chain ) return -1; // Bad rule name + + // Check the rules + for( rule = chain->FirstRule; rule; rule = rule->Next ) + { + rv = IPTables_DoRule(rule, AddressType, Src, Dest, Type, Flags, Length, Data); + if( rv == -1 ) + continue ; + if( rv == -2 ) // -2 = Return from a chain/table, pretend no match + return -1; + + return rv; + } + + return 0; // Accept all for now }