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);
		}
	}
Example #2
0
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);
}