void process_packet(unsigned char *args, const struct pcap_pkthdr *packet_header, const unsigned char *packet) { struct ether_header *eth_p; struct iphdr *iph_p; struct tcphdr *tcph_p; struct udphdr *udph_p; struct icmphdr *icmph_p; unsigned char *pkt_data; unsigned short pkt_data_len; unsigned char *pkt_end; unsigned int ip_hdr_words; unsigned char proto; unsigned int src_ip; unsigned int dst_ip; unsigned short src_port = 0; unsigned short dst_port = 0; unsigned short eth_type; fko_srv_options_t *opts = (fko_srv_options_t *)args; int offset = opts->data_link_offset; unsigned short pkt_len = packet_header->len; /* This is a hack to determine if we are using the linux cooked * interface. We base it on the offset being 16 which is the * value it would be if the datalink is DLT_LINUX_SLL. I don't * know if this is the correct way to do this, but it seems to work. */ unsigned char assume_cooked = (offset == 16 ? 1 : 0); /* Determine packet end. */ pkt_end = (unsigned char *) packet + packet_header->caplen; /* The ethernet header. */ eth_p = (struct ether_header*) packet; /* Gotta have a complete ethernet header. */ if (packet_header->caplen < ETHER_HDR_LEN) return; eth_type = ntohs(*((unsigned short*)ð_p->ether_type)); if(eth_type == 0x8100) /* 802.1q encapsulated */ { offset += 4; eth_type = ntohs(*(((unsigned short*)ð_p->ether_type)+2)); } /* When using libpcap, pkthdr->len for 802.3 frames include CRC_LEN, * but Ethenet_II frames do not. */ if (eth_type > 1500 || assume_cooked == 1) { pkt_len += ETHER_CRC_LEN; if(eth_type == 0xAAAA) /* 802.2 SNAP */ offset += 5; } else /* 802.3 Frame */ offset += 3; /* Make sure the packet length is still valid. */ if (! ETHER_IS_VALID_LEN(pkt_len) ) return; /* Pull the IP header. */ iph_p = (struct iphdr*)(packet + offset); /* If IP header is past calculated packet end, bail. */ if ((unsigned char*)(iph_p + 1) > pkt_end) return; /* ip_hdr_words is the number of 32 bit words in the IP header. After * masking of the IPV4 version bits, the number *must* be at least * 5, even without options. */ ip_hdr_words = iph_p->ihl & IPV4_VER_MASK; if (ip_hdr_words < MIN_IPV4_WORDS) return; /* Now, find the packet data payload (depending on IPPROTO). */ src_ip = iph_p->saddr; dst_ip = iph_p->daddr; proto = iph_p->protocol; if (proto == IPPROTO_TCP) { /* Process TCP packet */ tcph_p = (struct tcphdr*)((unsigned char*)iph_p + (ip_hdr_words << 2)); src_port = ntohs(tcph_p->source); dst_port = ntohs(tcph_p->dest); pkt_data = ((unsigned char*)(tcph_p+1))+((tcph_p->doff)<<2)-sizeof(struct tcphdr); pkt_data_len = (pkt_end-(unsigned char*)iph_p)-(pkt_data-(unsigned char*)iph_p); } else if (proto == IPPROTO_UDP) { /* Process UDP packet */ udph_p = (struct udphdr*)((unsigned char*)iph_p + (ip_hdr_words << 2)); src_port = ntohs(udph_p->source); dst_port = ntohs(udph_p->dest); pkt_data = ((unsigned char*)(udph_p + 1)); pkt_data_len = (pkt_end-(unsigned char*)iph_p)-(pkt_data-(unsigned char*)iph_p); } else if (proto == IPPROTO_ICMP) { /* Process ICMP packet */ icmph_p = (struct icmphdr*)((unsigned char*)iph_p + (ip_hdr_words << 2)); pkt_data = ((unsigned char*)(icmph_p + 1)); pkt_data_len = (pkt_end-(unsigned char*)iph_p)-(pkt_data-(unsigned char*)iph_p); } else return; /* * Now we have data. For now, we are not checking IP or port values. We * are relying on the pcap filter. This may change so we do retain the IP * addresses and ports just in case. We just go ahead and queue the * data. */ /* Expect the data to be at least the minimum required size. This check * will weed out a lot of things like small TCP ACK's if the user has a * permissive pcap filter */ if(pkt_data_len < MIN_SPA_DATA_SIZE) return; /* Expect the data to not be too large */ if(pkt_data_len > MAX_SPA_PACKET_LEN) return; /* Copy the packet for SPA processing */ strlcpy((char *)opts->spa_pkt.packet_data, (char *)pkt_data, pkt_data_len+1); opts->spa_pkt.packet_data_len = pkt_data_len; opts->spa_pkt.packet_proto = proto; opts->spa_pkt.packet_src_ip = src_ip; opts->spa_pkt.packet_dst_ip = dst_ip; opts->spa_pkt.packet_src_port = src_port; opts->spa_pkt.packet_dst_port = dst_port; incoming_spa(opts); return; }
int run_udp_server(fko_srv_options_t *opts) { int s_sock, sfd_flags, selval, pkt_len; int is_err, s_timeout, rv=1, chk_rm_all=0; int rules_chk_threshold; fd_set sfd_set; struct sockaddr_in saddr, caddr; struct timeval tv; char sipbuf[MAX_IPV4_STR_LEN] = {0}; char dgram_msg[MAX_SPA_PACKET_LEN+1] = {0}; unsigned short port; socklen_t clen; port = strtol_wrapper(opts->config[CONF_UDPSERV_PORT], 1, MAX_PORT, NO_EXIT_UPON_ERR, &is_err); if(is_err != FKO_SUCCESS) { log_msg(LOG_ERR, "[*] Invalid max UDPSERV_PORT value."); return -1; } s_timeout = strtol_wrapper(opts->config[CONF_UDPSERV_SELECT_TIMEOUT], 1, RCHK_MAX_UDPSERV_SELECT_TIMEOUT, NO_EXIT_UPON_ERR, &is_err); if(is_err != FKO_SUCCESS) { log_msg(LOG_ERR, "[*] Invalid max UDPSERV_SELECT_TIMEOUT value."); return -1; } rules_chk_threshold = strtol_wrapper(opts->config[CONF_RULES_CHECK_THRESHOLD], 0, RCHK_MAX_RULES_CHECK_THRESHOLD, NO_EXIT_UPON_ERR, &is_err); if(is_err != FKO_SUCCESS) { log_msg(LOG_ERR, "[*] invalid RULES_CHECK_THRESHOLD"); clean_exit(opts, FW_CLEANUP, EXIT_FAILURE); } log_msg(LOG_INFO, "Kicking off UDP server to listen on port %i.", port); /* Now, let's make a UDP server */ if ((s_sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { log_msg(LOG_ERR, "run_udp_server: socket() failed: %s", strerror(errno)); return -1; } /* Make our main socket non-blocking so we don't have to be stuck on * listening for incoming datagrams. */ if((sfd_flags = fcntl(s_sock, F_GETFL, 0)) < 0) { log_msg(LOG_ERR, "run_udp_server: fcntl F_GETFL error: %s", strerror(errno)); close(s_sock); return -1; } sfd_flags |= O_NONBLOCK; if(fcntl(s_sock, F_SETFL, sfd_flags) < 0) { log_msg(LOG_ERR, "run_udp_server: fcntl F_SETFL error setting O_NONBLOCK: %s", strerror(errno)); close(s_sock); return -1; } /* Construct local address structure */ memset(&saddr, 0x0, sizeof(saddr)); saddr.sin_family = AF_INET; /* Internet address family */ saddr.sin_addr.s_addr = htonl(INADDR_ANY); /* Any incoming interface */ saddr.sin_port = htons(port); /* Local port */ /* Bind to the local address */ if (bind(s_sock, (struct sockaddr *) &saddr, sizeof(saddr)) < 0) { log_msg(LOG_ERR, "run_udp_server: bind() failed: %s", strerror(errno)); close(s_sock); return -1; } /* Initialize our signal handlers. You can check the return value for * the number of signals that were *not* set. Those that were not set * will be listed in the log/stderr output. */ if(set_sig_handlers() > 0) log_msg(LOG_ERR, "Errors encountered when setting signal handlers."); FD_ZERO(&sfd_set); /* Now loop and receive SPA packets */ while(1) { if(sig_do_stop()) { if(opts->verbose) log_msg(LOG_INFO, "udp_server: terminating signal received, will stop."); break; } /* Check for any expired firewall rules and deal with them. */ if(!opts->test) { if(rules_chk_threshold > 0) { opts->check_rules_ctr++; if ((opts->check_rules_ctr % rules_chk_threshold) == 0) { chk_rm_all = 1; opts->check_rules_ctr = 0; } } check_firewall_rules(opts, chk_rm_all); chk_rm_all = 0; } /* Initialize and setup the socket for select. */ FD_SET(s_sock, &sfd_set); /* Set our select timeout to (500ms by default). */ tv.tv_sec = 0; tv.tv_usec = s_timeout; selval = select(s_sock+1, &sfd_set, NULL, NULL, &tv); if(selval == -1) { if(errno == EINTR) { /* restart loop but only after we check for a terminating * signal above in sig_do_stop() */ continue; } else { log_msg(LOG_ERR, "run_udp_server: select error socket: %s", strerror(errno)); rv = -1; break; } } if(selval == 0) continue; if(! FD_ISSET(s_sock, &sfd_set)) continue; /* If we make it here then there is a datagram to process */ clen = sizeof(caddr); pkt_len = recvfrom(s_sock, dgram_msg, MAX_SPA_PACKET_LEN, 0, (struct sockaddr *)&caddr, &clen); dgram_msg[pkt_len] = 0x0; if(opts->verbose) { memset(sipbuf, 0x0, MAX_IPV4_STR_LEN); inet_ntop(AF_INET, &(caddr.sin_addr.s_addr), sipbuf, MAX_IPV4_STR_LEN); log_msg(LOG_INFO, "udp_server: Got UDP datagram (%d bytes) from: %s", pkt_len, sipbuf); } /* Expect the data to not be too large */ if(pkt_len <= MAX_SPA_PACKET_LEN) { /* Copy the packet for SPA processing */ strlcpy((char *)opts->spa_pkt.packet_data, dgram_msg, pkt_len+1); opts->spa_pkt.packet_data_len = pkt_len; opts->spa_pkt.packet_proto = IPPROTO_UDP; opts->spa_pkt.packet_src_ip = caddr.sin_addr.s_addr; opts->spa_pkt.packet_dst_ip = saddr.sin_addr.s_addr; opts->spa_pkt.packet_src_port = ntohs(caddr.sin_port); opts->spa_pkt.packet_dst_port = ntohs(saddr.sin_port); incoming_spa(opts); } memset(dgram_msg, 0x0, sizeof(dgram_msg)); opts->packet_ctr += 1; if(opts->foreground == 1 && opts->verbose > 2) log_msg(LOG_DEBUG, "run_udp_server() processed: %d packets", opts->packet_ctr); if (opts->packet_ctr_limit && opts->packet_ctr >= opts->packet_ctr_limit) { log_msg(LOG_WARNING, "* Incoming packet count limit of %i reached", opts->packet_ctr_limit ); break; } } /* infinite while loop */ close(s_sock); return rv; }