/** * \brief Callback called by NetFilter when a packet with target QUEUE is matched. * * For TCP packet with flags different than SYN, just send it to NuAuth and * accept it. * * For other packet: First of all, fill a structure ::packet_idl (identifier, * timestamp, ...). Try to add the new packet to ::packets_list (fails if the * list is full). Ask an authentication to NuAuth using auth_request_send(), * If the packet can't be sended, remove it from the list. * * \return If an error occurs, returns 0, else returns 1. */ static int treat_packet(struct nfq_handle *qh, struct nfgenmsg *nfmsg, struct nfq_data *nfa, void *data) { packet_idl *current; struct queued_pckt q_pckt; struct nfqnl_msg_packet_hdr *ph; struct timeval timestamp; int ret; #ifdef HAVE_NFQ_INDEV_NAME struct nlif_handle *nlif_handle = (struct nlif_handle *) data; #endif debug_log_printf(DEBUG_AREA_PACKET, DEBUG_LEVEL_VERBOSE_DEBUG, "(*) New packet"); q_pckt.payload_len = nfq_get_payload(nfa, &(q_pckt.payload)); if (q_pckt.payload_len == -1) { log_area_printf(DEBUG_AREA_PACKET, DEBUG_LEVEL_INFO, "Unable to get payload"); return 0; } q_pckt.mark = nfq_get_nfmark(nfa); #ifdef HAVE_NFQ_INDEV_NAME if (!get_interface_information(nlif_handle, &q_pckt, nfa)) { log_area_printf(DEBUG_AREA_PACKET, DEBUG_LEVEL_INFO, "Can not get interfaces information for message"); return 0; } #else snprintf(q_pckt.indev, sizeof(q_pckt.indev), "*"); snprintf(q_pckt.physindev, sizeof(q_pckt.physindev), "*"); snprintf(q_pckt.outdev, sizeof(q_pckt.outdev), "*"); snprintf(q_pckt.physoutdev, sizeof(q_pckt.physoutdev), "*"); #endif ret = nfq_get_timestamp(nfa, ×tamp); if (ret == 0) { q_pckt.timestamp = timestamp.tv_sec; } else { q_pckt.timestamp = time(NULL); } if (look_for_tcp_flags ((unsigned char *) q_pckt.payload, q_pckt.payload_len)) { ph = nfq_get_msg_packet_hdr(nfa); if (ph) { q_pckt.packet_id = ntohl(ph->packet_id); auth_request_send(AUTH_CONTROL, &q_pckt); IPQ_SET_VERDICT(q_pckt.packet_id, NF_ACCEPT); RETURN_NO_LOG 1; } else { log_area_printf(DEBUG_AREA_PACKET, DEBUG_LEVEL_VERBOSE_DEBUG, "Can not get the packet headers"); return 0; } } current = calloc(1, sizeof(packet_idl)); current->nfmark = q_pckt.mark; current->timestamp = q_pckt.timestamp ; current->id = 0; if (current == NULL) { log_area_printf(DEBUG_AREA_MAIN, DEBUG_LEVEL_MESSAGE, "Can not allocate packet_id"); return 0; } #ifdef PERF_DISPLAY_ENABLE gettimeofday(&(current->arrival_time), NULL); #endif /* Get unique identifier of packet in queue */ ph = nfq_get_msg_packet_hdr(nfa); if (ph) { current->id = ntohl(ph->packet_id); } else { free(current); log_area_printf(DEBUG_AREA_PACKET, DEBUG_LEVEL_INFO, "Can not get id for message"); return 0; } /* Try to add the packet to the list */ ret = padd(current); q_pckt.packet_id = current->id; if (ret == 0) { /* send an auth request packet */ if (!auth_request_send(AUTH_REQUEST, &q_pckt)) { int sandf = 0; /* send failure dropping packet */ IPQ_SET_VERDICT(q_pckt.packet_id, NF_DROP); /* we fail to send the packet so we free packet related to current */ /* search and destroy packet by packet_id */ sandf = psearch_and_destroy(q_pckt.packet_id, &(q_pckt.mark)); if (!sandf) { log_area_printf(DEBUG_AREA_MAIN, DEBUG_LEVEL_WARNING, "Packet could not be removed: %u", q_pckt.packet_id); } } } return 1; }
/** * Process NuAuth message of type #AUTH_ANSWER */ int auth_process_answer(char *dgram, int dgram_size) { nuv5_nuauth_decision_response_t *answer; uint32_t nfmark; int sandf; u_int32_t packet_id; int payload_len; int msg_len; /* check packet size */ if (dgram_size < (int) sizeof(nuv4_nuauth_decision_response_t)) { return -1; } answer = (nuv5_nuauth_decision_response_t *) dgram; /* check payload length */ payload_len = ntohs(answer->payload_len); msg_len = payload_len + sizeof(nuv5_nuauth_decision_response_t); if (dgram_size < msg_len) { log_area_printf(DEBUG_AREA_GW, DEBUG_LEVEL_WARNING, "[!] Packet with improper size: payload of %d, received %d (vs %d)", payload_len, dgram_size, (int) (sizeof(nuv5_nuauth_decision_response_t) + payload_len)); return -1; } /* get packet id and user id */ packet_id = ntohl(answer->packet_id); /* search and destroy packet by packet_id */ sandf = psearch_and_destroy(packet_id, &nfmark); if (!sandf) { log_area_printf(DEBUG_AREA_GW | DEBUG_AREA_GW, DEBUG_LEVEL_WARNING, "[!] Packet without a known ID: %u", packet_id); return -1; } switch (answer->decision) { case DECISION_ACCEPT: /* accept packet */ debug_log_printf(DEBUG_AREA_PACKET, DEBUG_LEVEL_VERBOSE_DEBUG, "(*) Accepting packet with id=%u", packet_id); if (nufw_set_mark) { debug_log_printf(DEBUG_AREA_PACKET, DEBUG_LEVEL_VERBOSE_DEBUG, "(*) Marking packet with %d", ntohl(answer->tcmark)); #if HAVE_NFQ_MARK_EXPTIME if (ntohl(answer->expiration) != -1) { IPQ_SET_VWMARK_EXPTIME(packet_id, NF_ACCEPT, answer->tcmark, ntohl(answer->expiration)); } else { IPQ_SET_VWMARK(packet_id, NF_ACCEPT, answer->tcmark); } #else IPQ_SET_VWMARK(packet_id, NF_ACCEPT, answer->tcmark); #endif } else { IPQ_SET_VERDICT(packet_id, NF_ACCEPT); } pckt_tx++; break; case DECISION_REJECT: /* Packet is rejected, ie. dropped and ICMP signalized */ log_area_printf(DEBUG_AREA_PACKET, DEBUG_LEVEL_VERBOSE_DEBUG, "(*) Rejecting %" PRIu32, packet_id); IPQ_SET_VERDICT(packet_id, NF_DROP); if (send_icmp_unreach(dgram + sizeof(nuv5_nuauth_decision_response_t), payload_len) == -1) { log_area_printf(DEBUG_AREA_PACKET, DEBUG_LEVEL_WARNING, "(*) Could not sent ICMP reject for %" PRIu32, packet_id); } break; default: /* drop packet */ debug_log_printf(DEBUG_AREA_PACKET, DEBUG_LEVEL_VERBOSE_DEBUG, "(*) Drop packet %u", packet_id); IPQ_SET_VERDICT(packet_id, NF_DROP); } return msg_len; }