static bool do_ipset_cmd(struct ipset_session* session, enum ipset_cmd cmd, const char *setname, const ip_address_t *addr, uint32_t timeout, const char* iface) { const struct ipset_type *type; uint8_t family; int r; ipset_session_data_set(session, IPSET_SETNAME, setname); type = ipset_type_get(session, cmd); if (type == NULL) { /* possible reasons for failure: set name does not exist */ return false; } family = (addr->ifa.ifa_family == AF_INET) ? NFPROTO_IPV4 : NFPROTO_IPV6; ipset_session_data_set(session, IPSET_OPT_FAMILY, &family); ipset_session_data_set(session, IPSET_OPT_IP, &addr->u); if (timeout) ipset_session_data_set(session, IPSET_OPT_TIMEOUT, &timeout); if (iface) ipset_session_data_set(session, IPSET_OPT_IFACE, iface); r = ipset_cmd1(session, cmd, 0); return r == 0; }
/** * This function was designed for three values of cmd: * CMD_TEST: true if exists, false if not exists (or set name not found) * CMD_ADD: true if added, false if error occurred (set name not found?) * CMD_DEL: true if deleted, false if error occurred (set name not found?) */ static bool try_ipset_cmd(enum ipset_cmd cmd, const char *setname, const struct in_addr *addr, uint32_t timeout) { const struct ipset_type *type; uint8_t family; int r; r = ipset_session_data_set(session, IPSET_SETNAME, setname); /* since the IPSET_SETNAME option is valid, this should never fail */ assert(r == 0); type = ipset_type_get(session, cmd); if (type == NULL) { /* possible reasons for failure: set name does not exist */ return false; } family = NFPROTO_IPV4; ipset_session_data_set(session, IPSET_OPT_FAMILY, &family); ipset_session_data_set(session, IPSET_OPT_IP, addr); if (timeout) ipset_session_data_set(session, IPSET_OPT_TIMEOUT, &timeout); r = ipset_cmd(session, cmd, /*lineno*/ 0); /* assume that errors always occur if NOT in set. To do it otherwise, * see lib/session.c for IPSET_CMD_TEST in ipset_cmd */ return r == 0; }
/* Parse ICMP and ICMPv6 type/code */ static int parse_icmp_typecode(struct ipset_session *session, enum ipset_opt opt, const char *str, const char *family) { uint16_t typecode; uint8_t type, code; char *a, *saved, *tmp; int err; saved = tmp = strdup(str); if (tmp == NULL) return ipset_err(session, "Cannot allocate memory to duplicate %s.", str); a = cidr_separator(tmp); if (a == NULL) { free(saved); return ipset_err(session, "Cannot parse %s as an %s type/code.", str, family); } *a++ = '\0'; if ((err = string_to_u8(session, a, &type)) != 0 || (err = string_to_u8(session, tmp, &code)) != 0) goto error; typecode = (type << 8) | code; err = ipset_session_data_set(session, opt, &typecode); error: free(saved); return err; }
/** * ipset_parse_ether - parse ethernet address * @session: session structure * @opt: option kind of the data * @str: string to parse * * Parse string as an ethernet address. The parsed ethernet * address is stored in the data blob of the session. * * Returns 0 on success or a negative error code. */ int ipset_parse_ether(struct ipset_session *session, enum ipset_opt opt, const char *str) { unsigned int i = 0; unsigned char ether[ETH_ALEN]; assert(session); assert(opt == IPSET_OPT_ETHER); assert(str); if (strlen(str) != ETH_ALEN * 3 - 1) goto error; for (i = 0; i < ETH_ALEN; i++) { long number; char *end; number = strtol(str + i * 3, &end, 16); if (end == str + i * 3 + 2 && (*end == ':' || *end == '\0') && number >= 0 && number <= 255) ether[i] = number; else goto error; } return ipset_session_data_set(session, opt, ether); error: return syntax_err("cannot parse '%s' as ethernet address", str); }
static int get_addrinfo(struct ipset_session *session, enum ipset_opt opt, const char *str, struct addrinfo **info, uint8_t family) { struct addrinfo *i; size_t addrlen = family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6); int found, err = 0; if ((*info = call_getaddrinfo(session, str, family)) == NULL) { syntax_err("cannot parse %s: resolving to %s address failed", str, family == AF_INET ? "IPv4" : "IPv6"); return EINVAL; } for (i = *info, found = 0; i != NULL; i = i->ai_next) { if (i->ai_family != family || i->ai_addrlen != addrlen) continue; if (found == 0) { if (family == AF_INET) { /* Workaround: direct cast increases required alignment on Sparc */ const struct sockaddr_in *saddr = (void *)i->ai_addr; err = ipset_session_data_set(session, opt, &saddr->sin_addr); } else { /* Workaround: direct cast increases required alignment on Sparc */ const struct sockaddr_in6 *saddr = (void *)i->ai_addr; err = ipset_session_data_set(session, opt, &saddr->sin6_addr); } } else if (found == 1) { ipset_warn(session, "%s resolves to multiple addresses: " "using only the first one returned " "by the resolver", str); } found++; } if (found == 0) return syntax_err("cannot parse %s: " "%s address could not be resolved", str, family == AF_INET ? "IPv4" : "IPv6"); return err; }
/** * ipset_parse_setname - parse string as a setname * @session: session structure * @opt: option kind of the data * @str: string to parse * * Parse string as a setname. * The value is stored in the data blob of the session. * * Returns 0 on success or a negative error code. */ int ipset_parse_setname(struct ipset_session *session, enum ipset_opt opt, const char *str) { assert(session); assert(opt == IPSET_SETNAME || opt == IPSET_OPT_NAME || opt == IPSET_OPT_SETNAME2); assert(str); check_setname(str, NULL); return ipset_session_data_set(session, opt, str); }
/** * ipset_parse_icmpv6 - parse an ICMPv6 name or type/code * @session: session structure * @opt: option kind of the data * @str: string to parse * * Parse string as an ICMPv6 name or type/code numbers. * The parsed ICMPv6 type/code is stored in the data blob of the session. * * Returns 0 on success or a negative error code. */ int ipset_parse_icmpv6(struct ipset_session *session, enum ipset_opt opt, const char *str) { uint16_t typecode; assert(session); assert(opt == IPSET_OPT_PORT); assert(str); if (name_to_icmpv6(str, &typecode) < 0) return parse_icmp_typecode(session, opt, str, "ICMPv6"); return ipset_session_data_set(session, opt, &typecode); }
/** * ipset_parse_uint8 - parse string as an unsigned short integer * @session: session structure * @opt: option kind of the data * @str: string to parse * * Parse string as an unsigned short integer number. * The value is stored in the data blob of the session. * * Returns 0 on success or a negative error code. */ int ipset_parse_uint8(struct ipset_session *session, enum ipset_opt opt, const char *str) { uint8_t value; int err; assert(session); assert(str); if ((err = string_to_u8(session, str, &value)) == 0) return ipset_session_data_set(session, opt, &value); return err; }
static int parse_ipaddr(struct ipset_session *session, enum ipset_opt opt, const char *str, uint8_t family) { uint8_t m = family == AF_INET ? 32 : 128; int aerr = EINVAL, err = 0, range = 0; char *saved = strdup(str); char *a, *tmp = saved; struct addrinfo *info; enum ipset_opt copt = opt == IPSET_OPT_IP ? IPSET_OPT_CIDR : IPSET_OPT_CIDR2; if (tmp == NULL) return ipset_err(session, "Cannot allocate memory to duplicate %s.", str); if ((a = cidr_separator(tmp)) != NULL) { /* IP/mask */ *a++ = '\0'; if ((err = string_to_cidr(session, a, 0, m, &m)) != 0 || (err = ipset_session_data_set(session, copt, &m)) != 0) goto out; } else if ((a = range_separator(tmp)) != NULL) { /* IP-IP */ *a++ = '\0'; D("range %s", a); range++; } if ((aerr = get_addrinfo(session, opt, tmp, &info, family)) != 0 || !range) goto out; freeaddrinfo(info); aerr = get_addrinfo(session, IPSET_OPT_IP_TO, a, &info, family); out: if (aerr != EINVAL) /* getaddrinfo not failed */ freeaddrinfo(info); else if (aerr) err = -1; free(saved); return err; }
/** * ipset_parse_proto - parse protocol name * @session: session structure * @opt: option kind of the data * @str: string to parse * * Parse string as a protocol name. * The parsed protocol is stored in the data blob of the session. * * Returns 0 on success or a negative error code. */ int ipset_parse_proto(struct ipset_session *session, enum ipset_opt opt, const char *str) { const struct protoent *protoent; uint8_t proto = 0; assert(session); assert(opt == IPSET_OPT_PROTO); assert(str); protoent = getprotobyname(strcasecmp(str, "icmpv6") == 0 ? "ipv6-icmp" : str); if (protoent == NULL) return syntax_err("cannot parse '%s' " "as a protocol name", str); proto = protoent->p_proto; if (!proto) return syntax_err("Unsupported protocol '%s'", str); return ipset_session_data_set(session, opt, &proto); }
/** * ipset_parse_single_port - parse a single port number or name * @session: session structure * @opt: option kind of the data * @str: string to parse * @proto: protocol * * Parse string as a single port number or name. The parsed port * number is stored in the data blob of the session. * * Returns 0 on success or a negative error code. */ int ipset_parse_port(struct ipset_session *session, enum ipset_opt opt, const char *str, const char *proto) { uint16_t port; int err; assert(session); assert(opt == IPSET_OPT_PORT || opt == IPSET_OPT_PORT_TO); assert(str); if ((err = string_to_u16(session, str, &port)) == 0 || (err = parse_portname(session, str, &port, proto)) == 0) err = ipset_session_data_set(session, opt, &port); if (!err) /* No error, so reset false error messages! */ ipset_session_report_reset(session); return err; }
ipset_session_data_set(session, IPSET_OPT_TIMEOUT, &timeout); if (iface) ipset_session_data_set(session, IPSET_OPT_IFACE, iface); r = ipset_cmd1(session, cmd, 0); return r == 0; } static bool ipset_create(struct ipset_session* session, const char *setname, const char *typename, uint8_t family) { const struct ipset_type *type; int r; r = ipset_session_data_set(session, IPSET_SETNAME, setname); ipset_session_data_set(session, IPSET_OPT_TYPENAME, typename); type = ipset_type_get(session, IPSET_CMD_CREATE); if (type == NULL) return false; ipset_session_data_set(session, IPSET_OPT_TYPE, type); ipset_session_data_set(session, IPSET_OPT_FAMILY, &family); r = ipset_cmd1(session, IPSET_CMD_CREATE, 0); return r == 0; } static bool