inital public release

This commit is contained in:
Zakir Durumeric
2013-08-16 11:12:47 -04:00
commit 490054d239
63 changed files with 9215 additions and 0 deletions

66
src/Makefile Normal file
View File

@ -0,0 +1,66 @@
CC=gcc
CFLAGS=-Wall -pedantic -Wextra -std=gnu99 -I../lib -I./ -Ioutput_modules -O2 -g
LDFLAGS=-g -pthread
LDLIBS= -lpcap -lgmp -lm
TARGETS=zmap
VPATH=../lib:output_modules:probe_modules
PREFIX=/usr/local
INSTALL=install
INSTALLDATA=install -m 644
mandir=/usr/share/man/man1/
bindir=$(PREFIX)/sbin
# Hardening and warnings for building with gcc
#M aybe add -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations
#-Wold-style-definition -Wswitch-enum
GCCWARNINGS = -Wall -fno-strict-aliasing -W -Wfloat-equal -Wundef \
-Wpointer-arith \
-Wwrite-strings -Wredundant-decls -Wchar-subscripts -Wcomment \
-Wformat=2 -Wwrite-strings -Wredundant-decls -Wno-unused-but-set-variable \
-Wnested-externs -Wbad-function-cast -Winit-self \
-Wmissing-field-initializers \
-Waddress -Wmissing-noreturn -Wnormalized=id \
-Woverride-init -Wstrict-overflow=1 -Wextra -Warray-bounds \
-Wstack-protector -Wformat -Wformat-security -Wpointer-sign -Wno-format-nonliteral -Wno-format-y2k
GCCHARDENING=-D_FORTIFY_SOURCE=2 -fstack-protector-all -fwrapv -fPIC --param ssp-buffer-size=1
LDHARDENING=-z relro -z now
EXTRACFLAGS=-g -O2 $(EXTRA_CFLAGS) $(GCCHARDENING) $(GCCWARNINGS) -Werror
EXTRALDFLAGS= $(LDHARDENING)
CFLAGS+=-Wall $(INCLUDE) $(EXTRACFLAGS)
LDFLAGS+=$(EXTRALDFLAGS)
modules=module_tcp_synscan.o module_icmp_echo.o module_udp.o #ADD YOUR MODULE HERE
objects=constraint.o blacklist.o cyclic.o logger.o send.o recv.o state.o monitor.o zopt.o zmap.o random.o output_modules.o module_simple_file.o module_extended_file.o packet.o probe_modules.o ${modules} validate.o rijndael-alg-fst.o get_gateway.o aesrand.o
ifeq ($(REDIS), true)
LDLIBS+=-lhiredis
objects+=module_redis.o redis.o module_ssldb.o
CFLAGS+=-DREDIS
endif
all: $(TARGETS)
$(TARGETS):
$(CC) $(CFLAGS) $(DFLAGS) $(LDFLAGS) $^ -o $@ $(LDLIBS)
zmap: $(objects)
zopt.c zopt.h: zopt.ggo
gengetopt -C --no-help --no-version -i $^ -F $*
install: zmap
$(INSTALL) zmap $(bindir)/zmap
test -d /etc/zmap || (mkdir /etc/zmap && $(INSTALLDATA) ../conf/* /etc/zmap/)
$(INSTALLDATA) ./zmap.1 $(mandir)
echo "\n\n\n\n**************\nSuccess! ZMap is installed. Try running (as root):\nzmap -p 80 -N 10 -B 1M -o -\n**************"
clean:
-rm -f $(objects) $(TARGETS)
.PHONY: install clean

57
src/aesrand.c Normal file
View File

@ -0,0 +1,57 @@
/*
* ZMap Copyright 2013 Regents of the University of Michigan
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*/
#include <stdlib.h>
#include <stdint.h>
#include <assert.h>
#include <string.h>
#include "../lib/rijndael-alg-fst.h"
#include "../lib/random.h"
#include "../lib/logger.h"
#define AES_ROUNDS 10
#define AES_BLOCK_WORDS 4
#define AES_KEY_BYTES 16
#define OUTPUT_BYTES 16
static uint32_t aes_input[AES_BLOCK_WORDS];
static uint32_t aes_sched[(AES_ROUNDS+1)*4];
static uint8_t aes_output[OUTPUT_BYTES];
static int init = 0;
void aesrand_init(uint32_t seed)
{
memset(&aes_input, 0, sizeof(aes_input));
uint8_t key[AES_KEY_BYTES];
if (seed) {
memset(key, 0, AES_KEY_BYTES*sizeof(uint8_t));
memcpy(key, &seed, sizeof(uint32_t));
} else {
if (!random_bytes(key, AES_KEY_BYTES)) {
log_fatal("aesrand", "couldn't get random bytes");
}
}
if (rijndaelKeySetupEnc(aes_sched, key, AES_KEY_BYTES*8) != AES_ROUNDS) {
log_fatal("aesrand", "could not initialize AES key");
}
memset(aes_output, 0, OUTPUT_BYTES*sizeof(uint8_t));
init = 1;
}
uint64_t aesrand_getword(void)
{
assert(init);
memcpy(aes_input, aes_output, sizeof(aes_input));
rijndaelEncrypt(aes_sched, AES_ROUNDS,
(uint8_t *)aes_input, aes_output);
uint64_t retval;
memcpy(&retval, aes_output, sizeof(retval));
return retval;
}

18
src/aesrand.h Normal file
View File

@ -0,0 +1,18 @@
/*
* ZMap Copyright 2013 Regents of the University of Michigan
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*/
#include <stdint.h>
#ifndef _AESRAND_H
#define _AESRAND_H
void aesrand_init(uint32_t seed);
uint64_t aesrand_getword(void);
#endif

184
src/cyclic.c Normal file
View File

@ -0,0 +1,184 @@
/*
* ZMap Copyright 2013 Regents of the University of Michigan
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*/
/*
* cyclic provides an inexpensive approach to iterating over the IPv4 address
* space in a random(-ish) manner such that we connect to every host once in
* a scan execution without having to keep track of the IPs that have been
* scanned or need to be scanned and such that each scan has a different
* ordering. We accomplish this by utilizing a cyclic multiplicative group
* of integers modulo a prime and generating a new primitive root (generator)
* for each scan.
*
* We know that 3 is a generator of (Z mod 2^32 + 15 - {0}, *)
* and that we have coverage over the entire address space because 2**32 + 15
* is prime and ||(Z mod PRIME - {0}, *)|| == PRIME - 1. Therefore, we
* just need to find a new generator (primitive root) of the cyclic group for
* each scan that we perform.
*
* Because generators map to generators over an isomorphism, we can efficiently
* find random primitive roots of our mult. group by finding random generators
* of the group (Zp-1, +) which is isomorphic to (Zp*, *). Specifically the
* generators of (Zp-1, +) are { s | (s, p-1) == 1 } which implies that
* the generators of (Zp*, *) are { d^s | (s, p-1) == 1 }. where d is a known
* generator of the multiplicative group. We efficiently find
* generators of the additive group by precalculating the psub1_f of
* p - 1 and randomly checking random numbers against the psub1_f until
* we find one that is coprime and map it into Zp*. Because
* totient(totient(p)) ~= 10^9, this should take relatively few
* iterations to find a new generator.
*/
#include "cyclic.h"
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <time.h>
#include <assert.h>
#include <string.h>
#include <math.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <gmp.h>
#include "../lib/logger.h"
#include "../lib/blacklist.h"
#include "state.h"
#include "aesrand.h"
#define LSRC "cyclic"
#define PRIME 4294967311 // 2^32 + 15
#define KNOWN_PRIMROOT 3
// distinct prime factors of 2^32 + 15
static const uint64_t psub1_f[] = { 2, 3, 5, 131, 364289 };
// selected primitive root that we'll use as the generator
static uint64_t primroot = 0;
static uint64_t current = 0;
#define COPRIME 1
#define NOT_COPRIME 0
// check whether two integers are coprime
static int check_coprime(uint64_t check)
{
for (unsigned i=0; i < sizeof(psub1_f)/sizeof(psub1_f[0]); i++) {
if (psub1_f[i] > check && !(psub1_f[i] % check)) {
return NOT_COPRIME;
} else if (psub1_f[i] < check && !(check % psub1_f[i])) {
return NOT_COPRIME;
} else if (psub1_f[i] == check) {
return NOT_COPRIME;
}
}
return COPRIME;
}
// find gen of cyclic group Z modulo PRIME
static uint64_t find_primroot(void)
{
// what luck, rand() returns a uint32_t!
uint32_t candidate = (uint32_t) aesrand_getword() & 0xFFFF;
while(check_coprime(candidate) != COPRIME) {
++candidate;
}
// pre-modded result is gigantic so use GMP
mpz_t base, power, prime, primroot;
mpz_init_set_d(base, (double) KNOWN_PRIMROOT);
mpz_init_set_d(power, (double) candidate);
mpz_init_set_d(prime, (double) PRIME);
mpz_init(primroot);
mpz_powm(primroot, base, power, prime);
uint64_t retv = (uint64_t) mpz_get_ui(primroot);
mpz_clear(base);
mpz_clear(power);
mpz_clear(prime);
mpz_clear(primroot);
return retv;
}
int cyclic_init(uint32_t primroot_, uint32_t current_)
{
assert(!(!primroot_ && current_));
if (zconf.use_seed) {
aesrand_init(zconf.seed+1);
} else {
aesrand_init(0);
}
if (!primroot_) {
do {
primroot = find_primroot();
} while (primroot >= (1LL << 32));
log_debug(LSRC, "primitive root: %lld", primroot);
current = (uint32_t) aesrand_getword() & 0xFFFF;
log_debug(LSRC, "starting point: %lld", current);
} else {
primroot = primroot_;
log_debug(LSRC, "primitive root %lld specified by caller",
primroot);
if (!current_) {
current = (uint32_t) aesrand_getword() & 0xFFFF;
log_debug(LSRC, "no cyclic starting point, "
"selected random startpoint: %lld",
current);
} else {
current = current_;
log_debug(LSRC, "starting point %lld specified by caller",
current);
}
}
zconf.generator = primroot;
if (blacklist_init_from_files(zconf.whitelist_filename,
zconf.blacklist_filename)) {
return -1;
}
// make sure current is an allowed ip
cyclic_get_next_ip();
return 0;
}
uint32_t cyclic_get_curr_ip(void)
{
return (uint32_t) current;
}
uint32_t cyclic_get_primroot(void)
{
return (uint32_t) primroot;
}
static inline uint32_t cyclic_get_next_elem(void)
{
do {
current *= primroot;
current %= PRIME;
} while (current >= (1LL << 32));
return (uint32_t) current;
}
uint32_t cyclic_get_next_ip(void)
{
while (1) {
uint32_t candidate = cyclic_get_next_elem();
if (!blacklist_is_allowed(candidate)) {
zsend.blacklisted++;
} else {
return candidate;
}
}
}

25
src/cyclic.h Normal file
View File

@ -0,0 +1,25 @@
/*
* ZMap Copyright 2013 Regents of the University of Michigan
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*/
#include <stdint.h>
#ifndef _CYCLIC_H
#define _CYCLIC_H
int cyclic_init(uint32_t, uint32_t);
// get next IP address to scan
uint32_t cyclic_get_next_ip(void);
// what IP address was returned last
uint32_t cyclic_get_curr_ip(void);
// what primitive root was generated for this current scan
uint32_t cyclic_get_primroot(void);
#endif

237
src/get_gateway.c Normal file
View File

@ -0,0 +1,237 @@
/*
* ZMap Copyright 2013 Regents of the University of Michigan
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <assert.h>
#include <netinet/in.h>
#include <net/if.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include "../lib/logger.h"
int read_nl_sock(int sock, char *buf, int buf_len)
{
int msg_len = 0;
char *pbuf = buf;
do {
int len = recv(sock, pbuf, buf_len - msg_len, 0);
if (len <= 0) {
log_debug("get-gw", "recv failed: %s", strerror(errno));
return -1;
}
struct nlmsghdr *nlhdr = (struct nlmsghdr *)pbuf;
if (NLMSG_OK(nlhdr, ((unsigned int)len)) == 0 ||
nlhdr->nlmsg_type == NLMSG_ERROR) {
log_debug("get-gw", "recv failed: %s", strerror(errno));
return -1;
}
if (nlhdr->nlmsg_type == NLMSG_DONE) {
break;
} else {
msg_len += len;
pbuf += len;
}
if ((nlhdr->nlmsg_flags & NLM_F_MULTI) == 0) {
break;
}
} while (1);
return msg_len;
}
int send_nl_req(uint16_t msg_type, uint32_t seq,
void *payload, uint32_t payload_len)
{
int sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
if (sock < 0) {
log_error("get-gw", "unable to get socket: %s", strerror(errno));
return -1;
}
if (NLMSG_SPACE(payload_len) < payload_len) {
// Integer overflow
return -1;
}
struct nlmsghdr *nlmsg;
nlmsg = malloc(NLMSG_SPACE(payload_len));
if (!nlmsg) {
return -1;
}
memset(nlmsg, 0, sizeof(nlmsg));
memcpy(NLMSG_DATA(nlmsg), payload, payload_len);
nlmsg->nlmsg_type = msg_type;
nlmsg->nlmsg_len = NLMSG_LENGTH(payload_len);
nlmsg->nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;
nlmsg->nlmsg_seq = seq;
nlmsg->nlmsg_pid = getpid();
if (send(sock, nlmsg, nlmsg->nlmsg_len, 0) < 0) {
log_error("get-gw", "failure sending: %s", strerror(errno));
return -1;
}
free(nlmsg);
return sock;
}
int get_hw_addr(struct in_addr *gw_ip, char *iface, unsigned char *hw_mac)
{
char buf[8192];
struct ndmsg req;
struct nlmsghdr *nlhdr;
if (!gw_ip || !hw_mac) {
return -1;
}
// Send RTM_GETNEIGH request
req.ndm_family = AF_INET;
req.ndm_ifindex = if_nametoindex(iface);
req.ndm_state = NUD_REACHABLE;
req.ndm_type = NDA_LLADDR;
int sock = send_nl_req(RTM_GETNEIGH, 1, &req, sizeof(req));
// Read responses
unsigned nl_len = read_nl_sock(sock, buf, sizeof(buf));
if (nl_len <= 0) {
return -1;
}
// Parse responses
nlhdr = (struct nlmsghdr *)buf;
while (NLMSG_OK(nlhdr, nl_len)) {
struct rtattr *rt_attr;
struct rtmsg *rt_msg;
int rt_len;
unsigned char mac[6];
struct in_addr dst_ip;
int correct_ip = 0;
rt_msg = (struct rtmsg *) NLMSG_DATA(nlhdr);
if ((rt_msg->rtm_family != AF_INET)) {
return -1;
}
rt_attr = (struct rtattr *) RTM_RTA(rt_msg);
rt_len = RTM_PAYLOAD(nlhdr);
while (RTA_OK(rt_attr, rt_len)) {
switch (rt_attr->rta_type) {
case NDA_LLADDR:
assert(RTA_PAYLOAD(rt_attr) == IFHWADDRLEN);
memcpy(mac, RTA_DATA(rt_attr), IFHWADDRLEN);
break;
case NDA_DST:
assert(RTA_PAYLOAD(rt_attr) == sizeof(dst_ip));
memcpy(&dst_ip, RTA_DATA(rt_attr), sizeof(dst_ip));
if (memcmp(&dst_ip, gw_ip, sizeof(dst_ip)) == 0) {
correct_ip = 1;
}
break;
}
rt_attr = RTA_NEXT(rt_attr, rt_len);
}
if (correct_ip) {
memcpy(hw_mac, mac, IFHWADDRLEN);
return 0;
}
nlhdr = NLMSG_NEXT(nlhdr, nl_len);
}
return -1;
}
// gw and iface[IF_NAMESIZE] MUST be allocated
int get_default_gw(struct in_addr *gw, char *iface)
{
struct rtmsg req;
unsigned int nl_len;
char buf[8192];
struct nlmsghdr *nlhdr;
if (!gw || !iface) {
return -1;
}
// Send RTM_GETROUTE request
memset(&req, 0, sizeof(req));
int sock = send_nl_req(RTM_GETROUTE, 0, &req, sizeof(req));
// Read responses
nl_len = read_nl_sock(sock, buf, sizeof(buf));
if (nl_len <= 0) {
return -1;
}
// Parse responses
nlhdr = (struct nlmsghdr *)buf;
while (NLMSG_OK(nlhdr, nl_len)) {
struct rtattr *rt_attr;
struct rtmsg *rt_msg;
int rt_len;
int has_gw = 0;
rt_msg = (struct rtmsg *) NLMSG_DATA(nlhdr);
if ((rt_msg->rtm_family != AF_INET) || (rt_msg->rtm_table != RT_TABLE_MAIN)) {
return -1;
}
rt_attr = (struct rtattr *) RTM_RTA(rt_msg);
rt_len = RTM_PAYLOAD(nlhdr);
while (RTA_OK(rt_attr, rt_len)) {
switch (rt_attr->rta_type) {
case RTA_OIF:
if_indextoname(*(int *) RTA_DATA(rt_attr), iface);
break;
case RTA_GATEWAY:
gw->s_addr = *(unsigned int *) RTA_DATA(rt_attr);
has_gw = 1;
break;
}
rt_attr = RTA_NEXT(rt_attr, rt_len);
}
if (has_gw) {
return 0;
}
nlhdr = NLMSG_NEXT(nlhdr, nl_len);
}
return -1;
}
// Returns the first IP address for a given iface
int get_iface_ip(char *iface, struct in_addr *ip)
{
int sock;
struct ifreq ifr;
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0) {
log_error("get-gw", "failure opening socket: %s", strerror(errno));
return -1;
}
ifr.ifr_addr.sa_family = AF_INET;
strncpy(ifr.ifr_name, iface, IFNAMSIZ-1);
if (ioctl(sock, SIOCGIFADDR, &ifr) < 0) {
log_error("get-gw", "ioctl failure: %s", strerror(errno));
close(sock);
return -1;
}
close(sock);
memcpy(ip, &((struct sockaddr_in*)&ifr.ifr_addr)->sin_addr, sizeof(*ip));
return 0;
}

18
src/get_gateway.h Normal file
View File

@ -0,0 +1,18 @@
/*
* ZMap Copyright 2013 Regents of the University of Michigan
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*/
#ifndef _GET_GATEWAY_H
#define _GET_GATEWAY_H
#include <netinet/in.h>
int get_hw_addr(struct in_addr *gw_ip, char *iface, unsigned char *hw_mac);
int get_default_gw(struct in_addr *gw, char *iface);
int get_iface_ip(char *iface, struct in_addr *ip);
#endif

231
src/monitor.c Normal file
View File

@ -0,0 +1,231 @@
/*
* ZMap Copyright 2013 Regents of the University of Michigan
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*/
// module responsible for printing on-screen updates during the scan process
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <math.h>
#include "recv.h"
#include "monitor.h"
#include "state.h"
#include "../lib/logger.h"
#define UPDATE_INTERVAL 1 //seconds
static double last_now = 0.0;
static uint32_t last_sent = 0;
static uint32_t last_rcvd = 0;
static uint32_t last_drop = 0;
static uint32_t last_failures = 0;
static double min_d(double array[], int n)
{
double value=INFINITY;
for (int i=0; i<n; i++) {
if (array[i] < value) {
value = array[i];
}
}
return value;
}
// pretty print elapsed (or estimated) number of seconds
static void time_string(uint32_t time, int est, char *buf, size_t len)
{
int y = time / 31556736;
int d = (time % 31556736) / 86400;
int h = (time % 86400) / 3600;
int m = (time % 3600) / 60;
int s = time % 60;
if (est) {
if (y > 0) {
snprintf(buf, len, "%d years", y);
} else if (d > 9) {
snprintf(buf, len, "%dd", d);
} else if (d > 0) {
snprintf(buf, len, "%dd%02dh", d, h);
} else if (h > 9) {
snprintf(buf, len, "%dh", h);
} else if (h > 0) {
snprintf(buf, len, "%dh%02dm", h, m);
} else if (m > 9) {
snprintf(buf, len, "%dm", m);
} else if (m > 0) {
snprintf(buf, len, "%dm%02ds", m, s);
} else {
snprintf(buf, len, "%ds", s);
}
} else {
if (d > 0) {
snprintf(buf, len, "%dd%d:%02d:%02d", d, h, m, s);
} else if (h > 0) {
snprintf(buf, len, "%d:%02d:%02d", h, m, s);
} else {
snprintf(buf, len, "%d:%02d", m, s);
}
}
}
// pretty print quantities
static void number_string(uint32_t n, char *buf, size_t len)
{
int figs = 0;
if (n < 1000) {
snprintf(buf, len, "%u ", n);
} else if (n < 1000000) {
if (n < 10000) {
figs = 2;
} else if (n < 100000) {
figs = 1;
}
snprintf(buf, len, "%0.*f K", figs, (float)n/1000.);
} else {
if (figs < 10000000) {
figs = 2;
} else if (figs < 100000000) {
figs = 1;
}
snprintf(buf, len, "%0.*f M", figs, (float)n/1000000.);
}
}
// estimate time remaining time based on config and state
double compute_remaining_time(double age)
{
if (!zsend.complete) {
double remaining[] = {INFINITY, INFINITY, INFINITY};
if (zsend.targets) {
double done = (double)zsend.sent/zsend.targets;
remaining[0] = (1. - done)*(age/done) + zconf.cooldown_secs;
}
if (zconf.max_runtime) {
remaining[1] = (zconf.max_runtime - age)+zconf.cooldown_secs;
}
if (zconf.max_results) {
double done = (double)zrecv.success_unique/zconf.max_results;
remaining[2] = (1. - done)*(age/done);
}
return min_d(remaining, sizeof(remaining)/sizeof(double));
} else {
return zconf.cooldown_secs - (now() - zsend.finish);
}
}
static void monitor_update(void)
{
if (last_now > 0.0) {
double age = now() - zsend.start;
double delta = now() - last_now;
double remaining_secs = compute_remaining_time(age);
double percent_complete = 100.*age/(age + remaining_secs);
// ask pcap for fresh values
recv_update_pcap_stats();
// format times for display
char time_left[20];
if (age < 5) {
time_left[0] = '\0';
} else {
char buf[20];
time_string((int)remaining_secs, 1, buf, sizeof(buf));
snprintf(time_left, sizeof(time_left), " (%s left)", buf);
}
char time_past[20];
time_string((int)age, 0, time_past, sizeof(time_past));
char send_rate[20], send_avg[20],
recv_rate[20], recv_avg[20],
pcap_drop[20], pcap_drop_avg[20];
// recv stats
number_string((zrecv.success_unique - last_rcvd)/delta,
recv_rate, sizeof(recv_rate));
number_string((zrecv.success_unique/age), recv_avg, sizeof(recv_avg));
// dropped stats
number_string((zrecv.pcap_drop + zrecv.pcap_ifdrop - last_drop)/delta,
pcap_drop, sizeof(pcap_drop));
number_string(((zrecv.pcap_drop + zrecv.pcap_ifdrop)/age),
pcap_drop_avg, sizeof(pcap_drop_avg));
// Warn if we drop > 5% of our average receive rate
uint32_t drop_rate = (uint32_t)((zrecv.pcap_drop + zrecv.pcap_ifdrop - last_drop) / delta);
if (drop_rate > (uint32_t)((zrecv.success_unique - last_rcvd) / delta) / 20) {
log_warn("monitor", "Dropped %d packets in the last second, (%d total dropped (pcap: %d + iface: %d))",
drop_rate, zrecv.pcap_drop + zrecv.pcap_ifdrop, zrecv.pcap_drop, zrecv.pcap_ifdrop);
}
// Warn if we fail to send > 1% of our average send rate
uint32_t fail_rate = (uint32_t)((zsend.sendto_failures - last_failures) / delta); // failures/sec
if (fail_rate > ((zsend.sent / age) / 100)) {
log_warn("monitor", "Failed to send %d packets/sec (%d total failures)",
fail_rate, zsend.sendto_failures);
}
if (!zsend.complete) {
// main display (during sending)
number_string((zsend.sent - last_sent)/delta,
send_rate, sizeof(send_rate));
number_string((zsend.sent/age), send_avg, sizeof(send_avg));
fprintf(stderr,
"%5s %0.0f%%%s; send: %u %sp/s (%sp/s avg); "
"recv: %u %sp/s (%sp/s avg); "
"drops: %sp/s (%sp/s avg); "
"hits: %0.2f%%\n",
time_past,
percent_complete,
time_left,
zsend.sent,
send_rate,
send_avg,
zrecv.success_unique,
recv_rate,
recv_avg,
pcap_drop,
pcap_drop_avg,
zrecv.success_unique*100./zsend.sent);
} else {
// alternate display (during cooldown)
number_string((zsend.sent/(zsend.finish - zsend.start)), send_avg, sizeof(send_avg));
fprintf(stderr,
"%5s %0.0f%%%s; send: %u done (%sp/s avg); "
"recv: %u %sp/s (%sp/s avg); "
"drops: %sp/s (%sp/s avg); "
"hits: %0.2f%%\n",
time_past,
percent_complete,
time_left,
zsend.sent,
send_avg,
zrecv.success_unique,
recv_rate,
recv_avg,
pcap_drop,
pcap_drop_avg,
zrecv.success_unique*100./zsend.sent);
}
}
last_now = now();
last_sent = zsend.sent;
last_rcvd = zrecv.success_unique;
last_drop = zrecv.pcap_drop + zrecv.pcap_ifdrop;
last_failures = zsend.sendto_failures;
}
void monitor_run(void)
{
while (!(zsend.complete && zrecv.complete)) {
monitor_update();
sleep(UPDATE_INTERVAL);
}
}

14
src/monitor.h Normal file
View File

@ -0,0 +1,14 @@
/*
* ZMap Copyright 2013 Regents of the University of Michigan
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*/
#ifndef _MONITOR_H
#define _MONITOR_H
void monitor_run();
#endif

View File

@ -0,0 +1,109 @@
/*
* ZMap Copyright 2013 Regents of the University of Michigan
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <assert.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "../../lib/logger.h"
#include "output_modules.h"
static FILE *file = NULL;
#define UNUSED __attribute__((unused))
int extendedfile_init(struct state_conf *conf)
{
assert(conf);
if (conf->output_filename) {
if (!strcmp(conf->output_filename, "-")) {
file = stdout;
} else {
if (!(file = fopen(conf->output_filename, "w"))) {
perror("Couldn't open output file");
exit(EXIT_FAILURE);
}
}
fprintf(file, "response, saddr, daddr, sport, "
"dport, seq, ack, in_cooldown, is_repeat, timestamp\n");
}
return EXIT_SUCCESS;
}
static void fprint_tv(FILE *f, struct timeval *tv)
{
char time_string[40];
struct tm *ptm = localtime(&tv->tv_sec);
strftime(time_string, sizeof (time_string),
"%Y-%m-%d %H:%M:%S", ptm);
long milliseconds = tv->tv_usec / 1000;
fprintf(f, "%s.%03ld\n", time_string, milliseconds);
}
int extendedfile_ip(ipaddr_n_t saddr, ipaddr_n_t daddr,
const char *response_type, int is_repeat,
int in_cooldown, const u_char *packet, size_t buflen)
{
struct iphdr *ip_hdr = (struct iphdr *)&packet[sizeof(struct ethhdr)];
if (buflen < (sizeof(struct ethhdr) + ip_hdr->ihl*4 + sizeof(struct tcphdr)))
return EXIT_FAILURE;
struct tcphdr *tcp = (struct tcphdr *)((char *)ip_hdr + ip_hdr->ihl * 4);
if (file) {
struct in_addr addr;
addr.s_addr = saddr;
// inet_ntoa returns a <<const>> char *
fprintf(file, "%s, %s, ",
response_type,
inet_ntoa(addr));
addr.s_addr = daddr;
fprintf(file, "%s, %u, %u, %u, %u, %i, %i,",
inet_ntoa(addr),
ntohs(tcp->source),
ntohs(tcp->dest),
ntohl(tcp->seq),
ntohl(tcp->ack_seq),
in_cooldown,
is_repeat);
struct timeval t;
gettimeofday(&t, NULL);
fprint_tv(file, &t);
fflush(file);
}
return EXIT_SUCCESS;
}
int extendedfile_close(UNUSED struct state_conf* c,
UNUSED struct state_send* s, UNUSED struct state_recv* r)
{
if (file) {
fflush(file);
fclose(file);
}
return EXIT_SUCCESS;
}
output_module_t module_extended_file = {
.name = "extended_file",
.init = &extendedfile_init,
.start = NULL,
.update = NULL,
.update_interval = 0,
.close = &extendedfile_close,
.success_ip = &extendedfile_ip,
.other_ip = &extendedfile_ip
};

View File

@ -0,0 +1,20 @@
/*
* ZMap Copyright 2013 Regents of the University of Michigan
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*/
#include <output_modules.h>
int extendedfile_init(struct state_conf *conf);
int extendedfile_ip(ipaddr_n_t saddr, ipaddr_n_t daddr,
port_n_t sport, port_n_t dport, struct timeval* t,
const char *response_type, int is_repeat,
int in_cooldown, const u_char *packet);
int extendedfile_close(struct state_conf* c, struct state_send* s,
struct state_recv* r);

View File

@ -0,0 +1,96 @@
/*
* ZMap Copyright 2013 Regents of the University of Michigan
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "../../lib/zdlibc/logger.h"
#include "../../lib/zdlibc/redis.h"
#include "output_modules.h"
#define UNUSED __attribute__((unused))
typedef struct scannable_t {
in_addr_t ip_address;
uint8_t source;
} scannable_t;
#define QUEUE_NAME "zmap_results"
#define BUFFER_SIZE 500
#define SOURCE_ZMAP 0
static scannable_t* buffer;
static int buffer_fill = 0;
int redismodule_init(UNUSED struct state_conf *conf)
{
buffer = calloc(BUFFER_SIZE, sizeof(scannable_t));
assert(buffer);
buffer_fill = 0;
return redis_init();
}
int redismodule_flush(void)
{
if (redis_lpush(QUEUE_NAME, buffer,
buffer_fill, sizeof(scannable_t))) {
return EXIT_FAILURE;
}
buffer_fill = 0;
return EXIT_SUCCESS;
}
int redismodule_newip(ipaddr_n_t saddr, UNUSED ipaddr_n_t daddr,
UNUSED port_n_t sport, UNUSED port_n_t dport,
UNUSED const char *response_type, int is_repeat,
UNUSED int in_cooldown, UNUSED const u_char *packet)
{
if (!is_repeat) {
buffer[buffer_fill].ip_address = saddr;
buffer[buffer_fill].source = SOURCE_ZMAP;
if (++buffer_fill == BUFFER_SIZE) {
if (redismodule_flush()) {
return EXIT_FAILURE;
}
}
}
return EXIT_SUCCESS;
}
int redismodule_close(UNUSED struct state_conf* c,
UNUSED struct state_send* s,
UNUSED struct state_recv* r)
{
if (redismodule_flush()) {
return EXIT_FAILURE;
}
if (redis_close()) {
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
output_module_t module_redis = {
.name = "redis",
.init = &redismodule_init,
.start = NULL,
.update = NULL,
.update_interval = 0,
.close = &redismodule_close,
.success_ip = &redismodule_newip,
.other_ip = NULL
};

View File

@ -0,0 +1,19 @@
/*
* ZMap Copyright 2013 Regents of the University of Michigan
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*/
#include <output_modules.h>
int redismodule_init(struct state_conf *conf);
int redismodule_newip(ipaddr_n_t saddr, ipaddr_n_t daddr,
port_n_t sport, port_n_t dport, struct timeval* t,
const char *response_type, int is_repeat,
int in_cooldown, const u_char *packet);
int redismodule_close(struct state_conf* c,
struct state_send* s, struct state_recv* r);

View File

@ -0,0 +1,75 @@
/*
* ZMap Copyright 2013 Regents of the University of Michigan
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*/
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <assert.h>
#include <logger.h>
#include "output_modules.h"
#define UNUSED __attribute__((unused))
static FILE *file = NULL;
int simplefile_init(struct state_conf *conf)
{
assert(conf);
if (conf->output_filename) {
if (!strcmp(conf->output_filename, "-")) {
file = stdout;
} else {
if (!(file = fopen(conf->output_filename, "w"))) {
perror("Couldn't open output file");
exit(EXIT_FAILURE);
}
}
}
return EXIT_SUCCESS;
}
int simplefile_synack_newip(ipaddr_n_t saddr, UNUSED ipaddr_n_t daddr,
UNUSED const char *response_type,
int is_repeat, UNUSED int in_cooldown, UNUSED const u_char *packet,
UNUSED size_t buflen)
{
if (file && !is_repeat) {
struct in_addr addr;
addr.s_addr = saddr;
fprintf(file, "%s\n", inet_ntoa(addr));
}
fflush(file);
return EXIT_SUCCESS;
}
int simplefile_close(UNUSED struct state_conf* c,
UNUSED struct state_send* s,
UNUSED struct state_recv* r)
{
if (file) {
fflush(file);
fclose(file);
}
return EXIT_SUCCESS;
}
output_module_t module_simple_file = {
.name = "simple_file",
.init = &simplefile_init,
.start = NULL,
.update = NULL,
.update_interval = 0,
.close = &simplefile_close,
.success_ip = &simplefile_synack_newip,
.other_ip = NULL,
};

View File

@ -0,0 +1,54 @@
/*
* ZMap Copyright 2013 Regents of the University of Michigan
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*/
#include <stdio.h>
#include <string.h>
#include "output_modules.h"
extern output_module_t module_simple_file;
extern output_module_t module_extended_file;
// ADD YOUR MODULE HERE
#ifdef REDIS
extern output_module_t module_redis;
extern output_module_t module_ssldbfeed;
#endif
output_module_t* output_modules[] = {
&module_simple_file,
&module_extended_file,
#ifdef REDIS
&module_redis,
&module_ssldbfeed,
#endif
// ADD YOUR MODULE HERE
};
output_module_t* get_output_module_by_name(const char* name)
{
int num_modules = (int) (sizeof(output_modules)/sizeof(output_modules[0]));
for (int i=0; i < num_modules; i++) {
if (!strcmp(output_modules[i]->name, name)) {
return output_modules[i];
}
}
return NULL;
}
void print_output_modules(void)
{
int num_modules = (int) (sizeof(output_modules)/sizeof(output_modules[0]));
for (int i=0; i < num_modules; i++) {
printf("%s\n", output_modules[i]->name);
}
}

View File

@ -0,0 +1,44 @@
/*
* ZMap Copyright 2013 Regents of the University of Michigan
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*/
#ifndef HEADER_OUTPUT_MODULES_H
#define HEADER_OUTPUT_MODULES_H
#include "../state.h"
// called at scanner initialization
typedef int (*output_init_cb)(struct state_conf *);
// called on packet receipt
typedef int (*output_packet_cb)(ipaddr_n_t src_ip, ipaddr_n_t dst_ip,
const char* response_type,
int is_repeat, int in_cooldown,
const u_char* packetbuf, size_t buflen);
// called periodically during the scan
typedef int (*output_update_cb)(struct state_conf*, struct state_send*, struct state_recv*);
typedef struct output_module {
const char *name;
unsigned update_interval;
output_init_cb init;
output_update_cb start;
output_update_cb update;
output_update_cb close;
output_packet_cb success_ip;
output_packet_cb other_ip;
} output_module_t;
output_module_t* get_output_module_by_name(const char*);
void print_output_modules(void);
#endif // HEADER_OUTPUT_MODULES_H

View File

@ -0,0 +1,219 @@
/*
* ZMap Copyright 2013 Regents of the University of Michigan
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*/
// probe module for performing ICMP echo request (ping) scans
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <time.h>
#include <unistd.h>
#include <string.h>
#include <netinet/ether.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "probe_modules.h"
#include "packet.h"
#include "validate.h"
probe_module_t module_icmp_echo;
int icmp_echo_init_perthread(void* buf, macaddr_t *src,
macaddr_t *gw, __attribute__((unused)) port_h_t dst_port)
{
memset(buf, 0, MAX_PACKET_SIZE);
struct ethhdr *eth_header = (struct ethhdr *)buf;
make_eth_header(eth_header, src, gw);
struct iphdr *ip_header = (struct iphdr*)(&eth_header[1]);
uint16_t len = htons(sizeof(struct iphdr) + sizeof(struct icmp) - 8);
make_ip_header(ip_header, IPPROTO_ICMP, len);
struct icmp *icmp_header = (struct icmp*)(&ip_header[1]);
make_icmp_header(icmp_header);
return EXIT_SUCCESS;
}
int icmp_echo_make_packet(void *buf, ipaddr_n_t src_ip, ipaddr_n_t dst_ip,
uint32_t *validation, __attribute__((unused))int probe_num)
{
struct ethhdr *eth_header = (struct ethhdr *)buf;
struct iphdr *ip_header = (struct iphdr*)(&eth_header[1]);
struct icmp *icmp_header = (struct icmp*)(&ip_header[1]);
uint16_t icmp_idnum = validation[2] & 0xFFFF;
ip_header->saddr = src_ip;
ip_header->daddr = dst_ip;
icmp_header->icmp_id = icmp_idnum;
icmp_header->icmp_cksum = 0;
icmp_header->icmp_cksum = icmp_checksum((unsigned short *) icmp_header);
ip_header->check = 0;
ip_header->check = ip_checksum((unsigned short *) ip_header);
return EXIT_SUCCESS;
}
void icmp_echo_print_packet(FILE *fp, void* packet)
{
struct ethhdr *ethh = (struct ethhdr *) packet;
struct iphdr *iph = (struct iphdr *) &ethh[1];
struct icmp *icmp_header = (struct icmp*)(&iph[1]);
fprintf(fp, "icmp { type: %u | code: %u "
"| checksum: %u | id: %u | seq: %u }\n",
icmp_header->icmp_type,
icmp_header->icmp_code,
ntohs(icmp_header->icmp_cksum),
ntohs(icmp_header->icmp_id),
ntohs(icmp_header->icmp_seq));
struct in_addr *s = (struct in_addr *) &(iph->saddr);
struct in_addr *d = (struct in_addr *) &(iph->daddr);
char srcip[20];
char dstip[20];
// inet_ntoa is a const char * so we if just call it in
// fprintf, you'll get back wrong results since we're
// calling it twice.
strncpy(srcip, inet_ntoa(*s), 19);
strncpy(dstip, inet_ntoa(*d), 19);
fprintf(fp, "ip { saddr: %s | daddr: %s | checksum: %u }\n",
srcip,
dstip,
ntohl(iph->check));
fprintf(fp, "eth { shost: %02x:%02x:%02x:%02x:%02x:%02x | "
"dhost: %02x:%02x:%02x:%02x:%02x:%02x }\n",
(int) ((unsigned char *) ethh->h_source)[0],
(int) ((unsigned char *) ethh->h_source)[1],
(int) ((unsigned char *) ethh->h_source)[2],
(int) ((unsigned char *) ethh->h_source)[3],
(int) ((unsigned char *) ethh->h_source)[4],
(int) ((unsigned char *) ethh->h_source)[5],
(int) ((unsigned char *) ethh->h_dest)[0],
(int) ((unsigned char *) ethh->h_dest)[1],
(int) ((unsigned char *) ethh->h_dest)[2],
(int) ((unsigned char *) ethh->h_dest)[3],
(int) ((unsigned char *) ethh->h_dest)[4],
(int) ((unsigned char *) ethh->h_dest)[5]);
fprintf(fp, "------------------------------------------------------\n");
}
response_type_t* icmp_echo_classify_packet(const u_char *packet, uint32_t len)
{
(void)len;
struct iphdr *ip_hdr = (struct iphdr *)&packet[sizeof(struct ethhdr)];
struct icmp *icmp_hdr = (struct icmp*)((char *)ip_hdr
+ sizeof(struct iphdr));
switch (icmp_hdr->icmp_type) {
case ICMP_ECHOREPLY:
return &(module_icmp_echo.responses[0]);
case ICMP_UNREACH:
return &(module_icmp_echo.responses[1]);
case ICMP_SOURCEQUENCH:
return &(module_icmp_echo.responses[2]);
case ICMP_REDIRECT:
return &(module_icmp_echo.responses[3]);
case ICMP_TIMXCEED:
return &(module_icmp_echo.responses[4]);
default:
return &(module_icmp_echo.responses[5]);
}
}
int icmp_validate_packet(const struct iphdr *ip_hdr, uint32_t len, uint32_t *src_ip, uint32_t *validation)
{
if (ip_hdr->protocol != IPPROTO_ICMP) {
return 0;
}
if ((4*ip_hdr->ihl + sizeof(struct icmphdr)) > len) {
// buffer not large enough to contain expected icmp header
return 0;
}
struct icmphdr *icmp_h = (struct icmphdr*)((char *)ip_hdr + 4*ip_hdr->ihl);
uint16_t icmp_idnum = icmp_h->un.echo.id;
// ICMP validation is tricky: for some packet types, we must look inside
// the payload
if (icmp_h->type == ICMP_TIME_EXCEEDED || icmp_h->type == ICMP_DEST_UNREACH) {
if ((4*ip_hdr->ihl + sizeof(struct icmphdr) +
sizeof(struct iphdr)) > len) {
return 0;
}
struct iphdr *ip_inner = (struct iphdr *)(icmp_h + 1);
if ((4*ip_hdr->ihl + sizeof(struct icmphdr) +
4*ip_inner->ihl + sizeof(struct icmphdr)) > len) {
return 0;
}
struct icmphdr *icmp_inner = (struct icmphdr*)((char *)ip_inner + 4 *ip_hdr->ihl);
// Regenerate validation and icmp id based off inner payload
icmp_idnum = icmp_inner->un.echo.id;
*src_ip = ip_inner->daddr;
validate_gen(ip_hdr->daddr, ip_inner->daddr, (uint8_t *)validation);
}
// validate icmp id
if (icmp_idnum != (validation[2] & 0xFFFF)) {
return 0;
}
return 1;
}
static response_type_t responses[] = {
{
.name = "echoreply",
.is_success = 1
},
{
.name = "unreach",
.is_success = 0
},
{
.name = "sourcequench",
.is_success = 0
},
{
.name = "redirect",
.is_success = 0
},
{
.name = "timxceed",
.is_success = 0
},
{
.name = "other",
.is_success = 0
}
};
probe_module_t module_icmp_echo = {
.name = "icmp_echoscan",
.packet_length = 62,
.pcap_filter = "icmp and icmp[0]!=8",
.pcap_snaplen = 96,
.port_args = 0,
.thread_initialize = &icmp_echo_init_perthread,
.make_packet = &icmp_echo_make_packet,
.print_packet = &icmp_echo_print_packet,
.classify_packet = &icmp_echo_classify_packet,
.validate_packet = &icmp_validate_packet,
.close = NULL,
.responses = responses
};

View File

@ -0,0 +1,196 @@
/*
* ZMap Copyright 2013 Regents of the University of Michigan
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*/
// probe module for performing TCP SYN scans
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include <string.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <netinet/ether.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "probe_modules.h"
#include "packet.h"
probe_module_t module_tcp_synscan;
uint32_t num_ports = 1;
int synscan_init_perthread(void* buf, macaddr_t *src,
macaddr_t *gw, port_h_t dst_port)
{
memset(buf, 0, MAX_PACKET_SIZE);
struct ethhdr *eth_header = (struct ethhdr *)buf;
make_eth_header(eth_header, src, gw);
struct iphdr *ip_header = (struct iphdr*)(&eth_header[1]);
uint16_t len = htons(sizeof(struct iphdr) + sizeof(struct tcphdr));
make_ip_header(ip_header, IPPROTO_TCP, len);
struct tcphdr *tcp_header = (struct tcphdr*)(&ip_header[1]);
make_tcp_header(tcp_header, dst_port);
num_ports = zconf.source_port_last - zconf.source_port_first + 1;
return EXIT_SUCCESS;
}
int synscan_make_packet(void *buf, ipaddr_n_t src_ip, ipaddr_n_t dst_ip,
uint32_t *validation, int probe_num)
{
struct ethhdr *eth_header = (struct ethhdr *)buf;
struct iphdr *ip_header = (struct iphdr*)(&eth_header[1]);
struct tcphdr *tcp_header = (struct tcphdr*)(&ip_header[1]);
uint16_t src_port = zconf.source_port_first
+ ((validation[1] + probe_num) % num_ports);
uint32_t tcp_seq = validation[0];
ip_header->saddr = src_ip;
ip_header->daddr = dst_ip;
tcp_header->source = htons(src_port);
tcp_header->seq = tcp_seq;
tcp_header->check = 0;
tcp_header->check = tcp_checksum(sizeof(struct tcphdr),
ip_header->saddr, ip_header->daddr, tcp_header);
ip_header->check = 0;
ip_header->check = ip_checksum((unsigned short *) ip_header);
return EXIT_SUCCESS;
}
void synscan_print_packet(FILE *fp, void* packet)
{
struct ethhdr *ethh = (struct ethhdr *) packet;
struct iphdr *iph = (struct iphdr *) &ethh[1];
struct tcphdr *tcph = (struct tcphdr *) &iph[1];
fprintf(fp, "tcp { source: %u | dest: %u | seq: %u | checksum: %u }\n",
ntohs(tcph->source),
ntohs(tcph->dest),
ntohl(tcph->seq),
ntohl(tcph->check));
struct in_addr *s = (struct in_addr *) &(iph->saddr);
struct in_addr *d = (struct in_addr *) &(iph->daddr);
char srcip[20];
char dstip[20];
// inet_ntoa is a const char * so we if just call it in
// fprintf, you'll get back wrong results since we're
// calling it twice.
strncpy(srcip, inet_ntoa(*s), 19);
strncpy(dstip, inet_ntoa(*d), 19);
fprintf(fp, "ip { saddr: %s | daddr: %s | checksum: %u }\n",
srcip,
dstip,
ntohl(iph->check));
fprintf(fp, "eth { shost: %02x:%02x:%02x:%02x:%02x:%02x | "
"dhost: %02x:%02x:%02x:%02x:%02x:%02x }\n",
(int) ((unsigned char *) ethh->h_source)[0],
(int) ((unsigned char *) ethh->h_source)[1],
(int) ((unsigned char *) ethh->h_source)[2],
(int) ((unsigned char *) ethh->h_source)[3],
(int) ((unsigned char *) ethh->h_source)[4],
(int) ((unsigned char *) ethh->h_source)[5],
(int) ((unsigned char *) ethh->h_dest)[0],
(int) ((unsigned char *) ethh->h_dest)[1],
(int) ((unsigned char *) ethh->h_dest)[2],
(int) ((unsigned char *) ethh->h_dest)[3],
(int) ((unsigned char *) ethh->h_dest)[4],
(int) ((unsigned char *) ethh->h_dest)[5]);
fprintf(fp, "------------------------------------------------------\n");
}
response_type_t* synscan_classify_packet(const u_char *packet, uint32_t len)
{
(void)len;
struct iphdr *ip_hdr = (struct iphdr *)&packet[sizeof(struct ethhdr)];
struct tcphdr *tcp = (struct tcphdr*)((char *)ip_hdr
+ (sizeof(struct iphdr)));
if (tcp->rst) { // RST packet
return &(module_tcp_synscan.responses[1]);
} else { // SYNACK packet
return &(module_tcp_synscan.responses[0]);
}
}
// Returns 0 if dst_port is outside the expected valid range, non-zero otherwise
static inline int check_dst_port(uint16_t port, uint32_t *validation)
{
if (port > zconf.source_port_last
|| port < zconf.source_port_first) {
return EXIT_FAILURE;
}
int32_t to_validate = port - zconf.source_port_first;
int32_t min = validation[1] % num_ports;
int32_t max = (validation[1] + zconf.packet_streams - 1) % num_ports;
return (((max - min) % num_ports) >= ((to_validate - min) % num_ports));
}
int synscan_validate_packet(const struct iphdr *ip_hdr, uint32_t len,
__attribute__((unused))uint32_t *src_ip, uint32_t *validation)
{
if (ip_hdr->protocol != IPPROTO_TCP) {
return 0;
}
if ((4*ip_hdr->ihl + sizeof(struct tcphdr)) > len) {
// buffer not large enough to contain expected tcp header
return 0;
}
struct tcphdr *tcp = (struct tcphdr*)((char *)ip_hdr + 4*ip_hdr->ihl);
uint16_t sport = tcp->source;
uint16_t dport = tcp->dest;
// validate source port
if (ntohs(sport) != zconf.target_port) {
return 0;
}
// validate destination port
if (!check_dst_port(ntohs(dport), validation)) {
return 0;
}
// validate tcp acknowledgement number
if (htonl(tcp->ack_seq) != htonl(validation[0])+1) {
return 0;
}
return 1;
}
static response_type_t responses[] = {
{
.is_success = 1,
.name = "synack"
},
{
.is_success = 0,
.name = "rst"
}
};
probe_module_t module_tcp_synscan = {
.name = "tcp_synscan",
.packet_length = 54,
.pcap_filter = "tcp && tcp[13] & 4 != 0 || tcp[13] == 18",
.pcap_snaplen = 96,
.port_args = 1,
.thread_initialize = &synscan_init_perthread,
.make_packet = &synscan_make_packet,
.print_packet = &synscan_print_packet,
.classify_packet = &synscan_classify_packet,
.validate_packet = &synscan_validate_packet,
.close = NULL,
.responses = responses,
};

View File

@ -0,0 +1,227 @@
/*
* ZMap Copyright 2013 Regents of the University of Michigan
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*/
/* send module for performing TCP SYN scans */
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <netinet/udp.h>
#include <netinet/ip.h>
#include <netinet/ether.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "probe_modules.h"
#include "packet.h"
const char *udp_send_msg = "GET / HTTP/1.1\r\n\r\n"; // Must be null-terminated
static int num_ports = 1;
probe_module_t module_udp;
int udp_init_perthread(void* buf, macaddr_t *src,
macaddr_t *gw, __attribute__((unused)) port_h_t dst_port)
{
memset(buf, 0, MAX_PACKET_SIZE);
struct ethhdr *eth_header = (struct ethhdr *)buf;
make_eth_header(eth_header, src, gw);
struct iphdr *ip_header = (struct iphdr*)(&eth_header[1]);
uint16_t len = htons(sizeof(struct iphdr) + sizeof(struct udphdr) + strlen(udp_send_msg));
make_ip_header(ip_header, IPPROTO_UDP, len);
struct udphdr *udp_header = (struct udphdr*)(&ip_header[1]);
len = sizeof(struct udphdr) + strlen(udp_send_msg);
make_udp_header(udp_header, zconf.target_port, len);
char* payload = (char*)(&udp_header[1]);
module_udp.packet_length = sizeof(struct ethhdr) + sizeof(struct iphdr)
+ sizeof(struct udphdr) + strlen(udp_send_msg);
assert(module_udp.packet_length <= MAX_PACKET_SIZE);
strcpy(payload, udp_send_msg);
num_ports = zconf.source_port_last - zconf.source_port_first + 1;
return EXIT_SUCCESS;
}
int udp_make_packet(void *buf, ipaddr_n_t src_ip, ipaddr_n_t dst_ip,
uint32_t *validation, int probe_num)
{
struct ethhdr *eth_header = (struct ethhdr *)buf;
struct iphdr *ip_header = (struct iphdr*)(&eth_header[1]);
struct udphdr *udp_header = (struct udphdr*)(&ip_header[1]);
uint16_t src_port = zconf.source_port_first
+ ((validation[1] + probe_num) % num_ports);
ip_header->saddr = src_ip;
ip_header->daddr = dst_ip;
udp_header->source = src_port;
ip_header->check = 0;
ip_header->check = ip_checksum((unsigned short *) ip_header);
return EXIT_SUCCESS;
}
void udp_print_packet(FILE *fp, void* packet)
{
struct ethhdr *ethh = (struct ethhdr *) packet;
struct iphdr *iph = (struct iphdr *) &ethh[1];
struct udphdr *udph = (struct udphdr*)(&iph[1]);
fprintf(fp, "udp { source: %u | dest: %u | checksum: %u }\n",
ntohs(udph->source),
ntohs(udph->dest),
ntohl(udph->check));
//ip_header = (struct iphdr*)(&eth_header[1])
struct in_addr *s = (struct in_addr *) &(iph->saddr);
struct in_addr *d = (struct in_addr *) &(iph->daddr);
char srcip[20];
char dstip[20];
// inet_ntoa is a const char * so we if just call it in
// fprintf, you'll get back wrong results since we're
// calling it twice.
strncpy(srcip, inet_ntoa(*s), 19);
strncpy(dstip, inet_ntoa(*d), 19);
fprintf(fp, "ip { saddr: %s | daddr: %s | checksum: %u }\n",
srcip,
dstip,
ntohl(iph->check));
fprintf(fp, "eth { shost: %02x:%02x:%02x:%02x:%02x:%02x | "
"dhost: %02x:%02x:%02x:%02x:%02x:%02x }\n",
(int) ((unsigned char *) ethh->h_source)[0],
(int) ((unsigned char *) ethh->h_source)[1],
(int) ((unsigned char *) ethh->h_source)[2],
(int) ((unsigned char *) ethh->h_source)[3],
(int) ((unsigned char *) ethh->h_source)[4],
(int) ((unsigned char *) ethh->h_source)[5],
(int) ((unsigned char *) ethh->h_dest)[0],
(int) ((unsigned char *) ethh->h_dest)[1],
(int) ((unsigned char *) ethh->h_dest)[2],
(int) ((unsigned char *) ethh->h_dest)[3],
(int) ((unsigned char *) ethh->h_dest)[4],
(int) ((unsigned char *) ethh->h_dest)[5]);
fprintf(fp, "------------------------------------------------------\n");
}
response_type_t* udp_classify_packet(const u_char *packet, uint32_t len)
{
(void)len;
struct iphdr *ip_hdr = (struct iphdr *)&packet[sizeof(struct ethhdr)];
if (ip_hdr->protocol == IPPROTO_UDP) {
return &(module_udp.responses[0]);
} else if (ip_hdr->protocol == IPPROTO_ICMP) {
return &(module_udp.responses[1]);
} else {
return &(module_udp.responses[2]);
}
}
// Returns 0 if dst_port is outside the expected valid range, non-zero otherwise
static inline int check_dst_port(uint16_t port, uint32_t *validation)
{
if (port > zconf.source_port_last
|| port < zconf.source_port_first) {
return EXIT_FAILURE;
}
int32_t to_validate = port - zconf.source_port_first;
int32_t min = validation[1] % num_ports;
int32_t max = (validation[1] + zconf.packet_streams - 1) % num_ports;
return (((max - min) % num_ports) >= ((to_validate - min) % num_ports));
}
int udp_validate_packet(const struct iphdr *ip_hdr, uint32_t len,
__attribute__((unused))uint32_t *src_ip, uint32_t *validation)
{
uint16_t dport, sport;
if (ip_hdr->protocol == IPPROTO_UDP) {
if ((4*ip_hdr->ihl + sizeof(struct udphdr)) > len) {
// buffer not large enough to contain expected udp header
return 0;
}
struct udphdr *udp = (struct udphdr*)((char *)ip_hdr + 4*ip_hdr->ihl);
sport = ntohs(udp->dest);
dport = ntohs(udp->source);
} else if (ip_hdr->protocol == IPPROTO_ICMP) {
// UDP can return ICMP Destination unreach
// IP( ICMP( IP( UDP ) ) ) for a destination unreach
uint32_t min_len = 4*ip_hdr->ihl + sizeof(struct icmphdr)
+ sizeof(struct iphdr) + sizeof(struct udphdr);
if (len < min_len) {
// Not enough information for us to validate
return 0;
}
struct icmphdr *icmp = (struct icmphdr*)((char *)ip_hdr + 4*ip_hdr->ihl);
if (icmp->type != ICMP_DEST_UNREACH) {
return 0;
}
struct iphdr *ip_inner = (struct iphdr*)&icmp[1];
// Now we know the actual inner ip length, we should recheck the buffer
if (len < 4*ip_inner->ihl - sizeof(struct iphdr) + min_len) {
return 0;
}
// This is the packet we sent
struct udphdr *udp = (struct udphdr *)((char*)ip_inner + 4*ip_inner->ihl);
sport = ntohs(udp->source);
dport = ntohs(udp->dest);
} else {
return 0;
}
if (dport != zconf.target_port) {
return 0;
}
if (!check_dst_port(sport, validation)) {
return 0;
}
return 1;
}
static response_type_t responses[] = {
{
.is_success = 1,
.name = "data"
},
{
.is_success = 0,
.name = "port-unreach"
},
{
.is_success = 0,
.name = "invalid"
}
};
probe_module_t module_udp = {
.name = "udp",
.packet_length = 96,
.pcap_filter = "udp || icmp",
.pcap_snaplen = 96,
.port_args = 1,
.thread_initialize = &udp_init_perthread,
.make_packet = &udp_make_packet,
.print_packet = &udp_print_packet,
.validate_packet = &udp_validate_packet,
.classify_packet = &udp_classify_packet,
.close = NULL,
.responses = responses
};

View File

@ -0,0 +1,89 @@
/*
* ZMap Copyright 2013 Regents of the University of Michigan
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*/
#include "packet.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <netinet/ether.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <netinet/udp.h>
#include <netinet/ip_icmp.h>
#include <net/if.h>
#include <arpa/inet.h>
#include "state.h"
void print_macaddr(struct ifreq* i)
{
printf("Device %s -> Ethernet %02x:%02x:%02x:%02x:%02x:%02x\n",
i->ifr_name,
(int) ((unsigned char *) &i->ifr_hwaddr.sa_data)[0],
(int) ((unsigned char *) &i->ifr_hwaddr.sa_data)[1],
(int) ((unsigned char *) &i->ifr_hwaddr.sa_data)[2],
(int) ((unsigned char *) &i->ifr_hwaddr.sa_data)[3],
(int) ((unsigned char *) &i->ifr_hwaddr.sa_data)[4],
(int) ((unsigned char *) &i->ifr_hwaddr.sa_data)[5]);
}
void make_eth_header(struct ethhdr *ethh, macaddr_t *src, macaddr_t *dst)
{
memcpy(ethh->h_source, src, ETH_ALEN);
memcpy(ethh->h_dest, dst, ETH_ALEN);
ethh->h_proto = htons(ETH_P_IP);
}
void make_ip_header(struct iphdr *iph, uint8_t protocol, uint16_t len)
{
iph->ihl = 5; // Internet Header Length
iph->version = 4; // IPv4
iph->tos = 0; // Type of Service
iph->tot_len = len;
iph->id = htons(54321); // identification number
iph->frag_off = 0; //fragmentation falg
iph->ttl = MAXTTL; // time to live (TTL)
iph->protocol = protocol; // upper layer protocol => TCP
// we set the checksum = 0 for now because that's
// what it needs to be when we run the IP checksum
iph->check = 0;
}
void make_icmp_header(struct icmp *buf)
{
buf->icmp_type = ICMP_ECHO;
buf->icmp_code = 0;
buf->icmp_seq = 0;
}
void make_tcp_header(struct tcphdr *tcp_header, port_h_t dest_port)
{
tcp_header->seq = random();
tcp_header->ack_seq = 0;
tcp_header->res2 = 0;
tcp_header->doff = 5; // data offset
tcp_header->syn = 1;
tcp_header->window = htons(65535); // largest possible window
tcp_header->check = 0;
tcp_header->urg_ptr = 0;
tcp_header->dest = htons(dest_port);
}
void make_udp_header(struct udphdr *udp_header, port_h_t dest_port,
uint16_t len)
{
udp_header->dest = htons(dest_port);
udp_header->len = htons(len);
// checksum ignored in IPv4 if 0
udp_header->check = 0;
}

View File

@ -0,0 +1,82 @@
#include "state.h"
#include <netinet/ether.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <netinet/ip_icmp.h>
#include <netinet/udp.h>
#ifndef HEADER_ZMAP_PACKET_H
#define HEADER_ZMAP_PACKET_H
#define MAX_PACKET_SIZE 4096
typedef unsigned short __attribute__((__may_alias__)) alias_unsigned_short;
void make_eth_header(struct ethhdr *ethh, macaddr_t *src, macaddr_t *dst);
void make_ip_header(struct iphdr *iph, uint8_t, uint16_t);
void make_tcp_header(struct tcphdr*, port_h_t);
void make_icmp_header(struct icmp *);
void make_udp_header(struct udphdr *udp_header, port_h_t dest_port,
uint16_t len);
static inline unsigned short in_checksum(unsigned short *ip_pkt, int len)
{
unsigned long sum = 0;
for (int nwords = len/2; nwords > 0; nwords--) {
sum += *ip_pkt++;
}
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
return (unsigned short) (~sum);
}
__attribute__((unused)) static inline unsigned short ip_checksum(
unsigned short *buf)
{
return in_checksum(buf, (int) sizeof(struct iphdr));
}
__attribute__((unused)) static inline unsigned short icmp_checksum(
unsigned short *buf)
{
return in_checksum(buf, (int) sizeof(struct icmp));
}
static __attribute__((unused)) uint16_t tcp_checksum(unsigned short len_tcp,
uint32_t saddr, uint32_t daddr, struct tcphdr *tcp_pkt)
{
alias_unsigned_short *src_addr = (alias_unsigned_short *) &saddr;
alias_unsigned_short *dest_addr = (alias_unsigned_short *) &daddr;
unsigned char prot_tcp = 6;
unsigned long sum = 0;
int nleft = len_tcp;
unsigned short *w;
w = (unsigned short *) tcp_pkt;
// calculate the checksum for the tcp header and tcp data
while(nleft > 1) {
sum += *w++;
nleft -= 2;
}
// if nleft is 1 there ist still on byte left.
// We add a padding byte (0xFF) to build a 16bit word
if (nleft > 0) {
sum += *w & ntohs(0xFF00);
}
// add the pseudo header
sum += src_addr[0];
sum += src_addr[1];
sum += dest_addr[0];
sum += dest_addr[1];
sum += htons(len_tcp);
sum += htons(prot_tcp);
sum = (sum >> 16) + (sum & 0xFFFF);
sum += (sum >> 16);
// Take the one's complement of sum
return (unsigned short) (~sum);
}
#endif

View File

@ -0,0 +1,42 @@
/*
* ZMap Copyright 2013 Regents of the University of Michigan
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*/
#include <stdio.h>
#include <string.h>
#include "probe_modules.h"
extern probe_module_t module_tcp_synscan;
extern probe_module_t module_icmp_echo;
extern probe_module_t module_udp;
// ADD YOUR MODULE HERE
probe_module_t* probe_modules[] = {
&module_tcp_synscan,
&module_icmp_echo,
&module_udp
// ADD YOUR MODULE HERE
};
probe_module_t* get_probe_module_by_name(const char* name)
{
for (int i=0; i < (int) (sizeof(probe_modules)/sizeof(probe_modules[0])); i++) {
if (!strcmp(probe_modules[i]->name, name)) {
return probe_modules[i];
}
}
return NULL;
}
void print_probe_modules(void)
{
for (int i=0; i < (int) (sizeof(probe_modules)/sizeof(probe_modules[0])); i++) {
printf("%s\n", probe_modules[i]->name);
}
}

View File

@ -0,0 +1,45 @@
#include "../state.h"
#ifndef HEADER_PROBE_MODULES_H
#define HEADER_PROBE_MODULES_H
typedef struct probe_response_type {
const uint8_t is_success;
const char *name;
} response_type_t;
typedef int (*probe_global_init_cb)(struct state_conf *);
typedef int (*probe_thread_init_cb)(void* packetbuf, macaddr_t* src_mac, macaddr_t* gw_mac, port_n_t src_port);
typedef int (*probe_make_packet_cb)(void* packetbuf, ipaddr_n_t src_ip, ipaddr_n_t dst_ip,
uint32_t *validation, int probe_num);
typedef void (*probe_print_packet_cb)(FILE *, void* packetbuf);
typedef int (*probe_close_cb)(struct state_conf*, struct state_send*, struct state_recv*);
typedef response_type_t* (*probe_classify_packet_cb)(const u_char* packetbuf, uint32_t len);
typedef int (*probe_validate_packet_cb)(const struct iphdr *ip_hdr, uint32_t len, uint32_t *src_ip, uint32_t *validation);
typedef struct probe_module {
const char *name;
size_t packet_length;
const char *pcap_filter;
size_t pcap_snaplen;
// Should ZMap complain if the user hasn't specified valid
// source and target port numbers?
uint8_t port_args;
response_type_t *responses;
probe_global_init_cb global_initialize;
probe_thread_init_cb thread_initialize;
probe_make_packet_cb make_packet;
probe_print_packet_cb print_packet;
probe_validate_packet_cb validate_packet;
probe_classify_packet_cb classify_packet;
probe_close_cb close;
} probe_module_t;
probe_module_t* get_probe_module_by_name(const char*);
void print_probe_modules(void);
#endif // HEADER_PROBE_MODULES_H

195
src/recv.c Normal file
View File

@ -0,0 +1,195 @@
/*
* ZMap Copyright 2013 Regents of the University of Michigan
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <pcap.h>
#include <pcap/pcap.h>
#include <netinet/tcp.h>
#include <netinet/ip_icmp.h>
#include <netinet/udp.h>
#include <netinet/ip.h>
#include <netinet/in.h>
#include <linux/if_ether.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include "../lib/logger.h"
#include "state.h"
#include "validate.h"
#include "probe_modules/probe_modules.h"
#include "output_modules/output_modules.h"
#define PCAP_PROMISC 1
#define PCAP_TIMEOUT 1000
static uint32_t num_src_ports;
static pcap_t *pc = NULL;
// bitmap of observed IP addresses
static uint64_t *ip_seen = NULL;
static const int IP_SEEN_SIZE = 0x4000000; // == 2^32/64
// check if we've received a response from this address previously
static inline int check_ip(uint32_t ip)
{
return (ip_seen[ip >> 6] >> (ip & 0x3F)) & 1;
}
// set that we've received a response from the address
static inline void set_ip(uint32_t ip)
{
ip_seen[ip >> 6] |= (uint64_t)1 << (ip & 0x3F);
}
void packet_cb(u_char __attribute__((__unused__)) *user,
const struct pcap_pkthdr *p, const u_char *bytes)
{
if (!p) {
return;
}
if (zrecv.success_unique >= zconf.max_results) {
// Libpcap can process multiple packets per pcap_dispatch;
// we need to throw out results once we've
// gotten our --max-results worth.
return;
}
// length of entire packet captured by libpcap
uint32_t buflen = (uint32_t) p->caplen;
if ((sizeof(struct iphdr) + sizeof(struct ethhdr)) > buflen) {
// buffer not large enough to contain ethernet
// and ip headers. further action would overrun buf
return;
}
struct iphdr *ip_hdr = (struct iphdr *)&bytes[sizeof(struct ethhdr)];
uint32_t src_ip = ip_hdr->saddr;
uint32_t validation[VALIDATE_BYTES/sizeof(uint8_t)];
// TODO: for TTL exceeded messages, ip_hdr->saddr is going to be different
// and we must calculate off potential payload message instead
validate_gen(ip_hdr->daddr, ip_hdr->saddr, (uint8_t *)validation);
if (!zconf.probe_module->validate_packet(ip_hdr, buflen - sizeof(struct ethhdr),
&src_ip, validation)) {
return;
}
int is_repeat = check_ip(src_ip);
response_type_t *r = zconf.probe_module->classify_packet(bytes, buflen);
if (r->is_success) {
zrecv.success_total++;
if (!is_repeat) {
zrecv.success_unique++;
set_ip(src_ip);
}
if (zsend.complete) {
zrecv.cooldown_total++;
if (!is_repeat) {
zrecv.cooldown_unique++;
}
}
if (zconf.output_module && zconf.output_module->success_ip) {
zconf.output_module->success_ip(
ip_hdr->saddr, ip_hdr->daddr,
r->name, is_repeat, zsend.complete, bytes, buflen);
}
} else {
zrecv.failure_total++;
if (zconf.output_module && zconf.output_module->other_ip) {
zconf.output_module->other_ip(
ip_hdr->saddr, ip_hdr->daddr,
r->name, is_repeat, zsend.complete, bytes, buflen);
}
}
if (zconf.output_module && zconf.output_module->update
&& !(zrecv.success_unique % zconf.output_module->update_interval)) {
zconf.output_module->update(&zconf, &zsend, &zrecv);
}
}
int recv_update_pcap_stats(void)
{
if (!pc) {
return EXIT_FAILURE;
}
struct pcap_stat pcst;
if (pcap_stats(pc, &pcst)) {
log_error("recv", "unable to retrieve pcap statistics: %s",
pcap_geterr(pc));
return EXIT_FAILURE;
} else {
zrecv.pcap_recv = pcst.ps_recv;
zrecv.pcap_drop = pcst.ps_drop;
zrecv.pcap_ifdrop = pcst.ps_ifdrop;
}
return EXIT_SUCCESS;
}
int recv_run(pthread_mutex_t *recv_ready_mutex)
{
log_debug("recv", "thread started");
num_src_ports = zconf.source_port_last - zconf.source_port_first + 1;
ip_seen = calloc(IP_SEEN_SIZE, sizeof(uint64_t));
if (!ip_seen) {
log_fatal("recv", "couldn't allocate address bitmap");
}
log_debug("recv", "using dev %s", zconf.iface);
char errbuf[PCAP_ERRBUF_SIZE];
pc = pcap_open_live(zconf.iface, zconf.probe_module->pcap_snaplen,
PCAP_PROMISC, PCAP_TIMEOUT, errbuf);
if (pc == NULL) {
log_fatal("recv", "couldn't open device %s: %s",
zconf.iface, errbuf);
}
struct bpf_program bpf;
if (pcap_compile(pc, &bpf, zconf.probe_module->pcap_filter, 1, 0) < 0) {
log_fatal("recv", "couldn't compile filter");
}
if (pcap_setfilter(pc, &bpf) < 0) {
log_fatal("recv", "couldn't install filter");
}
log_debug("recv", "receiver ready");
pthread_mutex_lock(recv_ready_mutex);
zconf.recv_ready = 1;
pthread_mutex_unlock(recv_ready_mutex);
zrecv.start = now();
if (zconf.max_results == 0) {
zconf.max_results = -1;
}
do {
if (pcap_dispatch(pc, 0, packet_cb, NULL) == -1) {
log_fatal("recv", "pcap_dispatch error");
}
if (zconf.max_results && zrecv.success_unique >= zconf.max_results) {
zsend.complete = 1;
break;
}
} while (!(zsend.complete && (now()-zsend.finish > zconf.cooldown_secs)));
zrecv.finish = now();
// get final pcap statistics before closing
recv_update_pcap_stats();
pcap_close(pc);
zrecv.complete = 1;
log_debug("recv", "thread finished");
return 0;
}

16
src/recv.h Normal file
View File

@ -0,0 +1,16 @@
/*
* ZMap Copyright 2013 Regents of the University of Michigan
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*/
#ifndef _RECV_H
#define _RECV_H
int recv_update_pcap_stats(void);
int recv_run();
#endif //_RECV_H

295
src/send.c Normal file
View File

@ -0,0 +1,295 @@
/*
* ZMap Copyright 2013 Regents of the University of Michigan
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*/
#include "send.h"
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <time.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <linux/if_packet.h>
#include "../lib/logger.h"
#include "../lib/random.h"
#include "../lib/blacklist.h"
#include "cyclic.h"
#include "state.h"
#include "probe_modules/packet.h"
#include "probe_modules/probe_modules.h"
#include "validate.h"
// lock to manage access to share send state (e.g. counters and cyclic)
pthread_mutex_t send_mutex = PTHREAD_MUTEX_INITIALIZER;
// lock to provide thread safety to the user provided send callback
pthread_mutex_t syncb_mutex = PTHREAD_MUTEX_INITIALIZER;
// globals to handle sending from multiple ip addresses (shared across threads)
static uint16_t num_src_ports;
static uint32_t num_addrs;
static in_addr_t srcip_first;
static in_addr_t srcip_last;
// offset send addresses according to a random chosen per scan execution
// in order to help prevent cross-scan interference
static uint32_t srcip_offset;
// global sender initialize (not thread specific)
int send_init(void)
{
// generate a new primitive root and starting position
cyclic_init(0, 0);
zsend.first_scanned = cyclic_get_curr_ip();
// compute number of targets
uint64_t allowed = blacklist_count_allowed();
if (allowed == (1LL << 32)) {
zsend.targets = 0xFFFFFFFF;
} else {
zsend.targets = allowed;
}
if (zsend.targets > zconf.max_targets) {
zsend.targets = zconf.max_targets;
}
// process the dotted-notation addresses passed to ZMAP and determine
// the source addresses from which we'll send packets;
srcip_first = inet_addr(zconf.source_ip_first);
if (srcip_first == INADDR_NONE) {
log_fatal("send", "invalid begin source ip address: `%s'",
zconf.source_ip_first);
}
srcip_last = inet_addr(zconf.source_ip_last);
if (srcip_last == INADDR_NONE) {
log_fatal("send", "invalid end source ip address: `%s'",
zconf.source_ip_last);
}
if (srcip_first == srcip_last) {
srcip_offset = 0;
num_addrs = 1;
} else {
srcip_offset = rand() % (srcip_last - srcip_first);
num_addrs = ntohl(srcip_last) - ntohl(srcip_first) + 1;
}
// process the source port range that ZMap is allowed to use
num_src_ports = zconf.source_port_last - zconf.source_port_first + 1;
log_debug("send", "will send from %i address%s on %u source ports",
num_addrs, ((num_addrs==1)?"":"es"), num_src_ports);
// global initialization for send module
assert(zconf.probe_module);
if (zconf.probe_module->global_initialize) {
zconf.probe_module->global_initialize(&zconf);
}
// concert specified bandwidth to packet rate
if (zconf.bandwidth > 0) {
int pkt_len = zconf.probe_module->packet_length;
pkt_len *= 8;
pkt_len += 8*24; // 7 byte MAC preamble, 1 byte Start frame,
// 4 byte CRC, 12 byte inter-frame gap
if (pkt_len < 84*8) {
pkt_len = 84*8;
}
if (zconf.bandwidth / pkt_len > 0xFFFFFFFF) {
zconf.rate = 0;
} else {
zconf.rate = zconf.bandwidth / pkt_len;
if (zconf.rate == 0) {
log_warn("send", "bandwidth %lu bit/s is slower than 1 pkt/s, "
"setting rate to 1 pkt/s", zconf.bandwidth);
zconf.rate = 1;
}
}
log_debug("send", "using bandwidth %lu bits/s, rate set to %d pkt/s",
zconf.bandwidth, zconf.rate);
}
if (zconf.dryrun) {
log_info("send", "dryrun mode -- won't actually send packets");
}
// initialize random validation key
validate_init();
zsend.start = now();
return EXIT_SUCCESS;
}
static int get_socket(void)
{
int sock = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (sock <= 0) {
log_fatal("send", "couldn't create socket. "
"Are you root? Error: %s\n", strerror(errno));
}
return sock;
}
static inline ipaddr_n_t get_src_ip(ipaddr_n_t dst, int local_offset)
{
if (srcip_first == srcip_last) {
return srcip_first;
}
return htonl(((ntohl(dst) + srcip_offset + local_offset)
% num_addrs)) + srcip_first;
}
// one sender thread
int send_run(void)
{
log_debug("send", "thread started");
pthread_mutex_lock(&send_mutex);
int sock = get_socket();
struct sockaddr_ll sockaddr;
// get source interface index
struct ifreq if_idx;
memset(&if_idx, 0, sizeof(struct ifreq));
if (strlen(zconf.iface) >= IFNAMSIZ) {
log_error("send", "device interface name (%s) too long\n",
zconf.iface);
return -1;
}
strncpy(if_idx.ifr_name, zconf.iface, IFNAMSIZ-1);
if (ioctl(sock, SIOCGIFINDEX, &if_idx) < 0) {
perror("SIOCGIFINDEX");
return -1;
}
int ifindex = if_idx.ifr_ifindex;
// get source interface mac
struct ifreq if_mac;
memset(&if_mac, 0, sizeof(struct ifreq));
strncpy(if_mac.ifr_name, zconf.iface, IFNAMSIZ-1);
if (ioctl(sock, SIOCGIFHWADDR, &if_mac) < 0) {
perror("SIOCGIFHWADDR");
return -1;
}
// find source IP address associated with the dev from which we're sending.
// while we won't use this address for sending packets, we need the address
// to set certain socket options and it's easiest to just use the primary
// address the OS believes is associated.
struct ifreq if_ip;
memset(&if_ip, 0, sizeof(struct ifreq));
strncpy(if_ip.ifr_name, zconf.iface, IFNAMSIZ-1);
if (ioctl(sock, SIOCGIFADDR, &if_ip) < 0) {
perror("SIOCGIFADDR");
return -1;
}
// destination address for the socket
memset((void*) &sockaddr, 0, sizeof(struct sockaddr_ll));
sockaddr.sll_ifindex = ifindex;
sockaddr.sll_halen = ETH_ALEN;
memcpy(sockaddr.sll_addr, zconf.gw_mac, ETH_ALEN);
char buf[MAX_PACKET_SIZE];
memset(buf, 0, MAX_PACKET_SIZE);
zconf.probe_module->thread_initialize(buf,
(unsigned char *)if_mac.ifr_hwaddr.sa_data,
zconf.gw_mac, zconf.target_port);
pthread_mutex_unlock(&send_mutex);
// adaptive timing to hit target rate
uint32_t count = 0;
uint32_t last_count = count;
double last_time = now();
uint32_t delay = 0;
int interval = 0;
volatile int vi;
if (zconf.rate > 0) {
// estimate initial rate
delay = 10000;
for (vi = delay; vi--; )
;
delay *= 1 / (now() - last_time) / (zconf.rate / zconf.senders);
interval = (zconf.rate / zconf.senders) / 20;
last_time = now();
}
while (1) {
// adaptive timing delay
if (delay > 0) {
count++;
for (vi = delay; vi--; )
;
if (!interval || (count % interval == 0)) {
double t = now();
delay *= (double)(count - last_count)
/ (t - last_time) / (zconf.rate / zconf.senders);
if (delay < 1)
delay = 1;
last_count = count;
last_time = t;
}
}
// generate next ip from cyclic group and update global state
// (everything locked happens here)
pthread_mutex_lock(&send_mutex);
if (zsend.complete) {
pthread_mutex_unlock(&send_mutex);
break;
}
if (zsend.sent >= zconf.max_targets) {
zsend.complete = 1;
zsend.finish = now();
pthread_mutex_unlock(&send_mutex);
break;
}
if (zconf.max_runtime && zconf.max_runtime <= now() - zsend.start) {
zsend.complete = 1;
zsend.finish = now();
pthread_mutex_unlock(&send_mutex);
break;
}
uint32_t curr = cyclic_get_next_ip();
if (curr == zsend.first_scanned) {
zsend.complete = 1;
zsend.finish = now();
}
zsend.sent++;
pthread_mutex_unlock(&send_mutex);
for (int i=0; i < zconf.packet_streams; i++) {
uint32_t src_ip = get_src_ip(curr, i);
uint32_t validation[VALIDATE_BYTES/sizeof(uint32_t)];
validate_gen(src_ip, curr, (uint8_t *)validation);
zconf.probe_module->make_packet(buf, src_ip, curr, validation, i);
if (zconf.dryrun) {
zconf.probe_module->print_packet(stdout, buf);
} else {
int l = zconf.probe_module->packet_length;
int rc = sendto(sock, buf,
l, 0,
(struct sockaddr *)&sockaddr,
sizeof(struct sockaddr_ll));
if (rc < 0) {
struct in_addr addr;
addr.s_addr = curr;
log_debug("send", "sendto failed for %s. %s",
inet_ntoa(addr), strerror(errno));
pthread_mutex_lock(&send_mutex);
zsend.sendto_failures++;
pthread_mutex_unlock(&send_mutex);
}
}
}
}
log_debug("send", "thread finished");
return EXIT_SUCCESS;
}

15
src/send.h Normal file
View File

@ -0,0 +1,15 @@
/*
* ZMap Copyright 2013 Regents of the University of Michigan
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*/
#ifndef _SEND_H
#define _SEND_H
int send_init(void);
int send_run(void);
#endif //_SEND_H

70
src/state.c Normal file
View File

@ -0,0 +1,70 @@
/*
* ZMap Copyright 2013 Regents of the University of Michigan
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*/
#include "state.h"
#include "../lib/logger.h"
// global configuration and defaults
struct state_conf zconf = {
.log_level = LOG_INFO,
.source_port_first = 32768, // (these are the default
.source_port_last = 61000, // ephemeral range on Linux)
.output_filename = NULL,
.blacklist_filename = NULL,
.whitelist_filename = NULL,
.target_port = 0,
.max_targets = 0xFFFFFFFF,
.max_runtime = 0,
.max_results = 0,
.iface = NULL,
.rate = 0,
.bandwidth = 0,
.cooldown_secs = 0,
.senders = 1,
.packet_streams = 1,
.use_seed = 0,
.seed = 0,
.output_module = NULL,
.output_args = NULL,
.probe_module = NULL,
.probe_args = NULL,
.gw_mac = {0},
.gw_mac_set = 0,
.source_ip_first = NULL,
.source_ip_last = NULL,
.dryrun = 0,
.quiet = 0,
.summary = 0,
.recv_ready = 0,
};
// global sender stats and defaults
struct state_send zsend = {
.start = 0.0,
.finish = 0.0,
.sent = 0,
.blacklisted = 0,
.complete = 0,
.sendto_failures = 0,
.targets = 0,
};
// global receiver stats and defaults
struct state_recv zrecv = {
.success_unique = 0,
.success_total = 0,
.cooldown_unique = 0,
.cooldown_total = 0,
.failure_total = 0,
.complete = 0,
.pcap_recv = 0,
.pcap_drop = 0,
.pcap_ifdrop = 0,
};

124
src/state.h Normal file
View File

@ -0,0 +1,124 @@
/*
* ZMap Copyright 2013 Regents of the University of Michigan
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*/
#include <stdio.h>
#include <stdint.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <netinet/ether.h>
#include <net/if.h>
#ifndef _STATE_H
#define _STATE_H
#define MAX_PACKET_SIZE 4096
typedef uint32_t ipaddr_n_t; // IPv4 address network order
typedef uint32_t ipaddr_h_t; // IPv4 address host order
typedef uint16_t port_n_t; // port network order
typedef uint16_t port_h_t; // port host order
typedef unsigned char macaddr_t;
struct probe_module;
struct output_module;
// global configuration
struct state_conf {
int log_level;
port_h_t target_port;
port_h_t source_port_first;
port_h_t source_port_last;
// maximum number of packets that the scanner will send before terminating
uint32_t max_targets;
// maximum number of seconds that scanner will run before terminating
uint32_t max_runtime;
// maximum number of results before terminating
uint32_t max_results;
// name of network interface that
// will be utilized for sending/receiving
char *iface;
// rate in packets per second
// that the sender will maintain
int rate;
// rate in bits per second
uint64_t bandwidth;
// how many seconds after the termination of the sender will the receiver
// continue to process responses
int cooldown_secs;
// number of sending threads
int senders;
// should use CLI provided randomization seed instead of generating
// a random seed.
int use_seed;
uint32_t seed;
// generator of the cyclic multiplicative group that is utilized for
// address generation
uint32_t generator;
int packet_streams;
struct probe_module *probe_module;
struct output_module *output_module;
char *probe_args;
char *output_args;
macaddr_t gw_mac[IFHWADDRLEN];
int gw_mac_set;
char *source_ip_first;
char *source_ip_last;
char *output_filename;
char *blacklist_filename;
char *whitelist_filename;
int dryrun;
int summary;
int quiet;
int recv_ready;
};
extern struct state_conf zconf;
// global sender stats
struct state_send {
double start;
double finish;
uint32_t sent;
uint32_t blacklisted;
int complete;
uint32_t first_scanned;
uint32_t targets;
uint32_t sendto_failures;
};
extern struct state_send zsend;
// global receiver stats
struct state_recv {
// valid responses classified as "success"
uint32_t success_total;
// unique IPs that sent valid responses classified as "success"
uint32_t success_unique;
// valid responses classified as "success" received during cooldown
uint32_t cooldown_total;
// unique IPs that first sent valid "success"es during cooldown
uint32_t cooldown_unique;
// valid responses NOT classified as "success"
uint32_t failure_total;
int complete; // has the scanner finished sending?
double start; // timestamp of when recv started
double finish; // timestamp of when recv terminated
// number of packets captured by pcap filter
uint32_t pcap_recv;
// number of packets dropped because there was no room in
// the operating system's buffer when they arrived, because
// packets weren't being read fast enough
uint32_t pcap_drop;
// number of packets dropped by the network interface or its driver.
uint32_t pcap_ifdrop;
};
extern struct state_recv zrecv;
#endif // _STATE_H

47
src/validate.c Normal file
View File

@ -0,0 +1,47 @@
/*
* ZMap Copyright 2013 Regents of the University of Michigan
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*/
#include <stdint.h>
#include <assert.h>
#include "../lib/rijndael-alg-fst.h"
#include "../lib/random.h"
#include "../lib/logger.h"
#include "validate.h"
#define AES_ROUNDS 10
#define AES_BLOCK_WORDS 4
#define AES_KEY_BYTES 16
static int inited = 0;
static uint32_t aes_input[AES_BLOCK_WORDS];
static uint32_t aes_sched[(AES_ROUNDS+1)*4];
void validate_init()
{
for (int i=0; i < AES_BLOCK_WORDS; i++) {
aes_input[i] = 0;
}
uint8_t key[AES_KEY_BYTES];
if (!random_bytes(key, AES_KEY_BYTES)) {
log_fatal("validate", "couldn't get random bytes");
}
if (rijndaelKeySetupEnc(aes_sched, key, AES_KEY_BYTES*8) != AES_ROUNDS) {
log_fatal("validate", "couldn't initialize AES key");
}
inited = 1;
}
void validate_gen(const uint32_t src, const uint32_t dst,
uint8_t output[VALIDATE_BYTES])
{
assert(inited);
aes_input[0] = src;
aes_input[1] = dst;
rijndaelEncrypt(aes_sched, AES_ROUNDS, (uint8_t *)aes_input, output);
}

17
src/validate.h Normal file
View File

@ -0,0 +1,17 @@
/*
* ZMap Copyright 2013 Regents of the University of Michigan
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*/
#ifndef _VALIDATE_H
#define _VALIDATE_H
#define VALIDATE_BYTES 16
void validate_init();
void validate_gen(const uint32_t src, const uint32_t dst, uint8_t output[VALIDATE_BYTES]);
#endif//_VALIDATE_H

155
src/zmap.1 Normal file
View File

@ -0,0 +1,155 @@
.TH zmap 1 "06 Aug 2013" "1.0" "zmap man page"
.SH NAME
zmap \- A fast Internet-wide scanner
.SH SYNOPSIS
.B zmap
[
.I "OPTIONS \&..."
]
.SH DESCRIPTION
.I ZMap
is a network tool for scanning the entire Internet (or large samples).
.SH OPTIONS
.SS "Basic options"
.TP
.B \-p, --target-port=port
TCP port number to scan (for SYN scans)
.TP
.B \-o, --output-file=name
When using an output module that uses a file (such as the default),
write results to this file. Use - for stdout.
.TP
.B \-b, --blacklist-file=path
File of subnets to exclude, in CIDR notation (e.g. 192.168.0.0/16),
one-per line. It is recommended you use this to exclude RFC 1918
addresses, multicast, IANA reserved space, and other IANA
special-purpose addresses. An example blacklist file is provided in
.B conf/blacklist.example
for this purpose.
.TP
.B -w, --whitelist-file=path
File of subnets to constrain scan to, in CIDR
notation, e.g. 192.168.0.0/16
.SS "Scan options"
.TP
.B \-n, --max-targets=n
Cap number of targets to probe (as a number or
a percentage of the address space)
.TP
.B \-N, --max-results=n
Cap number of results to return
.TP
.B \-t, --max-runtime=secs
Cap length of time for sending packets
.TP
.B \-r, --rate=pps
Set send rate in packets/sec
.TP
.B \-B, --bandwidth=bps
Set send rate in bits/second (supports suffixes G, M and K). This
overrides the
.B --rate
flag.
.TP
.B \-c, --cooldown-time=secs
How long to continue receiving after sending
last probe (default=8)
.TP
.B \-e, --seed=n
Seed used to select address permutation. Specify the same seed in order to scan the same sample repeatedly.
.TP
.B \-T, --sender-threads=n
Threads used to send packets (default=1)
.TP
.B \-P, --probes=n
Number of probes to send to each IP
(default=1)
.TP
.B \-d, --dryrun
Print out each packet to stdout instead of sending it.
(May be useful for debugging.)
.SS "Network options"
.TP
.B \-s, --source-port=port|range
Source port(s) for scan packets
.TP
.B \-S, --source-ip=ip|range
Source address(es) for scan packets
.TP
.B \-G, --gateway-mac=addr
Specify gateway MAC address. All packets will be sent to this
Ethernet address.
.TP
.B \-i, --interface=name
Specify network interface to use.
.SS "Advanced options"
.TP
.B \-M, --probe-module=name
Select probe module (default=tcp_synscan)
.TP
.B \-O, --output-module=name
Select output module (default=simple_file)
.TP
.B --probe-args=args
Arguments to pass to probe module
.TP
.B --output-args=args
Arguments to pass to output module
.TP
.B --list-output-modules
List available output modules
.TP
.B --list-probe-modules
List available probe modules
.SS "Additional options"
.TP
.B \-C, --config=filename
Read a configuration file, which can specify
any of these options (default=zmap.conf)
.TP
.B \-q, --quiet
Do not print status updates
.TP
.B \-g, --summary
Print configuration and summary at end of scan
.TP
.B \-v, --verbosity=n
Level of log detail (0-5) (default=3)
.TP
.B \-h, --help
Print help and exit
.TP
.B \-V, --version
Print version and exit
.SH EXAMPLES
Scan the whole Internet for hosts with port 443 open (results discarded):
.PP
.\" -p: example of
.B zmap \-p 443
.PP
Find 5 HTTP servers (port 80), scanning at 10 Mb/s, print the results to stdout:
.PP
.\" -N: example of
.\" -B: example of
.B zmap -N 5 -B 10M -p 80 -o -
.SH WARNING
By default, ZMap attempts to scan at the line speed of your Ethernet
interface and can easily use 1 Gbit/second of bandwidth. If your
network is not able to support sending packets this quickly, your
local network may become congested, causing connectivity problems for
you and those around you. Use the -B (--bandwidth) option to set
ZMap's maximum bandwidth to an appropriate limit for your network and
upstream connection.
.
.SH AUTHOR
Zakir Durumeric,
Eric Wustrow,
J. Alex Halderman
.B (https://www.zmap.io)

483
src/zmap.c Normal file
View File

@ -0,0 +1,483 @@
/*
* ZMap Copyright 2013 Regents of the University of Michigan
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*/
#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <sched.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <net/if.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pcap/pcap.h>
#include <pthread.h>
#include "../lib/logger.h"
#include "../lib/random.h"
#include "zopt.h"
#include "send.h"
#include "recv.h"
#include "state.h"
#include "monitor.h"
#include "output_modules/output_modules.h"
#include "probe_modules/probe_modules.h"
#include "get_gateway.h"
pthread_mutex_t cpu_affinity_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t recv_ready_mutex = PTHREAD_MUTEX_INITIALIZER;
static void set_cpu(void)
{
pthread_mutex_lock(&cpu_affinity_mutex);
static int core=0;
int num_cores = sysconf(_SC_NPROCESSORS_ONLN);
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
CPU_SET(core, &cpuset);
if (pthread_setaffinity_np(pthread_self(),
sizeof(cpu_set_t), &cpuset) != 0) {
log_error("zmap", "can't set thread CPU affinity");
}
log_trace("zmap", "set thread %u affinity to core %d",
pthread_self(), core);
core = (core + 1) % num_cores;
pthread_mutex_unlock(&cpu_affinity_mutex);
}
static void* start_send(__attribute__((unused)) void *arg)
{
set_cpu();
send_run();
return NULL;
}
static void* start_recv(__attribute__((unused)) void *arg)
{
set_cpu();
recv_run(&recv_ready_mutex);
return NULL;
}
static void *start_mon(__attribute__((unused)) void *arg)
{
set_cpu();
monitor_run();
return NULL;
}
#define SI(w,x,y) printf("%s\t%s\t%i\n", w, x, y);
#define SD(w,x,y) printf("%s\t%s\t%f\n", w, x, y);
#define SU(w,x,y) printf("%s\t%s\t%u\n", w, x, y);
#define SLU(w,x,y) printf("%s\t%s\t%lu\n", w, x, y);
#define SS(w,x,y) printf("%s\t%s\t%s\n", w, x, y);
#define STRTIME_LEN 1024
static void summary(void)
{
char send_start_time[STRTIME_LEN+1];
assert(dstrftime(send_start_time, STRTIME_LEN, "%c", zsend.start));
char send_end_time[STRTIME_LEN+1];
assert(dstrftime(send_end_time, STRTIME_LEN, "%c", zsend.finish));
char recv_start_time[STRTIME_LEN+1];
assert(dstrftime(recv_start_time, STRTIME_LEN, "%c", zrecv.start));
char recv_end_time[STRTIME_LEN+1];
assert(dstrftime(recv_end_time, STRTIME_LEN, "%c", zrecv.finish));
double hitrate = ((double) 100 * zrecv.success_unique)/((double)zsend.sent);
SU("cnf", "target-port", zconf.target_port);
SU("cnf", "source-port-range-begin", zconf.source_port_first);
SU("cnf", "source-port-range-end", zconf.source_port_last);
SS("cnf", "source-addr-range-begin", zconf.source_ip_first);
SS("cnf", "source-addr-range-end", zconf.source_ip_last);
SU("cnf", "maximum-targets", zconf.max_targets);
SU("cnf", "maximum-runtime", zconf.max_runtime);
SU("cnf", "maximum-results", zconf.max_results);
SU("cnf", "permutation-seed", zconf.seed);
SI("cnf", "cooldown-period", zconf.cooldown_secs);
SS("cnf", "send-interface", zconf.iface);
SI("cnf", "rate", zconf.rate);
SLU("cnf", "bandwidth", zconf.bandwidth);
SU("env", "nprocessors", (unsigned) sysconf(_SC_NPROCESSORS_ONLN));
SS("exc", "send-start-time", send_start_time);
SS("exc", "send-end-time", send_end_time);
SS("exc", "recv-start-time", recv_start_time);
SS("exc", "recv-end-time", recv_end_time);
SU("exc", "sent", zsend.sent);
SU("exc", "blacklisted", zsend.blacklisted);
SU("exc", "first-scanned", zsend.first_scanned);
SD("exc", "hit-rate", hitrate);
SU("exc", "success-total", zrecv.success_total);
SU("exc", "success-unique", zrecv.success_unique);
SU("exc", "success-cooldown-total", zrecv.cooldown_total);
SU("exc", "success-cooldown-unique", zrecv.cooldown_unique);
SU("exc", "failure-total", zrecv.failure_total);
SU("exc", "sendto-failures", zsend.sendto_failures);
SU("adv", "permutation-gen", zconf.generator);
SS("exc", "scan-type", zconf.probe_module->name);
}
static void start_zmap(void)
{
log_init(stderr, zconf.log_level);
log_info("zmap", "started");
// finish setting up configuration
if (zconf.iface == NULL) {
char errbuf[PCAP_ERRBUF_SIZE];
char *iface = pcap_lookupdev(errbuf);
if (iface == NULL) {
log_fatal("zmap", "could not detect default network interface "
"(e.g. eth0). Try running as root or setting"
" interface using -i flag.");
}
log_debug("zmap", "no interface provided. will use %s", iface);
zconf.iface = iface;
}
if (zconf.source_ip_first == NULL) {
struct in_addr default_ip;
zconf.source_ip_first = malloc(INET_ADDRSTRLEN);
zconf.source_ip_last = zconf.source_ip_first;
if (get_iface_ip(zconf.iface, &default_ip) < 0) {
log_fatal("zmap", "could not detect default IP address for for %s."
" Try specifying a source address (-S).", zconf.iface);
}
inet_ntop(AF_INET, &default_ip, zconf.source_ip_first, INET_ADDRSTRLEN);
log_debug("zmap", "no source IP address given. will use %s",
zconf.source_ip_first);
}
if (!zconf.gw_mac_set) {
struct in_addr gw_ip;
char iface[IF_NAMESIZE];
if (get_default_gw(&gw_ip, iface) < 0) {
log_fatal("zmap", "could not detect default gateway address for %i."
" Try setting default gateway mac address (-G).");
}
log_debug("zmap", "found gateway IP %s on %s", inet_ntoa(gw_ip), iface);
if (get_hw_addr(&gw_ip, iface, zconf.gw_mac) < 0) {
log_fatal("zmap", "could not detect GW MAC address for %s on %s."
" Try setting default gateway mac address (-G).",
inet_ntoa(gw_ip), zconf.iface);
}
zconf.gw_mac_set = 1;
log_debug("zmap", "using default gateway MAC %02x:%02x:%02x:%02x:%02x:%02x",
zconf.gw_mac[0], zconf.gw_mac[1], zconf.gw_mac[2],
zconf.gw_mac[3], zconf.gw_mac[4], zconf.gw_mac[5]);
}
// initialization
if (zconf.output_module && zconf.output_module->init) {
zconf.output_module->init(&zconf);
}
if (send_init()) {
exit(EXIT_FAILURE);
}
if (zconf.output_module && zconf.output_module->start) {
zconf.output_module->start(&zconf, &zsend, &zrecv);
}
// start threads
pthread_t *tsend, trecv, tmon;
int r = pthread_create(&trecv, NULL, start_recv, NULL);
if (r != 0) {
log_fatal("zmap", "unable to create recv thread");
exit(EXIT_FAILURE);
}
for (;;) {
pthread_mutex_lock(&recv_ready_mutex);
if (zconf.recv_ready) {
break;
}
pthread_mutex_unlock(&recv_ready_mutex);
}
tsend = malloc(zconf.senders * sizeof(pthread_t));
assert(tsend);
log_debug("zmap", "using %d sender threads", zconf.senders);
for (int i=0; i < zconf.senders; i++) {
r = pthread_create(&tsend[i], NULL, start_send, NULL);
if (r != 0) {
log_fatal("zmap", "unable to create send thread");
exit(EXIT_FAILURE);
}
}
if (!zconf.quiet) {
r = pthread_create(&tmon, NULL, start_mon, NULL);
if (r != 0) {
log_fatal("zmap", "unable to create monitor thread");
exit(EXIT_FAILURE);
}
}
// wait for completion
for (int i=0; i < zconf.senders; i++) {
pthread_join(tsend[i], NULL);
if (r != 0) {
log_fatal("zmap", "unable to join send thread");
exit(EXIT_FAILURE);
}
}
log_debug("zmap", "senders finished");
pthread_join(trecv, NULL);
if (r != 0) {
log_fatal("zmap", "unable to join recv thread");
exit(EXIT_FAILURE);
}
if (!zconf.quiet) {
pthread_join(tmon, NULL);
if (r != 0) {
log_fatal("zmap", "unable to join monitor thread");
exit(EXIT_FAILURE);
}
}
// finished
if (zconf.summary) {
summary();
}
if (zconf.output_module && zconf.output_module->close) {
zconf.output_module->close(&zconf, &zsend, &zrecv);
}
if (zconf.probe_module && zconf.probe_module->close) {
zconf.probe_module->close(&zconf, &zsend, &zrecv);
}
log_info("zmap", "completed");
}
static void enforce_range(const char *name, int v, int min, int max)
{
if (v < min || v > max) {
fprintf(stderr, "%s: argument `%s' must be between %d and %d\n",
CMDLINE_PARSER_PACKAGE, name, min, max);
exit(EXIT_FAILURE);
}
}
static int file_exists(char *name)
{
FILE *file = fopen(name, "r");
if (!file)
return 0;
fclose(file);
return 1;
}
#define MAC_LEN IFHWADDRLEN
int parse_mac(macaddr_t *out, char *in)
{
if (strlen(in) < MAC_LEN*3-1)
return 0;
char octet[3];
octet[2] = '\0';
for (int i=0; i < MAC_LEN; i++) {
if (i < MAC_LEN-1 && in[i*3+2] != ':') {
return 0;
}
strncpy(octet, &in[i*3], 2);
char *err = NULL;
long b = strtol(octet, &err, 16);
if (err && *err != '\0') {
return 0;
}
out[i] = b & 0xFF;
}
return 1;
}
#define SET_IF_GIVEN(DST,ARG) \
{ if (args.ARG##_given) { (DST) = args.ARG##_arg; }; }
#define SET_BOOL(DST,ARG) \
{ if (args.ARG##_given) { (DST) = 1; }; }
int main(int argc, char *argv[])
{
struct gengetopt_args_info args;
struct cmdline_parser_params *params;
params = cmdline_parser_params_create();
params->initialize = 1;
params->override = 0;
params->check_required = 0;
if (cmdline_parser_ext(argc, argv, &args, params) != 0) {
exit(EXIT_SUCCESS);
}
if (args.help_given) {
cmdline_parser_print_help();
exit(EXIT_SUCCESS);
}
if (args.version_given) {
cmdline_parser_print_version();
exit(EXIT_SUCCESS);
}
if (args.list_output_modules_given) {
print_output_modules();
exit(EXIT_SUCCESS);
}
if (args.list_probe_modules_given) {
print_probe_modules();
exit(EXIT_SUCCESS);
}
if (args.config_given || file_exists(args.config_arg)) {
params->initialize = 0;
params->override = 0;
if (cmdline_parser_config_file(args.config_arg, &args, params)
!= 0) {
exit(EXIT_FAILURE);
}
}
if (cmdline_parser_required(&args, CMDLINE_PARSER_PACKAGE) != 0) {
exit(EXIT_FAILURE);
}
SET_IF_GIVEN(zconf.output_filename, output_file);
SET_IF_GIVEN(zconf.blacklist_filename, blacklist_file);
SET_IF_GIVEN(zconf.whitelist_filename, whitelist_file);
SET_IF_GIVEN(zconf.probe_args, probe_args);
SET_IF_GIVEN(zconf.output_args, output_args);
SET_IF_GIVEN(zconf.iface, interface);
SET_IF_GIVEN(zconf.max_runtime, max_runtime);
SET_IF_GIVEN(zconf.max_results, max_results);
SET_IF_GIVEN(zconf.rate, rate);
SET_IF_GIVEN(zconf.packet_streams, probes);
SET_BOOL(zconf.dryrun, dryrun);
SET_BOOL(zconf.quiet, quiet);
SET_BOOL(zconf.summary, summary);
zconf.cooldown_secs = args.cooldown_time_arg;
zconf.senders = args.sender_threads_arg;
zconf.log_level = args.verbosity_arg;
zconf.output_module = get_output_module_by_name(args.output_module_arg);
if (!zconf.output_module) {
fprintf(stderr, "%s: specified output module (%s) does not exist\n",
args.output_module_arg, CMDLINE_PARSER_PACKAGE);
exit(EXIT_FAILURE);
}
zconf.probe_module = get_probe_module_by_name(args.probe_module_arg);
if (!zconf.probe_module) {
fprintf(stderr, "%s: specified probe module (%s) does not exist\n",
CMDLINE_PARSER_PACKAGE, args.probe_module_arg);
exit(EXIT_FAILURE);
}
if (zconf.probe_module->port_args) {
if (args.source_port_given) {
char *dash = strchr(args.source_port_arg, '-');
if (dash) { // range
*dash = '\0';
zconf.source_port_first = atoi(args.source_port_arg);
enforce_range("starting source-port", zconf.source_port_first, 0, 0xFFFF);
zconf.source_port_last = atoi(dash+1);
enforce_range("ending source-port", zconf.source_port_last, 0, 0xFFFF);
if (zconf.source_port_first > zconf.source_port_last) {
fprintf(stderr, "%s: invalid source port range: "
"last port is less than first port\n",
CMDLINE_PARSER_PACKAGE);
exit(EXIT_FAILURE);
}
} else { // single port
int port = atoi(args.source_port_arg);
enforce_range("source-port", port, 0, 0xFFFF);
zconf.source_port_first = port;
zconf.source_port_last = port;
}
}
if (!args.target_port_given) {
fprintf(stderr, "%s: target port is required for this type of probe\n",
CMDLINE_PARSER_PACKAGE);
exit(EXIT_FAILURE);
}
enforce_range("target-port", args.target_port_arg, 0, 0xFFFF);
zconf.target_port = args.target_port_arg;
}
if (args.source_ip_given) {
char *dash = strchr(args.source_ip_arg, '-');
if (dash) { // range
*dash = '\0';
zconf.source_ip_first = args.source_ip_arg;
zconf.source_ip_last = dash+1;
} else { // single address
zconf.source_ip_first = args.source_ip_arg;
zconf.source_ip_last = args.source_ip_arg;
}
}
if (args.gateway_mac_given) {
if (!parse_mac(zconf.gw_mac, args.gateway_mac_arg)) {
fprintf(stderr, "%s: invalid MAC address `%s'\n",
CMDLINE_PARSER_PACKAGE, args.gateway_mac_arg);
exit(EXIT_FAILURE);
}
zconf.gw_mac_set = 1;
}
if (args.seed_given) {
zconf.seed = args.seed_arg;
zconf.use_seed = 1;
}
if (args.bandwidth_given) {
// Supported: G,g=*1000000000; M,m=*1000000 K,k=*1000 bits per second
zconf.bandwidth = atoi(args.bandwidth_arg);
char *suffix = args.bandwidth_arg;
while (*suffix >= '0' && *suffix <= '9') {
suffix++;
}
if (*suffix) {
switch (*suffix) {
case 'G': case 'g':
zconf.bandwidth *= 1000000000;
break;
case 'M': case 'm':
zconf.bandwidth *= 1000000;
break;
case 'K': case 'k':
zconf.bandwidth *= 1000;
break;
default:
fprintf(stderr, "%s: unknown bandwidth suffix '%s' "
"(supported suffixes are G, M and K)\n",
CMDLINE_PARSER_PACKAGE, suffix);
exit(EXIT_FAILURE);
}
}
}
if (args.max_targets_given) {
errno = 0;
char *end;
double v = strtod(args.max_targets_arg, &end);
if (end == args.max_targets_arg || errno != 0) {
fprintf(stderr, "%s: can't convert max-targets to a number\n",
CMDLINE_PARSER_PACKAGE);
exit(EXIT_FAILURE);
}
if (end[0] == '%' && end[1] == '\0') {
// treat as percentage
v = v * (1L << 32) / 100.;
} else if (end[0] != '\0') {
fprintf(stderr, "%s: extra characters after max-targets\n",
CMDLINE_PARSER_PACKAGE);
exit(EXIT_FAILURE);
}
if (v <= 0) {
zconf.max_targets = 0;
}
else if (v >= (1L << 32)) {
zconf.max_targets = 0xFFFFFFFF;
} else {
zconf.max_targets = v;
}
}
start_zmap();
cmdline_parser_free(&args);
free(params);
return EXIT_SUCCESS;
}

1339
src/zopt.c Normal file

File diff suppressed because it is too large Load Diff

119
src/zopt.ggo Normal file
View File

@ -0,0 +1,119 @@
# ZMap Copyright 2013 Regents of the University of Michigan
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
# zmap option description to be processed by gengetopt
package "zmap"
version "1.0.0"
purpose "A fast Internet-wide scanner."
section "Basic arguments"
option "target-port" p "TCP port number to scan (for SYN scans)"
typestr="port"
optional int
option "output-file" o "Output file"
typestr="name"
optional string
option "blacklist-file" b "File of subnets to exclude, in CIDR notation, e.g. 192.168.0.0/16"
typestr="path"
optional string
option "whitelist-file" w "File of subnets to constrain scan to, in CIDR notation, e.g. 192.168.0.0/16"
typestr="path"
optional string
section "Scan options"
option "max-targets" n "Cap number of targets to probe (as a number or a percentage of the address space)"
typestr="n"
optional string
option "max-results" N "Cap number of results to return"
typestr="n"
optional int
option "max-runtime" t "Cap length of time for sending packets"
typestr="ses"
optional int
option "rate" r "Set send rate in packets/sec"
typestr="pps"
optional int
option "bandwidth" B "Set send rate in bits/second (supports suffixes G, M and K)"
typestr="bps"
optional string
option "cooldown-time" c "How long to continue receiving after sending last probe"
typestr="secs"
default="8"
optional int
option "seed" e "Seed used to select address permutation"
typestr="n"
optional int
option "sender-threads" T "Threads used to send packets"
typestr="n"
default="1"
optional int
option "probes" P "Number of probes to send to each IP"
typestr="n"
default="1"
optional int
option "dryrun" d "Don't actually send packets"
optional
section "Network options"
option "source-port" s "Source port(s) for scan packets"
typestr="port|range"
optional string
option "source-ip" S "Source address(es) for scan packets"
typestr="ip|range"
optional string
option "gateway-mac" G "Specify gateway MAC address"
typestr="addr"
optional string
option "interface" i "Specify network interface to use"
typestr="name"
optional string
section "Advanced options"
option "probe-module" M "Select probe module"
typestr="name"
default="tcp_synscan"
optional string
option "output-module" O "Select output module"
typestr="name"
default="simple_file"
optional string
option "probe-args" - "Arguments to pass to probe module"
typestr="args"
optional string
option "output-args" - "Arguments to pass to output module"
typestr="args"
optional string
option "list-output-modules" - "List available output modules"
optional
option "list-probe-modules" - "List available probe modules"
optional
section "Additional options"
option "config" C "Read a configuration file, which can specify any of these options"
typestr="filename"
default="/etc/zmap/zmap.conf"
optional string
option "quiet" q "Do not print status updates"
optional
option "summary" g "Print configuration and summary at end of scan"
optional
option "verbosity" v "Level of log detail (0-5)"
typestr="n"
default="3"
optional int
option "help" h "Print help and exit"
optional
option "version" V "Print version and exit"
optional
text "\nExamples:\n\
zmap -p 443 (scans the whole Internet for hosts with port 443 open)\n\
zmap -N 5 -B 10M -p 80 -o - (find 5 HTTP servers, scanning at 10 Mb/s)"

298
src/zopt.h Normal file
View File

@ -0,0 +1,298 @@
/** @file zopt.h
* @brief The header file for the command line option parser
* generated by GNU Gengetopt version 2.22.5
* http://www.gnu.org/software/gengetopt.
* DO NOT modify this file, since it can be overwritten
* @author GNU Gengetopt by Lorenzo Bettini */
#ifndef ZOPT_H
#define ZOPT_H
/* If we use autoconf. */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h> /* for FILE */
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#ifndef CMDLINE_PARSER_PACKAGE
/** @brief the program name (used for printing errors) */
#define CMDLINE_PARSER_PACKAGE "zmap"
#endif
#ifndef CMDLINE_PARSER_PACKAGE_NAME
/** @brief the complete program name (used for help and version) */
#define CMDLINE_PARSER_PACKAGE_NAME "zmap"
#endif
#ifndef CMDLINE_PARSER_VERSION
/** @brief the program version */
#define CMDLINE_PARSER_VERSION "1.0.0"
#endif
/** @brief Where the command line options are stored */
struct gengetopt_args_info
{
int target_port_arg; /**< @brief TCP port number to scan (for SYN scans). */
char * target_port_orig; /**< @brief TCP port number to scan (for SYN scans) original value given at command line. */
const char *target_port_help; /**< @brief TCP port number to scan (for SYN scans) help description. */
char * output_file_arg; /**< @brief Output file. */
char * output_file_orig; /**< @brief Output file original value given at command line. */
const char *output_file_help; /**< @brief Output file help description. */
char * blacklist_file_arg; /**< @brief File of subnets to exclude, in CIDR notation, e.g. 192.168.0.0/16. */
char * blacklist_file_orig; /**< @brief File of subnets to exclude, in CIDR notation, e.g. 192.168.0.0/16 original value given at command line. */
const char *blacklist_file_help; /**< @brief File of subnets to exclude, in CIDR notation, e.g. 192.168.0.0/16 help description. */
char * whitelist_file_arg; /**< @brief File of subnets to constrain scan to, in CIDR notation, e.g. 192.168.0.0/16. */
char * whitelist_file_orig; /**< @brief File of subnets to constrain scan to, in CIDR notation, e.g. 192.168.0.0/16 original value given at command line. */
const char *whitelist_file_help; /**< @brief File of subnets to constrain scan to, in CIDR notation, e.g. 192.168.0.0/16 help description. */
char * max_targets_arg; /**< @brief Cap number of targets to probe (as a number or a percentage of the address space). */
char * max_targets_orig; /**< @brief Cap number of targets to probe (as a number or a percentage of the address space) original value given at command line. */
const char *max_targets_help; /**< @brief Cap number of targets to probe (as a number or a percentage of the address space) help description. */
int max_results_arg; /**< @brief Cap number of results to return. */
char * max_results_orig; /**< @brief Cap number of results to return original value given at command line. */
const char *max_results_help; /**< @brief Cap number of results to return help description. */
int max_runtime_arg; /**< @brief Cap length of time for sending packets. */
char * max_runtime_orig; /**< @brief Cap length of time for sending packets original value given at command line. */
const char *max_runtime_help; /**< @brief Cap length of time for sending packets help description. */
int rate_arg; /**< @brief Set send rate in packets/sec. */
char * rate_orig; /**< @brief Set send rate in packets/sec original value given at command line. */
const char *rate_help; /**< @brief Set send rate in packets/sec help description. */
char * bandwidth_arg; /**< @brief Set send rate in bits/second (supports suffixes G, M and K). */
char * bandwidth_orig; /**< @brief Set send rate in bits/second (supports suffixes G, M and K) original value given at command line. */
const char *bandwidth_help; /**< @brief Set send rate in bits/second (supports suffixes G, M and K) help description. */
int cooldown_time_arg; /**< @brief How long to continue receiving after sending last probe (default='8'). */
char * cooldown_time_orig; /**< @brief How long to continue receiving after sending last probe original value given at command line. */
const char *cooldown_time_help; /**< @brief How long to continue receiving after sending last probe help description. */
int seed_arg; /**< @brief Seed used to select address permutation. */
char * seed_orig; /**< @brief Seed used to select address permutation original value given at command line. */
const char *seed_help; /**< @brief Seed used to select address permutation help description. */
int sender_threads_arg; /**< @brief Threads used to send packets (default='1'). */
char * sender_threads_orig; /**< @brief Threads used to send packets original value given at command line. */
const char *sender_threads_help; /**< @brief Threads used to send packets help description. */
int probes_arg; /**< @brief Number of probes to send to each IP (default='1'). */
char * probes_orig; /**< @brief Number of probes to send to each IP original value given at command line. */
const char *probes_help; /**< @brief Number of probes to send to each IP help description. */
const char *dryrun_help; /**< @brief Don't actually send packets help description. */
char * source_port_arg; /**< @brief Source port(s) for scan packets. */
char * source_port_orig; /**< @brief Source port(s) for scan packets original value given at command line. */
const char *source_port_help; /**< @brief Source port(s) for scan packets help description. */
char * source_ip_arg; /**< @brief Source address(es) for scan packets. */
char * source_ip_orig; /**< @brief Source address(es) for scan packets original value given at command line. */
const char *source_ip_help; /**< @brief Source address(es) for scan packets help description. */
char * gateway_mac_arg; /**< @brief Specify gateway MAC address. */
char * gateway_mac_orig; /**< @brief Specify gateway MAC address original value given at command line. */
const char *gateway_mac_help; /**< @brief Specify gateway MAC address help description. */
char * interface_arg; /**< @brief Specify network interface to use. */
char * interface_orig; /**< @brief Specify network interface to use original value given at command line. */
const char *interface_help; /**< @brief Specify network interface to use help description. */
char * probe_module_arg; /**< @brief Select probe module (default='tcp_synscan'). */
char * probe_module_orig; /**< @brief Select probe module original value given at command line. */
const char *probe_module_help; /**< @brief Select probe module help description. */
char * output_module_arg; /**< @brief Select output module (default='simple_file'). */
char * output_module_orig; /**< @brief Select output module original value given at command line. */
const char *output_module_help; /**< @brief Select output module help description. */
char * probe_args_arg; /**< @brief Arguments to pass to probe module. */
char * probe_args_orig; /**< @brief Arguments to pass to probe module original value given at command line. */
const char *probe_args_help; /**< @brief Arguments to pass to probe module help description. */
char * output_args_arg; /**< @brief Arguments to pass to output module. */
char * output_args_orig; /**< @brief Arguments to pass to output module original value given at command line. */
const char *output_args_help; /**< @brief Arguments to pass to output module help description. */
const char *list_output_modules_help; /**< @brief List available output modules help description. */
const char *list_probe_modules_help; /**< @brief List available probe modules help description. */
char * config_arg; /**< @brief Read a configuration file, which can specify any of these options (default='/etc/zmap/zmap.conf'). */
char * config_orig; /**< @brief Read a configuration file, which can specify any of these options original value given at command line. */
const char *config_help; /**< @brief Read a configuration file, which can specify any of these options help description. */
const char *quiet_help; /**< @brief Do not print status updates help description. */
const char *summary_help; /**< @brief Print configuration and summary at end of scan help description. */
int verbosity_arg; /**< @brief Level of log detail (0-5) (default='3'). */
char * verbosity_orig; /**< @brief Level of log detail (0-5) original value given at command line. */
const char *verbosity_help; /**< @brief Level of log detail (0-5) help description. */
const char *help_help; /**< @brief Print help and exit help description. */
const char *version_help; /**< @brief Print version and exit help description. */
unsigned int target_port_given ; /**< @brief Whether target-port was given. */
unsigned int output_file_given ; /**< @brief Whether output-file was given. */
unsigned int blacklist_file_given ; /**< @brief Whether blacklist-file was given. */
unsigned int whitelist_file_given ; /**< @brief Whether whitelist-file was given. */
unsigned int max_targets_given ; /**< @brief Whether max-targets was given. */
unsigned int max_results_given ; /**< @brief Whether max-results was given. */
unsigned int max_runtime_given ; /**< @brief Whether max-runtime was given. */
unsigned int rate_given ; /**< @brief Whether rate was given. */
unsigned int bandwidth_given ; /**< @brief Whether bandwidth was given. */
unsigned int cooldown_time_given ; /**< @brief Whether cooldown-time was given. */
unsigned int seed_given ; /**< @brief Whether seed was given. */
unsigned int sender_threads_given ; /**< @brief Whether sender-threads was given. */
unsigned int probes_given ; /**< @brief Whether probes was given. */
unsigned int dryrun_given ; /**< @brief Whether dryrun was given. */
unsigned int source_port_given ; /**< @brief Whether source-port was given. */
unsigned int source_ip_given ; /**< @brief Whether source-ip was given. */
unsigned int gateway_mac_given ; /**< @brief Whether gateway-mac was given. */
unsigned int interface_given ; /**< @brief Whether interface was given. */
unsigned int probe_module_given ; /**< @brief Whether probe-module was given. */
unsigned int output_module_given ; /**< @brief Whether output-module was given. */
unsigned int probe_args_given ; /**< @brief Whether probe-args was given. */
unsigned int output_args_given ; /**< @brief Whether output-args was given. */
unsigned int list_output_modules_given ; /**< @brief Whether list-output-modules was given. */
unsigned int list_probe_modules_given ; /**< @brief Whether list-probe-modules was given. */
unsigned int config_given ; /**< @brief Whether config was given. */
unsigned int quiet_given ; /**< @brief Whether quiet was given. */
unsigned int summary_given ; /**< @brief Whether summary was given. */
unsigned int verbosity_given ; /**< @brief Whether verbosity was given. */
unsigned int help_given ; /**< @brief Whether help was given. */
unsigned int version_given ; /**< @brief Whether version was given. */
} ;
/** @brief The additional parameters to pass to parser functions */
struct cmdline_parser_params
{
int override; /**< @brief whether to override possibly already present options (default 0) */
int initialize; /**< @brief whether to initialize the option structure gengetopt_args_info (default 1) */
int check_required; /**< @brief whether to check that all required options were provided (default 1) */
int check_ambiguity; /**< @brief whether to check for options already specified in the option structure gengetopt_args_info (default 0) */
int print_errors; /**< @brief whether getopt_long should print an error message for a bad option (default 1) */
} ;
/** @brief the purpose string of the program */
extern const char *gengetopt_args_info_purpose;
/** @brief the usage string of the program */
extern const char *gengetopt_args_info_usage;
/** @brief all the lines making the help output */
extern const char *gengetopt_args_info_help[];
/**
* The command line parser
* @param argc the number of command line options
* @param argv the command line options
* @param args_info the structure where option information will be stored
* @return 0 if everything went fine, NON 0 if an error took place
*/
int cmdline_parser (int argc, char **argv,
struct gengetopt_args_info *args_info);
/**
* The command line parser (version with additional parameters - deprecated)
* @param argc the number of command line options
* @param argv the command line options
* @param args_info the structure where option information will be stored
* @param override whether to override possibly already present options
* @param initialize whether to initialize the option structure my_args_info
* @param check_required whether to check that all required options were provided
* @return 0 if everything went fine, NON 0 if an error took place
* @deprecated use cmdline_parser_ext() instead
*/
int cmdline_parser2 (int argc, char **argv,
struct gengetopt_args_info *args_info,
int override, int initialize, int check_required);
/**
* The command line parser (version with additional parameters)
* @param argc the number of command line options
* @param argv the command line options
* @param args_info the structure where option information will be stored
* @param params additional parameters for the parser
* @return 0 if everything went fine, NON 0 if an error took place
*/
int cmdline_parser_ext (int argc, char **argv,
struct gengetopt_args_info *args_info,
struct cmdline_parser_params *params);
/**
* Save the contents of the option struct into an already open FILE stream.
* @param outfile the stream where to dump options
* @param args_info the option struct to dump
* @return 0 if everything went fine, NON 0 if an error took place
*/
int cmdline_parser_dump(FILE *outfile,
struct gengetopt_args_info *args_info);
/**
* Save the contents of the option struct into a (text) file.
* This file can be read by the config file parser (if generated by gengetopt)
* @param filename the file where to save
* @param args_info the option struct to save
* @return 0 if everything went fine, NON 0 if an error took place
*/
int cmdline_parser_file_save(const char *filename,
struct gengetopt_args_info *args_info);
/**
* Print the help
*/
void cmdline_parser_print_help(void);
/**
* Print the version
*/
void cmdline_parser_print_version(void);
/**
* Initializes all the fields a cmdline_parser_params structure
* to their default values
* @param params the structure to initialize
*/
void cmdline_parser_params_init(struct cmdline_parser_params *params);
/**
* Allocates dynamically a cmdline_parser_params structure and initializes
* all its fields to their default values
* @return the created and initialized cmdline_parser_params structure
*/
struct cmdline_parser_params *cmdline_parser_params_create(void);
/**
* Initializes the passed gengetopt_args_info structure's fields
* (also set default values for options that have a default)
* @param args_info the structure to initialize
*/
void cmdline_parser_init (struct gengetopt_args_info *args_info);
/**
* Deallocates the string fields of the gengetopt_args_info structure
* (but does not deallocate the structure itself)
* @param args_info the structure to deallocate
*/
void cmdline_parser_free (struct gengetopt_args_info *args_info);
/**
* The config file parser (deprecated version)
* @param filename the name of the config file
* @param args_info the structure where option information will be stored
* @param override whether to override possibly already present options
* @param initialize whether to initialize the option structure my_args_info
* @param check_required whether to check that all required options were provided
* @return 0 if everything went fine, NON 0 if an error took place
* @deprecated use cmdline_parser_config_file() instead
*/
int cmdline_parser_configfile (const char *filename,
struct gengetopt_args_info *args_info,
int override, int initialize, int check_required);
/**
* The config file parser
* @param filename the name of the config file
* @param args_info the structure where option information will be stored
* @param params additional parameters for the parser
* @return 0 if everything went fine, NON 0 if an error took place
*/
int cmdline_parser_config_file (const char *filename,
struct gengetopt_args_info *args_info,
struct cmdline_parser_params *params);
/**
* Checks that all the required options were specified
* @param args_info the structure to check
* @param prog_name the name of the program that will be used to print
* possible errors
* @return
*/
int cmdline_parser_required (struct gengetopt_args_info *args_info,
const char *prog_name);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* ZOPT_H */