以下代码如何向内核中的另一个进行传递参数#include <linux/version.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/udp.h>
#include <linux/skbuff.h>
#include <linux/in.h>
#include <linux/netfilter/x_tables.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv6/ip6_tables.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
#include <net/netfilter/nf_conntrack_extend.h>
#include <net/netfilter/nf_conntrack_acct.h>
#endif
#include "ipt_urlset_match.h"
#include "acsmx.h"
#include<urlfilter_netlink.h>
#include<libipt_urlfilter_target.h>
#include<urlfilter_bitmap.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#define HOST_STR "\r\nHost: "
#define GET_METHOD "GET"
#define FIRST_FEW_PACKET 5
#define PORT_HTTP (80)
#define PORT_HTTPS (443)
#define TLS_SHAKEHAND_HEAD (5)
#define TLS_CLIENTHELLO_HEAD (38)
#define MAX_CLIENT_HELLO_LEN (1500)
#define TLS_SERVER_NAME_TYPE (0x0)
#define URL_LEN (128)
typedef unsigned char u_int8_t;
#define DEBUG_INFO 0
#if DEBUG_INFO
#define URL_DEBUG(fmt,arg...) printk(KERN_ERR "[urlset_match] %s():%d "fmt"\n", __FUNCTION__, __LINE__, ##arg)
#else
#define URL_DEBUG(fmt,arg...)
#endif
struct urlFilter_lru_node
{
struct list_head hlist;
struct list_head list;
char domain[URL_LEN];
char category[CATEGORY_LEN];
bitmap categories_bitmap[CATEGORIES_BITMAP_LEN];
uint16_t category_id;
uint16_t status; // 0:已经发起查询,但是还未收到结果;1:查询成功,得到分类结果;2:得到返回结果,但结果为NULL
};
struct urlFilter_lru_entry
{
struct list_head node_list;
unsigned int curr; /* current cell num in list */
};
struct urlFilter_lru_cache
{
struct urlFilter_lru_entry *lru_htable;
struct urlFilter_lru_entry *lru_list;
mempool_t *node_mempool;
struct kmem_cache *node_memcache;
uint16_t num_bucket;
uint16_t num_node_all;
uint16_t num_node_max;
spinlock_t lock;
};
static pid_t urlFIlter_control_pid = -1;
static struct proc_dir_entry *proc_ent;
// static char proc_test[128] = {"tplink test"};
static int block_redirection = 0;
static char block_message[128] = {" "};
struct urlFilter_lru_entry *htable = NULL;
struct urlFilter_lru_entry *hentry = NULL;
static struct kmem_cache *node_memcache = NULL;
static mempool_t *node_mempool = NULL;
static atomic_t node_avlnum = {0};
int url_confirmed = 0;
uint32_t ip_tmp = 0;
struct urlFilter_lru_cache lru_head = {.lru_htable = NULL,
.lru_list = NULL,
.node_mempool = NULL,
.node_memcache = NULL,
.num_bucket = HT_SPEC,
.num_node_max = LIMIT_NODE_SPEC,
.num_node_all = 0};
extern ip_set_id_t url_set_get_byname(const char *name,struct url_set **);
extern void url_set_nfnl_put(ip_set_id_t index);
extern ip_set_id_t url_set_nfnl_get_byindex(ip_set_id_t index);
extern struct url_set *getSetByIndex(ip_set_id_t index);
extern int urlset_isContain(struct url_set *set,char* name);
extern int urlset_isContain2(struct url_set *set,char* name,int flag);
extern int urlset_isContain3(struct url_set *set,char* name);
extern int urlset_nat_slowpath_marking(struct nf_conn *ct);
extern int acsmSearch(ACSM_STRUCT * , unsigned char * , int ,
/*void(* Match)(ACSM_PATTERN * pattern, ACSM_PATTERN *mlist, int nline, int index)*/
void(* Match)(ACSM_PATTERN *, ACSM_PATTERN *, int));
/*
* binary ip to string ip
*/
static void
_urlset_inet_ntoa(u32 ip, char *ip_str, size_t size )
{
struct in_addr in;
char *p;
in.s_addr = ip;
p = (char *)∈
#define UC(ip_str) (((int)ip_str)&0xff)
(void)snprintf(ip_str, size,
"%u.%u.%u.%u", UC(p[0]), UC(p[1]), UC(p[2]), UC(p[3]));
return;
}
static inline u_int8_t *url_memstr(u_int8_t* start, uint32_t len, const u_int8_t* strCharSet)
{
uint32_t i = 0;
uint32_t pattern_len = (uint32_t)strlen((const char*)strCharSet);
if (pattern_len == 0 || len < pattern_len) {
return NULL;
}
return strnstr(start, strCharSet, len);
}
//flag:表示分段发生在type_length的第几个bytes之后,0表示没有发生在type_length
//data_buff:flag==0,data_buff指向16位的offset变量;0<flag<=3,data_buff指向type_length数据的开头
static void tls_ext_check_handle(struct nf_conn *ct, u_int32_t seq, u_int8_t flag, u_int8_t *data_buff)
{
if(!ct)
{
URL_DEBUG("ct is NULL");
return;
}
if(ct->ext_tls_check.seq >= seq) //不用重复处理,并且如果预期seq比ct->ext_tls_check.seq还小也不处理
return;
if(ct->ext_tls_check.seq) //先清理上次处理后ext_tls_check中保存的信息
{
memset(&ct->ext_tls_check, 0, sizeof(ct->ext_tls_check));
}
if(!data_buff)
{
URL_DEBUG("data_buff is NULL");
return;
}
if(flag < 0 || flag > 3)
{
URL_DEBUG("flag is invalid");
return;
}
ct->ext_tls_check.flag = flag;
ct->ext_tls_check.seq = seq;
URL_DEBUG("nextSeq is :%x", seq);
if (flag == 0)
{
memcpy(ct->ext_tls_check.data, data_buff, 2);
}
else if (flag > 0 && flag <= 3)
{
memcpy(ct->ext_tls_check.data, data_buff, flag);
}
return;
}
bool urlset_tls_ext_partition_check(u_int8_t *pTcpPayload, u_int16_t tcpPayloadLen, u_int8_t *url, u_int16_t *url_len,
u_int32_t tcp_seq, struct nf_conn *ct, const struct iphdr *iph)
{
u_int8_t *pTcpElms = NULL;
u_int16_t tcpElmsLen = 0;
u_int16_t tlsExtType = 0;
u_int16_t tlsExtLen = 0;
u_int16_t serverListLen = 0;
u_int8_t serverNameType = 0;
u_int16_t serverNameLen = 0;
u_int32_t seqNext = tcp_seq + tcpPayloadLen;
u_int16_t urlMaxLen = *url_len;
u_int16_t offset_tmp = 0;
u_int8_t server_name_flag = 0;
if (NULL == pTcpPayload || NULL == url || NULL == ct)
{
URL_DEBUG("para error");
return false;
}
if (NULL == url_len || urlMaxLen < URL_LEN)
{
URL_DEBUG("url len error, url_len = 0x%x, *url_len = %d, urlMaxLen = %d", url_len, *url_len, urlMaxLen);
return false;
}
u_int16_t url_size = *url_len;
*url_len = 0;
u_int8_t flag = ct->ext_tls_check.flag;
u_int8_t tl_offset = 4- flag;
u_int8_t tlv_tl[4] = {0};
u_int16_t offset = 0;
pTcpElms = pTcpPayload;
tcpElmsLen = tcpPayloadLen;
URL_DEBUG("pTcpElms == %x, tcpElmsLen:%d", *pTcpElms, tcpElmsLen);
if (flag == 0)
{
offset = *((u_int16_t *)ct->ext_tls_check.data);
if (tcpPayloadLen < offset)
{
URL_DEBUG("tlsExtTypeLength is parted");
//extension value is parted
offset_tmp = offset - tcpPayloadLen;
tls_ext_check_handle(ct, seqNext, 0, (u_int8_t *)&offset_tmp);
return false;
}
pTcpElms = pTcpPayload + offset;
tcpElmsLen = tcpPayloadLen - offset;
URL_DEBUG("offset == %d, pTcpElms:%x", offset, *pTcpElms);
}
else if (flag > 0 && flag <= 3)
{
if (tcpPayloadLen < tl_offset)
{
return false;
}
memcpy(tlv_tl, ct->ext_tls_check.data, flag);
memcpy(tlv_tl + flag, pTcpElms, tl_offset);
pTcpElms = pTcpPayload + tl_offset;
tcpElmsLen = tcpPayloadLen - tl_offset;
tlsExtType = ntohs(*((u_int16_t *)tlv_tl));
tlsExtLen = ntohs(*(((u_int16_t *)tlv_tl) + 1));
URL_DEBUG("tlsExtType:%d, tlsExtLen:%d", tlsExtType, tlsExtLen);
goto TLS_EXT_TL;
}
else
{
URL_DEBUG("flag error");
return false;
}
/* Parse Extension */
while (tcpElmsLen > 0)
{
if (tcpElmsLen < 4)
{
URL_DEBUG("tlsExtTypeLength is parted");
//extension的type_length被截断
tls_ext_check_handle(ct, seqNext, tcpElmsLen, pTcpElms);
return false;
}
if (tcpElmsLen < 2)
{
return false;
}
tlsExtType = ntohs(*((u_int16_t *)pTcpElms));
pTcpElms += 2;
tcpElmsLen -= 2;
if (tcpElmsLen < 2)
{
return false;
}
tlsExtLen = ntohs(*((u_int16_t *)pTcpElms));
pTcpElms += 2;
tcpElmsLen -= 2;
TLS_EXT_TL:
if (TLS_SERVER_NAME_TYPE == tlsExtType)
{
URL_DEBUG("find https TLS_SERVER_NAME_TYPE");
if (tcpElmsLen < tlsExtLen)
{
URL_DEBUG("tlsSniValue is parted");
//sni的value被截断
return false;
}
if (tcpElmsLen < 2)
{
return false;
}
serverListLen = ntohs(*((u_int16_t *)pTcpElms));
pTcpElms += 2;
tcpElmsLen -= 2;
if (tcpElmsLen < serverListLen)
{
URL_DEBUG("tcpElmsLen(%d) < serverListLen(%d)", tcpElmsLen, serverListLen);
return false;
}
while (serverListLen > 0)
{
serverNameType = *pTcpElms;
serverNameLen = ntohs(*((u_int16_t *)(pTcpElms + 1)));
if (serverListLen < serverNameLen + 3)
{
return false;
}
pTcpElms += 3;
serverListLen -= 3;
if (0x0 == serverNameType) /* HOST NAME */
{
URL_DEBUG("find TLS_HOST_NAME");
server_name_flag = 1;
if (urlMaxLen < serverNameLen + 1)
{
break;
}
strncpy(url + *url_len, pTcpElms, serverNameLen);
url[*url_len+serverNameLen] = ',';
urlMaxLen -= (serverNameLen + 1);
*url_len = *url_len + serverNameLen + 1;
}
pTcpElms += serverNameLen;
serverListLen -= serverNameLen;
}
tcpElmsLen -= serverListLen;
url[*url_len-1] = '\0';
return true;
}
else
{
if (tcpElmsLen < tlsExtLen)
//tcpElmsLen==tlsExtLen可能会发生截断,当client hello中的SNI在第三个分段报文或者之后,且截断刚好发生在上一个TLV的结尾时。
//但由于判断条件不足(需要新增字段记录ext length),这里tcpElmsLen==tlsExtLen时当作没有发生发生截断,否则可能对下一个携带数据的TCP报文进行意外拦截。
{
URL_DEBUG("not find TLS_HOST_NAME");
//extension value is parted
offset_tmp = tlsExtLen - tcpElmsLen;
tls_ext_check_handle(ct, seqNext, 0, (u_int8_t *)&offset_tmp);
return false;
}
pTcpElms += tlsExtLen;
tcpElmsLen -= tlsExtLen;
}
}
if(0 == server_name_flag)
{
_urlset_inet_ntoa(iph->daddr, url, url_size);
*url_len = strlen(url);
return true;
}
return false;
}
static bool urlset_https_url(u_int8_t *pTlsHelloPayload, u_int16_t tlsHelloLen, u_int8_t *url,
u_int16_t *url_len, u_int16_t payload_len, u_int32_t tcp_seq, struct nf_conn *ct, const struct iphdr *iph)
{
u_int8_t *pTlsElms = NULL;
u_int16_t tlsElmsLen = 0;
u_int8_t sessionIdLen = 0;
u_int16_t cipherSuiteLen = 0;
u_int8_t compressionLen = 0;
u_int16_t extensionLen = 0;
u_int16_t tlsExtType = 0;
u_int16_t tlsExtLen = 0;
u_int16_t serverListLen = 0;
u_int8_t serverNameType = 0;
u_int16_t serverNameLen = 0;
u_int16_t ipRemainLen = 0;
u_int32_t seqNext = tcp_seq + payload_len;
u_int16_t urlMaxLen = *url_len;
u_int16_t offset_tmp = 0;
u_int8_t server_name_flag = 0;
if (NULL == pTlsHelloPayload || tlsHelloLen < TLS_CLIENTHELLO_HEAD || NULL == url)
{
URL_DEBUG("para error");
return false;
}
if (NULL == url_len || urlMaxLen < URL_LEN)
{
URL_DEBUG("url len error, url_len = 0x%x, *url_len = %d, urlMaxLen = %d", url_len, *url_len, urlMaxLen);
return false;
}
u_int16_t url_size = *url_len;
*url_len = 0;
pTlsElms = pTlsHelloPayload + TLS_CLIENTHELLO_HEAD;
tlsElmsLen = tlsHelloLen - TLS_CLIENTHELLO_HEAD;
ipRemainLen = payload_len - TLS_SHAKEHAND_HEAD - TLS_CLIENTHELLO_HEAD;
/*
if (tlsElmsLen > MAX_CLIENT_HELLO_LEN)
{
URL_DEBUG("tlsElmsLen error");
return false;
}
*/
/* Session ID*/
if (tlsElmsLen > 0)
{
if (ipRemainLen < 1)
{
return false;
}
sessionIdLen = *pTlsElms;
if (tlsElmsLen < sessionIdLen + 1)
{
URL_DEBUG("tlsElmsLen(%d) < sessionIdLen(%d)", tlsElmsLen, sessionIdLen);
return false;
}
pTlsElms += (sessionIdLen + 1);
tlsElmsLen -= (sessionIdLen + 1);
ipRemainLen -= (sessionIdLen + 1);
}
/* Cipher Suites */
if (tlsElmsLen > 0)
{
if (ipRemainLen < 2)
{
return false;
}
cipherSuiteLen = ntohs(*((u_int16_t *)pTlsElms));
if (tlsElmsLen < cipherSuiteLen + 2)
{
URL_DEBUG("tlsElmsLen(%d) < cipherSuiteLen(%d)", tlsElmsLen, cipherSuiteLen);
return false;
}
pTlsElms += (cipherSuiteLen + 2);
tlsElmsLen -= (cipherSuiteLen + 2);
ipRemainLen -= (cipherSuiteLen + 2);
}
/* Compression Methods */
if (tlsElmsLen > 0)
{
if (ipRemainLen < 1)
{
return false;
}
compressionLen = *pTlsElms;
if (tlsElmsLen < compressionLen + 1)
{
URL_DEBUG("tlsElmsLen(%d) < compressionLen(%d)", tlsElmsLen, compressionLen);
return false;
}
pTlsElms += (compressionLen + 1);
tlsElmsLen -= (compressionLen + 1);
ipRemainLen -= (compressionLen + 1);
}
/* Extension */
if (tlsElmsLen > 0)
{
if (tlsElmsLen < 2 || ipRemainLen < 2)
{
URL_DEBUG("tlsElmsLen(%d) < 2 or ipRemainLen(%d) < 2", tlsElmsLen, ipRemainLen);
return false;
}
extensionLen = ntohs(*((u_int16_t *)pTlsElms));
pTlsElms += 2;
tlsElmsLen -= 2;
ipRemainLen -= 2;
if (tlsElmsLen != extensionLen)
{
URL_DEBUG("extensionLen wrong");
return false;
}
}
else
{
return false;
}
/* Parse Extension */
while (tlsElmsLen > 0 && ipRemainLen > 0)
{
if (ipRemainLen < 4)
{
URL_DEBUG("tlsExtTypeLength is parted");
//extension的type_length被截断
tls_ext_check_handle(ct, seqNext, ipRemainLen, pTlsElms);
return false;
}
if (tlsElmsLen < 2 || ipRemainLen < 2)
{
return false;
}
tlsExtType = ntohs(*((u_int16_t *)pTlsElms));
pTlsElms += 2;
tlsElmsLen -= 2;
ipRemainLen -= 2;
if (tlsElmsLen < 2 || ipRemainLen < 2)
{
return false;
}
tlsExtLen = ntohs(*((u_int16_t *)pTlsElms));
pTlsElms += 2;
tlsElmsLen -= 2;
ipRemainLen -= 2;
if (TLS_SERVER_NAME_TYPE == tlsExtType)
{
URL_DEBUG("find https TLS_SERVER_NAME_TYPE");
if (ipRemainLen < tlsExtLen)
{
URL_DEBUG("tlsSniValue is parted");
//sni的value被截断。不进行sni数据重组,直接跳过处理。
return false;
}
if (tlsElmsLen < 2 || ipRemainLen < 2)
{
return false;
}
serverListLen = ntohs(*((u_int16_t *)pTlsElms));
pTlsElms += 2;
tlsElmsLen -= 2;
ipRemainLen -= 2;
if (tlsElmsLen < serverListLen || ipRemainLen < serverListLen)
{
URL_DEBUG("tlsElmsLen(%d) < serverListLen(%d) or ipRemainLen(%d) < serverListLen(%d)",
tlsElmsLen, serverListLen, ipRemainLen, serverListLen);
return false;
}
while (serverListLen > 0)
{
serverNameType = *pTlsElms;
serverNameLen = ntohs(*((u_int16_t *)(pTlsElms + 1)));
if (serverListLen < serverNameLen + 3)
{
return false;
}
pTlsElms += 3;
serverListLen -= 3;
if (0x0 == serverNameType) /* HOST NAME */
{
URL_DEBUG("find TLS_HOST_NAME");
server_name_flag = 1;
if (urlMaxLen < serverNameLen + 1)
{
break;
}
strncpy(url + *url_len, pTlsElms, serverNameLen);
url[*url_len+serverNameLen] = ',';
urlMaxLen -= (serverNameLen + 1);
*url_len = *url_len + serverNameLen + 1;
}
pTlsElms += serverNameLen;
serverListLen -= serverNameLen;
}
tlsElmsLen -= serverListLen;
ipRemainLen -= serverListLen;
url[*url_len-1] = '\0';
return true;
}
else
{
if (tlsElmsLen < tlsExtLen)
{
URL_DEBUG("not find TLS_HOST_NAME");
return false;
}
if (ipRemainLen < tlsExtLen || (ipRemainLen == tlsExtLen && ipRemainLen < tlsElmsLen))
{
URL_DEBUG("not find TLS_HOST_NAME");
//extension value is parted
offset_tmp = tlsExtLen - ipRemainLen;
tls_ext_check_handle(ct, seqNext, 0, (u_int8_t *)&offset_tmp);
return false;
}
pTlsElms += tlsExtLen;
tlsElmsLen -= tlsExtLen;
ipRemainLen -= tlsExtLen;
}
}
if(0 == server_name_flag)
{
_urlset_inet_ntoa(iph->daddr, url, url_size);
*url_len = strlen(url);
return true;
}
return false;
}
int send_url_to_user(char *url)
{
int state = 0;
struct urlFilter_url_msg url_msg;
strncpy(url_msg.url, url, URL_LEN);
if(0 == urlFIlter_control_pid)
{
return -1;
}
if((state = genl_msg_send_to_user(&url_msg, sizeof(struct urlFilter_url_msg), urlFIlter_control_pid)) < 0)
{
return -1;
}
return 0;
}
// 计算hash值
int cal_hash_urlfilter(const char *key_param, int key_len)
{
unsigned int a;
unsigned int len;
u8 *key = (u8 *)key_param;
/* Set up the internal state */
len = (unsigned)key_len;
a = len;
while(len >= 4)
{
a += key[0] + (key[1] << 8) + (key[2] << 16) + (key[3] << 24);
a += ~(a << 15);
a ^= (a >> 10);
a += (a << 3);
a ^= (a >> 6);
a += ~(a << 11);
a ^= (a >> 16);
key += 4;
len -= 4;
}
/* All the case statements fall through */
switch(len)
{
case 3:
a += key[2] << 16;
case 2:
a ^= key[1] << 8;
case 1:
a += key[0];
default:
break;
}
a = a % (HT_SPEC - 1);
return a;
}
static void extract_content_before_slash( u_int8_t *abs_url)
{
char *delimiter = "/";
char *ptr = NULL;
ptr = strchr(abs_url, *delimiter);
if (ptr != NULL)
{
*ptr = '\0';
}
return;
}
static bool url_process(u_int16_t *abs_url_len, u_int8_t **abs_url_ptr, int url_len)
{
if(0 != *abs_url_len && '\0' != *abs_url_ptr[0])
{
if(0 == strncasecmp(*abs_url_ptr, "www.", 4))
{
*abs_url_ptr += 4;
*abs_url_len -= 4;
}
extract_content_before_slash(*abs_url_ptr);
return true;
}
return false;
}
static void *mempool_alloc_priv(mempool_t *pool, gfp_t gfp_mask)
{
if(atomic_sub_return(1, &node_avlnum) < 0)
{
atomic_set(&node_avlnum, 0);
return NULL;
}
return mempool_alloc(pool, gfp_mask);
}
static void mempool_free_priv(void *element, mempool_t *pool)
{
mempool_free(element, pool);
if(atomic_add_return(1, &node_avlnum) > LIMIT_NODE_SPEC)
atomic_set(&node_avlnum, LIMIT_NODE_SPEC);
}
int genl_msg_send_to_user(void *data, int len, pid_t pid)
{
struct sk_buff *skb;
size_t size;
void *head;
int rc;
size = nla_total_size(len); /* total length of attribute including padding */
// 构造netlink头部和genl netlink头部
rc = genl_msg_prepare_usr_msg(URLFILTER_CMD_SENDURL_K2U, size, pid, &skb);
if(rc)
{
return rc;
}
// 构造genl netlink的payload
rc = genl_msg_mk_usr_msg(skb, URLFILTER_ATT_SENDURL_K2U, data, len);
if(rc)
{
kfree_skb(skb);
return rc;
}
head = genlmsg_data(nlmsg_data(nlmsg_hdr(skb)));
genlmsg_end(skb, head);
if(rc < 0)
{
kfree_skb(skb);
return rc;
}
rc = genlmsg_unicast(&init_net, skb, pid); // 向客户端回发数据
if(rc < 0)
{
return rc;
}
return 0;
}
static inline int genl_msg_mk_usr_msg(struct sk_buff *skb, int type, void *data, int len)
{
int rc;
/* add a netlink attribute to a socket buffer */
if((rc = nla_put(skb, type, len, data)) != 0)
{
return rc;
}
return 0;
}
static inline int genl_msg_prepare_usr_msg(u8 cmd, size_t size, pid_t pid, struct sk_buff **skbp)
{
struct sk_buff *skb;
/* create a new netlink msg */
skb = genlmsg_new(size, GFP_ATOMIC);
if(skb == NULL)
{
return -ENOMEM;
}
/* Add a new netlink message to an skb */
genlmsg_put(skb, pid, 0, &urlFilter_gnl_family, 0, cmd);
*skbp = skb;
return 0;
}
void urlFilter_lru_cache_del_tail_node(void)
{
struct urlFilter_lru_node *urlFilter_node;
if ((NULL == lru_head.lru_htable) || (NULL == lru_head.lru_list) || list_empty(&lru_head.lru_list->node_list))
{
printk("urlFilter_lru_cache_del_tail_node return \n");
return;
}
urlFilter_node = list_last_entry(&lru_head.lru_list->node_list, struct urlFilter_lru_node, list);
list_del(&urlFilter_node->hlist);
list_del(&urlFilter_node->list);
mempool_free_priv(urlFilter_node, lru_head.node_mempool);
lru_head.num_node_all--;
lru_head.lru_list->curr--;
return;
}
static bool urlFilter_lru_cache_add_empty_node(char *url, struct urlFilter_lru_entry *hentry)
{
if(NULL == url)
return false;
char *url_to_find = url;
struct urlFilter_lru_node *urlFilter_node;
if(lru_head.num_node_all >= lru_head.num_node_max)
{
urlFilter_lru_cache_del_tail_node();
}
urlFilter_node = mempool_alloc_priv(lru_head.node_mempool, GFP_ATOMIC);
if(NULL == urlFilter_node)
{
return false;
}
strncpy(urlFilter_node->domain, url_to_find, URL_LEN);
strncpy(urlFilter_node->category, "NULL", NAME_LEN);
urlFilter_node->category_id = -1;
urlFilter_node->status = 0;
bitmap_clear_bit(urlFilter_node->categories_bitmap, CATEGORIES_BITMAP_LEN);
list_add(&urlFilter_node->hlist, &hentry->node_list);
list_add(&urlFilter_node->list, &lru_head.lru_list->node_list);
lru_head.num_node_all++;
lru_head.lru_list->curr++;
send_url_to_user(url_to_find);
return true;
}
static bool urlFilter_lru_cache_get(char *url, int *node_status, bitmap *categories_bitmap, int categories_bitmap_len)
{
if(NULL == lru_head.lru_htable)
return false;
char *url_to_find = url;
struct list_head *lh, *lh_tmp, *list_tmp;
struct urlFilter_lru_node *urlFilter_node;
struct urlFilter_lru_entry *hentry = NULL;
int num_hash = cal_hash_urlfilter(url_to_find, strlen(url_to_find));
hentry = lru_head.lru_htable + num_hash;
if(list_empty(&hentry->node_list))
{
if(!urlFilter_lru_cache_add_empty_node(url, hentry))
return false;
*node_status = 0;
return true;
}
list_for_each_safe(lh, lh_tmp, &hentry->node_list)
{
urlFilter_node = list_entry(lh, struct urlFilter_lru_node, hlist);
if(0 == strncmp(url_to_find, urlFilter_node->domain, URL_LEN)) // 比较长度具体值待确认
{
*node_status = urlFilter_node->status;
list_tmp = &urlFilter_node->list;
list_del(list_tmp);
list_add(list_tmp, &lru_head.lru_list->node_list);
memcpy(categories_bitmap, urlFilter_node->categories_bitmap, categories_bitmap_len);
return true;
}
}
if(!urlFilter_lru_cache_add_empty_node(url, hentry))
return false;
*node_status = 0;
return true;
}
int urlFilter_lru_cache_compare(bitmap *bitmap_a, bitmap *bitmap_b)
{
int result = 0;
int n = 0;
int i = 0;
int num_hit = 0;
int p_category[MAX_NUM_CATEGORIES];
int p_category_hit[MAX_NUM_CATEGORIES];
n = bitmap_get_nonzero_list(bitmap_a, CATEGORIES_BITMAP_LEN, p_category);
for(i = 0; i < n; i++)
{
result = bitmap_get_bit(bitmap_b, CATEGORIES_BITMAP_LEN, p_category[i]);
if(result)
{
p_category_hit[num_hit] = p_category[i];
num_hit++;
}
}
if(num_hit > 0)
{
return 1;
}
return 0;
}
static bool
xt_urlset_mt(const struct sk_buff *skb, struct xt_action_param *par)
{
const struct ipt_matchset *info= par->matchinfo;
const struct urlFilter_target *tinfo = param->targinfo;
const struct iphdr *iph = ip_hdr(skb);
struct tcphdr *tcph, _tcph; /* Must be TCP */
u_int16_t dport;
u_int16_t iphdrlen;
u_int16_t iptotlen;
u_int16_t tcphdrlen;
u_int8_t *http_payload_start = NULL;
u_int16_t http_payload_len = 0;
u_int8_t *http_uri = NULL;
u_int8_t *host_header_start = NULL;
u_int8_t *host_body_start = NULL;
u_int16_t host_body_len = 0;
u_int8_t *crlf_pos = NULL;
u_int8_t *pTlsHelloPayload = NULL;
u_int16_t tlsHelloLen = 0;
struct nf_conn *ct = NULL;
enum ip_conntrack_info ctinfo;
int i, index = 0;
int result = 0;
struct url_set *urlset = NULL;
u_int8_t req_host[URL_LEN];
u_int8_t req_uri[URL_LEN];
u_int8_t abs_url[2*URL_LEN] = {0};
u_int8_t *abs_url_ptr;
u_int16_t abs_url_len = 0;
int node_status = 0;
bitmap categories_bitmap[CATEGORIES_BITMAP_LEN] = {0};
bool is_http = true;
ct = nf_ct_get(skb, &ctinfo);
if(NULL == ct)
{
URL_DEBUG("ct is NULL\n");
return false; /* don't limit the untracked pkts. */
}
urlset_nat_slowpath_marking(ct);
tcph = skb_header_pointer(skb, par->thoff, sizeof(_tcph), &_tcph);
if (tcph == NULL) {
URL_DEBUG("Invalid tcp header.\n");
return false;
}
dport = ntohs(tcph->dest);
if (PORT_HTTP != dport && PORT_HTTPS != dport)
{
URL_DEBUG("No HTTP or HTTPS");
return false;
}
iphdrlen = iph->ihl*4;
iptotlen = ntohs(iph->tot_len);
tcphdrlen = tcph->doff*4;
http_payload_start = (u_int8_t *)tcph + tcphdrlen;
http_payload_len = iptotlen - iphdrlen - tcphdrlen;
if(http_payload_len < 4)
{
return false;
}
/*
URL_DEBUG("tot_len %d src=%08x,dst=%08x,id=%x,tot_len = %d,ip head = %d, tcp head=%d",
iph->tot_len, ntohl(iph->saddr),ntohl(iph->daddr),ntohs(iph->id),ntohs(iph->tot_len),iph->ihl*4,tcph->doff*4);
URL_DEBUG("http_payload_start %p, http_payload_len %d", http_payload_start, http_payload_len);
*/
if (unlikely(skb_linearize(skb)))
{
par->hotdrop = true;
URL_DEBUG("skb linearize failed.");
return false;
}
if (PORT_HTTPS == dport)
{
if(ct->ext_tls_check.seq != ntohl(tcph->seq))
{
if ((skb->len >= iptotlen) && (iptotlen > iphdrlen + tcphdrlen + TLS_SHAKEHAND_HEAD)
&& (0x16 == *http_payload_start) /* TLS SHAKEHAND */
&& (0x1) == *(http_payload_start + TLS_SHAKEHAND_HEAD)) /* TLS Client Hello */
{
pTlsHelloPayload = http_payload_start + TLS_SHAKEHAND_HEAD;
tlsHelloLen = ntohs(*((u_int16_t *)(http_payload_start + 3)));
/*
if (iptotlen < iphdrlen + tcphdrlen + TLS_SHAKEHAND_HEAD + tlsHelloLen)
{
URL_DEBUG("tlsHelloLen wrong");
return false;
}
*/
abs_url_len = sizeof(abs_url);
URL_DEBUG("pTlsHelloPayload:%d, tlsHelloLen:%d, http_payload_len:%d", pTlsHelloPayload, tlsHelloLen, http_payload_len);
if (!urlset_https_url(pTlsHelloPayload, tlsHelloLen, abs_url, &abs_url_len, http_payload_len, ntohl(tcph->seq), ct, iph))
{
URL_DEBUG("parse https url fail, seq:%x sport:%d, destIp:%pI4", ntohl(tcph->seq), ntohs(tcph->source), &(iph->daddr));
return false;
}
URL_DEBUG("https url : %s, seq:%x sport:%d, destIp:%pI4", abs_url, ntohl(tcph->seq), ntohs(tcph->source), &(iph->daddr));
is_http = false;
/* match "." which means all url */
if(info->flags & SPECIAL_FLAG)
{
URL_DEBUG("Match special flag");
return 1;
}
}
else
{
return false;
}
}
else
{
abs_url_len = sizeof(abs_url);
if (!urlset_tls_ext_partition_check(http_payload_start, http_payload_len, abs_url, &abs_url_len, ntohl(tcph->seq), ct, iph))
{
URL_DEBUG("parse https url fail, seq:%x sport:%d, destIp:%pI4", ntohl(tcph->seq), ntohs(tcph->source), &(iph->daddr));
return false;
}
URL_DEBUG("https url :%s, seq:%x sport:%d, destIp:%pI4", abs_url, ntohl(tcph->seq), ntohs(tcph->source), &(iph->daddr));
/* match "." which means all url */
if(info->flags & SPECIAL_FLAG)
{
URL_DEBUG("Match special flag");
return 1;
}
}
}
else
{
if(('G' == http_payload_start[0] || 'g' == http_payload_start[0])
&& ('E' == http_payload_start[1] || 'e' == http_payload_start[1])
&& ('T' == http_payload_start[2] || 't' == http_payload_start[2])
&& ' ' == http_payload_start[3])
{
http_uri = http_payload_start + 4;
for(i = 0; *http_uri !=' ' && i < URL_LEN - 1; ++ http_uri, ++i)
{
req_uri[i] = *http_uri;
}
req_uri[i] = 0;
if('/' == req_uri[0] && 0 == req_uri[1])
{
req_uri[0]=0;
}
URL_DEBUG("HTTP GET URI (%s)", req_uri);
host_header_start = url_memstr(http_payload_start, http_payload_len, HOST_STR);
}
else if(('P' == http_payload_start[0] || 'p' == http_payload_start[0])
&& ('O' == http_payload_start[1] || 'o' == http_payload_start[1])
&& ('S' == http_payload_start[2] || 's' == http_payload_start[2])
&& ('T' == http_payload_start[3] || 't' == http_payload_start[3])
&& ' ' == http_payload_start[4])
{
if(info->flags_submit_forbid == SUBMIT_FORBID)
{
return 1;
}
else
{
return 0;
}
}
/*
http_uri = http_payload_start + 5;
for(i = 0; *http_uri !=' ' && i < URL_LEN - 1; ++ http_uri, ++i)
{
req_uri[i] = *http_uri;
}
req_uri[i] = 0;
if('/' == req_uri[0] && 0 == req_uri[1])
{
req_uri[0]=0;
}
URL_DEBUG("HTTP POST URI (%s)", req_uri);
host_header_start = url_memstr(http_payload_start, http_payload_len, HOST_STR);
}
*/
if (host_header_start != NULL)
{
URL_DEBUG("find host in url string");
host_body_start = host_header_start + 8;
/* only check the first <URL_LEN> content. */
crlf_pos = url_memstr(host_body_start, URL_LEN, "\r\n");
URL_DEBUG("crlf_pos %p", crlf_pos);
if (crlf_pos == NULL)
{
return 0; /* Host without \r\n... */
}
/* match "." which means all url */
if(info->flags & SPECIAL_FLAG)
{
URL_DEBUG("Match special flag");
return 1;
}
host_body_len = crlf_pos - host_body_start;
req_host[0] = '\0';
memcpy(req_host, host_body_start, host_body_len);
req_host[host_body_len] = 0;
URL_DEBUG("get host:%s, len=%d", req_host, host_body_len);
abs_url_len = sprintf(abs_url,"%s%s", req_host, req_uri);
URL_DEBUG("get complete url:%s len:%d",abs_url, abs_url_len);
}
}
if(info->flags == CATEGORY_URL)
{
abs_url_ptr = abs_url;
if(!url_process(&abs_url_len, &abs_url_ptr, URL_LEN))
return 0;
spin_lock_bh(&lru_head.lock);
if(!urlFilter_lru_cache_get(abs_url_ptr, &node_status, categories_bitmap, CATEGORIES_BITMAP_LEN))
{
spin_unlock_bh(&lru_head.lock);
return 0;
}
spin_unlock_bh(&lru_head.lock);
if(1 == node_status)
{
int ret = urlFilter_lru_cache_compare(categories_bitmap, tinfo->categories_bitmap);
if(0 != ret)
{
return 1;
}
}
}
else
{
if ('\0' != abs_url[0] && 0 != abs_url_len)
{
URL_DEBUG("rule match count %d",info->count);
for( i =0; i < info->count; i++)
{
index = info->setflag[i];
urlset = getSetByIndex(index);
if(urlset == NULL)
{
printk(KERN_ERR"cant find the corresonding set\n"); /*actully bug should be reported here*/
/*return 0;*/
continue;
}
URL_DEBUG("find urlset %p", urlset);
switch(urlset->type)
{
case 2: /* ac alg*/
if (info->flags == CONTROLLER_URL)
{
result = urlset_isContain3(urlset,abs_url);
if(result > 0)
{
URL_DEBUG("urlset match %s", abs_url);
return 1;
}
}
else
{
result = urlset_isContain2(urlset,abs_url,(info->flags == COMPLETE_URL));
URL_DEBUG("result = %d", result);
if(result > 0)
{
URL_DEBUG("urlset match %s", abs_url);
return 1;
}
}
break;
case 1: /* re */
break;
case 3: /* url,compare complete url directly */
result = urlset_isContain(urlset,abs_url);
if(result > 0)
{
URL_DEBUG("urlset match %s", abs_url);
return 1;
}
break;
}
}
}
}
return 0;
}
static int xt_urlset_mt_checkentry(const struct xt_mtchk_param *par)
{
struct ipt_matchset *info = par->matchinfo;
unsigned int i=0,j=0;
unsigned int index=0;
URL_DEBUG("count=%d,address=%x",info->count,(unsigned long)info);
for(i=0;i<info->count;i++)
{
index=url_set_nfnl_get_byindex(info->setflag[i]);
URL_DEBUG("[%d]=%d",i,index);
if(index == IPSET_INVALID_ID)
{
for(j=0;j<i;j++)
url_set_nfnl_put(info->setflag[j]);
printk(KERN_ERR"couldnt find set[%u]",i);
return -EINVAL;
}
}
return 0;
}
static void xt_urlset_mt_destroy(const struct xt_mtdtor_param *par)
{
struct ipt_matchset *info = par->matchinfo;
unsigned int i=0;
URL_DEBUG("address=%x,count=%d",(unsigned long)info,info->count);
for(;i<info->count;i++)
{
URL_DEBUG("[%d]=%d",i,info->setflag[i]);
url_set_nfnl_put(info->setflag[i]);
}
}
static struct xt_match urlset_mt_reg __read_mostly = {
.name = "urlsetmatch",
.revision = 0,
.family = NFPROTO_IPV4,
.match = xt_urlset_mt,
.checkentry = xt_urlset_mt_checkentry,
.destroy = xt_urlset_mt_destroy,
.matchsize = sizeof(struct ipt_matchset),
.proto = IPPROTO_TCP,
.me = THIS_MODULE,
};
static int __init urlset_mt_init(void)
{
URL_DEBUG("enter in init function");
return xt_register_match(&urlset_mt_reg);
}
static void __exit urlset_mt_exit(void)
{
xt_unregister_match(&urlset_mt_reg);
}
module_init(urlset_mt_init);
module_exit(urlset_mt_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("luopei<luopei@tp-link.net>");
MODULE_DESCRIPTION("Xtables: multiple urlset match for tcp(http/https)");
MODULE_ALIAS("ipt_urlset_match");
最新发布