diff --git a/kernel/Makefile b/kernel/Makefile new file mode 100755 index 0000000..fcd5b18 --- /dev/null +++ b/kernel/Makefile @@ -0,0 +1,2 @@ +appfilter-objs := app_filter.o af_utils.o flow_detection.o +obj-m += appfilter.o diff --git a/kernel/af_utils.c b/kernel/af_utils.c new file mode 100755 index 0000000..2dc8de8 --- /dev/null +++ b/kernel/af_utils.c @@ -0,0 +1,33 @@ +#include +#include +#include + +#include "af_utils.h" + +int check_local_network_ip(unsigned int ip) +{ + if ((ip & 0xffff0000) == 0xc0a80000) + return 1; + else if ((ip & 0xfff00000) == 0xac100000) + return 1; + else if ((ip & 0xff000000) == 0x0a000000) + return 1; + else + return 0; +} + +void dump_str(char *name, char *p, int len) +{ + #define MAX_DUMP_STR_LEN 64 + int i; + if (len > MAX_DUMP_STR_LEN) { + len = MAX_DUMP_STR_LEN - 1; + } + printk("%s: ",name); + for (i = 0; i < len; i++) { + printk("%c",*(p + i)); + } + printk("\n"); +} + + diff --git a/kernel/af_utils.h b/kernel/af_utils.h new file mode 100755 index 0000000..3d6c7f1 --- /dev/null +++ b/kernel/af_utils.h @@ -0,0 +1,9 @@ +#ifndef AF_UTILS_H +#define AF_UTILS_H + +int check_local_network_ip(unsigned int ip); + +void dump_str(char *name, char *p, int len); + +#endif + diff --git a/kernel/app_filter.c b/kernel/app_filter.c new file mode 100755 index 0000000..2de407b --- /dev/null +++ b/kernel/app_filter.c @@ -0,0 +1,237 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "app_filter.h" +#include "af_utils.h" + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("destan19@126.com"); +MODULE_DESCRIPTION("app filter module"); + +#define MIN_HTTP_DATA_LEN 16 + + +int parse_flow_base(struct sk_buff *skb, flow_info_t *flow) +{ + struct tcphdr * tcph = NULL; + struct udphdr * udph = NULL; + struct nf_conn *ct = NULL; + struct iphdr *iph = NULL; + if (!skb) { + return -1; + } + ct = (struct nf_conn *)skb->nfct; + if (!ct) { + return -1; + } + iph = ip_hdr(skb); + if ( !iph ) { + return -1; + } + flow->ct = ct; + flow->src = iph->saddr; + flow->dst = iph->daddr; + flow->l4_protocol = iph->protocol; + switch (iph->protocol) { + case IPPROTO_TCP: + tcph = (struct tcphdr *)(iph + 1); + flow->l4_data = skb->data + iph->ihl * 4 + tcph->doff * 4; + flow->l4_len = ntohs(iph->tot_len) - iph->ihl * 4 - tcph->doff * 4; + flow->dport = htons(tcph->dest); + flow->sport = htons(tcph->source); + break; + case IPPROTO_UDP: + udph = (struct udphdr *)(iph + 1); + flow->l4_data = skb->data + iph->ihl * 4 + 8; + flow->l4_len = ntohs(udph->len) - 8; + flow->dport = htons(udph->dest); + flow->sport = htons(udph->source); + break; + case IPPROTO_ICMP: + break; + default: + return -1; + } + return -1; +} + + +void parse_http_proto(flow_info_t *flow) +{ + if (!flow) { + AF_ERROR("flow is null\n"); + return; + } + if (flow->l4_protocol != IPPROTO_TCP) { + return; + } + + int i = 0; + int start = 0; + char *data = flow->l4_data; + int data_len = flow->l4_len; + if (data_len < MIN_HTTP_DATA_LEN) { + return; + } + if (flow->sport != 80 && flow->dport != 80) + return; + for (i = 0; i < data_len - 4; i++) { + if (data[i] == 0x0d && data[i + 1] == 0x0a){ + if (0 == memcmp(&data[start], "POST ", 5)) { + flow->http.match = AF_TRUE; + flow->http.method = HTTP_METHOD_POST; + flow->http.url_pos = data + start + 5; + flow->http.url_len = i - start - 5; + //dump_str("get request", flow->http.url_pos, flow->http.url_len); + } + else if(0 == memcmp(&data[start], "GET ", 4)) { + flow->http.match = AF_TRUE; + flow->http.method = HTTP_METHOD_GET; + flow->http.url_pos = data + start + 4; + flow->http.url_len = i - start - 4; + //dump_str("post request", flow->http.url_pos, flow->http.url_len); + } + else if (0 == memcmp(&data[start], "Host: ", 6) ){ + flow->http.host_pos = data + start + 6; + flow->http.host_len = i - start - 6; + //dump_str("host ", flow->http.host_pos, flow->http.host_len); + } + // 判断http头部结束 + if (data[i + 2] == 0x0d && data[i + 3] == 0x0a){ + flow->http.data_pos = data + i + 4; + flow->http.data_len = data_len - i - 4; + break; + } + // 0x0d 0x0a + start = i + 2; + } + } +} + +static void dump_http_flow_info(http_proto_t *http) { + if (!http) { + AF_ERROR("http ptr is NULL\n"); + return ; + } + if (!http->match) + return; + if (http->method == HTTP_METHOD_GET){ + printk("Http method: "HTTP_GET_METHOD_STR"\n"); + } + else if (http->method == HTTP_METHOD_POST) { + printk("Http method: "HTTP_POST_METHOD_STR"\n"); + } + if (http->url_len > 0 && http->url_pos){ + dump_str("Request url", http->url_pos, http->url_len); + } + + if (http->host_len > 0 && http->host_pos){ + dump_str("Host", http->host_pos, http->host_len); + } + + printk("--------------------------------------------------------\n\n\n"); +} + +static void dump_flow_info(flow_info_t *flow) +{ + if (!flow) { + AF_ERROR("flow is null\n"); + return; + } + #if 0 + if (check_local_network_ip(ntohl(flow->src))) { + printk("src ip(inner net):"NIPQUAD_FMT", dst ip = "NIPQUAD_FMT"\n", NIPQUAD(flow->src), NIPQUAD(flow->dst)); + } + else { + printk("src ip(outer net):"NIPQUAD_FMT", dst ip = "NIPQUAD_FMT"\n", NIPQUAD(flow->src), NIPQUAD(flow->dst)); + } + #endif + if (flow->l4_protocol == IPPROTO_TCP) { + if (AF_TRUE == flow->http.match) { + printk("-------------------http protocol-------------------------\n"); + printk("protocol:TCP , sport: %-8d, dport: %-8d, data_len: %-8d\n", + flow->sport, flow->dport, flow->l4_len); + dump_http_flow_info(&flow->http); + } + } + else if (flow->l4_protocol == IPPROTO_UDP) { + // printk("protocol:UDP ,sport: %-8d, dport: %-8d, data_len: %-8d\n", + // flow->sport, flow->dport, flow->l4_len); + } + else { + return; + } +} + +/* 在netfilter框架注册的钩子 */ +static u_int32_t app_filter_hook(unsigned int hook, + struct sk_buff *pskb, + const struct net_device *in, + const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + struct nf_conn *ct = (struct nf_conn *)pskb->nfct; + + if (ct == NULL) { + return NF_ACCEPT; + } + flow_info_t flow; + memset((char *)&flow, 0x0, sizeof(flow_info_t)); + parse_flow_base(pskb, &flow); + parse_http_proto(&flow); + dump_flow_info(&flow); + // todo: match url rules + // this is example + if (flow.http.match == AF_TRUE) { + if (flow.http.host_pos && + strnstr(flow.http.host_pos, "sohu", flow.http.host_len)){ + + dump_str("Drop url ",flow.http.host_pos, flow.http.host_len); + return NF_DROP; + } + } + return NF_ACCEPT; +} + + +static struct nf_hook_ops app_filter_ops[] __read_mostly = { + { + .hook = app_filter_hook, + .owner = THIS_MODULE, + .pf = PF_INET, + .hooknum = NF_INET_FORWARD, + .priority = NF_IP_PRI_MANGLE + 10, + }, +}; +/* + 模块退出 +*/ +static void app_filter_fini(void) +{ + AF_DEBUG("app filter module exit\n"); + nf_unregister_hooks(app_filter_ops, ARRAY_SIZE(app_filter_ops)); + return ; +} + +/* + 模块初始化 +*/ +static int __init app_filter_init(void) +{ + AF_DEBUG("app filter module init\n"); + nf_register_hooks(app_filter_ops, ARRAY_SIZE(app_filter_ops)); + printk("init app filter ........ok\n"); + return 0; +} + +module_init(app_filter_init); +module_exit(app_filter_fini); diff --git a/kernel/app_filter.h b/kernel/app_filter.h new file mode 100755 index 0000000..4f07f9a --- /dev/null +++ b/kernel/app_filter.h @@ -0,0 +1,55 @@ +#ifndef APP_FILTER_H +#define APP_FILTER_H +#define AF_DEBUG printk +#define AF_ERROR printk +#define AF_INFO printk + +//#define CONFIG_KERNEL_FUNC_TEST 1 + +#define HTTP_GET_METHOD_STR "GET" +#define HTTP_POST_METHOD_STR "POST" +#define HTTP_HEADER "HTTP" +#define NIPQUAD(addr) \ + ((unsigned char *)&addr)[0], \ + ((unsigned char *)&addr)[1], \ + ((unsigned char *)&addr)[2], \ + ((unsigned char *)&addr)[3] +#define NIPQUAD_FMT "%u.%u.%u.%u" + +#define AF_TRUE 1 +#define AF_FALSE 0 +enum e_http_method{ + HTTP_METHOD_GET = 1, + HTTP_METHOD_POST, +}; +typedef struct http_proto{ + int match; + int method; + char *url_pos; + int url_len; + char *host_pos; + int host_len; + char *data_pos; + int data_len; +}http_proto_t; + +typedef struct https_proto{ + int match; + char url_pos; + int url_len; +}https_proto_t; + +typedef struct flow_info{ + struct nf_conn *ct; // 连接跟踪指针 + u_int32_t src; + u_int32_t dst; + int l4_protocol; + u_int16_t sport; + u_int16_t dport; + unsigned char *l4_data; + int l4_len; + http_proto_t http; + https_proto_t https; +}flow_info_t; + +#endif diff --git a/kernel/flow_detection.c b/kernel/flow_detection.c new file mode 100755 index 0000000..e69de29 diff --git a/kernel/flow_detection.h b/kernel/flow_detection.h new file mode 100755 index 0000000..e69de29