├── README.md ├── Makefile ├── traffic_entry.h ├── traffic_entry.c └── map_core.c /README.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | obj-m += traffic_map.o 2 | traffic_map-objs := map_core.o traffic_entry.o 3 | 4 | PWD := $(shell pwd) 5 | KDIR := /lib/modules/$(shell uname -r)/build 6 | 7 | all: 8 | make -C $(KDIR) M=$(PWD) modules 9 | 10 | clean: 11 | make -C $(KDIR) M=$(PWD) clean 12 | -------------------------------------------------------------------------------- /traffic_entry.h: -------------------------------------------------------------------------------- 1 | #ifndef _TRAFFIC_ENTRY_H 2 | #define _TRAFFIC_ENTRY_H 3 | #include 4 | 5 | typedef struct _traffic_entry { 6 | struct list_head list; 7 | unsigned int saddr; 8 | unsigned int daddr; 9 | unsigned short sport; 10 | unsigned short dport; 11 | long int load; 12 | }traffic_entry_t; 13 | 14 | /* alloc memory */ 15 | extern int traffic_entry_init(void); 16 | extern traffic_entry_t *traffic_entry_new(unsigned int saddr, unsigned int daddr, 17 | unsigned short sport, unsigned short dport); 18 | extern traffic_entry_t *traffic_entry_search_saddr(unsigned int saddr); 19 | extern traffic_entry_t *traffic_entry_search_daddr(unsigned int daddr); 20 | extern int traffic_entry_destory(void); 21 | extern traffic_entry_t *traffic_entry_search(const unsigned int saddr, 22 | const unsigned int daddr); 23 | 24 | extern void traffic_entry_dump(void); 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /traffic_entry.c: -------------------------------------------------------------------------------- 1 | #include "traffic_entry.h" 2 | #include 3 | #include 4 | 5 | #ifndef NIPQUAD 6 | #define NIPQUAD(addr) \ 7 | ((unsigned char *)&addr)[0], \ 8 | ((unsigned char *)&addr)[1], \ 9 | ((unsigned char *)&addr)[2], \ 10 | ((unsigned char *)&addr)[3] 11 | 12 | #define NIPQUAD_FMT "%u.%u.%u.%u" 13 | #endif 14 | 15 | static struct kmem_cache *traffic_entry_cache=NULL; 16 | static LIST_HEAD(traffic_entry_head); 17 | 18 | int traffic_entry_init() 19 | { 20 | int ret = -1; 21 | #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,22) 22 | /*---------------------------------------------------------------------------- 23 | * In 2.6.23, the last argument was dropped from kmem_cache_create. */ 24 | traffic_entry_cache = kmem_cache_create("traffic_entry_cache", 25 | sizeof(struct _traffic_entry), 0, 0, NULL, NULL); 26 | #else 27 | traffic_entry_cache = kmem_cache_create("traffic_entry_cache", 28 | sizeof(struct _traffic_entry), 0, 0, NULL); 29 | #endif 30 | if ( !traffic_entry_cache ) { 31 | printk("kmem_cache_create error\n"); 32 | return ret; 33 | } 34 | 35 | return ret; 36 | } 37 | 38 | traffic_entry_t *traffic_entry_new(unsigned int saddr, unsigned int daddr, 39 | unsigned short sport, unsigned short dport) 40 | { 41 | traffic_entry_t *entry = NULL; 42 | 43 | if ( !traffic_entry_cache ) { 44 | return NULL; 45 | } 46 | entry = (traffic_entry_t *) kmem_cache_alloc(traffic_entry_cache, GFP_KERNEL); 47 | if ( !entry ) { 48 | printk("[traffic_map]: traffic_entry_new alloc memory failed!\n"); 49 | return entry; 50 | } 51 | 52 | entry->saddr = saddr; 53 | entry->daddr = daddr; 54 | entry->sport = sport; 55 | entry->dport = dport; 56 | entry->load = 0; 57 | 58 | INIT_LIST_HEAD(&entry->list); 59 | list_add(&entry->list, &traffic_entry_head); 60 | 61 | return entry; 62 | } 63 | 64 | traffic_entry_t *traffic_entry_search(const unsigned int saddr, 65 | const unsigned int daddr) 66 | { 67 | traffic_entry_t *entry = NULL; 68 | 69 | if ( !traffic_entry_cache ) { 70 | return NULL; 71 | } 72 | 73 | list_for_each_entry(entry, &traffic_entry_head, list) { 74 | if ( entry->saddr == saddr && entry->daddr == daddr ) 75 | return entry; 76 | } 77 | 78 | return NULL; 79 | } 80 | 81 | traffic_entry_t *traffic_entry_search_saddr(unsigned int saddr) 82 | { 83 | traffic_entry_t *entry = NULL; 84 | 85 | if ( !traffic_entry_cache ) { 86 | return NULL; 87 | } 88 | 89 | list_for_each_entry(entry, &traffic_entry_head, list) { 90 | if ( entry->saddr == saddr ) 91 | return entry; 92 | } 93 | 94 | return NULL; 95 | } 96 | 97 | traffic_entry_t *traffic_entry_search_daddr(unsigned int daddr) 98 | { 99 | traffic_entry_t *entry = NULL; 100 | 101 | if ( !traffic_entry_cache ) { 102 | return NULL; 103 | } 104 | 105 | list_for_each_entry(entry, &traffic_entry_head, list) { 106 | if ( entry->daddr == daddr ) 107 | return entry; 108 | } 109 | return NULL; 110 | } 111 | 112 | void traffic_entry_dump(void) 113 | { 114 | traffic_entry_t *entry = NULL; 115 | 116 | /* print banner */ 117 | printk("saddr:\t\tdaddr:\t\tsport:\t\tdport:\t\tload\n"); 118 | printk("=================================================================\n"); 119 | if ( !list_empty(&traffic_entry_head) ) { 120 | list_for_each_entry(entry, &traffic_entry_head, list) { 121 | printk(NIPQUAD_FMT"\t"NIPQUAD_FMT"\t%d\t\t%d\t\t%ld\n", 122 | NIPQUAD(entry->saddr), NIPQUAD(entry->daddr), 123 | ntohs(entry->sport), ntohs(entry->dport), 124 | entry->load); 125 | } 126 | } 127 | 128 | } 129 | 130 | int traffic_entry_destory() 131 | { 132 | traffic_entry_t *entry = NULL; 133 | traffic_entry_t *entry2 = NULL; 134 | int ret = -1; 135 | 136 | list_for_each_entry_safe(entry, entry2, &traffic_entry_head, list) { 137 | list_del(&entry->list); 138 | kmem_cache_free(traffic_entry_cache, entry); 139 | } 140 | 141 | if (traffic_entry_cache) 142 | kmem_cache_destroy(traffic_entry_cache); 143 | 144 | ret = 0; 145 | return ret; 146 | } 147 | -------------------------------------------------------------------------------- /map_core.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include /*PF_INET*/ 7 | #include /*NF_IP_PRE_FIRST*/ 8 | #include 9 | #include 10 | #include /*in_aton()*/ 11 | #include 12 | #include 13 | #include 14 | #include "traffic_entry.h" 15 | 16 | MODULE_LICENSE("GPL"); 17 | MODULE_AUTHOR("brytonlee01@gmail.com"); 18 | 19 | #ifndef NIPQUAD 20 | #define NIPQUAD(addr) \ 21 | ((unsigned char *)&addr)[0], \ 22 | ((unsigned char *)&addr)[1], \ 23 | ((unsigned char *)&addr)[2], \ 24 | ((unsigned char *)&addr)[3] 25 | 26 | #define NIPQUAD_FMT "%u.%u.%u.%u" 27 | #endif 28 | 29 | #define TCPHDR(skb) ((char*)(skb)->data+iph->ihl*4) 30 | 31 | struct nf_hook_ops nf_pre_route; 32 | struct nf_hook_ops nf_out; 33 | 34 | #define PORTS_MAX 20 35 | static unsigned short ports_array[PORTS_MAX]; 36 | int narr; 37 | 38 | static struct timer_list traffic_timer; 39 | 40 | module_param_array(ports_array, ushort, &narr, 0644); 41 | MODULE_PARM_DESC(ports_array, "ports_array: pass a port array to traffic_map module."); 42 | 43 | void entry_dump(unsigned long data) 44 | { 45 | int ret = 0; 46 | 47 | traffic_entry_dump(); 48 | 49 | ret = mod_timer(&traffic_timer, jiffies + msecs_to_jiffies(30 * 1000) ); 50 | if (ret) printk("Error in mod_timer\n"); 51 | } 52 | 53 | static void tcp_record(const struct sk_buff *skb, const struct iphdr *iph, 54 | const struct tcphdr *tcph) 55 | { 56 | // unsigned int daddr; 57 | // unsigned int saddr; 58 | // unsigned short sport; 59 | // unsigned short dport; 60 | traffic_entry_t *entry = NULL; 61 | 62 | int tot_len; /* packet data totoal length */ 63 | int iph_len; 64 | int tcph_len; 65 | int tcp_load; 66 | 67 | tot_len = ntohs(iph->tot_len); 68 | iph_len = ip_hdrlen(skb); 69 | tcph_len = tcph->doff * 4; 70 | tcp_load = tot_len - ( iph_len + tcph_len ); 71 | 72 | //saddr = ntohl(iph->saddr); 73 | //daddr = ntohl(iph->daddr); 74 | //sport = ntohs(tcph->source); 75 | //dport = ntohs(tcph->dest); 76 | 77 | entry = traffic_entry_search(iph->saddr, iph->daddr); 78 | if ( entry ) { 79 | entry->load += tcp_load; 80 | } else { 81 | entry = traffic_entry_new(iph->saddr, iph->daddr, tcph->source, tcph->dest); 82 | if ( !entry ) { 83 | //printk("alloc memory failed!\n"); 84 | return; 85 | } 86 | entry->load = tcp_load; 87 | } 88 | 89 | } 90 | 91 | static void tcp_info(const struct sk_buff *skb, const struct iphdr *iph, 92 | const struct tcphdr *tcph) 93 | { 94 | int tot_len; /* packet data totoal length */ 95 | int iph_len; 96 | int tcph_len; 97 | int tcp_load; 98 | 99 | tot_len = ntohs(iph->tot_len); 100 | iph_len = ip_hdrlen(skb); 101 | tcph_len = tcph->doff * 4; 102 | tcp_load = tot_len - ( iph_len + tcph_len ); 103 | 104 | /* debug */ 105 | // printk("total_len: %d, iph_len: %d, tcph_len: %d\n", 106 | // tot_len, iph_len, tcph_len); 107 | 108 | printk("tcp connection and src: "NIPQUAD_FMT":%d, dest: "NIPQUAD_FMT 109 | ":%d, load_length: %d\n", 110 | NIPQUAD(iph->saddr), ntohs(tcph->source), 111 | NIPQUAD(iph->daddr), ntohs(tcph->dest), tcp_load); 112 | } 113 | 114 | /* output */ 115 | #if defined(LINUX_VERSION_CODE) && defined(KERNEL_VERSION) && \ 116 | LINUX_VERSION_CODE > KERNEL_VERSION(2,6,28) 117 | unsigned int filter_out(unsigned int hooknum, 118 | struct sk_buff *__skb, 119 | const struct net_device *in, 120 | const struct net_device *out, 121 | int (*okfn)(struct sk_buff *)) 122 | { 123 | #else 124 | unsigned int filter_out(unsigned int hooknum, 125 | struct sk_buff **__skb, 126 | const struct net_device *in, 127 | const struct net_device *out, 128 | int (*okfn)(struct sk_buff *)) 129 | { 130 | #endif 131 | struct sk_buff *skb; 132 | struct iphdr *iph; 133 | struct tcphdr *tcph; 134 | unsigned short port; 135 | int i; 136 | 137 | #if defined(LINUX_VERSION_CODE) && defined(KERNEL_VERSION) && \ 138 | LINUX_VERSION_CODE > KERNEL_VERSION(2,6,28) 139 | skb = __skb; 140 | #else 141 | skb = *__skb; 142 | #endif 143 | 144 | if(skb == NULL) 145 | return NF_ACCEPT; 146 | iph = ip_hdr(skb); 147 | if(iph == NULL) 148 | return NF_ACCEPT; 149 | 150 | if(iph->protocol == IPPROTO_TCP) 151 | { 152 | tcph=(struct tcphdr*)TCPHDR(skb); 153 | 154 | for ( i = 0; i < narr; i++ ) { 155 | port = ports_array[i]; 156 | if ( tcph->source == htons(port) ) 157 | //tcp_info(skb, iph, tcph); 158 | tcp_record(skb, iph, tcph); 159 | } 160 | } 161 | 162 | return NF_ACCEPT; 163 | } 164 | 165 | /* input */ 166 | #if defined(LINUX_VERSION_CODE) && defined(KERNEL_VERSION) && \ 167 | LINUX_VERSION_CODE > KERNEL_VERSION(2,6,28) 168 | unsigned int filter_pre_route(unsigned int hooknum, 169 | struct sk_buff *__skb, 170 | const struct net_device *in, 171 | const struct net_device *out, 172 | int (*okfn)(struct sk_buff *)) 173 | { 174 | #else 175 | unsigned int filter_pre_route(unsigned int hooknum, 176 | struct sk_buff **__skb, 177 | const struct net_device *in, 178 | const struct net_device *out, 179 | int (*okfn)(struct sk_buff *)) 180 | { 181 | #endif 182 | struct sk_buff *skb; 183 | struct iphdr *iph; 184 | struct tcphdr *tcph; 185 | unsigned short port; 186 | int i; 187 | 188 | #if defined(LINUX_VERSION_CODE) && defined(KERNEL_VERSION) && \ 189 | LINUX_VERSION_CODE > KERNEL_VERSION(2,6,28) 190 | skb = __skb; 191 | #else 192 | skb = *__skb; 193 | #endif 194 | 195 | if(skb == NULL) 196 | return NF_ACCEPT; 197 | iph = ip_hdr(skb); 198 | if(iph == NULL) 199 | return NF_ACCEPT; 200 | 201 | if(iph->protocol == IPPROTO_TCP) 202 | { 203 | tcph=(struct tcphdr*)TCPHDR(skb); 204 | 205 | for ( i = 0; i < narr; i++ ) { 206 | port = ports_array[i]; 207 | if ( tcph->dest == htons(port) ) 208 | //tcp_info(skb, iph, tcph); 209 | tcp_record(skb, iph, tcph); 210 | } 211 | 212 | } 213 | return NF_ACCEPT; 214 | } 215 | 216 | static int __init filter_init(void) 217 | { 218 | int i; 219 | int ret; 220 | 221 | printk("traffic_map used to monitor tcp connections traffic\n" 222 | "Author: brytonlee01@gmail.com\n"); 223 | 224 | /* init listen port */ 225 | if ( narr > PORTS_MAX ) { 226 | printk("too many ports\n"); 227 | return -1; 228 | } 229 | 230 | for ( i = 0; i < narr; i++ ) { 231 | /* TODO check port valid ,sort ,uniq*/ 232 | printk("ports_array[%d] = %u\n", i, ports_array[i]); 233 | } 234 | 235 | /* init struct caceh */ 236 | traffic_entry_init(); 237 | 238 | /* input */ 239 | nf_pre_route.hook = filter_pre_route; 240 | nf_pre_route.pf = AF_INET; 241 | #if defined(LINUX_VERSION_CODE) && defined(KERNEL_VERSION) && \ 242 | LINUX_VERSION_CODE > KERNEL_VERSION(2,6,28) 243 | nf_pre_route.hooknum = NF_INET_PRE_ROUTING; 244 | #else 245 | nf_pre_route.hooknum = NF_IP_PRE_ROUTING; 246 | #endif 247 | nf_pre_route.priority = NF_IP_PRI_FIRST; 248 | 249 | ret = nf_register_hook(&nf_pre_route); 250 | if(ret < 0) 251 | { 252 | printk("%s\n", "can't modify skb hook!"); 253 | return ret; 254 | } 255 | 256 | /* output */ 257 | nf_out.hook = filter_out; 258 | nf_out.pf = AF_INET; 259 | #if defined(LINUX_VERSION_CODE) && defined(KERNEL_VERSION) && \ 260 | LINUX_VERSION_CODE > KERNEL_VERSION(2,6,28) 261 | nf_out.hooknum = NF_INET_LOCAL_OUT; 262 | #else 263 | nf_out.hooknum = NF_IP_LOCAL_OUT; 264 | #endif 265 | 266 | ret = nf_register_hook(&nf_out); 267 | if ( ret < 0 ) { 268 | printk("%s\n", "can't modify skb hook!"); 269 | return ret; 270 | } 271 | 272 | /* install timer */ 273 | setup_timer(&traffic_timer, entry_dump, 0); 274 | 275 | /* 30 seconds call timer function */ 276 | ret = mod_timer(&traffic_timer, jiffies + msecs_to_jiffies(30 * 1000) ); 277 | if (ret) printk("Error in mod_timer\n"); 278 | 279 | return 0; 280 | } 281 | 282 | static void filter_fini(void) 283 | { 284 | int ret = 0; 285 | 286 | ret = del_timer(&traffic_timer); 287 | if ( ret ) 288 | printk("The traffic_timer is still in use...\n"); 289 | 290 | traffic_entry_destory(); 291 | nf_unregister_hook(&nf_pre_route); 292 | nf_unregister_hook(&nf_out); 293 | printk("[traffic_map]: bye...\n"); 294 | } 295 | module_init(filter_init); 296 | module_exit(filter_fini); 297 | --------------------------------------------------------------------------------