Files
m241Neelima/components/ip_net2-6.9/ipfirewall/src/ipfirewall_mac.c
T
2026-07-30 11:19:44 +05:30

681 lines
23 KiB
C

/*
******************************************************************************
* INTERPEAK SOURCE FILE
*
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipfirewall_mac.c,v $ $Revision: 1.35.16.2 $
* $Source: /home/interpeak/CVSRoot/ipfirewall/src/ipfirewall_mac.c,v $
* $Author: svc-cmnet $
* $State: Exp $ $Locker: $
*
* INTERPEAK_COPYRIGHT_STRING
* Design and implementation by Markus Carlstedt <markus@interpeak.se>
******************************************************************************
*/
/*
****************************************************************************
* 1 DESCRIPTION
****************************************************************************
* MAC filter.
*/
/*
****************************************************************************
* 2 CONFIGURATION
****************************************************************************
*/
#include "ipfirewall_config.h"
/*
****************************************************************************
* 3 INCLUDE FILES
****************************************************************************
*/
#ifdef IPFIREWALL_USE_MAC_FILTER
#define IPCOM_USE_CLIB_PROTO
#include <ipcom_type.h>
#include <ipcom_cstyle.h>
#include <ipcom_clib.h>
#include <ipcom_sock.h>
#include <ipcom_syslog.h>
#include <ipcom_shell.h>
#include <ipcom_err.h>
#include <ipcom_sysvar.h>
#include <ipcom_time.h>
#define IPFIREWALL_C
#include "ipfirewall.h"
#include "ipfirewall_h.h"
/*
****************************************************************************
* 4 DEFINES
****************************************************************************
*/
/*
*===========================================================================
* IPFIREWALL_STATS
*===========================================================================
* MAC Filter statistics counters
*/
#ifdef IPFIREWALL_USE_MAC_STATISTICS
#define IPFIREWALL_STATS(xentry) ipfirewall->inner.stats.xentry
#else
#define IPFIREWALL_STATS(xentry) IP_NOOP
#endif
/*
*===========================================================================
* IPFIREWALL_MAC_IS_ME
*===========================================================================
* Check if MAC frame address is local
*/
#define IPFIREWALL_MAC_IS_ME(pktaddr, netif) \
(netif->link_addr_size == IPFIREWALL_MAC_ADDRESS_LEN && \
((Ip_u16 *)pktaddr)[0] == ((Ip_u16 *)netif->link_addr)[0] && \
((Ip_u16 *)pktaddr)[1] == ((Ip_u16 *)netif->link_addr)[1] && \
((Ip_u16 *)pktaddr)[2] == ((Ip_u16 *)netif->link_addr)[2])
/*
*===========================================================================
* IPFIREWALL_MAC_COMPARE
*===========================================================================
* Compare MAC frame address with rule address
*/
#define IPFIREWALL_MAC_COMPARE(addr, mask, pktaddr) \
(((Ip_u16 *)addr)[0] == (((Ip_u16 *)pktaddr)[0] & ((Ip_u16 *)mask)[0]) && \
((Ip_u16 *)addr)[1] == (((Ip_u16 *)pktaddr)[1] & ((Ip_u16 *)mask)[1]) && \
((Ip_u16 *)addr)[2] == (((Ip_u16 *)pktaddr)[2] & ((Ip_u16 *)mask)[2]))
/*
*===========================================================================
* IPFIREWALL_MAC_TEST_ADRESS
*===========================================================================
* Test MAC address against rule
*/
#define IPFIREWALL_MAC_TEST_ADRESS(any, me, not, addr, mask, pktaddr, netif) \
{ \
if (any) \
{ \
if (not) \
continue; \
} \
else if (me) \
{ \
if (IPFIREWALL_MAC_IS_ME(pktaddr, netif)) \
{ \
if (not) \
continue; \
} \
else if (!not) \
continue; \
} \
else \
{ \
if (IPFIREWALL_MAC_COMPARE(addr, mask, pktaddr)) \
{ \
if (not) \
continue; \
} \
else if (!not) \
continue; \
} \
}
/*
****************************************************************************
* 5 TYPES
****************************************************************************
*/
/*
****************************************************************************
* 6 EXTERN PROTOTYPES
****************************************************************************
*/
/*
****************************************************************************
* 7 LOCAL PROTOTYPES
****************************************************************************
*/
/*
****************************************************************************
* 8 DATA
****************************************************************************
*/
/*
****************************************************************************
* 9 LOCAL FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipfirewall_mac_log_pkt
*===========================================================================
* Description: Log a packet that matched a MAC filter rule.
* Parameters: fw_rule - pointer to the rule.
* netif - pointer to interface.
* pkt - pointer to packet.
* Returns: nothing.
*/
IP_STATIC void
ipfirewall_mac_log_pkt(Ipfirewall_rule *fw_rule, Ipcom_netif *netif, Ipcom_pkt *pkt)
{
Ipfirewall_mac_log *fw_mac_log;
struct Ip_timeval logtime;
if(fw_rule->inner.log_first == 1 && fw_rule->inner.log_hit == 1)
{
IPCOM_LOG2(DEBUG, "ipfirewall_log_pkt() :: MAC rule @%d:%d has already caused a log entry",
fw_rule->inner.group_no, fw_rule->inner.rule_no);
return;
}
if(ipfirewall->mac_head_log.size >= IPFIREWALL_MAX_MAC_LOG_ENTRIES)
{
IPCOM_LOG0(DEBUG, "ipfirewall_mac_log_pkt() :: Maximum number of log entries reached");
IPFIREWALL_STATS(mac_log_failures++);
return;
}
fw_mac_log = ipcom_malloc(sizeof(*fw_mac_log));
if(fw_mac_log == IP_NULL)
{
IPCOM_LOG0(ERR, "ipfirewall_mac_log_pkt() :: Could not allocate memory for log entry");
IPFIREWALL_STATS(mac_log_failures++);
return;
}
ipcom_memset(fw_mac_log, 0, sizeof(*fw_mac_log));
/* Populate the log entry */
ipcom_microtime(&logtime);
fw_mac_log->inner.tv_sec = (Ip_s32)logtime.tv_sec;
fw_mac_log->inner.tv_usec = (Ip_s32)logtime.tv_usec;
ipcom_strcpy((char *)fw_mac_log->inner.ifname, (char *)netif->name);
fw_mac_log->inner.rule_no = fw_rule->inner.rule_no;
fw_mac_log->inner.group_no = fw_rule->inner.group_no;
fw_mac_log->inner.block = fw_rule->inner.block;
ipcom_memcpy(fw_mac_log->inner.dst, &pkt->data[pkt->start], IPFIREWALL_MAC_ADDRESS_LEN);
ipcom_memcpy(fw_mac_log->inner.src, &pkt->data[pkt->start+IPFIREWALL_MAC_ADDRESS_LEN], IPFIREWALL_MAC_ADDRESS_LEN);
ipcom_memcpy(&fw_mac_log->inner.type_n, &pkt->data[pkt->start+IPFIREWALL_MAC_ADDRESS_LEN*2], 2);
fw_mac_log->inner.length = pkt->end - pkt->start - IPFIREWALL_MAC_HEADER_LEN;
ipcom_memcpy(fw_mac_log->inner.frame,
&pkt->data[pkt->start + IPFIREWALL_MAC_HEADER_LEN],
IP_MIN((Ip_size_t)fw_mac_log->inner.length, sizeof(fw_mac_log->inner.frame)));
ipcom_list_insert_last(&ipfirewall->mac_head_log, &fw_mac_log->list_log);
IPCOM_LOG2(DEBUG, "ipfirewall_mac_log_pkt() :: Logged packet from MAC rule @%d:%d",
fw_rule->inner.group_no, fw_rule->inner.rule_no);
if(fw_rule->inner.log_first == 1)
fw_rule->inner.log_hit = 1;
if(fw_rule->inner.block == 1)
{
if(fw_rule->inner.in == 1)
IPFIREWALL_STATS(mac_in_logged_block++);
else
IPFIREWALL_STATS(mac_out_logged_block++);
}
else
{
if(fw_rule->inner.in == 1)
IPFIREWALL_STATS(mac_in_logged_pass++);
else
IPFIREWALL_STATS(mac_out_logged_pass++);
}
} /*lint !e429 */
/*
*===========================================================================
* ipfirewall_mac_check_rules
*===========================================================================
* Description: Check packet against MAC filter rules.
* Parameters: in - IP_TRUE for incoming packet.
* netif - pointer to interface.
* pkt - pointer to packet.
* Returns: 1 = Block packet.
* 0 = Pass packet.
*/
IP_STATIC Ip_s32
ipfirewall_mac_check_rules(Ipcom_netif *netif, Ipcom_pkt *pkt, Ip_bool in)
{
Ipfirewall_rule *fw_rule;
Ipfirewall_rule *lastmatch = IP_NULL;
int current_group = 0;
Ip_u8 quick_head = 0;
Ip_u16 mac_type_n;
Ip_u8 ssap_n = 0;
Ip_u8 dsap_n = 0;
ip_assert(pkt);
ip_assert(pkt->data);
ip_assert(pkt->end > pkt->start);
if (in == IP_TRUE)
fw_rule = IPCOM_LIST_FIRST(&ipfirewall->mac_head_rule_input);
else
fw_rule = IPCOM_LIST_FIRST(&ipfirewall->mac_head_rule_output);
/* Match packet against mac rules */
for (; fw_rule != IP_NULL; fw_rule = IPCOM_LIST_NEXT(&fw_rule->list_rule))
{
if (ipfirewall->inner.mac_num_head_rules)
{
if (quick_head && current_group != fw_rule->inner.group_no)
break;
if (fw_rule->inner.group_no == 0)
{
current_group = 0;
quick_head = 0;
}
}
if (current_group == fw_rule->inner.group_no || fw_rule->inner.group_head)
{
/* Check direction */
if (fw_rule->inner.in)
{
if (in == IP_FALSE)
continue; /* Direction does not match */
}
else if (in == IP_TRUE)
{
continue; /* Direction does not match */
}
/* Check interface */
if(fw_rule->inner.on)
{
#ifdef IPNET_USE_VLAN
if (fw_rule->inner.in
&& netif->type != IP_IFT_L2VLAN
&& ((Ipnet_netif *)netif)->eth != IP_NULL
&& (ip_ntohs(*(Ip_u16 *)&pkt->data[pkt->start + IPFIREWALL_MAC_ADDRESS_LEN*2]) == 0x8100
#ifdef IPCOM_USE_HW_VLAN_TAGGING
|| IP_BIT_ISSET(pkt->flags, IPCOM_PKT_FLAG_VLAN_TAG)
#endif
)
&& ((Ipnet_netif *)netif)->eth->vlan.ifs != IP_NULL)
{
/* Find the correct VLAN interface */
Ipnet_netif *ipnet_netif;
int vid;
#ifdef IPCOM_USE_HW_VLAN_TAGGING
if (IP_BIT_ISSET(pkt->flags, IPCOM_PKT_FLAG_VLAN_TAG))
vid = IPNET_ETH_PKT_GET_VLAN_TAG(pkt) & 0x0fff;
else
#endif /* IPCOM_USE_HW_VLAN_TAGGING */
vid = IPNET_ETH_VLAN_GET_VID(*(Ip_u16 *)&pkt->data[pkt->start + IPFIREWALL_MAC_HEADER_LEN]);
ipnet_netif = ipcom_hash_get(((Ipnet_netif *)netif)->eth->vlan.ifs, &vid);
if (ipnet_netif != IP_NULL)
netif = &ipnet_netif->ipcom;
}
#endif
#ifdef IPFIREWALL_PHYSICAL_IF_SUPPORT
/* Check the physical interface before the logical interface */
if(fw_rule->inner.on_phys &&
(pkt->physical_netif != IP_NULL) ) {
if (fw_rule->inner.physical_ifindex)
{
/* Fast check */
IPFIREWALL_TEST_INTERFACE(fw_rule->inner.on_not,
fw_rule->inner.physical_ifindex,
pkt->physical_netif->ifindex)
}
else
{
/* Slow check */
if (ipfirewall_match_interface(fw_rule,
pkt->physical_netif) == 0)
continue; /* Interface does not match */
}
}
#endif
/* Check interface */
if (fw_rule->inner.on)
{
if (fw_rule->inner.ifindex)
{
/* Fast check */
IPFIREWALL_TEST_INTERFACE(fw_rule->inner.on_not, fw_rule->inner.ifindex, netif->ifindex)
}
else
{
/* Slow check */
if (ipfirewall_match_interface(fw_rule, netif) == 0)
continue; /* Interface does not match */
}
}
}
/* Check source and destination address */
if (fw_rule->inner.from)
{
IPFIREWALL_MAC_TEST_ADRESS(fw_rule->inner.src_any, fw_rule->inner.src_me, fw_rule->inner.src_not,
&fw_rule->inner.mac_src,
&fw_rule->inner.mac_src_mask,
&pkt->data[pkt->start + IPFIREWALL_MAC_ADDRESS_LEN],
netif)
IPFIREWALL_MAC_TEST_ADRESS(fw_rule->inner.dst_any, fw_rule->inner.dst_me, fw_rule->inner.dst_not,
&fw_rule->inner.mac_dst,
&fw_rule->inner.mac_dst_mask,
&pkt->data[pkt->start],
netif)
}
/* Check MAC type */
if (fw_rule->inner.mac_type)
{
#ifdef IPCOM_USE_HW_VLAN_TAGGING
if (IP_BIT_ISSET(pkt->flags, IPCOM_PKT_FLAG_VLAN_TAG))
mac_type_n = ip_htons(0x8100);
else
#endif
mac_type_n = *(Ip_u16 *)&pkt->data[pkt->start + IPFIREWALL_MAC_ADDRESS_LEN*2];
if (fw_rule->inner.the_mac_type_n != mac_type_n)
{
continue; /* MAC type does not match */
}
}
mac_type_n = *(Ip_u16 *)&pkt->data[pkt->start + IPFIREWALL_MAC_ADDRESS_LEN*2];
/* Check for the 802.2 frame type */
if(fw_rule->inner.frame_802_2 == 1)
{
if(ip_ntohs(mac_type_n) > IPFIREWALL_MAC_802_3_MAX_LEN)
continue; /* Not an 802.2 frame */
}
if(fw_rule->inner.dsap == 1 ||
fw_rule->inner.ssap == 1 ||
fw_rule->inner.snap_vendor == 1 ||
fw_rule->inner.snap_type == 1)
{
if(ip_ntohs(mac_type_n) > IPFIREWALL_MAC_802_3_MAX_LEN)
continue; /* Not an 802.2 frame */
dsap_n = *(Ip_u8 *)&pkt->data[pkt->start +
IPFIREWALL_MAC_HEADER_LEN];
ssap_n = *(Ip_u8 *)&pkt->data[pkt->start +
IPFIREWALL_MAC_HEADER_LEN + 1];
}
if(fw_rule->inner.dsap == 1)
{
IPFIREWALL_TEST_SAP(fw_rule->inner.dsap_not,
fw_rule->inner.the_dsap_n , dsap_n)
}
if(fw_rule->inner.ssap == 1)
{
IPFIREWALL_TEST_SAP(fw_rule->inner.ssap_not,
fw_rule->inner.the_ssap_n , ssap_n)
}
if(fw_rule->inner.snap_vendor == 1)
{
/* DSAP and SSAP must be 0xaa for a SNAP header
* to be present */
if((ssap_n != 0xaa) || (dsap_n != 0xaa))
continue;
IPFIREWALL_TEST_SNAP_VENDOR(fw_rule->inner.snap_vendor_not,
&fw_rule->inner.the_snap_vendor_n,&pkt->data[pkt->start +
IPFIREWALL_MAC_HEADER_LEN + IPFIREWALL_LLC_HEADER_LEN])
}
if(fw_rule->inner.snap_type == 1)
{
Ip_u16 snap_type_n;
/* DSAP and SSAP must be 0xaa for a SNAP header
* to be present */
if((ssap_n != 0xaa) || (dsap_n != 0xaa))
continue;
snap_type_n =
*(Ip_u16 *)&pkt->data[pkt->start +
IPFIREWALL_MAC_HEADER_LEN + IPFIREWALL_LLC_HEADER_LEN + 3];
IPFIREWALL_TEST_SNAP(fw_rule->inner.snap_type_not,
fw_rule->inner.the_snap_type_n , snap_type_n)
}
/* Packet matched rule - check rate limiting */
if(fw_rule->inner.limit)
{
if (ipfirewall_compare_limit(fw_rule) == 0)
continue;
}
#ifdef IPFIREWALL_USE_USERDEF
/* Call user defined function */
if(fw_rule->inner.userdef && fw_rule->user_match != IP_NULL)
{
IPCOM_LOG2(DEBUG2, "ipfirewall_mac_check_rules() :: Calling user defined match function id: %s with paramater string: %s",
(char *)fw_rule->inner.userdef_id, fw_rule->inner.userdef_param);
if (fw_rule->user_match(pkt, fw_rule->userdef_cookie, fw_rule->userdef_info) == 0)
continue;
}
#endif
IPCOM_LOG2(DEBUG, "ipfirewall_mac_check_rules() :: Matched MAC rule @%d:%d", fw_rule->inner.group_no, fw_rule->inner.rule_no);
lastmatch = fw_rule;
if(!fw_rule->inner.group_head)
{
if (fw_rule->inner.quick)
break;
}
else
{
current_group = fw_rule->inner.group_no;
quick_head = fw_rule->inner.quick;
}
}
}
if(lastmatch == IP_NULL)
{
if(in == IP_TRUE)
IPFIREWALL_STATS(mac_in_nomatch++);
else
IPFIREWALL_STATS(mac_out_nomatch++);
#ifdef IPFIREWALL_BLOCK_IF_NO_MAC_MATCH
/* Return block code */
return 1;
#else
/* Return pass code */
return 0;
#endif
}
else
{
if(lastmatch->inner.log == 1)
ipfirewall_mac_log_pkt(lastmatch, netif, pkt); /* Log the packet */
/* Update statistics */
if(lastmatch->inner.block)
{
if(in == IP_TRUE)
IPFIREWALL_STATS(mac_in_block++);
else
IPFIREWALL_STATS(mac_out_block++);
/* Return block code */
return 1;
}
else
{
if(in == IP_TRUE)
IPFIREWALL_STATS(mac_in_pass++);
else
IPFIREWALL_STATS(mac_out_pass++);
/* Return pass code */
return 0;
}
}
}
/*
****************************************************************************
* 10 GLOBAL FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipfirewall_mac_internal_get_rule
*===========================================================================
* Description: Get MAC filter rule entry.
* Parameters: ctrl - pointer to control structure.
* lenp - pointer to length of returned data.
* in - Rule direction
* Returns: 0 = success.
* <0 = fail.
*/
IP_GLOBAL Ip_s32
ipfirewall_mac_internal_get_rule(Ipfirewall_ctrl *ctrl, Ip_socklen_t *lenp, Ip_bool in)
{
Ipfirewall_rule *fw_rule;
Ip_u32 i;
/* Get the specified entry */
if (in == IP_TRUE)
fw_rule = IPCOM_LIST_FIRST(&ipfirewall->mac_head_rule_input);
else
fw_rule = IPCOM_LIST_FIRST(&ipfirewall->mac_head_rule_output);
for(i=0; i<ctrl->seqno && fw_rule != IP_NULL; i++)
fw_rule = IPCOM_LIST_NEXT(&fw_rule->list_rule);
/* Check if the entry existed */
if(fw_rule == IP_NULL)
{
*lenp = 0;
return 0;
}
ipcom_memcpy(&ctrl->type.rule_info, &fw_rule->inner, sizeof(fw_rule->inner));
*lenp = sizeof(*ctrl);
return 0;
}
/*
*===========================================================================
* ipfirewall_mac_internal_get_log
*===========================================================================
* Description: Get MAC filter log entry.
* Parameters: ctrl - pointer to control structure.
* lenp - pointer to length of returned data.
* Returns: 0 = success.
* <0 = fail.
*/
IP_GLOBAL Ip_s32
ipfirewall_mac_internal_get_log(Ipfirewall_ctrl *ctrl, Ip_socklen_t *lenp)
{
Ipfirewall_mac_log *fw_mac_log;
Ip_u32 i;
/* Get the specified entry */
fw_mac_log = IPCOM_LIST_FIRST(&ipfirewall->mac_head_log);
for(i=0; i<ctrl->seqno && fw_mac_log != IP_NULL; i++)
fw_mac_log = IPCOM_LIST_NEXT(&fw_mac_log->list_log);
/* Check if the entry existed */
if(fw_mac_log == IP_NULL)
{
*lenp = 0;
return 0;
}
ipcom_memcpy(&ctrl->type.mac_log_info, &fw_mac_log->inner, sizeof(fw_mac_log->inner));
*lenp = sizeof(*ctrl);
return 0;
}
/*
****************************************************************************
* 11 PUBLIC FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipfirewall_mac_input_hook
*===========================================================================
* Description: MAC filter input hook.
* Parameters: netif - pointer to interface.
* pkt - pointer to packet.
* Returns: 1 = Block packet.
* 0 = Pass packet.
*/
IP_PUBLIC Ip_s32
ipfirewall_mac_input_hook(Ipcom_netif *netif, Ipcom_pkt *pkt)
{
Ip_s32 ret;
if (ipfirewall->inner.enabled == 0 || ipfirewall->inner.mac_num_in_rules == 0)
return 0;
ret = ipfirewall_mac_check_rules(netif, pkt, IP_TRUE);
return ret;
}
/*
*===========================================================================
* ipfirewall_mac_output_hook
*===========================================================================
* Description: MAC filter output hook.
* Parameters: netif - pointer to interface.
* pkt - pointer to packet.
* Returns: 1 = Block packet.
* 0 = Pass packet.
*/
IP_PUBLIC Ip_s32
ipfirewall_mac_output_hook(Ipcom_netif *netif, Ipcom_pkt *pkt)
{
Ip_s32 ret;
if (ipfirewall->inner.enabled == 0 || ipfirewall->inner.mac_num_out_rules == 0)
return 0;
ret = ipfirewall_mac_check_rules(netif, pkt, IP_FALSE);
return ret;
}
#else
int ipfirewall_mac_empty_file;
#endif /* #ifdef IPFIREWALL_USE_MAC_FILTER */
/*
****************************************************************************
* END OF FILE
****************************************************************************
*/