www.pudn.com > Firewall_PNE_3_3.zip > fwHooks.c, change:2009-03-16,size:18557b


/* fwHooks.c - Implement firewall hooks */

/* Copyright 2004-2005 Wind River Systems, Inc. */
#include "copyright_wrs.h"

/*
modification history
--------------------
01h,30sep05,myz  fixed the problem of restoring data to a consumed packet
01g,13dec04,myz  added IPV6 support
01f,13jul04,myz  port to dual stack
01e,03mar04,svk  Remove NAT hook typedef
01d,10feb04,myz  correct the packet length problem at the input hook
01c,17oct03,zhu  Added NAT filter hooks into preinput and output hooks
01b,01oct03,vks  code cleanup, copyright info, comments
01a,03dec02,vks  created
*/

/*
DESCRIPTION
This file supplies the fw hook implementations. The four fw hooks 
for both IPV4 stack and IPV6 stack are implemented here.
*/

#include "fw.h"

#define INITIAL_VALUE  0xff

/*******************************************************************************
*
* fwPreinputHook - The wrapper routine for rule filter at the pre-input location
*  
* This routine will be invoked from the filter chain at the pre-input location.
* This function in turn calls the rule filter.
*
* RETURNS: 
*     IPFW_ACCEPT if no filter exists, or if the packet is accepted
*     IPFW_REJECT if the packet is rejected
*/

int fwPreinputHook
    (
    ipfw_t * pFilter,
    struct mbuf **mp, 
    UINT32 dir,
    ipfw_opt_t * pOpt
    )
    {
    struct ip *ip = mtod(*mp, struct ip *);
    u_long r;
    u_long actionCode = IPFW_REJECT;
  
    /* The rule filter assumes the ip_len and ip_off are already converted into 
     * the host byte order.
     */

    ip->ip_len = ntohs(ip->ip_len);
    ip->ip_off = ntohs(ip->ip_off);

doItAgain:
    r = ruleFilter(pFilter, *mp, dir, pOpt);

    /*
     * check if mbuf is changed. If so, pull it out here.  */

    if (pOpt->bits & IPFWB_MBUF) 
        {
	if ((*mp = pOpt->mbuf) == NULL)
            return (IPFW_REJECT);

        /* the new ip packet pointer */ 

        ip = mtod(*mp, struct ip *);
        }

        
    switch (r & FW_RETCODE) 
        {
        case FW_REJECT|FW_ICMP:
            icmp_error(*mp, (r & FW_ICMPTYPE) >> 8,(r & FW_ICMPCODE), 0, 0);

            /* the packet will be freed by icmp_error */

            *mp = 0;
            pOpt->mbuf = *mp;
            pOpt->bits |= IPFWB_MBUF;
            actionCode =  IPFW_REJECT;
            break;

        case FW_REJECT|FW_TCP_RESET:
            if (fwRewrite(pFilter,*mp,0,pOpt) == FW_ACCEPT)
                {
                actionCode = IPFW_ACCEPT;
                if (pOpt->bits & IPFWB_MBUF)
                    {
                    if ((*mp = pOpt->mbuf) == NULL)
                        actionCode = IPFW_REJECT;
                    else
                        ip = mtod(*mp, struct ip *);
                    }
                }
            else
                actionCode = IPFW_REJECT;
            break; 

        case FW_FRAG_REASSEMBLE:
	    {
            ULONG retCode;
           
            retCode = fwRewrite(pFilter,*mp,IPFWF_FILTER1,pOpt);

            if (pOpt->bits & IPFWB_MBUF)
                {
                *mp = pOpt->mbuf;
                if (*mp)
                    ip = mtod(*mp, struct ip *);
                }

            if ((retCode == FW_ACCEPT) && ((*mp) != NULL))
                { 
                if (pOpt->bits & IPFWB_MBUF) 
                    {
                    pOpt->bits = 0;
                    goto doItAgain;
                    }
                else
                    /* should not happen */

                    actionCode = IPFW_REJECT;
                }
            else
                actionCode = IPFW_REJECT;
            }
            break;
              
        default:
        case FW_REJECT:
            actionCode = IPFW_REJECT;
            break;

        case FW_ACCEPT:
            actionCode = IPFW_ACCEPT;
            break;
        }

    if (actionCode == IPFW_REJECT)
        /* packet dropped, don't restore byte order of ip_len and ip_off*/

        return IPFW_REJECT;
    else
        {
        /* convert it back to the byte order when it came in */

        if (*mp)
            {
            ip->ip_len = htons(ip->ip_len);
            ip->ip_off = htons(ip->ip_off);
            }

        return (pFilter->next == NULL ? IPFW_ACCEPT : IPFW_NEXT);
	}
    }

/*******************************************************************************
*
* fwInputHook - The wrapper function for rule filter at the input location. 
*  
* This routine will be invoked from the filter chain at the input location.
* This function in turn calls the rule filter.
*
* RETURNS: 
*     IPFW_ACCEPT if no filter exists, or if the packet is accepted
*     IPFW_REJECT if the packet is rejected
*
*/

int fwInputHook
    (
    ipfw_t * pFilter,
    struct mbuf **mp, 
    UINT32 dir,
    ipfw_opt_t * pOpt
    )
    {
    u_long r;
    struct ip *ip;

    /* the rule filter assumes the ip_len and ip_off are already in host
     * byte order.
     */

    ip = mtod(*mp, struct ip *);

    ip->ip_len  = ntohs(ip->ip_len);
    ip->ip_off  = ntohs(ip->ip_off);

    r = ruleFilter(pFilter, *mp, dir, pOpt);

    switch (r & FW_RETCODE) {
        case FW_ACCEPT:
            break;
        default:
        case FW_REJECT:
            return (IPFW_REJECT);
        }

    /* packet passed this filter, restore back byte order of ip_len and ip_off*/

    ip->ip_len  = htons(ip->ip_len);
    ip->ip_off  = htons(ip->ip_off);

    return (pFilter->next == NULL ? IPFW_ACCEPT : IPFW_NEXT);
    }

/*******************************************************************************
*
* fwForwardHook - The wrapper function for rule filter at the forward location. 
*  
* This routine will be invoked from the filter chain at the forward location.
* This function in turn calls the rule filter.
*
* RETURNS: 
*     IPFW_ACCEPT if no filter exists, or if the packet is accepted
*     IPFW_REJECT if the packet is rejected
*/
int fwForwardHook
    (
    ipfw_t * pFilter,
    struct mbuf **mp, 
    UINT32 dir,
    ipfw_opt_t * pOpt
    )
    {
    u_long r;
    struct ip *ip;

    /* the rule filter assumes the ip_len and ip_off are already in host
     * byte order.
     */

    ip = mtod(*mp, struct ip *);

    ip->ip_len  = ntohs(ip->ip_len);
    ip->ip_off  = ntohs(ip->ip_off);

    r = ruleFilter(pFilter, *mp, dir, pOpt);

    switch (r & FW_RETCODE) 
        {
        case FW_ACCEPT:
            break;
        default:
        case FW_REJECT:
            return (IPFW_REJECT);
        }
   
    /* packet passed this filter, restore back byte order of ip_len and ip_off*/

    ip = mtod(*mp, struct ip *);
    ip->ip_len  = htons(ip->ip_len);
    ip->ip_off  = htons(ip->ip_off);

    return (pFilter->next == NULL ? IPFW_ACCEPT : IPFW_NEXT);
    }


/*******************************************************************************
*
* fwOutputHook - The wrapper function for rule filter at the output location. 
*  
* This routine will be invoked from the filter chain at the output location.
* This function in turn calls the rule filter.
*
* RETURNS: 
*     IPFW_ACCEPT if no filter exists, or if the packet is accepted
*     IPFW_REJECT if the packet is rejected
*/

int fwOutputHook
    (
    ipfw_t * pFilter,
    struct mbuf **mp, 
    UINT32 dir,
    ipfw_opt_t * pOpt
    )
    {
    u_long r;
    struct ip *ip;

    /* the rule filter assumes the ip_len and ip_off are already in host
     * byte order.
     */

    ip = mtod(*mp, struct ip *);

    ip->ip_len  = ntohs(ip->ip_len);
    ip->ip_off  = ntohs(ip->ip_off);

    r = ruleFilter(pFilter, *mp, dir, pOpt);

    switch (r & FW_RETCODE) 
        {
        default:
        case FW_REJECT:
            return (IPFW_REJECT);
        case FW_ACCEPT:
            break;
        }
    /* packet passed this filter, restore back byte order of ip_len and ip_off*/

    ip = mtod(*mp, struct ip *);
    ip->ip_len  = htons(ip->ip_len);
    ip->ip_off  = htons(ip->ip_off);

    return (pFilter->next == NULL ? IPFW_ACCEPT : IPFW_NEXT);
    }

#ifdef INET6
/*******************************************************************************
*
* fwPreinputV6Hook - The wrapper routine for rule filter at the pre-inputV6 
*  
* This routine will be invoked from the filter chain at the pre-input location.
* This function in turn calls the rule filter.
*
* RETURNS: 
*     IPFW_ACCEPT if no filter exists, or if the packet is accepted
*     IPFW_REJECT if the packet is rejected
*/

int fwPreinputV6Hook
    (
    ipfw_t * pFilter,
    struct mbuf **mp, 
    UINT32 dir,
    ipfw_opt_t * pOpt
    )
    {
    u_long r;
    u_long actionCode = IPFW_REJECT;
  

doItAgain:
    r = ruleFilter(pFilter, *mp, dir, pOpt);

    /* check if mbuf is changed. If so, pull it out here.  */

    if (pOpt->bits & IPFWB_MBUF) 
        {
	if ((*mp = pOpt->mbuf) == NULL)
            return (IPFW_REJECT);
        }
        
    switch (r & FW_RETCODE) 
        {
        case FW_REJECT|FW_ICMP:
            {
            struct ip6_hdr * ip6;

            ip6 = mtod(*mp,struct ip6_hdr *);

            if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src))
                ip6->ip6_src.s6_addr16[1]
                        = htons((*mp)->m_pkthdr.rcvif->if_index);
            if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst))
                ip6->ip6_dst.s6_addr16[1]
                        = htons((*mp)->m_pkthdr.rcvif->if_index);

            icmp6_error(*mp, (r & FW_ICMPTYPE) >> 8,(r & FW_ICMPCODE), 0);

            /* the packet will be freed by icmp_error */

            *mp = 0;
            pOpt->mbuf = *mp;
            pOpt->bits |= IPFWB_MBUF;
            actionCode =  IPFW_REJECT;
            }
            break;

        case FW_REJECT|FW_TCP_RESET:
            if (fwRewrite(pFilter,*mp,0,pOpt) == FW_ACCEPT)
                {
                actionCode = IPFW_ACCEPT;
                if (pOpt->bits & IPFWB_MBUF)
                    {
                    if ((*mp = pOpt->mbuf) == NULL)
                        actionCode = IPFW_REJECT;
                    }
                }
            else
                actionCode = IPFW_REJECT;
            break; 

        case FW_FRAG_REASSEMBLE:
	    {
            ULONG retCode;
           
            retCode = fwRewrite(pFilter,*mp,IPFWF_FILTER1,pOpt);

            if (pOpt->bits & IPFWB_MBUF)
                *mp = pOpt->mbuf;

            if ((retCode == FW_ACCEPT) && ((*mp) != NULL))
                { 
                if (pOpt->bits & IPFWB_MBUF) 
                    {
                    pOpt->bits = 0;
                    goto doItAgain;
                    }
                else
                    /* should not happen */

                    actionCode = IPFW_REJECT;
                }
            else
                actionCode = IPFW_REJECT;
            }
            break;
              
        default:
        case FW_REJECT:
            actionCode = IPFW_REJECT;
            break;

        case FW_ACCEPT:
            actionCode = IPFW_ACCEPT;
            break;
        }

    if (actionCode == IPFW_REJECT)
        return IPFW_REJECT;
    else
        return (pFilter->next == NULL ? IPFW_ACCEPT : IPFW_NEXT);
    }

/*******************************************************************************
*
* fwInputV6Hook - The wrapper for rule filter at the IPV6 input location. 
*  
* This routine will be invoked from the filter chain at the IPV6 input location.
* This function in turn calls the rule filter.
*
* RETURNS: 
*     IPFW_ACCEPT if no filter exists, or if the packet is accepted
*     IPFW_REJECT if the packet is rejected
*
*/

int fwInputV6Hook
    (
    ipfw_t * pFilter,
    struct mbuf **mp, 
    UINT32 dir,
    ipfw_opt_t * pOpt
    )
    {
    u_long r;
    struct ip6_hdr * ip6;
    UINT8 srcScope[2] = {INITIAL_VALUE,INITIAL_VALUE};
    UINT8 dstScope[2] = {INITIAL_VALUE,INITIAL_VALUE};

    ip6 = mtod(*mp,struct ip6_hdr *);

    /* When the packet arrives here, both source and destination addresses
     * may have been modified to contain the scope information if they are
     * the link local addresses. Remove it before sending to ruleFilter.
     */

    if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src))
        { 
        srcScope[0] = ip6->ip6_src.s6_addr8[2];
        srcScope[1] = ip6->ip6_src.s6_addr8[3];
        ip6->ip6_src.s6_addr8[2] = 0;
        ip6->ip6_src.s6_addr8[3] = 0;
        }

    if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst))
        {
        dstScope[0] = ip6->ip6_dst.s6_addr8[2];
        dstScope[1] = ip6->ip6_dst.s6_addr8[3];
        ip6->ip6_dst.s6_addr8[2] = 0;
        ip6->ip6_dst.s6_addr8[3] = 0;
        }

    r = ruleFilter(pFilter, *mp, dir, pOpt);

    switch (r & FW_RETCODE) {
        case FW_ACCEPT:
            break;
        default:
        case FW_REJECT:
            return (IPFW_REJECT);
        }

    /* restore the scope info if packet pass this filter */
                                                                                
    if (srcScope[0] != (UINT8)INITIAL_VALUE ||
        srcScope[1] != (UINT8)INITIAL_VALUE)
        {
        ip6->ip6_src.s6_addr8[2] = srcScope[0];
        ip6->ip6_src.s6_addr8[3] = srcScope[1];
        }
                                                                                
    if (dstScope[0] != (UINT8)INITIAL_VALUE ||
        dstScope[1] != (UINT8)INITIAL_VALUE)
        {
        ip6->ip6_dst.s6_addr8[2] = dstScope[0];
        ip6->ip6_dst.s6_addr8[3] = dstScope[1];
        }
                                                                                
    return (pFilter->next == NULL ? IPFW_ACCEPT : IPFW_NEXT);
    }

/*******************************************************************************
*
* fwForwardV6Hook - The wrapper for rule filter at the IPV6 forward location. 
*  
* This routine will be invoked from the filter chain at the IPV6 forward 
* location. This function in turn calls the rule filter.
*
* RETURNS: 
*     IPFW_ACCEPT if no filter exists, or if the packet is accepted
*     IPFW_REJECT if the packet is rejected
*/
int fwForwardV6Hook
    (
    ipfw_t * pFilter,
    struct mbuf **mp, 
    UINT32 dir,
    ipfw_opt_t * pOpt
    )
    {
    u_long r;
    struct ip6_hdr * ip6;
    UINT8 srcScope[2] = {INITIAL_VALUE,INITIAL_VALUE};
    UINT8 dstScope[2] = {INITIAL_VALUE,INITIAL_VALUE};

    ip6 = mtod(*mp,struct ip6_hdr *);

    /* When the packet arrives here, both source and destination addresses
     * may have been modified to contain the scope information if they are
     * the link local addresses. Remove it before sending to ruleFilter.
     * Forward location usually should not get the link-local address
     * packets, just in case.
     */

    if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src))
        {
        srcScope[0] = ip6->ip6_src.s6_addr8[2];
        srcScope[1] = ip6->ip6_src.s6_addr8[3];
        ip6->ip6_src.s6_addr8[2] = 0;
        ip6->ip6_src.s6_addr8[3] = 0;
        }

    if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst))
        {
        dstScope[0] = ip6->ip6_dst.s6_addr8[2];
        dstScope[1] = ip6->ip6_dst.s6_addr8[3];
        ip6->ip6_dst.s6_addr8[2] = 0;
        ip6->ip6_dst.s6_addr8[3] = 0;
        }

    r = ruleFilter(pFilter, *mp, dir, pOpt);

    switch (r & FW_RETCODE) 
        {
        case FW_ACCEPT:
            break;
        default:
        case FW_REJECT:
            return (IPFW_REJECT);
        }

    /* restore the scope info if packet passes this filter */
                                                                                
    if (srcScope[0] != (UINT8)INITIAL_VALUE ||
        srcScope[1] != (UINT8)INITIAL_VALUE)
        {
        ip6->ip6_src.s6_addr8[2] = srcScope[0];
        ip6->ip6_src.s6_addr8[3] = srcScope[1];
        }
                                                                                
    if (dstScope[0] != (UINT8)INITIAL_VALUE ||
        dstScope[1] != (UINT8)INITIAL_VALUE)
        {
        ip6->ip6_dst.s6_addr8[2] = dstScope[0];
        ip6->ip6_dst.s6_addr8[3] = dstScope[1];
        }
                                                                                
    return (pFilter->next == NULL ? IPFW_ACCEPT : IPFW_NEXT);
    }


/*******************************************************************************
*
* fwOutputV6Hook - The wrapper for rule filter at the IPV6 output location. 
*  
* This routine will be invoked from the filter chain at the IPV6 output 
* location.  This function in turn calls the rule filter.
*
* RETURNS: 
*     IPFW_ACCEPT if no filter exists, or if the packet is accepted
*     IPFW_REJECT if the packet is rejected
*/

int fwOutputV6Hook
    (
    ipfw_t * pFilter,
    struct mbuf **mp, 
    UINT32 dir,
    ipfw_opt_t * pOpt
    )
    {
    u_long r;
    struct ip6_hdr * ip6;
    UINT8 srcScope[2] = {INITIAL_VALUE,INITIAL_VALUE};
    UINT8 dstScope[2] = {INITIAL_VALUE,INITIAL_VALUE};

    ip6 = mtod(*mp,struct ip6_hdr *);

    /* When the packet arrives here, both source and destination addresses
     * may have been modified to contain the scope information if they are
     * the link local addresses. Remove it before sending to ruleFilter.
     */

    if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src))
        {
        srcScope[0] = ip6->ip6_src.s6_addr8[2];
        srcScope[1] = ip6->ip6_src.s6_addr8[3];
        ip6->ip6_src.s6_addr8[2] = 0;
        ip6->ip6_src.s6_addr8[3] = 0;
        }

    if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst))
        {
        dstScope[0] = ip6->ip6_dst.s6_addr8[2];
        dstScope[1] = ip6->ip6_dst.s6_addr8[3];
        ip6->ip6_dst.s6_addr8[2] = 0;
        ip6->ip6_dst.s6_addr8[3] = 0;
        }

    r = ruleFilter(pFilter, *mp, dir, pOpt);

    switch (r & FW_RETCODE) 
        {
        default:
        case FW_REJECT:
            return (IPFW_REJECT);
        case FW_ACCEPT:
            break;
        }

    /* restore the scope info if packet passes this filter*/
                                                                                
    if (srcScope[0] != (UINT8)INITIAL_VALUE ||
        srcScope[1] != (UINT8)INITIAL_VALUE)
        {
        ip6->ip6_src.s6_addr8[2] = srcScope[0];
        ip6->ip6_src.s6_addr8[3] = srcScope[1];
        }
                                                                                
    if (dstScope[0] != (UINT8)INITIAL_VALUE ||
        dstScope[1] != (UINT8)INITIAL_VALUE)
        {
        ip6->ip6_dst.s6_addr8[2] = dstScope[0];
        ip6->ip6_dst.s6_addr8[3] = dstScope[1];
        }
                                                                                
    return (pFilter->next == NULL ? IPFW_ACCEPT : IPFW_NEXT);
    }
#endif