void recv_packet(void) { char errbuf[PCAP_ERRBUF_SIZE], pfilter[512], base_filter[256], addr_filter[64], defhost[64]; struct bpf_program filter; struct sockaddr_in lsin; bpf_u_int32 net, mask; int ac_s=0, ret=0; uint32_t foct=0, defport=0; uint8_t msg_type=0, status=0, *ptr=NULL; size_t msg_len=0; xpoll_t spdf[2]; union { void *ptr; uint8_t *cr; uint16_t *r_magic; } r_u; union { recv_udp_workunit_t *u; recv_tcp_workunit_t *t; recv_arp_workunit_t *a; uint8_t *cr; uint32_t *magic; } wku; union { listener_info_t *l; uint8_t *ptr; } l_u; r_queue=fifo_init(); close_output_modules(); close_report_modules(); close_payload_modules(); if (s->verbose > 3) MSG(M_DBG1, "Creating server socket"); CLEAR(defhost); CLEAR(defport); /* heh */ if (sscanf(DEF_LISTENER, "%63[0-9.]:%u", defhost, &defport) != 2) { MSG(M_ERR, "Cant parse default listener data `%s'", DEF_LISTENER); terminate(TERM_ERROR); } if (inet_aton(defhost, &lsin.sin_addr) < 0) { MSG(M_ERR, "Can't parse default host `%s'", defhost); terminate(TERM_ERROR); } if (defport > 0xFFFF) { MSG(M_ERR, "Default listening port is out of range"); terminate(TERM_ERROR); } lsin.sin_port=htons(defport); lsin.sin_addr.s_addr=htonl(INADDR_ANY); if ((ac_s=create_server_socket((const struct sockaddr_in *)&lsin)) < 0) { MSG(M_ERR, "cant create listener socket"); terminate(TERM_ERROR); } if (s->verbose > 3) MSG(M_DBG1, "Waiting for main to connect"); lc_s=wait_for_client(ac_s); if (lc_s < 0) { MSG(M_ERR, "main didnt connect, exiting"); terminate(TERM_ERROR); } if (s->verbose > 3) MSG(M_DBG1, "Got connection"); if (get_singlemessage(lc_s, &msg_type, &status, &ptr, &msg_len) != 1) { MSG(M_ERR, "Unexpected sequence of messages from parent waiting for ident request, exiting"); terminate(TERM_ERROR); } if (msg_type != MSG_IDENT || status != MSG_STATUS_OK) { MSG(M_VERB, "Got an unknown message type `%s' or bad status %d from parent, exiting", strmsgtype(msg_type), status); } if (send_message(lc_s, MSG_IDENTLISTENER, MSG_STATUS_OK, NULL, 0) < 0) { MSG(M_ERR, "Can't send back msgident to parent"); terminate(TERM_ERROR); } if (get_singlemessage(lc_s, &msg_type, &status, &ptr, &msg_len) != 1) { MSG(M_ERR, "Can't read ident ack message from parent, exiting"); terminate(TERM_ERROR); } if (msg_type != MSG_ACK || status != MSG_STATUS_OK) { MSG(M_VERB, "Got an unknown message type `%s' or bad status %d from parent, exiting", strmsgtype(msg_type), status); } if (s->verbose > 3) MSG(M_DBG1, "Sending ready message to parent"); l_u.l=(listener_info_t *)xmalloc(sizeof(listener_info_t)); l_u.l->myaddr=s->vi->myaddr.sin_addr.s_addr; memcpy(l_u.l->hwaddr, s->vi->hwaddr, THE_ONLY_SUPPORTED_HWADDR_LEN); l_u.l->mtu=s->vi->mtu; if (send_message(lc_s, MSG_READY, MSG_STATUS_OK, l_u.ptr, sizeof(listener_info_t)) < 0) { MSG(M_ERR, "Cant send message ready"); terminate(TERM_ERROR); } xfree(l_u.l); /* XXX */ s->_low_ip=0; s->_high_ip=0; s->repeats=0; s->pps=0; s->port_str=NULL; s->ss->syn_key=0; memset(s->ss, 0, sizeof(scan_settings_t)); if (get_singlemessage(lc_s, &msg_type, &status, &(wku.cr), &msg_len) != 1) { MSG(M_ERR, "Unexpected sequence of messages from parent looking for a workunit"); terminate(TERM_ERROR); } if (msg_type == MSG_QUIT || status != MSG_STATUS_OK) terminate(0); if (msg_type != MSG_WORKUNIT) { MSG(M_ERR, "I was expecting a work unit or quit message, i got a `%s' message", strmsgtype(msg_type)); terminate(TERM_ERROR); } assert(wku.magic != NULL); if (*wku.magic == UDP_RECV_MAGIC) { if (s->verbose > 5) MSG(M_DBG2, "Got udp workunit"); s->ss->mode=MODE_UDPSCAN; s->ss->recv_timeout=wku.u->recv_timeout; s->vi->mtu=wku.u->mtu; s->recv_opts=wku.u->recv_opts; } else if (*wku.magic == TCP_RECV_MAGIC) { if (s->verbose > 5) MSG(M_DBG2, "Got tcp workunit"); s->ss->mode=MODE_TCPSCAN; s->ss->recv_timeout=wku.t->recv_timeout; s->vi->mtu=wku.t->mtu; s->recv_opts=wku.t->recv_opts; s->ss->syn_key=wku.t->syn_key; } else if (*wku.magic == ARP_RECV_MAGIC) { if (s->verbose > 5) MSG(M_DBG2, "Got arp workunit"); s->ss->mode=MODE_ARPSCAN; s->ss->recv_timeout=wku.a->recv_timeout; s->vi->mtu=wku.a->mtu; s->recv_opts=wku.a->recv_opts; } else { MSG(M_ERR, "Unknown workunit type `%c'", *wku.cr); terminate(0); } s->mode=s->ss->mode; /* XXX */ if (s->verbose > 3) { if (s->ss->mode == MODE_TCPSCAN) { MSG(M_DBG1, "FROM IPC: TCP scan recv_timeout %d mtu %d recv_opts %x syn_key %.08x", s->ss->recv_timeout, s->vi->mtu, s->recv_opts, s->ss->syn_key); } else if (s->ss->mode == MODE_UDPSCAN) { MSG(M_DBG1, "FROM IPC: UDP scan recv_timeout %d mtu %d recv_opts %x", s->ss->recv_timeout, s->vi->mtu, s->recv_opts); } else if (s->ss->mode == MODE_ARPSCAN) { MSG(M_DBG1, "FROM IPC: ARP scan recv_timeout %d mtu %d recv_opts %x", s->ss->recv_timeout, s->vi->mtu, s->recv_opts); } } if (GET_RETPACKET()) { if (s->verbose > 3) MSG(M_DBG2, "Setting up packet queue"); p_queue=fifo_init(); } if (s->ss->mode == MODE_TCPSCAN || s->ss->mode == MODE_UDPSCAN) { foct=(htonl(s->vi->myaddr.sin_addr.s_addr) >> 24); if (foct == 0x7f) { snprintf(addr_filter, sizeof(addr_filter) -1, "dst %s", s->vi->myaddr_s); } else { snprintf(addr_filter, sizeof(addr_filter) -1, "dst %s and ! src %s", s->vi->myaddr_s, s->vi->myaddr_s); } }
void recv_packet(void) { char errbuf[PCAP_ERRBUF_SIZE], *pfilter=NULL; struct bpf_program filter; bpf_u_int32 net, mask; int ac_s=0, ret=0, worktodo=1; uint8_t msg_type=0, status=0, *ptr=NULL; size_t msg_len=0; xpoll_t spdf[2]; union { recv_workunit_t *r; uint8_t *cr; uint32_t *magic; } wk_u; union { listener_info_t *l; uint8_t *ptr; } l_u; union { drone_version_t *v; uint8_t *ptr; } d_u; drone_version_t dv; struct pcap_stat pcs; r_queue=fifo_init(); close_output_modules(); close_report_modules(); close_payload_modules(); DBG(M_IPC, "creating server socket"); memset(s->ss, 0, sizeof(scan_settings_t)); memset(&dv, 0, sizeof(dv)); d_u.v=&dv; dv.magic=DRONE_MAGIC; dv.maj=DRONE_MAJ; dv.min=DRONE_MIN; recv_stats_t recv_stats; /* heh */ if ((ac_s=socktrans_bind(s->ipcuri)) < 0) { terminate("cant create listener socket"); } DBG(M_IPC, "waiting for main to connect"); parent_sync(); lc_s=socktrans_accept(ac_s, DEF_SOCK_TIMEOUT); if (lc_s < 0) { terminate("main didnt connect, exiting"); } DBG(M_IPC, "got connection"); if (get_singlemessage(lc_s, &msg_type, &status, &ptr, &msg_len) != 1) { terminate("unexpected sequence of messages from parent waiting for ident request, exiting"); } if (msg_type != MSG_IDENT || status != MSG_STATUS_OK) { ERR("got an unknown message type `%s' or bad status %d from parent, exiting", strmsgtype(msg_type), status); } if (send_message(lc_s, MSG_IDENTLISTENER, MSG_STATUS_OK, d_u.ptr, sizeof(drone_version_t)) < 0) { terminate("cant send back msgident to parent"); } if (get_singlemessage(lc_s, &msg_type, &status, &ptr, &msg_len) != 1) { terminate("cant read ident ack message from parent, exiting"); } if (msg_type != MSG_ACK || status != MSG_STATUS_OK) { ERR("got an unknown message type `%s' or bad status %d from parent, exiting", strmsgtype(msg_type), status); } DBG(M_IPC, "sending ready message to parent"); l_u.l=(listener_info_t *)xmalloc(sizeof(listener_info_t)); memcpy(&l_u.l->myaddr, &s->vi[0]->myaddr, sizeof(struct sockaddr_storage)); memcpy(&l_u.l->mymask, &s->vi[0]->mymask, sizeof(struct sockaddr_storage)); memcpy(l_u.l->hwaddr, s->vi[0]->hwaddr, THE_ONLY_SUPPORTED_HWADDR_LEN); l_u.l->mtu=s->vi[0]->mtu; assert(s->interface_str != NULL); if (pcap_lookupnet(s->interface_str, &net, &mask, errbuf) < 0) { ERR("pcap_lookupnet fails, ignoring: %s", errbuf); } if (s->pcap_readfile == NULL) { pdev=pcap_open_live(s->interface_str, /* XXX haha */ s->vi[0]->mtu + 64, (GET_PROMISC() ? 1 : 0), 0, errbuf); if (pdev == NULL) { ERR("pcap open live: %s", errbuf); DBG(M_IPC, "sending ready error message to parent"); if (send_message(lc_s, MSG_READY, MSG_STATUS_ERROR, NULL, 0) < 0) { terminate("cant send message ready error"); } terminate("informed parent, exiting"); } } else { pdev=pcap_open_offline(s->pcap_readfile, errbuf); if (pdev == NULL) { ERR("pcap open offline: %s", errbuf); DBG(M_IPC, "sending ready error message to parent"); if (send_message(lc_s, MSG_READY, MSG_STATUS_ERROR, NULL, 0) < 0) { terminate("cant send message ready error"); } terminate("informed parent, exiting"); } } ret=util_getheadersize(pdev, errbuf); if (ret < 0 || ret > 0xffff) { ERR("error getting link header size: %s", errbuf); DBG(M_IPC, "sending ready error message to parent"); if (send_message(lc_s, MSG_READY, MSG_STATUS_ERROR, NULL, 0) < 0) { terminate("cant send message ready error"); } terminate("informed parent, exiting"); } s->ss->header_len=(uint16_t)ret; if (s->pcap_dumpfile != NULL) { VRB(0, "opening `%s' for pcap log", s->pcap_dumpfile); pdump=pcap_dump_open(pdev, s->pcap_dumpfile); if (pdump == NULL) { ERR("cant log to pcap file `%s'", pcap_geterr(pdev)); DBG(M_IPC, "sending ready error message to parent"); if (send_message(lc_s, MSG_READY, MSG_STATUS_ERROR, NULL, 0) < 0) { terminate("cant send message ready error"); } terminate("informed parent, exiting"); } } else { DBG(M_CLD, "not logging to pcap file"); } if (util_preparepcap(pdev, errbuf) < 0) { ERR("cant setup pcap filedesc to immediate mode: %s", errbuf); DBG(M_IPC, "sending ready error message to parent"); if (send_message(lc_s, MSG_READY, MSG_STATUS_ERROR, NULL, 0) < 0) { terminate("cant send message ready error"); } terminate("informed parent, exiting"); } /* pcap_fd will be -1 for a pcap file */ pcap_fd=pcap_get_selectable_fd(pdev); if (pcap_fd < 0 && s->pcap_readfile == NULL) { ERR("cant get selectable fd from pcap device, exiting"); DBG(M_IPC, "sending ready error message to parent"); if (send_message(lc_s, MSG_READY, MSG_STATUS_ERROR, NULL, 0) < 0) { terminate("sant send message ready error"); } terminate("informed parent, exiting"); } #ifdef PCAP_D_IN if (pcap_setdirection(pdev, PCAP_D_IN) < 0) { ERR("cant set pcap direction to in, exiting"); DBG(M_IPC, "sending ready error message to parent"); if (send_message(lc_s, MSG_READY, MSG_STATUS_ERROR, NULL, 0) < 0) { terminate("sant send message ready error"); } terminate("informed parent, exiting"); } #endif DBG(M_CLD, "listener dropping privs"); if (drop_privs() < 0) { terminate("cant drop privs"); } if (send_message(lc_s, MSG_READY, MSG_STATUS_OK, l_u.ptr, sizeof(listener_info_t)) < 0) { terminate("cant send message ready"); } xfree(l_u.l); /* XXX */ s->ss->syn_key=0; do { if (get_singlemessage(lc_s, &msg_type, &status, &wk_u.cr, &msg_len) != 1) { terminate("unexpected sequence of messages from parent looking for a workunit"); } if (status != MSG_STATUS_OK) { terminate("bad message status %u", status); } if (msg_type == MSG_QUIT) { worktodo=0; break; } else if (msg_type == MSG_WORKUNIT) { ; } else { terminate("unexpected message, expecting workunit or quit message"); } if (msg_len < sizeof(uint32_t)) { terminate("bad message, too short [" STFMT "]", msg_len); } if (msg_len < sizeof(recv_workunit_t)) { terminate("short workunit"); } worktodo=1; DBG(M_WRK, "workunit `%s'", strworkunit(wk_u.cr, msg_len)); s->ss->recv_timeout=wk_u.r->recv_timeout; s->ss->ret_layers=wk_u.r->ret_layers; s->recv_opts=wk_u.r->recv_opts; s->ss->window_size=wk_u.r->window_size; s->ss->syn_key=wk_u.r->syn_key; if (wk_u.r->pcap_len) { if ((msg_len - sizeof(recv_workunit_t)) == wk_u.r->pcap_len) { extract_pcapfilter(wk_u.cr + sizeof(recv_workunit_t), wk_u.r->pcap_len); } else { terminate("pcap option length illegal"); } } switch (*wk_u.magic) { case UDP_RECV_MAGIC: s->ss->mode=MODE_UDPSCAN; break; case TCP_RECV_MAGIC: s->ss->mode=MODE_TCPSCAN; break; case ARP_RECV_MAGIC: s->ss->mode=MODE_ARPSCAN; break; default: terminate("unknown recv workunit type"); break; } DBG(M_IPC, "from ipc, got workunit: %s", strworkunit((const void *)wk_u.cr, msg_len)); if (s->ss->mode == MODE_ARPSCAN) { if (s->ss->header_len != 14) { DBG(M_IPC, "sending msg error"); if (send_message(lc_s, MSG_READY, MSG_STATUS_ERROR, NULL, 0) < 0) { terminate("cant send message ready"); } terminate("wrong linktype for arp scan"); } } if (s->ss->ret_layers > 0) { DBG(M_CLD, "setting up packet queue"); p_queue=fifo_init(); } pfilter=get_pcapfilterstr(); VRB(1, "using pcap filter: `%s'", pfilter); memset(&filter, 0, sizeof(filter)); if (pcap_compile(pdev, &filter, pfilter, 0, net) < 0) { ERR("error compiling filter: %s", pcap_geterr(pdev)); if (send_message(lc_s, MSG_READY, MSG_STATUS_ERROR, NULL, 0) < 0) { ERR("cant send message ready error"); } terminate("cant compile pcap filter"); } if (pcap_setfilter(pdev, &filter) < 0) { ERR("error setting compiled filter: %s", pcap_geterr(pdev)); if (send_message(lc_s, MSG_READY, MSG_STATUS_ERROR, NULL, 0) < 0) { ERR("cant send message ready error"); } terminate("cant set compiled pcap filter"); } pcap_freecode(&filter); if (s->ss->ret_layers > 0) { DBG(M_IPC, "returning whole packet via ipc"); } DBG(M_IPC, "sending ready message to parent"); if (pcap_setnonblock(pdev, 1, errbuf) < 0) { terminate("cant set pcap non-blocking mode"); } if (send_message(lc_s, MSG_READY, MSG_STATUS_OK, NULL, 0) < 0) { terminate("cant send message ready"); } while (1) { spdf[0].fd=lc_s; spdf[1].fd=pcap_fd; /* if pdev is a socket ( ! -1 ) */ if (xpoll(&spdf[0], 2, -1) < 0) { ERR("xpoll fails: %s", strerror(errno)); } if (spdf[1].rw & XPOLL_READABLE) { pcap_dispatch(pdev, 1, parse_packet, NULL); } /* no packets, better drain the queue */ drain_pqueue(); if (spdf[0].rw & XPOLL_READABLE) { if (get_singlemessage(lc_s, &msg_type, &status, &ptr, &msg_len) != 1) { ERR("unexpected sequence of messages from parent in main read loop, exiting"); worktodo=0; break; } if (msg_type == MSG_TERMINATE) { DBG(M_IPC, "parent wants me to stop listening, breaking"); break; } else if (msg_type == MSG_QUIT) { DBG(M_IPC, "Parent wants me to quit, breaking"); worktodo=0; break; } else { ERR("got strange message `%s' from parent, exiting", strmsgtype(msg_type)); worktodo=0; break; } } } memset(&recv_stats, 0, sizeof(recv_stats)); if (pcap_stats(pdev, &pcs) != -1) { recv_stats.packets_recv=pcs.ps_recv; recv_stats.packets_dropped=pcs.ps_drop; recv_stats.packets_dropped=pcs.ps_ifdrop; } if (send_message(lc_s, MSG_WORKDONE, MSG_STATUS_OK, (void *)&recv_stats, sizeof(recv_stats)) < 0) { terminate("cant send workdone message to parent, exiting"); } } while (worktodo); pcap_close(pdev); if (s->pcap_dumpfile) { pcap_dump_close(pdump); } DBG(M_CLD, "listener exiting"); shutdown(lc_s, SHUT_RDWR); close(lc_s); uexit(0); }