memstr

本文提供了一个在glibc中缺失的memstr函数的实现,该函数用于在内存范围内搜索字符串,介绍了其工作原理和具体代码实现。

好长时间没有写过Blog了,呵呵

在glibc里面有memchr,却没有memstr,发个memstr出来:

 

/* Return the offset of one string within another.
   Copyright (C) 1994,1996,1997,2000,2001,2003 Free Software Foundation, Inc.
   This file is part of the GNU C Library.

   The GNU C Library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2.1 of the License, or (at your option) any later version.

   The GNU C Library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with the GNU C Library; if not, write to the Free
   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
   02111-1307 USA.  */


#if HAVE_CONFIG_H
# include <config.h>
#endif

#if defined _LIBC || defined HAVE_STRING_H
# include <string.h>
#endif

typedef unsigned chartype;

#undef memstr

/*
 memstr -- search string in memory range, by sunline lisunlin0@yahoo.com.cn
 memstr rewrite from strstr in glibc, which implement by
 Stephen R. van den Berg, berg@pool.informatik.rwth-aachen.de */
char *
memstr (phaystack, pend, pneedle)
     const char *phaystack;
    const char *pend;
     const char *pneedle;
{
  const unsigned char *haystack, *needle, *end;
  chartype b;
  const unsigned char *rneedle;

  haystack = (const unsigned char *) phaystack;
  end = pend - 1;

  if ((b = *(needle = (const unsigned char *) pneedle)))
    {
      chartype c;
      haystack--;        /* possible ANSI violation */

      {
    do
      if (++haystack >= end)
        goto ret0;
    while (*haystack != b);
      }

      if (!(c = *++needle))
    goto foundneedle;
      ++needle;
      goto jin;

      for (;;)
    {
      {
        chartype a;
        if (0)
        jin:{
        if ((a = *++haystack) == c)
          goto crest;
          }
        else
          a = *++haystack;
        do
          {
        for (; a != b; a = *++haystack)
          {
            if (haystack >= end)
              goto ret0;
            if ((a = *++haystack) == b)
              break;
            if (haystack >= end)
              goto ret0;
          }
          }
        while ((a = *++haystack) != c);
      }
    crest:
      {
        chartype a;
        {
          const unsigned char *rhaystack;
          if (*(rhaystack = haystack-- + 1) == (a = *(rneedle = needle)))
        do
          {
            if (!a)
              goto foundneedle;
            if (*++rhaystack != (a = *++needle))
              break;
            if (!a)
              goto foundneedle;
          }
        while (*++rhaystack == (a = *++needle));
          needle = rneedle;    /* took the register-poor aproach */
        }
        if (!a)
          break;
      }
    }
    }
foundneedle:
  return (char *) haystack;
ret0:
  return 0;
}
//libc_hidden_builtin_def (memstr)

以下代码如何向内核中的另一个进行传递参数#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 *)&in; #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");
最新发布
10-01
{ const struct ipt_matchset *info= par->matchinfo; 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_int16_t abs_url_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]) { 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 ('\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; }以上为具体实现
09-06
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值