289 lines
5.5 KiB
C
289 lines
5.5 KiB
C
|
|
/* SPDX-License-Identifier: LGPL-2.1-only */
|
||
|
|
/*
|
||
|
|
* Copyright (c) 2016 Magnus Öberg <magnus.oberg@westermo.se>
|
||
|
|
*/
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @ingroup act
|
||
|
|
* @defgroup act_nat NAT
|
||
|
|
*
|
||
|
|
* @{
|
||
|
|
*/
|
||
|
|
|
||
|
|
#include <netlink-private/netlink.h>
|
||
|
|
#include <netlink-private/tc.h>
|
||
|
|
#include <netlink/netlink.h>
|
||
|
|
#include <netlink/attr.h>
|
||
|
|
#include <netlink/utils.h>
|
||
|
|
#include <netlink-private/route/tc-api.h>
|
||
|
|
#include <netlink/route/act/nat.h>
|
||
|
|
#include <netlink/route/tc.h>
|
||
|
|
|
||
|
|
static struct nla_policy nat_policy[TCA_NAT_MAX + 1] = {
|
||
|
|
[TCA_NAT_PARMS] = { .minlen = sizeof(struct tc_nat) },
|
||
|
|
};
|
||
|
|
|
||
|
|
/**
|
||
|
|
* nat operations
|
||
|
|
*/
|
||
|
|
|
||
|
|
static int nat_msg_parser(struct rtnl_tc *tc, void *data)
|
||
|
|
{
|
||
|
|
struct tc_nat *nat = data;
|
||
|
|
struct nlattr *tb[TCA_NAT_MAX + 1];
|
||
|
|
int err;
|
||
|
|
|
||
|
|
err = tca_parse(tb, TCA_NAT_MAX, tc, nat_policy);
|
||
|
|
if (err < 0)
|
||
|
|
return err;
|
||
|
|
|
||
|
|
if (!tb[TCA_NAT_PARMS])
|
||
|
|
return -NLE_MISSING_ATTR;
|
||
|
|
|
||
|
|
nla_memcpy(nat, tb[TCA_NAT_PARMS], sizeof(*nat));
|
||
|
|
|
||
|
|
return NLE_SUCCESS;
|
||
|
|
}
|
||
|
|
|
||
|
|
static void nat_free_data(struct rtnl_tc *tc, void *data)
|
||
|
|
{
|
||
|
|
}
|
||
|
|
|
||
|
|
static int nat_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg)
|
||
|
|
{
|
||
|
|
struct tc_nat *nat = data;
|
||
|
|
|
||
|
|
if (!nat)
|
||
|
|
return -NLE_OBJ_NOTFOUND;
|
||
|
|
|
||
|
|
NLA_PUT(msg, TCA_NAT_PARMS, sizeof(*nat), nat);
|
||
|
|
|
||
|
|
return NLE_SUCCESS;
|
||
|
|
|
||
|
|
nla_put_failure:
|
||
|
|
return -NLE_NOMEM;
|
||
|
|
}
|
||
|
|
|
||
|
|
static void nat_dump_line(struct rtnl_tc *tc, void *data,
|
||
|
|
struct nl_dump_params *p)
|
||
|
|
{
|
||
|
|
struct tc_nat *nat = data;
|
||
|
|
char buf[32];
|
||
|
|
uint32_t mask;
|
||
|
|
int pfx = 0;
|
||
|
|
|
||
|
|
if (!nat)
|
||
|
|
return;
|
||
|
|
|
||
|
|
if (nat->flags & TCA_NAT_FLAG_EGRESS)
|
||
|
|
nl_dump(p, " egress");
|
||
|
|
else
|
||
|
|
nl_dump(p, " ingress");
|
||
|
|
|
||
|
|
mask = nat->mask;
|
||
|
|
while (mask > 0) {
|
||
|
|
mask = mask >> 1;
|
||
|
|
pfx++;
|
||
|
|
}
|
||
|
|
|
||
|
|
inet_ntop(AF_INET, &nat->old_addr, buf, sizeof(buf));
|
||
|
|
nl_dump(p, " %s", buf);
|
||
|
|
if (pfx < 32)
|
||
|
|
nl_dump(p, "/%d", pfx);
|
||
|
|
|
||
|
|
inet_ntop(AF_INET, &nat->new_addr, buf, sizeof(buf));
|
||
|
|
nl_dump(p, " %s", buf);
|
||
|
|
if (pfx < 32)
|
||
|
|
nl_dump(p, "/%d", pfx);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @name Attribute Modifications
|
||
|
|
* @{
|
||
|
|
*/
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Set old IPv4 address on a netlink NAT action object
|
||
|
|
* @arg act Action object
|
||
|
|
* @arg addr Binary IPv4 address in host byte order
|
||
|
|
*
|
||
|
|
* @return 0 on success or negative error code in case of an error.
|
||
|
|
*/
|
||
|
|
int rtnl_nat_set_old_addr(struct rtnl_act *act, in_addr_t addr)
|
||
|
|
{
|
||
|
|
struct tc_nat *nat;
|
||
|
|
|
||
|
|
if (!(nat = (struct tc_nat *)rtnl_tc_data(TC_CAST(act))))
|
||
|
|
return -NLE_NOMEM;
|
||
|
|
|
||
|
|
nat->old_addr = addr;
|
||
|
|
|
||
|
|
return NLE_SUCCESS;
|
||
|
|
}
|
||
|
|
|
||
|
|
int rtnl_nat_get_old_addr(struct rtnl_act *act, in_addr_t *addr)
|
||
|
|
{
|
||
|
|
struct tc_nat *nat;
|
||
|
|
|
||
|
|
if (!(nat = (struct tc_nat *)rtnl_tc_data_peek(TC_CAST(act))))
|
||
|
|
return -NLE_NOATTR;
|
||
|
|
|
||
|
|
*addr = nat->old_addr;
|
||
|
|
|
||
|
|
return NLE_SUCCESS;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Set new IPv4 address on a netlink NAT action object
|
||
|
|
* @arg act Action object
|
||
|
|
* @arg addr Binary IPv4 address in host byte order
|
||
|
|
*
|
||
|
|
* @return 0 on success or negative error code in case of an error.
|
||
|
|
*/
|
||
|
|
int rtnl_nat_set_new_addr(struct rtnl_act *act, in_addr_t addr)
|
||
|
|
{
|
||
|
|
struct tc_nat *nat;
|
||
|
|
|
||
|
|
if (!(nat = (struct tc_nat *)rtnl_tc_data(TC_CAST(act))))
|
||
|
|
return -NLE_NOMEM;
|
||
|
|
|
||
|
|
nat->new_addr = addr;
|
||
|
|
|
||
|
|
return NLE_SUCCESS;
|
||
|
|
}
|
||
|
|
|
||
|
|
int rtnl_nat_get_new_addr(struct rtnl_act *act, in_addr_t *addr)
|
||
|
|
{
|
||
|
|
struct tc_nat *nat;
|
||
|
|
|
||
|
|
if (!(nat = (struct tc_nat *)rtnl_tc_data_peek(TC_CAST(act))))
|
||
|
|
return -NLE_NOATTR;
|
||
|
|
|
||
|
|
*addr = nat->new_addr;
|
||
|
|
|
||
|
|
return NLE_SUCCESS;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Set IPv4 address mask on a netlink NAT action object
|
||
|
|
* @arg act Action object
|
||
|
|
* @arg mask IPv4 address mask
|
||
|
|
*
|
||
|
|
* @return 0 on success or negative error code in case of an error.
|
||
|
|
*/
|
||
|
|
int rtnl_nat_set_mask(struct rtnl_act *act, in_addr_t bitmask)
|
||
|
|
{
|
||
|
|
struct tc_nat *nat;
|
||
|
|
|
||
|
|
if (!(nat = (struct tc_nat *)rtnl_tc_data(TC_CAST(act))))
|
||
|
|
return -NLE_NOMEM;
|
||
|
|
|
||
|
|
nat->mask = bitmask;
|
||
|
|
|
||
|
|
return NLE_SUCCESS;
|
||
|
|
}
|
||
|
|
|
||
|
|
int rtnl_nat_get_mask(struct rtnl_act *act, in_addr_t *bitmask)
|
||
|
|
{
|
||
|
|
struct tc_nat *nat;
|
||
|
|
|
||
|
|
if (!(nat = (struct tc_nat *)rtnl_tc_data_peek(TC_CAST(act))))
|
||
|
|
return -NLE_NOATTR;
|
||
|
|
|
||
|
|
*bitmask = nat->mask;
|
||
|
|
|
||
|
|
return NLE_SUCCESS;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Set flags for a netlink NAT action object
|
||
|
|
* @arg act Action object
|
||
|
|
* @arg flags TCA_NAT_FLAG_* flags.
|
||
|
|
*
|
||
|
|
* Currently only TCA_NAT_FLAG_EGRESS is defined. Selects NAT on
|
||
|
|
* egress/IP src if set, ingress/IP dst otherwise.
|
||
|
|
*
|
||
|
|
* @return 0 on success or negative error code in case of an error.
|
||
|
|
*/
|
||
|
|
int rtnl_nat_set_flags(struct rtnl_act *act, uint32_t flags)
|
||
|
|
{
|
||
|
|
struct tc_nat *nat;
|
||
|
|
|
||
|
|
if (!(nat = (struct tc_nat *)rtnl_tc_data(TC_CAST(act))))
|
||
|
|
return -NLE_NOMEM;
|
||
|
|
|
||
|
|
nat->flags = flags;
|
||
|
|
|
||
|
|
return NLE_SUCCESS;
|
||
|
|
}
|
||
|
|
|
||
|
|
int rtnl_nat_get_flags(struct rtnl_act *act, uint32_t *flags)
|
||
|
|
{
|
||
|
|
struct tc_nat *nat;
|
||
|
|
|
||
|
|
if (!(nat = (struct tc_nat *)rtnl_tc_data_peek(TC_CAST(act))))
|
||
|
|
return -NLE_NOATTR;
|
||
|
|
|
||
|
|
*flags = nat->flags;
|
||
|
|
|
||
|
|
return NLE_SUCCESS;
|
||
|
|
}
|
||
|
|
|
||
|
|
int rtnl_nat_set_action(struct rtnl_act *act, int action)
|
||
|
|
{
|
||
|
|
struct tc_nat *nat;
|
||
|
|
|
||
|
|
if (!(nat = (struct tc_nat *)rtnl_tc_data(TC_CAST(act))))
|
||
|
|
return -NLE_NOMEM;
|
||
|
|
|
||
|
|
if (action < TC_ACT_UNSPEC)
|
||
|
|
return -NLE_INVAL;
|
||
|
|
|
||
|
|
nat->action = action;
|
||
|
|
|
||
|
|
return NLE_SUCCESS;
|
||
|
|
}
|
||
|
|
|
||
|
|
int rtnl_nat_get_action(struct rtnl_act *act, int *action)
|
||
|
|
{
|
||
|
|
struct tc_nat *nat;
|
||
|
|
|
||
|
|
if (!(nat = (struct tc_nat *)rtnl_tc_data_peek(TC_CAST(act))))
|
||
|
|
return -NLE_NOATTR;
|
||
|
|
|
||
|
|
*action = nat->action;
|
||
|
|
|
||
|
|
return NLE_SUCCESS;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @}
|
||
|
|
*/
|
||
|
|
|
||
|
|
static struct rtnl_tc_ops nat_ops = {
|
||
|
|
.to_kind = "nat",
|
||
|
|
.to_type = RTNL_TC_TYPE_ACT,
|
||
|
|
.to_size = sizeof(struct tc_nat),
|
||
|
|
.to_msg_parser = nat_msg_parser,
|
||
|
|
.to_free_data = nat_free_data,
|
||
|
|
.to_clone = NULL,
|
||
|
|
.to_msg_fill = nat_msg_fill,
|
||
|
|
.to_dump = {
|
||
|
|
[NL_DUMP_LINE] = nat_dump_line,
|
||
|
|
},
|
||
|
|
};
|
||
|
|
|
||
|
|
static void __init nat_init(void)
|
||
|
|
{
|
||
|
|
rtnl_tc_register(&nat_ops);
|
||
|
|
}
|
||
|
|
|
||
|
|
static void __exit nat_exit(void)
|
||
|
|
{
|
||
|
|
rtnl_tc_unregister(&nat_ops);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @}
|
||
|
|
*/
|