+
+bool
+fw3_check_ipset(struct fw3_ipset *set)
+{
+ bool rv = false;
+
+ socklen_t sz;
+ int s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
+ struct ip_set_req_version req_ver;
+ struct ip_set_req_get_set req_name;
+
+ if (s < 0 || fcntl(s, F_SETFD, FD_CLOEXEC))
+ goto out;
+
+ sz = sizeof(req_ver);
+ req_ver.op = IP_SET_OP_VERSION;
+
+ if (getsockopt(s, SOL_IP, SO_IP_SET, &req_ver, &sz))
+ goto out;
+
+ sz = sizeof(req_name);
+ req_name.op = IP_SET_OP_GET_BYNAME;
+ req_name.version = req_ver.version;
+ snprintf(req_name.set.name, IPSET_MAXNAMELEN - 1, "%s",
+ set->external ? set->external : set->name);
+
+ if (getsockopt(s, SOL_IP, SO_IP_SET, &req_name, &sz))
+ goto out;
+
+ rv = ((sz == sizeof(req_name)) && (req_name.set.index != IPSET_INVALID_ID));
+
+out:
+ if (s >= 0)
+ close(s);
+
+ return rv;
+}
+
+void
+fw3_ipsets_update_run_state(enum fw3_family family, struct fw3_state *run_state,
+ struct fw3_state *cfg_state)
+{
+ struct fw3_ipset *ipset_run, *ipset_cfg;
+ bool in_cfg;
+
+ list_for_each_entry(ipset_run, &run_state->ipsets, list) {
+ if (ipset_run->family != family)
+ continue;
+
+ in_cfg = false;
+
+ list_for_each_entry(ipset_cfg, &cfg_state->ipsets, list) {
+ if (ipset_cfg->family != family)
+ continue;
+
+ if (strlen(ipset_run->name) ==
+ strlen(ipset_cfg->name) &&
+ !strcmp(ipset_run->name, ipset_cfg->name)) {
+ in_cfg = true;
+ break;
+ }
+ }
+
+ /* If a set is found in run_state, but not in cfg_state then the
+ * set has been deleted/renamed. Set reload_set to true to force
+ * the old set to be destroyed in the "stop" fase of the reload.
+ * If the set is found, then copy the reload_set value from the
+ * configuration state. This ensures that the elements are
+ * always updated according to the configuration, and not the
+ * runtime state (which the user might have forgotten).
+ */
+ if (!in_cfg)
+ ipset_run->reload_set = true;
+ else
+ ipset_run->reload_set = ipset_cfg->reload_set;
+ }
+}