1556 lines
54 KiB
C
1556 lines
54 KiB
C
/*
|
|
******************************************************************************
|
|
* INTERPEAK SOURCE FILE
|
|
*
|
|
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipfirewall_userdef_http.c,v $ $Revision: 1.30.10.2 $
|
|
* $Source: /home/interpeak/CVSRoot/ipfirewall/src/ipfirewall_userdef_http.c,v $
|
|
* $Author: svc-cmnet $
|
|
* $State: Exp $ $Locker: $
|
|
*
|
|
* INTERPEAK_COPYRIGHT_STRING
|
|
* Design and implementation by Markus Carlstedt <markus@interpeak.se>
|
|
******************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 1 DESCRIPTION
|
|
****************************************************************************
|
|
* This library provides a rudimentary content filter for the HTTP packet.It
|
|
* performs the URL filtering, proxy filtering, cookie blocking, Java applet and
|
|
* ActiveX control filtering actions. The URL filtering is done based on the
|
|
* user specified URL database. Each entry of the database can specify either a
|
|
* URL path or a URL keyword to match. The proxy filtering matches all the packets
|
|
* which have absolute URI in its request line, i.e. the URI has the form:
|
|
* http://xxx.xxx.xxx/xxx. The cookie filtering replaces the cookie with the same
|
|
* length of the meaningless data in the request packet. It does not prevent the
|
|
* cookie from being set to your host. It simply prevents the cookie from being
|
|
* transmitted back to the server. Java applet and ActiveX control filterings
|
|
* simply block the requests for the files with extension .zip, .class, .jar;
|
|
* and .ocx,.cab respectively. It does not inspect the HTML OBJECT or APPLET tags
|
|
* or the signature of the object binary content.
|
|
* This content filter utilizes the firewall extension handler service
|
|
* registration mechanism to allow user add/remove the filtering functions
|
|
* described above dynamically. The content filter operates in the context of
|
|
* the firewall extension handler installed on a firewall rule intercepting the
|
|
* outbound HTTP traffic.
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 2 CONFIGURATION
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 3 INCLUDE FILES
|
|
****************************************************************************
|
|
*/
|
|
|
|
#define IPCOM_USE_CLIB_PROTO
|
|
#include <ipcom_type.h>
|
|
#include <ipcom_cstyle.h>
|
|
#include <ipcom_clib.h>
|
|
#include <ipcom_list.h>
|
|
#include <ipcom_syslog.h>
|
|
#include <ipcom_err.h>
|
|
|
|
#define IPFIREWALL_C
|
|
#include "ipfirewall.h"
|
|
#include "ipfirewall_h.h"
|
|
|
|
#ifdef IPFIREWALL_USE_HTTP_FILTER
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 4 DEFINES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*===========================================================================
|
|
* HTTP Filter identifier length
|
|
*===========================================================================
|
|
*/
|
|
#define IPFIREWALL_HTTP_FILTER_MAX_ID 32
|
|
|
|
/*
|
|
*===========================================================================
|
|
* URL filter type
|
|
*===========================================================================
|
|
*/
|
|
#define IPFIREWALL_CLASS_INDIVIDUAL 1 /* filter specific URLs */
|
|
#define IPFIREWALL_CLASS_ABS_URI 2 /* filter absolute URI URLs */
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* URL match type
|
|
*===========================================================================
|
|
*/
|
|
#define IPFIREWALL_URL_SPECIFIC_PATH 1 /* URL path match */
|
|
#define IPFIREWALL_URL_KEYWORD 2 /* URL keyword match */
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* Object filter type
|
|
*===========================================================================
|
|
*/
|
|
#define IPFIREWALL_OBJ_FILTER_JAVA 1 /* Java object filter type */
|
|
#define IPFIREWALL_OBJ_FILTER_ACTIVEX 2 /* ActiveX control filter type */
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* Constants
|
|
*===========================================================================
|
|
*/
|
|
#define IPFIREWALL_ONE_SPACE 1
|
|
#define IPFIREWALL_TOKEN_GET "GET"
|
|
#define IPFIREWALL_TOKEN_HTTP "http"
|
|
#define IPFIREWALL_TOKEN_HOST "Host"
|
|
#define IPFIREWALL_HTTP_S2H_LEN 7
|
|
#define IPFIREWALL_TMNATOR_TYPE_SPECIFIC 1
|
|
#define IPFIREWALL_TMNATOR_TYPE_GENERIC 2
|
|
#define IPFIREWALL_LOOSE_MATCH 0x10
|
|
#define IPFIREWALL_STRICT_MATCH 0x20
|
|
#define IPFIREWALL_FILE_EXT_MAXLEN 10
|
|
#define IPFIREWALL_SMALL_PATTERN_SIZE 5
|
|
#define IPFIREWALL_UCHAR_MAX 255
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* Macros
|
|
*===========================================================================
|
|
*/
|
|
#define IPFIREWALL_IS_STRING_SAME(str,strid) (ipcom_memcmp(str,strid,ipcom_strlen(strid)) == 0)
|
|
#define IPFIREWALL_NEXT_FIELD_POS(curToken) (ipcom_strlen(curToken) + IPFIREWALL_ONE_SPACE)
|
|
#define IPFIREWALL_TMNATOR_TYPE(t) ((t) & 0xff)
|
|
#define IPFIREWALL_TMNATOR_MATCH(t) (((t) >> 8) & 0xff)
|
|
#define IPFIREWALL_STR_GENERIC_TMNATOR(ch) ((ch) == '/' || (ch) == '\r' || (ch) == 0)
|
|
#define IPFIREWALL_ALIGNED(x, align) (((unsigned long)(x) & (align - 1)) == 0)
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 5 TYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*===========================================================================
|
|
* Ipfirewall_url
|
|
*===========================================================================
|
|
*/
|
|
typedef struct Ipfirewall_url_struct
|
|
{
|
|
Ipcom_list list_url;
|
|
char *url; /* URL string */
|
|
Ip_u16 len; /* the host length of URL, or entire length if keyword */
|
|
Ip_u16 attr; /* path or keyword type */
|
|
}
|
|
Ipfirewall_url;
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* Ipfirewall_http
|
|
*===========================================================================
|
|
*/
|
|
typedef struct Ipfirewall_http_struct
|
|
{
|
|
Ipcom_list list_http;
|
|
Ipcom_list head_url;
|
|
Ip_bool proxy;
|
|
Ip_bool cookie;
|
|
Ip_bool java;
|
|
Ip_bool activex;
|
|
char identifier[IPFIREWALL_HTTP_FILTER_MAX_ID];
|
|
}
|
|
Ipfirewall_http;
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 6 EXTERN PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 7 LOCAL PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 8 DATA
|
|
****************************************************************************
|
|
*/
|
|
|
|
IP_GLOBAL Ipcom_list head_http;
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 9 LOCAL FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipfirewall_http_bms_str_search
|
|
*===========================================================================
|
|
* Description: Search using the Boyer-Moore-Sunday (Quick Search) algorithm
|
|
* The Boyer-Moore-Sunday algorithm is a more efficient simplification of
|
|
* the Boyer-Moore algorithm. It performs comparisons between a character
|
|
* in the pattern and a character in the text buffer from left to right.
|
|
* After each mismatch it uses bad character heuristic to shift the
|
|
* pattern to the right. For more details on the algorithm, refer to
|
|
* "A Very Fast Substring Search Algorithm", Daniel M. Sunday, Communications
|
|
* of the ACM, Vol. 33 No. 8, August 1990, pp. 132-142.
|
|
* It has a O(Pattern Length x Text Buffer Length) worst-case time complexity.
|
|
* But empirical results have shown that this algorithm is one of the
|
|
* fastest in practice.
|
|
* Parameters: pattern - pattern to search for
|
|
* pattern_len - length of the pattern
|
|
* buffer - text buffer to search in
|
|
* buffer_len - length of the text buffer
|
|
* case_sensitive - case-sensitive search
|
|
* Returns: A pointer to the located pattern, or a IP_NULL pointer if the
|
|
* pattern is not found
|
|
*/
|
|
IP_STATIC char *
|
|
ipfirewall_http_bms_str_search(char *pattern,
|
|
int pattern_len,
|
|
char *buffer,
|
|
int buffer_len,
|
|
Ip_bool case_sensitive)
|
|
{
|
|
int skip_table[IPFIREWALL_UCHAR_MAX + 1];
|
|
int i;
|
|
int b;
|
|
char *p_pattern;
|
|
char *p_buffer;
|
|
char *p_buffer_compare;
|
|
char *p_pattern_end = pattern + pattern_len;
|
|
char *p_buffer_end = buffer + buffer_len - pattern_len + 1;
|
|
|
|
/* Validation check */
|
|
if ((pattern == IP_NULL) || (pattern_len == 0) ||
|
|
(buffer == IP_NULL) || (buffer_len == 0) ||
|
|
(pattern_len > buffer_len))
|
|
{
|
|
return IP_NULL;
|
|
}
|
|
|
|
/* Setup the skip table for the pattern */
|
|
for (i = 0; i < IPFIREWALL_UCHAR_MAX + 1; i++)
|
|
skip_table[(Ip_u8)i] = pattern_len + 1;
|
|
for (p_pattern = pattern; p_pattern < p_pattern_end; p_pattern++)
|
|
{
|
|
if (case_sensitive == IP_TRUE)
|
|
skip_table[(Ip_u8)*p_pattern] = (int)(p_pattern_end - p_pattern);
|
|
else
|
|
{
|
|
b = ipcom_tolower((int)*p_pattern);
|
|
skip_table[b] = (int)(p_pattern_end - p_pattern);
|
|
b = ipcom_toupper((int)*p_pattern);
|
|
skip_table[b] = (int)(p_pattern_end - p_pattern);
|
|
}
|
|
}
|
|
|
|
/* Main loop is the fast skip loop */
|
|
for (p_buffer = buffer; p_buffer < p_buffer_end;
|
|
p_buffer += skip_table[(Ip_u8)*(p_buffer + pattern_len)])
|
|
{
|
|
|
|
/* Comparison loop */
|
|
if (case_sensitive == IP_TRUE)
|
|
{
|
|
for (p_pattern = pattern, p_buffer_compare = p_buffer;
|
|
(p_pattern < p_pattern_end) && (*p_pattern == *p_buffer_compare);
|
|
p_pattern++, p_buffer_compare++)
|
|
;
|
|
}
|
|
else
|
|
{
|
|
for (p_pattern = pattern, p_buffer_compare = p_buffer;
|
|
(p_pattern < p_pattern_end) &&
|
|
(toupper((int)*p_pattern) == toupper((int)*p_buffer_compare));
|
|
p_pattern++, p_buffer_compare++)
|
|
;
|
|
}
|
|
|
|
if (p_pattern == p_pattern_end)
|
|
return p_buffer; /* match */
|
|
}
|
|
|
|
/* no match */
|
|
return IP_NULL;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipfirewall_http_bf_str_search
|
|
*===========================================================================
|
|
* Description: Search using the Brute Force algorithm
|
|
* The Brute Force algorithm is the simplest string search
|
|
* algorithm. It performs comparisons between a character in
|
|
* the pattern and a character in the text buffer from left to
|
|
* right. After each attempt it shifts the pattern by one position
|
|
* to the right. The Brute Force algorithm requires no
|
|
* pre-processing and no extra space. It has a O(Pattern Length
|
|
* x Text Buffer Length) worst-case time complexity.
|
|
* Parameters: pattern - pattern to search for
|
|
* pattern_len - length of the pattern
|
|
* buffer - text buffer to search in
|
|
* buffer_len - length of the text buffer
|
|
* case_sensitive - case-sensitive search
|
|
* Returns: A pointer to the located pattern, or a IP_NULL pointer if the
|
|
* pattern is not found
|
|
*/
|
|
IP_STATIC char *
|
|
ipfirewall_http_bf_str_search(char *pattern,
|
|
int pattern_len,
|
|
char *buffer,
|
|
int buffer_len,
|
|
Ip_bool case_sensitive)
|
|
{
|
|
char *p_pattern;
|
|
char *p_buffer;
|
|
char *p_buffer_compare;
|
|
char *p_pattern_end = pattern + pattern_len;
|
|
char *p_buffer_end = buffer + buffer_len - pattern_len + 1;
|
|
|
|
/* Validation check */
|
|
|
|
if ((pattern == IP_NULL) || (pattern_len == 0) ||
|
|
(buffer == IP_NULL) || (buffer_len == 0) ||
|
|
(pattern_len > buffer_len))
|
|
{
|
|
return IP_NULL;
|
|
}
|
|
|
|
for (p_buffer = buffer; p_buffer < p_buffer_end; p_buffer++)
|
|
{
|
|
if (case_sensitive == IP_TRUE)
|
|
{
|
|
for (p_pattern = pattern, p_buffer_compare = p_buffer;
|
|
(p_pattern < p_pattern_end) && (*p_pattern == *p_buffer_compare);
|
|
p_pattern++, p_buffer_compare++)
|
|
;
|
|
}
|
|
else
|
|
{
|
|
for (p_pattern = pattern, p_buffer_compare = p_buffer;
|
|
(p_pattern < p_pattern_end) &&
|
|
(toupper((int)*p_pattern) == toupper((int)*p_buffer_compare));
|
|
p_pattern++, p_buffer_compare++)
|
|
;
|
|
}
|
|
|
|
if (p_pattern == p_pattern_end)
|
|
return p_buffer; /* match */
|
|
}
|
|
|
|
/* no match */
|
|
return IP_NULL;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipfirewall_http_fast_str_search
|
|
*===========================================================================
|
|
* Description: Search by optimally choosing the search algorithm.
|
|
* Depending on the pattern size, this function uses either the
|
|
* Boyer-Moore-Sunday algorithm or the Brute Force algorithm. The
|
|
* Boyer-Moore-Sunday algorithm requires pre-processing,
|
|
* therefore for small patterns it is better to use the Brute
|
|
* Force algorithm.
|
|
* Parameters: pattern - pattern to search for
|
|
* pattern_len - length of the pattern
|
|
* buffer - text buffer to search in
|
|
* buffer_len - length of the text buffer
|
|
* case_sensitive - case-sensitive search
|
|
* Returns: A pointer to the located pattern, or a IP_NULL pointer if the
|
|
* pattern is not found
|
|
*/
|
|
IP_STATIC char *
|
|
ipfirewall_http_fast_str_search(char *pattern,
|
|
int pattern_len,
|
|
char *buffer,
|
|
int buffer_len,
|
|
Ip_bool case_sensitive)
|
|
{
|
|
if (pattern_len >= IPFIREWALL_SMALL_PATTERN_SIZE)
|
|
return ipfirewall_http_bms_str_search(pattern, pattern_len, buffer,
|
|
buffer_len, case_sensitive);
|
|
else
|
|
return ipfirewall_http_bf_str_search(pattern, pattern_len, buffer,
|
|
buffer_len, case_sensitive);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipfirewall_http_str_st_len
|
|
*===========================================================================
|
|
* Description: Returns the length of a string with specific terminator
|
|
* Parameters: str - pointer to the string
|
|
* terminator - terminating character
|
|
* maxlen - maximum length to search
|
|
* Returns: length of string
|
|
*/
|
|
IP_STATIC int
|
|
ipfirewall_http_str_st_len(char *str, char terminator, int maxlen)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < maxlen; i++)
|
|
{
|
|
if (str[i] == terminator)
|
|
return i;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipfirewall_http_is_ci_string_same
|
|
*===========================================================================
|
|
* Description: Compare two case insensitive strings
|
|
* Parameters: str - pointer to string one.
|
|
* id_str - pointer to string two.
|
|
* Returns: IP_TRUE if strings are the same or IP_FALSE if not.
|
|
*/
|
|
IP_STATIC Ip_bool
|
|
ipfirewall_http_is_ci_string_same(char *str, char *id_str)
|
|
{
|
|
Ip_u32 len, i;
|
|
|
|
len = (Ip_u32)ipcom_strlen(id_str);
|
|
for (i = 0; i < len; i++)
|
|
if (ipcom_tolower((Ip_u8)str[i]) != ipcom_tolower((Ip_u8)id_str[i]))
|
|
return IP_FALSE;
|
|
return IP_TRUE;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipfirewall_http_str_ci_cmp
|
|
*===========================================================================
|
|
* Description: Compare two case insensitive strings with specific
|
|
* terminators.
|
|
* Parameters: str1 - pointer to string one.
|
|
* str2 - pointer to string two.
|
|
* typematch - compare type.
|
|
* Returns: IP_TRUE if strings are the same or IP_FALSE if not.
|
|
*/
|
|
IP_STATIC Ip_bool
|
|
ipfirewall_http_str_ci_cmp(char *str1, char *str2, int typematch, char term1, char term2)
|
|
{
|
|
int cnt = 0;
|
|
Ip_bool cond1;
|
|
Ip_bool cond2;
|
|
|
|
for(;;)
|
|
{
|
|
if (IPFIREWALL_TMNATOR_TYPE(typematch) == IPFIREWALL_TMNATOR_TYPE_SPECIFIC)
|
|
{
|
|
cond1 = (str1[cnt] == term1);
|
|
cond2 = (str2[cnt] == term2);
|
|
}
|
|
else /* TMNATOR_TYPE_GENERIC */
|
|
{
|
|
cond1 = IPFIREWALL_STR_GENERIC_TMNATOR(str1[cnt]);
|
|
cond2 = IPFIREWALL_STR_GENERIC_TMNATOR(str2[cnt]);
|
|
}
|
|
|
|
if (cond1 && cond2)
|
|
return IP_TRUE;
|
|
else if (cond1 || cond2)
|
|
{
|
|
if (IPFIREWALL_TMNATOR_MATCH(typematch) == IPFIREWALL_LOOSE_MATCH)
|
|
return IP_TRUE;
|
|
else
|
|
return IP_FALSE;
|
|
}
|
|
|
|
if (ipcom_tolower((Ip_u8)str1[cnt]) != ipcom_tolower((Ip_u8)str2[cnt]))
|
|
return IP_FALSE;
|
|
cnt++;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipfirewall_http_find
|
|
*===========================================================================
|
|
* Description: This function searches for a HTTP filter.
|
|
* Parameters: id - identifier
|
|
* Returns: Pointer to the HTTP filter defined structure or IP_NULL if not found.
|
|
*/
|
|
IP_STATIC Ipfirewall_http *
|
|
ipfirewall_http_find(const char *id)
|
|
{
|
|
Ipfirewall_http *fw_http;
|
|
|
|
/* Check input */
|
|
if(id == IP_NULL)
|
|
return IP_NULL;
|
|
|
|
fw_http = IPCOM_LIST_FIRST(&head_http);
|
|
while(fw_http != IP_NULL)
|
|
{
|
|
if(ipcom_strcmp(fw_http->identifier, id) == 0)
|
|
return fw_http;
|
|
fw_http = IPCOM_LIST_NEXT(&fw_http->list_http);
|
|
}
|
|
return IP_NULL;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipfirewall_field_name_find
|
|
*===========================================================================
|
|
* Description: This routine searches a string in a structured message.
|
|
* It assumes the searched string always starts at the begining
|
|
* of each line of data terminated by \r\n characters. A message
|
|
* should be terminated by \r\n preceded by the line terminator
|
|
* \r\n.
|
|
* Parameters: buf - pointer to the message.
|
|
* id - string to search for.
|
|
* len - length of the HTTP payload.
|
|
* pos - offset where the string was found
|
|
* Returns: IP_TRUE = string found
|
|
* IP_FALSE = string not found
|
|
*/
|
|
IP_STATIC Ip_bool
|
|
ipfirewall_field_name_find(char *buf, char *id, int len, int *pos)
|
|
{
|
|
int search_len;
|
|
char *start = buf;
|
|
|
|
if (id == IP_NULL)
|
|
return IP_FALSE;
|
|
|
|
search_len = len;
|
|
while (1)
|
|
{
|
|
/* skip all space */
|
|
while (search_len > 0 && buf[0] == ' ')
|
|
{
|
|
buf++;
|
|
search_len--;
|
|
}
|
|
if (search_len < (int)ipcom_strlen(id))
|
|
{
|
|
IPCOM_LOG1(DEBUG, "ipfirewall_field_name_find() :: string not '%s' found - reached end of message", id);
|
|
return IP_FALSE;
|
|
}
|
|
if (IPFIREWALL_IS_STRING_SAME(buf, id))
|
|
{
|
|
IPCOM_LOG2(DEBUG, "ipfirewall_field_name_find() :: found string '%s' att offset %d",
|
|
id, buf - start);
|
|
break; /* Breaks out of outer loop */
|
|
}
|
|
|
|
/* advance to next line */
|
|
while (search_len > 1)
|
|
{
|
|
if (buf[0] == '\r' && buf[1] == '\n')
|
|
break; /* Breaks out of inner loop */
|
|
buf++;
|
|
search_len--;
|
|
}
|
|
|
|
if (search_len <= 1)
|
|
{
|
|
IPCOM_LOG1(DEBUG, "ipfirewall_field_name_find() :: string '%s' not found - line end not found", id);
|
|
return IP_FALSE;
|
|
}
|
|
buf += 2;
|
|
search_len -= 2;
|
|
|
|
if (search_len > 1)
|
|
{
|
|
if (buf[0] == '\r' && buf[1] == '\n')
|
|
{
|
|
/* reach the end mark \r\n\r\n */
|
|
IPCOM_LOG1(DEBUG, "ipfirewall_field_name_find() :: string '%s' not found - reached end mark", id);
|
|
return IP_FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
*pos = (int)(buf - start);
|
|
return IP_TRUE;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipfirewall_http_checksum_adjust
|
|
*===========================================================================
|
|
* Description: Adjust the TCP checksum for modified packet. Assume data
|
|
* starts at even boundary with even length.
|
|
* Parameters: cksum - original checksum.
|
|
* buf - pointer to modified data.
|
|
* len - modified data length.
|
|
* is_adding_data - IP_TRUE if data is added. IP_TRUE if data is
|
|
* removed.
|
|
* Returns: The new checksum.
|
|
*/
|
|
IP_STATIC Ip_u32
|
|
ipfirewall_http_checksum_adjust(Ip_u32 cksum, Ip_u16 *buf, int len,
|
|
Ip_bool is_adding_data)
|
|
{
|
|
cksum = (~cksum & 0x0000FFFF);
|
|
|
|
if (is_adding_data == IP_FALSE)
|
|
{
|
|
/* removing data */
|
|
while (len > 0)
|
|
{
|
|
cksum = cksum - ((*buf++) & 0x0000FFFF);
|
|
if ((Ip_s32) cksum <= 0x00000000L)
|
|
{
|
|
--cksum;
|
|
cksum = cksum & 0x0000FFFF;
|
|
}
|
|
len -= 2;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* adding data */
|
|
while (len > 0)
|
|
{
|
|
cksum = cksum + ((*buf++) & 0x0000FFFF);
|
|
if (cksum & 0x00010000)
|
|
{
|
|
++cksum;
|
|
cksum = cksum & 0x0000FFFF;
|
|
}
|
|
len -= 2;
|
|
}
|
|
}
|
|
cksum = ~cksum;
|
|
return cksum;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipfirewall_http_match_cookie
|
|
*===========================================================================
|
|
* Description: This function prevent a cookie from being sent back to
|
|
* the web server by overwritting the cookie in the client's
|
|
* request message header. It must therefore recalculate the
|
|
* TCP checksum.
|
|
* Parameters: buf - pointer to the HTTP payload.
|
|
* len - length of the HTTP payload.
|
|
* tcp - pointer to tcp header
|
|
* Returns: 1 = object found
|
|
* 0 = object not found;
|
|
*/
|
|
IP_STATIC int
|
|
ipfirewall_http_match_cookie(Ip_u8 *buf, int len, Ipcom_tcp_header *tcp)
|
|
{
|
|
Ip_u16 *chksum_start;
|
|
int ret, offset, cookielen, cslen, cstokenlen;
|
|
Ip_u32 new_checksum = 0;
|
|
|
|
ret = 0;
|
|
if (ipfirewall_field_name_find((char *)buf, "Cookie", len, &offset) == IP_TRUE)
|
|
{
|
|
buf += offset;
|
|
len -= offset;
|
|
|
|
cookielen = ipfirewall_http_str_st_len((char *)buf, '\r', len);
|
|
if (!IPFIREWALL_ALIGNED(buf, 2))
|
|
{
|
|
chksum_start = (Ip_u16 *)(buf - 1);
|
|
cslen = (cookielen & 0x1) ? cookielen + 1 : cookielen + 2;
|
|
}
|
|
else
|
|
{
|
|
chksum_start = (Ip_u16 *)buf;
|
|
cslen = (cookielen & 0x1) ? cookielen + 1 : cookielen;
|
|
}
|
|
|
|
/* subtract the cookie checksum data from TCP checksum */
|
|
new_checksum = ipfirewall_http_checksum_adjust(tcp->checksum, chksum_start, cslen, IP_FALSE);
|
|
|
|
/* remove the Cookie information by filling some junk data */
|
|
cstokenlen = ipfirewall_http_str_st_len((char *)buf, ':', len);
|
|
ipcom_memset(buf, 'd', (Ip_size_t)cstokenlen);
|
|
|
|
/* not to overwrite the : and space */
|
|
ipcom_memset(buf + cstokenlen + 2, 'x', (Ip_size_t)(cookielen - (cstokenlen + 2)));
|
|
|
|
/* add the new Cookie data to the adjusted TCP checksum */
|
|
tcp->checksum = (Ip_u16)ipfirewall_http_checksum_adjust(new_checksum, chksum_start, cslen, IP_TRUE);
|
|
|
|
IPCOM_LOG0(DEBUG, "ipfirewall_http_match_cookie() :: hiding cookie");
|
|
ret = 1;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipfirewall_http_match_object
|
|
*===========================================================================
|
|
* Description: This function matches binary objects in HTTP GET requests.
|
|
* It prevents certain executable files from running in the web
|
|
* browser by blocking the requests to the corresponding type
|
|
* of files. Currently it blocks the Java Applet by blocking
|
|
* the files with extension .class, .jar and .zip; and ActiveX
|
|
* control by blocking the files with extension .ocx and .cab.
|
|
* Parameters: buf - pointer to the HTTP payload.
|
|
* len - length of the HTTP payload.
|
|
* type - type of object
|
|
* Returns: 1 = object found
|
|
* 0 = object not found;
|
|
*/
|
|
IP_STATIC int
|
|
ipfirewall_http_match_object(Ip_u8 *buf, int len, int type)
|
|
{
|
|
int cnt, ret;
|
|
|
|
ret = 0;
|
|
if (IPFIREWALL_IS_STRING_SAME(buf, IPFIREWALL_TOKEN_GET))
|
|
{
|
|
/* advance pass GET token and space */
|
|
buf += IPFIREWALL_NEXT_FIELD_POS(IPFIREWALL_TOKEN_GET);
|
|
len = len - (int)IPFIREWALL_NEXT_FIELD_POS(IPFIREWALL_TOKEN_GET);
|
|
cnt = ipfirewall_http_str_st_len((char *)buf, ' ' , len);
|
|
buf += cnt;
|
|
len -= cnt;
|
|
|
|
/* search for file extension seperator */
|
|
for (cnt=0; (cnt < IPFIREWALL_FILE_EXT_MAXLEN) && (*buf-- != '.'); cnt++);
|
|
|
|
if (cnt < IPFIREWALL_FILE_EXT_MAXLEN)
|
|
{
|
|
buf += 2;
|
|
if (type == IPFIREWALL_OBJ_FILTER_ACTIVEX)
|
|
{
|
|
if (ipfirewall_http_is_ci_string_same((char *)buf,"ocx") ||
|
|
ipfirewall_http_is_ci_string_same((char *)buf,"cab") )
|
|
{
|
|
IPCOM_LOG0(DEBUG, "ipfirewall_http_match_object() :: found activex object");
|
|
ret = 1;
|
|
}
|
|
}
|
|
else if (type == IPFIREWALL_OBJ_FILTER_JAVA)
|
|
{
|
|
if (ipfirewall_http_is_ci_string_same((char *)buf,"class") ||
|
|
ipfirewall_http_is_ci_string_same((char *)buf,"jar") ||
|
|
ipfirewall_http_is_ci_string_same((char *)buf,"zip") )
|
|
{
|
|
IPCOM_LOG0(DEBUG, "ipfirewall_http_match_object() :: found java object");
|
|
ret = 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipfirewall_http_match_url
|
|
*===========================================================================
|
|
* Description: Performs the URL filtering for the HTTP packets.
|
|
* This routine filters the HTTP request packets based on the
|
|
* given URL database. It performs two match actions: the path
|
|
* match and keyword match. The path match means both the host
|
|
* name and the file path of the provided URL string matches the
|
|
* packet's ones. However, the given file path just needs to
|
|
* match the beginning portion of the packet's path. The keyword
|
|
* match means thegiven string matches any part of the packet's URL.
|
|
* Parameters: buf - pointer to the HTTP payload.
|
|
* len - length of the HTTP payload.
|
|
* type - URL filter type.
|
|
* Returns: 1 = object found
|
|
* 0 = object not found;
|
|
*/
|
|
IP_STATIC int
|
|
ipfirewall_http_match_url(Ip_u8 *buf, int len, int type, Ipfirewall_http *fw_http)
|
|
{
|
|
Ipfirewall_url *fw_url;
|
|
int cnt, pathlen, hostlen;
|
|
Ip_u8 *host, *path;
|
|
|
|
/* skip the method token, advance to URI */
|
|
cnt = ipfirewall_http_str_st_len((char *)buf, ' ', len);
|
|
buf += cnt + 1;
|
|
len -= cnt + 1;
|
|
|
|
/* Request-URI = "*" | absoluteURI | abs_path | authority
|
|
* "*" and authority forms are used by OPTION and CONNECT methods
|
|
* absoluteURI = scheme ":" ( hier_part | opaque_part )
|
|
* hier_part = ( net_path | abs_path ) [ "?" query ]
|
|
* net_path = "//" authority [ abs_path ]
|
|
* abs_path = "/" path_segments
|
|
*
|
|
* Host name case insensitive, scheme case insensitive
|
|
*/
|
|
|
|
/* consider absoluteURI and abs_path */
|
|
if (ipfirewall_http_str_ci_cmp((char *)buf, IPFIREWALL_TOKEN_HTTP, IPFIREWALL_TMNATOR_TYPE_SPECIFIC, ':', 0) == IP_TRUE)
|
|
{
|
|
/* absoluteURI
|
|
* HTTP/1.1 clients only generates absoluteURI in requests to
|
|
* proxies(RFC2616, 5.1.2).
|
|
*/
|
|
if (type == IPFIREWALL_CLASS_ABS_URI)
|
|
{
|
|
IPCOM_LOG0(DEBUG, "ipfirewall_http_match_url() :: Found absolute URI");
|
|
return 1;
|
|
}
|
|
|
|
buf += IPFIREWALL_HTTP_S2H_LEN;
|
|
len -= IPFIREWALL_HTTP_S2H_LEN;
|
|
host = buf;
|
|
hostlen = ipfirewall_http_str_st_len((char *)host, '/', len);
|
|
path = buf + hostlen;
|
|
pathlen = ipfirewall_http_str_st_len((char *)path, ' ', len - hostlen); /* terminated by space */
|
|
}
|
|
else
|
|
{
|
|
/* not absolute URI */
|
|
if (type == IPFIREWALL_CLASS_ABS_URI)
|
|
{
|
|
IPCOM_LOG0(DEBUG, "ipfirewall_http_match_url() :: Not an absolute URI");
|
|
return 0;
|
|
}
|
|
|
|
/* abs_path */
|
|
path = buf;
|
|
pathlen = ipfirewall_http_str_st_len((char *)path, ' ', len);
|
|
|
|
if (ipfirewall_field_name_find((char *)buf, IPFIREWALL_TOKEN_HOST, len, &cnt) == IP_FALSE)
|
|
{
|
|
IPCOM_LOG0(INFO, "ipfirewall_http_match_url() :: No 'Host:' token in request");
|
|
return 0;
|
|
}
|
|
|
|
buf += cnt;
|
|
len -= cnt;
|
|
buf += IPFIREWALL_NEXT_FIELD_POS(IPFIREWALL_TOKEN_HOST);
|
|
len = len - (int)IPFIREWALL_NEXT_FIELD_POS(IPFIREWALL_TOKEN_HOST);
|
|
while (*(char *)(buf) == ' ')
|
|
{
|
|
buf++;
|
|
len--;
|
|
}
|
|
host = buf;
|
|
hostlen = ipfirewall_http_str_st_len((char *)host, '\r', len);
|
|
}
|
|
|
|
ip_assert(fw_http != IP_NULL);
|
|
for (fw_url = IPCOM_LIST_FIRST(&fw_http->head_url);
|
|
fw_url != IP_NULL;
|
|
fw_url = IPCOM_LIST_NEXT(&fw_url->list_url))
|
|
{
|
|
if (fw_url->attr == IPFIREWALL_URL_SPECIFIC_PATH)
|
|
{
|
|
if (ipfirewall_http_str_ci_cmp((char *)fw_url->url, (char *)host, IPFIREWALL_TMNATOR_TYPE_GENERIC, 0, 0))
|
|
{
|
|
if (fw_url->url[fw_url->len] == 0 ||
|
|
IPFIREWALL_IS_STRING_SAME(path, fw_url->url + fw_url->len))
|
|
{
|
|
IPCOM_LOG1(DEBUG, "ipfirewall_http_match_url() :: Matched path: '%s'", fw_url->url);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* IPFIREWALL_URL_KEYWORD */
|
|
if (ipfirewall_http_fast_str_search((char *)fw_url->url, fw_url->len, (char *)host, hostlen, IP_FALSE) ||
|
|
ipfirewall_http_fast_str_search((char *)fw_url->url, fw_url->len, (char *)path, pathlen, IP_TRUE))
|
|
{
|
|
IPCOM_LOG1(DEBUG, "ipfirewall_http_match_url() :: Matched keyword: '%s'", fw_url->url);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* check if matches */
|
|
if (fw_url != IP_NULL)
|
|
{
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
IPCOM_LOG0(DEBUG, "ipfirewall_http_match_url() :: No keyword or path matched.");
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 10 GLOBAL FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 11 PUBLIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipfirewall_http_match
|
|
*===========================================================================
|
|
* Description: HTTP filter match function.
|
|
* Parameters: pkt - pointer to the ipcom packet
|
|
* cookie - a cookie set at registration.
|
|
* info - user defined info buffer
|
|
* Returns: 1 = rule matched.
|
|
* 0 = rule did not match.
|
|
*/
|
|
IP_PUBLIC int
|
|
ipfirewall_http_match(Ipcom_pkt *pkt, void *cookie, void *info)
|
|
{
|
|
Ipfirewall_http *fw_http;
|
|
Ipcom_tcp_header *tcp;
|
|
Ip_u8 ver, protocol = 0, is_frag = 0, first_frag = 0, *http_pkt;
|
|
Ip_u16 hlen;
|
|
int http_len, tcp_hlen, ret;
|
|
|
|
(void)cookie;
|
|
fw_http = *(Ipfirewall_http **)info;
|
|
ret = 0;
|
|
ip_assert(fw_http != IP_NULL);
|
|
|
|
/* Check version */
|
|
ver = (Ip_u8)(pkt->data[pkt->ipstart] >> 4);
|
|
if (ver == 4)
|
|
hlen = (Ip_u16)((pkt->data[pkt->ipstart] & 0x0f) << 2);
|
|
else if (ver == 6)
|
|
hlen = IPCOM_IP6_HEADER_LENGTH;
|
|
else
|
|
{
|
|
IPCOM_LOG0(ERR, "ipfirewall_http_match() :: Unknown version.");
|
|
return 0;
|
|
}
|
|
|
|
/* Check that the packet is long enough for the IP header */
|
|
if(pkt->end - pkt->ipstart < (int)hlen)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipfirewall_http_match() :: Packet too short for IP header.");
|
|
return 0;
|
|
}
|
|
|
|
#ifdef IPCOM_USE_INET
|
|
if (ver == 4)
|
|
{
|
|
Ipcom_ip_header *ip4;
|
|
|
|
ip4 = (Ipcom_ip_header *)&pkt->data[pkt->ipstart];
|
|
protocol = ip4->protocol;
|
|
/* Set MTU to MAX_ULONG */
|
|
ipfirewall_get_frag4_info(ip4, pkt, 0xffffffff, &is_frag, &first_frag);
|
|
}
|
|
#endif
|
|
|
|
#ifdef IPCOM_USE_INET6
|
|
if (ver == 6)
|
|
{
|
|
Ipcom_ip6_header *ip6;
|
|
|
|
ip6 = (Ipcom_ip6_header *)&pkt->data[pkt->ipstart];
|
|
/* Set MTU to MAX_ULONG */
|
|
if (ipfirewall_get_frag6_info(ip6, pkt, 0xffffffff, &is_frag, &first_frag, &protocol, &hlen) < 0)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipfirewall_http_match() :: Failed to parse IPv6 extension headers.");
|
|
return 0;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/* Cannot match fragments other than the first */
|
|
if (is_frag == 1 && first_frag == 0)
|
|
{
|
|
IPCOM_LOG0(DEBUG, "ipfirewall_http_match() :: Skipped fragment.");
|
|
return 0;
|
|
}
|
|
|
|
/* Verify that protocol is TCP */
|
|
if (protocol != IP_IPPROTO_TCP)
|
|
{
|
|
IPCOM_LOG0(DEBUG, "ipfirewall_http_match() :: Skipped non-TCP packet.");
|
|
return 0;
|
|
}
|
|
|
|
/* Check that the packet is long enough for mandatory TCP header */
|
|
if(pkt->end - pkt->ipstart - (int)hlen < IPCOM_TCP_HEADER_LENGTH)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipfirewall_http_match() :: Packet too short for mandatory TCP header.");
|
|
return 0;
|
|
}
|
|
|
|
/* Store pointer to TCP header */
|
|
tcp = (Ipcom_tcp_header *)&pkt->data[pkt->ipstart + (int)hlen];
|
|
tcp_hlen = ip_ntohs(tcp->offset_flags)>>10;
|
|
|
|
/* Check that the packet is long enough for the TCP header */
|
|
if(pkt->end - pkt->ipstart - (int)hlen < tcp_hlen)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipfirewall_http_match() :: Packet too short for TCP header.");
|
|
return 0;
|
|
}
|
|
|
|
/* Store pointer to HTTP packet */
|
|
http_pkt = (Ip_u8 *)tcp + tcp_hlen;
|
|
http_len = pkt->end - pkt->ipstart - (int)hlen - tcp_hlen;
|
|
|
|
/* Check that HTTP data is long enough to contain at least "GET / HTTP/1.0\r\n\r\n" */
|
|
if (http_len >= 18)
|
|
{
|
|
/* Match URL filter if at least one URL is inserted */
|
|
if (ret == 0 && fw_http->head_url.size > 0)
|
|
ret = ipfirewall_http_match_url(http_pkt, http_len, IPFIREWALL_CLASS_INDIVIDUAL, fw_http);
|
|
|
|
/* Match proxy filter if enabled */
|
|
if (ret == 0 && fw_http->proxy == IP_TRUE)
|
|
ret = ipfirewall_http_match_url(http_pkt, http_len, IPFIREWALL_CLASS_ABS_URI, IP_NULL);
|
|
|
|
/* Match java filter if enabled */
|
|
if (ret == 0 && fw_http->java == IP_TRUE)
|
|
ret = ipfirewall_http_match_object(http_pkt, http_len, IPFIREWALL_OBJ_FILTER_JAVA);
|
|
|
|
/* Match activex filter if enabled */
|
|
if (ret == 0 && fw_http->activex == IP_TRUE)
|
|
ret = ipfirewall_http_match_object(http_pkt, http_len, IPFIREWALL_OBJ_FILTER_ACTIVEX);
|
|
|
|
/* Remove cookies if cookie filter is enabled */
|
|
if (fw_http->cookie == IP_TRUE)
|
|
{
|
|
ipfirewall_http_match_cookie(http_pkt, http_len, tcp);
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipfirewall_http_check
|
|
*===========================================================================
|
|
* Description: HTTP filter check function.
|
|
* cookie - a cookie set at registration.
|
|
* info - parameter string specified in the rule syntax
|
|
* infolen - length of user defined info buffer
|
|
* Returns: 1 = rule parameters accepted
|
|
* 0 = rule parameters not accepted
|
|
*/
|
|
IP_PUBLIC int
|
|
ipfirewall_http_check(void *cookie, void *info, unsigned int infolen)
|
|
{
|
|
Ipfirewall_http *fw_http;
|
|
|
|
(void)cookie;
|
|
|
|
/* Verify that there is a HTTP filter matching the rule parameter string */
|
|
fw_http = ipfirewall_http_find(info);
|
|
if (fw_http == IP_NULL)
|
|
{
|
|
IPCOM_LOG1(ERR, "ipfirewall_http_check() :: HTTP filter '%s' not found", info);
|
|
return 0;
|
|
}
|
|
|
|
/* Store pointer to filter for faster access in match function */
|
|
if (infolen < (int)sizeof(fw_http))
|
|
return 0;
|
|
ipcom_memcpy(info, &fw_http, sizeof(fw_http));
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipfirewall_http_destroy
|
|
*===========================================================================
|
|
* Description: HTTP filter destroy function.
|
|
* cookie - a cookie set at registration.
|
|
* info - parameter string specified in the rule syntax
|
|
* infolen - length of user defined info buffer
|
|
*/
|
|
IP_PUBLIC void
|
|
ipfirewall_http_destroy(void *cookie, void *info, unsigned int infolen)
|
|
{
|
|
(void)cookie;
|
|
(void)info;
|
|
(void)infolen;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipfirewall_http_insert_url_filter
|
|
*===========================================================================
|
|
* Description: Add a URL path or keyword to a HTTP filter.
|
|
* Parameters: id - filter identifier.
|
|
* url - keyword or URL path.
|
|
* keyword - IP_TRUE for keyword match or IP_FALSE for URL path.
|
|
* Returns: IPCOM_SUCCESS or error code.
|
|
*/
|
|
IP_PUBLIC Ip_err
|
|
ipfirewall_http_insert_url_filter(const char *id, const char *url, Ip_bool keyword)
|
|
{
|
|
void *suspend_handle;
|
|
Ipfirewall_http *fw_http;
|
|
Ipfirewall_url *fw_url;
|
|
Ip_err ret = IPCOM_SUCCESS;
|
|
|
|
/* Find HTTP filter */
|
|
suspend_handle = ipnet_suspend_stack();
|
|
if (suspend_handle == IP_NULL)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipfirewall_http_insert_url() :: Could not suspend stack");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
fw_http = ipfirewall_http_find(id);
|
|
if (fw_http == IP_NULL)
|
|
{
|
|
IPCOM_LOG1(ERR, "ipfirewall_http_insert_url() :: HTTP filter '%s' not found", id);
|
|
ret = IPCOM_ERR_NOT_FOUND;
|
|
goto out;
|
|
}
|
|
|
|
/* Allocate the URL structure */
|
|
fw_url = ipcom_malloc(sizeof(*fw_url));
|
|
if(fw_url == IP_NULL)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipfirewall_http_insert_url() :: Could not allocate memory for URL match entry");
|
|
ret = IPCOM_ERR_NO_MEMORY;
|
|
goto out;
|
|
}
|
|
|
|
/* Populate the URL structure */
|
|
ipcom_memset(fw_url, 0, sizeof(*fw_url));
|
|
fw_url->url = ipcom_malloc(ipcom_strlen(url) + 1);
|
|
if (fw_url->url == IP_NULL)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipfirewall_http_insert_url() :: Could not allocate memory for URL string");
|
|
ipcom_free(fw_url);
|
|
ret = IPCOM_ERR_NO_MEMORY;
|
|
goto out;
|
|
}
|
|
|
|
/* Skip leading "http://" */
|
|
if (ipfirewall_http_str_ci_cmp((char *)url, IPFIREWALL_TOKEN_HTTP, IPFIREWALL_TMNATOR_TYPE_SPECIFIC, ':', 0) == IP_TRUE)
|
|
if (IPFIREWALL_IS_STRING_SAME((url + ipcom_strlen(IPFIREWALL_TOKEN_HTTP)),"://"))
|
|
url += IPFIREWALL_HTTP_S2H_LEN;
|
|
|
|
ipcom_strcpy(fw_url->url, url);
|
|
if (keyword == IP_FALSE)
|
|
{
|
|
fw_url->len = (Ip_u16)ipfirewall_http_str_st_len(fw_url->url, '/', (int)ipcom_strlen(fw_url->url));
|
|
if (!fw_url->len)
|
|
fw_url->len = (Ip_u16)ipcom_strlen(fw_url->url);
|
|
fw_url->attr = IPFIREWALL_URL_SPECIFIC_PATH;
|
|
}
|
|
else
|
|
{
|
|
fw_url->len = (Ip_u16)ipcom_strlen(fw_url->url);
|
|
fw_url->attr = IPFIREWALL_URL_KEYWORD;
|
|
}
|
|
ipcom_list_insert_last(&fw_http->head_url, &fw_url->list_url);
|
|
out:
|
|
ipnet_resume_stack(suspend_handle);
|
|
return ret;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipfirewall_http_insert_proxy_filter
|
|
*===========================================================================
|
|
* Description: Enable proxy filter in a HTTP filter.
|
|
* Parameters: id - filter identifier.
|
|
* Returns: IPCOM_SUCCESS or error code.
|
|
*/
|
|
IP_PUBLIC Ip_err
|
|
ipfirewall_http_insert_proxy_filter(const char *id)
|
|
{
|
|
void *suspend_handle;
|
|
Ipfirewall_http *fw_http;
|
|
Ip_err ret = IPCOM_SUCCESS;
|
|
|
|
/* Find HTTP filter */
|
|
suspend_handle = ipnet_suspend_stack();
|
|
if (suspend_handle == IP_NULL)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipfirewall_http_insert_proxy_filter :: Could not suspend stack");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
fw_http = ipfirewall_http_find(id);
|
|
if (fw_http != IP_NULL)
|
|
{
|
|
fw_http->proxy = IP_TRUE;
|
|
}
|
|
else
|
|
{
|
|
IPCOM_LOG1(ERR, "ipfirewall_http_insert_proxy_filter() :: HTTP filter '%s' not found", id);
|
|
ret = IPCOM_ERR_NOT_FOUND;
|
|
}
|
|
ipnet_resume_stack(suspend_handle);
|
|
return ret;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipfirewall_http_insert_cookie_filter
|
|
*===========================================================================
|
|
* Description: Enable cookie filter in a HTTP filter.
|
|
* Parameters: id - filter identifier.
|
|
* Returns: IPCOM_SUCCESS or error code.
|
|
*/
|
|
IP_PUBLIC Ip_err
|
|
ipfirewall_http_insert_cookie_filter(const char *id)
|
|
{
|
|
void *suspend_handle;
|
|
Ipfirewall_http *fw_http;
|
|
Ip_err ret = IPCOM_SUCCESS;
|
|
|
|
/* Find HTTP filter */
|
|
suspend_handle = ipnet_suspend_stack();
|
|
if (suspend_handle == IP_NULL)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipfirewall_http_insert_cookie_filter :: Could not suspend stack");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
fw_http = ipfirewall_http_find(id);
|
|
if (fw_http != IP_NULL)
|
|
{
|
|
fw_http->cookie = IP_TRUE;
|
|
}
|
|
else
|
|
{
|
|
IPCOM_LOG1(ERR, "ipfirewall_http_insert_cookie_filter() :: HTTP filter '%s' not found", id);
|
|
ret = IPCOM_ERR_NOT_FOUND;
|
|
}
|
|
ipnet_resume_stack(suspend_handle);
|
|
return ret;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipfirewall_http_insert_java_filter
|
|
*===========================================================================
|
|
* Description: Enable java filter in a HTTP filter.
|
|
* Parameters: id - filter identifier.
|
|
* Returns: IPCOM_SUCCESS or error code.
|
|
*/
|
|
IP_PUBLIC Ip_err
|
|
ipfirewall_http_insert_java_filter(const char *id)
|
|
{
|
|
void *suspend_handle;
|
|
Ipfirewall_http *fw_http;
|
|
Ip_err ret = IPCOM_SUCCESS;
|
|
|
|
/* Find HTTP filter */
|
|
suspend_handle = ipnet_suspend_stack();
|
|
if (suspend_handle == IP_NULL)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipfirewall_http_insert_java_filter :: Could not suspend stack");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
fw_http = ipfirewall_http_find(id);
|
|
if (fw_http != IP_NULL)
|
|
{
|
|
fw_http->java= IP_TRUE;
|
|
}
|
|
else
|
|
{
|
|
IPCOM_LOG1(ERR, "ipfirewall_http_insert_java_filter() :: HTTP filter '%s' not found", id);
|
|
ret = IPCOM_ERR_NOT_FOUND;
|
|
}
|
|
ipnet_resume_stack(suspend_handle);
|
|
return ret;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipfirewall_http_insert_activex_filter
|
|
*===========================================================================
|
|
* Description: Enable active filter in a HTTP filter.
|
|
* Parameters: id - filter identifier.
|
|
* Returns: IPCOM_SUCCESS or error code.
|
|
*/
|
|
IP_PUBLIC Ip_err
|
|
ipfirewall_http_insert_activex_filter(const char *id)
|
|
{
|
|
void *suspend_handle;
|
|
Ipfirewall_http *fw_http;
|
|
Ip_err ret = IPCOM_SUCCESS;
|
|
|
|
/* Find HTTP filter */
|
|
suspend_handle = ipnet_suspend_stack();
|
|
if (suspend_handle == IP_NULL)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipfirewall_http_insert_activex_filter :: Could not suspend stack");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
fw_http = ipfirewall_http_find(id);
|
|
if (fw_http != IP_NULL)
|
|
{
|
|
fw_http->activex = IP_TRUE;
|
|
}
|
|
else
|
|
{
|
|
IPCOM_LOG1(ERR, "ipfirewall_http_insert_activex_filter() :: HTTP filter '%s' not found", id);
|
|
ret = IPCOM_ERR_NOT_FOUND;
|
|
}
|
|
ipnet_resume_stack(suspend_handle);
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipfirewall_http_add_filter
|
|
*===========================================================================
|
|
* Description: Add a HTTP filter.
|
|
* Parameters: id - filter identifier.
|
|
* Returns: IPCOM_SUCCESS or error code.
|
|
*/
|
|
IP_PUBLIC Ip_err
|
|
ipfirewall_http_add_filter(const char *id)
|
|
{
|
|
void *suspend_handle;
|
|
Ipfirewall_http *fw_http;
|
|
Ip_err ret = IPCOM_SUCCESS;
|
|
|
|
/* Check for duplicate */
|
|
suspend_handle = ipnet_suspend_stack();
|
|
if (suspend_handle == IP_NULL)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipfirewall_http_add_filter :: Could not suspend stack");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
fw_http = ipfirewall_http_find(id);
|
|
if (fw_http != IP_NULL)
|
|
{
|
|
IPCOM_LOG1(ERR, "ipfirewall_http_add_filter() :: HTTP filter '%s' already exists", id);
|
|
ret = IPCOM_ERR_DUPLICATE;
|
|
goto out;
|
|
}
|
|
|
|
if(ipcom_strlen(id) >= sizeof(fw_http->identifier))
|
|
{
|
|
ret = IPCOM_ERR_FAILED;
|
|
goto out;
|
|
}
|
|
|
|
/* Allocate the HTTP filter structure */
|
|
fw_http = ipcom_malloc(sizeof(*fw_http));
|
|
if(fw_http == IP_NULL)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipfirewall_http_add_filter() :: Could not allocate memory for HTTP filter entry");
|
|
ret = IPCOM_ERR_NO_MEMORY;
|
|
goto out;
|
|
}
|
|
|
|
/* Populate the HTTP filter structure */
|
|
ipcom_memset(fw_http, 0, sizeof(*fw_http));
|
|
ipcom_strcpy(fw_http->identifier, id);
|
|
ipcom_list_init(&fw_http->head_url);
|
|
|
|
/* Insert the HTTP filter structure in list */
|
|
ipcom_list_insert_last(&head_http, &fw_http->list_http);
|
|
out:
|
|
ipnet_resume_stack(suspend_handle);
|
|
return ret;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipfirewall_http_remove_filter
|
|
*===========================================================================
|
|
* Description: Remove a HTTP filter.
|
|
* Parameters: id - filter identifier.
|
|
* Returns: IPCOM_SUCCESS or error code.
|
|
*/
|
|
IP_PUBLIC Ip_err
|
|
ipfirewall_http_remove_filter(const char *id)
|
|
{
|
|
void *suspend_handle;
|
|
#ifdef IPFIREWALL_USE_IP_STATEFUL
|
|
Ipfirewall_state *fw_state;
|
|
#endif
|
|
Ipfirewall_rule *fw_rule;
|
|
Ipfirewall_http *fw_http;
|
|
Ipfirewall_url *fw_url;
|
|
Ip_err ret = IPCOM_SUCCESS;
|
|
|
|
suspend_handle = ipnet_suspend_stack();
|
|
if (suspend_handle == IP_NULL)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipfirewall_http_remove_filter :: Could not suspend stack");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
|
|
/* Verify that there are no rules that refer this HTTP filter */
|
|
#ifdef IPFIREWALL_USE_MAC_FILTER
|
|
if (ret == IPCOM_SUCCESS)
|
|
{
|
|
for (fw_rule = IPCOM_LIST_FIRST(&ipfirewall->mac_head_rule_input);
|
|
fw_rule != IP_NULL;
|
|
fw_rule = IPCOM_LIST_NEXT(&fw_rule->list_rule))
|
|
{
|
|
if (fw_rule->inner.userdef == 1
|
|
&& ipcom_strcmp((char *)fw_rule->inner.userdef_id, IPFIREWALL_HTTP_FILTER_ID) == 0
|
|
&& ipcom_strcmp(fw_rule->inner.userdef_param, id) == 0)
|
|
{
|
|
IPCOM_LOG3(ERR, "ipfirewall_unregister_userdef() :: "
|
|
"Cannot remove HTTP filter '%s' since MAC filter rule @%d:%d "
|
|
"refers to it.",
|
|
fw_rule->inner.userdef_param, fw_rule->inner.group_no, fw_rule->inner.rule_no);
|
|
ret = IPCOM_ERR_FAILED;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (ret == IPCOM_SUCCESS)
|
|
{
|
|
for (fw_rule = IPCOM_LIST_FIRST(&ipfirewall->mac_head_rule_output);
|
|
fw_rule != IP_NULL;
|
|
fw_rule = IPCOM_LIST_NEXT(&fw_rule->list_rule))
|
|
{
|
|
if (fw_rule->inner.userdef == 1
|
|
&& ipcom_strcmp((char *)fw_rule->inner.userdef_id, IPFIREWALL_HTTP_FILTER_ID) == 0
|
|
&& ipcom_strcmp(fw_rule->inner.userdef_param, id) == 0)
|
|
{
|
|
IPCOM_LOG3(ERR, "ipfirewall_unregister_userdef() :: "
|
|
"Cannot remove HTTP filter '%s' since MAC filter rule @%d:%d "
|
|
"refers to it.",
|
|
fw_rule->inner.userdef_param, fw_rule->inner.group_no, fw_rule->inner.rule_no);
|
|
ret = IPCOM_ERR_FAILED;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
#endif /* #ifdef IPFIREWALL_USE_MAC_FILTER */
|
|
|
|
#ifdef IPFIREWALL_USE_IP_FILTER
|
|
if (ret == IPCOM_SUCCESS)
|
|
{
|
|
for (fw_rule = IPCOM_LIST_FIRST(&ipfirewall->head_rule_input);
|
|
fw_rule != IP_NULL;
|
|
fw_rule = IPCOM_LIST_NEXT(&fw_rule->list_rule))
|
|
{
|
|
if (fw_rule->inner.userdef == 1
|
|
&& ipcom_strcmp((char *)fw_rule->inner.userdef_id, IPFIREWALL_HTTP_FILTER_ID) == 0
|
|
&& ipcom_strcmp(fw_rule->inner.userdef_param, id) == 0)
|
|
{
|
|
IPCOM_LOG3(ERR, "ipfirewall_unregister_userdef() :: "
|
|
"Cannot remove HTTP filter '%s' since IP filter rule @%d:%d "
|
|
"refers to it.",
|
|
fw_rule->inner.userdef_param, fw_rule->inner.group_no, fw_rule->inner.rule_no);
|
|
ret = IPCOM_ERR_FAILED;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (ret == IPCOM_SUCCESS)
|
|
{
|
|
for (fw_rule = IPCOM_LIST_FIRST(&ipfirewall->head_rule_output);
|
|
fw_rule != IP_NULL;
|
|
fw_rule = IPCOM_LIST_NEXT(&fw_rule->list_rule))
|
|
{
|
|
if (fw_rule->inner.userdef == 1
|
|
&& ipcom_strcmp((char *)fw_rule->inner.userdef_id, IPFIREWALL_HTTP_FILTER_ID) == 0
|
|
&& ipcom_strcmp(fw_rule->inner.userdef_param, id) == 0)
|
|
{
|
|
IPCOM_LOG3(ERR, "ipfirewall_unregister_userdef() :: "
|
|
"Cannot remove HTTP filter '%s' since IP filter rule @%d:%d "
|
|
"refers to it.",
|
|
fw_rule->inner.userdef_param, fw_rule->inner.group_no, fw_rule->inner.rule_no);
|
|
ret = IPCOM_ERR_FAILED;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
#endif /* #ifdef IPFIREWALL_USE_IP_FILTER */
|
|
|
|
#ifdef IPFIREWALL_USE_IP_STATEFUL
|
|
if (ret == IPCOM_SUCCESS)
|
|
{
|
|
for (fw_state = IPCOM_LIST_FIRST(&ipfirewall->head_state);
|
|
fw_state != IP_NULL;
|
|
fw_state = IPCOM_LIST_NEXT(&ipfirewall->head_state))
|
|
{
|
|
fw_rule=(Ipfirewall_rule *)fw_state->fw_rule;
|
|
|
|
if ((fw_rule!=IP_NULL)&&(fw_rule->inner.userdef==1)
|
|
&&(ipcom_strcmp((char *)fw_rule->inner.userdef_id,IPFIREWALL_HTTP_FILTER_ID)==0)
|
|
&&(ipcom_strcmp(fw_rule->inner.userdef_param, id)==0))
|
|
{
|
|
ipfirewall_clean_state(fw_state);
|
|
}
|
|
}
|
|
}
|
|
#endif /* IPFIREWALL_USE_IP_STATEFUL */
|
|
|
|
/* Find HTTP filter */
|
|
if (ret == IPCOM_SUCCESS)
|
|
{
|
|
fw_http = ipfirewall_http_find(id);
|
|
if (fw_http != IP_NULL)
|
|
{
|
|
/* Clear URL list */
|
|
while((fw_url = IPCOM_LIST_LAST(&fw_http->head_url)) != IP_NULL)
|
|
{
|
|
ipcom_list_remove(&fw_url->list_url);
|
|
if (fw_url->url != IP_NULL)
|
|
ipcom_free(fw_url->url); /* Clear URL string */
|
|
ipcom_free(fw_url);
|
|
}
|
|
/* Remove from HTTP filter list */
|
|
ipcom_list_remove(&fw_http->list_http);
|
|
ipcom_free(fw_http);
|
|
}
|
|
else
|
|
{
|
|
IPCOM_LOG1(ERR, "ipfirewall_http_add() :: HTTP filter '%s' not found", id);
|
|
ret = IPCOM_ERR_NOT_FOUND;
|
|
}
|
|
}
|
|
ipnet_resume_stack(suspend_handle);
|
|
return ret;
|
|
}
|
|
|
|
#else
|
|
int ipfirewall_userdef_http_empty_file;
|
|
#endif /* #ifdef IPFIREWALL_USE_HTTP_FILTER */
|
|
|
|
/*
|
|
****************************************************************************
|
|
* END OF FILE
|
|
****************************************************************************
|
|
*/
|