FreeBSD port initial checkin. This is based on 5cd6f3294c,

September 9, 2013, before CMake changes. Includes proto_headers.h.
Most or all of __FREEBSD__ changes should, IMHO, be merged back into Linux version.
This should build on Linux with __FREEBSD__ defined.
This commit is contained in:
William Kelly 2013-10-16 22:12:11 -05:00
parent 5cd6f3294c
commit 833c781d94
17 changed files with 862 additions and 59 deletions

View File

@ -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)

View File

@ -48,7 +48,11 @@
#include <sys/socket.h>
#include <netinet/in.h>
#ifdef __FREEBSD_INCLUDES__
#include </usr/local/include/gmp.h>
#else
#include <gmp.h>
#endif
#include "../lib/logger.h"
#include "../lib/blacklist.h"

View File

@ -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)
{

View File

@ -15,16 +15,22 @@
#include <netinet/in.h>
#include <net/if.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#ifdef __FREEBSD__
#include <ifaddrs.h>
#else
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#endif
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#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

View File

@ -15,12 +15,14 @@
#include <unistd.h>
#include <string.h>
#ifndef __FREEBSD__
#include <netinet/ether.h>
#endif
#include <netinet/in.h> /* wbk order */
#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"
@ -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*)(&eth_header[1]);
uint16_t len = htons(sizeof(struct zmap_iphdr) + sizeof(struct icmp) - 8);
#else
struct iphdr *ip_header = (struct iphdr*)(&eth_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*)(&eth_header[1]);
#else
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]);
#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 *) &ethh[1];
#else
struct ethhdr *ethh = (struct ethhdr *) packet;
struct iphdr *iph = (struct iphdr *) &ethh[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));

View File

@ -15,9 +15,16 @@
#include <string.h>
#include <assert.h>
#ifdef __FREEBSD__ // TODO: __FREEBSD_INCLUDES__?
/* TODO: This may break Linux, might need to remove #ifdef here entirely */
#include <netinet/in.h> /* wbk needed before netinet/ip.h */
#endif
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <netinet/ether.h>
#ifdef __FREEBSD__
#else
#include <netinet/ether.h>
#endif
#include <sys/socket.h>
#include <netinet/in.h>
@ -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*)(&eth_header[1]);
uint16_t len = htons(sizeof(struct zmap_iphdr) + sizeof(struct zmap_tcphdr));
#else
struct iphdr *ip_header = (struct iphdr*)(&eth_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*)(&eth_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*)(&eth_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 *) &ethh[1];
struct zmap_tcphdr *tcph = (struct zmap_tcphdr *) &iph[1];
#else
struct ethhdr *ethh = (struct ethhdr *) packet;
struct iphdr *iph = (struct iphdr *) &ethh[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

View File

@ -16,12 +16,17 @@
#include <assert.h>
#include <netinet/udp.h>
#include <netinet/in.h> /* wbk order */
#include <netinet/ip.h>
#include <netinet/ether.h>
#include <netinet/ip_icmp.h>
#ifdef __FREEBSD__
#include "proto_headers.h" /* wbk TODO: test */
#else
#include <netinet/ether.h>
#include <netinet/ether.h> /* wbk TODO: Probably need proto_headers.h instead */
#include <netinet/ip_icmp.h>
#endif
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#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*)(&eth_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*)(&eth_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*)(&eth_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*)(&eth_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 *) &ethh[1];
struct zmap_udphdr *udph = (struct zmap_udphdr*)(&iph[1]);
#else
struct ethhdr *ethh = (struct ethhdr *) packet;
struct iphdr *iph = (struct iphdr *) &ethh[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);

View File

@ -12,7 +12,9 @@
#include <stdio.h>
#include <string.h>
#ifndef __FREEBSD__
#include <netinet/ether.h>
#endif
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <netinet/udp.h>
@ -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);

View File

@ -1,6 +1,11 @@
#include "state.h"
#include <netinet/ether.h>
#ifdef __FREEBSD__
#include "proto_headers.h"
#else
#include <netinet/ether.h>
#endif /* __FREEBSD__ */
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <netinet/ip_icmp.h>
@ -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;

View File

@ -16,7 +16,11 @@
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <linux/if_packet.h>
#ifdef __FREEBSD__
#include "../proto_headers.h"
#else
#include <linux/if_packet.h>
#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);
}

View File

@ -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);

174
src/proto_headers.h Normal file
View File

@ -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.
* <end of "sniffer.c" terms>
*/
//#include <sys/types.h> /* for u_char, uint16_t and the like */
#include <stdint.h> /* for u_char, uint16_t and the like */
#include <netinet/in.h> /* for in_addr */
//#include <netinet/tcp.h> /* 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 */

View File

@ -16,12 +16,17 @@
#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 <netinet/ip.h>
#include <netinet/ip_icmp.h> /* wbk BSD requires netinet/in.h and ip.h first */
#include <netinet/udp.h>
#include <linux/if_ether.h>
#ifdef __FREEBSD__
#include "proto_headers.h"
#define ETH_P_IP ETYPE_IPV4
#else
#include <linux/if_ether.h>
#endif
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
@ -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);
}

View File

@ -19,10 +19,27 @@
#include <assert.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#ifdef __FREEBSD_INCLUDES__
#include <pcap/pcap.h> /* TODO:other BSD's*/
#include <sys/types.h>
#include <sys/socket.h>
#include <ifaddrs.h>
#include <net/if_dl.h> /* for sockaddr_dl */
/* beware, defined in other modulkes */
#define PCAP_PROMISC 1
#define PCAP_TIMEOUT 1000
#else /* TODO double check this */
#include <sys/socket.h>
#include <sys/ioctl.h>
#endif
#include <net/if.h>
/* might want to change to ifdef __LINUX__. Will help more than just FreeBSD */
#ifdef __FREEBSD_INCLUDES__
#include "proto_headers.h"
#else
#include <linux/if_packet.h>
#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
}
}
}

View File

@ -9,9 +9,33 @@
#ifndef SEND_H
#define SEND_H
#include <stdint.h> /* for uintptr_t ? */
#ifdef ZMAP_PCAP_INJECT
#include <pcap/pcap.h>
#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

View File

@ -8,10 +8,20 @@
#include <stdio.h>
#include <stdint.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#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 <sys/types.h>
#include "proto_headers.h" // for IFHWADDR only
#else /* wbk TODO examine CPP logic a bit more... might be cleaner */
#include <netinet/ether.h>
#include <net/if.h>
#include <net/if.h> // for IFHWADDR
#endif /* __FREEBSD_INCLUDES__ */
//#include <netinet/ip.h> // wbk - doesn't seem to be needed
//#include <netinet/tcp.h>
#include "types.h"
#include "fieldset.h"

View File

@ -27,6 +27,10 @@
#include <pthread.h>
#ifdef __FREEBSD_INCLUDES__
#include <pthread_np.h> /* 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);