unplugged-system/external/libnl/lib/route/act/nat.c

289 lines
5.5 KiB
C
Raw Normal View History

/* 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);
}
/**
* @}
*/