mirror of
git://git.code.sf.net/p/xtables-addons/xtables-addons
synced 2025-09-07 13:15:12 +02:00
751 lines
19 KiB
C
751 lines
19 KiB
C
/* Copyright 2007-2010 Jozsef Kadlecsik (kadlec@blackhole.kfki.hu)
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation.
|
|
*/
|
|
#include <assert.h> /* assert */
|
|
#include <errno.h> /* errno */
|
|
#include <stdio.h> /* snprintf */
|
|
#include <netdb.h> /* getservbyport */
|
|
#include <sys/types.h> /* inet_ntop */
|
|
#include <sys/socket.h> /* inet_ntop */
|
|
#include <arpa/inet.h> /* inet_ntop */
|
|
#include <net/ethernet.h> /* ETH_ALEN */
|
|
|
|
#include <libipset/debug.h> /* D() */
|
|
#include <libipset/data.h> /* ipset_data_* */
|
|
#include <libipset/icmp.h> /* icmp_to_name */
|
|
#include <libipset/icmpv6.h> /* icmpv6_to_name */
|
|
#include <libipset/parse.h> /* IPSET_*_SEPARATOR */
|
|
#include <libipset/types.h> /* ipset set types */
|
|
#include <libipset/session.h> /* IPSET_FLAG_ */
|
|
#include <libipset/utils.h> /* UNUSED */
|
|
#include <libipset/ui.h> /* IPSET_ENV_* */
|
|
#include <libipset/print.h> /* prototypes */
|
|
|
|
/* Print data (to output buffer). All function must follow snprintf. */
|
|
|
|
#define SNPRINTF_FAILURE(size, len, offset) \
|
|
do { \
|
|
if (size < 0 || (unsigned int) size >= len) \
|
|
return size; \
|
|
offset += size; \
|
|
len -= size; \
|
|
} while (0)
|
|
|
|
/**
|
|
* ipset_print_ether - print ethernet address to string
|
|
* @buf: printing buffer
|
|
* @len: length of available buffer space
|
|
* @data: data blob
|
|
* @opt: the option kind
|
|
* @env: environment flags
|
|
*
|
|
* Print Ethernet address to output buffer.
|
|
*
|
|
* Return lenght of printed string or error size.
|
|
*/
|
|
int
|
|
ipset_print_ether(char *buf, unsigned int len,
|
|
const struct ipset_data *data, enum ipset_opt opt,
|
|
uint8_t env UNUSED)
|
|
{
|
|
const unsigned char *ether;
|
|
int i, size, offset = 0;
|
|
|
|
assert(buf);
|
|
assert(len > 0);
|
|
assert(data);
|
|
assert(opt == IPSET_OPT_ETHER);
|
|
|
|
if (len < ETH_ALEN*3)
|
|
return -1;
|
|
|
|
ether = ipset_data_get(data, opt);
|
|
assert(ether);
|
|
|
|
size = snprintf(buf, len, "%02X", ether[0]);
|
|
SNPRINTF_FAILURE(size, len, offset);
|
|
for (i = 1; i < ETH_ALEN; i++) {
|
|
size = snprintf(buf + offset, len, ":%02X", ether[i]);
|
|
SNPRINTF_FAILURE(size, len, offset);
|
|
}
|
|
|
|
return offset;
|
|
}
|
|
|
|
/**
|
|
* ipset_print_family - print INET family
|
|
* @buf: printing buffer
|
|
* @len: length of available buffer space
|
|
* @data: data blob
|
|
* @opt: the option kind
|
|
* @env: environment flags
|
|
*
|
|
* Print INET family string to output buffer.
|
|
*
|
|
* Return lenght of printed string or error size.
|
|
*/
|
|
int
|
|
ipset_print_family(char *buf, unsigned int len,
|
|
const struct ipset_data *data,
|
|
enum ipset_opt opt ASSERT_UNUSED,
|
|
uint8_t env UNUSED)
|
|
{
|
|
uint8_t family;
|
|
|
|
assert(buf);
|
|
assert(len > 0);
|
|
assert(data);
|
|
assert(opt == IPSET_OPT_FAMILY);
|
|
|
|
if (len < strlen("inet6") + 1)
|
|
return -1;
|
|
|
|
family = ipset_data_family(data);
|
|
|
|
return snprintf(buf, len, "%s",
|
|
family == AF_INET ? "inet" :
|
|
family == AF_INET6 ? "inet6" : "any");
|
|
}
|
|
|
|
/**
|
|
* ipset_print_type - print ipset type string
|
|
* @buf: printing buffer
|
|
* @len: length of available buffer space
|
|
* @data: data blob
|
|
* @opt: the option kind
|
|
* @env: environment flags
|
|
*
|
|
* Print ipset module string identifier to output buffer.
|
|
*
|
|
* Return lenght of printed string or error size.
|
|
*/
|
|
int
|
|
ipset_print_type(char *buf, unsigned int len,
|
|
const struct ipset_data *data, enum ipset_opt opt,
|
|
uint8_t env UNUSED)
|
|
{
|
|
const struct ipset_type *type;
|
|
|
|
assert(buf);
|
|
assert(len > 0);
|
|
assert(data);
|
|
assert(opt == IPSET_OPT_TYPE);
|
|
|
|
type = ipset_data_get(data, opt);
|
|
assert(type);
|
|
if (len < strlen(type->name) + 1)
|
|
return -1;
|
|
|
|
return snprintf(buf, len, "%s", type->name);
|
|
}
|
|
|
|
#define GETNAMEINFO(family, f, n) \
|
|
static inline int \
|
|
__getnameinfo##f(char *buf, unsigned int len, \
|
|
int flags, const union nf_inet_addr *addr) \
|
|
{ \
|
|
struct sockaddr_in##n saddr; \
|
|
int err; \
|
|
\
|
|
memset(&saddr, 0, sizeof(saddr)); \
|
|
in##f##cpy(&saddr.sin##n##_addr, &addr->in##n); \
|
|
saddr.sin##n##_family = family; \
|
|
\
|
|
err = getnameinfo((const struct sockaddr *)&saddr, \
|
|
sizeof(saddr), \
|
|
buf, len, NULL, 0, flags); \
|
|
\
|
|
if (!(flags & NI_NUMERICHOST) && \
|
|
(err == EAI_AGAIN || (err == 0 && strchr(buf, '-') != NULL))) \
|
|
err = getnameinfo((const struct sockaddr *)&saddr, \
|
|
sizeof(saddr), \
|
|
buf, len, NULL, 0, \
|
|
flags | NI_NUMERICHOST); \
|
|
D("getnameinfo err: %i, errno %i", err, errno); \
|
|
return (err == 0 ? (int)strlen(buf) : \
|
|
(err == EAI_OVERFLOW || err == EAI_SYSTEM) ? (int)len : -1);\
|
|
}
|
|
|
|
#define SNPRINTF_IP(mask, f) \
|
|
static int \
|
|
snprintf_ipv##f(char *buf, unsigned int len, int flags, \
|
|
const union nf_inet_addr *ip, uint8_t cidr) \
|
|
{ \
|
|
int size, offset = 0; \
|
|
\
|
|
size = __getnameinfo##f(buf, len, flags, ip); \
|
|
SNPRINTF_FAILURE(size, len, offset); \
|
|
\
|
|
D("cidr %u mask %u", cidr, mask); \
|
|
if (cidr == mask) \
|
|
return offset; \
|
|
D("print cidr"); \
|
|
size = snprintf(buf + offset, len, \
|
|
"%s%u", IPSET_CIDR_SEPARATOR, cidr); \
|
|
SNPRINTF_FAILURE(size, len, offset); \
|
|
return offset; \
|
|
}
|
|
|
|
GETNAMEINFO(AF_INET, 4, )
|
|
SNPRINTF_IP(32, 4)
|
|
|
|
GETNAMEINFO(AF_INET6, 6, 6)
|
|
SNPRINTF_IP(128, 6)
|
|
|
|
/**
|
|
* ipset_print_ip - print IPv4|IPv6 address to string
|
|
* @buf: printing buffer
|
|
* @len: length of available buffer space
|
|
* @data: data blob
|
|
* @opt: the option kind
|
|
* @env: environment flags
|
|
*
|
|
* Print IPv4|IPv6 address, address/cidr or address range to output buffer.
|
|
*
|
|
* Return lenght of printed string or error size.
|
|
*/
|
|
int
|
|
ipset_print_ip(char *buf, unsigned int len,
|
|
const struct ipset_data *data, enum ipset_opt opt,
|
|
uint8_t env)
|
|
{
|
|
const union nf_inet_addr *ip;
|
|
uint8_t family, cidr;
|
|
int flags, size, offset = 0;
|
|
enum ipset_opt cidropt;
|
|
|
|
assert(buf);
|
|
assert(len > 0);
|
|
assert(data);
|
|
assert(opt == IPSET_OPT_IP || opt == IPSET_OPT_IP2);
|
|
|
|
D("len: %u", len);
|
|
family = ipset_data_family(data);
|
|
cidropt = opt == IPSET_OPT_IP ? IPSET_OPT_CIDR : IPSET_OPT_CIDR2;
|
|
if (ipset_data_test(data, cidropt)) {
|
|
cidr = *(const uint8_t *) ipset_data_get(data, cidropt);
|
|
D("CIDR: %u", cidr);
|
|
} else
|
|
cidr = family == AF_INET6 ? 128 : 32;
|
|
flags = (env & IPSET_ENV_RESOLVE) ? 0 : NI_NUMERICHOST;
|
|
|
|
ip = ipset_data_get(data, opt);
|
|
assert(ip);
|
|
if (family == AF_INET)
|
|
size = snprintf_ipv4(buf, len, flags, ip, cidr);
|
|
else if (family == AF_INET6)
|
|
size = snprintf_ipv6(buf, len, flags, ip, cidr);
|
|
else
|
|
return -1;
|
|
D("size %i, len %u", size, len);
|
|
SNPRINTF_FAILURE(size, len, offset);
|
|
|
|
D("len: %u, offset %u", len, offset);
|
|
if (!ipset_data_test(data, IPSET_OPT_IP_TO))
|
|
return offset;
|
|
|
|
size = snprintf(buf + offset, len, "%s", IPSET_RANGE_SEPARATOR);
|
|
SNPRINTF_FAILURE(size, len, offset);
|
|
|
|
ip = ipset_data_get(data, IPSET_OPT_IP_TO);
|
|
if (family == AF_INET)
|
|
size = snprintf_ipv4(buf + offset, len, flags, ip, cidr);
|
|
else if (family == AF_INET6)
|
|
size = snprintf_ipv6(buf + offset, len, flags, ip, cidr);
|
|
else
|
|
return -1;
|
|
|
|
SNPRINTF_FAILURE(size, len, offset);
|
|
return offset;
|
|
}
|
|
|
|
/**
|
|
* ipset_print_ipaddr - print IPv4|IPv6 address to string
|
|
* @buf: printing buffer
|
|
* @len: length of available buffer space
|
|
* @data: data blob
|
|
* @opt: the option kind
|
|
* @env: environment flags
|
|
*
|
|
* Print IPv4|IPv6 address or address/cidr to output buffer.
|
|
*
|
|
* Return lenght of printed string or error size.
|
|
*/
|
|
int
|
|
ipset_print_ipaddr(char *buf, unsigned int len,
|
|
const struct ipset_data *data, enum ipset_opt opt,
|
|
uint8_t env)
|
|
{
|
|
const union nf_inet_addr *ip;
|
|
uint8_t family, cidr;
|
|
enum ipset_opt cidropt;
|
|
int flags;
|
|
|
|
assert(buf);
|
|
assert(len > 0);
|
|
assert(data);
|
|
assert(opt == IPSET_OPT_IP
|
|
|| opt == IPSET_OPT_IP_TO
|
|
|| opt == IPSET_OPT_IP2);
|
|
|
|
family = ipset_data_family(data);
|
|
cidropt = opt == IPSET_OPT_IP ? IPSET_OPT_CIDR : IPSET_OPT_CIDR2;
|
|
if (ipset_data_test(data, cidropt))
|
|
cidr = *(const uint8_t *) ipset_data_get(data, cidropt);
|
|
else
|
|
cidr = family == AF_INET6 ? 128 : 32;
|
|
flags = (env & IPSET_ENV_RESOLVE) ? 0 : NI_NUMERICHOST;
|
|
|
|
ip = ipset_data_get(data, opt);
|
|
assert(ip);
|
|
if (family == AF_INET)
|
|
return snprintf_ipv4(buf, len, flags, ip, cidr);
|
|
else if (family == AF_INET6)
|
|
return snprintf_ipv6(buf, len, flags, ip, cidr);
|
|
|
|
return -1;
|
|
}
|
|
|
|
/**
|
|
* ipset_print_number - print number to string
|
|
* @buf: printing buffer
|
|
* @len: length of available buffer space
|
|
* @data: data blob
|
|
* @opt: the option kind
|
|
* @env: environment flags
|
|
*
|
|
* Print number to output buffer.
|
|
*
|
|
* Return lenght of printed string or error size.
|
|
*/
|
|
int
|
|
ipset_print_number(char *buf, unsigned int len,
|
|
const struct ipset_data *data, enum ipset_opt opt,
|
|
uint8_t env UNUSED)
|
|
{
|
|
size_t maxsize;
|
|
const void *number;
|
|
|
|
assert(buf);
|
|
assert(len > 0);
|
|
assert(data);
|
|
|
|
number = ipset_data_get(data, opt);
|
|
maxsize = ipset_data_sizeof(opt, AF_INET);
|
|
D("opt: %u, maxsize %zu", opt, maxsize);
|
|
if (maxsize == sizeof(uint8_t))
|
|
return snprintf(buf, len, "%u", *(const uint8_t *) number);
|
|
else if (maxsize == sizeof(uint16_t))
|
|
return snprintf(buf, len, "%u", *(const uint16_t *) number);
|
|
else if (maxsize == sizeof(uint32_t))
|
|
return snprintf(buf, len, "%lu",
|
|
(long unsigned) *(const uint32_t *) number);
|
|
else
|
|
assert(0);
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* ipset_print_name - print setname element string
|
|
* @buf: printing buffer
|
|
* @len: length of available buffer space
|
|
* @data: data blob
|
|
* @opt: the option kind
|
|
* @env: environment flags
|
|
*
|
|
* Print setname element string to output buffer.
|
|
*
|
|
* Return lenght of printed string or error size.
|
|
*/
|
|
int
|
|
ipset_print_name(char *buf, unsigned int len,
|
|
const struct ipset_data *data, enum ipset_opt opt,
|
|
uint8_t env UNUSED)
|
|
{
|
|
const char *name;
|
|
int size, offset = 0;
|
|
|
|
assert(buf);
|
|
assert(len > 0);
|
|
assert(data);
|
|
assert(opt == IPSET_OPT_NAME);
|
|
|
|
if (len < 2*IPSET_MAXNAMELEN + 2 + strlen("before"))
|
|
return -1;
|
|
|
|
name = ipset_data_get(data, opt);
|
|
assert(name);
|
|
size = snprintf(buf, len, "%s", name);
|
|
SNPRINTF_FAILURE(size, len, offset);
|
|
|
|
if (ipset_data_test(data, IPSET_OPT_NAMEREF)) {
|
|
bool before = false;
|
|
if (ipset_data_flags_test(data, IPSET_FLAG(IPSET_OPT_FLAGS))) {
|
|
const uint32_t *flags =
|
|
ipset_data_get(data, IPSET_OPT_FLAGS);
|
|
before = (*flags) & IPSET_FLAG_BEFORE;
|
|
}
|
|
size = snprintf(buf + offset, len,
|
|
" %s %s", before ? "before" : "after",
|
|
(const char *) ipset_data_get(data,
|
|
IPSET_OPT_NAMEREF));
|
|
SNPRINTF_FAILURE(size, len, offset);
|
|
}
|
|
|
|
return offset;
|
|
}
|
|
|
|
/**
|
|
* ipset_print_port - print port or port range
|
|
* @buf: printing buffer
|
|
* @len: length of available buffer space
|
|
* @data: data blob
|
|
* @opt: the option kind
|
|
* @env: environment flags
|
|
*
|
|
* Print port or port range to output buffer.
|
|
*
|
|
* Return lenght of printed string or error size.
|
|
*/
|
|
int
|
|
ipset_print_port(char *buf, unsigned int len,
|
|
const struct ipset_data *data,
|
|
enum ipset_opt opt ASSERT_UNUSED,
|
|
uint8_t env UNUSED)
|
|
{
|
|
const uint16_t *port;
|
|
int size, offset = 0;
|
|
|
|
assert(buf);
|
|
assert(len > 0);
|
|
assert(data);
|
|
assert(opt == IPSET_OPT_PORT);
|
|
|
|
if (len < 2*strlen("65535") + 2)
|
|
return -1;
|
|
|
|
port = ipset_data_get(data, IPSET_OPT_PORT);
|
|
assert(port);
|
|
size = snprintf(buf, len, "%u", *port);
|
|
SNPRINTF_FAILURE(size, len, offset);
|
|
|
|
if (ipset_data_test(data, IPSET_OPT_PORT_TO)) {
|
|
port = ipset_data_get(data, IPSET_OPT_PORT_TO);
|
|
size = snprintf(buf + offset, len,
|
|
"%s%u",
|
|
IPSET_RANGE_SEPARATOR, *port);
|
|
SNPRINTF_FAILURE(size, len, offset);
|
|
}
|
|
|
|
return offset;
|
|
}
|
|
|
|
/**
|
|
* ipset_print_proto - print protocol name
|
|
* @buf: printing buffer
|
|
* @len: length of available buffer space
|
|
* @data: data blob
|
|
* @opt: the option kind
|
|
* @env: environment flags
|
|
*
|
|
* Print protocol name to output buffer.
|
|
*
|
|
* Return lenght of printed string or error size.
|
|
*/
|
|
int
|
|
ipset_print_proto(char *buf, unsigned int len,
|
|
const struct ipset_data *data,
|
|
enum ipset_opt opt ASSERT_UNUSED,
|
|
uint8_t env UNUSED)
|
|
{
|
|
const struct protoent *protoent;
|
|
uint8_t proto;
|
|
|
|
assert(buf);
|
|
assert(len > 0);
|
|
assert(data);
|
|
assert(opt == IPSET_OPT_PROTO);
|
|
|
|
proto = *(const uint8_t *) ipset_data_get(data, IPSET_OPT_PROTO);
|
|
assert(proto);
|
|
|
|
protoent = getprotobynumber(proto);
|
|
if (protoent)
|
|
return snprintf(buf, len, "%s", protoent->p_name);
|
|
|
|
/* Should not happen */
|
|
return snprintf(buf, len, "%u", proto);
|
|
}
|
|
|
|
/**
|
|
* ipset_print_icmp - print ICMP code name or type/code
|
|
* @buf: printing buffer
|
|
* @len: length of available buffer space
|
|
* @data: data blob
|
|
* @opt: the option kind
|
|
* @env: environment flags
|
|
*
|
|
* Print ICMP code name or type/code name to output buffer.
|
|
*
|
|
* Return lenght of printed string or error size.
|
|
*/
|
|
int
|
|
ipset_print_icmp(char *buf, unsigned int len,
|
|
const struct ipset_data *data,
|
|
enum ipset_opt opt ASSERT_UNUSED,
|
|
uint8_t env UNUSED)
|
|
{
|
|
const char *name;
|
|
uint16_t typecode;
|
|
|
|
assert(buf);
|
|
assert(len > 0);
|
|
assert(data);
|
|
assert(opt == IPSET_OPT_PORT);
|
|
|
|
typecode = *(const uint16_t *) ipset_data_get(data, IPSET_OPT_PORT);
|
|
name = icmp_to_name(typecode >> 8, typecode & 0xFF);
|
|
if (name != NULL)
|
|
return snprintf(buf, len, "%s", name);
|
|
else
|
|
return snprintf(buf, len, "%u/%u", typecode >> 8, typecode & 0xFF);
|
|
}
|
|
|
|
/**
|
|
* ipset_print_icmpv6 - print ICMPv6 code name or type/code
|
|
* @buf: printing buffer
|
|
* @len: length of available buffer space
|
|
* @data: data blob
|
|
* @opt: the option kind
|
|
* @env: environment flags
|
|
*
|
|
* Print ICMPv6 code name or type/code name to output buffer.
|
|
*
|
|
* Return lenght of printed string or error size.
|
|
*/
|
|
int
|
|
ipset_print_icmpv6(char *buf, unsigned int len,
|
|
const struct ipset_data *data,
|
|
enum ipset_opt opt ASSERT_UNUSED,
|
|
uint8_t env UNUSED)
|
|
{
|
|
const char *name;
|
|
uint16_t typecode;
|
|
|
|
assert(buf);
|
|
assert(len > 0);
|
|
assert(data);
|
|
assert(opt == IPSET_OPT_PORT);
|
|
|
|
typecode = *(const uint16_t *) ipset_data_get(data, IPSET_OPT_PORT);
|
|
name = icmpv6_to_name(typecode >> 8, typecode & 0xFF);
|
|
if (name != NULL)
|
|
return snprintf(buf, len, "%s", name);
|
|
else
|
|
return snprintf(buf, len, "%u/%u", typecode >> 8, typecode & 0xFF);
|
|
}
|
|
|
|
/**
|
|
* ipset_print_proto_port - print proto:port
|
|
* @buf: printing buffer
|
|
* @len: length of available buffer space
|
|
* @data: data blob
|
|
* @opt: the option kind
|
|
* @env: environment flags
|
|
*
|
|
* Print protocol and port to output buffer.
|
|
*
|
|
* Return lenght of printed string or error size.
|
|
*/
|
|
int
|
|
ipset_print_proto_port(char *buf, unsigned int len,
|
|
const struct ipset_data *data,
|
|
enum ipset_opt opt ASSERT_UNUSED,
|
|
uint8_t env UNUSED)
|
|
{
|
|
int size, offset = 0;
|
|
|
|
assert(buf);
|
|
assert(len > 0);
|
|
assert(data);
|
|
assert(opt == IPSET_OPT_PORT);
|
|
|
|
if (ipset_data_flags_test(data, IPSET_FLAG(IPSET_OPT_PROTO))) {
|
|
uint8_t proto = *(const uint8_t *) ipset_data_get(data,
|
|
IPSET_OPT_PROTO);
|
|
size = ipset_print_proto(buf, len, data, IPSET_OPT_PROTO, env);
|
|
SNPRINTF_FAILURE(size, len, offset);
|
|
if (len < 2)
|
|
return -ENOSPC;
|
|
size = snprintf(buf + offset, len, IPSET_PROTO_SEPARATOR);
|
|
SNPRINTF_FAILURE(size, len, offset);
|
|
|
|
switch (proto) {
|
|
case IPPROTO_TCP:
|
|
case IPPROTO_UDP:
|
|
break;
|
|
case IPPROTO_ICMP:
|
|
return ipset_print_icmp(buf + offset, len, data,
|
|
IPSET_OPT_PORT, env);
|
|
case IPPROTO_ICMPV6:
|
|
return ipset_print_icmpv6(buf + offset, len, data,
|
|
IPSET_OPT_PORT, env);
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
size = ipset_print_port(buf + offset, len, data, IPSET_OPT_PORT, env);
|
|
SNPRINTF_FAILURE(size, len, offset);
|
|
|
|
return offset;
|
|
}
|
|
|
|
#define print_second(data) \
|
|
ipset_data_flags_test(data, \
|
|
IPSET_FLAG(IPSET_OPT_PORT)|IPSET_FLAG(IPSET_OPT_ETHER))
|
|
|
|
#define print_third(data) \
|
|
ipset_data_flags_test(data, IPSET_FLAG(IPSET_OPT_IP2))
|
|
|
|
/**
|
|
* ipset_print_elem - print ADT elem according to settype
|
|
* @buf: printing buffer
|
|
* @len: length of available buffer space
|
|
* @data: data blob
|
|
* @opt: the option kind
|
|
* @env: environment flags
|
|
*
|
|
* Print (multipart) element according to settype
|
|
*
|
|
* Return lenght of printed string or error size.
|
|
*/
|
|
int
|
|
ipset_print_elem(char *buf, unsigned int len,
|
|
const struct ipset_data *data, enum ipset_opt opt UNUSED,
|
|
uint8_t env)
|
|
{
|
|
const struct ipset_type *type;
|
|
int size, offset = 0;
|
|
|
|
assert(buf);
|
|
assert(len > 0);
|
|
assert(data);
|
|
|
|
type = ipset_data_get(data, IPSET_OPT_TYPE);
|
|
if (!type)
|
|
return -1;
|
|
|
|
size = type->elem[IPSET_DIM_ONE].print(buf, len, data,
|
|
type->elem[IPSET_DIM_ONE].opt, env);
|
|
SNPRINTF_FAILURE(size, len, offset);
|
|
IF_D(ipset_data_test(data, type->elem[IPSET_DIM_TWO].opt),
|
|
"print second elem");
|
|
if (type->dimension == IPSET_DIM_ONE
|
|
|| (type->last_elem_optional
|
|
&& !ipset_data_test(data, type->elem[IPSET_DIM_TWO].opt)))
|
|
return offset;
|
|
|
|
size = snprintf(buf + offset, len, IPSET_ELEM_SEPARATOR);
|
|
SNPRINTF_FAILURE(size, len, offset);
|
|
size = type->elem[IPSET_DIM_TWO].print(buf + offset, len, data,
|
|
type->elem[IPSET_DIM_TWO].opt, env);
|
|
SNPRINTF_FAILURE(size, len, offset);
|
|
if (type->dimension == IPSET_DIM_TWO
|
|
|| (type->last_elem_optional
|
|
&& !ipset_data_test(data, type->elem[IPSET_DIM_THREE].opt)))
|
|
return offset;
|
|
|
|
size = snprintf(buf + offset, len, IPSET_ELEM_SEPARATOR);
|
|
SNPRINTF_FAILURE(size, len, offset);
|
|
size = type->elem[IPSET_DIM_THREE].print(buf + offset, len, data,
|
|
type->elem[IPSET_DIM_THREE].opt, env);
|
|
SNPRINTF_FAILURE(size, len, offset);
|
|
|
|
return offset;
|
|
}
|
|
|
|
/**
|
|
* ipset_print_flag - print a flag
|
|
* @buf: printing buffer
|
|
* @len: length of available buffer space
|
|
* @data: data blob
|
|
* @opt: the option kind
|
|
* @env: environment flags
|
|
*
|
|
* Print a flag, i.e. option without value
|
|
*
|
|
* Return lenght of printed string or error size.
|
|
*/
|
|
int
|
|
ipset_print_flag(char *buf UNUSED, unsigned int len UNUSED,
|
|
const struct ipset_data *data UNUSED,
|
|
enum ipset_opt opt UNUSED, uint8_t env UNUSED)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* ipset_print_data - print data, generic fuction
|
|
* @buf: printing buffer
|
|
* @len: length of available buffer space
|
|
* @data: data blob
|
|
* @opt: the option kind
|
|
* @env: environment flags
|
|
*
|
|
* Generic wrapper of the printing functions.
|
|
*
|
|
* Return lenght of printed string or error size.
|
|
*/
|
|
int
|
|
ipset_print_data(char *buf, unsigned int len,
|
|
const struct ipset_data *data, enum ipset_opt opt,
|
|
uint8_t env)
|
|
{
|
|
int size = 0, offset = 0;
|
|
|
|
assert(buf);
|
|
assert(len > 0);
|
|
assert(data);
|
|
|
|
switch (opt) {
|
|
case IPSET_OPT_FAMILY:
|
|
size = ipset_print_family(buf, len, data, opt, env);
|
|
break;
|
|
case IPSET_OPT_TYPE:
|
|
size = ipset_print_type(buf, len, data, opt, env);
|
|
break;
|
|
case IPSET_SETNAME:
|
|
size = snprintf(buf, len, "%s", ipset_data_setname(data));
|
|
break;
|
|
case IPSET_OPT_ELEM:
|
|
size = ipset_print_elem(buf, len, data, opt, env);
|
|
break;
|
|
case IPSET_OPT_IP:
|
|
size = ipset_print_ip(buf, len, data, opt, env);
|
|
break;
|
|
case IPSET_OPT_PORT:
|
|
size = ipset_print_port(buf, len, data, opt, env);
|
|
break;
|
|
case IPSET_OPT_GC:
|
|
case IPSET_OPT_HASHSIZE:
|
|
case IPSET_OPT_MAXELEM:
|
|
case IPSET_OPT_NETMASK:
|
|
case IPSET_OPT_PROBES:
|
|
case IPSET_OPT_RESIZE:
|
|
case IPSET_OPT_TIMEOUT:
|
|
case IPSET_OPT_REFERENCES:
|
|
case IPSET_OPT_ELEMENTS:
|
|
case IPSET_OPT_SIZE:
|
|
size = ipset_print_number(buf, len, data, opt, env);
|
|
break;
|
|
default:
|
|
return -1;
|
|
}
|
|
SNPRINTF_FAILURE(size, len, offset);
|
|
|
|
return offset;
|
|
}
|