pf: convert DIOCGETTIMEOUT/DIOCSETTIMEOUT to netlink

This commit is contained in:
Kristof Provost 2024-06-05 05:58:56 +02:00
parent 2c10bacdf4
commit 30bad751e8
9 changed files with 224 additions and 38 deletions

View file

@ -2522,3 +2522,87 @@ pfctl_set_debug(struct pfctl_handle *h, uint32_t level)
return (e.error);
}
int
pfctl_set_timeout(struct pfctl_handle *h, uint32_t timeout, uint32_t seconds)
{
struct snl_writer nw;
struct snl_errmsg_data e = {};
struct nlmsghdr *hdr;
uint32_t seq_id;
int family_id;
family_id = snl_get_genl_family(&h->ss, PFNL_FAMILY_NAME);
if (family_id == 0)
return (ENOTSUP);
snl_init_writer(&h->ss, &nw);
hdr = snl_create_genl_msg_request(&nw, family_id, PFNL_CMD_SET_TIMEOUT);
snl_add_msg_attr_u32(&nw, PF_TO_TIMEOUT, timeout);
snl_add_msg_attr_u32(&nw, PF_TO_SECONDS, seconds);
if ((hdr = snl_finalize_msg(&nw)) == NULL)
return (ENXIO);
seq_id = hdr->nlmsg_seq;
if (! snl_send_message(&h->ss, hdr))
return (ENXIO);
while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
}
return (e.error);
}
struct pfctl_nl_timeout {
uint32_t seconds;
};
#define _OUT(_field) offsetof(struct pfctl_nl_timeout, _field)
static struct snl_attr_parser ap_get_timeout[] = {
{ .type = PF_TO_SECONDS, .off = _OUT(seconds), .cb = snl_attr_get_uint32 },
};
static struct snl_field_parser fp_get_timeout[] = {};
#undef _OUT
SNL_DECLARE_PARSER(get_timeout_parser, struct genlmsghdr, fp_get_timeout, ap_get_timeout);
int
pfctl_get_timeout(struct pfctl_handle *h, uint32_t timeout, uint32_t *seconds)
{
struct snl_writer nw;
struct pfctl_nl_timeout to = {};
struct snl_errmsg_data e = {};
struct nlmsghdr *hdr;
uint32_t seq_id;
int family_id;
family_id = snl_get_genl_family(&h->ss, PFNL_FAMILY_NAME);
if (family_id == 0)
return (ENOTSUP);
snl_init_writer(&h->ss, &nw);
hdr = snl_create_genl_msg_request(&nw, family_id, PFNL_CMD_GET_TIMEOUT);
hdr->nlmsg_flags |= NLM_F_DUMP;
snl_add_msg_attr_u32(&nw, PF_TO_TIMEOUT, timeout);
if ((hdr = snl_finalize_msg(&nw)) == NULL)
return (ENXIO);
seq_id = hdr->nlmsg_seq;
if (! snl_send_message(&h->ss, hdr))
return (ENXIO);
while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
if (! snl_parse_nlmsg(&h->ss, hdr, &get_timeout_parser, &to))
continue;
}
if (seconds != NULL)
*seconds = to.seconds;
return (e.error);
}

View file

@ -493,5 +493,7 @@ struct pfctl_natlook {
int pfctl_natlook(struct pfctl_handle *h,
const struct pfctl_natlook_key *k, struct pfctl_natlook *r);
int pfctl_set_debug(struct pfctl_handle *h, uint32_t level);
int pfctl_set_timeout(struct pfctl_handle *h, uint32_t timeout, uint32_t seconds);
int pfctl_get_timeout(struct pfctl_handle *h, uint32_t timeout, uint32_t *seconds);
#endif

View file

@ -5165,7 +5165,7 @@ timeout_spec : STRING NUMBER
yyerror("only positive values permitted");
YYERROR;
}
if (pfctl_set_timeout(pf, $1, $2, 0) != 0) {
if (pfctl_apply_timeout(pf, $1, $2, 0) != 0) {
yyerror("unknown timeout %s", $1);
free($1);
YYERROR;
@ -5179,7 +5179,7 @@ timeout_spec : STRING NUMBER
yyerror("only positive values permitted");
YYERROR;
}
if (pfctl_set_timeout(pf, "interval", $2, 0) != 0)
if (pfctl_apply_timeout(pf, "interval", $2, 0) != 0)
YYERROR;
}
;

View file

@ -1656,17 +1656,15 @@ pfctl_show_running(int dev)
int
pfctl_show_timeouts(int dev, int opts)
{
struct pfioc_tm pt;
uint32_t seconds;
int i;
if (opts & PF_OPT_SHOWALL)
pfctl_print_title("TIMEOUTS:");
memset(&pt, 0, sizeof(pt));
for (i = 0; pf_timeouts[i].name; i++) {
pt.timeout = pf_timeouts[i].timeout;
if (ioctl(dev, DIOCGETTIMEOUT, &pt))
if (pfctl_get_timeout(pfh, pf_timeouts[i].timeout, &seconds))
err(1, "DIOCGETTIMEOUT");
printf("%-20s %10d", pf_timeouts[i].name, pt.seconds);
printf("%-20s %10d", pf_timeouts[i].name, seconds);
if (pf_timeouts[i].timeout >= PFTM_ADAPTIVE_START &&
pf_timeouts[i].timeout <= PFTM_ADAPTIVE_END)
printf(" states");
@ -2469,7 +2467,7 @@ pfctl_load_limit(struct pfctl *pf, unsigned int index, unsigned int limit)
}
int
pfctl_set_timeout(struct pfctl *pf, const char *opt, int seconds, int quiet)
pfctl_apply_timeout(struct pfctl *pf, const char *opt, int seconds, int quiet)
{
int i;
@ -2499,12 +2497,7 @@ pfctl_set_timeout(struct pfctl *pf, const char *opt, int seconds, int quiet)
int
pfctl_load_timeout(struct pfctl *pf, unsigned int timeout, unsigned int seconds)
{
struct pfioc_tm pt;
memset(&pt, 0, sizeof(pt));
pt.timeout = timeout;
pt.seconds = seconds;
if (ioctl(pf->dev, DIOCSETTIMEOUT, &pt)) {
if (pfctl_set_timeout(pf->h, timeout, seconds)) {
warnx("DIOCSETTIMEOUT");
return (1);
}
@ -2553,7 +2546,7 @@ pfctl_set_optimization(struct pfctl *pf, const char *opt)
}
for (i = 0; hint[i].name; i++)
if ((r = pfctl_set_timeout(pf, hint[i].name,
if ((r = pfctl_apply_timeout(pf, hint[i].name,
hint[i].timeout, 1)))
return (r);

View file

@ -285,7 +285,7 @@ int pfctl_add_pool(struct pfctl *, struct pfctl_pool *, sa_family_t);
void pfctl_move_pool(struct pfctl_pool *, struct pfctl_pool *);
void pfctl_clear_pool(struct pfctl_pool *);
int pfctl_set_timeout(struct pfctl *, const char *, int, int);
int pfctl_apply_timeout(struct pfctl *, const char *, int, int);
int pfctl_set_reassembly(struct pfctl *, int, int);
int pfctl_set_optimization(struct pfctl *, const char *);
int pfctl_set_limit(struct pfctl *, const char *, unsigned int);

View file

@ -2503,6 +2503,8 @@ int pf_ioctl_addrule(struct pf_krule *, uint32_t,
uint32_t, const char *, const char *, uid_t uid,
pid_t);
void pf_ioctl_clear_status(void);
int pf_ioctl_get_timeout(int, int *);
int pf_ioctl_set_timeout(int, int, int *);
void pf_krule_free(struct pf_krule *);
void pf_krule_clear_counters(struct pf_krule *);

View file

@ -2443,6 +2443,46 @@ pf_ioctl_clear_status(void)
PF_RULES_WUNLOCK();
}
int
pf_ioctl_set_timeout(int timeout, int seconds, int *prev_seconds)
{
uint32_t old;
if (timeout < 0 || timeout >= PFTM_MAX ||
seconds < 0)
return (EINVAL);
PF_RULES_WLOCK();
old = V_pf_default_rule.timeout[timeout];
if (timeout == PFTM_INTERVAL && seconds == 0)
seconds = 1;
V_pf_default_rule.timeout[timeout] = seconds;
if (timeout == PFTM_INTERVAL && seconds < old)
wakeup(pf_purge_thread);
if (prev_seconds != NULL)
*prev_seconds = old;
PF_RULES_WUNLOCK();
return (0);
}
int
pf_ioctl_get_timeout(int timeout, int *seconds)
{
PF_RULES_RLOCK_TRACKER;
if (timeout < 0 || timeout >= PFTM_MAX)
return (EINVAL);
PF_RULES_RLOCK();
*seconds = V_pf_default_rule.timeout[timeout];
PF_RULES_RUNLOCK();
return (0);
}
static int
pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td)
{
@ -3838,35 +3878,16 @@ pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td
case DIOCSETTIMEOUT: {
struct pfioc_tm *pt = (struct pfioc_tm *)addr;
int old;
if (pt->timeout < 0 || pt->timeout >= PFTM_MAX ||
pt->seconds < 0) {
error = EINVAL;
break;
}
PF_RULES_WLOCK();
old = V_pf_default_rule.timeout[pt->timeout];
if (pt->timeout == PFTM_INTERVAL && pt->seconds == 0)
pt->seconds = 1;
V_pf_default_rule.timeout[pt->timeout] = pt->seconds;
if (pt->timeout == PFTM_INTERVAL && pt->seconds < old)
wakeup(pf_purge_thread);
pt->seconds = old;
PF_RULES_WUNLOCK();
error = pf_ioctl_set_timeout(pt->timeout, pt->seconds,
&pt->seconds);
break;
}
case DIOCGETTIMEOUT: {
struct pfioc_tm *pt = (struct pfioc_tm *)addr;
if (pt->timeout < 0 || pt->timeout >= PFTM_MAX) {
error = EINVAL;
break;
}
PF_RULES_RLOCK();
pt->seconds = V_pf_default_rule.timeout[pt->timeout];
PF_RULES_RUNLOCK();
error = pf_ioctl_get_timeout(pt->timeout, &pt->seconds);
break;
}

View file

@ -1349,6 +1349,67 @@ pf_handle_set_debug(struct nlmsghdr *hdr, struct nl_pstate *npt)
return (0);
}
struct pf_nl_set_timeout
{
uint32_t timeout;
uint32_t seconds;
};
#define _OUT(_field) offsetof(struct pf_nl_set_timeout, _field)
static const struct nlattr_parser nla_p_set_timeout[] = {
{ .type = PF_TO_TIMEOUT, .off = _OUT(timeout), .cb = nlattr_get_uint32 },
{ .type = PF_TO_SECONDS, .off = _OUT(seconds), .cb = nlattr_get_uint32 },
};
static const struct nlfield_parser nlf_p_set_timeout[] = {};
#undef _OUT
NL_DECLARE_PARSER(set_timeout_parser, struct genlmsghdr, nlf_p_set_timeout, nla_p_set_timeout);
static int
pf_handle_set_timeout(struct nlmsghdr *hdr, struct nl_pstate *npt)
{
struct pf_nl_set_timeout attrs = {};
int error;
error = nl_parse_nlmsg(hdr, &set_timeout_parser, npt, &attrs);
if (error != 0)
return (error);
return (pf_ioctl_set_timeout(attrs.timeout, attrs.seconds, NULL));
}
static int
pf_handle_get_timeout(struct nlmsghdr *hdr, struct nl_pstate *npt)
{
struct pf_nl_set_timeout attrs = {};
struct nl_writer *nw = npt->nw;
struct genlmsghdr *ghdr_new;
int error;
error = nl_parse_nlmsg(hdr, &set_timeout_parser, npt, &attrs);
if (error != 0)
return (error);
error = pf_ioctl_get_timeout(attrs.timeout, &attrs.seconds);
if (error != 0)
return (error);
if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
return (ENOMEM);
ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
ghdr_new->cmd = PFNL_CMD_GET_TIMEOUT;
ghdr_new->version = 0;
ghdr_new->reserved = 0;
nlattr_add_u32(nw, PF_TO_SECONDS, attrs.seconds);
if (!nlmsg_end(nw)) {
nlmsg_abort(nw);
return (ENOMEM);
}
return (0);
}
static const struct nlhdr_parser *all_parsers[] = {
&state_parser,
&addrule_parser,
@ -1357,6 +1418,7 @@ static const struct nlhdr_parser *all_parsers[] = {
&set_statusif_parser,
&natlook_parser,
&set_debug_parser,
&set_timeout_parser,
};
static int family_id;
@ -1460,6 +1522,20 @@ static const struct genl_cmd pf_cmds[] = {
.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
.cmd_priv = PRIV_NETINET_PF,
},
{
.cmd_num = PFNL_CMD_SET_TIMEOUT,
.cmd_name = "SET_TIMEOUT",
.cmd_cb = pf_handle_set_timeout,
.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
.cmd_priv = PRIV_NETINET_PF,
},
{
.cmd_num = PFNL_CMD_GET_TIMEOUT,
.cmd_name = "GET_TIMEOUT",
.cmd_cb = pf_handle_get_timeout,
.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
.cmd_priv = PRIV_NETINET_PF,
},
};
void

View file

@ -50,6 +50,8 @@ enum {
PFNL_CMD_CLEAR_STATUS = 12,
PFNL_CMD_NATLOOK = 13,
PFNL_CMD_SET_DEBUG = 14,
PFNL_CMD_SET_TIMEOUT = 15,
PFNL_CMD_GET_TIMEOUT = 16,
__PFNL_CMD_MAX,
};
#define PFNL_CMD_MAX (__PFNL_CMD_MAX -1)
@ -334,6 +336,12 @@ enum pf_set_debug_types_t {
PF_SD_LEVEL = 1, /* u32 */
};
enum pf_timeout_types_t {
PF_TO_UNSPEC,
PF_TO_TIMEOUT = 1, /* u32 */
PF_TO_SECONDS = 2, /* u32 */
};
#ifdef _KERNEL
void pf_nl_register(void);