mirror of
https://github.com/freebsd/freebsd-src.git
synced 2024-12-03 14:48:57 +00:00
51e16cb8fc
Remove ancient SCCS tags from the tree, automated scripting, with two minor fixup to keep things compiling. All the common forms in the tree were removed with a perl script. Sponsored by: Netflix
574 lines
11 KiB
C
574 lines
11 KiB
C
|
|
/*
|
|
* Copyright (C) 2012 by Darren Reed.
|
|
*
|
|
* See the IPFILTER.LICENCE file for details on licencing.
|
|
*/
|
|
#include "ipf.h"
|
|
#include <fcntl.h>
|
|
#include <ctype.h>
|
|
#include <sys/ioctl.h>
|
|
#include "netinet/ipl.h"
|
|
|
|
|
|
#if !defined(__SVR4) && defined(__GNUC__)
|
|
extern char *index(const char *, int);
|
|
#endif
|
|
|
|
extern char *optarg;
|
|
extern int optind;
|
|
extern frentry_t *frtop;
|
|
|
|
|
|
void ipf_frsync(void);
|
|
void zerostats(void);
|
|
int main(int, char *[]);
|
|
|
|
int opts = 0;
|
|
int outputc = 0;
|
|
int use_inet6 = 0;
|
|
int exitstatus = 0;
|
|
|
|
static void procfile(char *);
|
|
static void flushfilter(char *, int *);
|
|
static void set_state(u_int);
|
|
static void showstats(friostat_t *);
|
|
static void packetlogon(char *);
|
|
static void swapactive(void);
|
|
static int opendevice(char *, int);
|
|
static void closedevice(void);
|
|
static char *ipfname = IPL_NAME;
|
|
static void usage(void);
|
|
static int showversion(void);
|
|
static int get_flags(void);
|
|
static int ipf_interceptadd(int, ioctlfunc_t, void *);
|
|
|
|
static int fd = -1;
|
|
static ioctlfunc_t iocfunctions[IPL_LOGSIZE] = { ioctl, ioctl, ioctl,
|
|
ioctl, ioctl, ioctl,
|
|
ioctl, ioctl };
|
|
|
|
/* XXX The following was added to satisfy a rescue/rescue/ build
|
|
XXX requirement. */
|
|
int nohdrfields;
|
|
|
|
static void usage()
|
|
{
|
|
fprintf(stderr, "usage: ipf [-6AdDEInoPrRsvVyzZ] %s %s %s\n",
|
|
"[-l block|pass|nomatch|state|nat]", "[-cc] [-F i|o|a|s|S|u]",
|
|
"[-f filename] [-T <tuneopts>]");
|
|
exit(1);
|
|
}
|
|
|
|
|
|
int
|
|
main(int argc, char *argv[])
|
|
{
|
|
int c, *filter = NULL;
|
|
|
|
if (argc < 2)
|
|
usage();
|
|
|
|
assigndefined(getenv("IPF_PREDEFINED"));
|
|
|
|
while ((c = getopt(argc, argv, "46Ac:dDEf:F:Il:m:noPrRsT:vVyzZ")) != -1) {
|
|
switch (c)
|
|
{
|
|
case '?' :
|
|
usage();
|
|
break;
|
|
case '4' :
|
|
use_inet6 = -1;
|
|
break;
|
|
case '6' :
|
|
use_inet6 = 1;
|
|
break;
|
|
case 'A' :
|
|
opts &= ~OPT_INACTIVE;
|
|
break;
|
|
case 'c' :
|
|
if (strcmp(optarg, "c") == 0)
|
|
outputc = 1;
|
|
break;
|
|
case 'E' :
|
|
set_state((u_int)1);
|
|
break;
|
|
case 'D' :
|
|
set_state((u_int)0);
|
|
break;
|
|
case 'd' :
|
|
opts ^= OPT_DEBUG;
|
|
break;
|
|
case 'f' :
|
|
procfile(optarg);
|
|
break;
|
|
case 'F' :
|
|
flushfilter(optarg, filter);
|
|
break;
|
|
case 'I' :
|
|
opts ^= OPT_INACTIVE;
|
|
break;
|
|
case 'l' :
|
|
packetlogon(optarg);
|
|
break;
|
|
case 'm' :
|
|
filter = parseipfexpr(optarg, NULL);
|
|
break;
|
|
case 'n' :
|
|
opts ^= OPT_DONOTHING|OPT_DONTOPEN;
|
|
break;
|
|
case 'o' :
|
|
break;
|
|
case 'P' :
|
|
ipfname = IPAUTH_NAME;
|
|
break;
|
|
case 'R' :
|
|
opts ^= OPT_NORESOLVE;
|
|
break;
|
|
case 'r' :
|
|
opts ^= OPT_REMOVE;
|
|
break;
|
|
case 's' :
|
|
swapactive();
|
|
break;
|
|
case 'T' :
|
|
if (opendevice(ipfname, 1) >= 0)
|
|
ipf_dotuning(fd, optarg, ioctl);
|
|
break;
|
|
case 'v' :
|
|
opts += OPT_VERBOSE;
|
|
break;
|
|
case 'V' :
|
|
if (showversion())
|
|
exit(1);
|
|
break;
|
|
case 'y' :
|
|
ipf_frsync();
|
|
break;
|
|
case 'z' :
|
|
opts ^= OPT_ZERORULEST;
|
|
break;
|
|
case 'Z' :
|
|
zerostats();
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (optind < 2)
|
|
usage();
|
|
|
|
if (fd != -1)
|
|
(void) close(fd);
|
|
|
|
return (exitstatus);
|
|
/* NOTREACHED */
|
|
}
|
|
|
|
|
|
static int
|
|
opendevice(char *ipfdev, int check)
|
|
{
|
|
if (opts & OPT_DONOTHING)
|
|
return (-2);
|
|
|
|
if (check && checkrev(ipfname) == -1) {
|
|
fprintf(stderr, "User/kernel version check failed\n");
|
|
return (-2);
|
|
}
|
|
|
|
if (!ipfdev)
|
|
ipfdev = ipfname;
|
|
|
|
if (fd == -1)
|
|
if ((fd = open(ipfdev, O_RDWR)) == -1)
|
|
if ((fd = open(ipfdev, O_RDONLY)) == -1)
|
|
ipferror(fd, "open device");
|
|
return (fd);
|
|
}
|
|
|
|
|
|
static void
|
|
closedevice(void)
|
|
{
|
|
close(fd);
|
|
fd = -1;
|
|
}
|
|
|
|
|
|
static int
|
|
get_flags(void)
|
|
{
|
|
int i = 0;
|
|
|
|
if ((opendevice(ipfname, 1) != -2) &&
|
|
(ioctl(fd, SIOCGETFF, &i) == -1)) {
|
|
ipferror(fd, "SIOCGETFF");
|
|
return (0);
|
|
}
|
|
return (i);
|
|
}
|
|
|
|
|
|
static void
|
|
set_state(u_int enable)
|
|
{
|
|
if (opendevice(ipfname, 0) != -2) {
|
|
if (ioctl(fd, SIOCFRENB, &enable) == -1) {
|
|
if (errno == EBUSY) {
|
|
fprintf(stderr,
|
|
"IP FIlter: already initialized\n");
|
|
} else {
|
|
ipferror(fd, "SIOCFRENB");
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
static void
|
|
procfile(char *file)
|
|
{
|
|
(void) opendevice(ipfname, 1);
|
|
|
|
initparse();
|
|
|
|
ipf_parsefile(fd, ipf_interceptadd, iocfunctions, file);
|
|
|
|
if (outputc) {
|
|
printC(0);
|
|
printC(1);
|
|
emit(-1, -1, NULL, NULL);
|
|
}
|
|
}
|
|
|
|
|
|
static int
|
|
ipf_interceptadd(int fd, ioctlfunc_t ioctlfunc, void *ptr)
|
|
{
|
|
if (outputc)
|
|
printc(ptr);
|
|
|
|
if (ipf_addrule(fd, ioctlfunc, ptr) != 0)
|
|
exitstatus = 1;
|
|
return (0);
|
|
}
|
|
|
|
|
|
static void
|
|
packetlogon(char *opt)
|
|
{
|
|
int flag, xfd, logopt, change = 0;
|
|
|
|
flag = get_flags();
|
|
if (flag != 0) {
|
|
if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE)
|
|
printf("log flag is currently %#x\n", flag);
|
|
}
|
|
|
|
flag &= ~(FF_LOGPASS|FF_LOGNOMATCH|FF_LOGBLOCK);
|
|
|
|
if (strstr(opt, "pass")) {
|
|
flag |= FF_LOGPASS;
|
|
if (opts & OPT_VERBOSE)
|
|
printf("set log flag: pass\n");
|
|
change = 1;
|
|
}
|
|
if (strstr(opt, "nomatch")) {
|
|
flag |= FF_LOGNOMATCH;
|
|
if (opts & OPT_VERBOSE)
|
|
printf("set log flag: nomatch\n");
|
|
change = 1;
|
|
}
|
|
if (strstr(opt, "block") || strchr(opt, 'd')) {
|
|
flag |= FF_LOGBLOCK;
|
|
if (opts & OPT_VERBOSE)
|
|
printf("set log flag: block\n");
|
|
change = 1;
|
|
}
|
|
if (strstr(opt, "none")) {
|
|
if (opts & OPT_VERBOSE)
|
|
printf("disable all log flags\n");
|
|
change = 1;
|
|
}
|
|
|
|
if (change == 1) {
|
|
if (opendevice(ipfname, 1) != -2 &&
|
|
(ioctl(fd, SIOCSETFF, &flag) != 0))
|
|
ipferror(fd, "ioctl(SIOCSETFF)");
|
|
}
|
|
|
|
if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) {
|
|
flag = get_flags();
|
|
printf("log flags are now %#x\n", flag);
|
|
}
|
|
|
|
if (strstr(opt, "state")) {
|
|
if (opts & OPT_VERBOSE)
|
|
printf("set state log flag\n");
|
|
xfd = open(IPSTATE_NAME, O_RDWR);
|
|
if (xfd >= 0) {
|
|
logopt = 0;
|
|
if (ioctl(xfd, SIOCGETLG, &logopt))
|
|
ipferror(fd, "ioctl(SIOCGETLG)");
|
|
else {
|
|
logopt = 1 - logopt;
|
|
if (ioctl(xfd, SIOCSETLG, &logopt))
|
|
ipferror(xfd, "ioctl(SIOCSETLG)");
|
|
}
|
|
close(xfd);
|
|
}
|
|
}
|
|
|
|
if (strstr(opt, "nat")) {
|
|
if (opts & OPT_VERBOSE)
|
|
printf("set nat log flag\n");
|
|
xfd = open(IPNAT_NAME, O_RDWR);
|
|
if (xfd >= 0) {
|
|
logopt = 0;
|
|
if (ioctl(xfd, SIOCGETLG, &logopt))
|
|
ipferror(xfd, "ioctl(SIOCGETLG)");
|
|
else {
|
|
logopt = 1 - logopt;
|
|
if (ioctl(xfd, SIOCSETLG, &logopt))
|
|
ipferror(xfd, "ioctl(SIOCSETLG)");
|
|
}
|
|
close(xfd);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
flushfilter(char *arg, int *filter)
|
|
{
|
|
int fl = 0, rem;
|
|
|
|
if (!arg || !*arg)
|
|
return;
|
|
if (!strcmp(arg, "s") || !strcmp(arg, "S") || ISDIGIT(*arg)) {
|
|
if (*arg == 'S')
|
|
fl = 0;
|
|
else if (*arg == 's')
|
|
fl = 1;
|
|
else
|
|
fl = atoi(arg);
|
|
rem = fl;
|
|
|
|
closedevice();
|
|
if (opendevice(IPSTATE_NAME, 1) == -2)
|
|
exit(1);
|
|
|
|
if (!(opts & OPT_DONOTHING)) {
|
|
if (use_inet6) {
|
|
fprintf(stderr,
|
|
"IPv6 rules are no longer separate\n");
|
|
} else if (filter != NULL) {
|
|
ipfobj_t obj;
|
|
|
|
obj.ipfo_rev = IPFILTER_VERSION;
|
|
obj.ipfo_size = filter[0] * sizeof(int);
|
|
obj.ipfo_type = IPFOBJ_IPFEXPR;
|
|
obj.ipfo_ptr = filter;
|
|
if (ioctl(fd, SIOCMATCHFLUSH, &obj) == -1) {
|
|
ipferror(fd, "ioctl(SIOCMATCHFLUSH)");
|
|
fl = -1;
|
|
} else {
|
|
fl = obj.ipfo_retval;
|
|
}
|
|
} else {
|
|
if (ioctl(fd, SIOCIPFFL, &fl) == -1) {
|
|
ipferror(fd, "ioctl(SIOCIPFFL)");
|
|
exit(1);
|
|
}
|
|
}
|
|
}
|
|
if ((opts & (OPT_DONOTHING|OPT_DEBUG)) == OPT_DEBUG) {
|
|
printf("remove flags %s (%d)\n", arg, rem);
|
|
}
|
|
if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) {
|
|
printf("%d state entries removed\n", fl);
|
|
}
|
|
closedevice();
|
|
return;
|
|
} else if (strchr(arg, 'i') || strchr(arg, 'I'))
|
|
fl = FR_INQUE;
|
|
else if (strchr(arg, 'o') || strchr(arg, 'O'))
|
|
fl = FR_OUTQUE;
|
|
else if (strchr(arg, 'a') || strchr(arg, 'A'))
|
|
fl = FR_OUTQUE|FR_INQUE;
|
|
else {
|
|
fprintf(stderr, "Incorrect flush argument: %s\n", arg);
|
|
usage();
|
|
}
|
|
if (opts & OPT_INACTIVE)
|
|
fl |= FR_INACTIVE;
|
|
rem = fl;
|
|
|
|
if (opendevice(ipfname, 1) == -2)
|
|
exit(1);
|
|
|
|
if (!(opts & OPT_DONOTHING)) {
|
|
if (use_inet6) {
|
|
if (ioctl(fd, SIOCIPFL6, &fl) == -1) {
|
|
ipferror(fd, "ioctl(SIOCIPFL6)");
|
|
exit(1);
|
|
}
|
|
} else {
|
|
if (ioctl(fd, SIOCIPFFL, &fl) == -1) {
|
|
ipferror(fd, "ioctl(SIOCIPFFL)");
|
|
exit(1);
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((opts & (OPT_DONOTHING|OPT_DEBUG)) == OPT_DEBUG) {
|
|
printf("remove flags %s%s (%d)\n", (rem & FR_INQUE) ? "I" : "",
|
|
(rem & FR_OUTQUE) ? "O" : "", rem);
|
|
}
|
|
if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) {
|
|
printf("%d filter rules removed\n", fl);
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
static void
|
|
swapactive(void)
|
|
{
|
|
int in = 2;
|
|
|
|
if (opendevice(ipfname, 1) != -2 && ioctl(fd, SIOCSWAPA, &in) == -1)
|
|
ipferror(fd, "ioctl(SIOCSWAPA)");
|
|
else
|
|
printf("Set %d now inactive\n", in);
|
|
}
|
|
|
|
|
|
void
|
|
ipf_frsync(void)
|
|
{
|
|
int frsyn = 0;
|
|
|
|
if (opendevice(ipfname, 1) != -2 && ioctl(fd, SIOCFRSYN, &frsyn) == -1)
|
|
ipferror(fd, "SIOCFRSYN");
|
|
else
|
|
printf("filter sync'd\n");
|
|
}
|
|
|
|
|
|
void
|
|
zerostats(void)
|
|
{
|
|
ipfobj_t obj;
|
|
friostat_t fio;
|
|
|
|
obj.ipfo_rev = IPFILTER_VERSION;
|
|
obj.ipfo_type = IPFOBJ_IPFSTAT;
|
|
obj.ipfo_size = sizeof(fio);
|
|
obj.ipfo_ptr = &fio;
|
|
obj.ipfo_offset = 0;
|
|
|
|
if (opendevice(ipfname, 1) != -2) {
|
|
if (ioctl(fd, SIOCFRZST, &obj) == -1) {
|
|
ipferror(fd, "ioctl(SIOCFRZST)");
|
|
exit(-1);
|
|
}
|
|
showstats(&fio);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
* read the kernel stats for packets blocked and passed
|
|
*/
|
|
static void
|
|
showstats(friostat_t *fp)
|
|
{
|
|
printf("bad packets:\t\tin %lu\tout %lu\n",
|
|
fp->f_st[0].fr_bad, fp->f_st[1].fr_bad);
|
|
printf(" input packets:\t\tblocked %lu passed %lu nomatch %lu",
|
|
fp->f_st[0].fr_block, fp->f_st[0].fr_pass,
|
|
fp->f_st[0].fr_nom);
|
|
printf(" counted %lu\n", fp->f_st[0].fr_acct);
|
|
printf("output packets:\t\tblocked %lu passed %lu nomatch %lu",
|
|
fp->f_st[1].fr_block, fp->f_st[1].fr_pass,
|
|
fp->f_st[1].fr_nom);
|
|
printf(" counted %lu\n", fp->f_st[0].fr_acct);
|
|
printf(" input packets logged:\tblocked %lu passed %lu\n",
|
|
fp->f_st[0].fr_bpkl, fp->f_st[0].fr_ppkl);
|
|
printf("output packets logged:\tblocked %lu passed %lu\n",
|
|
fp->f_st[1].fr_bpkl, fp->f_st[1].fr_ppkl);
|
|
}
|
|
|
|
|
|
static int
|
|
showversion(void)
|
|
{
|
|
struct friostat fio;
|
|
ipfobj_t ipfo;
|
|
u_32_t flags;
|
|
char *s;
|
|
int vfd;
|
|
|
|
bzero((caddr_t)&ipfo, sizeof(ipfo));
|
|
ipfo.ipfo_rev = IPFILTER_VERSION;
|
|
ipfo.ipfo_size = sizeof(fio);
|
|
ipfo.ipfo_ptr = (void *)&fio;
|
|
ipfo.ipfo_type = IPFOBJ_IPFSTAT;
|
|
|
|
printf("ipf: %s (%d)\n", IPL_VERSION, (int)sizeof(frentry_t));
|
|
|
|
if ((vfd = open(ipfname, O_RDONLY)) == -1) {
|
|
perror("open device");
|
|
return (1);
|
|
}
|
|
|
|
if (ioctl(vfd, SIOCGETFS, &ipfo)) {
|
|
ipferror(vfd, "ioctl(SIOCGETFS)");
|
|
close(vfd);
|
|
return (1);
|
|
}
|
|
close(vfd);
|
|
flags = get_flags();
|
|
|
|
printf("Kernel: %-*.*s\n", (int)sizeof(fio.f_version),
|
|
(int)sizeof(fio.f_version), fio.f_version);
|
|
printf("Running: %s\n", (fio.f_running > 0) ? "yes" : "no");
|
|
printf("Log Flags: %#x = ", flags);
|
|
s = "";
|
|
if (flags & FF_LOGPASS) {
|
|
printf("pass");
|
|
s = ", ";
|
|
}
|
|
if (flags & FF_LOGBLOCK) {
|
|
printf("%sblock", s);
|
|
s = ", ";
|
|
}
|
|
if (flags & FF_LOGNOMATCH) {
|
|
printf("%snomatch", s);
|
|
s = ", ";
|
|
}
|
|
if (flags & FF_BLOCKNONIP) {
|
|
printf("%snonip", s);
|
|
s = ", ";
|
|
}
|
|
if (!*s)
|
|
printf("none set");
|
|
putchar('\n');
|
|
|
|
printf("Default: ");
|
|
if (FR_ISPASS(fio.f_defpass))
|
|
s = "pass";
|
|
else if (FR_ISBLOCK(fio.f_defpass))
|
|
s = "block";
|
|
else
|
|
s = "nomatch -> block";
|
|
printf("%s all, Logging: %savailable\n", s, fio.f_logging ? "" : "un");
|
|
printf("Active list: %d\n", fio.f_active);
|
|
printf("Feature mask: %#x\n", fio.f_features);
|
|
|
|
return (0);
|
|
}
|