/** * ipset_parse_iptimeout - parse IPv4|IPv6 address and timeout * @session: session structure * @opt: option kind of the data * @str: string to parse * * Parse string as an IPv4|IPv6 address and timeout parameter. * If family is not set yet in the data blob, INET is assumed. * The value is stored in the data blob of the session. * * Compatibility parser. * * Returns 0 on success or a negative error code. */ int ipset_parse_iptimeout(struct ipset_session *session, enum ipset_opt opt, const char *str) { char *tmp, *saved, *a; int err; assert(session); assert(opt == IPSET_OPT_IP); assert(str); /* IP,timeout */ if (ipset_data_flags_test(ipset_session_data(session), IPSET_FLAG(IPSET_OPT_TIMEOUT))) return syntax_err("mixed syntax, timeout already specified"); tmp = saved = strdup(str); if (saved == NULL) return ipset_err(session, "Cannot allocate memory to duplicate %s.", str); a = elem_separator(tmp); if (a == NULL) { free(saved); return syntax_err("Missing separator from %s", str); } *a++ = '\0'; err = parse_ip(session, opt, tmp, IPADDR_ANY); if (!err) err = ipset_parse_uint32(session, IPSET_OPT_TIMEOUT, a); free(saved); return err; }
/** * ipset_parse_family - parse INET|INET6 family names * @session: session structure * @opt: option kind of the data * @str: string to parse * * Parse string as an INET|INET6 family name. * The value is stored in the data blob of the session. * * Returns 0 on success or a negative error code. */ int ipset_parse_family(struct ipset_session *session, enum ipset_opt opt, const char *str) { struct ipset_data *data; uint8_t family; assert(session); assert(opt == IPSET_OPT_FAMILY); assert(str); data = ipset_session_data(session); if (ipset_data_flags_test(data, IPSET_FLAG(IPSET_OPT_FAMILY))) syntax_err("protocol family may not be specified " "multiple times"); if (STREQ(str, "inet") || STREQ(str, "ipv4") || STREQ(str, "-4")) family = AF_INET; else if (STREQ(str, "inet6") || STREQ(str, "ipv6") || STREQ(str, "-6")) family = AF_INET6; else if (STREQ(str, "any") || STREQ(str, "unspec")) family = AF_UNSPEC; else return syntax_err("unknown INET family %s", str); return ipset_data_set(data, opt, &family); }
/** * ipset_parse_name_compat - parse setname as element * @session: session structure * @opt: option kind of the data * @str: string to parse * * Parse string as a setname or a setname element to add to a set. * The pattern "setname,before|after,setname" is recognized and * parsed. * The value is stored in the data blob of the session. * * Returns 0 on success or a negative error code. */ int ipset_parse_name_compat(struct ipset_session *session, enum ipset_opt opt, const char *str) { char *saved; char *a = NULL, *b = NULL, *tmp; int err, before = 0; const char *sep = IPSET_ELEM_SEPARATOR; struct ipset_data *data; assert(session); assert(opt == IPSET_OPT_NAME); assert(str); data = ipset_session_data(session); if (ipset_data_flags_test(data, IPSET_FLAG(IPSET_OPT_NAMEREF))) syntax_err("mixed syntax, before|after option already used"); tmp = saved = strdup(str); if (saved == NULL) return ipset_err(session, "Cannot allocate memory to duplicate %s.", str); if ((a = elem_separator(tmp)) != NULL) { /* setname,[before|after,setname */ *a++ = '\0'; if ((b = elem_separator(a)) != NULL) *b++ = '\0'; if (b == NULL || !(STREQ(a, "before") || STREQ(a, "after"))) { err = ipset_err(session, "you must specify elements " "as setname%s[before|after]%ssetname", sep, sep); goto out; } before = STREQ(a, "before"); } check_setname(tmp, saved); if ((err = ipset_data_set(data, opt, tmp)) != 0 || b == NULL) goto out; check_setname(b, saved); if ((err = ipset_data_set(data, IPSET_OPT_NAMEREF, b)) != 0) goto out; if (before) err = ipset_data_set(data, IPSET_OPT_BEFORE, &before); out: free(saved); return err; }
/** * 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 || opt == IPSET_OPT_PORT2); 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_SCTP: case IPPROTO_UDP: case IPPROTO_UDPLITE: break; case IPPROTO_ICMP: size = ipset_print_icmp(buf + offset, len, data, opt, env); goto out; case IPPROTO_ICMPV6: size = ipset_print_icmpv6(buf + offset, len, data, opt, env); goto out; default: break; } } size = ipset_print_port(buf + offset, len, data, opt, env); out: SNPRINTF_FAILURE(size, len, offset); return offset; }
/** * ipset_parse_after - parse string as "after" reference setname * @session: session structure * @opt: option kind of the data * @str: string to parse * * Parse string as a "after" reference setname for list:set * type of sets. The value is stored in the data blob of the session. * * Returns 0 on success or a negative error code. */ int ipset_parse_after(struct ipset_session *session, enum ipset_opt opt, const char *str) { struct ipset_data *data; assert(session); assert(opt == IPSET_OPT_NAMEREF); assert(str); data = ipset_session_data(session); if (ipset_data_flags_test(data, IPSET_FLAG(IPSET_OPT_NAMEREF))) syntax_err("mixed syntax, before|after option already used"); check_setname(str, NULL); return ipset_data_set(data, opt, str); }
/** * 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; }