diff --git a/src/Makefile b/src/Makefile index a1446dd..7a85fd5 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,10 +1,25 @@ -INCLUDE+=-I../lib -I./ -Ioutput_modules -LDFLAGS+=-pthread -LDLIBS+=-lpcap -lgmp -lm +#<<<<<<< HEAD +CC=gcc +#CC=clang + +#CFLAGS=-Wall -pedantic -Wextra -std=gnu99 -I../lib -I./ -Ioutput_modules -O2 -g +#wbk makefile hack to get rolling with C port. Fix later lol +CFLAGS=-Wall -pedantic -Wextra -std=gnu99 -I../lib -I./ -Ioutput_modules \ +-O2 -g -D__FREEBSD__ -D__FREEBSD_INCLUDES__ -D__FREEBSD_PTHREADS__ -DZMAP_PCAP_INJECT +LDFLAGS=-g -pthread +LDLIBS= -lpcap -lgmp -lm +#======= +#INCLUDE+=-I../lib -I./ -Ioutput_modules +#LDFLAGS+=-pthread +#LDLIBS+=-lpcap -lgmp -lm +#>>>>>>> 5cd6f3294cb4f6ddf711b4c42d72893989a9dc3d TARGETS=zmap VPATH=../lib:output_modules:probe_modules PREFIX=/usr/local +#wbk +LIBDIR=/usr/local/lib + INSTALL=install INSTALLDATA=install -m 644 mandir=$(PREFIX)/man/man1/ @@ -12,23 +27,43 @@ oldmanfile=/usr/share/man/man1/zmap.1 bindir=$(PREFIX)/sbin # Hardening and warnings for building with gcc -# Maybe add -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -GCCWARNINGS = -Wall -Wformat=2 -Wno-format-nonliteral\ --pedantic -fno-strict-aliasing \ --Wextra \ --Wfloat-equal -Wundef -Wwrite-strings -Wredundant-decls \ +#<<<<<<< HEAD +#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 \ -Wnested-externs -Wbad-function-cast -Winit-self \ --Wmissing-noreturn -Wnormalized=id \ --Wstack-protector +-Wmissing-field-initializers \ +-Waddress -Wmissing-noreturn -Wnormalized=id \ +-Woverride-init -Wstrict-overflow=1 -Wextra \ +-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 +# clang doesn't like this +#LDHARDENING=-z relro -z now -GCCHARDENING=-U_FORTIFY_SOURCE -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) +#======= +# Maybe add -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations +#GCCWARNINGS = -Wall -Wformat=2 -Wno-format-nonliteral\ +#-pedantic -fno-strict-aliasing \ +#-Wextra \ +#-Wfloat-equal -Wundef -Wwrite-strings -Wredundant-decls \ +#-Wnested-externs -Wbad-function-cast -Winit-self \ +#-Wmissing-noreturn -Wnormalized=id \ +#-Wstack-protector -EXTRACFLAGS=-std=gnu99 -g -O2 $(GCCHARDENING) $(GCCWARNINGS) $(EXTRA_CFLAGS) -Werror +#GCCHARDENING=-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 -fstack-protector-all -fwrapv -fPIC --param ssp-buffer-size=1 +#LDHARDENING=-z relro -z now + +#EXTRACFLAGS=-std=gnu99 -g -O2 $(GCCHARDENING) $(GCCWARNINGS) $(EXTRA_CFLAGS) -Werror +#>>>>>>> 5cd6f3294cb4f6ddf711b4c42d72893989a9dc3d EXTRALDFLAGS= $(LDHARDENING) CFLAGS+=$(INCLUDE) $(EXTRACFLAGS) LDFLAGS+=$(EXTRALDFLAGS) +LDFLAGS+=-L$(LIBDIR) probemodules=module_tcp_synscan.o module_icmp_echo.o module_udp.o #ADD YOUR PROBE MODULE HERE outputmodules= module_csv.o #ADD YOUR OUTPUT MODULE HERE @@ -51,7 +86,7 @@ endif all: $(TARGETS) $(TARGETS): - $(CC) $(CFLAGS) $(DFLAGS) $(LDFLAGS) $^ -o $@ $(LDLIBS) + $(CC) $(CFLAGS) $(DFLAGS) $(LDFLAGS) $^ -o $@ $(LDLIBS) zmap: $(objects) diff --git a/src/cyclic.c b/src/cyclic.c index a42c7f4..2134d7e 100644 --- a/src/cyclic.c +++ b/src/cyclic.c @@ -48,7 +48,11 @@ #include #include +#ifdef __FREEBSD_INCLUDES__ +#include +#else #include +#endif #include "../lib/logger.h" #include "../lib/blacklist.h" diff --git a/src/fieldset.c b/src/fieldset.c index eb5d27e..5a3534d 100644 --- a/src/fieldset.c +++ b/src/fieldset.c @@ -35,6 +35,8 @@ fieldset_t *fs_new_fieldset(void) return f; } +/* wbk TODO: Might have some subtle issues here on 32 bit architectures. Getting + compiler warnings about casting void* to uint64_t */ static inline void fs_add_word(fieldset_t *fs, const char *name, int type, int free_, size_t len, void *value) { diff --git a/src/get_gateway.c b/src/get_gateway.c index 52e32b6..b5126b2 100644 --- a/src/get_gateway.c +++ b/src/get_gateway.c @@ -15,16 +15,22 @@ #include #include -#include -#include -#include -#include +#ifdef __FREEBSD__ + #include +#else + #include + #include + #include + #include +#endif #include #include #include #include "../lib/logger.h" +#ifdef __FREEBSD__ +#else int read_nl_sock(int sock, char *buf, int buf_len) { int msg_len = 0; @@ -87,7 +93,14 @@ int send_nl_req(uint16_t msg_type, uint32_t seq, free(nlmsg); return sock; } +#endif +#ifdef __FREEBSD__ +int get_hw_addr(struct in_addr *gw_ip, char *iface, unsigned char *hw_mac) { + log_fatal("get-gw", "get_hw_addr() not yet implemented for BSD"); + return -1; +} +#else int get_hw_addr(struct in_addr *gw_ip, char *iface, unsigned char *hw_mac) { char buf[8192]; @@ -164,8 +177,19 @@ int get_hw_addr(struct in_addr *gw_ip, char *iface, unsigned char *hw_mac) } return -1; } +#endif // gw and iface[IF_NAMESIZE] MUST be allocated +/* wbk TODO: Need a better understanding of what the Linux rt stuff + is doing. May be portable to BSD using different constants */ +#ifdef __FREEBSD__ +/* TODO */ +int get_default_gw(struct in_addr *gw, char *iface) +{ + log_fatal("get-gw", "get_default_gw() not yet implemented for BSD; use -G [router MAC] instead"); + return -1; +} +#else int get_default_gw(struct in_addr *gw, char *iface) { struct rtmsg req; @@ -223,8 +247,29 @@ int get_default_gw(struct in_addr *gw, char *iface) } return -1; } +#endif // Returns the first IP address for a given iface +#ifdef __FREEBSD__ +int get_iface_ip(char *iface, struct in_addr *ip) +{ + /* retrieve IP address using getifaddrs(). Should port across BSD's. */ + struct ifaddrs *p = NULL; + struct sockaddr_in *sin = NULL; + if (getifaddrs(&p) == -1) { + log_fatal("get_getway", "get_if_ip() getifaddrs() failed!"); + } + for (; p != NULL; p = p->ifa_next) { + if ( (p->ifa_addr->sa_family == AF_INET) + && (strncmp(iface, p->ifa_name, IF_NAMESIZE) == 0) ) + { + sin = (struct sockaddr_in *)(p->ifa_addr); + memcpy(ip, &(sin->sin_addr), sizeof(*ip)); + return 0; + } + } +} +#else int get_iface_ip(char *iface, struct in_addr *ip) { int sock; @@ -246,4 +291,4 @@ int get_iface_ip(char *iface, struct in_addr *ip) memcpy(ip, &((struct sockaddr_in*)&ifr.ifr_addr)->sin_addr, sizeof(*ip)); return 0; } - +#endif diff --git a/src/probe_modules/module_icmp_echo.c b/src/probe_modules/module_icmp_echo.c index b276968..005bcda 100644 --- a/src/probe_modules/module_icmp_echo.c +++ b/src/probe_modules/module_icmp_echo.c @@ -15,12 +15,14 @@ #include #include +#ifndef __FREEBSD__ #include +#endif +#include /* wbk order */ #include #include #include -#include #include #include "probe_modules.h" @@ -35,11 +37,20 @@ int icmp_echo_init_perthread(void* buf, macaddr_t *src, { memset(buf, 0, MAX_PACKET_SIZE); +#ifdef __FREEBSD__ + struct zmap_ethhdr *eth_header = (struct zmap_ethhdr *)buf; +#else struct ethhdr *eth_header = (struct ethhdr *)buf; +#endif make_eth_header(eth_header, src, gw); +#ifdef __FREEBSD__ + struct zmap_iphdr *ip_header = (struct zmap_iphdr*)(ð_header[1]); + uint16_t len = htons(sizeof(struct zmap_iphdr) + sizeof(struct icmp) - 8); +#else struct iphdr *ip_header = (struct iphdr*)(ð_header[1]); uint16_t len = htons(sizeof(struct iphdr) + sizeof(struct icmp) - 8); +#endif make_ip_header(ip_header, IPPROTO_ICMP, len); struct icmp *icmp_header = (struct icmp*)(&ip_header[1]); @@ -51,13 +62,23 @@ int icmp_echo_init_perthread(void* buf, macaddr_t *src, 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) { +#ifdef __FREEBSD__ + struct zmap_ethhdr *eth_header = (struct zmap_ethhdr *)buf; + struct zmap_iphdr *ip_header = (struct zmap_iphdr*)(ð_header[1]); +#else struct ethhdr *eth_header = (struct ethhdr *)buf; struct iphdr *ip_header = (struct iphdr*)(ð_header[1]); - struct icmp *icmp_header = (struct icmp*)(&ip_header[1]); +#endif + struct icmp *icmp_header = (struct icmp*)(&ip_header[1]); /* TODO: struct icmp? */ uint16_t icmp_idnum = validation[2] & 0xFFFF; +#ifdef __FREEBSD__ + ip_header->saddr.s_addr = src_ip; + ip_header->daddr.s_addr = dst_ip; +#else ip_header->saddr = src_ip; ip_header->daddr = dst_ip; +#endif icmp_header->icmp_id = icmp_idnum; icmp_header->icmp_cksum = 0; @@ -71,8 +92,13 @@ int icmp_echo_make_packet(void *buf, ipaddr_n_t src_ip, ipaddr_n_t dst_ip, void icmp_echo_print_packet(FILE *fp, void* packet) { +#ifdef __FREEBSD__ + struct zmap_ethhdr *ethh = (struct zmap_ethhdr *) packet; + struct zmap_iphdr *iph = (struct zmap_iphdr *) ðh[1]; +#else struct ethhdr *ethh = (struct ethhdr *) packet; struct iphdr *iph = (struct iphdr *) ðh[1]; +#endif struct icmp *icmp_header = (struct icmp*)(&iph[1]); fprintf(fp, "icmp { type: %u | code: %u " @@ -87,10 +113,13 @@ void icmp_echo_print_packet(FILE *fp, void* packet) fprintf(fp, "------------------------------------------------------\n"); } - - +#ifdef __FREEBSD__ +int icmp_validate_packet(const struct zmap_iphdr *ip_hdr, + uint32_t len, uint32_t *src_ip, uint32_t *validation) +#else int icmp_validate_packet(const struct iphdr *ip_hdr, uint32_t len, uint32_t *src_ip, uint32_t *validation) +#endif { if (ip_hdr->protocol != IPPROTO_ICMP) { return 0; @@ -101,27 +130,50 @@ int icmp_validate_packet(const struct iphdr *ip_hdr, return 0; } +#ifdef __FREEBSD__ + struct zmap_icmphdr *icmp_h = (struct zmap_icmphdr*)((char *)ip_hdr + 4*ip_hdr->ihl); +#else struct icmphdr *icmp_h = (struct icmphdr*)((char *)ip_hdr + 4*ip_hdr->ihl); +#endif 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) + +#ifdef __FREEBSD__ + sizeof(struct zmap_iphdr)) > len) { +#else sizeof(struct iphdr)) > len) { +#endif return 0; } +#ifdef __FREEBSD__ + struct zmap_iphdr *ip_inner = (struct zmap_iphdr *)(icmp_h + 1); + if ((4*ip_hdr->ihl + sizeof(struct zmap_icmphdr) + + 4*ip_inner->ihl + sizeof(struct zmap_icmphdr)) > len) { +#else 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) { +#endif return 0; } +#ifdef __FREEBSD__ + struct zmap_icmphdr *icmp_inner = (struct zmap_icmphdr*)((char *)ip_inner + 4 *ip_hdr->ihl); +#else struct icmphdr *icmp_inner = (struct icmphdr*)((char *)ip_inner + 4 *ip_hdr->ihl); +#endif // Regenerate validation and icmp id based off inner payload icmp_idnum = icmp_inner->un.echo.id; +#ifdef __FREEBSD__ + *src_ip = ip_inner->daddr.s_addr; + validate_gen(ip_hdr->daddr.s_addr, ip_inner->daddr.s_addr, (uint8_t *)validation); +#else *src_ip = ip_inner->daddr; validate_gen(ip_hdr->daddr, ip_inner->daddr, (uint8_t *)validation); +#endif } // validate icmp id @@ -135,8 +187,13 @@ int icmp_validate_packet(const struct iphdr *ip_hdr, void icmp_echo_process_packet(const u_char *packet, __attribute__((unused)) uint32_t len, fieldset_t *fs) { +#ifdef __FREEBSD__ + struct zmap_iphdr *ip_hdr = (struct zmap_iphdr *)&packet[sizeof(struct zmap_ethhdr)]; + struct zmap_icmphdr *icmp_hdr = (struct zmap_icmphdr*)((char *)ip_hdr + 4 *ip_hdr->ihl); +#else struct iphdr *ip_hdr = (struct iphdr *)&packet[sizeof(struct ethhdr)]; struct icmphdr *icmp_hdr = (struct icmphdr*)((char *)ip_hdr + 4 *ip_hdr->ihl); +#endif fs_add_uint64(fs, "type", icmp_hdr->type); fs_add_uint64(fs, "code", icmp_hdr->code); fs_add_uint64(fs, "icmp-id", ntohs(icmp_hdr->un.echo.id)); diff --git a/src/probe_modules/module_tcp_synscan.c b/src/probe_modules/module_tcp_synscan.c index 52f4863..71add48 100644 --- a/src/probe_modules/module_tcp_synscan.c +++ b/src/probe_modules/module_tcp_synscan.c @@ -15,9 +15,16 @@ #include #include +#ifdef __FREEBSD__ // TODO: __FREEBSD_INCLUDES__? + /* TODO: This may break Linux, might need to remove #ifdef here entirely */ + #include /* wbk needed before netinet/ip.h */ +#endif #include #include -#include +#ifdef __FREEBSD__ +#else + #include +#endif #include #include @@ -40,12 +47,25 @@ int synscan_init_perthread(void* buf, macaddr_t *src, macaddr_t *gw, port_h_t dst_port) { memset(buf, 0, MAX_PACKET_SIZE); +#ifdef __FREEBSD__ + struct zmap_ethhdr *eth_header = (struct zmap_ethhdr *)buf; +#else struct ethhdr *eth_header = (struct ethhdr *)buf; +#endif make_eth_header(eth_header, src, gw); +#ifdef __FREEBSD__ + struct zmap_iphdr *ip_header = (struct zmap_iphdr*)(ð_header[1]); + uint16_t len = htons(sizeof(struct zmap_iphdr) + sizeof(struct zmap_tcphdr)); +#else struct iphdr *ip_header = (struct iphdr*)(ð_header[1]); uint16_t len = htons(sizeof(struct iphdr) + sizeof(struct tcphdr)); +#endif make_ip_header(ip_header, IPPROTO_TCP, len); +#ifdef __FREEBSD__ + struct zmap_tcphdr *tcp_header = (struct zmap_tcphdr*)(&ip_header[1]); +#else struct tcphdr *tcp_header = (struct tcphdr*)(&ip_header[1]); +#endif make_tcp_header(tcp_header, dst_port); return EXIT_SUCCESS; } @@ -53,20 +73,45 @@ int synscan_init_perthread(void* buf, macaddr_t *src, int synscan_make_packet(void *buf, ipaddr_n_t src_ip, ipaddr_n_t dst_ip, uint32_t *validation, int probe_num) { +#ifdef __FREEBSD__ + struct zmap_ethhdr *eth_header = (struct zmap_ethhdr *)buf; + struct zmap_iphdr *ip_header = (struct zmap_iphdr*)(ð_header[1]); + struct zmap_tcphdr *tcp_header = (struct zmap_tcphdr*)(&ip_header[1]); /* How does this work? What about options? */ +#else struct ethhdr *eth_header = (struct ethhdr *)buf; struct iphdr *ip_header = (struct iphdr*)(ð_header[1]); struct tcphdr *tcp_header = (struct tcphdr*)(&ip_header[1]); +#endif uint32_t tcp_seq = validation[0]; +#ifdef __FREEBSD__ + ip_header->saddr.s_addr = src_ip; + ip_header->daddr.s_addr = dst_ip; +#else ip_header->saddr = src_ip; ip_header->daddr = dst_ip; +#endif tcp_header->source = htons(get_src_port(num_ports, probe_num, validation)); tcp_header->seq = tcp_seq; tcp_header->check = 0; +#ifdef __FREEBSD__ + tcp_header->check = tcp_checksum(sizeof(struct zmap_tcphdr), + ip_header->saddr.s_addr, ip_header->daddr.s_addr, tcp_header); + + /* wbk Set TCP data offset. I think Linux SOCK_RAW might have set this for us + on Linux. Hardcoding for now. */ + //tcp_header->th_offx2 = 0x50; + //tcp_header->th_flags = 0x02; + /* If we ever add TCP options, we'll need to calculate header length in words and replace + 5 with that. */ + tcp_header->th_offx2 = (0x5 << 4); + tcp_header->th_flags = TH_SYN; +#else tcp_header->check = tcp_checksum(sizeof(struct tcphdr), ip_header->saddr, ip_header->daddr, tcp_header); +#endif ip_header->check = 0; ip_header->check = ip_checksum((unsigned short *) ip_header); @@ -76,9 +121,15 @@ int synscan_make_packet(void *buf, ipaddr_n_t src_ip, ipaddr_n_t dst_ip, void synscan_print_packet(FILE *fp, void* packet) { +#ifdef __FREEBSD__ + struct zmap_ethhdr *ethh = (struct zmap_ethhdr *) packet; + struct zmap_iphdr *iph = (struct zmap_iphdr *) ðh[1]; + struct zmap_tcphdr *tcph = (struct zmap_tcphdr *) &iph[1]; +#else struct ethhdr *ethh = (struct ethhdr *) packet; struct iphdr *iph = (struct iphdr *) ðh[1]; struct tcphdr *tcph = (struct tcphdr *) &iph[1]; +#endif fprintf(fp, "tcp { source: %u | dest: %u | seq: %u | checksum: %u }\n", ntohs(tcph->source), ntohs(tcph->dest), @@ -89,9 +140,15 @@ void synscan_print_packet(FILE *fp, void* packet) fprintf(fp, "------------------------------------------------------\n"); } +#ifdef __FREEBSD__ +int synscan_validate_packet(const struct zmap_iphdr *ip_hdr, uint32_t len, + __attribute__((unused))uint32_t *src_ip, + uint32_t *validation) +#else int synscan_validate_packet(const struct iphdr *ip_hdr, uint32_t len, __attribute__((unused))uint32_t *src_ip, uint32_t *validation) +#endif { if (ip_hdr->protocol != IPPROTO_TCP) { return 0; @@ -100,7 +157,11 @@ int synscan_validate_packet(const struct iphdr *ip_hdr, uint32_t len, // buffer not large enough to contain expected tcp header return 0; } +#ifdef __FREEBSD__ + struct zmap_tcphdr *tcp = (struct zmap_tcphdr*)((char *)ip_hdr + 4*ip_hdr->ihl);/*TODO*/ +#else struct tcphdr *tcp = (struct tcphdr*)((char *)ip_hdr + 4*ip_hdr->ihl); +#endif uint16_t sport = tcp->source; uint16_t dport = tcp->dest; // validate source port @@ -121,17 +182,31 @@ int synscan_validate_packet(const struct iphdr *ip_hdr, uint32_t len, void synscan_process_packet(const u_char *packet, __attribute__((unused)) uint32_t len, fieldset_t *fs) { +#ifdef __FREEBSD__ + struct zmap_iphdr *ip_hdr = (struct zmap_iphdr *)&packet[sizeof(struct zmap_ethhdr)]; + struct zmap_tcphdr *tcp = (struct zmap_tcphdr*)((char *)ip_hdr + + (sizeof(struct zmap_iphdr))); +#else struct iphdr *ip_hdr = (struct iphdr *)&packet[sizeof(struct ethhdr)]; struct tcphdr *tcp = (struct tcphdr*)((char *)ip_hdr + (sizeof(struct iphdr))); +#endif fs_add_uint64(fs, "sport", (uint64_t) ntohs(tcp->source)); fs_add_uint64(fs, "dport", (uint64_t) ntohs(tcp->dest)); fs_add_uint64(fs, "seqnum", (uint64_t) ntohl(tcp->seq)); fs_add_uint64(fs, "acknum", (uint64_t) ntohl(tcp->ack_seq)); +#ifdef __FREEBSD__ + fs_add_uint64(fs, "window", (uint64_t) ntohs(tcp->th_win)); +#else fs_add_uint64(fs, "window", (uint64_t) ntohs(tcp->window)); +#endif +#ifdef __FREEBSD__ + if (tcp->th_flags & TH_RST) { // RST packet +#else if (tcp->rst) { // RST packet +#endif fs_add_string(fs, "classification", (char*) "rst", 0); fs_add_uint64(fs, "success", 0); } else { // SYNACK packet diff --git a/src/probe_modules/module_udp.c b/src/probe_modules/module_udp.c index 8bb8b99..effc68f 100644 --- a/src/probe_modules/module_udp.c +++ b/src/probe_modules/module_udp.c @@ -16,12 +16,17 @@ #include #include +#include /* wbk order */ #include -#include -#include +#ifdef __FREEBSD__ + #include "proto_headers.h" /* wbk TODO: test */ +#else + #include + #include /* wbk TODO: Probably need proto_headers.h instead */ + #include +#endif #include -#include #include #include "probe_modules.h" @@ -159,20 +164,36 @@ 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); +#ifdef __FREEBSD__ + struct zmap_ethhdr *eth_header = (struct zmap_ethhdr *)buf; + make_eth_header(eth_header, src, gw); + struct zmap_iphdr *ip_header = (struct zmap_iphdr*)(ð_header[1]); + uint16_t len = htons(sizeof(struct zmap_iphdr) + sizeof(struct zmap_udphdr) + udp_send_msg_len); +#else struct ethhdr *eth_header = (struct ethhdr *)buf; make_eth_header(eth_header, src, gw); struct iphdr *ip_header = (struct iphdr*)(ð_header[1]); uint16_t len = htons(sizeof(struct iphdr) + sizeof(struct udphdr) + udp_send_msg_len); +#endif make_ip_header(ip_header, IPPROTO_UDP, len); +#ifdef __FREEBSD__ + struct zmap_udphdr *udp_header = (struct zmap_udphdr*)(&ip_header[1]); +#else struct udphdr *udp_header = (struct udphdr*)(&ip_header[1]); +#endif len = sizeof(struct udphdr) + udp_send_msg_len; make_udp_header(udp_header, zconf.target_port, len); char* payload = (char*)(&udp_header[1]); +#ifdef __FREEBSD__ + module_udp.packet_length = sizeof(struct zmap_ethhdr) + sizeof(struct zmap_iphdr) + + sizeof(struct zmap_udphdr) + udp_send_msg_len; +#else module_udp.packet_length = sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct udphdr) + udp_send_msg_len; +#endif assert(module_udp.packet_length <= MAX_PACKET_SIZE); memcpy(payload, udp_send_msg, udp_send_msg_len); @@ -183,12 +204,24 @@ int udp_init_perthread(void* buf, macaddr_t *src, int udp_make_packet(void *buf, ipaddr_n_t src_ip, ipaddr_n_t dst_ip, uint32_t *validation, int probe_num) { +#ifdef __FREEBSD__ + struct zmap_ethhdr *eth_header = (struct zmap_ethhdr *)buf; + struct zmap_iphdr *ip_header = (struct zmap_iphdr*)(ð_header[1]); + struct zmap_udphdr *udp_header = (struct zmap_udphdr*)(&ip_header[1]); +#else struct ethhdr *eth_header = (struct ethhdr *)buf; struct iphdr *ip_header = (struct iphdr*)(ð_header[1]); struct udphdr *udp_header = (struct udphdr*)(&ip_header[1]); +#endif +#ifdef __FREEBSD__ + ip_header->saddr.s_addr = src_ip; + ip_header->daddr.s_addr = dst_ip; +#else ip_header->saddr = src_ip; ip_header->daddr = dst_ip; +#endif + udp_header->source = get_src_port(num_ports, probe_num, validation); ip_header->check = 0; @@ -199,9 +232,15 @@ int udp_make_packet(void *buf, ipaddr_n_t src_ip, ipaddr_n_t dst_ip, void udp_print_packet(FILE *fp, void* packet) { +#ifdef __FREEBSD__ + struct zmap_ethhdr *ethh = (struct zmap_ethhdr *) packet; + struct zmap_iphdr *iph = (struct zmap_iphdr *) ðh[1]; + struct zmap_udphdr *udph = (struct zmap_udphdr*)(&iph[1]); +#else struct ethhdr *ethh = (struct ethhdr *) packet; struct iphdr *iph = (struct iphdr *) ðh[1]; struct udphdr *udph = (struct udphdr*)(&iph[1]); +#endif fprintf(fp, "udp { source: %u | dest: %u | checksum: %u }\n", ntohs(udph->source), ntohs(udph->dest), @@ -213,9 +252,16 @@ void udp_print_packet(FILE *fp, void* packet) void udp_process_packet(const u_char *packet, UNUSED uint32_t len, fieldset_t *fs) { - struct iphdr *ip_hdr = (struct iphdr *)&packet[sizeof(struct ethhdr)]; +#ifdef __FREEBSD__ + struct zmap_iphdr *ip_hdr = (struct zmap_iphdr *)&packet[sizeof(struct zmap_ethhdr)]; +#else +#endif if (ip_hdr->protocol == IPPROTO_UDP) { +#ifdef __FREEBSD__ + struct zmap_udphdr *udp = (struct zmap_udphdr *)((char *)ip_hdr + ip_hdr->ihl * 4); +#else struct udphdr *udp = (struct udphdr *)((char *)ip_hdr + ip_hdr->ihl * 4); +#endif fs_add_string(fs, "classification", (char*) "udp", 0); fs_add_uint64(fs, "success", 1); fs_add_uint64(fs, "sport", ntohs(udp->source)); @@ -226,16 +272,21 @@ void udp_process_packet(const u_char *packet, UNUSED uint32_t len, fieldset_t *f fs_add_null(fs, "icmp_unreach_str"); fs_add_binary(fs, "data", (ntohs(udp->len) - sizeof(struct udphdr)), (void*) &udp[1], 0); } else if (ip_hdr->protocol == IPPROTO_ICMP) { +#ifdef __FREEBSD__ + struct zmap_icmphdr *icmp = (struct zmap_icmphdr *)((char *)ip_hdr + ip_hdr->ihl * 4); + struct zmap_iphdr *ip_inner = (struct zmap_iphdr*)&icmp[1]; +#else struct icmphdr *icmp = (struct icmphdr *)((char *)ip_hdr + ip_hdr->ihl * 4); struct iphdr *ip_inner = (struct iphdr*)&icmp[1]; +#endif // ICMP unreach comes from another server (not the one we sent a probe to); // But we will fix up saddr to be who we sent the probe to, in case you care. - fs_modify_string(fs, "saddr", make_ip_str(ip_inner->daddr), 1); + fs_modify_string(fs, "saddr", make_ip_str(ip_inner->daddr.s_addr), 1); fs_add_string(fs, "classification", (char*) "icmp-unreach", 0); fs_add_uint64(fs, "success", 0); fs_add_null(fs, "sport"); fs_add_null(fs, "dport"); - fs_add_string(fs, "icmp_responder", make_ip_str(ip_hdr->saddr), 1); + fs_add_string(fs, "icmp_responder", make_ip_str(ip_hdr->saddr.s_addr), 1); fs_add_uint64(fs, "icmp_type", icmp->type); fs_add_uint64(fs, "icmp_code", icmp->code); if (icmp->code <= ICMP_PREC_CUTOFF) { @@ -257,41 +308,71 @@ void udp_process_packet(const u_char *packet, UNUSED uint32_t len, fieldset_t *f } } +#ifdef __FREEBSD__ +int udp_validate_packet(const struct zmap_iphdr *ip_hdr, uint32_t len, +#else int udp_validate_packet(const struct iphdr *ip_hdr, uint32_t len, +#endif __attribute__((unused))uint32_t *src_ip, uint32_t *validation) { uint16_t dport, sport; if (ip_hdr->protocol == IPPROTO_UDP) { +#ifdef __FREEBSD__ + if ((4*ip_hdr->ihl + sizeof(struct zmap_udphdr)) > len) { +#else if ((4*ip_hdr->ihl + sizeof(struct udphdr)) > len) { +#endif // buffer not large enough to contain expected udp header return 0; } +#ifdef __FREEBSD__ + struct zmap_udphdr *udp = (struct zmap_udphdr*)((char *)ip_hdr + 4*ip_hdr->ihl); +#else struct udphdr *udp = (struct udphdr*)((char *)ip_hdr + 4*ip_hdr->ihl); +#endif 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 +#ifdef __FREEBSD__ + uint32_t min_len = 4*ip_hdr->ihl + sizeof(struct zmap_icmphdr) + + sizeof(struct zmap_iphdr) + sizeof(struct zmap_udphdr); +#else uint32_t min_len = 4*ip_hdr->ihl + sizeof(struct icmphdr) + sizeof(struct iphdr) + sizeof(struct udphdr); +#endif if (len < min_len) { // Not enough information for us to validate return 0; } +#ifdef __FREEBSD__ + struct zmap_icmphdr *icmp = (struct zmap_icmphdr*)((char *)ip_hdr + 4*ip_hdr->ihl); +#else struct icmphdr *icmp = (struct icmphdr*)((char *)ip_hdr + 4*ip_hdr->ihl); +#endif if (icmp->type != ICMP_DEST_UNREACH) { return 0; } - +#ifdef __FREEBSD__ + struct zmap_iphdr *ip_inner = (struct zmap_iphdr*)&icmp[1]; + // Now we know the actual inner ip length, we should recheck the buffer + if (len < 4*ip_inner->ihl - sizeof(struct zmap_iphdr) + min_len) { +#else 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) { +#endif return 0; } // This is the packet we sent +#ifdef __FREEBSD__ + struct zmap_udphdr *udp = (struct zmap_udphdr *)((char*)ip_inner + 4*ip_inner->ihl); +#else struct udphdr *udp = (struct udphdr *)((char*)ip_inner + 4*ip_inner->ihl); +#endif sport = ntohs(udp->source); dport = ntohs(udp->dest); diff --git a/src/probe_modules/packet.c b/src/probe_modules/packet.c index 47d251f..55087b5 100644 --- a/src/probe_modules/packet.c +++ b/src/probe_modules/packet.c @@ -12,7 +12,9 @@ #include #include +#ifndef __FREEBSD__ #include +#endif #include #include #include @@ -24,6 +26,16 @@ #include "state.h" +#ifdef __FREEBSD__ +#include "../proto_headers.h" +#endif + +#ifdef __FREEBSD_INCLUDES__ /* some macros in Linux system headers */ +#define ETH_ALEN ETHER_ADDR_LEN +#define ETH_P_IP ETYPE_IPV4 /* EtherType 0x800 */ +#endif + +#ifndef __FREEBSD__ /* TODO: */ void print_macaddr(struct ifreq* i) { printf("Device %s -> Ethernet %02x:%02x:%02x:%02x:%02x:%02x\n", @@ -35,8 +47,13 @@ void print_macaddr(struct ifreq* i) (int) ((unsigned char *) &i->ifr_hwaddr.sa_data)[4], (int) ((unsigned char *) &i->ifr_hwaddr.sa_data)[5]); } +#endif +#ifdef __FREEBSD__ +void fprintf_ip_header(FILE *fp, struct zmap_iphdr *iph) +#else void fprintf_ip_header(FILE *fp, struct iphdr *iph) +#endif { struct in_addr *s = (struct in_addr *) &(iph->saddr); struct in_addr *d = (struct in_addr *) &(iph->daddr); @@ -53,7 +70,11 @@ void fprintf_ip_header(FILE *fp, struct iphdr *iph) ntohl(iph->check)); } +#ifdef __FREEBSD__ +void fprintf_eth_header(FILE *fp, struct zmap_ethhdr *ethh) +#else void fprintf_eth_header(FILE *fp, struct ethhdr *ethh) +#endif { fprintf(fp, "eth { shost: %02x:%02x:%02x:%02x:%02x:%02x | " "dhost: %02x:%02x:%02x:%02x:%02x:%02x }\n", @@ -71,14 +92,22 @@ void fprintf_eth_header(FILE *fp, struct ethhdr *ethh) (int) ((unsigned char *) ethh->h_dest)[5]); } +#ifdef __FREEBSD__ +void make_eth_header(struct zmap_ethhdr *ethh, macaddr_t *src, macaddr_t *dst) +#else void make_eth_header(struct ethhdr *ethh, macaddr_t *src, macaddr_t *dst) +#endif { memcpy(ethh->h_source, src, ETH_ALEN); memcpy(ethh->h_dest, dst, ETH_ALEN); ethh->h_proto = htons(ETH_P_IP); } +#ifdef __FREEBSD__ +void make_ip_header(struct zmap_iphdr *iph, uint8_t protocol, uint16_t len) +#else void make_ip_header(struct iphdr *iph, uint8_t protocol, uint16_t len) +#endif { iph->ihl = 5; // Internet Header Length iph->version = 4; // IPv4 @@ -99,7 +128,23 @@ void make_icmp_header(struct icmp *buf) buf->icmp_code = 0; buf->icmp_seq = 0; } +/* TODO: This is sketchy when linking against other translation units. + Probably need to reconcile the struct names properly */ + +#ifdef __FREEBSD__ +void make_tcp_header(struct zmap_tcphdr *tcp_header, port_h_t dest_port) +{ + tcp_header->seq = random(); + tcp_header->ack_seq = 0; + tcp_header->th_flags = 0; + tcp_header->th_flags = 5 << 4; /* data offset */ + tcp_header->th_flags &= TH_SYN; + tcp_header->th_win = htons(65535); + tcp_header->check = 0; + tcp_header->th_urp = 0; + tcp_header->dest = (htons(dest_port)); +#else void make_tcp_header(struct tcphdr *tcp_header, port_h_t dest_port) { tcp_header->seq = random(); @@ -111,9 +156,14 @@ void make_tcp_header(struct tcphdr *tcp_header, port_h_t dest_port) tcp_header->check = 0; tcp_header->urg_ptr = 0; tcp_header->dest = htons(dest_port); +#endif } +#ifdef __FREEBSD__ +void make_udp_header(struct zmap_udphdr *udp_header, port_h_t dest_port, +#else void make_udp_header(struct udphdr *udp_header, port_h_t dest_port, +#endif uint16_t len) { udp_header->dest = htons(dest_port); diff --git a/src/probe_modules/packet.h b/src/probe_modules/packet.h index 77f3827..e3d8d24 100644 --- a/src/probe_modules/packet.h +++ b/src/probe_modules/packet.h @@ -1,6 +1,11 @@ #include "state.h" -#include +#ifdef __FREEBSD__ + #include "proto_headers.h" +#else + #include +#endif /* __FREEBSD__ */ + #include #include #include @@ -11,17 +16,32 @@ #define MAX_PACKET_SIZE 4096 +/* wbk - proceed w/ caution here w/ all the sizeof's */ + typedef unsigned short __attribute__((__may_alias__)) alias_unsigned_short; -void make_eth_header(struct ethhdr *ethh, macaddr_t *src, macaddr_t *dst); +#ifdef __FREEBSD__ +void make_eth_header(struct zmap_ethhdr *ethh, macaddr_t *src, macaddr_t *dst); +void make_ip_header(struct zmap_iphdr *iph, uint8_t, uint16_t); +void make_tcp_header(struct zmap_tcphdr*, port_h_t); +#else +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); +#endif void make_icmp_header(struct icmp *); +#ifdef __FREEBSD__ +void make_udp_header(struct zmap_udphdr *udp_header, port_h_t dest_port, + uint16_t len); +void fprintf_ip_header(FILE *fp, struct zmap_iphdr *iph); +void fprintf_eth_header(FILE *fp, struct zmap_ethhdr *ethh); +#else void make_udp_header(struct udphdr *udp_header, port_h_t dest_port, uint16_t len); void fprintf_ip_header(FILE *fp, struct iphdr *iph); void fprintf_eth_header(FILE *fp, struct ethhdr *ethh); +#endif static inline unsigned short in_checksum(unsigned short *ip_pkt, int len) { @@ -37,7 +57,11 @@ static inline unsigned short in_checksum(unsigned short *ip_pkt, int len) __attribute__((unused)) static inline unsigned short ip_checksum( unsigned short *buf) { +#ifdef __FREEBSD__ + return in_checksum(buf, (int) sizeof(struct zmap_iphdr)); +#else return in_checksum(buf, (int) sizeof(struct iphdr)); +#endif } __attribute__((unused)) static inline unsigned short icmp_checksum( @@ -47,7 +71,11 @@ __attribute__((unused)) static inline unsigned short icmp_checksum( } static __attribute__((unused)) uint16_t tcp_checksum(unsigned short len_tcp, +#ifdef __FREEBSD__ + uint32_t saddr, uint32_t daddr, struct zmap_tcphdr *tcp_pkt) +#else uint32_t saddr, uint32_t daddr, struct tcphdr *tcp_pkt) +#endif { alias_unsigned_short *src_addr = (alias_unsigned_short *) &saddr; alias_unsigned_short *dest_addr = (alias_unsigned_short *) &daddr; diff --git a/src/probe_modules/probe_modules.c b/src/probe_modules/probe_modules.c index f28d9bf..f376994 100644 --- a/src/probe_modules/probe_modules.c +++ b/src/probe_modules/probe_modules.c @@ -16,7 +16,11 @@ #include #include #include -#include +#ifdef __FREEBSD__ + #include "../proto_headers.h" +#else + #include +#endif #include "../../lib/logger.h" #include "../fieldset.h" @@ -54,10 +58,14 @@ void print_probe_modules(void) } } +#ifdef __FREEBSD__ +void fs_add_ip_fields(fieldset_t *fs, struct zmap_iphdr *ip) +#else void fs_add_ip_fields(fieldset_t *fs, struct iphdr *ip) +#endif { - fs_add_string(fs, "saddr", make_ip_str(ip->saddr), 1); - fs_add_string(fs, "daddr", make_ip_str(ip->daddr), 1); + fs_add_string(fs, "saddr", make_ip_str(ip->saddr.s_addr), 1); + fs_add_string(fs, "daddr", make_ip_str(ip->daddr.s_addr), 1); fs_add_uint64(fs, "ipid", ntohs(ip->id)); fs_add_uint64(fs, "ttl", ip->ttl); } diff --git a/src/probe_modules/probe_modules.h b/src/probe_modules/probe_modules.h index 4f8ea5a..9402910 100644 --- a/src/probe_modules/probe_modules.h +++ b/src/probe_modules/probe_modules.h @@ -4,6 +4,8 @@ #ifndef PROBE_MODULES_H #define PROBE_MODULES_H +#include "../proto_headers.h" + typedef struct probe_response_type { const uint8_t is_success; const char *name; @@ -18,11 +20,15 @@ typedef int (*probe_make_packet_cb)(void* packetbuf, ipaddr_n_t src_ip, uint32_t *validation, int probe_num); typedef void (*probe_print_packet_cb)(FILE *, void* packetbuf); -typedef int (*probe_close_cb)(struct state_conf*, +typedef int (*probe_close_cb)(struct state_conf*, struct state_send*, struct state_recv*); +#ifdef __FREEBSD__ +typedef int (*probe_validate_packet_cb)(const struct zmap_iphdr *ip_hdr, + uint32_t len, uint32_t *src_ip, uint32_t *validation); +#else typedef int (*probe_validate_packet_cb)(const struct iphdr *ip_hdr, uint32_t len, uint32_t *src_ip, uint32_t *validation); - +#endif typedef void (*probe_classify_packet_cb)(const u_char* packetbuf, uint32_t len, fieldset_t*); @@ -51,7 +57,11 @@ typedef struct probe_module { probe_module_t* get_probe_module_by_name(const char*); +#ifdef __FREEBSD__ +void fs_add_ip_fields(fieldset_t *fs, struct zmap_iphdr *ip); +#else void fs_add_ip_fields(fieldset_t *fs, struct iphdr *ip); +#endif void fs_add_system_fields(fieldset_t *fs, int is_repeat, int in_cooldown); void print_probe_modules(void); diff --git a/src/proto_headers.h b/src/proto_headers.h new file mode 100644 index 0000000..a817927 --- /dev/null +++ b/src/proto_headers.h @@ -0,0 +1,174 @@ +#ifndef HEADER_PROTO_HEADERS_H +#define HEADER_PROTO_HEADERS_H +/* struct definitions for accessing frames and packets */ + +/* Initially copied from Tim Carsten's "sniffex" example from tcpdump.org. + Macros are all that remain. Though it's almost 100% modified, + here is his permissive license to be on the safe side: */ + +/* This document is Copyright 2002 Tim Carstens. All rights reserved. + Redistribution and use, with or without modification, are permitted + provided that the following conditions are met: + Redistribution must retain the above copyright notice and this + list of conditions. + The name of Tim Carstens may not be used to endorse or promote + products derived from this document without specific prior + written permission. */ +/* + **************************************************************************** + * + * This software is a modification of Tim Carstens' "sniffer.c" + * demonstration source code, released as follows: + * + * sniffer.c + * Copyright (c) 2002 Tim Carstens + * 2002-01-07 + * Demonstration of using libpcap + * timcarst -at- yahoo -dot- com + * + * "sniffer.c" is distributed under these terms: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. The name "Tim Carstens" may not be used to endorse or promote + * products derived from this software without prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +//#include /* for u_char, uint16_t and the like */ +#include /* for u_char, uint16_t and the like */ +#include /* for in_addr */ +//#include /* for tcp_seq */ /* TODO: get it out? too dangerous? */ + +/* Macros that may already exist on Linux but not other platforms. */ +/* Ethernet addresses are 6 bytes */ +#ifndef ETHER_ADDR_LEN + #define ETHER_ADDR_LEN 6 +#endif +#ifndef ETHER_HDR_LEN + #define ETHER_HDR_LEN 14 /* wbk - adding to avoid sizeof(sniff_ethernet) */ +#endif +#ifndef IFHWADDRLEN + #define IFHWADDRLEN ETHER_ADDR_LEN +#endif + + struct zmap_ethhdr { + u_char h_dest[ETHER_ADDR_LEN]; + u_char h_source[ETHER_ADDR_LEN]; + uint16_t h_proto; + #define ETYPE_IPV4 0x0800 + #define ETYPE_IPV6 0x86dd + #define ETYPE_ARP 0x0806 + #define ETYPE_RARP 0x8035 + }; + + struct zmap_iphdr { + /* wbk TODO: This bitfield stuff will almost certainly need to go, but will + complicate client code. */ + u_char ihl:4, + version:4; + u_char tos; + uint16_t tot_len; + uint16_t id; + uint16_t frag_off; + u_char ttl; + u_char protocol; + uint16_t check; + struct in_addr saddr, daddr; + #define IP_FLAGMASK 0xe000 /* flags are first 3 bits of ip_off - wbk */ + #define IP_RF 0x8000 /* reserved fragment flag */ + #define IP_DF 0x4000 /* dont fragment flag */ + #define IP_MF 0x2000 /* more fragments flag */ + #define IP_OFFMASK 0x1fff /* mask for fragmenting bits */ + #define IP_HL(ip) (((ip)->ip_vhl) & 0x0f) + #define IP_V(ip) (((ip)->ip_vhl) >> 4) + + }; + + struct zmap_tcphdr { /* TODO: maybe change to zmap_tcphdr?*/ + uint16_t source; /* source port */ + uint16_t dest; /* destination port */ + uint32_t seq; /* sequence number */ /*TODO type tcp_seq? */ + uint32_t ack_seq; /* acknowledgement number */ + + u_char th_offx2; /* data offset, rsvd */ + #define TH_OFF(th) (((th)->th_offx2 & 0xf0) >> 4) + u_char th_flags; + #define TH_FIN 0x01 + #define TH_SYN 0x02 + #define TH_RST 0x04 + #define TH_PUSH 0x08 + #define TH_ACK 0x10 + #define TH_URG 0x20 + #define TH_ECE 0x40 + #define TH_CWR 0x80 + #ifndef TH_FLAGS /* wbk - FreeBSD has equivalent in netinet/tcp.h */ + #define TH_FLAGS (TH_FIN|TH_SYN|TH_RST|TH_ACK|TH_URG|TH_ECE|TH_CWR) + #endif + uint16_t th_win; /* window */ + uint16_t check; /* checksum */ + uint16_t th_urp; /* urgent pointer */ + }; + + struct zmap_udphdr { + uint16_t source; + uint16_t dest; + uint16_t len; + uint16_t check; + }; + +#ifndef ICMP_HDR_LEN + #define ICMP_HDR_LEN 64 +#endif + struct zmap_icmphdr { + uint8_t type; + uint8_t code; + uint16_t checksum; + /*uint16_t id; / * this part is different for different ICMP services * / + uint16_t seq; */ + union { + struct { + uint16_t id; + uint16_t sequence; + } echo; + uint32_t gateway; + struct { // TODO: check this. Perfect overlap causing warnings? + uint16_t __unused; + uint16_t mtu; + } frag; + } un; + #ifndef ICMP_ECHO + #define ICMP_ECHO 8 + #endif + #ifndef ICMP_ECHOREPLY + #define ICMP_ECHOREPLY 0 + #endif + #ifndef ICMP_TIME_EXCEEDED + #define ICMP_TIME_EXCEEDED 11 + #endif + #ifndef ICMP_DEST_UNREACH + #define ICMP_DEST_UNREACH 3 + #endif + #ifndef ICMP_PREC_CUTOFF + #define ICMP_PREC_CUTOFF 15 + #endif + }; +#endif /* HEADER_PROTO_HEADERS_H */ diff --git a/src/recv.c b/src/recv.c index 7f15765..b55b582 100644 --- a/src/recv.c +++ b/src/recv.c @@ -16,12 +16,17 @@ #include #include -#include -#include -#include #include +#include +#include /* wbk BSD requires netinet/in.h and ip.h first */ +#include -#include +#ifdef __FREEBSD__ + #include "proto_headers.h" + #define ETH_P_IP ETYPE_IPV4 +#else + #include +#endif #include #include #include @@ -76,21 +81,41 @@ void packet_cb(u_char __attribute__((__unused__)) *user, // length of entire packet captured by libpcap uint32_t buflen = (uint32_t) p->caplen; +#ifdef __FREEBSD__ + if ((sizeof(struct zmap_iphdr) + (zconf.send_ip_pkts ? 0 : sizeof(struct zmap_ethhdr))) > buflen) { +#else if ((sizeof(struct iphdr) + (zconf.send_ip_pkts ? 0 : sizeof(struct ethhdr))) > buflen) { +#endif // buffer not large enough to contain ethernet // and ip headers. further action would overrun buf return; } +#ifdef __FREEBSD__ + struct zmap_iphdr *ip_hdr = (struct zmap_iphdr *)&bytes[(zconf.send_ip_pkts ? 0 : sizeof(struct zmap_ethhdr))]; +#else struct iphdr *ip_hdr = (struct iphdr *)&bytes[(zconf.send_ip_pkts ? 0 : sizeof(struct ethhdr))]; - +#endif + +#ifdef __FREEBSD__ /* TODO: this change might work on Linux; is cleaner */ + uint32_t src_ip = ip_hdr->saddr.s_addr; +#else uint32_t src_ip = ip_hdr->saddr; +#endif 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 +#ifdef __FREEBSD__ + validate_gen(ip_hdr->daddr.s_addr, ip_hdr->saddr.s_addr, (uint8_t *)validation); +#else validate_gen(ip_hdr->daddr, ip_hdr->saddr, (uint8_t *)validation); +#endif +#ifdef __FREEBSD__ + if (!zconf.probe_module->validate_packet(ip_hdr, buflen - (zconf.send_ip_pkts ? 0 : sizeof(struct zmap_ethhdr)), +#else if (!zconf.probe_module->validate_packet(ip_hdr, buflen - (zconf.send_ip_pkts ? 0 : sizeof(struct ethhdr)), +#endif &src_ip, validation)) { return; } @@ -108,7 +133,11 @@ void packet_cb(u_char __attribute__((__unused__)) *user, if (buflen > sizeof(fake_eth_hdr)) { buflen = sizeof(fake_eth_hdr); } - memcpy(&fake_eth_hdr[sizeof(struct ethhdr)], bytes, buflen); +#ifdef __FREEBSD__ + memcpy(&fake_eth_hdr[sizeof(struct zmap_ethhdr)], bytes, buflen); /* wbk TODO: replace these sizeof(struct *hdr) with macros) */ +#else + memcpy(&fake_eth_hdr[sizeof(struct ethhdr)], bytes, buflen); /* wbk TODO: replace these sizeof(struct *hdr) with macros) */ +#endif bytes = fake_eth_hdr; } zconf.probe_module->process_packet(bytes, buflen, fs); @@ -198,7 +227,11 @@ int recv_run(pthread_mutex_t *recv_ready_mutex) } } if (zconf.send_ip_pkts) { +#ifdef __FREEBSD__ + struct zmap_ethhdr *eth = (struct zmap_ethhdr *)fake_eth_hdr; +#else struct ethhdr *eth = (struct ethhdr *)fake_eth_hdr; +#endif memset(fake_eth_hdr, 0, sizeof(fake_eth_hdr)); eth->h_proto = htons(ETH_P_IP); } diff --git a/src/send.c b/src/send.c index ebb971c..91294c4 100644 --- a/src/send.c +++ b/src/send.c @@ -19,10 +19,27 @@ #include #include -#include -#include +#ifdef __FREEBSD_INCLUDES__ + #include /* TODO:other BSD's*/ + #include + #include + #include + #include /* for sockaddr_dl */ + /* beware, defined in other modulkes */ + #define PCAP_PROMISC 1 + #define PCAP_TIMEOUT 1000 +#else /* TODO double check this */ + #include + #include +#endif #include + +/* might want to change to ifdef __LINUX__. Will help more than just FreeBSD */ +#ifdef __FREEBSD_INCLUDES__ +#include "proto_headers.h" +#else #include +#endif /* __FREEBSD__ */ #include "../lib/logger.h" #include "../lib/random.h" @@ -132,6 +149,93 @@ int send_init(void) return EXIT_SUCCESS; } +#ifdef ZMAP_PCAP_INJECT +pcap_t* get_pcap_t(void) +{ + pcap_t *pc = NULL; + char errbuf[PCAP_ERRBUF_SIZE]; + /* wbk return a pcap_t ready for pcap_inject */ + log_debug("send", "getting pcap handle"); + /* snaplen of 0 since we only write on this pcpa_t? */ + pc = pcap_open_live(zconf.iface, 0, + PCAP_PROMISC, /* needed?*/ + PCAP_TIMEOUT, + errbuf); + if (pc == NULL) { + log_fatal("send", "couldn't open device %s:, %s. " + "Do you have permissions for the device?", + zconf.iface, errbuf); + } + /*struct bpf_program bpf; + //if (pcap_compile(pc, &bpf, zconf.probe_module->pcap_filter, 1, 0) < 0) { + if (pcap_compile(pc, &bpf, zconf.probe_module->pcap_filter, 1, PCAP_NETMASK_UNKNOWN) < 0) { + log_debug("send", "pcap_filter failed. Tried \"%s\"", + zconf.probe_module->pcap_filter); + log_fatal("send", "couldn't compile filter"); + } + if (pcap_setfilter(pc, &bpf) < 0) { + log_fatal("send", "couldn't install filter"); + }*/ + log_debug("send", "injector ready"); + return pc; +} + +static void get_hwaddr(unsigned char *hwaddr) /* TODO determine ret type etc -wbk**/ + /* error return or rely on log_fatal? TODO*/ +{ + /* pass a pointer to ETHER_ADDR_LEN bytes. */ + /* double check that interface name gets validated since + we use strcmp here. Unless there's some POSIX ocnstant for + max iface name (doubt it) IFNAMESIZ? */ + struct ifaddrs *p = NULL; + struct sockaddr_dl* sdl = NULL; /* BSD-specific hardware address */ + + if (getifaddrs(&p) == -1) { + log_fatal("send", "get_hwaddr() getifaddrs() failed!"); + /* TODO: strerror() */ + + } + for (;p != NULL; p = p->ifa_next) { + if ( (p->ifa_addr->sa_family == AF_LINK) /* linux would need AF_PACKET */ + && (strncmp(zconf.iface, p->ifa_name, IF_NAMESIZE) == 0) ) + { + /* copy MAC. Or get the whole sockaddr :). Eliminate sizeof()? */ + /* Linux has sockaddr_ll. BSD has sockaddr_dl. structs are differnent */ + /* let's just get the hardware address to pass back. */ + sdl = (struct sockaddr_dl*)(p->ifa_addr); + if (sdl->sdl_alen == ETHER_ADDR_LEN) /* paranoia */ + memcpy(hwaddr, LLADDR((sdl)), sdl->sdl_alen); + else + log_fatal("send", "gethwaddr() unexpected sdl_alen!"); + } + } +} + +/*static void get_ipaddr(struct sockaddr *sa)*/ +/* TODO: Is this even needed? */ +static void get_ipaddr(struct in_addr *in) +{ + /* retrieve IPaddress using getifaddrs(), used by caller to craft packet for + pcap_inject(). TODO:see how nmap handles this. */ + struct ifaddrs *p = NULL; + struct sockaddr_in *sin = NULL; + if (getifaddrs(&p) == -1) { + log_fatal("send", "get_ipaddr() getifaddrs() failed!"); + } + for (; p != NULL; p = p->ifa_next) { + if ( (p->ifa_addr->sa_family == AF_INET) + && (strncmp(zconf.iface, p->ifa_name, IF_NAMESIZE) == 0) ) + { + /* TODO: grab IPs a struct sockaddr_in I guess */ + sin = (struct sockaddr_in *)(p->ifa_addr); + /* copy the struct in_addr for return*/ + /* TODO: Idon't like using sizeof() macro; see if there's a better alternative. */ + /* TODO:sanity check here? */ + memcpy(in, &(sin->sin_addr), sizeof(struct in_addr)); + } + } +} +#else int get_socket(void) { int sock = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); @@ -141,6 +245,7 @@ int get_socket(void) } return sock; } +#endif int get_dryrun_socket(void) { @@ -167,11 +272,27 @@ static inline ipaddr_n_t get_src_ip(ipaddr_n_t dst, int local_offset) } // one sender thread +#ifdef ZMAP_PCAP_INJECT +int send_run(pcap_t *pc) +#else int send_run(int sock) +#endif { log_debug("send", "thread started"); pthread_mutex_lock(&send_mutex); - +#ifdef ZMAP_PCAP_INJECT + /* Using pcap, mirror the linux SOCK_RAW behaviour as closely + as possible */ + unsigned char mac[ETHER_ADDR_LEN]; + struct in_addr src_ip = {0}; + //pcap_t *pc = get_pcap_t(); + /* We don't need the index; we have a pcap handle to the proper + interface */ + get_hwaddr(mac); + get_ipaddr(&src_ip); + +#else + //int sock = get_socket(); struct sockaddr_ll sockaddr; // get source interface index struct ifreq if_idx; @@ -181,7 +302,7 @@ int send_run(int sock) zconf.iface); return -1; } - strncpy(if_idx.ifr_name, zconf.iface, IFNAMSIZ-1); + strncpy(if_idx.ifr_name, zconf.iface, IFNAMSIZ-2); if (ioctl(sock, SIOCGIFINDEX, &if_idx) < 0) { perror("SIOCGIFINDEX"); return -1; @@ -206,16 +327,23 @@ int send_run(int sock) perror("SIOCGIFADDR"); return -1; } + // wbk TODO: gateway MAC. // 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); +#endif /* not ZMAP_PCAP_INJECT */ /* may move down... TODO wbk */ + char buf[MAX_PACKET_SIZE]; memset(buf, 0, MAX_PACKET_SIZE); zconf.probe_module->thread_initialize(buf, +#ifdef ZMAP_PCAP_INJECT + mac, +#else (unsigned char *)if_mac.ifr_hwaddr.sa_data, +#endif zconf.gw_mac, zconf.target_port); pthread_mutex_unlock(&send_mutex); @@ -288,6 +416,19 @@ int send_run(int sock) zconf.probe_module->print_packet(stdout, buf); } else { int l = zconf.probe_module->packet_length; + +#ifdef ZMAP_PCAP_INJECT + int rc = pcap_inject(pc, buf, (size_t)l); + if (rc == -1) { + struct in_addr addr; + addr.s_addr = curr; + log_fatal("send", "pcap_inject() failed for %s. %s", /* TODO: make log_debug */ + inet_ntoa(addr), strerror(errno)); + pthread_mutex_lock(&send_mutex); + zsend.sendto_failures++; + pthread_mutex_unlock(&send_mutex); + } +#else /* TODO: error handling can be shared. */ int rc = sendto(sock, buf + zconf.send_ip_pkts*sizeof(struct ethhdr), l, 0, (struct sockaddr *)&sockaddr, @@ -301,6 +442,7 @@ int send_run(int sock) zsend.sendto_failures++; pthread_mutex_unlock(&send_mutex); } +#endif } } } diff --git a/src/send.h b/src/send.h index 553f56d..7154fb5 100644 --- a/src/send.h +++ b/src/send.h @@ -9,9 +9,33 @@ #ifndef SEND_H #define SEND_H +#include /* for uintptr_t ? */ +#ifdef ZMAP_PCAP_INJECT +#include +#else +#endif + +/* wrapper for Linux socket handle or pcap_t. BSD port uses + pcap_inject() instead of Linux SOCK_RAW sendto(). + This is an ugly hack. Client code will need to check + zconf for dryrun, and if ZMAP_PCAP_INJECT, use pcap_t, + otherwise sock.*/ +struct send_handle { +#ifdef ZMAP_PCAP_INJECT + pcap_t *pc; +#endif + //int sock; + uintptr_t sock; +}; + int get_socket(void); int get_dryrun_socket(void); int send_init(void); -int send_run(int); +#ifdef ZMAP_PCAP_INJECT +pcap_t *get_pcap_t(void); +int send_run(pcap_t *pc); +#else +int send_run(int); +#endif #endif //SEND_H diff --git a/src/state.h b/src/state.h index 5bd3f75..ef8fe45 100644 --- a/src/state.h +++ b/src/state.h @@ -8,10 +8,20 @@ #include #include -#include -#include + +#ifdef __FREEBSD_INCLUDES__ +/* wbk TODO: Might just conditionally include ip.h if on Linux. Might not + need netinet/ip.h once we have out handrolled structs for protocol headers */ +#include +#include "proto_headers.h" // for IFHWADDR only + +#else /* wbk TODO examine CPP logic a bit more... might be cleaner */ #include -#include +#include // for IFHWADDR +#endif /* __FREEBSD_INCLUDES__ */ + +//#include // wbk - doesn't seem to be needed +//#include #include "types.h" #include "fieldset.h" diff --git a/src/zmap.c b/src/zmap.c index 083566d..8c10d6f 100644 --- a/src/zmap.c +++ b/src/zmap.c @@ -27,6 +27,10 @@ #include +#ifdef __FREEBSD_INCLUDES__ +#include /* per man PTHREAD_AFFINITY_NP(3) */ +#endif + #include "../lib/logger.h" #include "../lib/random.h" @@ -79,11 +83,15 @@ static void set_cpu(void) pthread_mutex_lock(&cpu_affinity_mutex); static int core=0; int num_cores = sysconf(_SC_NPROCESSORS_ONLN); +#ifdef __FREEBSD_PTHREADS__ + cpuset_t cpuset; +#else cpu_set_t cpuset; +#endif CPU_ZERO(&cpuset); CPU_SET(core, &cpuset); if (pthread_setaffinity_np(pthread_self(), - sizeof(cpu_set_t), &cpuset) != 0) { + sizeof(cpuset), &cpuset) != 0) { log_error("zmap", "can't set thread CPU affinity"); } log_trace("zmap", "set thread %u affinity to core %d", @@ -94,10 +102,21 @@ static void set_cpu(void) static void* start_send(void *arg) { - uintptr_t v = (uintptr_t) arg; + /* TODO: This is really ugly. */ + /* keep in mind this is all pointing at the caller's stack copy of this + struct. If we let zmap_start return before threads die, or if we modify + the members within the worker threads, this will need to be changed. + Should be ok, if ugly, as long as access is read-only and calling function + doesn't return early, leaving this pointer pointing out of the stack */ + struct send_handle *handle = (struct send_handle *) arg; + uintptr_t v = handle->sock; int sock = (int) v & 0xFFFF; set_cpu(); - send_run(sock); +#ifdef ZMAP_PCAP_INJECT + send_run(handle->pc); +#else + send_run(handle->sock); +#endif return NULL; } @@ -253,14 +272,20 @@ static void start_zmap(void) assert(tsend); log_debug("zmap", "using %d sender threads", zconf.senders); for (int i=0; i < zconf.senders; i++) { - uintptr_t sock; + //uintptr_t sock; + struct send_handle handle = {0,NULL}; if (zconf.dryrun) { - sock = get_dryrun_socket(); + handle.sock = get_dryrun_socket(); } else { - sock = get_socket(); +#ifdef ZMAP_PCAP_INJECT + handle.pc = get_pcap_t(); +#else + handle.sock = get_socket(); +#endif } - int r = pthread_create(&tsend[i], NULL, start_send, (void*) sock); + //int r = pthread_create(&tsend[i], NULL, start_send, (void*) sock); + int r = pthread_create(&tsend[i], NULL, start_send, (void*) &handle); if (r != 0) { log_fatal("zmap", "unable to create send thread"); exit(EXIT_FAILURE);