#include <linux/errno.h>
#include <linux/string.h>
#include <linux/types.h>
#include <net/net_namespace.h>
#include <net/netfilter/ipv4/nf_conntrack_ipv4.h>
#include <net/netfilter/nf_conntrack_tuple.h>
#include <net/netfilter/nf_conntrack_l3proto.h>
#include <net/netfilter/nf_conntrack_l4proto.h>
#include <linux/skbuff.h>
#include <net/netfilter/nf_conntrack_core.h>
#include "../modules/userhash/k-userhash.h" 
#include "../modules/usercfgrcv/usercfg_kinit.h"
#include <asm-generic/int-ll64.h>
#include <linux/netfilter.h>

extern struct list_head hash_array[];
extern freeauth_configure_t *kfreeauth;

/*匹配免认证规则 */
int judge(u_int8_t proto, __be32 sip, __be32 dip, __be16 dport )
{
    /*免认证规则要求是http报文,http基于tcp协议 */
    if (proto != 6) return 0;

    if ((sip != kfreeauth->sip) && (dip != kfreeauth->dip)) return 0;

    if (dport != kfreeauth->dport) return 0;

    return 1;
}


int match_rule(const struct sk_buff *skb,u_int16_t l3num,
                    struct net *net,struct nf_conntrack_tuple *tuple)
{
    const struct nf_conntrack_l3proto *l3proto;
	const struct nf_conntrack_l4proto *l4proto;
    unsigned int nhoff;   /*nhoff表示L3首部在skb中的偏移 */
	unsigned int protoff; 
	u_int8_t protonum;
    unsigned int dataoff; /*dataoff表示L4首部在skb中的偏移 */
    int ret;
    int result;

    USERINFO *kresult;
    kresult = (USERINFO *)kmalloc(sizeof(USERINFO), GFP_KERNEL);
    if (NULL == kresult)
    {
        return ENOMEM;
    }

    /*获取版本号、源端口、目的端口、源IP、目的IP */
    /*nf_ct_get_tuple函数主要根据协议号调用pkt_to_tuple生成一个tuple */
    /*tcp/udp协议就是生成五元组(源ip、目的ip、源端口、目的端口、协议号),icmp协议就是(id、code、type) */
    ret = nf_ct_get_tuple(skb, nhoff, protoff, l3num, protonum, net, tuple,l3proto, l4proto);
    if(ret == 0)
    {
        printk("resolve_normal_ct: Can't get tuple\n");
        kfree(kresult);
        return EIO; 
    }
 
    /*1.判断用户认证成功 ——非重定向
    2.判断是否符合免认证规则 ——非重定向
    3.判断目的端口是否是80—— 重定向标记
    4.目的端口不是80的情况下,判断协议是否是DHCP和DNS,如果是DHCP和DNS——非重定向
    5.其余包 drop*/
    kresult = search_user(tuple->src.u3.ip);
   
    /*用户已经认证通过 */
    if(kresult != NULL) 
    {
        kfree(kresult);
        return NF_ACCEPT;
    }
  
    /*报文匹配免认证规则 */
    result = judge(tuple->dst.protonum, tuple->src.u3.ip, tuple->dst.u3.ip, tuple->dst.u.tcp.port );
    if (result == 1)
    {
       kfree(kresult);
       return NF_ACCEPT;
    }
    
    /*80端口接入的HTTP报文重定向到Web Server */
    if((tuple->dst.protonum == 6) && (tuple->dst.u.tcp.port == 80))
    {
        /*打重定向Mark标记 */
        kfree(kresult);
    }
    else
    {
        /*dhcp报文 dns报文 默认放行 */
        if((tuple->dst.u.tcp.port == 67) || (tuple->dst.u.tcp.port == 68) || (tuple->dst.u.tcp.port ==53))
        {
            kfree(kresult);
            return NF_ACCEPT;
        }
        
    }  

    kfree(kresult);          
    return NF_DROP;         
}