void start_netflow_collection(process_packet_pointer func_ptr) { logger<< log4cpp::Priority::INFO<<"netflow plugin started"; netflow_process_func_ptr = func_ptr; // By default we listen on IPv4 std::string netflow_host = "0.0.0.0"; if (configuration_map.count("netflow_port") != 0) { netflow_port = convert_string_to_integer(configuration_map["netflow_port"]); } if (configuration_map.count("netflow_host") != 0) { netflow_host = configuration_map["netflow_host"]; } if (configuration_map.count("netflow_sampling_ratio") != 0) { sampling_rate = convert_string_to_integer(configuration_map["netflow_sampling_ratio"]); logger<< log4cpp::Priority::INFO<<"We use custom sampling ratio for netflow: "<<sampling_rate; } logger<< log4cpp::Priority::INFO<<"netflow plugin will listen on "<<netflow_host<<":"<<netflow_port<< " udp port"; unsigned int udp_buffer_size = 65536; char udp_buffer[udp_buffer_size]; struct addrinfo hints; memset(&hints, 0, sizeof hints); // Could be AF_INET6 or AF_INET hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_DGRAM; // This flag will generate wildcard IP address if we not specified certain IP address for binding hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; struct addrinfo *servinfo = NULL; const char* address_for_binding = NULL; if (!netflow_host.empty()) { address_for_binding = netflow_host.c_str(); } char port_as_string[16]; sprintf(port_as_string, "%d", netflow_port); int getaddrinfo_result = getaddrinfo(address_for_binding, port_as_string, &hints, &servinfo); if (getaddrinfo_result != 0) { logger<< log4cpp::Priority::ERROR<<"Netflow getaddrinfo function failed with code: "<<getaddrinfo_result<<" please check netflow_host"; exit(1); } int sockfd = socket(servinfo->ai_family, servinfo->ai_socktype, servinfo->ai_protocol); int bind_result = bind(sockfd, servinfo->ai_addr, servinfo->ai_addrlen); if (bind_result) { logger<< log4cpp::Priority::ERROR<<"Can't listen port: "<<netflow_port<<" on host "<<netflow_host<<" errno:"<<errno<< " error: "<<strerror(errno); return; } struct sockaddr_in6 peer; memset(&peer, 0, sizeof(peer)); for (;;) { // This approach provide ability to store both IPv4 and IPv6 client's addresses struct sockaddr_storage client_address; // It's MUST memset(&client_address, 0, sizeof(struct sockaddr_storage)); socklen_t address_len = sizeof(struct sockaddr_storage); int received_bytes = recvfrom(sockfd, udp_buffer, udp_buffer_size, 0, (struct sockaddr *)&client_address, &address_len); if (received_bytes > 0) { // Pass host and port as numbers without any conversion int getnameinfo_flags = NI_NUMERICSERV | NI_NUMERICHOST; char host[NI_MAXHOST]; char service[NI_MAXSERV]; int result = getnameinfo((struct sockaddr *) &client_address, address_len, host, NI_MAXHOST, service, NI_MAXSERV, getnameinfo_flags); // We sill store client's IP address as string for allowing IPv4 and IPv6 processing in same time std::string client_addres_in_string_format = std::string(host); // logger<< log4cpp::Priority::INFO<<"We receive packet from IP: "<<client_addres_in_string_format; // printf("We receive %d\n", received_bytes); process_netflow_packet((u_int8_t*)udp_buffer, received_bytes, client_addres_in_string_format); } else { logger<< log4cpp::Priority::ERROR<<"netflow data receive failed"; } } freeaddrinfo(servinfo); }
void start_netflow_collector(std::string netflow_host, unsigned int netflow_port) { logger << log4cpp::Priority::INFO << "netflow plugin will listen on " << netflow_host << ":" << netflow_port << " udp port"; unsigned int udp_buffer_size = 65536; char udp_buffer[udp_buffer_size]; struct addrinfo hints; memset(&hints, 0, sizeof hints); // Could be AF_INET6 or AF_INET hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_DGRAM; // This flag will generate wildcard IP address if we not specified certain IP address for // binding hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; struct addrinfo* servinfo = NULL; const char* address_for_binding = NULL; if (!netflow_host.empty()) { address_for_binding = netflow_host.c_str(); } char port_as_string[16]; sprintf(port_as_string, "%d", netflow_port); int getaddrinfo_result = getaddrinfo(address_for_binding, port_as_string, &hints, &servinfo); if (getaddrinfo_result != 0) { logger << log4cpp::Priority::ERROR << "Netflow getaddrinfo function failed with code: " << getaddrinfo_result << " please check netflow_host"; exit(1); } int sockfd = socket(servinfo->ai_family, servinfo->ai_socktype, servinfo->ai_protocol); int bind_result = bind(sockfd, servinfo->ai_addr, servinfo->ai_addrlen); if (bind_result) { logger << log4cpp::Priority::ERROR << "Can't listen on port: " << netflow_port << " on host " << netflow_host << " errno:" << errno << " error: " << strerror(errno); return; } struct sockaddr_in6 peer; memset(&peer, 0, sizeof(peer)); /* We should specify timeout there for correct toolkit shutdown */ /* Because otherwise recvfrom will stay in blocked mode forever */ struct timeval tv; tv.tv_sec = 5; /* X Secs Timeout */ tv.tv_usec = 0; // Not init'ing this can cause strange errors setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(struct timeval)); while (true) { // This approach provide ability to store both IPv4 and IPv6 client's addresses struct sockaddr_storage client_address; // It's MUST memset(&client_address, 0, sizeof(struct sockaddr_storage)); socklen_t address_len = sizeof(struct sockaddr_storage); int received_bytes = recvfrom(sockfd, udp_buffer, udp_buffer_size, 0, (struct sockaddr*)&client_address, &address_len); if (received_bytes > 0) { // Pass host and port as numbers without any conversion int getnameinfo_flags = NI_NUMERICSERV | NI_NUMERICHOST; char host[NI_MAXHOST]; char service[NI_MAXSERV]; int result = getnameinfo((struct sockaddr*)&client_address, address_len, host, NI_MAXHOST, service, NI_MAXSERV, getnameinfo_flags); // We sill store client's IP address as string for allowing IPv4 and IPv6 processing in // same time std::string client_addres_in_string_format = std::string(host); // logger<< log4cpp::Priority::INFO<<"We receive packet from IP: // "<<client_addres_in_string_format; // printf("We receive %d\n", received_bytes); process_netflow_packet((u_int8_t*)udp_buffer, received_bytes, client_addres_in_string_format); } else { if (received_bytes == -1) { if (errno == EAGAIN) { // We got timeout, it's OK! } else { logger << log4cpp::Priority::ERROR << "netflow data receive failed"; } } } // Add interruption point for correct application shutdown boost::this_thread::interruption_point(); } freeaddrinfo(servinfo); }