330 lines
7.7 KiB
C
330 lines
7.7 KiB
C
/* $OpenBSD: pf.c,v 1.14 2024/04/22 13:30:22 bluhm Exp $ */
|
|
/*
|
|
* Copyright (c) 2001, 2007 Can Erkin Acar <canacar@openbsd.org>
|
|
*
|
|
* Permission to use, copy, modify, and distribute this software for any
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
* copyright notice and this permission notice appear in all copies.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
*/
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/sysctl.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/signal.h>
|
|
#include <net/if.h>
|
|
#include <netinet/in.h>
|
|
#include <netinet/ip.h>
|
|
#include <net/pfvar.h>
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#include <errno.h>
|
|
#include <err.h>
|
|
#include <unistd.h>
|
|
#include <syslog.h>
|
|
#include "pfctl_parser.h"
|
|
#include "systat.h"
|
|
|
|
void print_pf(void);
|
|
int read_pf(void);
|
|
int select_pf(void);
|
|
void print_fld_double(field_def *, double);
|
|
|
|
const char *pf_reasons[PFRES_MAX+1] = PFRES_NAMES;
|
|
const char *pf_lcounters[LCNT_MAX+1] = LCNT_NAMES;
|
|
const char *pf_fcounters[FCNT_MAX+1] = FCNT_NAMES;
|
|
const char *pf_scounters[SCNT_MAX+1] = FCNT_NAMES;
|
|
const char *pf_ncounters[NCNT_MAX+1] = FCNT_NAMES;
|
|
|
|
static struct pf_status status;
|
|
int num_pf = 0;
|
|
|
|
field_def fields_pf[] = {
|
|
{"TYPE", 13, 16, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
|
|
{"NAME", 12, 24, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
|
|
{"VALUE", 8, 10, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
|
|
{"RATE", 8, 10, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 60},
|
|
};
|
|
|
|
#define FLD_PF_TYPE FIELD_ADDR(fields_pf,0)
|
|
#define FLD_PF_NAME FIELD_ADDR(fields_pf,1)
|
|
#define FLD_PF_VALUE FIELD_ADDR(fields_pf,2)
|
|
#define FLD_PF_RATE FIELD_ADDR(fields_pf,3)
|
|
|
|
/* Define views */
|
|
field_def *view_pf_0[] = {
|
|
FLD_PF_TYPE, FLD_PF_NAME, FLD_PF_VALUE, FLD_PF_RATE, NULL
|
|
};
|
|
|
|
|
|
/* Define view managers */
|
|
struct view_manager pf_mgr = {
|
|
"PF", select_pf, read_pf, NULL, print_header,
|
|
print_pf, keyboard_callback, NULL, NULL
|
|
};
|
|
|
|
field_view views_pf[] = {
|
|
{view_pf_0, "pf", 'P', &pf_mgr},
|
|
{NULL, NULL, 0, NULL}
|
|
};
|
|
|
|
|
|
|
|
int
|
|
select_pf(void)
|
|
{
|
|
return (0);
|
|
}
|
|
|
|
int
|
|
read_pf(void)
|
|
{
|
|
size_t size = sizeof(status);
|
|
int mib[3] = { CTL_KERN, KERN_PFSTATUS };
|
|
|
|
if (sysctl(mib, 2, &status, &size, NULL, 0) == -1) {
|
|
error("sysctl(PFCTL_STATUS): %s", strerror(errno));
|
|
return (-1);
|
|
}
|
|
|
|
num_disp = 4;
|
|
|
|
if (status.ifname[0] != 0)
|
|
num_disp += 13;
|
|
|
|
num_disp += FCNT_MAX + 2;
|
|
num_disp += SCNT_MAX + 2;
|
|
num_disp += NCNT_MAX + 2;
|
|
num_disp += PFRES_MAX + 1;
|
|
num_disp += LCNT_MAX + 1;
|
|
|
|
return (0);
|
|
}
|
|
|
|
int
|
|
initpf(void)
|
|
{
|
|
field_view *v;
|
|
|
|
for (v = views_pf; v->name != NULL; v++)
|
|
add_view(v);
|
|
|
|
return(1);
|
|
}
|
|
|
|
void
|
|
print_fld_double(field_def *fld, double val)
|
|
{
|
|
int len;
|
|
|
|
if (fld == NULL)
|
|
return;
|
|
|
|
len = fld->width;
|
|
if (len < 1)
|
|
return;
|
|
|
|
tb_start();
|
|
if (tbprintf("%.2f", val) > len)
|
|
print_fld_str(fld, "*");
|
|
else
|
|
print_fld_tb(fld);
|
|
tb_end();
|
|
}
|
|
|
|
#define ADD_LINE_A(t, n, v) \
|
|
do { \
|
|
if (cur >= dispstart && cur < end) { \
|
|
print_fld_str(FLD_PF_TYPE, (t)); \
|
|
print_fld_str(FLD_PF_NAME, (n)); \
|
|
print_fld_age(FLD_PF_VALUE, (v)); \
|
|
end_line(); \
|
|
} \
|
|
if (++cur >= end) \
|
|
return; \
|
|
} while (0)
|
|
|
|
#define ADD_EMPTY_LINE \
|
|
do { \
|
|
if (cur >= dispstart && cur < end) \
|
|
end_line(); \
|
|
if (++cur >= end) \
|
|
return; \
|
|
} while (0)
|
|
|
|
#define ADD_LINE_S(t, n, v) \
|
|
do { \
|
|
if (cur >= dispstart && cur < end) { \
|
|
print_fld_str(FLD_PF_TYPE, (t)); \
|
|
print_fld_str(FLD_PF_NAME, (n)); \
|
|
print_fld_str(FLD_PF_VALUE, (v)); \
|
|
end_line(); \
|
|
} \
|
|
if (++cur >= end) \
|
|
return; \
|
|
} while (0)
|
|
|
|
#define ADD_LINE_V(t, n, v) \
|
|
do { \
|
|
if (cur >= dispstart && cur < end) { \
|
|
print_fld_str(FLD_PF_TYPE, (t)); \
|
|
print_fld_str(FLD_PF_NAME, (n)); \
|
|
print_fld_size(FLD_PF_VALUE, (v)); \
|
|
end_line(); \
|
|
} \
|
|
if (++cur >= end) \
|
|
return; \
|
|
} while (0)
|
|
|
|
#define ADD_LINE_VR(t, n, v, r) \
|
|
do { \
|
|
if (cur >= dispstart && cur < end) { \
|
|
print_fld_str(FLD_PF_TYPE, (t)); \
|
|
print_fld_str(FLD_PF_NAME, (n)); \
|
|
print_fld_size(FLD_PF_VALUE, (v)); \
|
|
print_fld_double(FLD_PF_RATE, (r)); \
|
|
end_line(); \
|
|
} \
|
|
if (++cur >= end) \
|
|
return; \
|
|
} while (0)
|
|
|
|
|
|
void
|
|
print_pf(void)
|
|
{
|
|
char *debug;
|
|
time_t tm = 0;
|
|
struct timespec uptime;
|
|
int i;
|
|
struct pf_status *s = &status;
|
|
|
|
int cur = 0;
|
|
int end = dispstart + maxprint;
|
|
if (end > num_disp)
|
|
end = num_disp;
|
|
|
|
if (!clock_gettime(CLOCK_BOOTTIME, &uptime))
|
|
tm = uptime.tv_sec - s->since;
|
|
|
|
ADD_LINE_S("pf", "Status", s->running ? "Enabled" : "Disabled");
|
|
ADD_LINE_A("pf", "Since", tm);
|
|
|
|
switch (s->debug) {
|
|
case LOG_EMERG:
|
|
debug = "emerg";
|
|
break;
|
|
case LOG_ALERT:
|
|
debug = "alert";
|
|
break;
|
|
case LOG_CRIT:
|
|
debug = "crit";
|
|
break;
|
|
case LOG_ERR:
|
|
debug = "err";
|
|
break;
|
|
case LOG_WARNING:
|
|
debug = "warning";
|
|
break;
|
|
case LOG_NOTICE:
|
|
debug = "notice";
|
|
break;
|
|
case LOG_INFO:
|
|
debug = "info";
|
|
break;
|
|
case LOG_DEBUG:
|
|
debug = "debug";
|
|
break;
|
|
default:
|
|
debug = "unknown";
|
|
break;
|
|
}
|
|
ADD_LINE_S("pf", "Debug", debug);
|
|
|
|
tb_start();
|
|
tbprintf("0x%08x\n", ntohl(s->hostid));
|
|
tb_end();
|
|
|
|
ADD_LINE_S("pf", "Hostid", tmp_buf);
|
|
|
|
if (s->ifname[0] != 0) {
|
|
ADD_EMPTY_LINE;
|
|
ADD_LINE_V(s->ifname, "Bytes In IPv4", s->bcounters[0][0]);
|
|
ADD_LINE_V(s->ifname, "Bytes In IPv6", s->bcounters[1][0]);
|
|
ADD_LINE_V(s->ifname, "Bytes Out IPv4", s->bcounters[0][1]);
|
|
ADD_LINE_V(s->ifname, "Bytes Out IPv6", s->bcounters[1][1]);
|
|
ADD_LINE_V(s->ifname, "Packets In Passed IPv4", s->pcounters[0][0][PF_PASS]);
|
|
ADD_LINE_V(s->ifname, "Packets In Passed IPv6", s->pcounters[1][0][PF_PASS]);
|
|
ADD_LINE_V(s->ifname, "Packets In Blocked IPv4", s->pcounters[0][0][PF_DROP]);
|
|
ADD_LINE_V(s->ifname, "Packets In Blocked IPv6", s->pcounters[1][0][PF_DROP]);
|
|
ADD_LINE_V(s->ifname, "Packets Out Passed IPv4", s->pcounters[0][1][PF_PASS]);
|
|
ADD_LINE_V(s->ifname, "Packets Out Passed IPv6", s->pcounters[1][1][PF_PASS]);
|
|
ADD_LINE_V(s->ifname, "Packets Out Blocked IPv4", s->pcounters[0][1][PF_DROP]);
|
|
ADD_LINE_V(s->ifname, "Packets Out Blocked IPv6", s->pcounters[1][1][PF_DROP]);
|
|
}
|
|
|
|
|
|
ADD_EMPTY_LINE;
|
|
ADD_LINE_V("state", "Count", s->states);
|
|
|
|
for (i = 0; i < FCNT_MAX; i++) {
|
|
if (tm > 0)
|
|
ADD_LINE_VR("state", pf_fcounters[i], s->fcounters[i],
|
|
(double)s->fcounters[i] / (double)tm);
|
|
else
|
|
ADD_LINE_V("state", pf_fcounters[i], s->fcounters[i]);
|
|
}
|
|
|
|
|
|
ADD_EMPTY_LINE;
|
|
ADD_LINE_V("src track", "Count", s->src_nodes);
|
|
|
|
for (i = 0; i < SCNT_MAX; i++) {
|
|
if (tm > 0)
|
|
ADD_LINE_VR("src track", pf_scounters[i], s->scounters[i],
|
|
(double)s->scounters[i] / (double)tm);
|
|
else
|
|
ADD_LINE_V("src track", pf_scounters[i], s->scounters[i]);
|
|
}
|
|
|
|
ADD_EMPTY_LINE;
|
|
ADD_LINE_V("fragment", "Count", s->fragments);
|
|
|
|
for (i = 0; i < NCNT_MAX; i++) {
|
|
if (tm > 0)
|
|
ADD_LINE_VR("fragment", pf_ncounters[i], s->ncounters[i],
|
|
(double)s->ncounters[i] / (double)tm);
|
|
else
|
|
ADD_LINE_V("fragment", pf_ncounters[i], s->ncounters[i]);
|
|
}
|
|
|
|
ADD_EMPTY_LINE;
|
|
for (i = 0; i < PFRES_MAX; i++) {
|
|
if (tm > 0)
|
|
ADD_LINE_VR("counter", pf_reasons[i], s->counters[i],
|
|
(double)s->counters[i] / (double)tm);
|
|
else
|
|
ADD_LINE_V("counter", pf_reasons[i], s->counters[i]);
|
|
}
|
|
|
|
ADD_EMPTY_LINE;
|
|
for (i = 0; i < LCNT_MAX; i++) {
|
|
if (tm > 0)
|
|
ADD_LINE_VR("limit counter", pf_lcounters[i], s->lcounters[i],
|
|
(double)s->lcounters[i] / (double)tm);
|
|
else
|
|
ADD_LINE_V("limit counter", pf_lcounters[i], s->lcounters[i]);
|
|
}
|
|
}
|