Skip to content

Commit

Permalink
Replace IPFW with PF.
Browse files Browse the repository at this point in the history
- Make ReQrypt compatible with BSD and MacOSX.
- WIP solution for #3.
  • Loading branch information
basil00 committed Apr 30, 2018
1 parent 7b2308b commit f7e1b7f
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 78 deletions.
123 changes: 52 additions & 71 deletions src/freebsd/capture.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* capture.c
* (C) 2017, all rights reserved,
* (C) 2018, all rights reserved,
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Expand All @@ -20,7 +20,7 @@
* Filtering, packet capture, and re-injection for FreeBSD
*
* FILTERING:
* Filtering is achieved by issuing ipfw commands to redirect packets
* Filtering is achieved by issuing pfctl commands to redirect packets
* to IP_DIVERT sockets.
*
* CAPTURING/RE-INJECTION:
Expand All @@ -46,47 +46,31 @@
#define DIVERT_PORT 40403

/*
* IPFW commands.
* PFCTL commands.
*/
#define IPFW_BUFFSIZE 256
#define IPFW_ARGS_MAX 32
#ifndef MACOSX
static const char *ipfw_divert_tcp_1 =
"/sbin/ipfw 40404 add divert %d out proto tcp dst-port 443 uid %d";
static const char *ipfw_divert_tcp_2 =
"/sbin/ipfw 40405 add divert %d out proto tcp dst-port 80 uid %d";
static const char *ipfw_divert_udp =
"/sbin/ipfw 40406 add divert %d out proto udp dst-port 53 uid %d";
#else
// MACOSX uid is buggy
static const char *ipfw_divert_tcp_1 =
"/sbin/ipfw 40404 add divert %d out proto tcp dst-port 443";
static const char *ipfw_divert_tcp_2 =
"/sbin/ipfw 40405 add divert %d out proto tcp dst-port 80";
static const char *ipfw_divert_udp =
"/sbin/ipfw 40406 add divert %d out proto udp dst-port 53";
#endif /* MACOSX */
static const char *ipfw_filter_icmp =
"/sbin/ipfw 40407 add deny in icmptypes 11";
static const char *ipfw_undo =
"/sbin/ipfw delete 40404 40405 40406 40407";
#define PFCTL_BUFFSIZE 256
#define PFCTL_ARGS_MAX 32
static const char *pfctl_divert =
"/sbin/pactl -a reqrypt -f ./pf.conf";
static const char *pfctl_undo =
"/sbin/pfctl -a reqrypt -F rules";

/*
* Prototypes.
*/
static void ipfw(const char *command);
static void ipfw_undo_on_signal(int sig);
static void ipfw_undo_flush(void);
static void pfctl(const char *command);
static void pfctl_undo_on_signal(int sig);
static void pfctl_undo_flush(void);

/*
* Global divert socket for capture/injection.
*/
static int socket_divert;

/*
* Cleaned up ipfw state?
* Cleaned up pf state?
*/
static bool ipfw_clean = true;
static bool pf_clean = true;

/*
* Initialise packet capturing.
Expand All @@ -112,25 +96,22 @@ void init_capture(void)
error("unable to bind divert socket to port %d", DIVERT_PORT);
}

// Initialise packet capture/redirection with ipfw.
// Initialise packet capture/redirection with pf.
#ifndef DEBUG
signal(SIGINT, ipfw_undo_on_signal);
signal(SIGQUIT, ipfw_undo_on_signal);
signal(SIGHUP, ipfw_undo_on_signal);
signal(SIGILL, ipfw_undo_on_signal);
signal(SIGFPE, ipfw_undo_on_signal);
signal(SIGABRT, ipfw_undo_on_signal);
signal(SIGSEGV, ipfw_undo_on_signal);
signal(SIGTERM, ipfw_undo_on_signal);
signal(SIGPIPE, ipfw_undo_on_signal);
signal(SIGALRM, ipfw_undo_on_signal);
signal(SIGINT, pfctl_undo_on_signal);
signal(SIGQUIT, pfctl_undo_on_signal);
signal(SIGHUP, pfctl_undo_on_signal);
signal(SIGILL, pfctl_undo_on_signal);
signal(SIGFPE, pfctl_undo_on_signal);
signal(SIGABRT, pfctl_undo_on_signal);
signal(SIGSEGV, pfctl_undo_on_signal);
signal(SIGTERM, pfctl_undo_on_signal);
signal(SIGPIPE, pfctl_undo_on_signal);
signal(SIGALRM, pfctl_undo_on_signal);
#endif /* DEBUG */
ipfw(ipfw_divert_tcp_1);
ipfw(ipfw_divert_tcp_2);
ipfw(ipfw_divert_udp);
ipfw(ipfw_filter_icmp);
ipfw_clean = false;
atexit(ipfw_undo_flush);
pfctl(pfctl_divert);
pf_clean = false;
atexit(pfctl_undo_flush);
}

/*
Expand Down Expand Up @@ -189,28 +170,28 @@ void inject_packet(uint8_t *buff, size_t size)
}

/*
* Execute an ipfw command.
* Execute an pfctl command.
*/
static void ipfw(const char *command)
static void pfctl(const char *command)
{
if (options_get()->seen_no_ipfw)
if (options_get()->seen_no_pf)
{
return;
}

char buff[IPFW_BUFFSIZE];
char buff[PFCTL_BUFFSIZE];
if (snprintf(buff, sizeof(buff), command, DIVERT_PORT, getuid()) >=
sizeof(buff))
{
panic("ipfw buffer is too small");
panic("pfctl buffer is too small");
}
log("[" PLATFORM "] executing ipfw command \"%s\"", buff);
log("[" PLATFORM "] executing pfctl command \"%s\"", buff);

// Note: never use system() because we have setuid as root.
char *args[IPFW_ARGS_MAX];
char *args[PFCTL_ARGS_MAX];
args[0] = buff;
int i, j;
for (i = 0, j = 1; buff[i] && j < IPFW_ARGS_MAX-1; i++)
for (i = 0, j = 1; buff[i] && j < PFCTL_ARGS_MAX-1; i++)
{
if(buff[i] == ' ')
{
Expand All @@ -226,57 +207,57 @@ static void ipfw(const char *command)
pid_t pid = fork();
if (pid == -1)
{
error("unable to execute ipfw command; failed to fork current "
error("unable to execute pfctl command; failed to fork current "
"process");
}
else if (pid == 0)
{
if (setgid(0) != 0)
{
error("unable to set the group ID to 0 (root) for ipfw command");
error("unable to set the group ID to 0 (root) for pfctl command");
}
if (setuid(0) != 0)
{
error("unable to set the user ID to 0 (root) for ipfw command");
error("unable to set the user ID to 0 (root) for pfctl command");
}
execv("/sbin/ipfw", args);
error("unable to execute ipfw command");
execv("/sbin/pfctl", args);
error("unable to execute pfctl command");
}

int exit_status;
while (waitpid(pid, &exit_status, 0) < 0)
{
if (errno != EINTR)
{
error("unable to execute ipfw command; failed to wait for ipfw "
error("unable to execute pfctl command; failed to wait for pfctl "
"to complete");
}
}
if(exit_status != 0)
{
error("ipfw command returned non-zero exit status %d", exit_status);
error("pfctl command returned non-zero exit status %d", exit_status);
}
}

/*
* Undo ipfw commands on signal then exit.
* Undo pfctl commands on signal then exit.
*/
static void ipfw_undo_on_signal(int sig)
static void pfctl_undo_on_signal(int sig)
{
log("[" PLATFORM "] caught deadly signal %d; cleaning up ipfw state", sig);
ipfw_undo_flush();
log("[" PLATFORM "] caught deadly signal %d; cleaning up pf state", sig);
pfctl_undo_flush();
error("caught deadly signal %d; exitting", sig);
}

/*
* Undo ipfw commands.
* Undo pfctl commands.
*/
static void ipfw_undo_flush(void)
static void pfctl_undo_flush(void)
{
if (!ipfw_clean)
if (!pf_clean)
{
ipfw(ipfw_undo);
ipfw_clean = true;
pfctl(pfctl_undo);
pf_clean = true;
}
}

10 changes: 5 additions & 5 deletions src/options.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* options.c
* (C) 2017, all rights reserved,
* (C) 2018, all rights reserved,
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -69,7 +69,7 @@ struct opt_info_s opt_info[] =
{"help", OPT_BOOL, &options.seen_help, NULL},
{"no-capture", OPT_BOOL, &options.seen_no_capture, NULL},
#ifdef FREEBSD
{"no-ipfw", OPT_BOOL, &options.seen_no_ipfw, NULL},
{"no-pf", OPT_BOOL, &options.seen_no_pf, NULL},
#endif
#ifdef LINUX
{"no-iptables", OPT_BOOL, &options.seen_no_iptables, NULL},
Expand Down Expand Up @@ -205,9 +205,9 @@ static void help(void)
puts("\t\tDo not capture and tunnel packets (this option effectively");
printf("\t\tdisables %s).\n", PROGRAM_NAME);
#ifdef FREEBSD
puts("\t--no-ipfw");
printf("\t\tPrevent %s from issuing ipfw commands.\n", PROGRAM_NAME);
puts("\t\tUse this option if you wish to configure ipfw manually.");
puts("\t--no-pf");
printf("\t\tPrevent %s from issuing pf commands.\n", PROGRAM_NAME);
puts("\t\tUse this option if you wish to configure pf manually.");
#endif
#ifdef LINUX
puts("\t--no-iptables");
Expand Down
4 changes: 2 additions & 2 deletions src/options.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* options.h
* (C) 2017, all rights reserved,
* (C) 2018, all rights reserved,
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -30,7 +30,7 @@ struct options_s
bool seen_help;
bool seen_no_capture;
#ifdef FREEBSD
bool seen_no_ipfw;
bool seen_no_pf;
#endif
#ifdef LINUX
bool seen_no_iptables;
Expand Down

0 comments on commit f7e1b7f

Please sign in to comment.