summaryrefslogtreecommitdiffstats
path: root/iptables
diff options
context:
space:
mode:
authorPhil Sutter <phil@nwl.cc>2019-10-25 18:02:52 +0200
committerPhil Sutter <phil@nwl.cc>2019-10-26 21:09:03 +0200
commitfd0bb3f4b024e91044ae7cb7707d946504eae42f (patch)
tree68a28574d7430fdb40d3b5569c98f2a3c49cfac3 /iptables
parent9376c42a59929031610ea70d2fc6347fbfa46e67 (diff)
xtables-arp: Use xtables_ipparse_multiple()
Use the same code for parsing source and destination IP addresses as iptables and drop all the local functions dealing with that. While being at it, call free() for 'saddrs' and 'daddrs' unconditionally (like iptables does), they are NULL if not used. Signed-off-by: Phil Sutter <phil@nwl.cc> Acked-by: Florian Westphal <fw@strlen.de>
Diffstat (limited to 'iptables')
-rw-r--r--iptables/xtables-arp.c243
1 files changed, 30 insertions, 213 deletions
diff --git a/iptables/xtables-arp.c b/iptables/xtables-arp.c
index 35844a9b..1a260e75 100644
--- a/iptables/xtables-arp.c
+++ b/iptables/xtables-arp.c
@@ -317,89 +317,10 @@ static int get16_and_mask(char *from, uint16_t *to, uint16_t *mask, int base)
return 0;
}
-static int
-string_to_number(const char *s, unsigned int min, unsigned int max,
- unsigned int *ret)
-{
- long number;
- char *end;
-
- /* Handle hex, octal, etc. */
- errno = 0;
- number = strtol(s, &end, 0);
- if (*end == '\0' && end != s) {
- /* we parsed a number, let's see if we want this */
- if (errno != ERANGE && min <= number && number <= max) {
- *ret = number;
- return 0;
- }
- }
- return -1;
-}
-
/*********************************************/
/* ARPTABLES SPECIFIC NEW FUNCTIONS END HERE */
/*********************************************/
-static struct in_addr *
-dotted_to_addr(const char *dotted)
-{
- static struct in_addr addr;
- unsigned char *addrp;
- char *p, *q;
- unsigned int onebyte;
- int i;
- char buf[20];
-
- /* copy dotted string, because we need to modify it */
- strncpy(buf, dotted, sizeof(buf) - 1);
- addrp = (unsigned char *) &(addr.s_addr);
-
- p = buf;
- for (i = 0; i < 3; i++) {
- if ((q = strchr(p, '.')) == NULL)
- return (struct in_addr *) NULL;
-
- *q = '\0';
- if (string_to_number(p, 0, 255, &onebyte) == -1)
- return (struct in_addr *) NULL;
-
- addrp[i] = (unsigned char) onebyte;
- p = q + 1;
- }
-
- /* we've checked 3 bytes, now we check the last one */
- if (string_to_number(p, 0, 255, &onebyte) == -1)
- return (struct in_addr *) NULL;
-
- addrp[3] = (unsigned char) onebyte;
-
- return &addr;
-}
-
-static struct in_addr *
-network_to_addr(const char *name)
-{
- struct netent *net;
- static struct in_addr addr;
-
- if ((net = getnetbyname(name)) != NULL) {
- if (net->n_addrtype != AF_INET)
- return (struct in_addr *) NULL;
- addr.s_addr = htonl((unsigned long) net->n_net);
- return &addr;
- }
-
- return (struct in_addr *) NULL;
-}
-
-static void
-inaddrcpy(struct in_addr *dst, struct in_addr *src)
-{
- /* memcpy(dst, src, sizeof(struct in_addr)); */
- dst->s_addr = src->s_addr;
-}
-
static void
exit_tryhelp(int status)
{
@@ -588,127 +509,6 @@ check_inverse(const char option[], int *invert, int *optidx, int argc)
return FALSE;
}
-static struct in_addr *
-host_to_addr(const char *name, unsigned int *naddr)
-{
- struct in_addr *addr;
- struct addrinfo hints = {
- .ai_flags = AI_CANONNAME,
- .ai_family = AF_INET,
- .ai_socktype = SOCK_RAW,
- };;
- struct addrinfo *res, *p;
- int err;
- unsigned int i;
-
- *naddr = 0;
- err = getaddrinfo(name, NULL, &hints, &res);
- if (err != 0)
- return NULL;
- else {
- for (p = res; p != NULL; p = p->ai_next)
- (*naddr)++;
- addr = xtables_calloc(*naddr, sizeof(struct in_addr));
- for (i = 0, p = res; p != NULL; p = p->ai_next)
- memcpy(&addr[i++],
- &((const struct sockaddr_in *)p->ai_addr)->sin_addr,
- sizeof(struct in_addr));
- freeaddrinfo(res);
- return addr;
- }
-
- return (struct in_addr *) NULL;
-}
-
-/*
- * All functions starting with "parse" should succeed, otherwise
- * the program fails.
- * Most routines return pointers to static data that may change
- * between calls to the same or other routines with a few exceptions:
- * "host_to_addr", "parse_hostnetwork", and "parse_hostnetworkmask"
- * return global static data.
-*/
-
-static struct in_addr *
-parse_hostnetwork(const char *name, unsigned int *naddrs)
-{
- struct in_addr *addrp, *addrptmp;
-
- if ((addrptmp = dotted_to_addr(name)) != NULL ||
- (addrptmp = network_to_addr(name)) != NULL) {
- addrp = xtables_malloc(sizeof(struct in_addr));
- inaddrcpy(addrp, addrptmp);
- *naddrs = 1;
- return addrp;
- }
- if ((addrp = host_to_addr(name, naddrs)) != NULL)
- return addrp;
-
- xtables_error(PARAMETER_PROBLEM, "host/network `%s' not found", name);
-}
-
-static struct in_addr *
-parse_mask(char *mask)
-{
- static struct in_addr maskaddr;
- struct in_addr *addrp;
- unsigned int bits;
-
- if (mask == NULL) {
- /* no mask at all defaults to 32 bits */
- maskaddr.s_addr = 0xFFFFFFFF;
- return &maskaddr;
- }
- if ((addrp = dotted_to_addr(mask)) != NULL)
- /* dotted_to_addr already returns a network byte order addr */
- return addrp;
- if (string_to_number(mask, 0, 32, &bits) == -1)
- xtables_error(PARAMETER_PROBLEM,
- "invalid mask `%s' specified", mask);
- if (bits != 0) {
- maskaddr.s_addr = htonl(0xFFFFFFFF << (32 - bits));
- return &maskaddr;
- }
-
- maskaddr.s_addr = 0L;
- return &maskaddr;
-}
-
-static void
-parse_hostnetworkmask(const char *name, struct in_addr **addrpp,
- struct in_addr *maskp, unsigned int *naddrs)
-{
- struct in_addr *addrp;
- char buf[256];
- char *p;
- int i, j, k, n;
-
- strncpy(buf, name, sizeof(buf) - 1);
- if ((p = strrchr(buf, '/')) != NULL) {
- *p = '\0';
- addrp = parse_mask(p + 1);
- } else
- addrp = parse_mask(NULL);
- inaddrcpy(maskp, addrp);
-
- /* if a null mask is given, the name is ignored, like in "any/0" */
- if (maskp->s_addr == 0L)
- strcpy(buf, "0.0.0.0");
-
- addrp = *addrpp = parse_hostnetwork(buf, naddrs);
- n = *naddrs;
- for (i = 0, j = 0; i < n; i++) {
- addrp[j++].s_addr &= maskp->s_addr;
- for (k = 0; k < j - 1; k++) {
- if (addrp[k].s_addr == addrp[j - 1].s_addr) {
- (*naddrs)--;
- j--;
- break;
- }
- }
- }
-}
-
static void
parse_interface(const char *arg, char *vianame, unsigned char *mask)
{
@@ -814,8 +614,10 @@ append_entry(struct nft_handle *h,
int rulenum,
unsigned int nsaddrs,
const struct in_addr saddrs[],
+ const struct in_addr smasks[],
unsigned int ndaddrs,
const struct in_addr daddrs[],
+ const struct in_addr dmasks[],
bool verbose, bool append)
{
unsigned int i, j;
@@ -823,8 +625,10 @@ append_entry(struct nft_handle *h,
for (i = 0; i < nsaddrs; i++) {
cs->arp.arp.src.s_addr = saddrs[i].s_addr;
+ cs->arp.arp.smsk.s_addr = smasks[i].s_addr;
for (j = 0; j < ndaddrs; j++) {
cs->arp.arp.tgt.s_addr = daddrs[j].s_addr;
+ cs->arp.arp.tmsk.s_addr = dmasks[j].s_addr;
if (append) {
ret = nft_rule_append(h, chain, table, cs, NULL,
verbose);
@@ -844,11 +648,15 @@ replace_entry(const char *chain,
struct iptables_command_state *cs,
unsigned int rulenum,
const struct in_addr *saddr,
+ const struct in_addr *smask,
const struct in_addr *daddr,
+ const struct in_addr *dmask,
bool verbose, struct nft_handle *h)
{
cs->arp.arp.src.s_addr = saddr->s_addr;
cs->arp.arp.tgt.s_addr = daddr->s_addr;
+ cs->arp.arp.smsk.s_addr = smask->s_addr;
+ cs->arp.arp.tmsk.s_addr = dmask->s_addr;
return nft_rule_replace(h, chain, table, cs, rulenum, verbose);
}
@@ -859,8 +667,10 @@ delete_entry(const char *chain,
struct iptables_command_state *cs,
unsigned int nsaddrs,
const struct in_addr saddrs[],
+ const struct in_addr smasks[],
unsigned int ndaddrs,
const struct in_addr daddrs[],
+ const struct in_addr dmasks[],
bool verbose, struct nft_handle *h)
{
unsigned int i, j;
@@ -868,8 +678,10 @@ delete_entry(const char *chain,
for (i = 0; i < nsaddrs; i++) {
cs->arp.arp.src.s_addr = saddrs[i].s_addr;
+ cs->arp.arp.smsk.s_addr = smasks[i].s_addr;
for (j = 0; j < ndaddrs; j++) {
cs->arp.arp.tgt.s_addr = daddrs[j].s_addr;
+ cs->arp.arp.tmsk.s_addr = dmasks[j].s_addr;
ret = nft_rule_delete(h, chain, table, cs, verbose);
}
}
@@ -919,7 +731,8 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
};
int invert = 0;
unsigned int nsaddrs = 0, ndaddrs = 0;
- struct in_addr *saddrs = NULL, *daddrs = NULL;
+ struct in_addr *saddrs = NULL, *smasks = NULL;
+ struct in_addr *daddrs = NULL, *dmasks = NULL;
int c, verbose = 0;
const char *chain = NULL;
@@ -1292,12 +1105,12 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
}
if (shostnetworkmask)
- parse_hostnetworkmask(shostnetworkmask, &saddrs,
- &(cs.arp.arp.smsk), &nsaddrs);
+ xtables_ipparse_multiple(shostnetworkmask, &saddrs,
+ &smasks, &nsaddrs);
if (dhostnetworkmask)
- parse_hostnetworkmask(dhostnetworkmask, &daddrs,
- &(cs.arp.arp.tmsk), &ndaddrs);
+ xtables_ipparse_multiple(dhostnetworkmask, &daddrs,
+ &dmasks, &ndaddrs);
if ((nsaddrs > 1 || ndaddrs > 1) &&
(cs.arp.arp.invflags & (ARPT_INV_SRCIP | ARPT_INV_TGTIP)))
@@ -1343,12 +1156,14 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
switch (command) {
case CMD_APPEND:
ret = append_entry(h, chain, *table, &cs, 0,
- nsaddrs, saddrs, ndaddrs, daddrs,
+ nsaddrs, saddrs, smasks,
+ ndaddrs, daddrs, dmasks,
options&OPT_VERBOSE, true);
break;
case CMD_DELETE:
ret = delete_entry(chain, *table, &cs,
- nsaddrs, saddrs, ndaddrs, daddrs,
+ nsaddrs, saddrs, smasks,
+ ndaddrs, daddrs, dmasks,
options&OPT_VERBOSE, h);
break;
case CMD_DELETE_NUM:
@@ -1356,11 +1171,13 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
break;
case CMD_REPLACE:
ret = replace_entry(chain, *table, &cs, rulenum - 1,
- saddrs, daddrs, options&OPT_VERBOSE, h);
+ saddrs, smasks, daddrs, dmasks,
+ options&OPT_VERBOSE, h);
break;
case CMD_INSERT:
ret = append_entry(h, chain, *table, &cs, rulenum - 1,
- nsaddrs, saddrs, ndaddrs, daddrs,
+ nsaddrs, saddrs, smasks,
+ ndaddrs, daddrs, dmasks,
options&OPT_VERBOSE, false);
break;
case CMD_LIST:
@@ -1409,10 +1226,10 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
exit_tryhelp(2);
}
- if (nsaddrs)
- free(saddrs);
- if (ndaddrs)
- free(daddrs);
+ free(saddrs);
+ free(smasks);
+ free(daddrs);
+ free(dmasks);
if (cs.target)
free(cs.target->t);