增加协议识别内核模块

This commit is contained in:
Derry 2018-12-15 11:41:12 +08:00
parent 28f0207576
commit 1c2170a014
7 changed files with 336 additions and 0 deletions

2
kernel/Makefile Executable file
View File

@ -0,0 +1,2 @@
appfilter-objs := app_filter.o af_utils.o flow_detection.o
obj-m += appfilter.o

33
kernel/af_utils.c Executable file
View File

@ -0,0 +1,33 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/types.h>
#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");
}

9
kernel/af_utils.h Executable file
View File

@ -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

237
kernel/app_filter.c Executable file
View File

@ -0,0 +1,237 @@
#include <linux/init.h>
#include <linux/module.h>
#include <net/tcp.h>
#include <linux/netfilter.h>
#include <net/netfilter/nf_conntrack.h>
#include <linux/skbuff.h>
#include <net/ip.h>
#include <linux/types.h>
#include <net/sock.h>
#include <linux/etherdevice.h>
#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);

55
kernel/app_filter.h Executable file
View File

@ -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

0
kernel/flow_detection.c Executable file
View File

0
kernel/flow_detection.h Executable file
View File