Exemplo n.º 1
0
/** Allocate a new client from a config section
 *
 * @param ctx to allocate new clients in.
 * @param cs to process as a client.
 * @param in_server Whether the client should belong to a specific virtual server.
 * @param with_coa If true and coa_server or coa_pool aren't specified automatically,
 *	create a coa home_server section and add it to the client CONF_SECTION.
 * @return new RADCLIENT struct.
 */
RADCLIENT *client_afrom_cs(TALLOC_CTX *ctx, CONF_SECTION *cs, bool in_server, bool with_coa)
{
    RADCLIENT	*c;
    char const	*name2;

    name2 = cf_section_name2(cs);
    if (!name2) {
        cf_log_err_cs(cs, "Missing client name");
        return NULL;
    }

    /*
     *	The size is fine.. Let's create the buffer
     */
    c = talloc_zero(ctx, RADCLIENT);
    c->cs = cs;

    memset(&cl_ipaddr, 0, sizeof(cl_ipaddr));
    if (cf_section_parse(cs, c, client_config) < 0) {
        cf_log_err_cs(cs, "Error parsing client section");
error:
        client_free(c);
#ifdef WITH_TCP
        hs_proto = NULL;
        cl_srcipaddr = NULL;
#endif

        return NULL;
    }

    /*
     *	Global clients can set servers to use, per-server clients cannot.
     */
    if (in_server && c->server) {
        cf_log_err_cs(cs, "Clients inside of an server section cannot point to a server");
        goto error;
    }

    /*
     *	Newer style client definitions with either ipaddr or ipaddr6
     *	config items.
     */
    if (cf_pair_find(cs, "ipaddr") || cf_pair_find(cs, "ipv4addr") || cf_pair_find(cs, "ipv6addr")) {
        char buffer[128];

        /*
         *	Sets ipv4/ipv6 address and prefix.
         */
        c->ipaddr = cl_ipaddr;

        /*
         *	Set the long name to be the result of a reverse lookup on the IP address.
         */
        fr_inet_ntoh(&c->ipaddr, buffer, sizeof(buffer));
        c->longname = talloc_typed_strdup(c, buffer);

        /*
         *	Set the short name to the name2.
         */
        if (!c->shortname) c->shortname = talloc_typed_strdup(c, name2);
        /*
         *	No "ipaddr" or "ipv6addr", use old-style "client <ipaddr> {" syntax.
         */
    } else {
        cf_log_err_cs(cs, "No 'ipaddr' or 'ipv4addr' or 'ipv6addr' configuration "
                      "directive found in client %s", name2);
        goto error;
    }

    c->proto = IPPROTO_UDP;
    if (hs_proto) {
        if (strcmp(hs_proto, "udp") == 0) {
            hs_proto = NULL;

#ifdef WITH_TCP
        } else if (strcmp(hs_proto, "tcp") == 0) {
            hs_proto = NULL;
            c->proto = IPPROTO_TCP;
#  ifdef WITH_TLS
        } else if (strcmp(hs_proto, "tls") == 0) {
            hs_proto = NULL;
            c->proto = IPPROTO_TCP;
            c->tls_required = true;

        } else if (strcmp(hs_proto, "radsec") == 0) {
            hs_proto = NULL;
            c->proto = IPPROTO_TCP;
            c->tls_required = true;
#  endif
        } else if (strcmp(hs_proto, "*") == 0) {
            hs_proto = NULL;
            c->proto = IPPROTO_IP; /* fake for dual */
#endif
        } else {
            cf_log_err_cs(cs, "Unknown proto \"%s\".", hs_proto);
            goto error;
        }
    }

    /*
     *	If a src_ipaddr is specified, when we send the return packet
     *	we will use this address instead of the src from the
     *	request.
     */
    if (cl_srcipaddr) {
#ifdef WITH_UDPFROMTO
        switch (c->ipaddr.af) {
        case AF_INET:
            if (fr_inet_pton4(&c->src_ipaddr, cl_srcipaddr, -1, true, false, true) < 0) {
                cf_log_err_cs(cs, "Failed parsing src_ipaddr: %s", fr_strerror());
                goto error;
            }
            break;

        case AF_INET6:
            if (fr_inet_pton6(&c->src_ipaddr, cl_srcipaddr, -1, true, false, true) < 0) {
                cf_log_err_cs(cs, "Failed parsing src_ipaddr: %s", fr_strerror());
                goto error;
            }
            break;
        default:
            rad_assert(0);
        }
#else
        WARN("Server not built with udpfromto, ignoring client src_ipaddr");
#endif
        cl_srcipaddr = NULL;
    }

    /*
     *	A response_window of zero is OK, and means that it's
     *	ignored by the rest of the server timers.
     */
    if (timerisset(&c->response_window)) {
        FR_TIMEVAL_BOUND_CHECK("response_window", &c->response_window, >=, 0, 1000);
        FR_TIMEVAL_BOUND_CHECK("response_window", &c->response_window, <=, 60, 0);
        FR_TIMEVAL_BOUND_CHECK("response_window", &c->response_window, <=, main_config.max_request_time, 0);
    }
Exemplo n.º 2
0
/** Simple wrapper to decide whether an IP value is v4 or v6 and call the appropriate parser
 *
 * @param[out] out	Where to write the ip address value.
 * @param[in] value	to parse.
 * @param[in] inlen	Length of value, if value is \0 terminated inlen may be -1.
 * @param[in] resolve	If true and value doesn't look like an IP address, try and resolve value
 *			as a hostname.
 * @param[in] af	If the address type is not obvious from the format, and resolve is true,
 *			the DNS record (A or AAAA) we require.  Also controls which parser we pass
 *			the address to if we have no idea what it is.
 *			- AF_UNSPEC - Use the server default IP family.
 *			- AF_INET - Treat value as an IPv4 address.
 *			- AF_INET6 - Treat value as in IPv6 address.
 * @param[in] mask If true, set address bits to zero.
 * @return
 *	- 0 if ip address was parsed successfully.
 *	- -1 on failure.
 */
int fr_inet_pton(fr_ipaddr_t *out, char const *value, ssize_t inlen, int af, bool resolve, bool mask)
{
	size_t len, i;
	bool hostname = true;
	bool ipv4 = true;
	bool ipv6 = true;

	len = (inlen >= 0) ? (size_t)inlen : strlen(value);

	for (i = 0; i < len; i++) {
		/*
		 *	These are valid for IPv4, IPv6, and host names.
		 */
		if ((value[i] >= '0') && (value[i] <= '9')) {
			continue;
		}

		/*
		 *	These are invalid for IPv4, but OK for IPv6
		 *	and host names.
		 */
		if ((value[i] >= 'a') && (value[i] <= 'f')) {
			ipv4 = false;
			continue;
		}

		/*
		 *	These are invalid for IPv4, but OK for IPv6
		 *	and host names.
		 */
		if ((value[i] >= 'A') && (value[i] <= 'F')) {
			ipv4 = false;
			continue;
		}

		/*
		 *	This is only valid for IPv6 addresses.
		 */
		if (value[i] == ':') {
			ipv4 = false;
			hostname = false;
			continue;
		}

		/*
		 *	Valid for IPv4 and host names, not for IPv6.
		 */
		if (value[i] == '.') {
			ipv6 = false;
			continue;
		}

		/*
		 *	Netmasks are allowed by us, and MUST come at
		 *	the end of the address.
		 */
		if (value[i] == '/') {
			break;
		}

		/*
		 *	Any characters other than what are checked for
		 *	above can't be IPv4 or IPv6 addresses.
		 */
		ipv4 = false;
		ipv6 = false;
	}

	/*
	 *	It's not an IPv4 or IPv6 address.  It MUST be a host
	 *	name.
	 */
	if (!ipv4 && !ipv6) {
		/*
		 *	Not an IPv4 or IPv6 address, and we weren't
		 *	asked to do DNS resolution, we can't do it.
		 */
		if (!resolve) {
			fr_strerror_printf("Not IPv4/6 address, and asked not to resolve");
			return -1;
		}

		/*
		 *	It's not a hostname, either, so bail out
		 *	early.
		 */
		if (!hostname) {
			fr_strerror_printf("Invalid address");
			return -1;
		}

		/*
		 *	Fall through to resolving the address, using
		 *	whatever address family they prefer.  If they
		 *	don't specify an address family, force IPv4.
		 */
		if (af == AF_UNSPEC) af = AF_INET;
	}

	/*
	 *	The name has a ':' in it.  Therefore it must be an
	 *	IPv6 address.  Error out if the caller specified IPv4.
	 *	Otherwise, force IPv6.
	 */
	if (ipv6 && !hostname) {
		if (af == AF_INET) {
			fr_strerror_printf("Invalid address");
			return -1;
		}

		af = AF_INET6;
	}

	/*
	 *	Use whatever the caller specified, OR what we
	 *	insinuated above from looking at the name string.
	 */
	switch (af) {
	case AF_UNSPEC:
		return fr_inet_pton4(out, value, inlen, resolve, true, mask);

	case AF_INET:
		return fr_inet_pton4(out, value, inlen, resolve, false, mask);

	case AF_INET6:
		return fr_inet_pton6(out, value, inlen, resolve, false, mask);

	default:
		break;
	}

	/*
	 *	No idea what it is...
	 */
	fr_strerror_printf("Invalid address family %i", af);
	return -1;
}