Add top-level config options IPv4Only and IPv6Only.
[radsecproxy.git] / radsecproxy.c
index 5248c41..2868aa7 100644 (file)
@@ -1758,7 +1758,7 @@ void *clientwr(void *arg) {
 
     conf = server->conf;
 
-#define ZZZ 60
+#define ZZZ 900
 
     if (server->dynamiclookuparg && !dynamicconfig(server)) {
        dynconffail = 1;
@@ -1773,7 +1773,7 @@ void *clientwr(void *arg) {
     /* FIXME: Is resolving not always done by compileserverconfig(),
      * either as part of static configuration setup or by
      * dynamicconfig() above?  */
-    if (!resolvehostports(conf->hostports, conf->pdef->socktype)) {
+    if (!resolvehostports(conf->hostports, conf->hostaf, conf->pdef->socktype)) {
         debug(DBG_WARN, "%s: resolve failed, sleeping %ds", __func__, ZZZ);
         sleep(ZZZ);
         goto errexit;
@@ -1926,7 +1926,7 @@ void createlistener(uint8_t type, char *arg) {
     int s = -1, on = 1, *sp = NULL;
     struct hostportres *hp = newhostport(arg, protodefs[type]->portdefault, 0);
 
-    if (!hp || !resolvehostport(hp, protodefs[type]->socktype, 1))
+    if (!hp || !resolvehostport(hp, AF_UNSPEC, protodefs[type]->socktype, 1))
        debugx(1, DBG_ERR, "createlistener: failed to resolve %s", arg);
 
     for (res = hp->addrinfo; res; res = res->ai_next) {
@@ -2297,14 +2297,9 @@ int dynamicconfig(struct server *server) {
     }
 
     if (status) {
-       if (WEXITSTATUS(status) == 10) {
-           debug(DBG_INFO, "dynamicconfig: command signals empty config");
-       }
-       else {
-           debug(DBG_INFO, "dynamicconfig: command exited with status %d",
-                 WEXITSTATUS(status));
-           goto errexit;
-       }
+        debug(DBG_INFO, "dynamicconfig: command exited with status %d",
+              WEXITSTATUS(status));
+        goto errexit;
     }
 
     if (ok)
@@ -2689,10 +2684,31 @@ int mergesrvconf(struct clsrvconf *dst, struct clsrvconf *src) {
     return 1;
 }
 
+/** Set *AF according to IPV4ONLY and IPV6ONLY:
+    - If both are set, the function fails.
+    - If exactly one is set, *AF is set accordingly.
+    - If none is set, *AF is not affected.
+    Return 0 on success and !0 on failure.
+    In the case of an error, *AF is not affected.  */
+int config_hostaf(const char *desc, int ipv4only, int ipv6only, int *af) {
+    assert(af != NULL);
+    if (ipv4only && ipv6only) {
+       debug(DBG_ERR, "error in block %s, at most one of IPv4Only and "
+              "IPv6Only can be enabled", desc);
+        return -1;
+    }
+    if (ipv4only)
+        *af = AF_INET;
+    if (ipv6only)
+        *af = AF_INET6;
+    return 0;
+}
+
 int confclient_cb(struct gconffile **cf, void *arg, char *block, char *opt, char *val) {
     struct clsrvconf *conf;
     char *conftype = NULL, *rewriteinalias = NULL;
     long int dupinterval = LONG_MIN, addttl = LONG_MIN;
+    uint8_t ipv4only, ipv6only;
 
     debug(DBG_DBG, "confclient_cb called for %s", block);
 
@@ -2706,6 +2722,8 @@ int confclient_cb(struct gconffile **cf, void *arg, char *block, char *opt, char
            cf, block,
            "type", CONF_STR, &conftype,
            "host", CONF_MSTR, &conf->hostsrc,
+            "IPv4Only", CONF_BLN, &ipv4only,
+            "IPv6Only", CONF_BLN, &ipv6only,
            "secret", CONF_STR, &conf->secret,
 #if defined(RADPROT_TLS) || defined(RADPROT_DTLS)
            "tls", CONF_STR, &conf->tls,
@@ -2757,6 +2775,12 @@ int confclient_cb(struct gconffile **cf, void *arg, char *block, char *opt, char
     }
 #endif
 
+    conf->hostaf = AF_UNSPEC;
+    if (config_hostaf("top level", options.ipv4only, options.ipv6only, &conf->hostaf))
+        debugx(1, DBG_ERR, "config error: ^");
+    if (config_hostaf(block, ipv4only, ipv6only, &conf->hostaf))
+        debugx(1, DBG_ERR, "error in block %s: ^", block);
+
     if (dupinterval != LONG_MIN) {
        if (dupinterval < 0 || dupinterval > 255)
            debugx(1, DBG_ERR, "error in block %s, value of option DuplicateInterval is %d, must be 0-255", block, dupinterval);
@@ -2787,7 +2811,7 @@ int confclient_cb(struct gconffile **cf, void *arg, char *block, char *opt, char
     }
 
     if (!addhostport(&conf->hostports, conf->hostsrc, conf->pdef->portdefault, 1) ||
-       !resolvehostports(conf->hostports, conf->pdef->socktype))
+       !resolvehostports(conf->hostports, conf->hostaf, conf->pdef->socktype))
        debugx(1, DBG_ERR, "%s: resolve failed, exiting", __func__);
 
     if (!conf->secret) {
@@ -2849,7 +2873,9 @@ int compileserverconfig(struct clsrvconf *conf, const char *block) {
        return 0;
     }
 
-    if (!conf->dynamiclookupcommand && !resolvehostports(conf->hostports, conf->pdef->socktype)) {
+    if (!conf->dynamiclookupcommand &&
+        !resolvehostports(conf->hostports, conf->hostaf,
+                          conf->pdef->socktype)) {
        debug(DBG_ERR, "%s: resolve failed", __func__);
        return 0;
     }
@@ -2860,6 +2886,7 @@ int confserver_cb(struct gconffile **cf, void *arg, char *block, char *opt, char
     struct clsrvconf *conf, *resconf;
     char *conftype = NULL, *rewriteinalias = NULL;
     long int retryinterval = LONG_MIN, retrycount = LONG_MIN, addttl = LONG_MIN;
+    uint8_t ipv4only, ipv6only;
 
     debug(DBG_DBG, "confserver_cb called for %s", block);
 
@@ -2880,6 +2907,8 @@ int confserver_cb(struct gconffile **cf, void *arg, char *block, char *opt, char
     if (!getgenericconfig(cf, block,
                          "type", CONF_STR, &conftype,
                          "host", CONF_MSTR, &conf->hostsrc,
+                          "IPv4Only", CONF_BLN, &ipv4only,
+                          "IPv6Only", CONF_BLN, &ipv6only,
                          "port", CONF_STR, &conf->portsrc,
                          "secret", CONF_STR, &conf->secret,
 #if defined(RADPROT_TLS) || defined(RADPROT_DTLS)
@@ -2927,6 +2956,12 @@ int confserver_cb(struct gconffile **cf, void *arg, char *block, char *opt, char
     free(conftype);
     conftype = NULL;
 
+    conf->hostaf = AF_UNSPEC;
+    if (config_hostaf("top level", options.ipv4only, options.ipv6only, &conf->hostaf))
+        debugx(1, DBG_ERR, "config error: ^");
+    if (config_hostaf(block, ipv4only, ipv6only, &conf->hostaf))
+        goto errexit;
+
     conf->pdef = protodefs[conf->type];
 
     if (!conf->confrewritein)
@@ -3128,6 +3163,8 @@ void getmainconfig(const char *configfile) {
            "FTicksKey", CONF_STR, &fticks_key_str,
            "FTicksSyslogFacility", CONF_STR, &options.ftickssyslogfacility,
 #endif
+            "IPv4Only", CONF_BLN, &options.ipv4only,
+            "IPv6Only", CONF_BLN, &options.ipv6only,
            NULL
            ))
        debugx(1, DBG_ERR, "configuration error");