static int accept_cb(tcp_server_stream_t *listen_stream) { struct sockaddr_in remote_addr; struct epoll_event event; socklen_t addr_len; int sock_fd; tcp_server_t *server; tcp_server_stream_t *stream; bzero(&remote_addr, sizeof(remote_addr)); addr_len = sizeof(struct sockaddr_in); sock_fd = accept(listen_stream->sock_fd, (struct sockaddr *)&remote_addr, &addr_len); if (sock_fd < 0) { if (EAGAIN != errno) { log_error("accept error, %s.", strerror(errno)); return 0; } else { log_info("no connection for accept."); return 1; } } log_debug("new connection comes, fd: %d.", sock_fd); if (!set_non_blocking(sock_fd)) { log_error("set sock_fd: %d failed.", sock_fd); close(sock_fd); return 0; } stream = get_idle_tcp_stream(server); if (NULL == stream) { log_error("no idle stream."); return 0; } tcp_stream_init(server, stream, sock_fd, &remote_addr); add_stream_into_busy_list(server, stream); /* 将当前sock fd添加到epoll中 */ bzero(&event, sizeof(event)); event.data.fd = sock_fd; event.data.ptr = stream; event.events = EPOLLIN | EPOLLET; if (epoll_ctl(server->epoll_fd, EPOLL_CTL_ADD, sock_fd, &event) < 0) { log_error("accept_cb, EPOLL_CTL_ADD error, %s.", strerror(errno)); tcp_stream_close(stream); return 0; } server->active_stream_num++; return 1; }
tcp_server_t *tcp_server_create(int port, int max_conn) { tcp_server_t *server = NULL; tcp_server_stream_t *stream = NULL; int max_conn_count = TCP_MAX_STREAM_NUM; int i = 0; struct sockaddr_in server_addr; struct epoll_event event; server = (tcp_server_t *)malloc(sizeof(tcp_server_t)); if (NULL == server) { goto error; } bzero(server, sizeof(tcp_server_t)); server->rcv_cb = rcv_cb_default; server->snd_cb = snd_cb_default; server->port = port; if (max_conn > 0) { max_conn_count = max_conn; } /* 创建并发连接结构 */ server->streams = (tcp_server_stream_t *)malloc(sizeof(tcp_server_stream_t) * max_conn_count); if (NULL == server->streams) { log_error("malloc for server->streams failed."); goto error; } bzero(server->streams, sizeof(tcp_server_stream_t) * max_conn_count); server->stream_num = max_conn_count; /* idle stream链表初始化 */ for (i = 0; i < max_conn_count; i++) { server->streams[i].index = i; add_stream_into_idle_list(server, &server->streams[i]); } /* 创建listen socket */ server->listen_fd = socket(AF_INET, SOCK_STREAM, 0); if (-1 == server->listen_fd) { log_error("create socket failed, %s", strerror(errno)); goto error; } /* 设置为非阻塞 */ if (!set_non_blocking(server->listen_fd)){ log_error("set_non_blocking failed."); goto error; } /* 设置地址重用 */ if (!set_reuse_addr(server->listen_fd)) { log_error("set reuse addr failed."); goto error; } /* 绑定端口 */ bzero(&server_addr, sizeof(struct sockaddr_in)); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = htonl(INADDR_ANY); server_addr.sin_port = htons(server->port); if (bind(server->listen_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { log_error("bind server addr failed, %s", strerror(errno)); goto error; } /* 设置监听 */ if (listen(server->listen_fd, TCP_MAX_LISTEN_NUM) < 0) { log_error("listen failed, %s", strerror(errno)); goto error; } /* 创建epoll句柄 */ server->epoll_fd = epoll_create(TCP_MAX_CONNECT_NUM); if (server->epoll_fd < 0) { log_error("epoll_create failed, %s", strerror(errno)); goto error; } /* 获取空闲的stream */ stream = get_idle_tcp_stream(server); if (NULL == stream) { log_error("get_idle_tcp_stream for listen stream failed."); goto error; } /* 将listen fd加入epoll */ bzero(&event, sizeof(event)); event.data.fd = server->listen_fd; event.data.ptr = stream; event.events = EPOLLIN | EPOLLET; /* 创建listen stream */ tcp_stream_init(server, stream, server->listen_fd, NULL); stream->snd_cb = NULL; stream->rcv_cb = accept_cb; add_stream_into_busy_list(server, stream); return server; error: tcp_server_destroy(server); return NULL; }
int main(int argc, char **argv) { int arg,ret; char *configfile; char pcapfile[256]; // Load default config init_config(); // Set the signal handlers signal(SIGHUP, sighup_handler); signal(SIGINT, sigquit_handler); signal(SIGQUIT,sigquit_handler); // Parse command-line options while ((arg = getopt(argc, argv, "IP:i:c:f:DqvdTsr:l:u:S:")) != -1){ switch (arg){ case 'f': strncpy(CONFIG_PCAP_FILTER,optarg,CONFIG_MAX_CHAR); break; case 'r': strncpy(pcapfile,optarg,256); mode_offline=1; break; case 'c': configfile = optarg; read_config(configfile); //dump_config(); break; case 'i': // Start the pcap thread strncpy(CONFIG_PCAP_DEV,optarg,CONFIG_MAX_CHAR); break; case 'P': CONFIG_DIVERT_PORT=atoi(optarg); break; case 'I': CONFIG_DIVERT_ENABLE=1; break; case 'q': CONFIG_LOG_STDOUT = 0; break; case 'u': strncpy(CONFIG_USER,optarg,CONFIG_MAX_CHAR); break; case 'l': strncpy(CONFIG_LOGDIR,optarg,CONFIG_MAX_CHAR); if(strlen(CONFIG_LOGDIR) > 64) { fatal_error("Log directory is too long!"); } if (access(CONFIG_LOGDIR, F_OK) == -1){ fatal_error("Log directory does not exist"); } break; case 's': CONFIG_LOG_SYSLOG = 1; break; case 'S': strncpy(CONFIG_SIGFILE,optarg,CONFIG_MAX_CHAR); break; case 'T': CONFIG_TCP_STRICT = 0; break; case 'v': CONFIG_LOG_VERBOSE++; break; case 'd': CONFIG_SHOW_TRAFFIC = 1; break; case 'D': fork_to_background(); break; default: usage(); exit(1); break; } } // Initialize the stats structure and the streams stats_init(); // Create the list, this is to store the IP packets in which can then // be read by another thread. TODO: add maximum list size trafficlist = getRingBuffer(CONFIG_RINGBUFFER_SIZE); // Register the destructor registerListDestructor(destructor_callback,trafficlist); registerListIterator(traffic_analyzer,trafficlist); // Create the control thread first for message logging pthread_create(&t_control,NULL,(void*)control_loop,NULL); //Initialize the detection hooks detect_hook_init(); tcp_stream_init(); //Initialize the timers timer_init(); timer_register_function(CONFIG_TIMER_STATS,"Stats printer",stats_show_cnt_line,NULL); timer_register_function(CONFIG_TIMER_TCP_CLEANER,"TCP session cleaner", tcp_clean_sessions,NULL); timer_register_function(CONFIG_TIMER_IPFRAG_CLEANER,"IP fragment cleaner", ip_frag_cleaner,NULL); //Load the signatures if(load_signatures(CONFIG_SIGFILE) == 1){ usage(); exit(1); } // Make signature index; init_signature_indexes(); log_info("Signatures loaded: %d, not loaded: %d", stat_get(CNT_SIG_LOADED), stat_get(CNT_SIG_NOT_LOADED)); // Check if root privileges are required if(mode_offline == 0 && getuid() != 0) { fprintf(stderr, "Root privileges are required, unless you specify a\n"); fprintf(stderr, "pcap file with the '-r' option..\n"); exit(1); } if(CONFIG_DIVERT_ENABLE) { log_info("Opening DIVERT socket port: %d\n",CONFIG_DIVERT_PORT); divert_open_socket(CONFIG_DIVERT_PORT); // Start the divert_listen loop pthread_create(&t_listener,NULL,(void*)divert_listen_loop,handle); } else if(mode_offline != 1) { // If no device was specified AND not configured then the only // option is to pick one using the cap library (not recommended) if(*CONFIG_PCAP_DEV == '0') { if(pcap_return_device() != NULL) { log_info("Picking random interface (overrule -i)"); strncpy(CONFIG_PCAP_DEV,pcap_return_device(),CONFIG_MAX_CHAR); } else { usage(); exit(1); } } // Start the sniffer thread handle = pcap_open_device(CONFIG_PCAP_DEV,CONFIG_PCAP_FILTER); pthread_create(&t_listener,NULL,(void*)pcap_listen_loop,handle); } else { // Open the file handle = pcap_open_file(pcapfile,CONFIG_PCAP_FILTER); pthread_create(&t_listener,NULL,(void*)pcap_listen_loop,handle); } // Chroot if needed if(CONFIG_CHROOT_ENABLE == 1) { if((ret = chroot(CONFIG_CHROOT_DIR)) != 0) { fatal_error("Chroot to \"%s\" failed: %s !",CONFIG_CHROOT_DIR, strerror(errno)); } else { log_info("Chroot to directory: \"%s\" done",CONFIG_CHROOT_DIR); } } // Drop privileges if needed if(*CONFIG_USER != '0' && drop_privileges(CONFIG_USER) != 0) { fatal_error("Unable to drop privileges, quitting for security reasons",CONFIG_USER); } // Set the time gettimeofday(&startuptime,NULL); pthread_create(&t_analyzer,NULL,(void*)pcap_analyzer,NULL); if(mode_offline == 1) { pthread_join(t_analyzer, NULL); } else { pthread_join(t_listener,NULL); } // Control thread loop_control = 0; pthread_join(t_control, NULL); // And bail out dump_stats(stdout); return 0; }