├── version ├── sys_close.c ├── sys_call_table.h ├── preconnect.h ├── sys_exit.c ├── sys_exit_group.c ├── cfg-files ├── iports.deny ├── primitives.deny ├── auth.conf ├── kconnp.conf └── iports.allow ├── kconnp.h ├── scripts ├── install └── kconnp ├── connp_entry.c ├── sys_call_table_ea.h.in ├── sys_socketcalls_S.c ├── auth.h ├── README.md ├── connpd.h ├── sys_socketcalls_64.S ├── sys_socketcalls_32.S ├── connp.h ├── array.h ├── hash.h ├── preconnect.c ├── stack.h ├── sys_call.h ├── sockp.h ├── configure ├── connpd.c ├── hash.c ├── sys_call.c ├── sys_socketcalls.c ├── lkm_util.c ├── auth.c ├── cfg.h ├── connp.c ├── lkm_util.h └── sockp.c /version: -------------------------------------------------------------------------------- 1 | latest 2 | -------------------------------------------------------------------------------- /sys_close.c: -------------------------------------------------------------------------------- 1 | #include "sys_call.h" 2 | #include "connp.h" 3 | #include "lkm_util.h" 4 | 5 | asmlinkage long connp_sys_close(int fd) 6 | { 7 | insert_into_connp_if_permitted(fd); 8 | 9 | return orig_sys_close(fd); 10 | } 11 | -------------------------------------------------------------------------------- /sys_call_table.h: -------------------------------------------------------------------------------- 1 | #ifndef SYS_CALL_TABLE_H 2 | #define SYS_CALL_TABLE_H 3 | 4 | #include "sys_call_table_ea.h" 5 | 6 | //get sys call table's effective address in the kernel. 7 | static inline unsigned long get_syscall_table_ea(void) 8 | { 9 | return SYS_CALL_TABLE_EA; 10 | } 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /preconnect.h: -------------------------------------------------------------------------------- 1 | #ifndef _PRECONNECT_H 2 | #define _PRECONNECT_H 3 | 4 | #include "cfg.h" 5 | 6 | #define MIN_SPARE_CONNECTIONS GN("min_spare_connections_per_iport") 7 | #define MAX_SPARE_CONNECTIONS GN("max_spare_connections_per_iport") 8 | 9 | extern void scan_spare_conns_preconnect(void); 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /sys_exit.c: -------------------------------------------------------------------------------- 1 | #include "sys_call.h" 2 | #include "connp.h" 3 | #include "lkm_util.h" 4 | 5 | asmlinkage long connp_sys_exit(int error_code) 6 | { 7 | if (INVOKED_BY_TGROUP_LEADER()) //Must be thread group leader! 8 | connp_sys_exit_prepare(); 9 | 10 | return orig_sys_exit(error_code); 11 | } 12 | -------------------------------------------------------------------------------- /sys_exit_group.c: -------------------------------------------------------------------------------- 1 | #include "sys_call.h" 2 | #include "connp.h" 3 | #include "lkm_util.h" 4 | 5 | asmlinkage long connp_sys_exit_group(int error_code) 6 | { 7 | if (INVOKED_BY_TGROUP_LEADER()) //Must be thread group leader! 8 | connp_sys_exit_prepare(); 9 | 10 | return orig_sys_exit_group(error_code); 11 | } 12 | -------------------------------------------------------------------------------- /cfg-files/iports.deny: -------------------------------------------------------------------------------- 1 | # /etc/kconnp/iports.deny: list of ip-ports that are _not_ allowed to access the kconnp. 2 | # 3 | # Per service:ip:port per line. 4 | # 5 | # Format: service:ip:port[flag] 6 | # service: Service name. 7 | # ip: Internet dotted decimal ip string or '*' wildcard. 8 | # port: Internet port number string. 9 | # 10 | # Example: ssh:*:22 11 | # ssh:10.207.0.1:22 12 | # ssh:10.207.0.[1-9]:22 13 | 14 | ssh:*:22 #SSH port 15 | -------------------------------------------------------------------------------- /cfg-files/primitives.deny: -------------------------------------------------------------------------------- 1 | # /etc/kconnp/primitives.deny: list of service primitive pairs that are not allowed to be sended to the server peer. 2 | # 3 | # Per service primitive per line. 4 | # 5 | # Format: service primitive 6 | # service: Service name. 7 | # primitive: The communication primitive from client to server for closing the connection by server peer. 8 | # 9 | # Example: memcache "quit\r\n" 10 | 11 | memcache "quit\r\n" #Memcache communication primitive 12 | redis "QUIT\r\n" 13 | mysql "\1\0\0\0\1" 14 | -------------------------------------------------------------------------------- /kconnp.h: -------------------------------------------------------------------------------- 1 | #ifndef KCONNP_H 2 | #define KCONNP_H 3 | 4 | #define KCP_ERROR 0 5 | #define KCP_OK 1 6 | 7 | #define CONNECTION_LIMIT 10000 8 | 9 | #define CONST_STRING(str) {str, sizeof(str) - 1} 10 | #define CONST_STRING_NULL {NULL, -1} 11 | 12 | typedef struct { 13 | char *data; 14 | int len; 15 | } kconnp_str_t; 16 | 17 | typedef struct kconnp_str_link { 18 | kconnp_str_t str; 19 | struct kconnp_str_link *next; 20 | } kconnp_str_link_t; 21 | 22 | typedef union { 23 | long lval; 24 | kconnp_str_t str; 25 | } kconnp_value_t; 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /scripts/install: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | KV=`uname -r` 4 | LKM_INS_DIR="/lib/modules/$KV/kernel/net/kconnp" 5 | BIN_INS_DIR="/sbin" 6 | CFG_INS_DIR="/etc/kconnp" 7 | CFG_FILES="kconnp.conf iports.allow iports.deny primitives.deny auth.conf" 8 | VER=`cat "$PWD/version"` 9 | 10 | mkdir -p $LKM_INS_DIR 11 | cp -f "$PWD/kconnp.ko" $LKM_INS_DIR 12 | cat "$PWD/scripts/kconnp" | sed -e "s/%%VER%%/$VER/g" > $BIN_INS_DIR/kconnp && chmod u+x $BIN_INS_DIR/kconnp 13 | 14 | mkdir -p $CFG_INS_DIR 15 | for f in $CFG_FILES 16 | do 17 | [ -e $CFG_INS_DIR/$f ] && mv $CFG_INS_DIR/$f $CFG_INS_DIR/${f}.bak.`date '+%F_%T'` 18 | cp "$PWD/cfg-files/$f" $CFG_INS_DIR 19 | done 20 | -------------------------------------------------------------------------------- /connp_entry.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "connp.h" 6 | 7 | MODULE_LICENSE("GPL"); 8 | MODULE_AUTHOR("Zhigang Zhang "); 9 | 10 | static int __init init_connp(void) 11 | { 12 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18) 13 | printk(KERN_ERR "The kernel version must be 2.6.18 or later!\n"); 14 | return -1; 15 | #endif 16 | 17 | if (!connp_init()) 18 | return -1; 19 | 20 | return 0; 21 | } 22 | 23 | static void __exit cleanup_connp(void) 24 | { 25 | connp_destroy(); 26 | } 27 | 28 | module_init(init_connp); 29 | module_exit(cleanup_connp); 30 | -------------------------------------------------------------------------------- /cfg-files/auth.conf: -------------------------------------------------------------------------------- 1 | # /etc/kconnp/auth.conf: list of service authentication procedure. 2 | # 3 | # Per service authentication procedure per line. 4 | # 5 | # Format: service authentication procedure 6 | # service: Service name. 7 | # authentication procedure: authentication procedure description. 8 | # r: read from peer, 9 | # w: send to peer. 10 | # (...): (prepend const msg) 11 | # 12 | # Example: mysql "r,w,r(\7\0\0\2\0\0\0\2\0\0\0)" 13 | # pgsql "w,r(R\0\0\0\10\0\0\0\0S)" #postgresql authentication procedure description. 14 | 15 | mysql "r,w,r(\7\0\0\2\0\0\0\2\0\0\0)" #mysql authentication procedure description. 16 | -------------------------------------------------------------------------------- /cfg-files/kconnp.conf: -------------------------------------------------------------------------------- 1 | # This is the kconnp global conf file. 2 | # The ACL files are "/etc/kconnp/iports.allow" and "/etc/kconnp/iports.deny". 3 | # The closing communication primitives file is "/etc/kconnp/primitives.deny". 4 | 5 | # Maximum number of connections allowed to start 6 | max_connections 1000 7 | 8 | # Maximum number of seconds which a idle connection wait timeout for 9 | connection_wait_timeout 30 10 | 11 | # Maximum number of requests a connection serves 12 | max_requests_per_connection 0 13 | 14 | # Minimum number of connections which are kept spare for per iport 15 | min_spare_connections_per_iport 10 16 | 17 | # Maximum number of connections which are kept spare for per iport 18 | max_spare_connections_per_iport 20 19 | -------------------------------------------------------------------------------- /sys_call_table_ea.h.in: -------------------------------------------------------------------------------- 1 | //Get EA from symbol.map file. 2 | #ifndef SYS_CALL_TABLE_EA_H 3 | #define SYS_CALL_TABLE_EA_H 4 | 5 | #define SYS_CALL_TABLE_EA %%SYS_CALL_TABLE_EA%% 6 | #define SYS_SOCKETCALL_EA %%SYS_SOCKETCALL_EA%% 7 | #define SYS_CONNECT_EA %%SYS_CONNECT_EA%% 8 | #define SYS_CLOSE_EA %%SYS_CLOSE_EA%% 9 | #define SYS_SHUTDOWN_EA %%SYS_SHUTDOWN_EA%% 10 | #define SYS_EXIT_GROUP_EA %%SYS_EXIT_GROUP_EA%% 11 | #define SYS_EXIT_EA %%SYS_EXIT_EA%% 12 | #define SYS_WRITE_EA %%SYS_WRITE_EA%% 13 | #define SYS_SEND_EA %%SYS_SEND_EA%% 14 | #define SYS_SENDTO_EA %%SYS_SENDTO_EA%% 15 | #define SYS_READ_EA %%SYS_READ_EA%% 16 | #define SYS_RECV_EA %%SYS_RECV_EA%% 17 | #define SYS_RECVFROM_EA %%SYS_RECVFROM_EA%% 18 | 19 | #define SYS_POLL_EA %%SYS_POLL_EA%% 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /cfg-files/iports.allow: -------------------------------------------------------------------------------- 1 | # /etc/kconnp/iports.allow: list of ip-ports that are allowed to access the kconnp. 2 | # 3 | # Per service:ip:port per line. 4 | # 5 | # Format: service:ip:port(flags) 6 | # service: Service name. 7 | # ip: Internet dotted decimal ip string or '*' wildcard. 8 | # port: Internet port number string. 9 | # flags: S or N 10 | # S 11 | # Stateful connection. 12 | # N 13 | # Non-state connection, that is default set. 14 | # 15 | # Example: memcache:*:11211 16 | # memcache:10.207.0.1:11211 17 | # memcache:10.207.0.[1-9]:11211 18 | # mysql:10.207.0.[1-9]:3306(S) 19 | 20 | memcache:*:11211 #Memcache port, Non-state connection 21 | redis:*:6379 22 | mysql:*:3306 23 | -------------------------------------------------------------------------------- /sys_socketcalls_S.c: -------------------------------------------------------------------------------- 1 | #include "sys_call.h" 2 | #include "auth.h" 3 | #include "lkm_util.h" 4 | 5 | asmlinkage long connp_sys_poll(struct pollfd __user *ufds, unsigned int nfds, 6 | long timeout_msecs) 7 | { 8 | if (nfds == 1) { 9 | struct pollfd pfd; 10 | u32 retcnt; 11 | if (copy_from_user(&pfd, ufds, sizeof(struct pollfd))) 12 | goto orig_poll; 13 | 14 | if (!(pfd.events & POLLIN)) 15 | goto orig_poll; 16 | 17 | retcnt = check_if_ignore_auth_procedure(pfd.fd, NULL, 0, 'i'); //POLLIN 18 | if (retcnt) { 19 | pfd.revents |= POLLIN; 20 | if (__put_user(pfd, ufds)) 21 | goto orig_poll; 22 | 23 | return 1; 24 | } 25 | } 26 | 27 | orig_poll: 28 | return orig_sys_poll(ufds, nfds, timeout_msecs); 29 | } 30 | -------------------------------------------------------------------------------- /auth.h: -------------------------------------------------------------------------------- 1 | #ifndef AUTH_H 2 | #define AUTH_H 3 | 4 | #include "kconnp.h" 5 | #include "lkm_util.h" 6 | 7 | typedef enum { 8 | AUTH_NEW, 9 | AUTH_PROCESSING, 10 | AUTH_FAIL, 11 | AUTH_SUCCESS 12 | } auth_status_t; 13 | 14 | struct auth_stage { 15 | char type; //auth call r/w/i 16 | kconnp_str_t info; //auth info. 17 | struct auth_stage *next; 18 | }; 19 | 20 | extern int check_if_ignore_auth_procedure(int fd, const char __user *buf, size_t len, 21 | char io_type); 22 | 23 | static inline void auth_procedure_destroy(struct auth_stage *procedure_head) 24 | { 25 | struct auth_stage *p, *q; 26 | 27 | p = procedure_head; 28 | 29 | while(p) { 30 | if (p->info.data) 31 | lkmfree(p->info.data); 32 | //printk(KERN_ERR "cfg_destroy type: %d", p->type); 33 | q = p->next; 34 | lkmfree(p); 35 | p = q; 36 | } 37 | } 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | kconnp 2 | ====== 3 | 4 | The connection pool in linux kernel layer. 5 | 6 | ###Requires: 7 | * X86 CPU 8 | * Linux Kernel Version >= 2.6.18 9 | * Host OR VM (KVM,XEN,Vmware, etc) 10 | 11 | ### Installation 12 | 1. $ [download src package](https://github.com/zzgang/kconnp/releases) 13 | 1. $ cd kconnp 14 | 1. $ ./configure 15 | 1. $ make 16 | 1. $ make install 17 | 18 | ### Usage 19 | #####Commands 20 | kconnp (stats|reload|start|stop|restart) 21 | * stats: output the statistics information 22 | * reload: reload the config 23 | * start: start the service 24 | * stop: shutdown the service 25 | * restart: restart the service 26 | 27 | #####Configuration 28 | ######Files 29 | * Global: /etc/kconnp.conf 30 | * White list for ACL: /etc/iports.allow 31 | * Black list for ACL: /etc/iports.deny 32 | * Communication Primitives: /etc/primitives.deny 33 | 34 | ######Explains 35 | * The priority of black list is higher than white black list. 36 | * If the iport is specified,the connections will be pre-connected. 37 | * If the connection is configured stateful (tag: (S)),each connection only be use one time before closing. 38 | 39 | 40 | **E-Mail:**:zzgang2008@gmail.com 41 | -------------------------------------------------------------------------------- /connpd.h: -------------------------------------------------------------------------------- 1 | #ifndef CONNPD_H 2 | #define CONNPD_H 3 | 4 | #include 5 | 6 | #include "stack.h" 7 | #include "cfg.h" 8 | #include "kconnp.h" 9 | 10 | #define NR_MAX_OPEN_FDS CONNECTION_LIMIT 11 | 12 | #define CONNP_DAEMON_TSKP (connp_daemon) 13 | #define CONNP_DAEMON_EXISTS() CONNP_DAEMON_TSKP 14 | #define INVOKED_BY_CONNP_DAEMON() (current == CONNP_DAEMON_TSKP) 15 | 16 | extern struct task_struct * volatile connp_daemon; 17 | 18 | extern int connpd_init(void); 19 | extern void connpd_destroy(void); 20 | 21 | extern struct stack_t *connpd_close_pending_fds, 22 | *connpd_unused_fds; 23 | 24 | #define fd_list_in(list, fd) \ 25 | ({int *ele = (int *)(list)->in(list, &fd); \ 26 | ele ? *ele : -1;}) 27 | #define fd_list_out(list) \ 28 | ({int *ele = (int *)(list)->out(list); \ 29 | ele ? *ele : -1;}) 30 | 31 | #define connpd_get_unused_fd() connpd_unused_fds_out() 32 | 33 | #define connpd_unused_fds_in(fd) fd_list_in(connpd_unused_fds, fd) 34 | #define connpd_unused_fds_out() fd_list_out(connpd_unused_fds) 35 | 36 | #define connpd_close_pending_fds_in(fd) fd_list_in(connpd_close_pending_fds, fd) 37 | #define connpd_close_pending_fds_out() fd_list_out(connpd_close_pending_fds) 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /sys_socketcalls_64.S: -------------------------------------------------------------------------------- 1 | /*For 64bits asm*/ 2 | 3 | .section .text 4 | 5 | .align 2 6 | 7 | .globl connp_sys_poll 8 | 9 | .type connp_sys_poll, @function 10 | 11 | connp_sys_poll: 12 | push %r12 13 | mov %rdx,%r12 14 | push %rbp 15 | mov %rdi,%rbp 16 | push %rbx 17 | mov %esi,%ebx 18 | sub $0x8,%rsp 19 | cmp $0x1,%esi 20 | je connp_poll 21 | orig_sys_call: 22 | mov %r12,%rdx 23 | mov %ebx,%esi 24 | mov %rbp,%rdi 25 | add $0x8,%rsp 26 | pop %rbx 27 | pop %rbp 28 | pop %r12 29 | jmp *orig_sys_poll 30 | out_ret: 31 | add $0x8,%rsp 32 | pop %rbx 33 | pop %rbp 34 | pop %r12 35 | retq 36 | connp_poll: 37 | mov %rdi,%rsi 38 | mov $0x8,%edx 39 | mov %rsp,%rdi 40 | callq lkm_copy_from_user 41 | test %rax,%rax 42 | jne orig_sys_call 43 | testb $0x1,0x4(%rsp) 44 | je orig_sys_call 45 | mov (%rsp),%edi 46 | xor %edx,%edx 47 | xor %esi,%esi 48 | mov $0x69,%ecx 49 | callq check_if_ignore_auth_procedure 50 | test %eax,%eax 51 | je orig_sys_call 52 | orw $0x1,0x6(%rsp) 53 | xor %eax,%eax 54 | mov (%rsp),%rdx 55 | mov %rdx,0x0(%rbp) 56 | test %eax,%eax 57 | jne orig_sys_call 58 | mov $0x1,%eax 59 | jmp out_ret 60 | -------------------------------------------------------------------------------- /sys_socketcalls_32.S: -------------------------------------------------------------------------------- 1 | /*for 32bits asm*/ 2 | .section .text 3 | .align 2 4 | .globl connp_sys_poll 5 | 6 | .type connp_sys_poll, @function 7 | 8 | .type connp_sys_poll, @function 9 | 10 | connp_sys_poll: 11 | push %ebp 12 | mov %esp,%ebp 13 | push %edi 14 | push %esi 15 | push %ebx 16 | sub $0x8,%esp 17 | mov 0xc(%ebp),%edi 18 | mov 0x8(%ebp),%esi 19 | cmp $0x1,%edi 20 | jne orig_sys_call 21 | lea -0x14(%ebp),%eax 22 | mov $0x8,%ecx 23 | mov %esi,%edx 24 | call lkm_copy_from_user 25 | test %eax,%eax 26 | mov %eax,%ebx 27 | jne orig_sys_call 28 | testb $0x1,-0x10(%ebp) 29 | je orig_sys_call 30 | mov -0x14(%ebp),%eax 31 | xor %edx,%edx 32 | xor %ecx,%ecx 33 | push $0x69 34 | call check_if_ignore_auth_procedure 35 | pop %edx 36 | test %eax,%eax 37 | je orig_sys_call 38 | orw $0x1,-0xe(%ebp) 39 | mov -0x14(%ebp),%eax 40 | mov -0x10(%ebp),%edx 41 | mov %eax,(%esi) 42 | mov %edx,0x4(%esi) 43 | test %ebx,%ebx 44 | mov $0x1,%eax 45 | je out_ret 46 | 47 | orig_sys_call: 48 | lea -0xc(%ebp),%esp 49 | pop %ebx 50 | pop %esi 51 | pop %edi 52 | pop %ebp 53 | /*change call to jmp to fix bug when the kconnp is unloaded*/ 54 | /* 55 | pushl 0x10(%ebp) 56 | push %edi 57 | push %esi 58 | */ 59 | jmp *orig_sys_poll 60 | /* 61 | add $0xc,%esp 62 | */ 63 | out_ret: 64 | lea -0xc(%ebp),%esp 65 | pop %ebx 66 | pop %esi 67 | pop %edi 68 | pop %ebp 69 | ret 70 | -------------------------------------------------------------------------------- /scripts/kconnp: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | help(){ 4 | cat < /proc/kconnp/$f; 41 | done; 42 | else 43 | echo "kconnp not running."; 44 | fi 45 | } 46 | 47 | start(){ 48 | if (eval $kconnp_running) 49 | then 50 | echo "kconnp already running."; 51 | exit; 52 | else 53 | insmod $kmconnp && reload; 54 | fi 55 | } 56 | 57 | stop(){ 58 | if (eval $kconnp_running) 59 | then 60 | rmmod $kmconnp; 61 | else 62 | echo "kconnp not running."; 63 | fi 64 | } 65 | 66 | restart(){ 67 | stop; 68 | start; 69 | } 70 | 71 | 72 | 73 | if test $# -eq 0 74 | then 75 | echo "Non action is passed!\n"; 76 | help; 77 | fi 78 | while [ $# -gt 0 ] 79 | do 80 | case "$1" in 81 | -v) 82 | ver; 83 | ;; 84 | stats) 85 | stats; 86 | ;; 87 | reload) 88 | reload; 89 | ;; 90 | start) 91 | start; 92 | ;; 93 | stop) 94 | stop; 95 | ;; 96 | restart) 97 | restart; 98 | ;; 99 | *) 100 | echo "Unrecognized param: $1\n"; 101 | help; 102 | ;; 103 | esac 104 | shift; 105 | done 106 | -------------------------------------------------------------------------------- /connp.h: -------------------------------------------------------------------------------- 1 | #ifndef _CONNP_H 2 | #define _CONNP_H 3 | 4 | #include 5 | #include 6 | #include "sockp.h" 7 | 8 | #define CONN_BLOCK 1 9 | #define CONN_NONBLOCK 2 10 | #define CONN_IS_NONBLOCK(filp) ((filp)->f_flags & O_NONBLOCK) 11 | 12 | //cfg flags 13 | #define CONN_STATEFUL (1<<0) //stateful connection 14 | 15 | #define CONN_PASSIVE_TIMEOUT_JIFFIES_THRESHOLD (60 * HZ) /*1 minute*/ 16 | 17 | typedef enum { 18 | CLOSE_POSITIVE = 0, 19 | CLOSE_PASSIVE 20 | } conn_close_way_t; 21 | 22 | struct conn_attr_t { 23 | struct { 24 | conn_close_way_t close_way; 25 | u64 last_set_jiffies; 26 | } close_way_attrs; 27 | 28 | u64 keep_alive; 29 | int close_now; 30 | 31 | struct { 32 | unsigned int all_count; 33 | unsigned int idle_count; 34 | lkm_atomic_t connected_hit_count; 35 | lkm_atomic_t connected_miss_count; 36 | } stats; 37 | }; 38 | 39 | extern int check_if_ignore_primitives(int fd, const char __user *buf, size_t len); 40 | extern int connp_fd_allowed(int fd); 41 | extern int insert_into_connp_if_permitted(int fd); 42 | extern int fetch_conn_from_connp(int fd, struct sockaddr *); 43 | 44 | extern void connp_sys_exit_prepare(void); 45 | 46 | extern int connp_init(void); 47 | extern void connp_destroy(void); 48 | 49 | #define ALL_COUNT 0 50 | #define IDLE_COUNT 1 51 | #define CONNECTED_HIT_COUNT 2 52 | #define CONNECTED_MISS_COUNT 3 53 | #define conn_inc_all_count(addr) conn_inc_count(addr, ALL_COUNT) 54 | #define conn_inc_idle_count(addr) conn_inc_count(addr, IDLE_COUNT) 55 | #define conn_inc_connected_hit_count(addr) conn_inc_count(addr, CONNECTED_HIT_COUNT) 56 | #define conn_inc_connected_miss_count(addr) conn_inc_count(addr, CONNECTED_MISS_COUNT) 57 | extern int conn_inc_count(struct sockaddr *, int count_type); 58 | 59 | extern int conn_spec_check_close_flag(struct sockaddr *); 60 | 61 | extern void conn_stats_info_dump(void); 62 | 63 | extern rwlock_t connp_rwlock; 64 | /* connpd lock funcions */ 65 | static inline void connp_rwlock_init(void) 66 | { 67 | rwlock_init(&connp_rwlock); 68 | } 69 | 70 | static inline void connp_rlock(void) 71 | { 72 | read_lock(&connp_rwlock); 73 | } 74 | 75 | static inline void connp_runlock(void) 76 | { 77 | read_unlock(&connp_rwlock); 78 | } 79 | 80 | static inline void connp_wlock(void) 81 | { 82 | write_lock(&connp_rwlock); 83 | } 84 | 85 | static inline void connp_wunlock(void) 86 | { 87 | write_unlock(&connp_rwlock); 88 | } 89 | /*end*/ 90 | 91 | #endif 92 | -------------------------------------------------------------------------------- /array.h: -------------------------------------------------------------------------------- 1 | #ifndef ARRAY_H 2 | #define ARRAY_H 3 | 4 | #include "lkm_util.h" 5 | 6 | struct array_t { 7 | //attrs 8 | char *eles; 9 | int ele_size; //one ele real size 10 | int ele_size_align; //one ele size after align 11 | int elements; 12 | 13 | //funcs 14 | int (*create)(struct array_t **s, int elements, int ele_size); 15 | int (*clone)(struct array_t **d, struct array_t *s); 16 | 17 | char *(*get)(struct array_t *s, int idx); 18 | char *(*set)(struct array_t *s, void *ele, int idx); 19 | 20 | void (*destroy)(struct array_t **s); 21 | 22 | }; 23 | 24 | static inline int array_init(struct array_t **s, int elements, int ele_size); 25 | static inline int array_clone(struct array_t **d, struct array_t *s); 26 | 27 | static inline char *array_set(struct array_t *s, void *ele, int idx); 28 | static inline char *array_get(struct array_t *s, int idx); 29 | 30 | static inline void array_destroy(struct array_t **s); 31 | 32 | 33 | static inline int array_init(struct array_t **s, int elements, int ele_size) 34 | { 35 | int ele_size_align; 36 | 37 | if (elements <= 0 || ele_size <= 0) { 38 | *s = NULL; 39 | return 0; 40 | } 41 | 42 | *s = lkmalloc(sizeof(struct array_t)); 43 | if (!*s) 44 | return 0; 45 | 46 | ele_size_align = BYTES_ALIGN(ele_size); 47 | 48 | (*s)->eles = lkmalloc(elements * ele_size_align); 49 | if (!(*s)->eles) { 50 | lkmfree(*s); 51 | *s = NULL; 52 | return 0; 53 | } 54 | 55 | (*s)->elements = elements; 56 | (*s)->ele_size = ele_size; 57 | (*s)->ele_size_align = ele_size_align; 58 | 59 | (*s)->create = array_init; 60 | (*s)->clone = array_clone; 61 | 62 | (*s)->set = array_set; 63 | (*s)->get = array_get; 64 | 65 | (*s)->destroy = array_destroy; 66 | 67 | return 1; 68 | } 69 | 70 | static inline int array_clone(struct array_t **d, struct array_t *s) 71 | { 72 | if (!s) 73 | return 0; 74 | 75 | return array_init(d, s->elements, s->ele_size); 76 | } 77 | 78 | static inline char *array_set(struct array_t *s, void *ele, int idx) 79 | { 80 | if (!s || !ele || idx > (s->elements - 1)) 81 | return NULL; 82 | 83 | return memcpy(s->eles + (idx * s->ele_size_align), ele, s->ele_size); 84 | } 85 | 86 | static inline char *array_get(struct array_t *s, int idx) 87 | { 88 | if (!s || idx > (s->elements - 1)) 89 | return NULL; 90 | 91 | return s->eles + (idx * s->ele_size_align); 92 | } 93 | 94 | static inline void array_destroy(struct array_t **s) 95 | { 96 | if (*s && (*s)->eles) 97 | lkmfree((*s)->eles); 98 | 99 | if (*s) 100 | lkmfree(*s); 101 | 102 | *s = NULL; 103 | } 104 | 105 | #endif 106 | -------------------------------------------------------------------------------- /hash.h: -------------------------------------------------------------------------------- 1 | #ifndef HASH_H 2 | #define HASH_H 3 | 4 | #include "lkm_util.h" 5 | 6 | typedef enum { 7 | HASH_ADD = 1, 8 | HASH_SET 9 | } hash_ops; 10 | 11 | #define hash_key(p) (p)->hkey.key 12 | #define hash_value(p) (p)->hval.val 13 | 14 | #define hash_init(ht, dtor_func) \ 15 | _hash_init(ht, 0, hash_func_times33, dtor_func) 16 | 17 | #define hash_add(ht, key, klen, val, vlen) \ 18 | hash_add_or_set((ht), (key), (klen), (val), (vlen), HASH_ADD) 19 | 20 | #define hash_set(ht, key, klen, val, vlen) \ 21 | hash_add_or_set((ht), (key), (klen), (val), (vlen), HASH_SET) 22 | 23 | #define hash_for_each(ht, pos) \ 24 | for (pos = ((struct hash_table_t *)ht)->trav_head; pos; pos = pos->tnext) 25 | 26 | 27 | typedef unsigned long (*hash_func_t)(const char *, unsigned int); 28 | typedef void (*dtor_func_t)(void *data); 29 | 30 | struct key_t { 31 | char *key; 32 | unsigned int klen; 33 | }; 34 | 35 | struct val_t { 36 | void *val; 37 | unsigned int vlen; 38 | }; 39 | 40 | struct hash_bucket_t { 41 | struct key_t hkey; 42 | struct val_t hval; 43 | struct hash_bucket_t *next; 44 | struct hash_bucket_t *prev; 45 | struct hash_bucket_t *tnext; /*traverse*/ 46 | struct hash_bucket_t *tprev; 47 | }; 48 | 49 | struct hash_table_t { 50 | struct hash_bucket_t **buckets; 51 | struct hash_bucket_t *trav_head; 52 | struct hash_bucket_t *trav_tail; 53 | unsigned int table_size; 54 | unsigned int hash_mask; 55 | unsigned int elements_count; 56 | dtor_func_t dtor_func; 57 | hash_func_t hash_func; 58 | }; 59 | 60 | 61 | /* 62 | *Times 33 arithmetic hash func. 63 | */ 64 | static inline unsigned long hash_func_times33(const char *key, unsigned int klen) 65 | { 66 | register unsigned long hash = 0; 67 | const char *c; 68 | int i; 69 | 70 | for (i = 0, c = key; i < klen; i++, c++) 71 | hash = ((hash << 5) + hash) + *c; 72 | 73 | return hash; 74 | } 75 | 76 | static inline void dtor_func_lkmfree(void *data) 77 | { 78 | if (data) 79 | lkmfree(data); 80 | } 81 | 82 | extern int _hash_init(struct hash_table_t **, unsigned int tsize, 83 | hash_func_t hash_func, dtor_func_t dtor_func); 84 | extern int hash_add_or_set(struct hash_table_t *, 85 | const char *key, unsigned int klen, 86 | void *val, unsigned int vlen, 87 | hash_ops op); 88 | extern int hash_find(struct hash_table_t *, 89 | const char *key, unsigned int klen, 90 | void **val); 91 | static inline int hash_exists(struct hash_table_t *ht, const char *key, 92 | unsigned int klen) 93 | { 94 | void *val = NULL; 95 | 96 | if (hash_find(ht, key, klen, &val) && val) 97 | return 1; 98 | 99 | return 0; 100 | } 101 | extern int hash_destroy(struct hash_table_t **); 102 | 103 | #endif 104 | -------------------------------------------------------------------------------- /preconnect.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "cfg.h" 4 | #include "preconnect.h" 5 | #include "lkm_util.h" 6 | #include "sys_call.h" 7 | #include "connp.h" 8 | 9 | /* 10 | *Scan cfg entries to find the spare conns. 11 | * 12 | *If the spare counts of conns exceeds the MAX_SPARE_CONNECTIONS, shutdown the conns. 13 | *If the spare counts of conns lower than the MIN_SPARE_CONNECTIONS, create the conns. 14 | */ 15 | 16 | static void do_preconnect(void *data); 17 | static void conn_init_count(void *data); 18 | 19 | static void do_create_connects(struct sockaddr_in *, int nums); 20 | 21 | static void conn_init_count(void *data) 22 | { 23 | struct conn_node_t *conn_node; 24 | 25 | conn_node = (typeof(conn_node))data; 26 | conn_node->conn_all_count = 0; 27 | conn_node->conn_idle_count = 0; 28 | } 29 | 30 | static void do_preconnect(void *data) 31 | { 32 | struct conn_node_t *conn_node; 33 | struct sockaddr_in address; 34 | unsigned int idle_count; 35 | int preconnect_nums; 36 | 37 | conn_node = (typeof(conn_node))data; 38 | 39 | if (conn_node->conn_ip == 0 || conn_node->conn_port == 0) 40 | return; 41 | 42 | idle_count = conn_node->conn_idle_count; 43 | 44 | address.sin_family = AF_INET; 45 | address.sin_addr.s_addr = conn_node->conn_ip; 46 | address.sin_port = conn_node->conn_port; 47 | 48 | //set close flag for one group conns. 49 | if (idle_count > MAX_SPARE_CONNECTIONS) { 50 | conn_node->conn_close_now = 1; 51 | return; 52 | } 53 | 54 | //do preconnect 55 | preconnect_nums = MIN_SPARE_CONNECTIONS - idle_count; 56 | do_create_connects(&address, preconnect_nums); 57 | 58 | return; 59 | } 60 | 61 | static void do_create_connects(struct sockaddr_in *servaddr, int nums) 62 | { 63 | int fd; 64 | struct socket *sock; 65 | struct sockaddr cliaddr; 66 | struct conn_node_t *conn_node; 67 | int i, pre_insert_auth_sock = 0; 68 | 69 | conn_node = cfg_conn_get_node((struct sockaddr *)servaddr); 70 | if (!conn_node) 71 | return; 72 | 73 | pre_insert_auth_sock = conn_node->auth_node && conn_node->auth_node->data; 74 | 75 | for (i = 0; i < nums; i++) { 76 | 77 | fd = lkm_create_tcp_connect(servaddr); 78 | if (fd < 0) 79 | break; 80 | 81 | sock = getsock(fd); 82 | if (!sock) 83 | break; 84 | 85 | if (!getsockcliaddr(sock, &cliaddr)) 86 | break; 87 | 88 | if (insert_sock_to_sockp(&cliaddr, 89 | (struct sockaddr *)servaddr, 90 | sock, fd, 91 | SOCK_PRECONNECT, 92 | NULL, 93 | pre_insert_auth_sock) != KCP_OK) { 94 | orig_sys_close(fd); 95 | break; 96 | } 97 | } 98 | 99 | return; 100 | } 101 | 102 | void scan_spare_conns_preconnect() 103 | { 104 | cfg_allowed_entries_for_each_call(do_preconnect); 105 | cfg_allowed_entries_for_each_call(conn_init_count); 106 | } 107 | -------------------------------------------------------------------------------- /stack.h: -------------------------------------------------------------------------------- 1 | #ifndef STACK_H 2 | #define STACK_H 3 | 4 | #include "lkm_util.h" 5 | 6 | #define WITHOUT_MUTEX 0 7 | #define WITH_MUTEX 1 8 | 9 | struct stack_t { 10 | //attrs 11 | char *eles; 12 | int ele_size; //one ele size 13 | int ele_size_align; //one ele size after align 14 | int list_size; //stack capacity 15 | int elements; 16 | int sp; 17 | spinlock_t *s_lock; 18 | 19 | //funcs 20 | int (*create)(struct stack_t **s, int list_size, int ele_size, int mutex); 21 | int (*clone)(struct stack_t **d, struct stack_t *s); 22 | 23 | char *(*in)(struct stack_t *s, void *ele); 24 | char *(*out)(struct stack_t *s); 25 | 26 | void (*destroy)(struct stack_t **s); 27 | }; 28 | 29 | static inline int stack_init(struct stack_t **s, int list_size, int ele_size, int mutex); 30 | static inline int stack_clone(struct stack_t **d, struct stack_t *s); 31 | 32 | static inline char *stack_push(struct stack_t *s, void *ele); 33 | static inline char *stack_pop(struct stack_t *s); 34 | 35 | static inline void stack_destroy(struct stack_t **s); 36 | 37 | #define stack_is_empty(s) (s->sp == -1) 38 | #define stack_is_full(s) (s->sp == (s->list_size - 1)) 39 | 40 | static inline int stack_init(struct stack_t **s, int list_size, int ele_size, int mutex) 41 | { 42 | int ele_size_align; 43 | 44 | if (list_size <= 0 || ele_size <= 0) { 45 | *s = NULL; 46 | return 0; 47 | } 48 | 49 | *s = lkmalloc(sizeof(struct stack_t)); 50 | if (!*s) 51 | return 0; 52 | 53 | ele_size_align = BYTES_ALIGN(ele_size); 54 | 55 | (*s)->eles = lkmalloc(list_size * ele_size_align); 56 | if (!(*s)->eles) { 57 | lkmfree(*s); 58 | *s = NULL; 59 | return 0; 60 | } 61 | 62 | (*s)->list_size = list_size; 63 | (*s)->ele_size = ele_size; 64 | (*s)->ele_size_align = ele_size_align; 65 | (*s)->elements = 0; 66 | (*s)->sp = -1; 67 | (*s)->s_lock = NULL; 68 | 69 | (*s)->create = stack_init; 70 | (*s)->clone = stack_clone; 71 | 72 | (*s)->in = stack_push; 73 | (*s)->out = stack_pop; 74 | 75 | (*s)->destroy = stack_destroy; 76 | 77 | if (mutex) { 78 | (*s)->s_lock = (spinlock_t *)lkmalloc(sizeof(spinlock_t)); 79 | spin_lock_init((*s)->s_lock); 80 | } 81 | 82 | return 1; 83 | } 84 | 85 | static inline int stack_clone(struct stack_t **d, struct stack_t *s) 86 | { 87 | if (!s) 88 | return 0; 89 | 90 | return stack_init(d, s->list_size, s->ele_size, s->s_lock ? WITH_MUTEX : WITHOUT_MUTEX); 91 | } 92 | 93 | static inline char *stack_push(struct stack_t *s, void *ele) 94 | { 95 | if (!s) 96 | return NULL; 97 | 98 | if (s->s_lock) 99 | spin_lock(s->s_lock); 100 | 101 | if (stack_is_full(s)) 102 | goto ret_fail; 103 | 104 | ++s->sp; 105 | ++s->elements; 106 | 107 | memcpy(s->eles + (s->sp * s->ele_size_align), ele, s->ele_size); 108 | 109 | out: 110 | if (s->s_lock) 111 | spin_unlock(s->s_lock); 112 | return ele; 113 | ret_fail: 114 | ele = NULL; 115 | goto out; 116 | } 117 | 118 | static inline char *stack_pop(struct stack_t *s) 119 | { 120 | void *ele; 121 | 122 | if (!s) 123 | return NULL; 124 | 125 | if (s->s_lock) 126 | spin_lock(s->s_lock); 127 | 128 | if (stack_is_empty(s)) 129 | goto ret_fail; 130 | 131 | ele = s->eles + (s->sp * s->ele_size_align); 132 | 133 | --s->sp; 134 | --s->elements; 135 | 136 | out: 137 | if (s->s_lock) 138 | spin_unlock(s->s_lock); 139 | return ele; 140 | ret_fail: 141 | ele = NULL; 142 | goto out; 143 | } 144 | 145 | static inline void stack_destroy(struct stack_t **s) 146 | { 147 | if (*s && (*s)->s_lock) 148 | lkmfree((*s)->s_lock); 149 | 150 | if (*s && (*s)->eles) 151 | lkmfree((*s)->eles); 152 | 153 | if (*s) 154 | lkmfree(*s); 155 | 156 | *s = NULL; 157 | } 158 | 159 | #endif 160 | -------------------------------------------------------------------------------- /sys_call.h: -------------------------------------------------------------------------------- 1 | #ifndef SYS_CALL_H 2 | #define SYS_CALL_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "sockp.h" 8 | 9 | #define SYSCALL_REPLACE (1 << 0) 10 | #define SYSCALL_RESTORE (1 << 1) 11 | 12 | #define replace_syscalls() connp_set_syscall(SYSCALL_REPLACE) 13 | #define restore_syscalls() connp_set_syscall(SYSCALL_RESTORE) 14 | 15 | #define MAX_SYS_CALL_NUM 2048 16 | 17 | struct pollfd; 18 | 19 | struct syscall_func_struct { 20 | char *name; //sys call name. 21 | unsigned long sym_addr; // Get from symbol map file. 22 | unsigned long real_addr; //Get from kernel symbol table. 23 | int nr; //sys call nr 24 | void ** new_sys_func; 25 | void ** orig_sys_func; 26 | }; 27 | 28 | extern int connp_set_syscall(int flag); 29 | 30 | typedef asmlinkage long (*sys_connect_func_ptr_t)(int fd, struct sockaddr __user *, int addrlen); 31 | typedef asmlinkage long (*sys_shutdown_func_ptr_t)(int fd, int way); 32 | typedef asmlinkage long (*sys_close_func_ptr_t)(int fd); 33 | typedef asmlinkage long (*sys_exit_func_ptr_t)(int error_code); 34 | 35 | typedef asmlinkage ssize_t (*sys_write_func_ptr_t)(int fd, const char __user *buf, size_t count); 36 | typedef asmlinkage ssize_t (*sys_sendto_func_ptr_t)(int sockfd, const void __user *buf, size_t len, int flags, const struct sockaddr __user *addr, int addrlen); 37 | 38 | typedef asmlinkage ssize_t (*sys_read_func_ptr_t)(int fd, const char __user *buf, size_t count); 39 | typedef asmlinkage ssize_t (*sys_recvfrom_func_ptr_t)(int sockfd, const void __user *buf, size_t len, int flags, const struct sockaddr __user *addr, int *addrlen); 40 | typedef asmlinkage long (*sys_poll_func_ptr_t)(struct pollfd __user *ufds, unsigned int nfds, long timeout_msecs); 41 | 42 | extern sys_connect_func_ptr_t orig_sys_connect; 43 | extern sys_shutdown_func_ptr_t orig_sys_shutdown; 44 | extern sys_close_func_ptr_t orig_sys_close; 45 | extern sys_exit_func_ptr_t orig_sys_exit; 46 | extern sys_exit_func_ptr_t orig_sys_exit_group; 47 | extern sys_write_func_ptr_t orig_sys_write; 48 | extern sys_sendto_func_ptr_t orig_sys_sendto; 49 | extern sys_read_func_ptr_t orig_sys_read; 50 | extern sys_recvfrom_func_ptr_t orig_sys_recvfrom; 51 | extern sys_poll_func_ptr_t orig_sys_poll; 52 | 53 | #ifdef __NR_socketcall 54 | typedef asmlinkage long (*sys_socketcall_func_ptr_t)(int call, unsigned long __user *args); 55 | typedef asmlinkage long (*sys_send_func_ptr_t)(int sockfd, const void __user * buf, size_t len, int flags); 56 | typedef asmlinkage long (*sys_recv_func_ptr_t)(int sockfd, const void __user * buf, size_t len, int flags); 57 | extern sys_socketcall_func_ptr_t orig_sys_socketcall; 58 | extern sys_send_func_ptr_t orig_sys_send; 59 | extern sys_recv_func_ptr_t orig_sys_recv; 60 | #endif 61 | 62 | extern asmlinkage long connp_sys_connect(int fd, struct sockaddr __user *, int addrlen); 63 | extern asmlinkage long connp_sys_shutdown(int fd, int way); 64 | extern asmlinkage long connp_sys_close(int fd); 65 | extern asmlinkage long connp_sys_exit(int error_code); 66 | extern asmlinkage long connp_sys_exit_group(int error_code); 67 | extern asmlinkage ssize_t connp_sys_write(int fd, const char __user * buf, size_t count); 68 | extern asmlinkage long connp_sys_sendto(int sockfd, const void __user * buf, size_t len, int flags, const struct sockaddr __user * dest_addr, int addrlen); 69 | extern asmlinkage ssize_t connp_sys_read(int fd, const char __user *buf, size_t count); 70 | extern asmlinkage ssize_t connp_sys_recvfrom(int sockfd, const void __user *buf, size_t len, int flags, const struct sockaddr __user *addr, int *addrlen); 71 | extern asmlinkage long connp_sys_poll(struct pollfd __user *ufds, unsigned int nfds, 72 | long timeout_msecs); 73 | 74 | #ifdef __NR_socketcall 75 | extern asmlinkage long connp_sys_socketcall(int call, unsigned long __user *args); 76 | extern asmlinkage long socketcall_sys_send(int sockfd, const void __user * buf, size_t len, int flags); 77 | extern asmlinkage long socketcall_sys_recv(int sockfd, const void __user * buf, size_t len, int flags); 78 | #endif 79 | 80 | extern long socketcall_sys_connect(int fd, struct sockaddr __user *, int addrlen); 81 | extern long socketcall_sys_sendto(int sockfd, const void __user * buf, size_t len, int flags, const struct sockaddr __user * dest_addr, int addrlen); 82 | extern ssize_t socketcall_sys_recvfrom(int sockfd, const void __user *buf, size_t len, int flags, const struct sockaddr __user *addr, int *addrlen); 83 | extern long socketcall_sys_shutdown(int fd, int way); 84 | extern int socketcall_move_addr_to_kernel(void __user *uaddr, int ulen, 85 | struct sockaddr *kaddr); 86 | 87 | #endif 88 | -------------------------------------------------------------------------------- /sockp.h: -------------------------------------------------------------------------------- 1 | /** 2 | *Header for sockp.c 3 | *Date 05/27/2012 4 | *Author Zhigang Zhang 5 | */ 6 | #ifndef SOCKP_H 7 | #define SOCKP_H 8 | 9 | #include /*define struct sockaddr_in*/ 10 | #include /*define struct socket*/ 11 | #include 12 | #include "stack.h" 13 | #include "auth.h" 14 | 15 | #define SOCKP_DEBUG 0 16 | 17 | #define NR_SOCKET_BUCKET NR_MAX_OPEN_FDS 18 | 19 | #define NR_HASH ((NR_SOCKET_BUCKET)/2 + 1) 20 | #define NR_SHASH (NR_SOCKET_BUCKET) 21 | 22 | #define WAIT_TIMEOUT (GN("connection_wait_timeout") * HZ)//seconds 23 | 24 | #define MAX_REQUESTS ({ \ 25 | u64 requests = GN("max_requests_per_connection"); \ 26 | requests ? requests : ~0ULL; \ 27 | }) 28 | 29 | #define LRU 1 //LRU replace algorithm 30 | 31 | #define shutdown_all_sock_list() shutdown_sock_list(SHUTDOWN_ALL) 32 | #define shutdown_timeout_sock_list() shutdown_sock_list(SHUTDOWN_IDLE) 33 | 34 | typedef enum { 35 | SOCK_NEW, 36 | SOCK_AUTH, 37 | SOCK_CONNECTED 38 | } sock_status_t; 39 | 40 | typedef enum { 41 | SOCK_RECLAIM, 42 | SOCK_PRECONNECT 43 | } sock_create_way_t; 44 | 45 | typedef enum { 46 | SHUTDOWN_ALL, 47 | SHUTDOWN_IDLE 48 | } shutdown_way_t; 49 | 50 | struct socket_bucket { 51 | struct sockaddr cliaddr; 52 | struct sockaddr servaddr; 53 | 54 | struct socket *sock; 55 | struct sock *sk; 56 | 57 | sock_create_way_t sock_create_way; 58 | 59 | unsigned char sb_in_use; 60 | unsigned char sock_in_use; /*tag: wether it is in use*/ 61 | 62 | unsigned char sock_close_now; /*tag: wether be closed at once*/ 63 | 64 | u64 sock_create_jiffies; /*the jiffies to be inserted*/ 65 | u64 last_used_jiffies; /*the last used jiffies*/ 66 | 67 | u64 uc; /*used count*/ 68 | 69 | struct socket_bucket *sb_prev; 70 | struct socket_bucket *sb_next; /*for hash table*/ 71 | 72 | struct socket_bucket *sb_sprev; 73 | struct socket_bucket *sb_snext; /*for with sk addr hash table*/ 74 | 75 | struct socket_bucket *sb_trav_prev; /*traverse all used buckets*/ 76 | struct socket_bucket *sb_trav_next; 77 | 78 | struct socket_bucket *sb_free_prev; /*free bucket indicator*/ 79 | struct socket_bucket *sb_free_next; 80 | 81 | int connpd_fd; /*attached fd of the connpd*/ 82 | 83 | /*add auth procedure for stateful connection*/ 84 | struct { 85 | unsigned int generation; //initial from cfg generation! 86 | #define cfg_generation auth_procedure.generation 87 | auth_status_t status; 88 | #define auth_procedure_status auth_procedure.status 89 | struct auth_stage *procedure_head; 90 | #define auth_procedure_head auth_procedure.procedure_head 91 | struct auth_stage *procedure_tail; 92 | #define auth_procedure_tail auth_procedure.procedure_tail 93 | struct auth_stage *stage; 94 | #define auth_procedure_stage auth_procedure.stage 95 | } auth_procedure; 96 | 97 | spinlock_t s_lock; //sb spin lock 98 | }; 99 | 100 | extern struct stack_t *sockp_sbs_check_list; 101 | 102 | #define sockp_sbs_check_list_in(sb) \ 103 | sockp_sbs_check_list->in(sockp_sbs_check_list, sb) 104 | 105 | #define sockp_sbs_check_list_out(sb) \ 106 | sockp_sbs_check_list->out(sockp_sbs_check_list) 107 | 108 | #define SOCK_SET_ATTR_DEFINE(sock, attr) \ 109 | void set_##attr(struct socket *sock, typeof(((struct socket_bucket *)NULL)->attr) attr) 110 | 111 | extern void set_sock_close_now(struct socket *sock, typeof(((struct socket_bucket *)NULL)->sock_close_now) close_now); 112 | 113 | /** 114 | *Apply a existed socket from socket pool. 115 | */ 116 | extern struct socket_bucket *apply_sk_from_sockp(struct sockaddr *, struct sockaddr *); 117 | 118 | #define AUTH_SOCK_SB 1 119 | #define JUST_PREINSERT_AUTH_SOCK_SB 2 120 | 121 | #define get_auth_sb(sk) get_sock_sb(sk, AUTH_SOCK_SB) 122 | #define get_just_preinsert_auth_sb(sk) get_sock_sb(sk, JUST_PREINSERT_AUTH_SOCK_SB) 123 | extern struct socket_bucket *get_sock_sb(struct sock *sk, int sock_type); 124 | 125 | /** 126 | *Free a socket which is returned by 'apply_socket_from_sockp', return the bucket of this socket. 127 | */ 128 | extern int free_sk_to_sockp(struct sock *, struct socket_bucket **); 129 | 130 | /** 131 | *Insert a new socket to sockp, return the new bucket of this socket. 132 | */ 133 | extern int insert_sock_to_sockp(struct sockaddr *, struct sockaddr *, 134 | struct socket *, int fd, sock_create_way_t create_way, 135 | struct socket_bucket **sbpp, int pre_insert_auth_sock); 136 | 137 | 138 | extern void shutdown_sock_list(shutdown_way_t shutdown_way); 139 | 140 | extern int sockp_init(void); 141 | extern void sockp_destroy(void); 142 | 143 | #endif 144 | -------------------------------------------------------------------------------- /configure: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | help(){ 4 | cat </dev/null; 22 | rm -f Makefile; 23 | rm -f sys_call_table_ea.h; 24 | rm -f local_func_ea.h; 25 | } 26 | 27 | #kernel version. 28 | kv=`uname -r`; 29 | 30 | #kernel system map. 31 | sysmap_file=""; 32 | 33 | #kernel build dir. 34 | kmbd="/lib/modules/${kv}/build"; 35 | 36 | boot_dir="/boot" 37 | 38 | #check sysmap. 39 | if [ -f "${boot_dir}/System.map-$kv" ] 40 | then 41 | sysmap_file="${boot_dir}/System.map-$kv"; 42 | elif [ -f "${boot_dir}/Systemmap-$kv" ] 43 | then 44 | sysmap_file="${boot_dir}/Systemmap-$kv"; 45 | fi 46 | 47 | while [ $# -gt 0 ] 48 | do 49 | case "${1%=*}" in 50 | --with-kernel-build-dir) 51 | kmbd="${1#*=}"; 52 | ;; 53 | --debug) 54 | sysctl -w kernel.panic=1 > /dev/null 55 | ;; 56 | --clean) 57 | clean; 58 | exit; 59 | ;; 60 | --help) 61 | help; 62 | ;; 63 | *) 64 | echo "Unrecognized param: ${1%=*}"; 65 | help; 66 | ;; 67 | esac 68 | shift; 69 | done 70 | 71 | if test ! -d $kmbd || test ! -e $sysmap_file 72 | then 73 | echo "Error: Can't build the ENV for building the LKM"; 74 | help; 75 | else 76 | echo "Check kernel devel dir for building LKM... yes"; 77 | echo "Check kernel sysmap file for building LKM... yes"; 78 | fi 79 | 80 | ####################### 81 | #Generate sys calls ea. 82 | ####################### 83 | 84 | sys_call_table_ea=`grep '\bsys_call_table\b' $sysmap_file | awk '{print $1;}' | sed -e 's/0x//'`; 85 | sys_socketcall_ea=`grep '\bsys_socketcall\b' $sysmap_file | awk '{print $1;}' | sed -e 's/0x//'`; 86 | sys_connect_ea=`grep '\bsys_connect\b' $sysmap_file | awk '{print $1;}' | sed -e 's/0x//'`; 87 | sys_close_ea=`grep '\bsys_close\b' $sysmap_file | awk '{print $1;}' | sed -e 's/0x//'`; 88 | sys_shutdown_ea=`grep '\bsys_shutdown\b' $sysmap_file | awk '{print $1;}' | sed -e 's/0x//'`; 89 | sys_exit_group_ea=`grep '\bsys_exit_group\b' $sysmap_file | awk '{print $1;}' | sed -e 's/0x//'`; 90 | sys_exit_ea=`grep '\bsys_exit\b' $sysmap_file | awk '{print $1;}' | sed -e 's/0x//'`; 91 | sys_write_ea=`grep '\bsys_write\b' $sysmap_file | awk '{print $1;}' | sed -e 's/0x//'`; 92 | sys_send_ea=`grep '\bsys_send\b' $sysmap_file | awk '{print $1;}' | sed -e 's/0x//'`; 93 | sys_sendto_ea=`grep '\bsys_sendto\b' $sysmap_file | awk '{print $1;}' | sed -e 's/0x//'`; 94 | sys_read_ea=`grep '\bsys_read\b' $sysmap_file | awk '{print $1;}' | sed -e 's/0x//'`; 95 | sys_recv_ea=`grep '\bsys_recv\b' $sysmap_file | awk '{print $1;}' | sed -e 's/0x//'`; 96 | sys_recvfrom_ea=`grep '\bsys_recvfrom\b' $sysmap_file | awk '{print $1;}' | sed -e 's/0x//'`; 97 | sys_poll_ea=`grep '\bsys_poll\b' $sysmap_file | awk '{print $1;}' | sed -e 's/0x//'`; 98 | 99 | cat sys_call_table_ea.h.in | 100 | sed -e "s/%%SYS_CALL_TABLE_EA%%/0x${sys_call_table_ea}/" | 101 | sed -e "s/%%SYS_SOCKETCALL_EA%%/0x${sys_socketcall_ea}/" | 102 | sed -e "s/%%SYS_CONNECT_EA%%/0x${sys_connect_ea}/" | 103 | sed -e "s/%%SYS_CLOSE_EA%%/0x${sys_close_ea}/" | 104 | sed -e "s/%%SYS_SHUTDOWN_EA%%/0x${sys_shutdown_ea}/" | 105 | sed -e "s/%%SYS_EXIT_GROUP_EA%%/0x${sys_exit_group_ea}/" | 106 | sed -e "s/%%SYS_EXIT_EA%%/0x${sys_exit_ea}/" | 107 | sed -e "s/%%SYS_WRITE_EA%%/0x${sys_write_ea}/" | 108 | sed -e "s/%%SYS_SEND_EA%%/0x${sys_send_ea}/" | 109 | sed -e "s/%%SYS_SENDTO_EA%%/0x${sys_sendto_ea}/" | 110 | sed -e "s/%%SYS_READ_EA%%/0x${sys_read_ea}/" | 111 | sed -e "s/%%SYS_RECV_EA%%/0x${sys_recv_ea}/" | 112 | sed -e "s/%%SYS_RECVFROM_EA%%/0x${sys_recvfrom_ea}/" | 113 | sed -e "s/%%SYS_POLL_EA%%/0x${sys_poll_ea}/" > sys_call_table_ea.h; 114 | 115 | EXTRA_CFLAGS="" 116 | 117 | machine_type=`uname -m | sed -e 's/^i[0-9]86$/x86_32/'` 118 | 119 | case "$machine_type" in 120 | 'x86_32') 121 | machine_type='x86_32' 122 | ;; 123 | 'x86_64') 124 | ;; 125 | *) 126 | echo "Error: Unsurported machine type $machine_type" 127 | exit 128 | ;; 129 | esac 130 | 131 | echo "Check machine type... $machine_type yes"; 132 | 133 | gcc_ver=`gcc -v 2>&1 | tail -n 1 | grep -o -P "\d\.\d" | head -n 1` 134 | gcc_ver_pri=`echo $gcc_ver | awk -F '.' '{print $1;}'` 135 | gcc_ver_sec=`echo $gcc_ver | awk -F '.' '{print $2;}'` 136 | gcc_ver_curr=$((gcc_ver_pri*100 + gcc_ver_sec)); 137 | gcc_ver_min=$((4*100 + 4)); 138 | if [ $gcc_ver_curr -ge $gcc_ver_min ] 139 | then 140 | gcc_ver_valid="yes" 141 | else 142 | gcc_ver_valid="no" 143 | fi 144 | 145 | echo "Check gcc version... $gcc_ver >= 4.4 $gcc_ver_valid" 146 | test $gcc_ver_valid = "no" && exit 147 | 148 | if [ "$machine_type" = "x86_32" ] 149 | then 150 | EXTRA_CFLAGS="EXTRA_CFLAGS += -fno-omit-frame-pointer" 151 | ASM_OBJ_FILE="sys_socketcalls_32.o" 152 | else 153 | ASM_OBJ_FILE="sys_socketcalls_64.o" 154 | EXTRA_CFLAGS="EXTRA_CFLAGS += -foptimize-sibling-calls" 155 | fi 156 | 157 | cat > Makefile < 2 | #include "connpd.h" 3 | #include "connp.h" 4 | #include "sockp.h" 5 | #include "sys_call.h" 6 | #include "preconnect.h" 7 | #include "lkm_util.h" 8 | #include "array.h" 9 | 10 | #define CONNPD_NAME "kconnpd" 11 | #define CONNP_DAEMON_SET(v) (connp_daemon = (v)) 12 | 13 | struct task_struct * volatile connp_daemon; 14 | 15 | static int connpd_func(void *data); 16 | static int connpd_start(void); 17 | static void connpd_stop(void); 18 | 19 | static int connpd_do_poll(void *data, poll_table *pt); 20 | static void connp_wait_events_or_timout(void); 21 | 22 | static void connpd_unused_fds_prefetch(void); 23 | static void connpd_unused_fds_put(void); 24 | 25 | #define CLOSE_ALL 0 26 | #define CLOSE_TIMEOUT 1 27 | #define close_all_files() do_close_files(CLOSE_ALL) 28 | #define close_timeout_files() do_close_files(CLOSE_TIMEOUT) 29 | static void do_close_files(int close_type); 30 | 31 | struct stack_t *connpd_close_pending_fds, 32 | *connpd_unused_fds; 33 | 34 | #define connpd_close_pending_fds_init(num) \ 35 | stack_init(&connpd_close_pending_fds, num, sizeof(int), WITHOUT_MUTEX) 36 | 37 | #define connpd_close_pending_fds_destroy() \ 38 | do { \ 39 | if (connpd_close_pending_fds) \ 40 | connpd_close_pending_fds->destroy(&connpd_close_pending_fds); \ 41 | } while(0) 42 | 43 | #define connpd_unused_fds_init(num) \ 44 | stack_init(&connpd_unused_fds, num, sizeof(int), WITH_MUTEX) 45 | 46 | #define connpd_unused_fds_destroy() \ 47 | do { \ 48 | if (connpd_unused_fds) \ 49 | connpd_unused_fds->destroy(&connpd_unused_fds); \ 50 | } while(0) 51 | 52 | static void connpd_unused_fds_prefetch() 53 | { 54 | int fd; 55 | 56 | while ((fd = lkm_get_unused_fd()) >= 0) { 57 | if (connpd_unused_fds_in(fd) >= 0) 58 | continue; 59 | else { 60 | put_unused_fd(fd); 61 | break; 62 | } 63 | } 64 | } 65 | 66 | static void connpd_unused_fds_put() 67 | { 68 | int fd; 69 | 70 | while ((fd = connpd_unused_fds_out()) >= 0) 71 | put_unused_fd(fd); 72 | } 73 | 74 | static void do_close_files(int close_type) 75 | { 76 | int fd; 77 | 78 | if (close_type == CLOSE_ALL) 79 | shutdown_all_sock_list(); 80 | else 81 | shutdown_timeout_sock_list(); 82 | 83 | while ((fd = connpd_close_pending_fds_out()) >= 0) 84 | orig_sys_close(fd); 85 | 86 | } 87 | 88 | static int connpd_do_poll(void *data, poll_table *pt) 89 | { 90 | struct socket_bucket *sb; 91 | struct file *file; 92 | int mask = 0; 93 | 94 | sb = (struct socket_bucket *)data; 95 | file = lkm_get_file(sb->connpd_fd); 96 | 97 | spin_lock(&sb->s_lock); 98 | if (sb->sock->sk) 99 | mask = file->f_op->poll(file, pt); 100 | spin_unlock(&sb->s_lock); 101 | 102 | return mask; 103 | } 104 | 105 | /** 106 | *Wait events or timeout. 107 | */ 108 | static void connp_wait_events_or_timout(void) 109 | { 110 | int nums; 111 | struct socket_bucket **sb; 112 | struct pollfd_ex_t pfdt; 113 | struct array_t *pollfd_array; 114 | int count = 0; 115 | int idx = 0; 116 | int timeout = 1;//sec 117 | 118 | nums = sockp_sbs_check_list->elements; 119 | 120 | if (!array_init(&pollfd_array, nums, sizeof(struct pollfd_ex_t))) 121 | goto poll; 122 | 123 | while ((sb = (struct socket_bucket **)sockp_sbs_check_list_out())) { 124 | 125 | pfdt.pollfd.fd = (*sb)->connpd_fd; 126 | pfdt.pollfd.events = POLLRDHUP; 127 | pfdt.pollfd.revents = 0; 128 | pfdt.data = (*sb); 129 | pfdt.poll_func = connpd_do_poll; 130 | 131 | pollfd_array->set(pollfd_array, &pfdt, idx++); 132 | 133 | } 134 | 135 | poll: 136 | count = lkm_poll(pollfd_array, timeout); 137 | 138 | if (!pollfd_array) 139 | return; 140 | 141 | if (count <= 0) 142 | goto out_free; 143 | 144 | { 145 | struct pollfd_ex_t *pfdp; 146 | 147 | for(idx = 0; idx < pollfd_array->elements; idx++) { 148 | 149 | pfdp = (struct pollfd_ex_t *)pollfd_array->get(pollfd_array, idx); 150 | 151 | if (pfdp && (pfdp->pollfd.revents & (POLLRDHUP|E_EVENTS))) { 152 | struct socket *sock; 153 | 154 | sock = ((struct socket_bucket *)pfdp->data)->sock; 155 | set_sock_close_now(sock, 1); 156 | } 157 | 158 | } 159 | } 160 | 161 | out_free: 162 | pollfd_array->destroy(&pollfd_array); 163 | } 164 | 165 | static int connpd_func(void *data) 166 | { 167 | struct rlimit new_rlim = {NR_MAX_OPEN_FDS, NR_MAX_OPEN_FDS}; 168 | 169 | lkm_setrlimit(RLIMIT_NOFILE, new_rlim); 170 | 171 | allow_signal(NOTIFY_SIG); 172 | 173 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0) 174 | init_waitqueue_head(¤t->files->resize_wait); 175 | #endif 176 | 177 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0) 178 | init_waitqueue_head(¤t->files->resize_wait); 179 | #endif 180 | 181 | for(;;) { 182 | 183 | if (kthread_should_stop()) { 184 | 185 | connp_wlock(); 186 | 187 | connpd_unused_fds_put(); 188 | close_all_files(); 189 | 190 | CONNP_DAEMON_SET(NULL); 191 | 192 | connp_wunlock(); 193 | 194 | break; 195 | 196 | } else { 197 | //Scan and shutdown 198 | close_timeout_files(); 199 | 200 | connpd_unused_fds_prefetch(); 201 | 202 | scan_spare_conns_preconnect(); 203 | 204 | conn_stats_info_dump(); 205 | 206 | connp_wait_events_or_timout(); 207 | 208 | } 209 | 210 | } 211 | 212 | return 1; 213 | } 214 | 215 | /** 216 | *Create the kconnpd and start it. 217 | */ 218 | static int connpd_start(void) 219 | { 220 | struct task_struct *ptr; 221 | 222 | ptr = kthread_run(connpd_func, NULL, CONNPD_NAME); 223 | 224 | if (!IS_ERR(ptr)) 225 | CONNP_DAEMON_SET(ptr); 226 | else 227 | printk(KERN_ERR "Create connpd error!"); 228 | 229 | return IS_ERR(ptr) ? 0 : 1; 230 | } 231 | 232 | /** 233 | *Stop the kconnpd. 234 | */ 235 | static void connpd_stop(void) 236 | { 237 | kthread_stop(CONNP_DAEMON_TSKP); 238 | } 239 | 240 | int connpd_init() 241 | { 242 | if (!connpd_close_pending_fds_init(NR_MAX_OPEN_FDS)) 243 | return 0; 244 | 245 | if (!connpd_unused_fds_init(NR_MAX_OPEN_FDS/2)) { 246 | connpd_close_pending_fds_destroy(); 247 | return 0; 248 | } 249 | 250 | if (!connpd_start()) 251 | return 0; 252 | 253 | return 1; 254 | } 255 | 256 | void connpd_destroy(void) 257 | { 258 | connpd_stop(); 259 | 260 | connpd_close_pending_fds_destroy(); 261 | connpd_unused_fds_destroy(); 262 | } 263 | -------------------------------------------------------------------------------- /hash.c: -------------------------------------------------------------------------------- 1 | #include "lkm_util.h" 2 | #include "hash.h" 3 | #include "cfg.h" 4 | 5 | #define INSERT_INTO_HLIST(p, hlist_head) \ 6 | do { \ 7 | (p)->prev = NULL; \ 8 | (p)->next = *(hlist_head); \ 9 | if (*(hlist_head)) \ 10 | (*(hlist_head))->prev = p; \ 11 | *(hlist_head) = p; \ 12 | } while (0) 13 | 14 | #define INSERT_INTO_TLIST(p, ht) \ 15 | do { \ 16 | if (!(ht)->trav_head) \ 17 | (ht)->trav_head = p; \ 18 | (p)->tnext = NULL; \ 19 | (p)->tprev = ht->trav_tail; \ 20 | if ((ht)->trav_tail) \ 21 | (ht)->trav_tail->tnext = p; \ 22 | (ht)->trav_tail = p; \ 23 | } while (0) 24 | 25 | 26 | #define INIT_KV(p, k, klen, v, vlen) \ 27 | do { \ 28 | (p)->hkey.key = lkmalloc(klen); \ 29 | if (!(p)->hkey.key) { \ 30 | lkmfree(p); \ 31 | return 0; \ 32 | } \ 33 | memcpy((p)->hkey.key, (k), klen); \ 34 | (p)->hkey.klen = klen; \ 35 | if (vlen) { \ 36 | (p)->hval.val = lkmalloc(vlen); \ 37 | if (!(p)->hval.val) { \ 38 | lkmfree((p)->hkey.key); \ 39 | lkmfree(p); \ 40 | return 0; \ 41 | } \ 42 | memcpy((p)->hval.val, (v), vlen); \ 43 | } else \ 44 | (p)->hval.val = v; \ 45 | (p)->hval.vlen = vlen; \ 46 | } while (0) 47 | 48 | #define UPDATE_VAL(ht, p, v, vlen) \ 49 | do { \ 50 | if ((ht)->dtor_func) \ 51 | (ht)->dtor_func((p)->hval.val); \ 52 | if (vlen) { \ 53 | (p)->hval.val = lkmalloc(vlen); \ 54 | if (!(p)->hval.val) \ 55 | return 0; \ 56 | memcpy((p)->hval.val, v, vlen); \ 57 | } else \ 58 | (p)->hval.val = v; \ 59 | (p)->hval.vlen = vlen; \ 60 | } while (0) 61 | 62 | static int hash_table_resize(struct hash_table_t *); 63 | static void hash_table_rehash(struct hash_table_t *); 64 | 65 | static int hash_table_resize(struct hash_table_t *ht) 66 | { 67 | struct hash_bucket_t **tmp; 68 | unsigned int htable_new_size = ht->table_size << 1; 69 | 70 | if (htable_new_size != 0) { //Prevent overflow. 71 | tmp = lkmalloc(htable_new_size * sizeof(struct hash_bucket_t *)); 72 | if (!tmp) { 73 | printk(KERN_ERR "No more memory in %s", __FUNCTION__); 74 | return 0; 75 | } 76 | lkmfree(ht->buckets); 77 | ht->buckets = tmp; 78 | ht->table_size = htable_new_size; 79 | ht->hash_mask = ht->table_size - 1; 80 | hash_table_rehash(ht); 81 | } 82 | 83 | return 1; 84 | } 85 | 86 | static void hash_table_rehash(struct hash_table_t *ht) 87 | { 88 | struct hash_bucket_t *p, **hlist_head; 89 | unsigned long h; 90 | unsigned int idx; 91 | 92 | for (p = ht->trav_head; p; p = p->tnext) { 93 | h = ht->hash_func(p->hkey.key, p->hkey.klen); 94 | idx = h & ht->hash_mask; 95 | hlist_head = &ht->buckets[idx]; 96 | INSERT_INTO_HLIST(p, hlist_head); 97 | } 98 | } 99 | 100 | int _hash_init(struct hash_table_t **ht_ptr, unsigned int tsize, 101 | hash_func_t hash_func, dtor_func_t dtor_func) 102 | { 103 | unsigned int i = 3; //1 << 3 104 | 105 | *ht_ptr = lkmalloc(sizeof(struct hash_table_t)); 106 | if (!*ht_ptr) 107 | return 0; 108 | 109 | if (tsize > 0x80000000) 110 | /*Prevent overflow*/ 111 | (*ht_ptr)->table_size = 0x80000000; 112 | else { 113 | while ((1U << i++) <= tsize); 114 | (*ht_ptr)->table_size = 1U << (i - 1); 115 | } 116 | 117 | (*ht_ptr)->buckets = lkmalloc((*ht_ptr)->table_size * sizeof(struct hash_bucket_t *)); 118 | if (!(*ht_ptr)->buckets) { 119 | lkmfree(*ht_ptr); 120 | *ht_ptr = NULL; 121 | return 0; 122 | } 123 | 124 | (*ht_ptr)->hash_mask = (*ht_ptr)->table_size - 1; //Table size mask 125 | (*ht_ptr)->elements_count = 0; 126 | (*ht_ptr)->hash_func = hash_func; 127 | (*ht_ptr)->dtor_func = dtor_func ? dtor_func : dtor_func_lkmfree; 128 | 129 | return 1; 130 | } 131 | 132 | int hash_add_or_set(struct hash_table_t *ht, 133 | const char *key, unsigned int klen, 134 | void *val, unsigned int vlen, 135 | hash_ops op) 136 | { 137 | struct hash_bucket_t *p, **hlist_head; 138 | unsigned long h; 139 | unsigned int idx; 140 | 141 | h = ht->hash_func(key, klen); 142 | 143 | idx = h & ht->hash_mask; 144 | 145 | p = ht->buckets[idx]; 146 | 147 | for (; p; p = p->next) { 148 | if (p->hkey.klen == klen && !memcmp(p->hkey.key, key, klen)) {//Match 149 | if (op == HASH_ADD) { 150 | return 0; 151 | } 152 | UPDATE_VAL(ht, p, val, vlen); 153 | return 1; 154 | } 155 | } 156 | 157 | p = lkmalloc(sizeof(struct hash_bucket_t)); 158 | if (!p) 159 | return 0; 160 | 161 | hlist_head = &ht->buckets[idx]; 162 | 163 | INIT_KV(p, key, klen, val, vlen); 164 | 165 | INSERT_INTO_HLIST(p, hlist_head); 166 | 167 | INSERT_INTO_TLIST(p, ht); 168 | 169 | ht->elements_count++; 170 | 171 | if (ht->elements_count > ht->table_size) 172 | hash_table_resize(ht); 173 | 174 | return 1; 175 | } 176 | 177 | int hash_find(struct hash_table_t *ht, 178 | const char *key, unsigned int klen, 179 | void **val) 180 | { 181 | struct hash_bucket_t *p; 182 | unsigned long h; 183 | unsigned int idx; 184 | 185 | h = ht->hash_func(key, klen); 186 | 187 | idx = h & ht->hash_mask; 188 | 189 | p = ht->buckets[idx]; 190 | 191 | for (; p; p = p->next) { 192 | if (p->hkey.klen == klen && !memcmp(p->hkey.key, key, klen)) { 193 | *val = (void *)p->hval.val; 194 | return 1; 195 | } 196 | } 197 | 198 | return 0; 199 | } 200 | 201 | int hash_destroy(struct hash_table_t **ht_ptr) 202 | { 203 | struct hash_bucket_t *p, *q; 204 | 205 | p = (*ht_ptr)->trav_head; 206 | 207 | while (p) { 208 | q = p->tnext; 209 | lkmfree(p->hkey.key); 210 | if ((*ht_ptr)->dtor_func) 211 | (*ht_ptr)->dtor_func(p->hval.val); 212 | lkmfree(p); 213 | p = q; 214 | } 215 | 216 | lkmfree((*ht_ptr)->buckets); 217 | 218 | lkmfree(*ht_ptr); 219 | 220 | *ht_ptr = NULL; 221 | 222 | return 1; 223 | } 224 | -------------------------------------------------------------------------------- /sys_call.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "sys_call_table.h" 3 | #include "sys_call.h" 4 | #include "lkm_util.h" 5 | 6 | /*original sys calls*/ 7 | #ifdef __NR_socketcall 8 | sys_socketcall_func_ptr_t orig_sys_socketcall = (void *)SYS_SOCKETCALL_EA; 9 | sys_send_func_ptr_t orig_sys_send = (void *)SYS_SEND_EA; 10 | sys_recv_func_ptr_t orig_sys_recv = (void *)SYS_RECV_EA; 11 | #endif 12 | 13 | sys_connect_func_ptr_t orig_sys_connect = (void *)SYS_CONNECT_EA; 14 | sys_shutdown_func_ptr_t orig_sys_shutdown = (void *)SYS_SHUTDOWN_EA; 15 | sys_close_func_ptr_t orig_sys_close = (void *)SYS_CLOSE_EA; 16 | sys_exit_func_ptr_t orig_sys_exit = (void *)SYS_EXIT_EA; 17 | sys_exit_func_ptr_t orig_sys_exit_group = (void *)SYS_EXIT_GROUP_EA; 18 | sys_write_func_ptr_t orig_sys_write = (void *)SYS_WRITE_EA; 19 | sys_read_func_ptr_t orig_sys_read = (void *)SYS_READ_EA; 20 | sys_sendto_func_ptr_t orig_sys_sendto = (void *)SYS_SENDTO_EA; 21 | sys_recvfrom_func_ptr_t orig_sys_recvfrom = (void *)SYS_RECVFROM_EA; 22 | sys_poll_func_ptr_t orig_sys_poll = (void *)SYS_POLL_EA; 23 | 24 | /*new sys calls*/ 25 | #ifdef __NR_socketcall 26 | static sys_socketcall_func_ptr_t new_sys_socketcall = connp_sys_socketcall; 27 | #else //__NR_connect and __NR_shutdown 28 | static sys_connect_func_ptr_t new_sys_connect = connp_sys_connect; 29 | static sys_shutdown_func_ptr_t new_sys_shutdown = connp_sys_shutdown; 30 | static sys_sendto_func_ptr_t new_sys_sendto = connp_sys_sendto; 31 | static sys_recvfrom_func_ptr_t new_sys_recvfrom = connp_sys_recvfrom; 32 | #endif 33 | 34 | static sys_close_func_ptr_t new_sys_close = connp_sys_close; 35 | static sys_exit_func_ptr_t new_sys_exit = connp_sys_exit; 36 | static sys_exit_func_ptr_t new_sys_exit_group = connp_sys_exit_group; 37 | static sys_write_func_ptr_t new_sys_write = connp_sys_write; 38 | static sys_read_func_ptr_t new_sys_read = connp_sys_read; 39 | static sys_poll_func_ptr_t new_sys_poll = connp_sys_poll; 40 | 41 | static int build_syscall_func_table(unsigned long *sys_call_table, int *nr_min, int *nr_max); 42 | 43 | static struct syscall_func_struct syscall_func[] = { //initial. 44 | #ifdef __NR_socketcall //usually for 32 bits. 45 | { 46 | .name = "sys_socketcall", 47 | .sym_addr = SYS_SOCKETCALL_EA, 48 | .real_addr = 0, 49 | .nr = -1, 50 | .new_sys_func = (void **)&new_sys_socketcall, 51 | .orig_sys_func = (void**)&orig_sys_socketcall 52 | }, 53 | #else 54 | { 55 | .name = "sys_connect", 56 | .sym_addr = SYS_CONNECT_EA, 57 | .real_addr = 0, 58 | .nr = -1, 59 | .new_sys_func = (void **)&new_sys_connect, 60 | .orig_sys_func = (void**)&orig_sys_connect 61 | }, 62 | { 63 | .name = "sys_shutdown", 64 | .sym_addr = SYS_SHUTDOWN_EA, 65 | .real_addr = 0, 66 | .nr = -1, 67 | .new_sys_func = (void **)&new_sys_shutdown, 68 | .orig_sys_func = (void **)&orig_sys_shutdown 69 | }, 70 | { 71 | .name = "sys_sendto", 72 | .sym_addr = SYS_SENDTO_EA, 73 | .real_addr = 0, 74 | .nr = -1, 75 | .new_sys_func = (void **)&new_sys_sendto, 76 | .orig_sys_func = (void **)&orig_sys_sendto 77 | }, 78 | { 79 | .name = "sys_recvfrom", 80 | .sym_addr = SYS_RECVFROM_EA, 81 | .real_addr = 0, 82 | .nr = -1, 83 | .new_sys_func = (void **)&new_sys_recvfrom, 84 | .orig_sys_func = (void **)&orig_sys_recvfrom 85 | }, 86 | 87 | #endif 88 | { 89 | .name = "sys_close", 90 | .sym_addr = SYS_CLOSE_EA, 91 | .real_addr = (unsigned long)sys_close, 92 | .nr = -1, 93 | .new_sys_func = (void **)&new_sys_close, 94 | .orig_sys_func = (void **)&orig_sys_close 95 | }, 96 | { 97 | .name = "sys_exit", 98 | .sym_addr = SYS_EXIT_EA, 99 | .real_addr = 0, 100 | .nr = -1, 101 | .new_sys_func = (void **)&new_sys_exit, 102 | .orig_sys_func = (void **)&orig_sys_exit 103 | }, 104 | { 105 | .name = "sys_exit_group", 106 | .sym_addr = SYS_EXIT_GROUP_EA, 107 | .real_addr = 0, 108 | .nr = -1, 109 | .new_sys_func = (void **)&new_sys_exit_group, 110 | .orig_sys_func = (void **)&orig_sys_exit_group 111 | }, 112 | { 113 | .name = "sys_write", 114 | .sym_addr = SYS_WRITE_EA, 115 | .real_addr = 0, 116 | .nr = -1, 117 | .new_sys_func = (void **)&new_sys_write, 118 | .orig_sys_func = (void **)&orig_sys_write 119 | }, 120 | { 121 | .name = "sys_read", 122 | .sym_addr = SYS_READ_EA, 123 | .real_addr = 0, 124 | .nr = -1, 125 | .new_sys_func = (void **)&new_sys_read, 126 | .orig_sys_func = (void **)&orig_sys_read 127 | }, 128 | { 129 | .name = "sys_poll", 130 | .sym_addr = SYS_POLL_EA, 131 | .real_addr = 0, 132 | .nr = -1, 133 | .new_sys_func = (void **)&new_sys_poll, 134 | .orig_sys_func = (void **)&orig_sys_poll 135 | }, 136 | 137 | {NULL, 0, 0, -1, NULL, NULL} //end tag. 138 | }; 139 | 140 | static int build_syscall_func_table(unsigned long *sys_call_table, int *nr_min, int *nr_max) 141 | { 142 | struct syscall_func_struct *p; 143 | int i; 144 | 145 | for (p = syscall_func; p->name; p++) { 146 | if (p->real_addr && (p->real_addr != p->sym_addr)) {//check symbol map addr. 147 | printk(KERN_ERR "Current kernel is ambiguous!"); 148 | return 0; 149 | } 150 | for (i = 0; i < MAX_SYS_CALL_NUM; i++) 151 | if (sys_call_table[i] == p->sym_addr) {//match the symbol map addr. 152 | p->nr = i; 153 | *p->orig_sys_func = (void *)sys_call_table[i]; //reassign. 154 | break; 155 | } 156 | 157 | if (i >= MAX_SYS_CALL_NUM) { 158 | printk(KERN_ERR "Can't find the sys call \"%s\", consider enlarging the macro MAX_SYS_CALL_NUM", p->name); 159 | return 0; 160 | } 161 | 162 | if (*nr_min > p->nr) 163 | *nr_min = p->nr; 164 | 165 | if (*nr_max < p->nr) 166 | *nr_max = p->nr; 167 | } 168 | 169 | return 1; 170 | } 171 | 172 | /** 173 | *@brief set syscall table. 174 | *@param flag: 0: replace 1: restore 175 | */ 176 | int connp_set_syscall(int flag) 177 | { 178 | struct syscall_func_struct *p; 179 | unsigned long * sys_call_table; 180 | static int sys_call_span_pages, nr_min, nr_max; 181 | 182 | *(unsigned long *)&sys_call_table = get_syscall_table_ea(); 183 | 184 | if (flag & SYSCALL_REPLACE) { //init. 185 | if (!build_syscall_func_table((unsigned long *)sys_call_table, 186 | &nr_min, &nr_max)) { 187 | return 0; 188 | } 189 | sys_call_span_pages = (((unsigned long)&sys_call_table[nr_max] >> PAGE_SHIFT) - ((unsigned long)&sys_call_table[nr_min] >> PAGE_SHIFT)) + 1; 190 | } 191 | 192 | preempt_disable(); 193 | 194 | page_protection_disable((unsigned long)&sys_call_table[nr_min], sys_call_span_pages); 195 | 196 | for (p = syscall_func; p->name; p++) { 197 | if (flag & SYSCALL_REPLACE) { //Replace 198 | xchg(&sys_call_table[p->nr], (unsigned long)*p->new_sys_func); 199 | printk(KERN_INFO "Replace %s: nr %d, addr %p", p->name, p->nr, *p->new_sys_func); 200 | } else if (flag & SYSCALL_RESTORE) { //Restore 201 | xchg(&sys_call_table[p->nr], (unsigned long)*p->orig_sys_func); 202 | printk(KERN_INFO "Restore %s: nr %d, addr %p", p->name, p->nr, *p->orig_sys_func); 203 | } 204 | } 205 | 206 | page_protection_enable((unsigned long)&sys_call_table[nr_min], sys_call_span_pages); 207 | 208 | preempt_enable(); 209 | 210 | return 1; 211 | } 212 | -------------------------------------------------------------------------------- /sys_socketcalls.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "sockp.h" 6 | #include "connp.h" 7 | #include "sys_call.h" 8 | #include "lkm_util.h" 9 | 10 | #ifdef __NR_socketcall /*32 bits*/ 11 | asmlinkage long connp_sys_socketcall(int call, unsigned long __user *args) 12 | { 13 | unsigned long a[6]; 14 | int err; 15 | 16 | switch(call) { 17 | case SYS_CONNECT: 18 | if (copy_from_user(a, args, 3 * sizeof(a[0]))) { 19 | printk(KERN_ERR "connect Efault!\n"); 20 | return -EFAULT; 21 | } 22 | err = socketcall_sys_connect(a[0], (struct sockaddr __user *)a[1], a[2]); 23 | if (err > 0) 24 | goto orig_sys_socketcall; 25 | break; 26 | 27 | case SYS_SHUTDOWN: 28 | if (copy_from_user(a, args, 2 * sizeof(a[0]))){ 29 | printk(KERN_ERR "shutdown Efault!\n"); 30 | return -EFAULT; 31 | } 32 | err = socketcall_sys_shutdown(a[0], a[1]); 33 | if (err) 34 | goto orig_sys_socketcall; 35 | break; 36 | 37 | case SYS_SEND: 38 | if (copy_from_user(a, args, 4 * sizeof(a[0]))) { 39 | printk(KERN_ERR "send Efault!\n"); 40 | return -EFAULT; 41 | } 42 | err = socketcall_sys_send(a[0], (void __user *)a[1], a[2], a[3]); 43 | if (!err) 44 | goto orig_sys_socketcall; 45 | break; 46 | 47 | case SYS_SENDTO: 48 | if (copy_from_user(a, args, 6 * sizeof(a[0]))) { 49 | printk(KERN_ERR "sendto Efault!\n"); 50 | return -EFAULT; 51 | } 52 | err = socketcall_sys_sendto(a[0], (void __user *)a[1], a[2], a[3], 53 | (struct sockaddr __user *)a[4], a[5]); 54 | if (!err) 55 | goto orig_sys_socketcall; 56 | break; 57 | 58 | case SYS_RECV: 59 | if (copy_from_user(a, args, 4 * sizeof(a[0]))) { 60 | printk(KERN_ERR "recv Efault!\n"); 61 | return -EFAULT; 62 | } 63 | err = socketcall_sys_recv(a[0], (void __user *)a[1], a[2], a[3]); 64 | if (!err) 65 | goto orig_sys_socketcall; 66 | break; 67 | 68 | case SYS_RECVFROM: 69 | if (copy_from_user(a, args, 6 * sizeof(a[0]))) { 70 | printk(KERN_ERR "recvfrom Efault!\n"); 71 | return -EFAULT; 72 | } 73 | err = socketcall_sys_recvfrom(a[0], (void __user *)a[1], a[2], a[3], 74 | (struct sockaddr __user *)a[4], (int *)a[5]); 75 | if (!err) 76 | goto orig_sys_socketcall; 77 | break; 78 | 79 | default: 80 | orig_sys_socketcall: 81 | __asm__ __volatile__("leave\n\t" 82 | "jmp *%0" 83 | : 84 | :"m"(orig_sys_socketcall)); 85 | return 0;//dummy 86 | break; 87 | } 88 | 89 | return err; 90 | } 91 | 92 | asmlinkage long socketcall_sys_send(int sockfd, const void __user *buf, size_t len, int flags) 93 | { 94 | if (check_if_ignore_primitives(sockfd, buf, len)) 95 | return len; 96 | 97 | { 98 | long cnt = check_if_ignore_auth_procedure(sockfd, buf, len, 'w'); 99 | if (cnt) 100 | return cnt; 101 | } 102 | 103 | return 0; 104 | } 105 | 106 | asmlinkage long socketcall_sys_recv(int sockfd, const void __user *buf, size_t len, int flags) 107 | { 108 | long cnt = check_if_ignore_auth_procedure(sockfd, buf, len, 'r'); 109 | if (cnt) 110 | return cnt; 111 | 112 | return 0; 113 | } 114 | 115 | #else /*b4bits*/ 116 | 117 | asmlinkage long connp_sys_connect(int fd, 118 | struct sockaddr __user * uservaddr, int addrlen) 119 | { 120 | int err; 121 | err = socketcall_sys_connect(fd, uservaddr, addrlen); 122 | if (err <= 0) 123 | return err; 124 | 125 | return orig_sys_connect(fd, uservaddr, addrlen); 126 | } 127 | 128 | asmlinkage long connp_sys_shutdown(int fd, int way) 129 | { 130 | int err; 131 | err = socketcall_sys_shutdown(fd, way); 132 | if (!err) 133 | return 0; 134 | 135 | return orig_sys_shutdown(fd, way); 136 | } 137 | 138 | asmlinkage long connp_sys_sendto(int sockfd, const void __user *buf, size_t len, 139 | int flags, const struct sockaddr __user *dest_addr, int addrlen) 140 | { 141 | int err; 142 | err = socketcall_sys_sendto(sockfd, buf, len, flags, dest_addr, addrlen); 143 | if (err) 144 | return err; 145 | 146 | return orig_sys_sendto(sockfd, buf, len, flags, dest_addr, addrlen); 147 | } 148 | 149 | asmlinkage ssize_t connp_sys_recvfrom(int sockfd, const void __user *buf, size_t len, 150 | int flags, const struct sockaddr __user *src_addr, int *addrlen) 151 | { 152 | int err; 153 | err = socketcall_sys_recvfrom(sockfd, buf, len, flags, src_addr, addrlen); 154 | if (err) 155 | return err; 156 | 157 | return orig_sys_recvfrom(sockfd, buf, len, flags, src_addr, addrlen); 158 | } 159 | #endif 160 | 161 | int socketcall_move_addr_to_kernel(void __user *uaddr, int ulen, 162 | struct sockaddr *kaddr) 163 | { 164 | if (ulen < 0 || ulen > sizeof(struct sockaddr_storage)) 165 | return -EINVAL; 166 | 167 | if (ulen == 0) 168 | return 1; 169 | 170 | if (copy_from_user(kaddr, uaddr, ulen)){ 171 | printk(KERN_ERR "move to kernel copy data EFAULT;\n"); 172 | return -EFAULT; 173 | } 174 | 175 | return 0; 176 | } 177 | 178 | long socketcall_sys_connect(int fd, 179 | struct sockaddr __user * uservaddr, int addrlen) 180 | { 181 | struct sockaddr_storage servaddr; 182 | int err; 183 | 184 | err = socketcall_move_addr_to_kernel(uservaddr, addrlen, (struct sockaddr *)&servaddr); 185 | if (err < 0) 186 | return err; 187 | 188 | if ((err = fetch_conn_from_connp(fd, (struct sockaddr *)&servaddr))) { 189 | if (err == CONN_BLOCK) 190 | return 0; 191 | else if (err == CONN_NONBLOCK) 192 | return -EINPROGRESS; 193 | } 194 | 195 | return 1; 196 | } 197 | 198 | long socketcall_sys_shutdown(int fd, int way) 199 | { 200 | if (connp_fd_allowed(fd)) 201 | return 0; 202 | 203 | return 1; 204 | } 205 | 206 | long socketcall_sys_sendto(int sockfd, const void __user *buf, size_t len, 207 | int flags, const struct sockaddr __user *dest_addr, int addrlen) 208 | { 209 | if (check_if_ignore_primitives(sockfd, buf, len)) 210 | return len; 211 | 212 | { 213 | long cnt = check_if_ignore_auth_procedure(sockfd, buf, len, 'w'); 214 | if (cnt) 215 | return cnt; 216 | } 217 | 218 | return 0; 219 | } 220 | 221 | ssize_t socketcall_sys_recvfrom(int sockfd, const void __user *buf, size_t len, 222 | int flags, const struct sockaddr __user *src_addr, int *addrlen) 223 | { 224 | long cnt = check_if_ignore_auth_procedure(sockfd, buf, len, 'r'); 225 | if (cnt) 226 | return cnt; 227 | return 0; 228 | } 229 | 230 | asmlinkage ssize_t connp_sys_write(int fd, const char __user *buf, size_t count) 231 | { 232 | if (check_if_ignore_primitives(fd, buf, count)) 233 | return count; 234 | { 235 | long cnt = check_if_ignore_auth_procedure(fd, buf, count, 'w'); 236 | if (cnt) 237 | return cnt; 238 | } 239 | 240 | return orig_sys_write(fd, buf, count); 241 | } 242 | 243 | asmlinkage ssize_t connp_sys_read(int fd, const char __user *buf, size_t count) 244 | { 245 | long cnt; 246 | cnt = check_if_ignore_auth_procedure(fd, buf, count, 'r'); 247 | if (cnt) 248 | return cnt; 249 | 250 | return orig_sys_read(fd, buf, count); 251 | } 252 | -------------------------------------------------------------------------------- /lkm_util.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "sys_call.h" 5 | #include "array.h" 6 | #include "lkm_util.h" 7 | 8 | unsigned long lkm_copy_from_user(void *to, const void __user *from, unsigned len) 9 | { 10 | return copy_from_user(to, from, len); 11 | } 12 | 13 | /* Poll funcs start */ 14 | struct poll_table_entry_alias { 15 | struct file *filp; 16 | unsigned long key; 17 | wait_queue_t wait; 18 | wait_queue_head_t *wait_address; 19 | }; 20 | 21 | struct poll_wqueues_alias { 22 | poll_table pt; 23 | struct poll_table_page *table; 24 | struct task_struct *polling_task; 25 | int triggered; 26 | int error; 27 | int inline_index; 28 | struct poll_table_entry_alias inline_entries[N_INLINE_POLL_ENTRIES]; 29 | }; 30 | 31 | struct poll_table_page { 32 | struct poll_table_page *next; 33 | struct poll_table_entry_alias *entry; 34 | struct poll_table_entry_alias entries[0]; 35 | }; 36 | 37 | #define POLL_TABLE_FULL(table) \ 38 | ((unsigned long)((table)->entry+1) > PAGE_SIZE + (unsigned long)(table)) 39 | 40 | static void __pollwait(struct file *filp, wait_queue_head_t *wait_address, 41 | poll_table *p); 42 | 43 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) 44 | 45 | static inline void set_pt_key(poll_table *pt, int events) 46 | { 47 | #if LINUX_VERSION_CODE <= KERNEL_VERSION(3, 2, 45) 48 | pt->key = events; 49 | #else 50 | pt->_key = events; 51 | #endif 52 | } 53 | 54 | #endif 55 | 56 | #undef DEFAULT_POLLMASK 57 | #define DEFAULT_POLLMASK (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM) 58 | 59 | static int inline do_poll(struct pollfd_ex_t *pfdt, poll_table *pwait) 60 | { 61 | unsigned int mask; 62 | int events; 63 | int fd; 64 | struct pollfd *pfd; 65 | 66 | pfd = &pfdt->pollfd; 67 | 68 | fd = pfd->fd; 69 | events = pfd->events; 70 | mask = 0; 71 | if (fd >= 0) { 72 | struct file * file; 73 | struct pollfd_ex_t *pfdt; 74 | 75 | file = lkm_get_file(fd); /*Needn't add f_count*/ 76 | 77 | mask = POLLNVAL; 78 | 79 | if (file != NULL) { 80 | mask = DEFAULT_POLLMASK; 81 | 82 | events = events|POLLERR|POLLHUP; 83 | 84 | if (file->f_op && file->f_op->poll) { 85 | 86 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) 87 | if (pwait) 88 | set_pt_key(pwait, events); 89 | #endif 90 | 91 | pfdt = container_of(pfd, struct pollfd_ex_t, pollfd); 92 | 93 | if (pfdt->data && pfdt->poll_func) 94 | mask = pfdt->poll_func(pfdt->data, pwait); 95 | else 96 | mask = file->f_op->poll(file, pwait); 97 | } 98 | 99 | /* Mask out unneeded events. */ 100 | mask &= events; 101 | } 102 | } 103 | 104 | return mask; 105 | } 106 | 107 | static void lkm_poll_initwait(struct poll_wqueues_alias *pwq) 108 | { 109 | init_poll_funcptr(&pwq->pt, __pollwait); 110 | pwq->error = 0; 111 | pwq->table = NULL; 112 | pwq->inline_index = 0; 113 | pwq->polling_task = current; 114 | pwq->triggered = 0; 115 | } 116 | 117 | static inline void free_poll_entry(struct poll_table_entry_alias *entry) 118 | { 119 | remove_wait_queue(entry->wait_address, &entry->wait); 120 | } 121 | 122 | static void lkm_poll_freewait(struct poll_wqueues_alias *pwq) 123 | { 124 | struct poll_table_page *p = pwq->table; 125 | int i; 126 | 127 | for (i = 0; i < pwq->inline_index; i++) 128 | free_poll_entry(pwq->inline_entries + i); 129 | 130 | while (p) { 131 | struct poll_table_entry_alias * entry; 132 | struct poll_table_page *old; 133 | 134 | entry = p->entry; 135 | do { 136 | entry--; 137 | free_poll_entry(entry); 138 | } while (entry > p->entries); 139 | old = p; 140 | p = p->next; 141 | free_page((unsigned long) old); 142 | } 143 | } 144 | 145 | static struct poll_table_entry_alias *poll_get_entry(struct poll_wqueues_alias *p) 146 | { 147 | struct poll_table_page *table = p->table; 148 | 149 | if (p->inline_index < N_INLINE_POLL_ENTRIES) 150 | return p->inline_entries + p->inline_index++; 151 | 152 | if (!table || POLL_TABLE_FULL(table)) { 153 | struct poll_table_page *new_table; 154 | 155 | new_table = (struct poll_table_page *) __get_free_page(GFP_ATOMIC); 156 | if (!new_table) { 157 | p->error = -ENOMEM; 158 | return NULL; 159 | } 160 | new_table->entry = new_table->entries; 161 | new_table->next = table; 162 | p->table = new_table; 163 | table = new_table; 164 | } 165 | 166 | return table->entry++; 167 | } 168 | 169 | static int __pollwake(wait_queue_t *wait, unsigned mode, int sync, void *key) 170 | { 171 | struct poll_wqueues_alias *pwq = wait->private; 172 | DECLARE_WAITQUEUE(dummy_wait, pwq->polling_task); 173 | 174 | smp_wmb(); 175 | pwq->triggered = 1; 176 | 177 | return default_wake_function(&dummy_wait, mode, sync, key); 178 | } 179 | 180 | static int pollwake(wait_queue_t *wait, unsigned mode, int sync, void *key) 181 | { 182 | struct poll_table_entry_alias *entry; 183 | 184 | entry = container_of(wait, struct poll_table_entry_alias, wait); 185 | if (key && !((unsigned long)key & entry->key)) 186 | return 0; 187 | 188 | return __pollwake(wait, mode, sync, key); 189 | } 190 | 191 | /* Add a new entry */ 192 | static void __pollwait(struct file *filp, 193 | wait_queue_head_t *wait_address, poll_table *p) 194 | { 195 | struct poll_wqueues_alias *pwq = container_of(p, struct poll_wqueues_alias, pt); 196 | struct poll_table_entry_alias *entry = poll_get_entry(pwq); 197 | 198 | if (!entry) 199 | return; 200 | 201 | entry->filp = filp; 202 | entry->wait_address = wait_address; 203 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) 204 | #if LINUX_VERSION_CODE <= KERNEL_VERSION(3, 2, 45) 205 | entry->key = p->key; 206 | #else 207 | entry->key = p->_key; 208 | #endif 209 | #endif 210 | 211 | init_waitqueue_func_entry(&entry->wait, pollwake); 212 | entry->wait.private = pwq; 213 | 214 | add_wait_queue(wait_address, &entry->wait); 215 | } 216 | 217 | int lkm_poll(array_t *pfdt_list, int timeo) 218 | { 219 | struct poll_wqueues_alias table; 220 | poll_table *pt; 221 | int count = 0; 222 | int timed_out = 0; 223 | long __timeout = timeo * HZ; 224 | 225 | lkm_poll_initwait(&table); 226 | pt = &(&table)->pt; 227 | for (;;) { 228 | int idx; 229 | 230 | if (!(pfdt_list)) 231 | goto ignore_poll; 232 | 233 | for (idx = 0; idx < (pfdt_list)->elements; idx++) { 234 | struct pollfd_ex_t *pfdt; 235 | struct pollfd *pfd; 236 | 237 | pfdt = (struct pollfd_ex_t *)(pfdt_list)->get(pfdt_list, idx); 238 | 239 | pfd = (struct pollfd *)&pfdt->pollfd; 240 | 241 | pfd->revents = do_poll(pfdt, pt); 242 | 243 | if (pfd->revents) { 244 | 245 | count++; 246 | pt = NULL; 247 | 248 | } 249 | 250 | } 251 | 252 | ignore_poll: 253 | 254 | pt = NULL; 255 | 256 | if (!count) { 257 | if (signal_pending(current)) { 258 | count = -EINTR; 259 | flush_signals(current); 260 | } 261 | } 262 | 263 | if (count || timed_out) 264 | break; 265 | 266 | __timeout = wait_for_sig_or_timeout(__timeout); 267 | if (!__timeout) 268 | timed_out = 1; 269 | } 270 | 271 | lkm_poll_freewait(&table); 272 | 273 | return count; 274 | } 275 | /* Poll funcs END */ 276 | 277 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 10) 278 | static int sock_map_fd(struct socket *sock, int flags) 279 | { 280 | struct file *newfile; 281 | int fd; 282 | 283 | fd = get_unused_fd_flags(flags); 284 | if (unlikely(fd < 0)) 285 | return fd; 286 | 287 | newfile = sock_alloc_file(sock, flags, NULL); 288 | if (likely(!IS_ERR(newfile))) { 289 | fd_install(fd, newfile); 290 | return fd; 291 | } 292 | 293 | put_unused_fd(fd); 294 | return PTR_ERR(newfile); 295 | } 296 | #endif 297 | 298 | int lkm_create_tcp_connect(struct sockaddr_in *address) 299 | { 300 | int fd; 301 | struct socket *sock; 302 | int err; 303 | 304 | fd = sock_create(address->sin_family, SOCK_STREAM, 0, &sock); 305 | if (fd < 0) 306 | return fd; 307 | 308 | #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 26) 309 | fd = sock_map_fd(sock); 310 | #else 311 | fd = sock_map_fd(sock, 0); 312 | #endif 313 | if (fd < 0) { 314 | sock_release(sock); 315 | return fd; 316 | } 317 | 318 | sock->file->f_flags |= O_NONBLOCK; 319 | 320 | err = sock->ops->connect(sock, (struct sockaddr *)address, 321 | sizeof(struct sockaddr), sock->file->f_flags); 322 | 323 | SET_CLIENT_FLAG(sock); 324 | 325 | return fd; 326 | } 327 | -------------------------------------------------------------------------------- /auth.c: -------------------------------------------------------------------------------- 1 | #include "auth.h" 2 | #include "sockp.h" 3 | #include "cfg.h" 4 | #include "sys_call.h" 5 | 6 | #define INSERT_INTO_AUTH_PROCEDURE(sb, auth_stage) \ 7 | do { \ 8 | if (!(sb)->auth_procedure_head) \ 9 | (sb)->auth_procedure_head = auth_stage; \ 10 | if ((sb)->auth_procedure_tail) \ 11 | (sb)->auth_procedure_tail->next = auth_stage; \ 12 | (sb)->auth_procedure_tail = auth_stage; \ 13 | } while (0); 14 | 15 | int check_if_ignore_auth_procedure(int fd, const char __user *buf, size_t len, 16 | char io_type) 17 | { 18 | struct socket_bucket *sb; 19 | struct socket *sock; 20 | struct sockaddr cliaddr; 21 | struct sockaddr servaddr; 22 | int ret = 0; 23 | 24 | /*ACL check start*/ 25 | 26 | if (!is_sock_fd(fd)) 27 | return 0; 28 | 29 | sock = getsock(fd); 30 | if (!sock 31 | || !IS_TCP_SOCK(sock) 32 | || !IS_CLIENT_SOCK(sock)) 33 | return 0; 34 | 35 | if (!getsockcliaddr(sock, &cliaddr) || !IS_IPV4_SA(&cliaddr)) 36 | return 0; 37 | 38 | if (!getsockservaddr(sock, &servaddr) || !IS_IPV4_SA(&servaddr)) 39 | return 0; 40 | 41 | if (!cfg_conn_acl_allowed(&servaddr)) 42 | return 0; 43 | 44 | /*ACL check end*/ 45 | 46 | 47 | if (!(sb = get_auth_sb(sock->sk))) 48 | return 0; 49 | 50 | 51 | if (sb->auth_procedure_status == AUTH_FAIL) 52 | return 0; 53 | 54 | if (sb->auth_procedure_head && !sb->auth_procedure_stage) 55 | return 0; 56 | 57 | if (sb->cfg_generation != cfg->auth_generation 58 | && sb->auth_procedure_status != AUTH_SUCCESS) { 59 | sb->auth_procedure_status = AUTH_FAIL; 60 | return 0; 61 | } 62 | 63 | if (io_type == 'i') { 64 | if (sb->auth_procedure_status == AUTH_SUCCESS) 65 | return POLLIN; 66 | else 67 | return 0; 68 | } 69 | 70 | //printk(KERN_ERR "debug io_type entry: %d", io_type); 71 | 72 | if (sb->auth_procedure_status == AUTH_PROCESSING) { 73 | struct conn_node_t *conn_node = cfg_conn_get_node(&servaddr); 74 | if (!conn_node) 75 | return 0; 76 | if (!sb->auth_procedure_stage) { 77 | struct auth_stage *cfg_auth_procedure = NULL; 78 | if (conn_node->auth_node) 79 | cfg_auth_procedure = conn_node->auth_node->data; 80 | 81 | if (!cfg_auth_procedure) { 82 | sb->auth_procedure_status = AUTH_FAIL; 83 | return 0; 84 | } 85 | 86 | sb->auth_procedure_stage = cfg_auth_procedure; 87 | } 88 | 89 | if (!sb->auth_procedure_stage || sb->auth_procedure_stage->type != io_type) { 90 | printk(KERN_ERR "debug sb-type: %d, io_type: %d", sb->auth_procedure_stage->type, io_type); 91 | printk(KERN_ERR "Auth procedure (service: %s) is not corresponding!", conn_node->conn_sn.data); 92 | sb->auth_procedure_status = AUTH_FAIL; 93 | return 0; 94 | } 95 | 96 | if (io_type == 'r') { //read 97 | unsigned int count; 98 | count = orig_sys_read(fd, buf, len); 99 | if (count) { 100 | struct auth_stage *auth_stage; 101 | auth_stage = lkmalloc(sizeof(*auth_stage)); 102 | if (!auth_stage) { 103 | printk(KERN_ERR "No more memory!"); 104 | sb->auth_procedure_status = AUTH_FAIL; 105 | return 0; 106 | } 107 | auth_stage->type = 'r'; 108 | auth_stage->info.data = lkmalloc(count); 109 | if (!auth_stage->info.data) { 110 | printk(KERN_ERR "No more memory!"); 111 | sb->auth_procedure_status = AUTH_FAIL; 112 | lkmfree(auth_stage); 113 | return 0; 114 | } 115 | if (copy_from_user(auth_stage->info.data, buf, count) 116 | || (sb->auth_procedure_stage->info.len 117 | && memcmp(auth_stage->info.data, sb->auth_procedure_stage->info.data, sb->auth_procedure_stage->info.len))) { 118 | printk(KERN_ERR "Copy mem error or auth procedure const data is not correct! count: %d, len: %d", count, sb->auth_procedure_stage->info.len); 119 | sb->auth_procedure_status = AUTH_FAIL; 120 | lkmfree(auth_stage->info.data); 121 | lkmfree(auth_stage); 122 | return 0; 123 | } /*else 124 | printk(KERN_ERR "Corresponding\n");*/ 125 | 126 | auth_stage->info.len = count; 127 | 128 | INSERT_INTO_AUTH_PROCEDURE(sb, auth_stage); 129 | 130 | ret = count; 131 | goto out_auth_processing; 132 | } 133 | } else { //'w' 134 | struct auth_stage *auth_stage; 135 | auth_stage = lkmalloc(sizeof(*auth_stage)); 136 | if (!auth_stage) { 137 | printk(KERN_ERR "No more memory!"); 138 | sb->auth_procedure_status = AUTH_FAIL; 139 | return 0; 140 | } 141 | 142 | auth_stage->type = 'w'; 143 | auth_stage->info.data = lkmalloc(len); 144 | if (!auth_stage->info.data) { 145 | printk(KERN_ERR "No more memory!"); 146 | sb->auth_procedure_status = AUTH_FAIL; 147 | lkmfree(auth_stage); 148 | return 0; 149 | } 150 | if (!copy_from_user(auth_stage->info.data, buf, len)) { 151 | auth_stage->info.len = len; 152 | INSERT_INTO_AUTH_PROCEDURE(sb, auth_stage); 153 | ret = 0; 154 | goto out_auth_processing; 155 | } else { 156 | sb->auth_procedure_status = AUTH_FAIL; 157 | lkmfree(auth_stage->info.data); 158 | lkmfree(auth_stage); 159 | return 0; 160 | } 161 | } 162 | 163 | out_auth_processing: 164 | 165 | if (!sb->auth_procedure_stage->next) //last procedure step. 166 | sb->auth_procedure_status = AUTH_SUCCESS; 167 | 168 | sb->auth_procedure_stage = sb->auth_procedure_stage->next; 169 | 170 | return ret; 171 | 172 | } else if (sb->auth_procedure_status == AUTH_SUCCESS) { 173 | if (!sb->auth_procedure_head) { 174 | printk(KERN_ERR "Auth procedure is not exists!"); 175 | return 0; 176 | } 177 | 178 | if (!sb->auth_procedure_stage) { 179 | printk(KERN_ERR "Auth procedure head is not set!"); 180 | return 0; 181 | } 182 | 183 | if (sb->auth_procedure_stage->type != io_type) { 184 | printk(KERN_ERR "Auth procedure is not corresponding!"); 185 | return 0; 186 | } 187 | 188 | if (io_type == 'r') { 189 | if (!sb->auth_procedure_stage->info.len) { 190 | printk(KERN_ERR "Auth procedure data for reading is empty!"); 191 | return 0; 192 | } 193 | 194 | //printk(KERN_ERR "user len: %d, info_len: %d\n", len, sb->auth_procedure_stage->info.len); 195 | if (copy_to_user((void *)buf, sb->auth_procedure_stage->info.data, sb->auth_procedure_stage->info.len)) { 196 | printk(KERN_ERR "Auth procedure copy data error!"); 197 | return 0; 198 | } 199 | 200 | ret = sb->auth_procedure_stage->info.len; 201 | goto out_auth_success; 202 | } else {//'w' 203 | /* 204 | kconnp_str_t str; 205 | str.data = lkmalloc(len); 206 | if (!str.data) { 207 | printk(KERN_ERR "No more memory!"); 208 | return 0; 209 | } 210 | 211 | if (copy_from_user(str.data, buf, len)) { 212 | printk(KERN_ERR "Auth procedure copy data error!"); 213 | lkmfree(str.data); 214 | return 0; 215 | } 216 | 217 | if (len != sb->auth_procedure_stage->info.len 218 | || memcmp(str.data, sb->auth_procedure_stage->info.data, len)) { 219 | int i = 0; 220 | printk(KERN_INFO "Auth procedure data for writing is not corresponding! len: %d, info-len: %d", len, sb->auth_procedure_stage->info.len); 221 | while (i < len) { 222 | printk(KERN_ERR "str-data: %d\n", str.data[i]); 223 | printk(KERN_ERR "auth_procedure_stage-data: %d\n", sb->auth_procedure_stage->info.data[i]); 224 | if (str.data[i] != sb->auth_procedure_stage->info.data[i]) { 225 | printk(KERN_ERR "writing data is not coresponding!i:%d", i); 226 | } 227 | i++; 228 | } 229 | } 230 | 231 | lkmfree(str.data); 232 | */ 233 | ret = len; 234 | goto out_auth_success; 235 | } 236 | 237 | out_auth_success: 238 | sb->auth_procedure_stage = sb->auth_procedure_stage->next; 239 | return ret; 240 | } 241 | 242 | return 0; 243 | } 244 | -------------------------------------------------------------------------------- /cfg.h: -------------------------------------------------------------------------------- 1 | #ifndef CFG_H 2 | #define CFG_H 3 | 4 | #include 5 | #include 6 | #include "connp.h" 7 | #include "hash.h" 8 | #include "kconnp.h" 9 | #include "auth.h" 10 | 11 | #define CFG_BASE_DIR_NAME "kconnp" 12 | 13 | struct cfg_entry { 14 | /*attributes*/ 15 | char *f_name; /*cfg file name*/ 16 | struct proc_dir_entry *cfg_proc_file; 17 | unsigned int raw_len; /*the data length read from the procfile*/ 18 | char *raw_ptr; /*cfg raw data pointer*/ 19 | void *cfg_ptr; /*handle the cfg storage*/ 20 | time_t mtime; /*modify time*/ 21 | unsigned int generation; /*increase the generation after reloading the cfg.*/ 22 | rwlock_t cfg_rwlock; 23 | 24 | /*proc r/w funcs*/ 25 | #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0) 26 | int (*proc_read)(char __user *buffer, char **buffer_location, off_t offset, 27 | int buffer_length, int *eof, void *data); 28 | int (*proc_write)(struct file *file, const char __user *buffer, unsigned long count, 29 | void *data); 30 | #else 31 | struct file_operations *proc_fops; 32 | int (*proc_read)(struct seq_file *seq, void *offset); 33 | ssize_t (*proc_write)(struct file *file, const char __user *buffer, size_t count, 34 | loff_t *pos); 35 | #endif 36 | 37 | /*cfg funcs*/ 38 | int (*init)(struct cfg_entry *); 39 | void (*destroy)(struct cfg_entry *); 40 | 41 | int (*proc_file_init)(struct cfg_entry *); 42 | void (*proc_file_destroy)(struct cfg_entry *); 43 | 44 | int (*entity_init)(struct cfg_entry *); 45 | void (*entity_destroy)(struct cfg_entry *); 46 | int (*entity_reload)(struct cfg_entry *); 47 | }; 48 | 49 | struct cfg_dir { 50 | struct cfg_entry global; 51 | #define gl global 52 | #define gl_ptr global.cfg_ptr 53 | #define gl_rwlock global.cfg_rwlock 54 | struct cfg_entry allowed_list; 55 | #define al allowed_list 56 | #define al_ptr allowed_list.cfg_ptr 57 | #define al_rwlock allowed_list.cfg_rwlock 58 | struct cfg_entry denied_list; 59 | #define dl denied_list 60 | #define dl_ptr denied_list.cfg_ptr 61 | #define dl_rwlock denied_list.cfg_rwlock 62 | struct cfg_entry prim_list; 63 | #define pl prim_list 64 | #define pl_ptr prim_list.cfg_ptr 65 | #define pl_rwlock prim_list.cfg_rwlock 66 | struct cfg_entry auth; 67 | #define auth_generation auth.generation 68 | #define auth_ptr auth.cfg_ptr 69 | #define auth_rwlock auth.cfg_rwlock 70 | struct cfg_entry stats_info; 71 | #define st stats_info 72 | #define st_ptr stats_info.raw_ptr 73 | #define st_len stats_info.raw_len 74 | #define st_rwlock stats_info.cfg_rwlock 75 | }; 76 | 77 | extern struct cfg_dir *cfg; 78 | 79 | typedef struct pos { //start and end pos 80 | int start; 81 | int end; 82 | } pos_t; 83 | 84 | struct item_str_t { 85 | int line; //the line NO! where the cfg item located in the global cfg proc file. 86 | 87 | kconnp_str_t name; 88 | kconnp_str_t value; 89 | 90 | struct item_str_t *next; 91 | }; 92 | 93 | struct items_str_list_t { 94 | struct item_str_t *list; 95 | struct item_str_t *tail; 96 | int count; 97 | }; 98 | 99 | struct item_pos_t { 100 | pos_t name_pos; 101 | #define name_start name_pos.start 102 | #define name_end name_pos.end 103 | pos_t value_pos; 104 | #define value_start value_pos.start 105 | #define value_end value_pos.end 106 | }; 107 | 108 | typedef enum { 109 | INTEGER = 1, 110 | STRING 111 | } node_type; 112 | 113 | struct item_node_t { 114 | //item node 115 | kconnp_str_t name; 116 | 117 | kconnp_value_t value; 118 | #define v_strlen value.str.len 119 | #define v_str value.str.data 120 | #define v_lval value.lval 121 | 122 | void *data; 123 | 124 | int (*cfg_item_set_node)(struct item_node_t *node, kconnp_str_t *str); 125 | }; 126 | 127 | #define MAX_PRIMITIVE_LEN 64 128 | #define MAX_AUTH_PROCEDURE_LEN 128 129 | #define MAX_AUTH_PROCEDURE_PART_LEN 32 130 | #define MAX_SN_PADDING_ZERO_LEN 33 /*real max length is (MAX_SN_PADDING_NULL_LEN - 1)*/ 131 | struct iport_t { 132 | //Ip and port must be first elements 133 | unsigned int ip; 134 | unsigned short int port; 135 | unsigned int flags; 136 | struct { 137 | char data[MAX_SN_PADDING_ZERO_LEN]; 138 | unsigned int len; 139 | } sn; 140 | }; 141 | 142 | struct iport_raw_t { 143 | unsigned int ip; 144 | unsigned short int port; 145 | }; 146 | 147 | struct conn_node_t { 148 | struct iport_t iport_node; 149 | #define conn_ip iport_node.ip 150 | #define conn_port iport_node.port 151 | #define conn_flags iport_node.flags 152 | #define conn_sn iport_node.sn 153 | 154 | /*direct access*/ 155 | struct item_node_t *prim_node; 156 | struct item_node_t *auth_node; 157 | 158 | struct conn_attr_t conn_attrs; 159 | #define conn_close_way conn_attrs.close_way_attrs.close_way 160 | #define conn_close_way_last_set_jiffies conn_attrs.close_way_attrs.last_set_jiffies 161 | #define conn_keep_alive conn_attrs.keep_alive 162 | #define conn_close_now conn_attrs.close_now 163 | #define conn_all_count conn_attrs.stats.all_count 164 | #define conn_idle_count conn_attrs.stats.idle_count 165 | #define conn_connected_hit_count conn_attrs.stats.connected_hit_count 166 | #define conn_connected_miss_count conn_attrs.stats.connected_miss_count 167 | }; 168 | 169 | struct iport_str_t { 170 | int line; //the line NO! where the iport located in the cfg proc file. 171 | 172 | char *sn_str; 173 | char *ip_str; 174 | char *port_str; 175 | char *flags_str; 176 | 177 | struct iport_str_t *next; 178 | }; 179 | 180 | struct iports_str_list_t { 181 | struct iport_str_t *list; 182 | struct iport_str_t *tail; 183 | int count; 184 | }; 185 | 186 | struct iport_pos_t { 187 | pos_t sn_pos; 188 | #define sn_start sn_pos.start 189 | #define sn_end sn_pos.end 190 | pos_t ip_pos; 191 | #define ip_start ip_pos.start 192 | #define ip_end ip_pos.end 193 | pos_t port_pos; 194 | #define port_start port_pos.start 195 | #define port_end port_pos.end 196 | pos_t flags_pos; 197 | #define flags_start flags_pos.start 198 | #define flags_end flags_pos.end 199 | }; 200 | 201 | #define ACL_CHECK 0x0 202 | #define ACL_SPEC_CHECK 0x1 203 | #define POSITIVE_CHECK 0x2 204 | #define PASSIVE_SET 0x3 205 | #define KEEP_ALIVE_SET 0x4 206 | #define KEEP_ALIVE_GET 0x5 207 | #define CHECK_PRIMITIVE 0x6 208 | #define AUTH_PROCEDURE_GET 0x7 209 | #define CONN_NODE_GET 0x8 210 | 211 | #define cfg_conn_acl_allowed(addr) cfg_conn_op(addr, ACL_CHECK, NULL) 212 | #define cfg_conn_acl_spec_allowed(addr) cfg_conn_op(addr, ACL_SPEC_CHECK, NULL) 213 | #define cfg_conn_is_positive(addr) cfg_conn_op(addr, POSITIVE_CHECK, NULL) 214 | #define cfg_conn_set_passive(addr) cfg_conn_op(addr, PASSIVE_SET, NULL) 215 | #define cfg_conn_set_keep_alive(addr, val) cfg_conn_op(addr, KEEP_ALIVE_SET, val) 216 | #define cfg_conn_get_keep_alive(addr, val) cfg_conn_op(addr, KEEP_ALIVE_GET, val) 217 | #define cfg_conn_check_primitive(addr, val) cfg_conn_op(addr, CHECK_PRIMITIVE, val) 218 | #define cfg_conn_get_auth_procedure(addr) ({ \ 219 | struct item_node_t *val = NULL; \ 220 | struct auth_stage *auth_stage = NULL; \ 221 | if (cfg_conn_op(addr, AUTH_PROCEDURE_GET, (void *)&val)) \ 222 | auth_stage = val->data; \ 223 | auth_stage;}) 224 | 225 | #define cfg_conn_get_node(addr) ({ \ 226 | struct conn_node_t *node = NULL; \ 227 | cfg_conn_op(addr, CONN_NODE_GET, (void *)&node); \ 228 | node;}); 229 | 230 | extern int cfg_conn_op(struct sockaddr *addr, int op_type, void *val); 231 | 232 | extern void cfg_allowed_entries_for_each_call(void (*call_func)(void *data)); 233 | 234 | extern void cfg_allowed_iport_node_for_each_call(unsigned int ip, unsigned short int port ,void (*call_func)(void *data)); 235 | 236 | extern int cfg_init(void); 237 | extern void cfg_destroy(void); 238 | 239 | static inline long cfg_item_get_value(struct cfg_entry *ce, const char *name, int len, kconnp_value_t *value, node_type type) 240 | { 241 | struct item_node_t *item_node; 242 | int ret; 243 | 244 | read_lock(&ce->cfg_rwlock); 245 | 246 | if (!ce->cfg_ptr) { //init default value. 247 | if (value) 248 | memset(value, 0, sizeof(kconnp_value_t)); 249 | ret = 0; 250 | goto ret_unlock; 251 | } 252 | 253 | if (hash_find((struct hash_table_t *)ce->cfg_ptr, 254 | name, len, 255 | (void **)&item_node)) { 256 | 257 | switch (type) { 258 | case STRING: 259 | if (value) { 260 | value->str.data = lkmalloc(item_node->v_strlen); 261 | if (!value->str.data) { 262 | ret = -1; 263 | goto ret_unlock; 264 | } 265 | memcpy(value->str.data, item_node->v_str, item_node->v_strlen); 266 | value->str.len = item_node->v_strlen; 267 | ret = 1; 268 | } else 269 | ret = -1; 270 | break; 271 | case INTEGER: 272 | if (value) { 273 | value->lval = item_node->v_lval; 274 | ret = 1; 275 | } else 276 | ret = item_node->v_lval; 277 | break; 278 | default: 279 | ret = -1; 280 | break; 281 | } 282 | 283 | } else { 284 | printk(KERN_ERR 285 | "The item name %s is not found in file /proc/%s/%s\n", 286 | name, CFG_BASE_DIR_NAME, ce->f_name); 287 | ret = -1; 288 | } 289 | 290 | ret_unlock: 291 | read_unlock(&ce->cfg_rwlock); 292 | 293 | return ret; 294 | } 295 | 296 | #define GN(name) cfg_item_get_value(&cfg->global, name, sizeof(name)-1, NULL, INTEGER) 297 | #define GVS(name, vp) cfg_item_get_value(&cfg->global, name, sizeof(name)-1, vp, STRING) 298 | 299 | #define lkm_proc_mkdir(dname) proc_mkdir(dname, NULL) 300 | #define lkm_proc_rmdir(dname) remove_proc_entry(dname, NULL) 301 | 302 | #define lkm_proc_remove(fname, parent) remove_proc_entry(fname, parent) 303 | 304 | #endif 305 | -------------------------------------------------------------------------------- /connp.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "sys_call.h" 7 | #include "lkm_util.h" 8 | #include "cfg.h" 9 | #include "sockp.h" 10 | #include "connp.h" 11 | #include "connpd.h" 12 | #include "auth.h" 13 | 14 | rwlock_t connp_rwlock; //global connp r/w lock; 15 | 16 | static void do_conn_spec_check_close_flag(void *data); 17 | static void do_conn_inc_all_count(void *data); 18 | static void do_conn_inc_idle_count(void *data); 19 | static void do_conn_inc_connected_miss_count(void *data); 20 | static void do_conn_inc_connected_hit_count(void *data); 21 | 22 | static inline int insert_socket_to_connp(struct sockaddr *, struct sockaddr *, struct socket *, int pre_insert_auth_sock); 23 | static inline int insert_into_connp(struct sockaddr *, struct sockaddr *, struct socket *); 24 | 25 | static inline void deferred_destroy(void); 26 | 27 | static int conn_close_flag; 28 | static void do_conn_spec_check_close_flag(void *data) 29 | { 30 | struct conn_node_t *conn_node = (typeof(conn_node))data; 31 | 32 | if (conn_node->conn_ip != 0 && conn_node->conn_port != 0) { 33 | conn_close_flag = conn_node->conn_close_now; 34 | conn_node->conn_close_now = 0; //clear the close flag. 35 | } 36 | } 37 | 38 | int conn_spec_check_close_flag(struct sockaddr *address) 39 | { 40 | unsigned int ip; 41 | unsigned short int port; 42 | 43 | ip = SOCKADDR_IP(address); 44 | port = SOCKADDR_PORT(address); 45 | 46 | conn_close_flag = 0; 47 | 48 | cfg_allowed_iport_node_for_each_call(ip, port, do_conn_spec_check_close_flag); 49 | 50 | return conn_close_flag; 51 | } 52 | 53 | static void do_conn_inc_all_count(void *data) 54 | { 55 | struct conn_node_t *conn_node = (typeof(conn_node))data; 56 | 57 | ++conn_node->conn_all_count; 58 | } 59 | 60 | static void do_conn_inc_idle_count(void *data) 61 | { 62 | struct conn_node_t *conn_node = (typeof(conn_node))data; 63 | 64 | ++conn_node->conn_idle_count; 65 | } 66 | 67 | static void do_conn_inc_connected_miss_count(void *data) 68 | { 69 | struct conn_node_t *conn_node = (typeof(conn_node))data; 70 | 71 | lkm_atomic_add(&conn_node->conn_connected_miss_count, 1); 72 | } 73 | 74 | static void do_conn_inc_connected_hit_count(void *data) 75 | { 76 | struct conn_node_t *conn_node = (typeof(conn_node))data; 77 | 78 | lkm_atomic_add(&conn_node->conn_connected_hit_count, 1); 79 | } 80 | 81 | int conn_inc_count(struct sockaddr *addr, int count_type) 82 | { 83 | unsigned int ip; 84 | unsigned short int port; 85 | void (*conn_inc_count_func)(void *data) = NULL; 86 | 87 | ip = SOCKADDR_IP(addr); 88 | port = SOCKADDR_PORT(addr); 89 | 90 | if (count_type == ALL_COUNT) 91 | conn_inc_count_func = do_conn_inc_all_count; 92 | else if (count_type == IDLE_COUNT) 93 | conn_inc_count_func = do_conn_inc_idle_count; 94 | else if (count_type == CONNECTED_HIT_COUNT) 95 | conn_inc_count_func = do_conn_inc_connected_hit_count; 96 | else if (count_type == CONNECTED_MISS_COUNT) 97 | conn_inc_count_func = do_conn_inc_connected_miss_count; 98 | 99 | cfg_allowed_iport_node_for_each_call(ip, port, conn_inc_count_func); 100 | 101 | return 1; 102 | } 103 | 104 | static inline int insert_socket_to_connp(struct sockaddr *cliaddr, 105 | struct sockaddr *servaddr, 106 | struct socket *sock, 107 | int pre_insert_auth_sock) 108 | { 109 | int ret; 110 | int connpd_fd; 111 | 112 | connpd_fd = connpd_get_unused_fd(); 113 | if (connpd_fd < 0) 114 | return KCP_ERROR; 115 | 116 | task_fd_install(CONNP_DAEMON_TSKP, connpd_fd, sock->file); 117 | file_refcnt_inc(sock->file); //add file reference count. 118 | 119 | ret = insert_sock_to_sockp(cliaddr, servaddr, sock, connpd_fd, SOCK_RECLAIM, NULL, pre_insert_auth_sock); 120 | if (ret != KCP_OK) { 121 | connpd_close_pending_fds_in(connpd_fd); 122 | return ret; 123 | } 124 | 125 | return KCP_OK; 126 | } 127 | 128 | static inline int insert_into_connp(struct sockaddr *cliaddr, struct sockaddr *servaddr, 129 | struct socket *sock) 130 | { 131 | int ret = 0; 132 | struct sock *sk = sock->sk; 133 | struct socket_bucket *sb = NULL; 134 | 135 | //To free 136 | ret = free_sk_to_sockp(sk, &sb); 137 | if (ret) { 138 | if (ret == KCP_OK) {//free success 139 | if (sb) { 140 | if (sb->connpd_fd >= 0) 141 | sock->sk = NULL; //Remove reference to avoid destroying the sk. 142 | else { 143 | int fd; 144 | fd = connpd_get_unused_fd(); 145 | if (fd < 0) { 146 | sb->sock_close_now = 1; 147 | goto out_ret; 148 | } 149 | 150 | task_fd_install(CONNP_DAEMON_TSKP, fd, sock->file); 151 | file_refcnt_inc(sock->file); //add file reference count. 152 | smp_mb(); 153 | sb->connpd_fd = fd; 154 | } 155 | } 156 | } 157 | goto out_ret; 158 | } 159 | 160 | //To insert 161 | ret = insert_socket_to_connp(cliaddr, servaddr, sock, 0); 162 | 163 | out_ret: 164 | return ret; 165 | } 166 | 167 | int check_if_ignore_primitives(int fd, const char __user *buf, size_t len) 168 | { 169 | struct socket *sock; 170 | struct sockaddr servaddr; 171 | kconnp_str_t b = {.data = (char *)buf, .len = len}; 172 | 173 | if (!is_sock_fd(fd)) 174 | return 0; 175 | 176 | sock = getsock(fd); 177 | if (!sock 178 | || !IS_TCP_SOCK(sock) 179 | || !IS_CLIENT_SOCK(sock)) 180 | return 0; 181 | 182 | if (!getsockservaddr(sock, &servaddr)) 183 | return 0; 184 | 185 | if (!IS_IPV4_SA(&servaddr)) 186 | return 0; 187 | 188 | return cfg_conn_check_primitive(&servaddr, (void *)&b); 189 | 190 | } 191 | 192 | 193 | int connp_fd_allowed(int fd) 194 | { 195 | struct socket *sock; 196 | struct sockaddr cliaddr; 197 | struct sockaddr servaddr; 198 | 199 | if (!is_sock_fd(fd)) 200 | return 0; 201 | 202 | sock = getsock(fd); 203 | if (!sock 204 | || !IS_TCP_SOCK(sock) 205 | || !IS_CLIENT_SOCK(sock)) 206 | return 0; 207 | 208 | if (!getsockcliaddr(sock, &cliaddr) || !IS_IPV4_SA(&cliaddr)) 209 | return 0; 210 | 211 | if (!getsockservaddr(sock, &servaddr) || !IS_IPV4_SA(&servaddr)) 212 | return 0; 213 | 214 | if (!cfg_conn_acl_allowed(&servaddr)) 215 | return 0; 216 | 217 | return 1; 218 | } 219 | 220 | int insert_into_connp_if_permitted(int fd) 221 | { 222 | int err; 223 | int refcnt; 224 | struct socket *sock; 225 | struct sockaddr cliaddr; 226 | struct sockaddr servaddr; 227 | 228 | connp_rlock(); 229 | 230 | if (!CONNP_DAEMON_EXISTS() || INVOKED_BY_CONNP_DAEMON()) 231 | goto ret_fail; 232 | 233 | if (!is_sock_fd(fd)) 234 | goto ret_fail; 235 | 236 | sock = getsock(fd); 237 | if (!sock 238 | || !IS_TCP_SOCK(sock) 239 | || !IS_CLIENT_SOCK(sock)) 240 | goto ret_fail; 241 | 242 | refcnt = file_refcnt_read(sock->file); 243 | 244 | if (refcnt != 1) 245 | goto ret_fail; 246 | 247 | if (!getsockcliaddr(sock, &cliaddr) || !IS_IPV4_SA(&cliaddr)) 248 | goto ret_fail; 249 | 250 | if (!getsockservaddr(sock, &servaddr) || !IS_IPV4_SA(&servaddr)) 251 | goto ret_fail; 252 | 253 | if (!cfg_conn_is_positive(&servaddr)) 254 | goto sock_close; 255 | 256 | if (!SOCK_ESTABLISHED(sock)) { 257 | cfg_conn_set_passive(&servaddr); //may be passive sock. 258 | goto sock_close; 259 | } 260 | 261 | err = insert_into_connp(&cliaddr, &servaddr, sock); 262 | if (err < 0) 263 | err = -EBADF; 264 | 265 | connp_runlock(); 266 | return err; 267 | 268 | sock_close: 269 | set_sock_close_now(sock, 1); 270 | notify(CONNP_DAEMON_TSKP); //wake up connpd to nonconnection collection. 271 | 272 | ret_fail: 273 | connp_runlock(); 274 | return 0; 275 | } 276 | 277 | int fetch_conn_from_connp(int fd, struct sockaddr *servaddr) 278 | { 279 | struct sockaddr cliaddr; 280 | struct socket *sock; 281 | struct socket_bucket *sb; 282 | int ret = 0; 283 | 284 | connp_rlock(); 285 | 286 | if (!CONNP_DAEMON_EXISTS()) 287 | goto ret_unlock; 288 | 289 | if (!is_sock_fd(fd)) 290 | goto ret_unlock; 291 | 292 | sock = getsock(fd); 293 | if (!sock 294 | || !sock->sk 295 | || !IS_TCP_SOCK(sock) 296 | || !IS_UNCONNECTED_SOCK(sock)) 297 | goto ret_unlock; 298 | 299 | if (!IS_IPV4_SA(servaddr) 300 | || !cfg_conn_acl_allowed(servaddr)) 301 | goto ret_unlock; 302 | 303 | //check the client sock local address 304 | if (!getsockcliaddr(sock, &cliaddr)) 305 | goto ret_unlock; 306 | 307 | if (SOCKADDR_IP(&cliaddr) == htonl(INADDR_ANY)) { // address not bind before connect 308 | //get local sock client addr 309 | if (!getsocklocaladdr(sock, &cliaddr, servaddr) || !IS_IPV4_SA(&cliaddr)) 310 | goto ret_unlock; 311 | } else if (!IS_IPV4_SA(&cliaddr)) 312 | goto ret_unlock; 313 | 314 | if ((sb = apply_sk_from_sockp((struct sockaddr *)&cliaddr, servaddr))) { 315 | 316 | //Destroy the pre-create sk 317 | sk_destroy(sock->sk); 318 | 319 | sock_graft(sb->sk, sock); 320 | 321 | SET_SOCK_STATE(sock, SS_CONNECTED); 322 | 323 | if (CONN_IS_NONBLOCK(sock->file)) 324 | ret = CONN_NONBLOCK; 325 | else 326 | ret = CONN_BLOCK; 327 | 328 | conn_inc_connected_hit_count(servaddr); 329 | } else { 330 | if(cfg_conn_get_auth_procedure(servaddr)) 331 | //insert_socket_to_connp(&cliaddr, servaddr, sock, 1); //pre-insert 332 | insert_sock_to_sockp(&cliaddr, servaddr, sock, -1, SOCK_RECLAIM, NULL, 1); 333 | 334 | conn_inc_connected_miss_count(servaddr); 335 | } 336 | 337 | SET_CLIENT_FLAG(sock); 338 | 339 | ret_unlock: 340 | connp_runlock(); 341 | return ret; 342 | } 343 | 344 | void connp_sys_exit_prepare() 345 | { 346 | struct fd_entry *pos, *tmp; 347 | 348 | LIST_HEAD(fds_list); 349 | TASK_GET_FDS(current, &fds_list); 350 | list_for_each_entry_safe(pos, tmp, &fds_list, siblings) { 351 | insert_into_connp_if_permitted(pos->fd); 352 | lkmfree(pos); 353 | } 354 | } 355 | 356 | static inline void deferred_destroy(void) 357 | { 358 | int time_going = 1 * HZ;//1s 359 | 360 | wait_for_timeout(time_going); 361 | } 362 | 363 | int connp_init() 364 | { 365 | connp_rwlock_init(); 366 | 367 | if (!cfg_init()) { 368 | printk(KERN_ERR "Error: cfg_init error!"); 369 | return 0; 370 | } 371 | 372 | if (!sockp_init()) { 373 | cfg_destroy(); 374 | printk(KERN_ERR "Error: sockp_init error!"); 375 | return 0; 376 | } 377 | 378 | if (!connpd_init()) { 379 | sockp_destroy(); 380 | cfg_destroy(); 381 | printk(KERN_ERR "Error: create connp daemon thread error!"); 382 | return 0; 383 | } 384 | 385 | if (!replace_syscalls()) { 386 | connpd_destroy(); 387 | sockp_destroy(); 388 | cfg_destroy(); 389 | printk(KERN_ERR "Error: replace_syscalls error!"); 390 | return 0; 391 | } 392 | 393 | return 1; 394 | } 395 | 396 | void connp_destroy() 397 | { 398 | restore_syscalls(); 399 | connpd_destroy(); 400 | sockp_destroy(); 401 | cfg_destroy(); 402 | deferred_destroy();//Make sure all threads exit the kconnp routines. 403 | } 404 | -------------------------------------------------------------------------------- /lkm_util.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Most of the codes for this file is brought from kernel source code. 3 | * 4 | */ 5 | 6 | #ifndef LKM_UTIL_H 7 | #define LKM_UTIL_H 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) 23 | #include 24 | #endif 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | #define wait_for_sig_or_timeout(timeout) schedule_timeout_interruptible(timeout) 35 | #define wait_for_timeout(timeout) schedule_timeout_uninterruptible(timeout) 36 | 37 | struct pollfd_ex_t { 38 | struct pollfd pollfd; 39 | void *data; 40 | int (*poll_func)(void *data, poll_table *pt); 41 | }; 42 | 43 | #define MIN(arg1, arg2) (arg1 < arg2 ? arg1 : arg2) 44 | #define MAX(arg1, arg2) (arg1 > arg2 ? arg1 : arg2) 45 | 46 | #define E_EVENTS (POLLERR|POLLHUP|POLLNVAL) 47 | 48 | #define NOW_SECS (CURRENT_TIME_SEC.tv_sec) 49 | 50 | #define NOTIFY_SIG (SIGINT) 51 | #define SEND_FORCE (1) 52 | #define notify(tskp) send_sig(NOTIFY_SIG, (tskp), SEND_FORCE) 53 | 54 | #define INVOKED_BY_TGROUP_LEADER() (current == current->group_leader) 55 | 56 | #define lkmalloc(size) kzalloc(size, GFP_ATOMIC) 57 | #define lkmfree(ptr) kfree(ptr) 58 | 59 | #define BYTES_ALIGN(size) (((size) + (sizeof(long) - 1)) & ~(sizeof(long) - 1)) 60 | 61 | #define SOCK_CLIENT_TAG (1U << 30) 62 | 63 | #define IS_IPV4_SA(addr) \ 64 | ((addr)->sa_family == AF_INET) 65 | 66 | #define IS_CLIENT_SOCK(sock) \ 67 | ((sock)->file && ((sock)->file->f_flags & SOCK_CLIENT_TAG)) 68 | 69 | #define SET_CLIENT_FLAG(sock) do { \ 70 | if ((sock)->file) \ 71 | (sock)->file->f_flags |= SOCK_CLIENT_TAG; \ 72 | } while (0) 73 | 74 | #define CLEAR_CLIENT_FLAG(sock) do { \ 75 | if ((sock)->file) \ 76 | (sock)->file->f_flags &= ~SOCK_CLIENT_TAG; \ 77 | } while (0) 78 | 79 | #define SK_ESTABLISHING(sk) \ 80 | (sk->sk_state == TCP_SYN_SENT) 81 | 82 | #define SK_ESTABLISHED(sk) \ 83 | (sk->sk_state == TCP_ESTABLISHED) 84 | 85 | #define SET_SOCK_STATE(sock, STATE) \ 86 | ((sock)->state = STATE) 87 | 88 | #define SOCK_ESTABLISHED(sock) \ 89 | ((sock)->sk && SK_ESTABLISHED((sock)->sk)) 90 | 91 | #define IS_TCP_SOCK(sock) \ 92 | ((sock)->type == SOCK_STREAM) 93 | 94 | #define IS_UNCONNECTED_SOCK(sock) \ 95 | ((sock)->type == SS_UNCONNECTED) 96 | 97 | #define lkm_atomic32_read(v) atomic_read((atomic_t *)v) 98 | #define lkm_atomic32_add(v, a) atomic_add_return(a, (atomic_t *)v) 99 | #define lkm_atomic32_sub(v, a) atomic_sub_return(a, (atomic_t *)v) 100 | #define lkm_atomic32_set(v, a) atomic_set((atomic_t *)v, a) 101 | 102 | #define lkm_atomic64_read(v) atomic64_read((atomic64_t *)v) 103 | #define lkm_atomic64_add(v, a) atomic64_add_return(a, (atomic64_t *)v) 104 | #define lkm_atomic64_sub(v, a) atomic64_sub_return(a, (atomic64_t *)v) 105 | #define lkm_atomic64_set(v, a) atomic64_set((atomic64_t *)v, a) 106 | 107 | #if BITS_PER_LONG == 32 //32 bits 108 | 109 | typedef atomic_t lkm_atomic_t; 110 | #define lkm_atomic_read(v) lkm_atomic32_read(v) 111 | #define lkm_atomic_add(v, a) lkm_atomic32_add(v, a) 112 | #define lkm_atomic_sub(v, a) lkm_atomic32_sub(v, a) 113 | #define lkm_atomic_set(v, a) lkm_atomic32_set(v, a) 114 | 115 | #elif BITS_PER_LONG == 64 //64 bits 116 | 117 | typedef atomic64_t lkm_atomic_t; 118 | #define lkm_atomic_read(v) lkm_atomic64_read(v) 119 | #define lkm_atomic_add(v, a) lkm_atomic64_add(v, a) 120 | #define lkm_atomic_sub(v, a) lkm_atomic64_sub(v, a) 121 | #define lkm_atomic_set(v, a) lkm_atomic64_set(v, a) 122 | 123 | #endif 124 | 125 | #define lkm_get_file(fd) \ 126 | ({ struct file * __file; \ 127 | rcu_read_lock(); \ 128 | __file = fcheck_files(TASK_FILES(current), fd); \ 129 | rcu_read_unlock(); \ 130 | __file;}) 131 | 132 | #define TASK_FILES(tsk) (tsk)->files 133 | 134 | #define FILE_FDT_TYPE typeof(((struct files_struct *)0)->fdtab) 135 | 136 | #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 32) 137 | 138 | #define TASK_FILES_FDT(tsk) ({ \ 139 | FILE_FDT_TYPE * __tmp; \ 140 | rcu_read_lock(); \ 141 | __tmp = rcu_dereference(TASK_FILES(tsk)->fdt); \ 142 | rcu_read_unlock(); \ 143 | __tmp;}) 144 | 145 | #else 146 | 147 | #define TASK_FILES_FDT(tsk) ({ \ 148 | FILE_FDT_TYPE * __tmp; \ 149 | rcu_read_lock(); \ 150 | __tmp = rcu_dereference_check_fdtable(TASK_FILES(tsk), TASK_FILES(tsk)->fdt); \ 151 | rcu_read_unlock(); \ 152 | __tmp;}) 153 | 154 | #endif 155 | 156 | #define FDT_GET_FILE(fdt) ({ \ 157 | struct file *__tmp; \ 158 | rcu_read_lock(); \ 159 | __tmp = rcu_dereference(fdt->fd[fd]); \ 160 | rcu_read_unlock(); \ 161 | __tmp;}) 162 | 163 | #define lkm_setrlimit(resource, new_rlim) \ 164 | do { \ 165 | struct rlimit *old_rlim; \ 166 | \ 167 | old_rlim = current->signal->rlim + resource; \ 168 | *old_rlim = new_rlim; \ 169 | } while (0) 170 | 171 | 172 | #define SOCKADDR_FAMILY(sockaddr_ptr) (((struct sockaddr_in *)(sockaddr_ptr)))->sin_family 173 | #define SOCKADDR_IP(sockaddr_ptr) (((struct sockaddr_in *)(sockaddr_ptr)))->sin_addr.s_addr 174 | #define SOCKADDR_PORT(sockaddr_ptr) (((struct sockaddr_in *)(sockaddr_ptr)))->sin_port 175 | 176 | typedef struct array_t array_t; 177 | extern int lkm_poll(array_t *, int timeout); 178 | 179 | #define lkm_jiffies (unsigned)jiffies 180 | 181 | //Compat for 32-bits jiffies 182 | static inline u64 lkm_jiffies_elapsed_from(u64 from) 183 | { 184 | s64 elapsed_jiffies = lkm_jiffies - from; 185 | 186 | return elapsed_jiffies >= 0 ? elapsed_jiffies : (elapsed_jiffies + ULONG_MAX); 187 | } 188 | 189 | static inline int file_refcnt_read(struct file *filp) 190 | { 191 | return lkm_atomic32_read(&filp->f_count); 192 | } 193 | 194 | static inline int file_refcnt_inc(struct file *filp) 195 | { 196 | return lkm_atomic32_add(&filp->f_count, 1); 197 | } 198 | 199 | static inline int file_refcnt_dec(struct file *filp) 200 | { 201 | return lkm_atomic32_sub(&filp->f_count, 1); 202 | } 203 | 204 | static inline void file_refcnt_set(struct file *filp, int c) 205 | { 206 | lkm_atomic32_set(&filp->f_count, c); 207 | } 208 | 209 | struct fd_entry { 210 | int fd; 211 | struct list_head siblings; 212 | }; 213 | 214 | static inline int lkm_get_unused_fd(void) 215 | { 216 | int fd; 217 | 218 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 10) 219 | fd = get_unused_fd_flags(0); 220 | #else 221 | fd = get_unused_fd(); 222 | #endif 223 | 224 | return fd; 225 | } 226 | 227 | struct sockaddr_in; 228 | extern int lkm_create_tcp_connect(struct sockaddr_in *); 229 | 230 | /*wrapper copy_from_user function for fixing asm compatible*/ 231 | extern unsigned long lkm_copy_from_user(void *to, const void __user *from, unsigned len); 232 | 233 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 10) 234 | extern int lkm_sock_map_fd(struct socket *sock, int flags); 235 | #endif 236 | 237 | static inline void TASK_GET_FDS(struct task_struct *tsk, struct list_head *fds_list) 238 | { 239 | int i, j = 0; 240 | FILE_FDT_TYPE *fdt; 241 | 242 | fdt = TASK_FILES_FDT(tsk); 243 | 244 | for (;;) { 245 | unsigned long set; 246 | struct fd_entry *tmp; 247 | 248 | #if LINUX_VERSION_CODE <= KERNEL_VERSION(3, 2, 45) 249 | i = j * __NFDBITS; 250 | #else 251 | i = j * BITS_PER_LONG; 252 | #endif 253 | 254 | if (i >= fdt->max_fds) 255 | break; 256 | 257 | #if LINUX_VERSION_CODE <= KERNEL_VERSION(3, 2, 45) 258 | set = fdt->open_fds->fds_bits[j++]; 259 | #else 260 | set = fdt->open_fds[j++]; 261 | #endif 262 | 263 | while (set) { 264 | 265 | if (set & 1) { 266 | /*Collect the fds list and must free mem space by caller.*/ 267 | tmp = (typeof(*tmp) *)lkmalloc(sizeof(typeof(*tmp))); 268 | tmp->fd = i; 269 | list_add_tail(&tmp->siblings, fds_list); 270 | } 271 | i++; 272 | set >>= 1; 273 | 274 | } 275 | } 276 | } 277 | 278 | static inline void task_fd_install(struct task_struct *tsk, int fd, struct file *filp) 279 | { 280 | FILE_FDT_TYPE *fdt; 281 | struct files_struct *files = TASK_FILES(tsk); 282 | 283 | spin_lock(&files->file_lock); 284 | 285 | fdt = TASK_FILES_FDT(tsk); 286 | rcu_assign_pointer(fdt->fd[fd], filp); 287 | 288 | spin_unlock(&files->file_lock); 289 | } 290 | 291 | 292 | static inline struct socket *getsock(int fd) 293 | { 294 | struct file *filp; 295 | FILE_FDT_TYPE *fdt = TASK_FILES_FDT(current); 296 | 297 | filp = FDT_GET_FILE(fdt); 298 | if (filp) 299 | return (struct socket *)filp->private_data; 300 | 301 | return NULL; 302 | } 303 | 304 | #define getsockcliaddr(sock, address) getsockaddr(sock, address, 0) 305 | #define getsockservaddr(sock, address) getsockaddr(sock, address, 1) 306 | static inline int getsockaddr(struct socket *sock, struct sockaddr *address, int peer) 307 | { 308 | int len; 309 | int err; 310 | 311 | if (!sock->sk) 312 | return 0; 313 | 314 | err = sock->ops->getname(sock, address, &len, peer); 315 | if (err) 316 | return 0; 317 | 318 | return 1; 319 | } 320 | 321 | 322 | #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 0) 323 | static inline int lkm_ip_route_connect(struct rtable **rp, u32 dst, 324 | u32 src, u32 tos, int oif, u8 protocol, 325 | u16 sport, u16 dport, struct sock *sk, 326 | int flags) 327 | { 328 | struct flowi fl = { .oif = oif, 329 | .nl_u = { .ip4_u = { .daddr = dst, 330 | .saddr = src, 331 | .tos = tos } }, 332 | .proto = protocol, 333 | .uli_u = { .ports = 334 | { .sport = sport, 335 | .dport = dport } } }; 336 | int err; 337 | 338 | if (!dst || !src) { 339 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 28) 340 | err = __ip_route_output_key(rp, &fl); 341 | #else 342 | err = __ip_route_output_key(sock_net(sk), rp, &fl); 343 | #endif 344 | if (err) 345 | return err; 346 | fl.fl4_dst = (*rp)->rt_dst; 347 | fl.fl4_src = (*rp)->rt_src; 348 | ip_rt_put(*rp); 349 | *rp = NULL; 350 | } 351 | security_sk_classify_flow(sk, &fl); 352 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 28) 353 | return ip_route_output_flow(rp, &fl, sk, flags); 354 | #else 355 | return ip_route_output_flow(sock_net(sk), rp, &fl, sk, flags); 356 | #endif 357 | 358 | } 359 | #endif 360 | 361 | static inline int getsocklocaladdr(struct socket *sock, struct sockaddr *cliaddr, struct sockaddr *servaddr) 362 | { 363 | struct sock *sk = sock->sk; 364 | struct sockaddr_in *usin = (struct sockaddr_in *)servaddr; 365 | struct inet_sock *inet = inet_sk(sk); 366 | struct rtable *rt; 367 | __be32 daddr, nexthop; 368 | 369 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0) 370 | __be16 orig_sport, orig_dport; 371 | struct flowi4 *fl4; 372 | int err; 373 | struct ip_options_rcu *inet_opt; 374 | 375 | nexthop = daddr = SOCKADDR_IP(usin); 376 | inet_opt = rcu_dereference_protected(inet->inet_opt, 377 | sock_owned_by_user(sk)); 378 | if (inet_opt && inet_opt->opt.srr) { 379 | if (!daddr) 380 | return 0; 381 | nexthop = inet_opt->opt.faddr; 382 | } 383 | 384 | orig_sport = inet->inet_sport; 385 | orig_dport = SOCKADDR_PORT(usin); 386 | fl4 = &inet->cork.fl.u.ip4; 387 | 388 | #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0) 389 | rt = ip_route_connect(fl4, nexthop, inet->inet_saddr, 390 | RT_CONN_FLAGS(sk), sk->sk_bound_dev_if, 391 | IPPROTO_TCP, 392 | orig_sport, orig_dport, sk, 1); 393 | #else 394 | rt = ip_route_connect(fl4, nexthop, inet->inet_saddr, 395 | RT_CONN_FLAGS(sk), sk->sk_bound_dev_if, 396 | IPPROTO_TCP, 397 | orig_sport, orig_dport, sk); 398 | #endif 399 | 400 | if (IS_ERR(rt)) { 401 | err = PTR_ERR(rt); 402 | if (err == -ENETUNREACH) 403 | IP_INC_STATS_BH(sock_net(sk), IPSTATS_MIB_OUTNOROUTES); 404 | return 0; 405 | } 406 | 407 | if (rt->rt_flags & (RTCF_MULTICAST | RTCF_BROADCAST)) { 408 | ip_rt_put(rt); 409 | return 0; 410 | } 411 | 412 | SOCKADDR_IP(cliaddr) = fl4->saddr; 413 | 414 | #else 415 | 416 | int tmp; 417 | 418 | nexthop = daddr = SOCKADDR_IP(usin); 419 | 420 | #if defined(optlength) 421 | 422 | if (inet->opt && inet->opt->srr) { 423 | if (!daddr) 424 | return 0; 425 | nexthop = inet->opt->faddr; 426 | } 427 | 428 | #else 429 | 430 | { 431 | struct ip_options_rcu *inet_opt; 432 | inet_opt = inet->inet_opt; 433 | if (inet_opt && inet_opt->opt.srr) { 434 | if (!daddr) 435 | return 0; 436 | nexthop = inet_opt->opt.faddr; 437 | } 438 | } 439 | 440 | #endif 441 | 442 | tmp = lkm_ip_route_connect(&rt, nexthop, inet->saddr, 443 | RT_CONN_FLAGS(sk), sk->sk_bound_dev_if, 444 | IPPROTO_TCP, 445 | inet->sport, usin->sin_port, sk, 1); 446 | if (tmp < 0) 447 | return 0; 448 | 449 | if (rt->rt_flags & (RTCF_MULTICAST | RTCF_BROADCAST)) { 450 | ip_rt_put(rt); 451 | return 0; 452 | } 453 | 454 | SOCKADDR_IP(cliaddr) = rt->rt_src; 455 | 456 | #endif 457 | 458 | return 1; 459 | } 460 | 461 | static inline int is_sock_fd(int fd) 462 | { 463 | struct kstat statbuf; 464 | 465 | if(vfs_fstat(fd, &statbuf) < 0) 466 | return 0; 467 | 468 | return S_ISSOCK(statbuf.mode); 469 | } 470 | 471 | static inline void sk_destroy(struct sock *sk) 472 | { 473 | sk_common_release(sk); 474 | } 475 | 476 | static inline time_t get_fmtime(char *fname) 477 | { 478 | struct kstat statbuf; 479 | 480 | if (vfs_stat(fname, &statbuf) < 0) 481 | return 0; 482 | 483 | return statbuf.mtime.tv_sec; 484 | } 485 | 486 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 28) 487 | 488 | #if BITS_PER_LONG == 32 489 | 490 | static inline pte_t *my_lookup_address(unsigned long address, unsigned int *level/*cummy for compile*/) 491 | { 492 | pgd_t *pgd = pgd_offset_k(address); 493 | pud_t *pud; 494 | pmd_t *pmd; 495 | if (pgd_none(*pgd)) 496 | return NULL; 497 | pud = pud_offset(pgd, address); 498 | if (pud_none(*pud)) 499 | return NULL; 500 | pmd = pmd_offset(pud, address); 501 | if (pmd_none(*pmd)) 502 | return NULL; 503 | if (pmd_large(*pmd)) 504 | return (pte_t *)pmd; 505 | return pte_offset_kernel(pmd, address); 506 | } 507 | 508 | #elif BITS_PER_LONG == 64 509 | 510 | static inline pte_t *my_lookup_address(unsigned long address, unsigned int *level/*dummy for compile*/) 511 | { 512 | pgd_t *pgd = pgd_offset_k(address); 513 | pud_t *pud; 514 | pmd_t *pmd; 515 | pte_t *pte; 516 | if (pgd_none(*pgd)) 517 | return NULL; 518 | pud = pud_offset(pgd, address); 519 | if (!pud_present(*pud)) 520 | return NULL; 521 | pmd = pmd_offset(pud, address); 522 | if (!pmd_present(*pmd)) 523 | return NULL; 524 | if (pmd_large(*pmd)) 525 | return (pte_t *)pmd; 526 | pte = pte_offset_kernel(pmd, address); 527 | if (pte && !pte_present(*pte)) 528 | pte = NULL; 529 | return pte; 530 | } 531 | 532 | #endif 533 | 534 | #define lkm_lookup_address my_lookup_address 535 | 536 | #else 537 | 538 | #define lkm_lookup_address lookup_address 539 | 540 | #endif 541 | 542 | #define lkm_ptep_val(ptep) (*((unsigned long *)(ptep))) 543 | 544 | static inline void set_page_rw(unsigned long addr) 545 | { 546 | unsigned int level; 547 | 548 | pte_t *ptep = lkm_lookup_address(addr, &level); 549 | 550 | if (lkm_ptep_val(ptep) & ~_PAGE_RW) 551 | lkm_ptep_val(ptep) |= _PAGE_RW; 552 | } 553 | 554 | static inline void set_page_ro(unsigned long addr) 555 | { 556 | unsigned int level; 557 | 558 | pte_t *ptep = lkm_lookup_address(addr, &level); 559 | 560 | if (lkm_ptep_val(ptep) & _PAGE_RW) 561 | lkm_ptep_val(ptep) &= ~_PAGE_RW; 562 | } 563 | 564 | static inline void page_protection_disable(unsigned long addr, int pages) 565 | { 566 | while (pages-- > 0) { 567 | set_page_rw(addr); 568 | addr += PAGE_SIZE; 569 | } 570 | 571 | __flush_tlb_all(); 572 | } 573 | 574 | static inline void page_protection_enable(unsigned long addr, int pages) 575 | { 576 | while (pages-- > 0) { 577 | set_page_ro(addr); 578 | addr += PAGE_SIZE; 579 | } 580 | 581 | __flush_tlb_all(); 582 | } 583 | 584 | //Usually stand for host based OS. 585 | 586 | static inline void page_protection_global_disable(void) 587 | { 588 | unsigned long value; 589 | 590 | asm volatile("mov %%cr0,%0" : "=r" (value)); 591 | 592 | if (value & 0x10000UL) { 593 | value &= ~0x10000UL; 594 | asm volatile("mov %0, %%cr0": : "r" (value)); 595 | } 596 | } 597 | 598 | static inline void page_protection_global_enable(void) 599 | { 600 | unsigned long value; 601 | 602 | asm volatile("mov %%cr0,%0" : "=r" (value)); 603 | 604 | if (!(value & 0x10000UL)) { 605 | value |= 0x10000UL; 606 | asm volatile("mov %0, %%cr0": : "r" (value)); 607 | } 608 | } 609 | 610 | #endif 611 | -------------------------------------------------------------------------------- /sockp.c: -------------------------------------------------------------------------------- 1 | /** 2 | *Kernel socket pool 3 | *Author Zhigang Zhang 4 | */ 5 | #include 6 | #include 7 | #include 8 | #include "sys_call.h" 9 | #include "connpd.h" 10 | #include "sockp.h" 11 | #include "lkm_util.h" 12 | #include "cfg.h" 13 | #include "preconnect.h" 14 | #include "auth.h" 15 | 16 | //spin lock 17 | #define SOCKP_LOCK_T spinlock_t 18 | #define SOCKP_LOCK_INIT() spin_lock_init(&ht->ht_lock) 19 | #define SOCKP_LOCK() spin_lock(&ht->ht_lock) 20 | #define SOCKP_UNLOCK() spin_unlock(&ht->ht_lock) 21 | #define SOCKP_LOCK_DESTROY() 22 | 23 | #define HASH(cliaddr_ptr, servaddr_ptr) ht->hash_table[_hashfn((struct sockaddr_in *)(cliaddr_ptr), (struct sockaddr_in *)(servaddr_ptr))] 24 | #define SHASH(sk) ht->shash_table[_shashfn(sk)] 25 | 26 | #define KEY_MATCH(address_ptr11, address_ptr12, address_ptr21, address_ptr22) (SOCKADDR_IP(address_ptr11) == SOCKADDR_IP(address_ptr12) && SOCKADDR_PORT(address_ptr21) == SOCKADDR_PORT(address_ptr22) && SOCKADDR_IP(address_ptr21) == SOCKADDR_IP(address_ptr22)) 27 | #define SKEY_MATCH(sk_ptr1, sk_ptr2) (sk_ptr1 == sk_ptr2) 28 | 29 | #define PUT_SB(sb) ((sb)->sb_in_use = 0) 30 | 31 | #define IN_HLIST(head, bucket) ({ \ 32 | struct socket_bucket *__p = NULL; \ 33 | for (__p = (head); __p; __p = __p->sb_next) { \ 34 | LOOP_COUNT_SAFE_CHECK(__p); \ 35 | if (__p == (bucket)) \ 36 | break; \ 37 | } \ 38 | LOOP_COUNT_RESET(); \ 39 | __p;}) 40 | 41 | #define INSERT_INTO_HLIST(head, bucket) \ 42 | do { \ 43 | (bucket)->sb_prev = NULL; \ 44 | (bucket)->sb_next = (head); \ 45 | if ((head)) \ 46 | (head)->sb_prev = (bucket); \ 47 | (head) = (bucket); \ 48 | } while(0) 49 | 50 | #define REMOVE_FROM_HLIST(head, bucket) \ 51 | do { \ 52 | if ((bucket)->sb_prev) \ 53 | (bucket)->sb_prev->sb_next = (bucket)->sb_next; \ 54 | if ((bucket)->sb_next) \ 55 | (bucket)->sb_next->sb_prev = (bucket)->sb_prev; \ 56 | if ((head) == (bucket)) \ 57 | (head) = (bucket)->sb_next; \ 58 | } while(0) 59 | 60 | #define INSERT_INTO_SHLIST(head, bucket) \ 61 | do { \ 62 | (bucket)->sb_sprev = NULL; \ 63 | (bucket)->sb_snext = (head); \ 64 | if ((head)) \ 65 | (head)->sb_sprev = (bucket); \ 66 | (head) = (bucket);\ 67 | } while(0) 68 | 69 | #define REMOVE_FROM_SHLIST(head, bucket) \ 70 | do { \ 71 | if ((bucket)->sb_sprev) \ 72 | (bucket)->sb_sprev->sb_snext = (bucket)->sb_snext; \ 73 | if ((bucket)->sb_snext) \ 74 | (bucket)->sb_snext->sb_sprev = (bucket)->sb_sprev; \ 75 | if ((head) == (bucket)) \ 76 | (head) = (bucket)->sb_snext; \ 77 | } while(0) 78 | 79 | #define IN_TLIST(bucket) ({ \ 80 | struct socket_bucket *__p; \ 81 | for (__p = ht->sb_trav_head; __p; __p = __p->sb_trav_next) { \ 82 | LOOP_COUNT_SAFE_CHECK(__p); \ 83 | if (__p == (bucket)) \ 84 | break; \ 85 | } \ 86 | LOOP_COUNT_RESET(); \ 87 | __p;}) 88 | 89 | #define INSERT_INTO_TLIST(bucket) \ 90 | do { \ 91 | (bucket)->sb_trav_next = NULL; \ 92 | (bucket)->sb_trav_prev = ht->sb_trav_tail; \ 93 | if (!ht->sb_trav_head) \ 94 | ht->sb_trav_head = (bucket); \ 95 | if (ht->sb_trav_tail) \ 96 | ht->sb_trav_tail->sb_trav_next = (bucket); \ 97 | ht->sb_trav_tail = (bucket); \ 98 | ht->elements_count++; \ 99 | } while(0) 100 | 101 | #define REMOVE_FROM_TLIST(bucket) \ 102 | do { \ 103 | if ((bucket)->sb_trav_next) \ 104 | (bucket)->sb_trav_next->sb_trav_prev = (bucket)->sb_trav_prev; \ 105 | if ((bucket)->sb_trav_prev) \ 106 | (bucket)->sb_trav_prev->sb_trav_next = (bucket)->sb_trav_next; \ 107 | if ((bucket) == ht->sb_trav_head) \ 108 | ht->sb_trav_head = (bucket)->sb_trav_next; \ 109 | if ((bucket) == ht->sb_trav_tail) \ 110 | ht->sb_trav_tail = (bucket)->sb_trav_prev; \ 111 | ht->elements_count--; \ 112 | } while(0) 113 | 114 | #define SOCKADDR_COPY(sockaddr_dest, sockaddr_src) memcpy((void *)sockaddr_dest, (void *)sockaddr_src, sizeof(struct sockaddr)) 115 | 116 | #define AUTH_PROCEDURE_INIT(sb) \ 117 | do { \ 118 | (sb)->cfg_generation = cfg->auth_generation; \ 119 | (sb)->auth_procedure_status = AUTH_NEW; \ 120 | (sb)->auth_procedure_head = NULL; \ 121 | (sb)->auth_procedure_tail = NULL; \ 122 | (sb)->auth_procedure_stage = NULL; \ 123 | } while (0); 124 | 125 | #define AUTH_PROCEDURE_DESTROY(sb) \ 126 | do { \ 127 | if ((sb)->auth_procedure_head) { \ 128 | auth_procedure_destroy((sb)->auth_procedure_head); \ 129 | (sb)->auth_procedure_head = NULL; \ 130 | } \ 131 | } while (0); 132 | #define REMOVE_FROM_SOCKP(sb) \ 133 | do { \ 134 | AUTH_PROCEDURE_DESTROY(sb); \ 135 | \ 136 | if (IN_HLIST(HASH(&(sb)->cliaddr, &(sb)->servaddr), sb)) \ 137 | REMOVE_FROM_HLIST(HASH(&(sb)->cliaddr, &(sb)->servaddr), sb); \ 138 | REMOVE_FROM_SHLIST(SHASH((sb)->sk), sb); \ 139 | REMOVE_FROM_TLIST(sb); \ 140 | \ 141 | PUT_SB(sb); \ 142 | } while (0) 143 | #define INIT_SB(sb, s, fd, way) \ 144 | do { \ 145 | (sb)->sb_in_use = 1; \ 146 | (sb)->sock_in_use = 0; \ 147 | (sb)->sock_close_now = 0; \ 148 | (sb)->sock = s; \ 149 | (sb)->sk = (s)->sk; \ 150 | (sb)->sock_create_way = way; \ 151 | (sb)->sock_create_jiffies = lkm_jiffies; \ 152 | (sb)->last_used_jiffies = lkm_jiffies; \ 153 | (sb)->connpd_fd = fd; \ 154 | (sb)->uc = 0; \ 155 | (sb)->sb_prev = NULL; \ 156 | (sb)->sb_next = NULL; \ 157 | (sb)->sb_sprev = NULL; \ 158 | (sb)->sb_snext = NULL; \ 159 | (sb)->sb_trav_prev = NULL; \ 160 | (sb)->sb_trav_next = NULL; \ 161 | AUTH_PROCEDURE_INIT(sb); \ 162 | } while(0) 163 | 164 | #define ATOMIC_SET_SOCK_ATTR(sock, attr) \ 165 | do { \ 166 | struct socket_bucket *p; \ 167 | \ 168 | SOCKP_LOCK(); \ 169 | \ 170 | if (!sock->sk) \ 171 | goto break_unlock; \ 172 | \ 173 | p = SHASH(sock->sk); \ 174 | for (; p; p = p->sb_snext) { \ 175 | if (SKEY_MATCH(sock->sk, p->sk)) { \ 176 | p->attr = attr; \ 177 | break; \ 178 | } \ 179 | } \ 180 | \ 181 | break_unlock: \ 182 | SOCKP_UNLOCK(); \ 183 | \ 184 | } while(0) 185 | 186 | #define LEFT_LIFETIME_THRESHOLD ((unsigned)(HZ >> 1)) //500ms 187 | 188 | #define SOCK_IS_RECLAIM(sb) ((sb)->sock_create_way == SOCK_RECLAIM) 189 | #define SOCK_IS_RECLAIM_PASSIVE(sb) (SOCK_IS_RECLAIM(sb) && !cfg_conn_is_positive(&(sb)->servaddr)) 190 | 191 | #define SOCK_IS_PRECONNECT(sb) ((sb)->sock_create_way == SOCK_PRECONNECT) 192 | #define SOCK_IS_NOT_SPEC_BUT_PRECONNECT(sb) (!cfg_conn_acl_spec_allowed(&(sb)->servaddr) && SOCK_IS_PRECONNECT(sb)) 193 | 194 | #define sockp_sbs_check_list_init(num) \ 195 | stack_init(&sockp_sbs_check_list, num, sizeof(struct socket_bucket *), WITH_MUTEX) 196 | 197 | #define sockp_sbs_check_list_destroy() \ 198 | do { \ 199 | if (sockp_sbs_check_list) \ 200 | sockp_sbs_check_list->destroy(&sockp_sbs_check_list); \ 201 | } while(0) 202 | 203 | #if SOCKP_DEBUG 204 | 205 | static unsigned int loop_count = 0; 206 | #define LOOP_COUNT_SAFE_CHECK(ptr) do { \ 207 | if (++loop_count > NR_SOCKET_BUCKET) { \ 208 | printk(KERN_ERR "Loop count overflow, function: %s, line: %d", __FUNCTION__, __LINE__); \ 209 | } \ 210 | } while(0) 211 | 212 | #define LOOP_COUNT_LOCAL_DEFINE(var_name) unsigned int var_name 213 | 214 | #define LOOP_COUNT_SAVE(local) do { \ 215 | local = loop_count; \ 216 | } while(0) 217 | 218 | #define LOOP_COUNT_RESTORE(local) do { \ 219 | loop_count = local; \ 220 | } while(0) 221 | 222 | #define LOOP_COUNT_VALUE() (loop_count) 223 | #define LOOP_COUNT_RESET() (loop_count = 0) 224 | 225 | #else 226 | 227 | #define LOOP_COUNT_SAFE_CHECK(ptr) 228 | #define LOOP_COUNT_LOCAL_DEFINE(var) 229 | #define LOOP_COUNT_SAVE(local) 230 | #define LOOP_COUNT_RESTORE(local) 231 | #define LOOP_COUNT_RESET() 232 | 233 | #endif 234 | 235 | static struct { 236 | struct socket_bucket *hash_table[NR_HASH]; 237 | struct socket_bucket *shash_table[NR_SHASH]; //for sock addr hash table. 238 | 239 | struct socket_bucket *sb_free_p; 240 | 241 | struct socket_bucket *sb_trav_head; 242 | struct socket_bucket *sb_trav_tail; 243 | 244 | unsigned int elements_count; 245 | 246 | SOCKP_LOCK_T ht_lock; 247 | } *ht; 248 | 249 | static struct socket_bucket *SB; 250 | 251 | struct stack_t *sockp_sbs_check_list; 252 | 253 | #if LRU 254 | static struct socket_bucket *get_empty_slot(struct sockaddr *, struct sockaddr *); 255 | #else 256 | static struct socket_bucket *get_empty_slot(void); 257 | #endif 258 | 259 | #define sock_is_not_available(sb) (!sock_is_available(sb)) 260 | static inline int sock_is_available(struct socket_bucket *); 261 | static inline u64 estimate_min_left_lifetime(u64 est_time); 262 | 263 | static inline unsigned int _hashfn(struct sockaddr_in *, struct sockaddr_in *); 264 | static inline unsigned int _shashfn(struct sock *); 265 | 266 | static inline u64 estimate_min_left_lifetime(u64 timev) 267 | { 268 | u64 estimate_time = timev >> 1; 269 | 270 | return MIN(estimate_time, LEFT_LIFETIME_THRESHOLD); 271 | } 272 | 273 | static inline int sock_is_available(struct socket_bucket *sb) 274 | { 275 | u64 sock_keep_alive; 276 | u64 sock_age; 277 | s64 sock_left_lifetime; 278 | 279 | if (!SK_ESTABLISHED(sb->sk)) 280 | return 0; 281 | 282 | if (sb->auth_procedure_status > AUTH_PROCESSING) 283 | return 1; 284 | 285 | cfg_conn_get_keep_alive(&sb->servaddr, &sock_keep_alive); 286 | sock_age = lkm_jiffies_elapsed_from(sb->sock_create_jiffies); 287 | sock_left_lifetime = sock_keep_alive - sock_age; 288 | 289 | //In case the peer is closing the socket. 290 | if (sock_left_lifetime < estimate_min_left_lifetime(sock_keep_alive)) 291 | return 0; 292 | 293 | return 1; 294 | } 295 | 296 | static inline unsigned int _hashfn(struct sockaddr_in *cliaddr, struct sockaddr_in *servaddr) 297 | { 298 | return (unsigned)(SOCKADDR_IP(cliaddr) ^ SOCKADDR_PORT(servaddr) ^ SOCKADDR_IP(servaddr)) % NR_HASH; 299 | } 300 | 301 | static inline unsigned int _shashfn(struct sock *sk) 302 | { 303 | return (unsigned long)sk % NR_SHASH; 304 | } 305 | 306 | SOCK_SET_ATTR_DEFINE(sock, sock_close_now) 307 | { 308 | ATOMIC_SET_SOCK_ATTR(sock, sock_close_now); 309 | } 310 | 311 | struct socket_bucket *apply_sk_from_sockp(struct sockaddr *cliaddr, struct sockaddr *servaddr) 312 | { 313 | struct socket_bucket *p; 314 | 315 | SOCKP_LOCK(); 316 | 317 | p = HASH(cliaddr, servaddr); 318 | for (; p; p = p->sb_next) { 319 | 320 | LOOP_COUNT_SAFE_CHECK(p); 321 | 322 | if (KEY_MATCH(cliaddr, &p->cliaddr, servaddr, &p->servaddr)) { 323 | //printk(KERN_ERR "apply find start! sock_in_use: %d, sock_close_now: %d, sock-sk: %d, avaialbe: %d, passive: %d", p->sock_in_use, p->sock_close_now, !p->sock->sk, sock_is_not_available(p), SOCK_IS_RECLAIM_PASSIVE(p)); 324 | 325 | if (p->connpd_fd < 0 326 | || p->sock_in_use 327 | || p->sock_close_now 328 | || !p->sock->sk 329 | || sock_is_not_available(p) 330 | || SOCK_IS_RECLAIM_PASSIVE(p)) 331 | continue; 332 | 333 | //printk(KERN_ERR "apply find end!"); 334 | 335 | if (p->sk != p->sock->sk) { 336 | printk(KERN_ERR "SK of sock changed!"); 337 | continue; 338 | } 339 | 340 | if(++p->uc > MAX_REQUESTS) //check used count 341 | p->sock_close_now = 1; 342 | 343 | p->sock_in_use = 1; //set "in use" tag. 344 | 345 | REMOVE_FROM_HLIST(HASH(cliaddr, servaddr), p); 346 | 347 | LOOP_COUNT_RESET(); 348 | 349 | SOCKP_UNLOCK(); 350 | 351 | //Remove reference to avoid polling events in sockp. 352 | spin_lock(&p->s_lock); 353 | p->sock->sk = NULL; 354 | spin_unlock(&p->s_lock); 355 | 356 | return p; 357 | } 358 | } 359 | 360 | LOOP_COUNT_RESET(); 361 | 362 | SOCKP_UNLOCK(); 363 | return NULL; 364 | } 365 | 366 | /** 367 | *To scan all sock pool to close the expired or all sockets. The caller is kconnpd. 368 | */ 369 | void shutdown_sock_list(shutdown_way_t shutdown_way) 370 | { 371 | struct socket_bucket *p; 372 | 373 | BUG_ON(!INVOKED_BY_CONNP_DAEMON()); 374 | 375 | SOCKP_LOCK(); 376 | 377 | p = ht->sb_trav_head; 378 | for (; p; p = p->sb_trav_next) { 379 | 380 | LOOP_COUNT_SAFE_CHECK(p); 381 | 382 | if (shutdown_way == SHUTDOWN_ALL) 383 | goto shutdown; 384 | 385 | if (p->sock_close_now) { 386 | if (!p->uc) { //get keep alive timeout at begin time. 387 | u64 keep_alive; 388 | keep_alive = lkm_jiffies_elapsed_from(p->sock_create_jiffies); 389 | cfg_conn_set_keep_alive(&p->servaddr, &keep_alive); 390 | } 391 | cfg_conn_set_passive(&p->servaddr); //may be passive socket 392 | goto shutdown; 393 | } 394 | 395 | if (!SK_ESTABLISHING(p->sk) && sock_is_not_available(p)) 396 | goto shutdown; 397 | 398 | if (SOCK_IS_NOT_SPEC_BUT_PRECONNECT(p) 399 | || SOCK_IS_RECLAIM_PASSIVE(p) 400 | || (SOCK_IS_RECLAIM(p) 401 | && (lkm_jiffies_elapsed_from(p->last_used_jiffies) > WAIT_TIMEOUT)) 402 | || (SOCK_IS_PRECONNECT(p) //Be a long connection activity 403 | && p->sock_in_use 404 | && (lkm_jiffies_elapsed_from(p->last_used_jiffies) > WAIT_TIMEOUT))) 405 | goto shutdown; 406 | 407 | //Luckly, selected as idle conn. 408 | if (conn_spec_check_close_flag(&p->servaddr)) 409 | goto shutdown; 410 | 411 | if (p->connpd_fd < 0) 412 | continue; 413 | 414 | if (!p->sock_in_use) 415 | conn_inc_idle_count(&p->servaddr); 416 | 417 | conn_inc_all_count(&p->servaddr); 418 | 419 | sockp_sbs_check_list_in(&p); 420 | 421 | continue; 422 | 423 | shutdown: 424 | do { 425 | LOOP_COUNT_LOCAL_DEFINE(local_loop_count); 426 | LOOP_COUNT_SAVE(local_loop_count); 427 | 428 | LOOP_COUNT_RESET(); 429 | 430 | if (p->connpd_fd < 0) 431 | goto remove_from_sockp; 432 | 433 | if (connpd_close_pending_fds_in(p->connpd_fd) < 0) { 434 | printk(KERN_ERR "Close pending fds buffer overflow!"); 435 | break; 436 | } 437 | 438 | remove_from_sockp: 439 | REMOVE_FROM_SOCKP(p); 440 | 441 | LOOP_COUNT_RESTORE(local_loop_count); 442 | } while (0); 443 | } 444 | 445 | LOOP_COUNT_RESET(); 446 | 447 | SOCKP_UNLOCK(); 448 | } 449 | 450 | struct socket_bucket *get_sock_sb(struct sock *sk, int sock_type) 451 | { 452 | struct socket_bucket *p, *sb = NULL; 453 | 454 | SOCKP_LOCK(); 455 | 456 | p = SHASH(sk); 457 | for(; p; p = p->sb_snext) 458 | if (SKEY_MATCH(sk, p->sk)) { 459 | sb = p; 460 | break; 461 | } 462 | 463 | SOCKP_UNLOCK(); 464 | 465 | if (!sb) 466 | return NULL; 467 | 468 | switch(sock_type) { 469 | case AUTH_SOCK_SB: 470 | if (sb->auth_procedure_status > AUTH_NEW) 471 | return sb; 472 | else 473 | return NULL; 474 | break; 475 | case JUST_PREINSERT_AUTH_SOCK_SB: 476 | if (!sb->uc && sb->auth_procedure_status > AUTH_NEW) //not been applied 477 | return sb; 478 | else 479 | return NULL; 480 | break; 481 | default: 482 | break; 483 | } 484 | 485 | return sb; 486 | } 487 | 488 | /** 489 | *Free a sock which is applied from sockp 490 | */ 491 | int free_sk_to_sockp(struct sock *sk, struct socket_bucket **sbpp) 492 | { 493 | int ret = KCP_ERROR; 494 | struct socket_bucket *p, *sb = NULL; 495 | 496 | SOCKP_LOCK(); 497 | 498 | p = SHASH(sk); 499 | for (; p; p = p->sb_snext) { 500 | 501 | LOOP_COUNT_SAFE_CHECK(p); 502 | 503 | if (SKEY_MATCH(sk, p->sk)) { 504 | 505 | if (!p->sock_in_use) {//can't release it repeatedly! 506 | printk(KERN_ERR "Free sk error, sk is not in use."); 507 | ret = -1; 508 | break; 509 | } 510 | 511 | if ((p->auth_procedure_status >= AUTH_PROCESSING) 512 | && (p->auth_procedure_status != AUTH_SUCCESS)) { 513 | p->sock_close_now = 1; 514 | notify(CONNP_DAEMON_TSKP); //collection at once. 515 | break; 516 | } 517 | 518 | p->auth_procedure_stage = p->auth_procedure_head;//reset 519 | 520 | p->sock_in_use = 0; //clear "in use" tag. 521 | p->last_used_jiffies = lkm_jiffies; 522 | 523 | INSERT_INTO_HLIST(HASH(&p->cliaddr, &p->servaddr), p); 524 | 525 | sb = p; 526 | ret = KCP_OK; 527 | 528 | break; 529 | } 530 | 531 | } 532 | 533 | LOOP_COUNT_RESET(); 534 | 535 | SOCKP_UNLOCK(); 536 | 537 | //Grafted to sock of sockp 538 | if (sb) { 539 | //printk(KERN_ERR "free success!"); 540 | sock_graft(sk, sb->sock); 541 | if (sbpp) 542 | *sbpp = sb; 543 | } 544 | 545 | return ret; 546 | } 547 | 548 | static inline int socket_buckets_pool_resize(void) 549 | { 550 | static int nr_current_connections = 0; 551 | long nr_max_connections = GN("max_connections"); 552 | int i; 553 | 554 | if (nr_max_connections > NR_MAX_OPEN_FDS) 555 | nr_max_connections = NR_MAX_OPEN_FDS; 556 | 557 | if (!nr_current_connections && !nr_max_connections) 558 | return 0; 559 | 560 | if (nr_current_connections != nr_max_connections) { 561 | 562 | if (nr_current_connections) { 563 | SB[nr_current_connections - 1].sb_free_next = SB + (nr_current_connections % NR_MAX_OPEN_FDS); 564 | } 565 | 566 | if (nr_max_connections) { 567 | SB[0].sb_free_prev = SB + nr_max_connections - 1; 568 | SB[nr_max_connections - 1].sb_free_next = SB; 569 | } 570 | 571 | //Close the connections in previous effective pool. 572 | for (i = nr_max_connections; i < nr_current_connections; i++) { 573 | if (SB[i].sb_in_use) { 574 | SB[i].sock_close_now = 1; 575 | } 576 | } 577 | 578 | nr_current_connections = nr_max_connections; 579 | } 580 | 581 | return nr_max_connections; 582 | } 583 | 584 | /** 585 | *Get a empty slot from sockp; 586 | */ 587 | #if LRU 588 | static struct socket_bucket *get_empty_slot(struct sockaddr *cliaddr, struct sockaddr *servaddr) 589 | #else 590 | static struct socket_bucket *get_empty_slot(void) 591 | #endif 592 | { 593 | struct socket_bucket *p; 594 | #if LRU 595 | struct socket_bucket *lru = NULL; 596 | u64 uc = ~0ULL; 597 | #endif 598 | 599 | if (!socket_buckets_pool_resize()) 600 | return NULL; 601 | 602 | p = ht->sb_free_p; 603 | 604 | do { 605 | 606 | LOOP_COUNT_SAFE_CHECK(p); 607 | 608 | if (!p->sb_in_use) { 609 | ht->sb_free_p = p->sb_free_next; 610 | LOOP_COUNT_RESET(); 611 | return p; 612 | } 613 | 614 | #if LRU 615 | /*connpd_fd: -1, was not attached to connpd*/ 616 | if (!p->sock_in_use 617 | && !KEY_MATCH(cliaddr, &p->cliaddr, servaddr, &p->servaddr) 618 | && p->connpd_fd >= 0 619 | && p->uc <= uc) { 620 | lru = p; 621 | uc = p->uc; 622 | } 623 | #endif 624 | 625 | p = p->sb_free_next; 626 | 627 | } while (p != ht->sb_free_p); 628 | 629 | LOOP_COUNT_RESET(); 630 | 631 | #if LRU 632 | if (lru) { 633 | 634 | if (connpd_close_pending_fds_in(lru->connpd_fd) < 0) { 635 | printk(KERN_ERR "Close pending fds buffer overflow!"); 636 | return NULL; 637 | } 638 | 639 | ht->sb_free_p = lru->sb_free_next; 640 | 641 | if (lru->auth_procedure_status != AUTH_NEW) 642 | AUTH_PROCEDURE_DESTROY(lru); 643 | 644 | //It is safe because it is in all link list already. 645 | REMOVE_FROM_HLIST(HASH(&lru->cliaddr, &lru->servaddr), lru); 646 | REMOVE_FROM_SHLIST(SHASH(lru->sk), lru); 647 | REMOVE_FROM_TLIST(lru); 648 | 649 | printk(KERN_WARNING "LRU executed, consider raising the max_connections setting"); 650 | 651 | return lru; 652 | 653 | } 654 | #endif 655 | 656 | return NULL; 657 | } 658 | 659 | /** 660 | *Insert a new socket to sockp. 661 | */ 662 | int insert_sock_to_sockp(struct sockaddr *cliaddr, 663 | struct sockaddr *servaddr, 664 | struct socket *s, int connpd_fd, 665 | sock_create_way_t create_way, 666 | struct socket_bucket **sbpp, 667 | int pre_insert_auth_sock) 668 | { 669 | int ret = 0; 670 | struct socket_bucket *p, *sb = NULL; 671 | 672 | SOCKP_LOCK(); 673 | 674 | //Check if exists 675 | p = SHASH(s->sk); 676 | for (; p; p = p->sb_snext) 677 | if (SKEY_MATCH(s->sk, p->sk)) { 678 | ret = -1; 679 | goto unlock_ret; 680 | } 681 | 682 | #if LRU 683 | if (!(sb = get_empty_slot(cliaddr, servaddr))) 684 | goto unlock_ret; 685 | #else 686 | if (!(sb = get_empty_slot())) 687 | goto unlock_ret; 688 | #endif 689 | 690 | INIT_SB(sb, s, connpd_fd, create_way); 691 | 692 | SOCKADDR_COPY(&sb->cliaddr, cliaddr); 693 | SOCKADDR_COPY(&sb->servaddr, servaddr); 694 | 695 | if (pre_insert_auth_sock) { 696 | sb->auth_procedure_status = AUTH_PROCESSING; 697 | if (create_way != SOCK_PRECONNECT) 698 | sb->sock_in_use = 1; //set in-use flag if sock was connected by normal process. 699 | else //connected by kconnpd. 700 | goto insert_hlist; //prepare for apply. 701 | } else 702 | insert_hlist: 703 | INSERT_INTO_HLIST(HASH(&sb->cliaddr, &sb->servaddr), sb); 704 | 705 | INSERT_INTO_SHLIST(SHASH(sb->sk), sb); 706 | INSERT_INTO_TLIST(sb); 707 | 708 | unlock_ret: 709 | SOCKP_UNLOCK(); 710 | 711 | if (sb) { 712 | if (sbpp) 713 | *sbpp = sb; 714 | ret = 1; 715 | } 716 | 717 | return ret; 718 | } 719 | 720 | int sockp_init() 721 | { 722 | struct socket_bucket *sb_tmp; 723 | 724 | SB = lkmalloc(NR_SOCKET_BUCKET * sizeof(struct socket_bucket)); 725 | if (!SB) { 726 | printk("No momory!"); 727 | return KCP_ERROR; 728 | } 729 | 730 | ht = lkmalloc(sizeof(*ht)); 731 | if (!ht) { 732 | lkmfree(SB); 733 | printk("No memory"); 734 | return KCP_ERROR; 735 | } 736 | 737 | //init sockp freelist. 738 | ht->sb_free_p = sb_tmp = SB; 739 | 740 | while (sb_tmp < SB + NR_SOCKET_BUCKET) { 741 | sb_tmp->sb_free_prev = sb_tmp - 1; 742 | sb_tmp->sb_free_next = sb_tmp + 1; 743 | 744 | spin_lock_init(&sb_tmp->s_lock); 745 | 746 | sb_tmp++; 747 | } 748 | 749 | sb_tmp--; 750 | SB[0].sb_free_prev = sb_tmp; 751 | sb_tmp->sb_free_next = SB; 752 | 753 | SOCKP_LOCK_INIT(); 754 | 755 | if (!sockp_sbs_check_list_init(NR_SOCKET_BUCKET)) { 756 | SOCKP_LOCK_DESTROY(); 757 | lkmfree(ht); 758 | lkmfree(SB); 759 | return 0; 760 | } 761 | 762 | return 1; 763 | } 764 | 765 | /* 766 | *destroy the sockp and the hash table. 767 | */ 768 | void sockp_destroy(void) 769 | { 770 | sockp_sbs_check_list_destroy(); 771 | SOCKP_LOCK_DESTROY(); 772 | lkmfree(ht); 773 | lkmfree(SB); 774 | } 775 | --------------------------------------------------------------------------------