Blame utils/nfsynproxy.c

Packit 7b22a4
/*
Packit 7b22a4
 * Copyright (c) 2013 Patrick McHardy <kaber@trash.net>
Packit 7b22a4
 *
Packit 7b22a4
 * This program is free software; you can redistribute it and/or modify
Packit 7b22a4
 * it under the terms of the GNU General Public License version 2 as
Packit 7b22a4
 * published by the Free Software Foundation.
Packit 7b22a4
 */
Packit 7b22a4
Packit 7b22a4
#define _GNU_SOURCE
Packit 7b22a4
#include <stdlib.h>
Packit 7b22a4
#include <stdbool.h>
Packit 7b22a4
#include <unistd.h>
Packit 7b22a4
#include <string.h>
Packit 7b22a4
#include <errno.h>
Packit 7b22a4
#include <getopt.h>
Packit 7b22a4
#include <sys/types.h>
Packit 7b22a4
#include <sys/socket.h>
Packit 7b22a4
#include <netinet/in.h>
Packit 7b22a4
#include <arpa/inet.h>
Packit 7b22a4
#include <pcap/pcap.h>
Packit 7b22a4
#include <netinet/ip.h>
Packit 7b22a4
#include <netinet/tcp.h>
Packit 7b22a4
Packit 7b22a4
static const char *iface = "lo";
Packit 7b22a4
static uint16_t port;
Packit 7b22a4
static const char *chain = "SYNPROXY";
Packit 7b22a4
Packit 7b22a4
static int parse_packet(const char *host, const uint8_t *data)
Packit 7b22a4
{
Packit 7b22a4
	const struct iphdr *iph = (void *)data + 14;
Packit 7b22a4
	const struct tcphdr *th = (void *)iph + iph->ihl * 4;
Packit 7b22a4
	int length;
Packit 7b22a4
	uint8_t *ptr;
Packit 7b22a4
Packit 7b22a4
	if (!th->syn || !th->ack)
Packit 7b22a4
		return 0;
Packit 7b22a4
Packit 7b22a4
	printf("-A %s -d %s -p tcp --dport %u "
Packit 7b22a4
	       "-m state --state UNTRACKED,INVALID "
Packit 7b22a4
	       "-j SYNPROXY ", chain, host, port);
Packit 7b22a4
Packit 7b22a4
	/* ECE && !CWR */
Packit 7b22a4
	if (th->res2 == 0x1)
Packit 7b22a4
		printf("--ecn ");
Packit 7b22a4
Packit 7b22a4
	length = th->doff * 4 - sizeof(*th);
Packit 7b22a4
	ptr = (uint8_t *)(th + 1);
Packit 7b22a4
	while (length > 0) {
Packit 7b22a4
		int opcode = *ptr++;
Packit 7b22a4
		int opsize;
Packit 7b22a4
Packit 7b22a4
		switch (opcode) {
Packit 7b22a4
		case TCPOPT_EOL:
Packit 7b22a4
			return 1;
Packit 7b22a4
		case TCPOPT_NOP:
Packit 7b22a4
			length--;
Packit 7b22a4
			continue;
Packit 7b22a4
		default:
Packit 7b22a4
			opsize = *ptr++;
Packit 7b22a4
			if (opsize < 2)
Packit 7b22a4
				return 1;
Packit 7b22a4
			if (opsize > length)
Packit 7b22a4
				return 1;
Packit 7b22a4
Packit 7b22a4
			switch (opcode) {
Packit 7b22a4
			case TCPOPT_MAXSEG:
Packit 7b22a4
				if (opsize == TCPOLEN_MAXSEG)
Packit 7b22a4
					printf("--mss %u ", ntohs(*(uint16_t *)ptr));
Packit 7b22a4
				break;
Packit 7b22a4
			case TCPOPT_WINDOW:
Packit 7b22a4
				if (opsize == TCPOLEN_WINDOW)
Packit 7b22a4
					printf("--wscale %u ", *ptr);
Packit 7b22a4
				break;
Packit 7b22a4
			case TCPOPT_TIMESTAMP:
Packit 7b22a4
				if (opsize == TCPOLEN_TIMESTAMP)
Packit 7b22a4
					printf("--timestamp ");
Packit 7b22a4
				break;
Packit 7b22a4
			case TCPOPT_SACK_PERMITTED:
Packit 7b22a4
				if (opsize == TCPOLEN_SACK_PERMITTED)
Packit 7b22a4
					printf("--sack-perm ");
Packit 7b22a4
				break;
Packit 7b22a4
			}
Packit 7b22a4
Packit 7b22a4
			ptr += opsize - 2;
Packit 7b22a4
			length -= opsize;
Packit 7b22a4
		}
Packit 7b22a4
	}
Packit 7b22a4
	printf("\n");
Packit 7b22a4
	return 1;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static void probe_host(const char *host)
Packit 7b22a4
{
Packit 7b22a4
	struct sockaddr_in sin;
Packit 7b22a4
	char pcap_errbuf[PCAP_ERRBUF_SIZE];
Packit 7b22a4
	struct pcap_pkthdr pkthdr;
Packit 7b22a4
	const uint8_t *data;
Packit 7b22a4
	struct bpf_program fp;
Packit 7b22a4
	pcap_t *ph;
Packit 7b22a4
	int fd;
Packit 7b22a4
Packit 7b22a4
	ph = pcap_create(iface, pcap_errbuf);
Packit 7b22a4
	if (ph == NULL) {
Packit 7b22a4
		perror("pcap_create");
Packit 7b22a4
		goto err1;
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	if (pcap_setnonblock(ph, 1, pcap_errbuf) == -1) {
Packit 7b22a4
		perror("pcap_setnonblock");
Packit 7b22a4
		goto err2;
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	if (pcap_setfilter(ph, &fp) == -1) {
Packit 7b22a4
		pcap_perror(ph, "pcap_setfilter");
Packit 7b22a4
		goto err2;
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	if (pcap_activate(ph) != 0) {
Packit 7b22a4
		pcap_perror(ph, "pcap_activate");
Packit 7b22a4
		goto err2;
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	if (pcap_compile(ph, &fp, "src host 127.0.0.1 and tcp and src port 80",
Packit 7b22a4
			 1, PCAP_NETMASK_UNKNOWN) == -1) {
Packit 7b22a4
		pcap_perror(ph, "pcap_compile");
Packit 7b22a4
		goto err2;
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	fd = socket(AF_INET, SOCK_STREAM, 0);
Packit 7b22a4
	if (fd < 0) {
Packit 7b22a4
		perror("socket");
Packit 7b22a4
		goto err3;
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	memset(&sin, 0, sizeof(sin));
Packit 7b22a4
	sin.sin_family		= AF_INET;
Packit 7b22a4
	sin.sin_port		= htons(port);
Packit 7b22a4
	sin.sin_addr.s_addr	= inet_addr(host);
Packit 7b22a4
Packit 7b22a4
	if (connect(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
Packit 7b22a4
		perror("connect");
Packit 7b22a4
		goto err4;
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	for (;;) {
Packit 7b22a4
		data = pcap_next(ph, &pkthdr);
Packit 7b22a4
		if (data == NULL)
Packit 7b22a4
			break;
Packit 7b22a4
		if (parse_packet(host, data))
Packit 7b22a4
			break;
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	close(fd);
Packit 7b22a4
Packit 7b22a4
err4:
Packit 7b22a4
	close(fd);
Packit 7b22a4
err3:
Packit 7b22a4
	pcap_freecode(&fp);
Packit 7b22a4
err2:
Packit 7b22a4
	pcap_close(ph);
Packit 7b22a4
err1:
Packit 7b22a4
	return;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
enum {
Packit 7b22a4
	OPT_HELP	= 'h',
Packit 7b22a4
	OPT_IFACE	= 'i',
Packit 7b22a4
	OPT_PORT	= 'p',
Packit 7b22a4
	OPT_CHAIN	= 'c',
Packit 7b22a4
};
Packit 7b22a4
Packit 7b22a4
static const struct option options[] = {
Packit 7b22a4
	{ .name = "help",  .has_arg = false, .val = OPT_HELP },
Packit 7b22a4
	{ .name = "iface", .has_arg = true,  .val = OPT_IFACE },
Packit 7b22a4
	{ .name = "port" , .has_arg = true,  .val = OPT_PORT },
Packit 7b22a4
	{ .name = "chain", .has_arg = true,  .val = OPT_CHAIN },
Packit 7b22a4
	{ }
Packit 7b22a4
};
Packit 7b22a4
Packit 7b22a4
static void print_help(const char *name)
Packit 7b22a4
{
Packit 7b22a4
	printf("%s [ options ] address...\n"
Packit 7b22a4
	       "\n"
Packit 7b22a4
	       "Options:\n"
Packit 7b22a4
	       " -i/--iface        Outbound interface\n"
Packit 7b22a4
	       " -p/--port         Port number to probe\n"
Packit 7b22a4
	       " -c/--chain        Chain name to use for rules\n"
Packit 7b22a4
	       " -h/--help         Show this help\n",
Packit 7b22a4
	       name);
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
int main(int argc, char **argv)
Packit 7b22a4
{
Packit 7b22a4
	int optidx = 0, c;
Packit 7b22a4
Packit 7b22a4
	for (;;) {
Packit 7b22a4
		c = getopt_long(argc, argv, "hi:p:c:", options, &optidx);
Packit 7b22a4
		if (c == -1)
Packit 7b22a4
			break;
Packit 7b22a4
Packit 7b22a4
		switch (c) {
Packit 7b22a4
		case OPT_IFACE:
Packit 7b22a4
			iface = optarg;
Packit 7b22a4
			break;
Packit 7b22a4
		case OPT_PORT:
Packit 7b22a4
			port = atoi(optarg);
Packit 7b22a4
			break;
Packit 7b22a4
		case OPT_CHAIN:
Packit 7b22a4
			chain = optarg;
Packit 7b22a4
			break;
Packit 7b22a4
		case OPT_HELP:
Packit 7b22a4
			print_help(argv[0]);
Packit 7b22a4
			exit(0);
Packit 7b22a4
		case '?':
Packit 7b22a4
			print_help(argv[0]);
Packit 7b22a4
			exit(1);
Packit 7b22a4
		}
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	argc -= optind;
Packit 7b22a4
	argv += optind;
Packit 7b22a4
Packit 7b22a4
	while (argc > 0) {
Packit 7b22a4
		probe_host(*argv);
Packit 7b22a4
		argc--;
Packit 7b22a4
		argv++;
Packit 7b22a4
	}
Packit 7b22a4
	return 0;
Packit 7b22a4
}